Compare commits

..

5 Commits

Author SHA1 Message Date
Lovell Fuller
1cce56b024 Use tile cache for interlace output
Doubles performance of Adam7 interlaced PNG output
2014-07-09 23:47:04 +01:00
Lovell Fuller
2126f9afc1 Ensure xcode/clang uses cflags
Silence pedantic warnings triggered by V8 in 0.11
2014-07-09 21:14:40 +01:00
Lovell Fuller
41420eedcf Add details of Heroku buildpack, thanks @alex88 #57 2014-07-06 13:20:41 +01:00
Lovell Fuller
1b6ab19b6d Remove fftw dependency when compiling libvips from src #57 2014-07-03 21:12:18 +01:00
Lovell Fuller
fbe5c18762 Expose depth of task queue 2014-06-25 23:21:39 +01:00
6 changed files with 63 additions and 29 deletions

View File

@@ -5,12 +5,12 @@ node_js:
before_install: before_install:
- sudo add-apt-repository ppa:lyrasis/precise-backports -y - sudo add-apt-repository ppa:lyrasis/precise-backports -y
- sudo apt-get update -qq - sudo apt-get update -qq
- sudo apt-get install -qq automake gobject-introspection gtk-doc-tools libfftw3-dev libglib2.0-dev libjpeg-turbo8-dev libpng12-dev libwebp-dev libtiff4-dev libexif-dev libxml2-dev swig graphicsmagick libmagick++-dev - sudo apt-get install -qq automake gobject-introspection gtk-doc-tools libglib2.0-dev libjpeg-turbo8-dev libpng12-dev libwebp-dev libtiff4-dev libexif-dev libxml2-dev swig graphicsmagick libmagick++-dev
- git clone https://github.com/jcupitt/libvips.git - git clone https://github.com/jcupitt/libvips.git
- cd libvips - cd libvips
- git checkout 7.38 - git checkout 7.38
- ./bootstrap.sh - ./bootstrap.sh
- ./configure --enable-debug=no --enable-cxx=yes --without-orc --without-python - ./configure --enable-debug=no --enable-cxx=yes --without-orc --without-python --without-fftw
- make - make
- sudo make install - sudo make install
- sudo ldconfig - sudo ldconfig

View File

@@ -48,12 +48,12 @@ The _gettext_ dependency of _libvips_ [can lead](https://github.com/lovell/sharp
Compiling from source is recommended: Compiling from source is recommended:
sudo apt-get install automake build-essential git gobject-introspection gtk-doc-tools libfftw3-dev libglib2.0-dev libjpeg-turbo8-dev libpng12-dev libwebp-dev libtiff5-dev libexif-dev libxml2-dev swig sudo apt-get install automake build-essential git gobject-introspection gtk-doc-tools libglib2.0-dev libjpeg-turbo8-dev libpng12-dev libwebp-dev libtiff5-dev libexif-dev libxml2-dev swig
git clone https://github.com/jcupitt/libvips.git git clone https://github.com/jcupitt/libvips.git
cd libvips cd libvips
git checkout 7.38 git checkout 7.38
./bootstrap.sh ./bootstrap.sh
./configure --enable-debug=no --enable-cxx=yes --without-python --without-orc ./configure --enable-debug=no --enable-cxx=yes --without-python --without-orc --without-fftw
make make
sudo make install sudo make install
sudo ldconfig sudo ldconfig
@@ -68,6 +68,10 @@ Requires `libtiff4-dev` instead of `libtiff5-dev` and has [a bug](https://bugs.l
Then follow Ubuntu 13.x instructions. Then follow Ubuntu 13.x instructions.
### Install libvips on Heroku
[Alessandro Tagliapietra](https://github.com/alex88) maintains an [Heroku buildpack for libvips](https://github.com/alex88/heroku-buildpack-vips) and its dependencies.
## Usage examples ## Usage examples
```javascript ```javascript
@@ -160,11 +164,11 @@ Embed the resized image on a black background of the exact size specified.
### rotate([angle]) ### rotate([angle])
Rotate the output image by either an explicit angle or auto-orient based on the EXIF `Orientation` tag. Mirroring is not supported. Rotate the output image by either an explicit angle or auto-orient based on the EXIF `Orientation` tag.
`angle`, if present, is a Number with a value of `0`, `90`, `180` or `270`. `angle`, if present, is a Number with a value of `0`, `90`, `180` or `270`.
Use this method without `angle` to determine the angle from EXIF data. Use this method without `angle` to determine the angle from EXIF data. Mirroring is currently unsupported.
### withoutEnlargement() ### withoutEnlargement()
@@ -257,9 +261,9 @@ This method always returns cache statistics, useful for determining how much wor
Warnings such as _Application transferred too many scanlines_ are a good indicator you've set this value too low. Warnings such as _Application transferred too many scanlines_ are a good indicator you've set this value too low.
```javascript ```javascript
var stats = sharp.cache(); // { current: 98, high: 115, limit: 100 } var stats = sharp.cache(); // { current: 98, high: 115, limit: 100, queue: 0 }
sharp.cache(200); // { current: 98, high: 115, limit: 200 } sharp.cache(200); // { current: 98, high: 115, limit: 200, queue: 0 }
sharp.cache(50); // { current: 49, high: 115, limit: 50 } sharp.cache(50); // { current: 49, high: 115, limit: 50, queue: 0 }
``` ```
## Testing ## Testing

View File

@@ -12,7 +12,10 @@
'<!(PKG_CONFIG_PATH="<(PKG_CONFIG_PATH)" pkg-config --cflags vips glib-2.0)', '<!(PKG_CONFIG_PATH="<(PKG_CONFIG_PATH)" pkg-config --cflags vips glib-2.0)',
'<!(node -e "require(\'nan\')")' '<!(node -e "require(\'nan\')")'
], ],
'cflags': ['-fexceptions', '-pedantic', '-Wall', '-O3'], 'cflags': ['-fexceptions', '-Wall', '-O3'],
'cflags_cc': ['-fexceptions', '-pedantic', '-Wall', '-O3'] 'cflags_cc': ['-fexceptions', '-Wall', '-O3'],
'xcode_settings': {
'OTHER_CFLAGS': ['-fexceptions', '-Wall', '-O3']
}
}] }]
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "sharp", "name": "sharp",
"version": "0.5.1", "version": "0.5.2",
"author": "Lovell Fuller <npm@lovell.info>", "author": "Lovell Fuller <npm@lovell.info>",
"contributors": [ "contributors": [
"Pierre Inglebert <pierre.inglebert@gmail.com>", "Pierre Inglebert <pierre.inglebert@gmail.com>",
@@ -33,11 +33,11 @@
], ],
"dependencies": { "dependencies": {
"nan": "^1.2.0", "nan": "^1.2.0",
"bluebird": "^2.1.2" "bluebird": "^2.2.1"
}, },
"devDependencies": { "devDependencies": {
"imagemagick": "^0.1.3", "imagemagick": "^0.1.3",
"imagemagick-native": "^1.1.1", "imagemagick-native": "^1.2.2",
"gm": "^1.16.0", "gm": "^1.16.0",
"async": "^0.9.0", "async": "^0.9.0",
"benchmark": "^1.0.0" "benchmark": "^1.0.0"

View File

@@ -54,6 +54,9 @@ unsigned char const MARKER_JPEG[] = {0xff, 0xd8};
unsigned char const MARKER_PNG[] = {0x89, 0x50}; unsigned char const MARKER_PNG[] = {0x89, 0x50};
unsigned char const MARKER_WEBP[] = {0x52, 0x49}; unsigned char const MARKER_WEBP[] = {0x52, 0x49};
// How many tasks are in the queue?
volatile int queue_length = 0;
static bool ends_with(std::string const &str, std::string const &end) { static bool ends_with(std::string const &str, std::string const &end) {
return str.length() >= end.length() && 0 == str.compare(str.length() - end.length(), end.length(), end); return str.length() >= end.length() && 0 == str.compare(str.length() - end.length(), end.length(), end);
} }
@@ -370,46 +373,58 @@ class ResizeWorker : public NanAsyncWorker {
vips_colourspace(sharpened, &colourspaced, VIPS_INTERPRETATION_sRGB, NULL); vips_colourspace(sharpened, &colourspaced, VIPS_INTERPRETATION_sRGB, NULL);
g_object_unref(sharpened); g_object_unref(sharpened);
// Generate image tile cache when interlace output is required
VipsImage *cached = vips_image_new();
if (baton->progressive) {
if (vips_tilecache(colourspaced, &cached, "threaded", TRUE, "persistent", TRUE, "max_tiles", -1, NULL)) {
return resize_error(baton, colourspaced);
}
} else {
vips_copy(colourspaced, &cached, NULL);
}
g_object_unref(colourspaced);
// Output // Output
VipsImage *output = cached;
if (baton->file_out == "__jpeg" || (baton->file_out == "__input" && inputImageType == JPEG)) { if (baton->file_out == "__jpeg" || (baton->file_out == "__input" && inputImageType == JPEG)) {
// Write JPEG to buffer // Write JPEG to buffer
if (vips_jpegsave_buffer(colourspaced, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progressive, NULL)) { if (vips_jpegsave_buffer(output, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progressive, NULL)) {
return resize_error(baton, colourspaced); return resize_error(baton, output);
} }
} else if (baton->file_out == "__png" || (baton->file_out == "__input" && inputImageType == PNG)) { } else if (baton->file_out == "__png" || (baton->file_out == "__input" && inputImageType == PNG)) {
// Write PNG to buffer // Write PNG to buffer
if (vips_pngsave_buffer(colourspaced, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "compression", baton->compressionLevel, "interlace", baton->progressive, NULL)) { if (vips_pngsave_buffer(output, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "compression", baton->compressionLevel, "interlace", baton->progressive, NULL)) {
return resize_error(baton, colourspaced); return resize_error(baton, output);
} }
} else if (baton->file_out == "__webp" || (baton->file_out == "__input" && inputImageType == WEBP)) { } else if (baton->file_out == "__webp" || (baton->file_out == "__input" && inputImageType == WEBP)) {
// Write WEBP to buffer // Write WEBP to buffer
if (vips_webpsave_buffer(colourspaced, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "Q", baton->quality, NULL)) { if (vips_webpsave_buffer(output, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "Q", baton->quality, NULL)) {
return resize_error(baton, colourspaced); return resize_error(baton, output);
} }
} else if (is_jpeg(baton->file_out)) { } else if (is_jpeg(baton->file_out)) {
// Write JPEG to file // Write JPEG to file
if (vips_jpegsave(colourspaced, baton->file_out.c_str(), "strip", TRUE, "Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progressive, NULL)) { if (vips_jpegsave(output, baton->file_out.c_str(), "strip", TRUE, "Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progressive, NULL)) {
return resize_error(baton, colourspaced); return resize_error(baton, output);
} }
} else if (is_png(baton->file_out)) { } else if (is_png(baton->file_out)) {
// Write PNG to file // Write PNG to file
if (vips_pngsave(colourspaced, baton->file_out.c_str(), "strip", TRUE, "compression", baton->compressionLevel, "interlace", baton->progressive, NULL)) { if (vips_pngsave(output, baton->file_out.c_str(), "strip", TRUE, "compression", baton->compressionLevel, "interlace", baton->progressive, NULL)) {
return resize_error(baton, colourspaced); return resize_error(baton, output);
} }
} else if (is_webp(baton->file_out)) { } else if (is_webp(baton->file_out)) {
// Write WEBP to file // Write WEBP to file
if (vips_webpsave(colourspaced, baton->file_out.c_str(), "strip", TRUE, "Q", baton->quality, NULL)) { if (vips_webpsave(output, baton->file_out.c_str(), "strip", TRUE, "Q", baton->quality, NULL)) {
return resize_error(baton, colourspaced); return resize_error(baton, output);
} }
} else if (is_tiff(baton->file_out)) { } else if (is_tiff(baton->file_out)) {
// Write TIFF to file // Write TIFF to file
if (vips_tiffsave(colourspaced, baton->file_out.c_str(), "strip", TRUE, "compression", VIPS_FOREIGN_TIFF_COMPRESSION_JPEG, "Q", baton->quality, NULL)) { if (vips_tiffsave(output, baton->file_out.c_str(), "strip", TRUE, "compression", VIPS_FOREIGN_TIFF_COMPRESSION_JPEG, "Q", baton->quality, NULL)) {
return resize_error(baton, colourspaced); return resize_error(baton, output);
} }
} else { } else {
(baton->err).append("Unsupported output " + baton->file_out); (baton->err).append("Unsupported output " + baton->file_out);
} }
g_object_unref(colourspaced); g_object_unref(output);
vips_thread_shutdown(); vips_thread_shutdown();
} }
@@ -427,6 +442,8 @@ class ResizeWorker : public NanAsyncWorker {
} }
delete baton; delete baton;
callback->Call(2, argv); callback->Call(2, argv);
// Decrement queue length
g_atomic_int_dec_and_test(&queue_length);
} }
private: private:
@@ -480,6 +497,10 @@ NAN_METHOD(resize) {
// Join queue for worker thread // Join queue for worker thread
NanCallback *callback = new NanCallback(args[2].As<v8::Function>()); NanCallback *callback = new NanCallback(args[2].As<v8::Function>());
NanAsyncQueueWorker(new ResizeWorker(callback, baton)); NanAsyncQueueWorker(new ResizeWorker(callback, baton));
// Increment queue length
g_atomic_int_inc(&queue_length);
NanReturnUndefined(); NanReturnUndefined();
} }
@@ -496,6 +517,7 @@ NAN_METHOD(cache) {
cache->Set(NanNew<String>("current"), NanNew<Number>(vips_tracked_get_mem() / 1048576)); cache->Set(NanNew<String>("current"), NanNew<Number>(vips_tracked_get_mem() / 1048576));
cache->Set(NanNew<String>("high"), NanNew<Number>(vips_tracked_get_mem_highwater() / 1048576)); cache->Set(NanNew<String>("high"), NanNew<Number>(vips_tracked_get_mem_highwater() / 1048576));
cache->Set(NanNew<String>("limit"), NanNew<Number>(vips_cache_get_max_mem() / 1048576)); cache->Set(NanNew<String>("limit"), NanNew<Number>(vips_cache_get_max_mem() / 1048576));
cache->Set(NanNew<String>("queue"), NanNew<Number>(queue_length));
NanReturnValue(cache); NanReturnValue(cache);
} }

View File

@@ -8,6 +8,10 @@ var inputJpg = path.join(__dirname, "fixtures/2569067123_aca715a2ee_o.jpg"); //
var width = 720; var width = 720;
var height = 480; var height = 480;
var timer = setInterval(function() {
console.dir(sharp.cache());
}, 100);
async.mapSeries([1, 1, 2, 4, 8, 16, 32, 64, 128], function(parallelism, next) { async.mapSeries([1, 1, 2, 4, 8, 16, 32, 64, 128], function(parallelism, next) {
var start = new Date().getTime(); var start = new Date().getTime();
async.times(parallelism, async.times(parallelism,
@@ -28,5 +32,6 @@ async.mapSeries([1, 1, 2, 4, 8, 16, 32, 64, 128], function(parallelism, next) {
} }
); );
}, function() { }, function() {
clearInterval(timer);
console.dir(sharp.cache()); console.dir(sharp.cache());
}); });