diff --git a/src/common.cc b/src/common.cc index ae0de8cb..baec435e 100644 --- a/src/common.cc +++ b/src/common.cc @@ -317,23 +317,26 @@ namespace sharp { return std::make_tuple(left, top); } + + /* + Are pixel values in this image 16-bit integer? + */ + bool Is16Bit(VipsInterpretation const interpretation) { + return interpretation == VIPS_INTERPRETATION_RGB16 || interpretation == VIPS_INTERPRETATION_GREY16; + } + /* Return the image alpha maximum. Useful for combining alpha bands. scRGB images are 0 - 1 for image data, but the alpha is 0 - 255. */ - int MaximumImageAlpha(VipsInterpretation interpretation) { - if(interpretation == VIPS_INTERPRETATION_RGB16 || - interpretation == VIPS_INTERPRETATION_GREY16) { - return (65535); - } else { - return (255); - } + double MaximumImageAlpha(VipsInterpretation const interpretation) { + return Is16Bit(interpretation) ? 65535.0 : 255.0; } /* - Get VIPS Boolean operatoin type from string + Get boolean operation type from string */ - VipsOperationBoolean GetBooleanOperation(std::string opStr) { + VipsOperationBoolean GetBooleanOperation(std::string const opStr) { return static_cast( vips_enum_from_nick(nullptr, VIPS_TYPE_OPERATION_BOOLEAN, opStr.data()) ); diff --git a/src/common.h b/src/common.h index e2774291..e931e460 100644 --- a/src/common.h +++ b/src/common.h @@ -117,17 +117,21 @@ namespace sharp { std::tuple CalculateCrop(int const inWidth, int const inHeight, int const outWidth, int const outHeight, int const x, int const y); + /* + Are pixel values in this image 16-bit integer? + */ + bool Is16Bit(VipsInterpretation const interpretation); + /* Return the image alpha maximum. Useful for combining alpha bands. scRGB images are 0 - 1 for image data, but the alpha is 0 - 255. */ - int MaximumImageAlpha(VipsInterpretation interpretation); + double MaximumImageAlpha(VipsInterpretation const interpretation); /* - Get VIPS Boolean operatoin type from string + Get boolean operation type from string */ - VipsOperationBoolean GetBooleanOperation(std::string opStr); - + VipsOperationBoolean GetBooleanOperation(std::string const opStr); } // namespace sharp diff --git a/src/operations.cc b/src/operations.cc index 8c7987c4..b1a3f1d9 100644 --- a/src/operations.cc +++ b/src/operations.cc @@ -162,8 +162,8 @@ namespace sharp { // the range of the mask and the image need to match .. one could be // 16-bit, one 8-bit - int dstMax = MaximumImageAlpha(dst.interpretation()); - int maskMax = MaximumImageAlpha(mask.interpretation()); + double const dstMax = MaximumImageAlpha(dst.interpretation()); + double const maskMax = MaximumImageAlpha(mask.interpretation()); // combine the new mask and the existing alpha ... there are // many ways of doing this, mult is the simplest @@ -419,7 +419,7 @@ namespace sharp { // significantly different from this std::vector background = image(0, 0); - int max = MaximumImageAlpha(image.interpretation()); + double const max = MaximumImageAlpha(image.interpretation()); // we need to smooth the image, subtract the background from every pixel, take // the absolute value of the difference, then threshold diff --git a/src/pipeline.cc b/src/pipeline.cc index 8b513f65..45b8550d 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -78,9 +78,12 @@ using sharp::IsDzZip; using sharp::IsV; using sharp::FreeCallback; using sharp::CalculateCrop; +using sharp::Is16Bit; +using sharp::MaximumImageAlpha; +using sharp::GetBooleanOperation; + using sharp::counterProcess; using sharp::counterQueue; -using sharp::GetBooleanOperation; class PipelineWorker : public AsyncWorker { public: @@ -409,13 +412,12 @@ class PipelineWorker : public AsyncWorker { } // Calculate maximum alpha value based on input image pixel depth - bool is16Bit = (image.format() == VIPS_FORMAT_USHORT); - double maxAlpha = is16Bit ? 65535.0 : 255.0; + double const maxAlpha = MaximumImageAlpha(image.interpretation()); // Flatten image to remove alpha channel if (baton->flatten && HasAlpha(image)) { // Scale up 8-bit values to match 16-bit input image - double multiplier = (image.interpretation() == VIPS_INTERPRETATION_RGB16) ? 256.0 : 1.0; + double const multiplier = Is16Bit(image.interpretation()) ? 256.0 : 1.0; // Background colour std::vector background { baton->background[0] * multiplier, @@ -471,7 +473,7 @@ class PipelineWorker : public AsyncWorker { // Ensure image has an alpha channel when there is an overlay bool hasOverlay = baton->overlayBufferInLength > 0 || !baton->overlayFileIn.empty(); if (hasOverlay && !HasAlpha(image)) { - double multiplier = (image.interpretation() == VIPS_INTERPRETATION_RGB16) ? 256.0 : 1.0; + double const multiplier = Is16Bit(image.interpretation()) ? 256.0 : 1.0; image = image.bandjoin( VImage::new_matrix(image.width(), image.height()).new_from_image(255 * multiplier) ); @@ -481,10 +483,7 @@ class PipelineWorker : public AsyncWorker { bool shouldBlur = baton->blurSigma != 0.0; bool shouldConv = baton->convKernelWidth * baton->convKernelHeight > 0; bool shouldSharpen = baton->sharpenSigma != 0.0; - bool shouldThreshold = baton->threshold != 0; bool shouldCutout = baton->overlayCutout; - bool shouldBandbool = baton->bandBoolOp < VIPS_OPERATION_BOOLEAN_LAST && - baton->bandBoolOp >= VIPS_OPERATION_BOOLEAN_AND; bool shouldPremultiplyAlpha = HasAlpha(image) && (shouldAffineTransform || shouldBlur || shouldConv || shouldSharpen || (hasOverlay && !shouldCutout)); @@ -554,7 +553,7 @@ class PipelineWorker : public AsyncWorker { if (image.width() != baton->width || image.height() != baton->height) { if (baton->canvas == Canvas::EMBED) { // Scale up 8-bit values to match 16-bit input image - double multiplier = (image.interpretation() == VIPS_INTERPRETATION_RGB16) ? 256.0 : 1.0; + double const multiplier = Is16Bit(image.interpretation()) ? 256.0 : 1.0; // Create background colour std::vector background; if (image.bands() > 2) { @@ -617,7 +616,7 @@ class PipelineWorker : public AsyncWorker { // Extend edges if (baton->extendTop > 0 || baton->extendBottom > 0 || baton->extendLeft > 0 || baton->extendRight > 0) { // Scale up 8-bit values to match 16-bit input image - const double multiplier = (image.interpretation() == VIPS_INTERPRETATION_RGB16) ? 256.0 : 1.0; + double const multiplier = Is16Bit(image.interpretation()) ? 256.0 : 1.0; // Create background colour std::vector background { baton->background[0] * multiplier, @@ -643,7 +642,7 @@ class PipelineWorker : public AsyncWorker { } // Threshold - must happen before blurring, due to the utility of blurring after thresholding - if (shouldThreshold) { + if (baton->threshold != 0) { image = Threshold(image, baton->threshold, baton->thresholdGrayscale); } @@ -758,7 +757,7 @@ class PipelineWorker : public AsyncWorker { if (shouldPremultiplyAlpha) { image = image.unpremultiply(VImage::option()->set("max_alpha", maxAlpha)); // Cast pixel values to integer - if (is16Bit) { + if (Is16Bit(image.interpretation())) { image = image.cast(VIPS_FORMAT_USHORT); } else { image = image.cast(VIPS_FORMAT_UCHAR); @@ -776,7 +775,7 @@ class PipelineWorker : public AsyncWorker { } // Convert image to sRGB, if not already - if (image.interpretation() == VIPS_INTERPRETATION_RGB16) { + if (Is16Bit(image.interpretation())) { image = image.cast(VIPS_FORMAT_USHORT); } if (image.interpretation() != VIPS_INTERPRETATION_sRGB) { @@ -828,7 +827,7 @@ class PipelineWorker : public AsyncWorker { } // Apply per-channel Bandbool bitwise operations after all other operations - if (shouldBandbool) { + if (baton->bandBoolOp >= VIPS_OPERATION_BOOLEAN_AND && baton->bandBoolOp < VIPS_OPERATION_BOOLEAN_LAST) { image = Bandbool(image, baton->bandBoolOp); }