diff --git a/docs/changelog.md b/docs/changelog.md index 62089916..569d4d16 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -7,6 +7,13 @@ * Bundle pre-compiled libvips and its dependencies for 64-bit Linux and Windows. [#42](https://github.com/lovell/sharp/issues/42) +* Take advantage of libvips v8.1.0+ features. + [#152](https://github.com/lovell/sharp/issues/152) + +* Pre-extract rotatation should not swap width/height. + [#296](https://github.com/lovell/sharp/issues/296) + [@asilvas](https://github.com/asilvas) + ### v0.11 - "*knife*" #### v0.11.4 - 5th November 2015 diff --git a/index.js b/index.js index 0062a9f8..2cd67d73 100755 --- a/index.js +++ b/index.js @@ -375,11 +375,7 @@ Sharp.prototype.gamma = function(gamma) { Enhance output image contrast by stretching its luminance to cover the full dynamic range */ Sharp.prototype.normalize = function(normalize) { - if (process.platform !== 'win32') { - this.options.normalize = (typeof normalize === 'boolean') ? normalize : true; - } else { - console.error('normalize unavailable on win32 platform'); - } + this.options.normalize = (typeof normalize === 'boolean') ? normalize : true; return this; }; Sharp.prototype.normalise = Sharp.prototype.normalize; @@ -425,14 +421,10 @@ Sharp.prototype.compressionLevel = function(compressionLevel) { }; /* - Disable the use of adaptive row filtering for PNG output - requires libvips 7.42.0+ + Disable the use of adaptive row filtering for PNG output */ Sharp.prototype.withoutAdaptiveFiltering = function(withoutAdaptiveFiltering) { - if (semver.gte(libvipsVersion, '7.42.0')) { - this.options.withoutAdaptiveFiltering = (typeof withoutAdaptiveFiltering === 'boolean') ? withoutAdaptiveFiltering : true; - } else { - console.error('withoutAdaptiveFiltering requires libvips 7.41.0+'); - } + this.options.withoutAdaptiveFiltering = (typeof withoutAdaptiveFiltering === 'boolean') ? withoutAdaptiveFiltering : true; return this; }; @@ -445,41 +437,29 @@ Sharp.prototype.withoutChromaSubsampling = function(withoutChromaSubsampling) { }; /* - Apply trellis quantisation to JPEG output - requires libvips 8.0.0+ compiled against mozjpeg 3.0+ + Apply trellis quantisation to JPEG output - requires mozjpeg 3.0+ */ Sharp.prototype.trellisQuantisation = function(trellisQuantisation) { - if (semver.gte(libvipsVersion, '8.0.0')) { - this.options.trellisQuantisation = (typeof trellisQuantisation === 'boolean') ? trellisQuantisation : true; - } else { - console.error('trellisQuantisation requires libvips 8.0.0+'); - } + this.options.trellisQuantisation = (typeof trellisQuantisation === 'boolean') ? trellisQuantisation : true; return this; }; Sharp.prototype.trellisQuantization = Sharp.prototype.trellisQuantisation; /* - Apply overshoot deringing to JPEG output - requires libvips 8.0.0+ compiled against mozjpeg 3.0+ + Apply overshoot deringing to JPEG output - requires mozjpeg 3.0+ */ Sharp.prototype.overshootDeringing = function(overshootDeringing) { - if (semver.gte(libvipsVersion, '8.0.0')) { - this.options.overshootDeringing = (typeof overshootDeringing === 'boolean') ? overshootDeringing : true; - } else { - console.error('overshootDeringing requires libvips 8.0.0+'); - } + this.options.overshootDeringing = (typeof overshootDeringing === 'boolean') ? overshootDeringing : true; return this; }; /* - Optimise scans in progressive JPEG output - requires libvips 8.0.0+ compiled against mozjpeg 3.0+ + Optimise scans in progressive JPEG output - requires mozjpeg 3.0+ */ Sharp.prototype.optimiseScans = function(optimiseScans) { - if (semver.gte(libvipsVersion, '8.0.0')) { - this.options.optimiseScans = (typeof optimiseScans === 'boolean') ? optimiseScans : true; - if (this.options.optimiseScans) { - this.progressive(); - } - } else { - console.error('optimiseScans requires libvips 8.0.0+'); + this.options.optimiseScans = (typeof optimiseScans === 'boolean') ? optimiseScans : true; + if (this.options.optimiseScans) { + this.progressive(); } return this; }; diff --git a/src/operations.cc b/src/operations.cc index 88d6979a..2e3c4f46 100755 --- a/src/operations.cc +++ b/src/operations.cc @@ -121,73 +121,10 @@ namespace sharp { return vips_bandjoin2(outRGBPremultiplied, outAlpha, out, NULL); } - /* - * Premultiply alpha channel of `image`. - */ - int Premultiply(VipsObject *context, VipsImage *image, VipsImage **out) { -#if (VIPS_MAJOR_VERSION >= 9 || (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 1)) - return vips_premultiply(image, out, NULL); -#else - VipsImage *imageRGB; - if (vips_extract_band(image, &imageRGB, 0, "n", image->Bands - 1, NULL)) - return -1; - vips_object_local(context, imageRGB); - - VipsImage *imageAlpha; - if (vips_extract_band(image, &imageAlpha, image->Bands - 1, "n", 1, NULL)) - return -1; - vips_object_local(context, imageAlpha); - - VipsImage *imageAlphaNormalized; - if (vips_linear1(imageAlpha, &imageAlphaNormalized, 1.0 / 255.0, 0.0, NULL)) - return -1; - vips_object_local(context, imageAlphaNormalized); - - VipsImage *imageRGBPremultiplied; - if (vips_multiply(imageRGB, imageAlphaNormalized, &imageRGBPremultiplied, NULL)) - return -1; - vips_object_local(context, imageRGBPremultiplied); - - return vips_bandjoin2(imageRGBPremultiplied, imageAlpha, out, NULL); -#endif - } - - /* - * Unpremultiply alpha channel of `image`. - */ - int Unpremultiply(VipsObject *context, VipsImage *image, VipsImage **out) { -#if (VIPS_MAJOR_VERSION >= 9 || (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 1)) - return vips_unpremultiply(image, out, NULL); -#else - VipsImage *imageRGBPremultipliedTransformed; - if (vips_extract_band(image, &imageRGBPremultipliedTransformed, 0, "n", image->Bands - 1, NULL)) - return -1; - vips_object_local(context, imageRGBPremultipliedTransformed); - - VipsImage *imageAlphaTransformed; - if (vips_extract_band(image, &imageAlphaTransformed, image->Bands - 1, "n", 1, NULL)) - return -1; - vips_object_local(context, imageAlphaTransformed); - - VipsImage *imageAlphaNormalizedTransformed; - if (vips_linear1(imageAlphaTransformed, &imageAlphaNormalizedTransformed, 1.0 / 255.0, 0.0, NULL)) - return -1; - vips_object_local(context, imageAlphaNormalizedTransformed); - - VipsImage *imageRGBUnpremultipliedTransformed; - if (vips_divide(imageRGBPremultipliedTransformed, imageAlphaNormalizedTransformed, &imageRGBUnpremultipliedTransformed, NULL)) - return -1; - vips_object_local(context, imageRGBUnpremultipliedTransformed); - - return vips_bandjoin2(imageRGBUnpremultipliedTransformed, imageAlphaTransformed, out, NULL); -#endif - } - /* * Stretch luminance to cover full dynamic range. */ int Normalize(VipsObject *context, VipsImage *image, VipsImage **out) { -#ifndef _WIN32 // Get original colourspace VipsInterpretation typeBeforeNormalize = image->Type; if (typeBeforeNormalize == VIPS_INTERPRETATION_RGB) { @@ -262,11 +199,6 @@ namespace sharp { // Cannot normalise zero-range image *out = image; } -#else - // The normalize operation is currently unsupported on Windows - // See https://github.com/lovell/sharp/issues/152 - *out = image; -#endif return 0; } diff --git a/src/operations.h b/src/operations.h index bcd98d69..ca70346c 100755 --- a/src/operations.h +++ b/src/operations.h @@ -9,16 +9,6 @@ namespace sharp { */ int Composite(VipsObject *context, VipsImage *src, VipsImage *dst, VipsImage **out); - /* - * Premultiply alpha channel of `image`. - */ - int Premultiply(VipsObject *context, VipsImage *image, VipsImage **out); - - /* - * Unpremultiply alpha channel of `image`. - */ - int Unpremultiply(VipsObject *context, VipsImage *image, VipsImage **out); - /* * Stretch luminance to cover full dynamic range. */ diff --git a/src/pipeline.cc b/src/pipeline.cc index 26a493eb..538c8802 100755 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -37,8 +37,6 @@ using Nan::Null; using Nan::Equals; using sharp::Composite; -using sharp::Premultiply; -using sharp::Unpremultiply; using sharp::Normalize; using sharp::Blur; using sharp::Sharpen; @@ -522,7 +520,7 @@ class PipelineWorker : public AsyncWorker { // See: http://entropymine.com/imageworsener/resizealpha/ if (shouldPremultiplyAlpha) { VipsImage *imagePremultiplied; - if (Premultiply(hook, image, &imagePremultiplied)) { + if (vips_premultiply(image, &imagePremultiplied, NULL)) { (baton->err).append("Failed to premultiply alpha channel."); return Error(); } @@ -761,7 +759,7 @@ class PipelineWorker : public AsyncWorker { // Premultiply overlay VipsImage *overlayImagePremultiplied; - if (Premultiply(hook, overlayImageRGB, &overlayImagePremultiplied)) { + if (vips_premultiply(overlayImageRGB, &overlayImagePremultiplied, NULL)) { (baton->err).append("Failed to premultiply alpha channel of overlay image."); return Error(); } @@ -779,11 +777,10 @@ class PipelineWorker : public AsyncWorker { // Reverse premultiplication after all transformations: if (shouldPremultiplyAlpha) { VipsImage *imageUnpremultiplied; - if (Unpremultiply(hook, image, &imageUnpremultiplied)) { + if (vips_unpremultiply(image, &imageUnpremultiplied, NULL)) { (baton->err).append("Failed to unpremultiply alpha channel."); return Error(); } - vips_object_local(hook, imageUnpremultiplied); image = imageUnpremultiplied; } @@ -832,34 +829,19 @@ class PipelineWorker : public AsyncWorker { SetExifOrientation(image, baton->withMetadataOrientation); } -#if !(VIPS_MAJOR_VERSION >= 8 || (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 40 && VIPS_MINOR_VERSION >= 5)) - // Generate image tile cache when interlace output is required - no longer required as of libvips 7.40.5+ - if (baton->progressive) { - VipsImage *cached; - if (vips_tilecache(image, &cached, "threaded", TRUE, "persistent", TRUE, "max_tiles", -1, NULL)) { - return Error(); - } - vips_object_local(hook, cached); - image = cached; - } -#endif - // Output if (baton->output == "__jpeg" || (baton->output == "__input" && inputImageType == ImageType::JPEG)) { // Write JPEG to buffer if (vips_jpegsave_buffer(image, &baton->bufferOut, &baton->bufferOutLength, "strip", !baton->withMetadata, "Q", baton->quality, "optimize_coding", TRUE, "no_subsample", baton->withoutChromaSubsampling, -#if (VIPS_MAJOR_VERSION >= 8) "trellis_quant", baton->trellisQuantisation, "overshoot_deringing", baton->overshootDeringing, "optimize_scans", baton->optimiseScans, -#endif "interlace", baton->progressive, NULL)) { return Error(); } baton->outputFormat = "jpeg"; } else if (baton->output == "__png" || (baton->output == "__input" && inputImageType == ImageType::PNG)) { -#if (VIPS_MAJOR_VERSION >= 8 || (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 42)) // Select PNG row filter int filter = baton->withoutAdaptiveFiltering ? VIPS_FOREIGN_PNG_FILTER_NONE : VIPS_FOREIGN_PNG_FILTER_ALL; // Write PNG to buffer @@ -867,13 +849,6 @@ class PipelineWorker : public AsyncWorker { "compression", baton->compressionLevel, "interlace", baton->progressive, "filter", filter, NULL)) { return Error(); } -#else - // Write PNG to buffer - if (vips_pngsave_buffer(image, &baton->bufferOut, &baton->bufferOutLength, "strip", !baton->withMetadata, - "compression", baton->compressionLevel, "interlace", baton->progressive, NULL)) { - return Error(); - } -#endif baton->outputFormat = "png"; } else if (baton->output == "__webp" || (baton->output == "__input" && inputImageType == ImageType::WEBP)) { // Write WEBP to buffer @@ -882,7 +857,6 @@ class PipelineWorker : public AsyncWorker { return Error(); } baton->outputFormat = "webp"; -#if (VIPS_MAJOR_VERSION >= 8 || (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 42)) } else if (baton->output == "__raw") { // Write raw, uncompressed image data to buffer if (baton->greyscale || image->Type == VIPS_INTERPRETATION_B_W) { @@ -910,7 +884,6 @@ class PipelineWorker : public AsyncWorker { return Error(); } baton->outputFormat = "raw"; -#endif } else { bool outputJpeg = IsJpeg(baton->output); bool outputPng = IsPng(baton->output); @@ -922,17 +895,14 @@ class PipelineWorker : public AsyncWorker { // Write JPEG to file if (vips_jpegsave(image, baton->output.c_str(), "strip", !baton->withMetadata, "Q", baton->quality, "optimize_coding", TRUE, "no_subsample", baton->withoutChromaSubsampling, -#if (VIPS_MAJOR_VERSION >= 8) "trellis_quant", baton->trellisQuantisation, "overshoot_deringing", baton->overshootDeringing, "optimize_scans", baton->optimiseScans, -#endif "interlace", baton->progressive, NULL)) { return Error(); } baton->outputFormat = "jpeg"; } else if (outputPng || (matchInput && inputImageType == ImageType::PNG)) { -#if (VIPS_MAJOR_VERSION >= 8 || (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 42)) // Select PNG row filter int filter = baton->withoutAdaptiveFiltering ? VIPS_FOREIGN_PNG_FILTER_NONE : VIPS_FOREIGN_PNG_FILTER_ALL; // Write PNG to file @@ -940,13 +910,6 @@ class PipelineWorker : public AsyncWorker { "compression", baton->compressionLevel, "interlace", baton->progressive, "filter", filter, NULL)) { return Error(); } -#else - // Write PNG to file - if (vips_pngsave(image, baton->output.c_str(), "strip", !baton->withMetadata, - "compression", baton->compressionLevel, "interlace", baton->progressive, NULL)) { - return Error(); - } -#endif baton->outputFormat = "png"; } else if (outputWebp || (matchInput && inputImageType == ImageType::WEBP)) { // Write WEBP to file diff --git a/src/utilities.cc b/src/utilities.cc index 4f384f45..cd7f42c9 100755 --- a/src/utilities.cc +++ b/src/utilities.cc @@ -157,7 +157,6 @@ NAN_METHOD(format) { between two images of the same dimensions and number of channels. */ NAN_METHOD(_maxColourDistance) { - using sharp::Premultiply; using sharp::DetermineImageType; using sharp::ImageType; using sharp::InitImage; @@ -212,7 +211,7 @@ NAN_METHOD(_maxColourDistance) { // Premultiply and remove alpha if (HasAlpha(image1)) { VipsImage *imagePremultiplied1; - if (Premultiply(hook, image1, &imagePremultiplied1)) { + if (vips_premultiply(image1, &imagePremultiplied1, NULL)) { g_object_unref(hook); return ThrowError(vips_error_buffer()); } @@ -227,7 +226,7 @@ NAN_METHOD(_maxColourDistance) { } if (HasAlpha(image2)) { VipsImage *imagePremultiplied2; - if (Premultiply(hook, image2, &imagePremultiplied2)) { + if (vips_premultiply(image2, &imagePremultiplied2, NULL)) { g_object_unref(hook); return ThrowError(vips_error_buffer()); }