mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
Added Deep Zoom support.
Added OpenSuse 13.1 and 13.2 support in preinstall.sh script. Added OpenSlide support in preinstall script. Added unit tests for Deep Zoom and OpenSlide.
This commit is contained in:
parent
5240eeb518
commit
2d1e6f2644
21
README.md
21
README.md
@ -12,7 +12,7 @@
|
|||||||
The typical use case for this high speed Node.js module is to convert large images of many formats to smaller, web-friendly JPEG, PNG and WebP images of varying dimensions.
|
The typical use case for this high speed Node.js module is to convert large images of many formats to smaller, web-friendly JPEG, PNG and WebP images of varying dimensions.
|
||||||
|
|
||||||
This module supports reading and writing JPEG, PNG and WebP images to and from Streams, Buffer objects and the filesystem.
|
This module supports reading and writing JPEG, PNG and WebP images to and from Streams, Buffer objects and the filesystem.
|
||||||
It also supports reading images of many other types from the filesystem via libmagick or libgraphicsmagick if present.
|
It also supports reading images of many other types from the filesystem via libmagick, libgraphicsmagick or [OpenSlide](http://openslide.org/) if present and writing Deep Zoom images.
|
||||||
Colour spaces, embedded ICC profiles and alpha transparency channels are all handled correctly.
|
Colour spaces, embedded ICC profiles and alpha transparency channels are all handled correctly.
|
||||||
|
|
||||||
Only small regions of uncompressed image data are held in memory and processed at a time, taking full advantage of multiple CPU cores and L1/L2/L3 cache. Resizing an image is typically 4x faster than using the quickest ImageMagick and GraphicsMagick settings.
|
Only small regions of uncompressed image data are held in memory and processed at a time, taking full advantage of multiple CPU cores and L1/L2/L3 cache. Resizing an image is typically 4x faster than using the quickest ImageMagick and GraphicsMagick settings.
|
||||||
@ -34,6 +34,7 @@ This module is powered by the blazingly fast [libvips](https://github.com/jcupit
|
|||||||
* Node.js v0.10+ or io.js
|
* Node.js v0.10+ or io.js
|
||||||
* [libvips](https://github.com/jcupitt/libvips) v7.40.0+ (7.42.0+ recommended)
|
* [libvips](https://github.com/jcupitt/libvips) v7.40.0+ (7.42.0+ recommended)
|
||||||
* C++11 compatible compiler such as gcc 4.6+ or clang 3.0+
|
* C++11 compatible compiler such as gcc 4.6+ or clang 3.0+
|
||||||
|
* [OpenSlide](http://openslide.org/) 3.4.0+ for reading OpenSlide images (optional)
|
||||||
|
|
||||||
To install the most suitable version of libvips on the following Operating Systems:
|
To install the most suitable version of libvips on the following Operating Systems:
|
||||||
|
|
||||||
@ -48,6 +49,8 @@ To install the most suitable version of libvips on the following Operating Syste
|
|||||||
* RHEL/Centos/Scientific 6, 7
|
* RHEL/Centos/Scientific 6, 7
|
||||||
* Fedora 21, 22
|
* Fedora 21, 22
|
||||||
* Amazon Linux 2014.09
|
* Amazon Linux 2014.09
|
||||||
|
* OpenSuse Linux
|
||||||
|
* OpenSuse 13.1, 13.2
|
||||||
|
|
||||||
run the following as a user with `sudo` access:
|
run the following as a user with `sudo` access:
|
||||||
|
|
||||||
@ -57,6 +60,14 @@ or run the following as `root`:
|
|||||||
|
|
||||||
curl -s https://raw.githubusercontent.com/lovell/sharp/master/preinstall.sh | bash -
|
curl -s https://raw.githubusercontent.com/lovell/sharp/master/preinstall.sh | bash -
|
||||||
|
|
||||||
|
To enable OpenSlide, add the --with-openslide argument:
|
||||||
|
|
||||||
|
> curl -s https://raw.githubusercontent.com/lovell/sharp/master/preinstall.sh | sudo bash -s -- --with-openslide
|
||||||
|
|
||||||
|
or run the following as `root`:
|
||||||
|
|
||||||
|
curl -s https://raw.githubusercontent.com/lovell/sharp/master/preinstall.sh | bash -s -- --with-openslide
|
||||||
|
|
||||||
The [preinstall.sh](https://github.com/lovell/sharp/blob/master/preinstall.sh) script requires `curl` and `pkg-config`.
|
The [preinstall.sh](https://github.com/lovell/sharp/blob/master/preinstall.sh) script requires `curl` and `pkg-config`.
|
||||||
|
|
||||||
### Mac OS tips
|
### Mac OS tips
|
||||||
@ -508,11 +519,17 @@ _Requires libvips 7.42.0+_
|
|||||||
|
|
||||||
An advanced setting to disable adaptive row filtering for the lossless PNG output format.
|
An advanced setting to disable adaptive row filtering for the lossless PNG output format.
|
||||||
|
|
||||||
|
#### tileSize(tileSize)
|
||||||
|
Setting the tile_size when DZI output format is selected. Default is 256.
|
||||||
|
|
||||||
|
#### tileOverlap(tileOverlap)
|
||||||
|
Setting the overlap when DZI output format is selected. Default is 0.
|
||||||
|
|
||||||
### Output methods
|
### Output methods
|
||||||
|
|
||||||
#### toFile(filename, [callback])
|
#### toFile(filename, [callback])
|
||||||
|
|
||||||
`filename` is a String containing the filename to write the image data to. The format is inferred from the extension, with JPEG, PNG, WebP and TIFF supported.
|
`filename` is a String containing the filename to write the image data to. The format is inferred from the extension, with JPEG, PNG, WebP, TIFF and DZI supported.
|
||||||
|
|
||||||
`callback`, if present, is called with two arguments `(err, info)` where:
|
`callback`, if present, is called with two arguments `(err, info)` where:
|
||||||
|
|
||||||
|
38
index.js
38
index.js
@ -66,7 +66,9 @@ var Sharp = function(input) {
|
|||||||
withoutAdaptiveFiltering: false,
|
withoutAdaptiveFiltering: false,
|
||||||
withoutChromaSubsampling: false,
|
withoutChromaSubsampling: false,
|
||||||
streamOut: false,
|
streamOut: false,
|
||||||
withMetadata: false
|
withMetadata: false,
|
||||||
|
tileSize: 256,
|
||||||
|
tileOverlap: 0
|
||||||
};
|
};
|
||||||
if (typeof input === 'string') {
|
if (typeof input === 'string') {
|
||||||
// input=file
|
// input=file
|
||||||
@ -377,6 +379,32 @@ Sharp.prototype.withMetadata = function(withMetadata) {
|
|||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
dz tile size for DZ output
|
||||||
|
max is 8192 since 7.36.5 (1024 before)
|
||||||
|
*/
|
||||||
|
Sharp.prototype.tileSize = function(tileSize) {
|
||||||
|
if (!Number.isNaN(tileSize) && tileSize >= 1 && tileSize <= 8192) {
|
||||||
|
this.options.tileSize = tileSize;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid tileSize (1 to 8192) ' + tileSize);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
dz overlap for DZ output
|
||||||
|
*/
|
||||||
|
Sharp.prototype.tileOverlap = function(tileOverlap) {
|
||||||
|
if (!Number.isNaN(tileOverlap) && tileOverlap >=0 && tileOverlap <= 8192) {
|
||||||
|
this.options.tileOverlap = tileOverlap;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid tileOverlap (0 to 8192) ' + tileOverlap);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
Sharp.prototype.resize = function(width, height) {
|
Sharp.prototype.resize = function(width, height) {
|
||||||
if (!width) {
|
if (!width) {
|
||||||
this.options.width = -1;
|
this.options.width = -1;
|
||||||
@ -483,6 +511,14 @@ Sharp.prototype.raw = function() {
|
|||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Force DZI output
|
||||||
|
*/
|
||||||
|
Sharp.prototype.dz = function() {
|
||||||
|
this.options.output = '__dzi';
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Force output to a given format
|
Force output to a given format
|
||||||
@param format is either the id as a String or an Object with an 'id' attribute
|
@param format is either the id as a String or an Object with an 'id' attribute
|
||||||
|
@ -13,7 +13,8 @@
|
|||||||
"Brandon Aaron <hello.brandon@aaron.sh>",
|
"Brandon Aaron <hello.brandon@aaron.sh>",
|
||||||
"Andreas Lind <andreas@one.com>",
|
"Andreas Lind <andreas@one.com>",
|
||||||
"Maurus Cuelenaere <mcuelenaere@gmail.com>",
|
"Maurus Cuelenaere <mcuelenaere@gmail.com>",
|
||||||
"Linus Unnebäck <linus@folkdatorn.se>"
|
"Linus Unnebäck <linus@folkdatorn.se>",
|
||||||
|
"Victor Mateevitsi <mvictoras@gmail.com>"
|
||||||
],
|
],
|
||||||
"description": "High performance Node.js module to resize JPEG, PNG, WebP and TIFF images using the libvips library",
|
"description": "High performance Node.js module to resize JPEG, PNG, WebP and TIFF images using the libvips library",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
245
preinstall.sh
245
preinstall.sh
@ -16,6 +16,10 @@ vips_version_minimum=7.40.0
|
|||||||
vips_version_latest_major_minor=7.42
|
vips_version_latest_major_minor=7.42
|
||||||
vips_version_latest_patch=3
|
vips_version_latest_patch=3
|
||||||
|
|
||||||
|
openslide_version_minimum=3.4.0
|
||||||
|
openslide_version_latest_major_minor=3.4
|
||||||
|
openslide_version_latest_patch=0
|
||||||
|
|
||||||
install_libvips_from_source() {
|
install_libvips_from_source() {
|
||||||
echo "Compiling libvips $vips_version_latest_major_minor.$vips_version_latest_patch from source"
|
echo "Compiling libvips $vips_version_latest_major_minor.$vips_version_latest_patch from source"
|
||||||
curl -O http://www.vips.ecs.soton.ac.uk/supported/$vips_version_latest_major_minor/vips-$vips_version_latest_major_minor.$vips_version_latest_patch.tar.gz
|
curl -O http://www.vips.ecs.soton.ac.uk/supported/$vips_version_latest_major_minor/vips-$vips_version_latest_major_minor.$vips_version_latest_patch.tar.gz
|
||||||
@ -31,32 +35,82 @@ install_libvips_from_source() {
|
|||||||
echo "Installed libvips $vips_version_latest_major_minor.$vips_version_latest_patch"
|
echo "Installed libvips $vips_version_latest_major_minor.$vips_version_latest_patch"
|
||||||
}
|
}
|
||||||
|
|
||||||
sorry() {
|
install_libopenslide_from_source() {
|
||||||
echo "Sorry, I don't yet know how to install libvips on $1"
|
echo "Compiling openslide $openslide_version_latest_major_minor.$openslide_version_latest_patch from source"
|
||||||
exit 1
|
curl -O -L https://github.com/openslide/openslide/releases/download/v$openslide_version_latest_major_minor.$openslide_version_latest_patch/openslide-$openslide_version_latest_major_minor.$openslide_version_latest_patch.tar.gz
|
||||||
|
tar xzvf openslide-$openslide_version_latest_major_minor.$openslide_version_latest_patch.tar.gz
|
||||||
|
cd openslide-$openslide_version_latest_major_minor.$openslide_version_latest_patch
|
||||||
|
PKG_CONFIG_PATH=$pkg_config_path ./configure $1
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
cd ..
|
||||||
|
rm -rf openslide-$openslide_version_latest_major_minor.$openslide_version_latest_patch
|
||||||
|
rm openslide-$openslide_version_latest_major_minor.$openslide_version_latest_patch.tar.gz
|
||||||
|
ldconfig
|
||||||
|
echo "Installed libopenslide $openslide_version_latest_major_minor.$openslide_version_latest_patch"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Is libvips already installed, and is it at least the minimum required version?
|
sorry() {
|
||||||
|
echo "Sorry, I don't yet know how to install lib$1 on $2"
|
||||||
if ! type pkg-config >/dev/null; then
|
exit 1
|
||||||
sorry "a system without pkg-config"
|
}
|
||||||
fi
|
|
||||||
|
|
||||||
pkg_config_path_homebrew=`which brew >/dev/null 2>&1 && eval $(brew --env) && echo $PKG_CONFIG_LIBDIR || true`
|
pkg_config_path_homebrew=`which brew >/dev/null 2>&1 && eval $(brew --env) && echo $PKG_CONFIG_LIBDIR || true`
|
||||||
pkg_config_path="$pkg_config_path_homebrew:$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig"
|
pkg_config_path="$pkg_config_path_homebrew:$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig"
|
||||||
|
|
||||||
PKG_CONFIG_PATH=$pkg_config_path pkg-config --exists vips
|
check_if_library_exists() {
|
||||||
|
PKG_CONFIG_PATH=$pkg_config_path pkg-config --exists $1
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
vips_version_found=$(PKG_CONFIG_PATH=$pkg_config_path pkg-config --modversion vips)
|
version_found=$(PKG_CONFIG_PATH=$pkg_config_path pkg-config --modversion $1)
|
||||||
pkg-config --atleast-version=$vips_version_minimum vips
|
PKG_CONFIG_PATH=$pkg_config_path pkg-config --atleast-version=$2 $1
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
# Found suitable version of libvips
|
# Found suitable version of libvips
|
||||||
echo "Found libvips $vips_version_found"
|
echo "Found lib$1 $version_found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo "Found lib$1 $version_found but require $2"
|
||||||
|
else
|
||||||
|
echo "Could not find lib$1 using a PKG_CONFIG_PATH of '$pkg_config_path'"
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
enable_openslide=0
|
||||||
|
# Is libvips already installed, and is it at least the minimum required version?
|
||||||
|
if [ $# -eq 1 ]; then
|
||||||
|
if [ "$1" = "--with-openslide" ]; then
|
||||||
|
echo "Installing vips with openslide support"
|
||||||
|
enable_openslide=1
|
||||||
|
else
|
||||||
|
echo "Sorry, $1 is not supported. Did you mean --with-openslide?"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! type pkg-config >/dev/null; then
|
||||||
|
sorry "vips" "a system without pkg-config"
|
||||||
|
fi
|
||||||
|
|
||||||
|
openslide_exists=0
|
||||||
|
if [ $enable_openslide -eq 1 ]; then
|
||||||
|
check_if_library_exists "openslide" "$openslide_version_minimum"
|
||||||
|
openslide_exists=$?
|
||||||
|
fi
|
||||||
|
|
||||||
|
check_if_library_exists "vips" "$vips_version_minimum"
|
||||||
|
vips_exists=$?
|
||||||
|
if [ $vips_exists -eq 1 ] && [ $enable_openslide -eq 1 ]; then
|
||||||
|
if [ $openslide_exists -eq 1 ]; then
|
||||||
|
# Check if vips compiled with openslide support
|
||||||
|
vips_with_openslide=`vips list classes | grep -i opensli`
|
||||||
|
if [ -z $vips_with_openslide ]; then
|
||||||
|
echo "Vips compiled without openslide support."
|
||||||
|
else
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
echo "Found libvips $vips_version_found but require $vips_version_minimum"
|
fi
|
||||||
else
|
elif [ $vips_exists -eq 1 ] && [ $enable_openslide -eq 0 ]; then
|
||||||
echo "Could not find libvips using a PKG_CONFIG_PATH of '$pkg_config_path'"
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Verify root/sudo access
|
# Verify root/sudo access
|
||||||
@ -65,20 +119,21 @@ if [ "$(id -u)" -ne "0" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# OS-specific installations of libvips follows
|
# OS-specific installations of libopenslide follows
|
||||||
|
# Either openslide does not exist, or vips is installed without openslide support
|
||||||
|
if [ $enable_openslide -eq 1 ] && [ -z $vips_with_openslide ] && [ $openslide_exists -eq 0 ]; then
|
||||||
case $(uname -s) in
|
case $(uname -s) in
|
||||||
*[Dd]arwin*)
|
*[Dd]arwin*)
|
||||||
# Mac OS
|
# Mac OS
|
||||||
echo "Detected Mac OS"
|
echo "Detected Mac OS"
|
||||||
if type "brew" > /dev/null; then
|
if type "brew" > /dev/null; then
|
||||||
echo "Installing libvips via homebrew"
|
echo "Installing libopenslide via homebrew"
|
||||||
brew install homebrew/science/vips --with-webp --with-graphicsmagick
|
brew install openslide
|
||||||
elif type "port" > /dev/null; then
|
elif type "port" > /dev/null; then
|
||||||
echo "Installing libvips via MacPorts"
|
echo "Installing libopenslide via MacPorts"
|
||||||
port install vips
|
port install openslide
|
||||||
else
|
else
|
||||||
sorry "Mac OS without homebrew or MacPorts"
|
sorry "openslide" "Mac OS without homebrew or MacPorts"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@ -89,8 +144,118 @@ case $(uname -s) in
|
|||||||
case "$DISTRO" in
|
case "$DISTRO" in
|
||||||
jessie|vivid)
|
jessie|vivid)
|
||||||
# Debian 8, Ubuntu 15
|
# Debian 8, Ubuntu 15
|
||||||
|
echo "Installing libopenslide via apt-get"
|
||||||
|
apt-get install -y libopenslide-dev
|
||||||
|
;;
|
||||||
|
trusty|utopic|qiana|rebecca)
|
||||||
|
# Ubuntu 14, Mint 17
|
||||||
|
echo "Installing libopenslide dependencies via apt-get"
|
||||||
|
apt-get install -y automake build-essential curl zlib1g-dev libopenjpeg-dev libpng12-dev libjpeg-dev libtiff5-dev libgdk-pixbuf2.0-dev libxml2-dev libsqlite3-dev libcairo2-dev libglib2.0-dev sqlite3 libsqlite3-dev
|
||||||
|
install_libopenslide_from_source
|
||||||
|
;;
|
||||||
|
precise|wheezy|maya)
|
||||||
|
# Debian 7, Ubuntu 12.04, Mint 13
|
||||||
|
echo "Installing libopenslide dependencies via apt-get"
|
||||||
|
apt-get install -y automake build-essential curl zlib1g-dev libopenjpeg-dev libpng12-dev libjpeg-dev libtiff5-dev libgdk-pixbuf2.0-dev libxml2-dev libsqlite3-dev libcairo2-dev libglib2.0-dev sqlite3 libsqlite3-dev
|
||||||
|
install_libopenslide_from_source
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Unsupported Debian-based OS
|
||||||
|
sorry "openslide" "Debian-based $DISTRO"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
elif [ -f /etc/redhat-release ]; then
|
||||||
|
# Red Hat Linux
|
||||||
|
RELEASE=$(cat /etc/redhat-release)
|
||||||
|
echo "Detected Red Hat Linux '$RELEASE'"
|
||||||
|
case $RELEASE in
|
||||||
|
"Red Hat Enterprise Linux release 7."*|"CentOS Linux release 7."*|"Scientific Linux release 7."*)
|
||||||
|
# RHEL/CentOS 7
|
||||||
|
echo "Installing libopenslide dependencies via yum"
|
||||||
|
yum groupinstall -y "Development Tools"
|
||||||
|
yum install -y tar curl libpng-devel libjpeg-devel libxml2-devel zlib-devel openjpeg-devel libtiff-devel gdk-pixbuf2-devel sqlite-devel cairo-devel glib2-devel
|
||||||
|
install_libopenslide_from_source "--prefix=/usr"
|
||||||
|
;;
|
||||||
|
"Red Hat Enterprise Linux release 6."*|"CentOS release 6."*|"Scientific Linux release 6."*)
|
||||||
|
# RHEL/CentOS 6
|
||||||
|
echo "Installing libopenslide dependencies via yum"
|
||||||
|
yum groupinstall -y "Development Tools"
|
||||||
|
yum install -y tar curl libpng-devel libjpeg-devel libxml2-devel zlib-devel openjpeg-devel libtiff-devel gdk-pixbuf2-devel sqlite-devel cairo-devel glib2-devel
|
||||||
|
install_libopenslide_from_source "--prefix=/usr"
|
||||||
|
;;
|
||||||
|
"Fedora release 21 "*|"Fedora release 22 "*)
|
||||||
|
# Fedora 21, 22
|
||||||
|
echo "Installing libopenslide via yum"
|
||||||
|
yum install -y openslide-devel
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Unsupported RHEL-based OS
|
||||||
|
sorry "openslide" "$RELEASE"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
elif [ -f /etc/os-release ]; then
|
||||||
|
RELEASE=$(cat /etc/os-release | grep VERSION)
|
||||||
|
echo "Detected OpenSuse Linux '$RELEASE'"
|
||||||
|
case $RELEASE in
|
||||||
|
*"13.2"*)
|
||||||
|
echo "Installing libopenslide via zypper"
|
||||||
|
zypper --gpg-auto-import-keys install -y libopenslide-devel
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
elif [ -f /etc/SuSE-brand ]; then
|
||||||
|
RELEASE=$(cat /etc/SuSE-brand | grep VERSION)
|
||||||
|
echo "Detected OpenSuse Linux '$RELEASE'"
|
||||||
|
case $RELEASE in
|
||||||
|
*"13.1")
|
||||||
|
echo "Installing libopenslide dependencies via zypper"
|
||||||
|
zypper --gpg-auto-import-keys install -y --type pattern devel_basis
|
||||||
|
zypper --gpg-auto-import-keys install -y tar curl libpng16-devel libjpeg-turbo libjpeg8-devel libxml2-devel zlib-devel openjpeg-devel libtiff-devel libgdk_pixbuf-2_0-0 sqlite3-devel cairo-devel glib2-devel
|
||||||
|
install_libopenslide_from_source
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
# Unsupported OS
|
||||||
|
sorry "openslide" "$(uname -a)"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# OS-specific installations of libvips follows
|
||||||
|
|
||||||
|
case $(uname -s) in
|
||||||
|
*[Dd]arwin*)
|
||||||
|
# Mac OS
|
||||||
|
echo "Detected Mac OS"
|
||||||
|
if type "brew" > /dev/null; then
|
||||||
|
echo "Installing libvips via homebrew"
|
||||||
|
if [ $enable_openslide -eq 1 ]; then
|
||||||
|
brew install homebrew/science/vips --with-webp --with-graphicsmagick --with-openslide
|
||||||
|
else
|
||||||
|
brew install homebrew/science/vips --with-webp --with-graphicsmagick
|
||||||
|
fi
|
||||||
|
elif type "port" > /dev/null; then
|
||||||
|
echo "Installing libvips via MacPorts"
|
||||||
|
port install vips
|
||||||
|
else
|
||||||
|
sorry "vips" "Mac OS without homebrew or MacPorts"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ -f /etc/debian_version ]; then
|
||||||
|
# Debian Linux
|
||||||
|
DISTRO=$(lsb_release -c -s)
|
||||||
|
echo "Detected Debian Linux '$DISTRO'"
|
||||||
|
case "$DISTRO" in
|
||||||
|
jessie|vivid)
|
||||||
|
# Debian 8, Ubuntu 15
|
||||||
|
if [ $enable_openslide -eq 1 ]; then
|
||||||
echo "Installing libvips via apt-get"
|
echo "Installing libvips via apt-get"
|
||||||
apt-get install -y libvips-dev libgsf-1-dev
|
apt-get install -y libvips-dev libgsf-1-dev
|
||||||
|
else
|
||||||
|
echo "Recompiling vips with openslide support"
|
||||||
|
install_libvips_from_source
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
trusty|utopic|qiana|rebecca)
|
trusty|utopic|qiana|rebecca)
|
||||||
# Ubuntu 14, Mint 17
|
# Ubuntu 14, Mint 17
|
||||||
@ -108,7 +273,7 @@ case $(uname -s) in
|
|||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
# Unsupported Debian-based OS
|
# Unsupported Debian-based OS
|
||||||
sorry "Debian-based $DISTRO"
|
sorry "vips" "Debian-based $DISTRO"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
elif [ -f /etc/redhat-release ]; then
|
elif [ -f /etc/redhat-release ]; then
|
||||||
@ -136,12 +301,20 @@ case $(uname -s) in
|
|||||||
;;
|
;;
|
||||||
"Fedora release 21 "*|"Fedora release 22 "*)
|
"Fedora release 21 "*|"Fedora release 22 "*)
|
||||||
# Fedora 21, 22
|
# Fedora 21, 22
|
||||||
|
if [ $enable_openslide -eq 1 ]; then
|
||||||
|
echo "Installing libvips dependencies via yum"
|
||||||
|
yum groupinstall -y "Development Tools"
|
||||||
|
yum install -y gcc-c++ gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel lcms-devel ImageMagick-devel gobject-introspection-devel libwebp-devel curl
|
||||||
|
echo "Compiling vips with openslide support"
|
||||||
|
install_libvips_from_source "--prefix=/usr"
|
||||||
|
else
|
||||||
echo "Installing libvips via yum"
|
echo "Installing libvips via yum"
|
||||||
yum install -y vips-devel
|
yum install -y vips-devel
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
# Unsupported RHEL-based OS
|
# Unsupported RHEL-based OS
|
||||||
sorry "$RELEASE"
|
sorry "vips" "$RELEASE"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
elif [ -f /etc/system-release ]; then
|
elif [ -f /etc/system-release ]; then
|
||||||
@ -157,9 +330,31 @@ case $(uname -s) in
|
|||||||
install_libvips_from_source "--prefix=/usr"
|
install_libvips_from_source "--prefix=/usr"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
elif [ -f /etc/os-release ]; then
|
||||||
|
RELEASE=$(cat /etc/os-release | grep VERSION)
|
||||||
|
echo "Detected OpenSuse Linux '$RELEASE'"
|
||||||
|
case $RELEASE in
|
||||||
|
*"13.2"*)
|
||||||
|
echo "Installing libvips dependencies via zypper"
|
||||||
|
zypper --gpg-auto-import-keys install -y --type pattern devel_basis
|
||||||
|
zypper --gpg-auto-import-keys install -y tar curl gtk-doc libxml2-devel libjpeg-turbo libjpeg8-devel libpng16-devel libtiff-devel libexif-devel liblcms2-devel ImageMagick-devel gobject-introspection-devel libwebp-devel
|
||||||
|
install_libvips_from_source
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
elif [ -f /etc/SuSE-brand ]; then
|
||||||
|
RELEASE=$(cat /etc/SuSE-brand | grep VERSION)
|
||||||
|
echo "Detected OpenSuse Linux '$RELEASE'"
|
||||||
|
case $RELEASE in
|
||||||
|
*"13.1")
|
||||||
|
echo "Installing libvips dependencies via zypper"
|
||||||
|
zypper --gpg-auto-import-keys install -y --type pattern devel_basis
|
||||||
|
zypper --gpg-auto-import-keys install -y tar curl gtk-doc libxml2-devel libjpeg-turbo libjpeg8-devel libpng16-devel libtiff-devel libexif-devel liblcms2-devel ImageMagick-devel gobject-introspection-devel libwebp-devel
|
||||||
|
install_libvips_from_source
|
||||||
|
;;
|
||||||
|
esac
|
||||||
else
|
else
|
||||||
# Unsupported OS
|
# Unsupported OS
|
||||||
sorry "$(uname -a)"
|
sorry "vips" "$(uname -a)"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
@ -28,6 +28,9 @@ namespace sharp {
|
|||||||
bool IsTiff(std::string const &str) {
|
bool IsTiff(std::string const &str) {
|
||||||
return EndsWith(str, ".tif") || EndsWith(str, ".tiff") || EndsWith(str, ".TIF") || EndsWith(str, ".TIFF");
|
return EndsWith(str, ".tif") || EndsWith(str, ".tiff") || EndsWith(str, ".TIF") || EndsWith(str, ".TIFF");
|
||||||
}
|
}
|
||||||
|
bool IsDz(std::string const &str) {
|
||||||
|
return EndsWith(str, ".dzi") || EndsWith(str, ".DZI");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Determine image format of a buffer.
|
Determine image format of a buffer.
|
||||||
@ -103,6 +106,7 @@ namespace sharp {
|
|||||||
} else if(vips_foreign_is_a("magickload", file)) {
|
} else if(vips_foreign_is_a("magickload", file)) {
|
||||||
imageType = ImageType::MAGICK;
|
imageType = ImageType::MAGICK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return imageType;
|
return imageType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,8 @@ namespace sharp {
|
|||||||
PNG,
|
PNG,
|
||||||
WEBP,
|
WEBP,
|
||||||
TIFF,
|
TIFF,
|
||||||
MAGICK
|
MAGICK,
|
||||||
|
DZ
|
||||||
};
|
};
|
||||||
|
|
||||||
// How many tasks are in the queue?
|
// How many tasks are in the queue?
|
||||||
@ -23,6 +24,7 @@ namespace sharp {
|
|||||||
bool IsPng(std::string const &str);
|
bool IsPng(std::string const &str);
|
||||||
bool IsWebp(std::string const &str);
|
bool IsWebp(std::string const &str);
|
||||||
bool IsTiff(std::string const &str);
|
bool IsTiff(std::string const &str);
|
||||||
|
bool IsDz(std::string const &str);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Determine image format of a buffer.
|
Determine image format of a buffer.
|
||||||
|
@ -90,6 +90,7 @@ class MetadataWorker : public NanAsyncWorker {
|
|||||||
case ImageType::WEBP: baton->format = "webp"; break;
|
case ImageType::WEBP: baton->format = "webp"; break;
|
||||||
case ImageType::TIFF: baton->format = "tiff"; break;
|
case ImageType::TIFF: baton->format = "tiff"; break;
|
||||||
case ImageType::MAGICK: baton->format = "magick"; break;
|
case ImageType::MAGICK: baton->format = "magick"; break;
|
||||||
|
case ImageType::DZ: baton->format = "dzi"; break;
|
||||||
case ImageType::UNKNOWN: break;
|
case ImageType::UNKNOWN: break;
|
||||||
}
|
}
|
||||||
// VipsImage attributes
|
// VipsImage attributes
|
||||||
|
@ -32,6 +32,7 @@ using sharp::IsJpeg;
|
|||||||
using sharp::IsPng;
|
using sharp::IsPng;
|
||||||
using sharp::IsWebp;
|
using sharp::IsWebp;
|
||||||
using sharp::IsTiff;
|
using sharp::IsTiff;
|
||||||
|
using sharp::IsDz;
|
||||||
using sharp::counterProcess;
|
using sharp::counterProcess;
|
||||||
using sharp::counterQueue;
|
using sharp::counterQueue;
|
||||||
|
|
||||||
@ -94,6 +95,8 @@ struct ResizeBaton {
|
|||||||
bool withoutChromaSubsampling;
|
bool withoutChromaSubsampling;
|
||||||
std::string err;
|
std::string err;
|
||||||
bool withMetadata;
|
bool withMetadata;
|
||||||
|
int tileSize;
|
||||||
|
int tileOverlap;
|
||||||
|
|
||||||
ResizeBaton():
|
ResizeBaton():
|
||||||
bufferInLength(0),
|
bufferInLength(0),
|
||||||
@ -120,7 +123,9 @@ struct ResizeBaton {
|
|||||||
compressionLevel(6),
|
compressionLevel(6),
|
||||||
withoutAdaptiveFiltering(false),
|
withoutAdaptiveFiltering(false),
|
||||||
withoutChromaSubsampling(false),
|
withoutChromaSubsampling(false),
|
||||||
withMetadata(false) {
|
withMetadata(false),
|
||||||
|
tileSize(256),
|
||||||
|
tileOverlap(0) {
|
||||||
background[0] = 0.0;
|
background[0] = 0.0;
|
||||||
background[1] = 0.0;
|
background[1] = 0.0;
|
||||||
background[2] = 0.0;
|
background[2] = 0.0;
|
||||||
@ -755,7 +760,8 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
bool outputPng = IsPng(baton->output);
|
bool outputPng = IsPng(baton->output);
|
||||||
bool outputWebp = IsWebp(baton->output);
|
bool outputWebp = IsWebp(baton->output);
|
||||||
bool outputTiff = IsTiff(baton->output);
|
bool outputTiff = IsTiff(baton->output);
|
||||||
bool matchInput = !(outputJpeg || outputPng || outputWebp || outputTiff);
|
bool outputDz = IsDz(baton->output);
|
||||||
|
bool matchInput = !(outputJpeg || outputPng || outputWebp || outputTiff || outputDz);
|
||||||
if (outputJpeg || (matchInput && inputImageType == ImageType::JPEG)) {
|
if (outputJpeg || (matchInput && inputImageType == ImageType::JPEG)) {
|
||||||
// Write JPEG to file
|
// Write JPEG to file
|
||||||
if (vips_jpegsave(image, baton->output.c_str(), "strip", !baton->withMetadata,
|
if (vips_jpegsave(image, baton->output.c_str(), "strip", !baton->withMetadata,
|
||||||
@ -795,6 +801,14 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
baton->outputFormat = "tiff";
|
baton->outputFormat = "tiff";
|
||||||
|
} else if (outputDz || matchInput) {
|
||||||
|
// Write DZ to file
|
||||||
|
std::string filename_no_extension = baton->output.substr(0, baton->output.length() - 4);
|
||||||
|
if (vips_dzsave(image, filename_no_extension.c_str(), "strip", !baton->withMetadata,
|
||||||
|
"tile_size", baton->tileSize, "overlap", baton->tileOverlap, NULL)) {
|
||||||
|
return Error(baton, hook);
|
||||||
|
}
|
||||||
|
baton->outputFormat = "dz";
|
||||||
} else {
|
} else {
|
||||||
(baton->err).append("Unsupported output " + baton->output);
|
(baton->err).append("Unsupported output " + baton->output);
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
@ -828,8 +842,13 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
// Info Object
|
// Info Object
|
||||||
Local<Object> info = NanNew<Object>();
|
Local<Object> info = NanNew<Object>();
|
||||||
info->Set(NanNew<String>("format"), NanNew<String>(baton->outputFormat));
|
info->Set(NanNew<String>("format"), NanNew<String>(baton->outputFormat));
|
||||||
info->Set(NanNew<String>("width"), NanNew<Integer>(width));
|
info->Set(NanNew<String>("width"), NanNew<Uint32>(static_cast<uint32_t>(width)));
|
||||||
info->Set(NanNew<String>("height"), NanNew<Integer>(height));
|
info->Set(NanNew<String>("height"), NanNew<Uint32>(static_cast<uint32_t>(height)));
|
||||||
|
|
||||||
|
if (baton->outputFormat == "dz" ) {
|
||||||
|
info->Set(NanNew<String>("tileSize"), NanNew<Uint32>(static_cast<uint32_t>(baton->tileSize)));
|
||||||
|
info->Set(NanNew<String>("tileOverlap"), NanNew<Uint32>(static_cast<uint32_t>(baton->tileOverlap)));
|
||||||
|
}
|
||||||
|
|
||||||
if (baton->bufferOutLength > 0) {
|
if (baton->bufferOutLength > 0) {
|
||||||
// Copy data to new Buffer
|
// Copy data to new Buffer
|
||||||
@ -1017,6 +1036,8 @@ NAN_METHOD(resize) {
|
|||||||
baton->withMetadata = options->Get(NanNew<String>("withMetadata"))->BooleanValue();
|
baton->withMetadata = options->Get(NanNew<String>("withMetadata"))->BooleanValue();
|
||||||
// Output filename or __format for Buffer
|
// Output filename or __format for Buffer
|
||||||
baton->output = *String::Utf8Value(options->Get(NanNew<String>("output"))->ToString());
|
baton->output = *String::Utf8Value(options->Get(NanNew<String>("output"))->ToString());
|
||||||
|
baton->tileSize = options->Get(NanNew<String>("tileSize"))->Int32Value();
|
||||||
|
baton->tileOverlap = options->Get(NanNew<String>("tileOverlap"))->Int32Value();
|
||||||
|
|
||||||
// Join queue for worker thread
|
// Join queue for worker thread
|
||||||
NanCallback *callback = new NanCallback(args[1].As<Function>());
|
NanCallback *callback = new NanCallback(args[1].As<Function>());
|
||||||
|
BIN
test/fixtures/CMU-1-Small-Region.svs
vendored
Normal file
BIN
test/fixtures/CMU-1-Small-Region.svs
vendored
Normal file
Binary file not shown.
2
test/fixtures/index.js
vendored
2
test/fixtures/index.js
vendored
@ -25,6 +25,8 @@ module.exports = {
|
|||||||
inputSvg: getPath('Wikimedia-logo.svg'), // http://commons.wikimedia.org/wiki/File:Wikimedia-logo.svg
|
inputSvg: getPath('Wikimedia-logo.svg'), // http://commons.wikimedia.org/wiki/File:Wikimedia-logo.svg
|
||||||
inputPsd: getPath('free-gearhead-pack.psd'), // https://dribbble.com/shots/1624241-Free-Gearhead-Vector-Pack
|
inputPsd: getPath('free-gearhead-pack.psd'), // https://dribbble.com/shots/1624241-Free-Gearhead-Vector-Pack
|
||||||
|
|
||||||
|
inputSvs: getPath('CMU-1-Small-Region.svs'), // http://openslide.cs.cmu.edu/download/openslide-testdata/Aperio/CMU-1-Small-Region.svs
|
||||||
|
|
||||||
outputJpg: getPath('output.jpg'),
|
outputJpg: getPath('output.jpg'),
|
||||||
outputPng: getPath('output.png'),
|
outputPng: getPath('output.png'),
|
||||||
outputWebP: getPath('output.webp'),
|
outputWebP: getPath('output.webp'),
|
||||||
|
@ -519,6 +519,42 @@ describe('Input/output', function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sharp.format.dz.output.file) {
|
||||||
|
it('Convert JPEG to DZ', function(done) {
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.resize(320, 240)
|
||||||
|
.toFormat(sharp.format.dz)
|
||||||
|
.toFile(fixtures.path('output.jpg.dzi'), function(err, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, info.size > 0);
|
||||||
|
assert.strictEqual('dz', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
assert.strictEqual(256, info.tileSize);
|
||||||
|
assert.strictEqual(0, info.tileOverlap);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Convert JPEG to DZ (test tileSize and tileOverlap)', function(done) {
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.resize(320, 240)
|
||||||
|
.toFormat(sharp.format.dz)
|
||||||
|
.tileSize(512)
|
||||||
|
.tileOverlap(10)
|
||||||
|
.toFile(fixtures.path('output.tileTest.jpg.dzi'), function(err, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, info.size > 0);
|
||||||
|
assert.strictEqual('dz', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
assert.strictEqual(512, info.tileSize);
|
||||||
|
assert.strictEqual(10, info.tileOverlap);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (sharp.format.tiff.input.buffer) {
|
if (sharp.format.tiff.input.buffer) {
|
||||||
it('Load TIFF from Buffer', function(done) {
|
it('Load TIFF from Buffer', function(done) {
|
||||||
var inputTiffBuffer = fs.readFileSync(fixtures.inputTiff);
|
var inputTiffBuffer = fs.readFileSync(fixtures.inputTiff);
|
||||||
@ -668,4 +704,65 @@ describe('Input/output', function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(sharp.format.openslide.input.file) {
|
||||||
|
describe('Openslide output', function() {
|
||||||
|
it('Aperio - convert SVS to PNG', function(done) {
|
||||||
|
sharp(fixtures.inputSvs)
|
||||||
|
.toFile(fixtures.path('output.svs.png'), function(err, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, info.size > 0);
|
||||||
|
assert.strictEqual('png', info.format);
|
||||||
|
assert.strictEqual(2220, info.width);
|
||||||
|
assert.strictEqual(2967, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('Aperio - convert SVS to JPEG', function(done) {
|
||||||
|
sharp(fixtures.inputSvs)
|
||||||
|
.toFile(fixtures.path('output.svs.jpeg'), function(err, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, info.size > 0);
|
||||||
|
assert.strictEqual('jpeg', info.format);
|
||||||
|
assert.strictEqual(2220, info.width);
|
||||||
|
assert.strictEqual(2967, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('Aperio - convert SVS to TIFF', function(done) {
|
||||||
|
sharp(fixtures.inputSvs)
|
||||||
|
.toFile(fixtures.path('output.svs.tiff'), function(err, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, info.size > 0);
|
||||||
|
assert.strictEqual('tiff', info.format);
|
||||||
|
assert.strictEqual(2220, info.width);
|
||||||
|
assert.strictEqual(2967, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('Aperio - convert SVS to WEBP', function(done) {
|
||||||
|
sharp(fixtures.inputSvs)
|
||||||
|
.toFile(fixtures.path('output.svs.webp'), function(err, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, info.size > 0);
|
||||||
|
assert.strictEqual('webp', info.format);
|
||||||
|
assert.strictEqual(2220, info.width);
|
||||||
|
assert.strictEqual(2967, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('Aperio - convert SVS to DZI', function(done) {
|
||||||
|
sharp(fixtures.inputSvs)
|
||||||
|
.toFile(fixtures.path('output.aperio.svs.dzi'), function(err, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, info.size > 0);
|
||||||
|
assert.strictEqual('dz', info.format);
|
||||||
|
assert.strictEqual(2220, info.width);
|
||||||
|
assert.strictEqual(2967, info.height);
|
||||||
|
assert.strictEqual(256, info.tileSize);
|
||||||
|
assert.strictEqual(0, info.tileOverlap);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user