mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
Refactor internal 'resize' to more apt 'pipeline'
Refactor 'composite' C to C++ 'operations'
This commit is contained in:
parent
e2c53b59ce
commit
36be0453dd
@ -3,9 +3,9 @@
|
||||
'target_name': 'sharp',
|
||||
'sources': [
|
||||
'src/common.cc',
|
||||
'src/composite.c',
|
||||
'src/metadata.cc',
|
||||
'src/resize.cc',
|
||||
'src/operations.cc',
|
||||
'src/pipeline.cc',
|
||||
'src/sharp.cc',
|
||||
'src/utilities.cc'
|
||||
],
|
||||
|
24
index.js
24
index.js
@ -567,7 +567,7 @@ Sharp.prototype.toFile = function(output, callback) {
|
||||
}
|
||||
} else {
|
||||
this.options.output = output;
|
||||
return this._sharp(callback);
|
||||
return this._pipeline(callback);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
@ -577,7 +577,7 @@ Sharp.prototype.toFile = function(output, callback) {
|
||||
Write output to a Buffer
|
||||
*/
|
||||
Sharp.prototype.toBuffer = function(callback) {
|
||||
return this._sharp(callback);
|
||||
return this._pipeline(callback);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -640,7 +640,7 @@ Sharp.prototype.toFormat = function(format) {
|
||||
Sharp.prototype._read = function() {
|
||||
if (!this.options.streamOut) {
|
||||
this.options.streamOut = true;
|
||||
this._sharp();
|
||||
this._pipeline();
|
||||
}
|
||||
};
|
||||
|
||||
@ -648,18 +648,18 @@ Sharp.prototype._read = function() {
|
||||
Invoke the C++ image processing pipeline
|
||||
Supports callback, stream and promise variants
|
||||
*/
|
||||
Sharp.prototype._sharp = function(callback) {
|
||||
Sharp.prototype._pipeline = function(callback) {
|
||||
var that = this;
|
||||
if (typeof callback === 'function') {
|
||||
// output=file/buffer
|
||||
if (this.options.streamIn) {
|
||||
// output=file/buffer, input=stream
|
||||
this.on('finish', function() {
|
||||
sharp.resize(that.options, callback);
|
||||
sharp.pipeline(that.options, callback);
|
||||
});
|
||||
} else {
|
||||
// output=file/buffer, input=file/buffer
|
||||
sharp.resize(this.options, callback);
|
||||
sharp.pipeline(this.options, callback);
|
||||
}
|
||||
return this;
|
||||
} else if (this.options.streamOut) {
|
||||
@ -667,9 +667,9 @@ Sharp.prototype._sharp = function(callback) {
|
||||
if (this.options.streamIn) {
|
||||
// output=stream, input=stream
|
||||
this.on('finish', function() {
|
||||
sharp.resize(that.options, function(err, data) {
|
||||
sharp.pipeline(that.options, function(err, data) {
|
||||
if (err) {
|
||||
that.emit('error', new Error(err));
|
||||
that.emit('error', err);
|
||||
} else {
|
||||
that.push(data);
|
||||
}
|
||||
@ -678,9 +678,9 @@ Sharp.prototype._sharp = function(callback) {
|
||||
});
|
||||
} else {
|
||||
// output=stream, input=file/buffer
|
||||
sharp.resize(this.options, function(err, data) {
|
||||
sharp.pipeline(this.options, function(err, data) {
|
||||
if (err) {
|
||||
that.emit('error', new Error(err));
|
||||
that.emit('error', err);
|
||||
} else {
|
||||
that.push(data);
|
||||
}
|
||||
@ -694,7 +694,7 @@ Sharp.prototype._sharp = function(callback) {
|
||||
// output=promise, input=stream
|
||||
return new BluebirdPromise(function(resolve, reject) {
|
||||
that.on('finish', function() {
|
||||
sharp.resize(that.options, function(err, data) {
|
||||
sharp.pipeline(that.options, function(err, data) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
@ -706,7 +706,7 @@ Sharp.prototype._sharp = function(callback) {
|
||||
} else {
|
||||
// output=promise, input=file/buffer
|
||||
return new BluebirdPromise(function(resolve, reject) {
|
||||
sharp.resize(that.options, function(err, data) {
|
||||
sharp.pipeline(that.options, function(err, data) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
|
212
src/composite.c
212
src/composite.c
@ -1,212 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <vips/vips.h>
|
||||
|
||||
|
||||
// Constants
|
||||
const int ALPHA_BAND_INDEX = 3;
|
||||
const int NUM_COLOR_BANDS = 3;
|
||||
|
||||
// TODO: Copied from `common.cc`. Deduplicate once this becomes a C++ module.
|
||||
int HasAlpha(VipsImage *image) {
|
||||
return (
|
||||
(image->Bands == 2 && image->Type == VIPS_INTERPRETATION_B_W) ||
|
||||
(image->Bands == 4 && image->Type != VIPS_INTERPRETATION_CMYK) ||
|
||||
(image->Bands == 5 && image->Type == VIPS_INTERPRETATION_CMYK)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
Composite images `src` and `dst` with premultiplied alpha channel and output
|
||||
image with premultiplied alpha.
|
||||
*/
|
||||
int Composite(VipsObject *context, VipsImage *srcPremultiplied, VipsImage *dstPremultiplied, VipsImage **outPremultiplied) {
|
||||
if (srcPremultiplied->Bands != 4 || dstPremultiplied->Bands != 4)
|
||||
return -1;
|
||||
|
||||
// Extract RGB bands:
|
||||
VipsImage *srcRGBPremultiplied;
|
||||
if (vips_extract_band(srcPremultiplied, &srcRGBPremultiplied, 0, "n", NUM_COLOR_BANDS, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, srcRGBPremultiplied);
|
||||
|
||||
VipsImage *dstRGBPremultiplied;
|
||||
if (vips_extract_band(dstPremultiplied, &dstRGBPremultiplied, 0, "n", NUM_COLOR_BANDS, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, dstRGBPremultiplied);
|
||||
|
||||
// Extract alpha bands:
|
||||
VipsImage *srcAlpha;
|
||||
if (vips_extract_band(srcPremultiplied, &srcAlpha, ALPHA_BAND_INDEX, "n", 1, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, srcAlpha);
|
||||
|
||||
VipsImage *dstAlpha;
|
||||
if (vips_extract_band(dstPremultiplied, &dstAlpha, ALPHA_BAND_INDEX, "n", 1, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, dstAlpha);
|
||||
|
||||
// Compute normalized input alpha channels:
|
||||
VipsImage *srcAlphaNormalized;
|
||||
if (vips_linear1(srcAlpha, &srcAlphaNormalized, 1.0 / 255.0, 0.0, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, srcAlphaNormalized);
|
||||
|
||||
VipsImage *dstAlphaNormalized;
|
||||
if (vips_linear1(dstAlpha, &dstAlphaNormalized, 1.0 / 255.0, 0.0, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, dstAlphaNormalized);
|
||||
|
||||
//
|
||||
// Compute normalized output alpha channel:
|
||||
//
|
||||
// References:
|
||||
// - http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
|
||||
// - https://github.com/jcupitt/ruby-vips/issues/28#issuecomment-9014826
|
||||
//
|
||||
// out_a = src_a + dst_a * (1 - src_a)
|
||||
// ^^^^^^^^^^^
|
||||
// t0
|
||||
// ^^^^^^^^^^^^^^^^^^^
|
||||
// t1
|
||||
VipsImage *t0;
|
||||
if (vips_linear1(srcAlphaNormalized, &t0, -1.0, 1.0, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, t0);
|
||||
|
||||
VipsImage *t1;
|
||||
if (vips_multiply(dstAlphaNormalized, t0, &t1, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, t1);
|
||||
|
||||
VipsImage *outAlphaNormalized;
|
||||
if (vips_add(srcAlphaNormalized, t1, &outAlphaNormalized, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, outAlphaNormalized);
|
||||
|
||||
//
|
||||
// Compute output RGB channels:
|
||||
//
|
||||
// Wikipedia:
|
||||
// out_rgb = (src_rgb * src_a + dst_rgb * dst_a * (1 - src_a)) / out_a
|
||||
// ^^^^^^^^^^^
|
||||
// t0
|
||||
//
|
||||
// Omit division by `out_a` since `Compose` is supposed to output a
|
||||
// premultiplied RGBA image as reversal of premultiplication is handled
|
||||
// externally.
|
||||
//
|
||||
VipsImage *t2;
|
||||
if (vips_multiply(dstRGBPremultiplied, t0, &t2, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, t2);
|
||||
|
||||
VipsImage *outRGBPremultiplied;
|
||||
if (vips_add(srcRGBPremultiplied, t2, &outRGBPremultiplied, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, outRGBPremultiplied);
|
||||
|
||||
// Denormalize output alpha channel:
|
||||
VipsImage *outAlpha;
|
||||
if (vips_linear1(outAlphaNormalized, &outAlpha, 255.0, 0.0, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, outAlpha);
|
||||
|
||||
// Combine RGB and alpha channel into output image:
|
||||
VipsImage *joined;
|
||||
if (vips_bandjoin2(outRGBPremultiplied, outAlpha, &joined, NULL))
|
||||
return -1;
|
||||
|
||||
// Return a reference to the composited output image:
|
||||
*outPremultiplied = joined;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Premultiply alpha channel of `image`.
|
||||
*/
|
||||
int Premultiply(VipsObject *context, VipsImage *image, VipsImage **out) {
|
||||
VipsImage *imagePremultiplied;
|
||||
|
||||
#if (VIPS_MAJOR_VERSION >= 9 || (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 1))
|
||||
|
||||
if (vips_premultiply(image, &imagePremultiplied, NULL))
|
||||
return -1;
|
||||
|
||||
#else
|
||||
|
||||
VipsImage *imageRGB;
|
||||
if (vips_extract_band(image, &imageRGB, 0, "n", NUM_COLOR_BANDS, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, imageRGB);
|
||||
|
||||
VipsImage *imageAlpha;
|
||||
if (vips_extract_band(image, &imageAlpha, ALPHA_BAND_INDEX, "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);
|
||||
|
||||
if (vips_bandjoin2(imageRGBPremultiplied, imageAlpha, &imagePremultiplied, NULL))
|
||||
return -1;
|
||||
|
||||
#endif
|
||||
|
||||
// Return a reference to the premultiplied output image:
|
||||
*out = imagePremultiplied;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Unpremultiply alpha channel of `image`.
|
||||
*/
|
||||
int Unpremultiply(VipsObject *context, VipsImage *image, VipsImage **out) {
|
||||
VipsImage *imageUnpremultiplied;
|
||||
|
||||
#if (VIPS_MAJOR_VERSION >= 9 || (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 1))
|
||||
|
||||
if (vips_unpremultiply(image, &imageUnpremultiplied, NULL))
|
||||
return -1;
|
||||
|
||||
#else
|
||||
|
||||
VipsImage *imageRGBPremultipliedTransformed;
|
||||
if (vips_extract_band(image, &imageRGBPremultipliedTransformed, 0, "n", NUM_COLOR_BANDS, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, imageRGBPremultipliedTransformed);
|
||||
|
||||
VipsImage *imageAlphaTransformed;
|
||||
if (vips_extract_band(image, &imageAlphaTransformed, ALPHA_BAND_INDEX, "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);
|
||||
|
||||
if (vips_bandjoin2(imageRGBUnpremultipliedTransformed, imageAlphaTransformed, &imageUnpremultiplied, NULL))
|
||||
return -1;
|
||||
|
||||
#endif
|
||||
|
||||
// Return a reference to the unpremultiplied output image:
|
||||
*out = imageUnpremultiplied;
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
#ifndef SRC_COMPOSITE_H_
|
||||
#define SRC_COMPOSITE_H_
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int Composite(VipsObject *context, VipsImage *src, VipsImage *dst, VipsImage **out);
|
||||
int Premultiply(VipsObject *context, VipsImage *image, VipsImage **out);
|
||||
int Unpremultiply(VipsObject *context, VipsImage *image, VipsImage **out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SRC_COMPOSITE_H_
|
191
src/operations.cc
Executable file
191
src/operations.cc
Executable file
@ -0,0 +1,191 @@
|
||||
#include <vips/vips.h>
|
||||
|
||||
#include "operations.h"
|
||||
|
||||
namespace sharp {
|
||||
|
||||
/*
|
||||
Composite images `src` and `dst` with premultiplied alpha channel and output
|
||||
image with premultiplied alpha.
|
||||
*/
|
||||
int Composite(VipsObject *context, VipsImage *srcPremultiplied, VipsImage *dstPremultiplied, VipsImage **outPremultiplied) {
|
||||
if (srcPremultiplied->Bands != 4 || dstPremultiplied->Bands != 4)
|
||||
return -1;
|
||||
|
||||
// Extract RGB bands:
|
||||
VipsImage *srcRGBPremultiplied;
|
||||
if (vips_extract_band(srcPremultiplied, &srcRGBPremultiplied, 0, "n", srcPremultiplied->Bands - 1, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, srcRGBPremultiplied);
|
||||
|
||||
VipsImage *dstRGBPremultiplied;
|
||||
if (vips_extract_band(dstPremultiplied, &dstRGBPremultiplied, 0, "n", dstPremultiplied->Bands - 1, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, dstRGBPremultiplied);
|
||||
|
||||
// Extract alpha bands:
|
||||
VipsImage *srcAlpha;
|
||||
if (vips_extract_band(srcPremultiplied, &srcAlpha, srcPremultiplied->Bands - 1, "n", 1, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, srcAlpha);
|
||||
|
||||
VipsImage *dstAlpha;
|
||||
if (vips_extract_band(dstPremultiplied, &dstAlpha, dstPremultiplied->Bands - 1, "n", 1, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, dstAlpha);
|
||||
|
||||
// Compute normalized input alpha channels:
|
||||
VipsImage *srcAlphaNormalized;
|
||||
if (vips_linear1(srcAlpha, &srcAlphaNormalized, 1.0 / 255.0, 0.0, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, srcAlphaNormalized);
|
||||
|
||||
VipsImage *dstAlphaNormalized;
|
||||
if (vips_linear1(dstAlpha, &dstAlphaNormalized, 1.0 / 255.0, 0.0, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, dstAlphaNormalized);
|
||||
|
||||
//
|
||||
// Compute normalized output alpha channel:
|
||||
//
|
||||
// References:
|
||||
// - http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
|
||||
// - https://github.com/jcupitt/ruby-vips/issues/28#issuecomment-9014826
|
||||
//
|
||||
// out_a = src_a + dst_a * (1 - src_a)
|
||||
// ^^^^^^^^^^^
|
||||
// t0
|
||||
// ^^^^^^^^^^^^^^^^^^^
|
||||
// t1
|
||||
VipsImage *t0;
|
||||
if (vips_linear1(srcAlphaNormalized, &t0, -1.0, 1.0, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, t0);
|
||||
|
||||
VipsImage *t1;
|
||||
if (vips_multiply(dstAlphaNormalized, t0, &t1, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, t1);
|
||||
|
||||
VipsImage *outAlphaNormalized;
|
||||
if (vips_add(srcAlphaNormalized, t1, &outAlphaNormalized, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, outAlphaNormalized);
|
||||
|
||||
//
|
||||
// Compute output RGB channels:
|
||||
//
|
||||
// Wikipedia:
|
||||
// out_rgb = (src_rgb * src_a + dst_rgb * dst_a * (1 - src_a)) / out_a
|
||||
// ^^^^^^^^^^^
|
||||
// t0
|
||||
//
|
||||
// Omit division by `out_a` since `Compose` is supposed to output a
|
||||
// premultiplied RGBA image as reversal of premultiplication is handled
|
||||
// externally.
|
||||
//
|
||||
VipsImage *t2;
|
||||
if (vips_multiply(dstRGBPremultiplied, t0, &t2, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, t2);
|
||||
|
||||
VipsImage *outRGBPremultiplied;
|
||||
if (vips_add(srcRGBPremultiplied, t2, &outRGBPremultiplied, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, outRGBPremultiplied);
|
||||
|
||||
// Denormalize output alpha channel:
|
||||
VipsImage *outAlpha;
|
||||
if (vips_linear1(outAlphaNormalized, &outAlpha, 255.0, 0.0, NULL))
|
||||
return -1;
|
||||
vips_object_local(context, outAlpha);
|
||||
|
||||
// Combine RGB and alpha channel into output image:
|
||||
VipsImage *joined;
|
||||
if (vips_bandjoin2(outRGBPremultiplied, outAlpha, &joined, NULL))
|
||||
return -1;
|
||||
|
||||
// Return a reference to the composited output image
|
||||
*outPremultiplied = joined;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Premultiply alpha channel of `image`.
|
||||
*/
|
||||
int Premultiply(VipsObject *context, VipsImage *image, VipsImage **out) {
|
||||
VipsImage *imagePremultiplied;
|
||||
|
||||
#if (VIPS_MAJOR_VERSION >= 9 || (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 1))
|
||||
if (vips_premultiply(image, &imagePremultiplied, NULL))
|
||||
return -1;
|
||||
#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);
|
||||
|
||||
if (vips_bandjoin2(imageRGBPremultiplied, imageAlpha, &imagePremultiplied, NULL))
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
// Return a reference to the premultiplied output image
|
||||
*out = imagePremultiplied;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unpremultiply alpha channel of `image`.
|
||||
*/
|
||||
int Unpremultiply(VipsObject *context, VipsImage *image, VipsImage **out) {
|
||||
VipsImage *imageUnpremultiplied;
|
||||
|
||||
#if (VIPS_MAJOR_VERSION >= 9 || (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 1))
|
||||
if (vips_unpremultiply(image, &imageUnpremultiplied, NULL))
|
||||
return -1;
|
||||
#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);
|
||||
|
||||
if (vips_bandjoin2(imageRGBUnpremultipliedTransformed, imageAlphaTransformed, &imageUnpremultiplied, NULL))
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
// Return a reference to the unpremultiplied output image
|
||||
*out = imageUnpremultiplied;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace sharp
|
24
src/operations.h
Executable file
24
src/operations.h
Executable file
@ -0,0 +1,24 @@
|
||||
#ifndef SRC_OPERATIONS_H_
|
||||
#define SRC_OPERATIONS_H_
|
||||
|
||||
namespace sharp {
|
||||
|
||||
/*
|
||||
Composite images `src` and `dst` with premultiplied alpha channel and output
|
||||
image with premultiplied alpha.
|
||||
*/
|
||||
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);
|
||||
|
||||
} // namespace sharp
|
||||
|
||||
#endif // SRC_OPERATIONS_H_
|
@ -8,8 +8,8 @@
|
||||
#include "nan.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "composite.h"
|
||||
#include "resize.h"
|
||||
#include "operations.h"
|
||||
#include "pipeline.h"
|
||||
|
||||
using v8::Handle;
|
||||
using v8::Local;
|
||||
@ -22,6 +22,10 @@ using v8::Array;
|
||||
using v8::Function;
|
||||
using v8::Exception;
|
||||
|
||||
using sharp::Composite;
|
||||
using sharp::Premultiply;
|
||||
using sharp::Unpremultiply;
|
||||
|
||||
using sharp::ImageType;
|
||||
using sharp::DetermineImageType;
|
||||
using sharp::InitImage;
|
||||
@ -53,7 +57,7 @@ enum class Angle {
|
||||
DLAST
|
||||
};
|
||||
|
||||
struct ResizeBaton {
|
||||
struct PipelineBaton {
|
||||
std::string fileIn;
|
||||
char *bufferIn;
|
||||
size_t bufferInLength;
|
||||
@ -105,7 +109,7 @@ struct ResizeBaton {
|
||||
int tileSize;
|
||||
int tileOverlap;
|
||||
|
||||
ResizeBaton():
|
||||
PipelineBaton():
|
||||
bufferInLength(0),
|
||||
limitInputPixels(0),
|
||||
outputFormat(""),
|
||||
@ -154,12 +158,12 @@ static void DeleteBuffer(VipsObject *object, char *buffer) {
|
||||
}
|
||||
}
|
||||
|
||||
class ResizeWorker : public NanAsyncWorker {
|
||||
class PipelineWorker : public NanAsyncWorker {
|
||||
|
||||
public:
|
||||
ResizeWorker(NanCallback *callback, ResizeBaton *baton, NanCallback *queueListener) :
|
||||
PipelineWorker(NanCallback *callback, PipelineBaton *baton, NanCallback *queueListener) :
|
||||
NanAsyncWorker(callback), baton(baton), queueListener(queueListener) {}
|
||||
~ResizeWorker() {}
|
||||
~PipelineWorker() {}
|
||||
|
||||
/*
|
||||
libuv worker
|
||||
@ -1099,7 +1103,7 @@ class ResizeWorker : public NanAsyncWorker {
|
||||
}
|
||||
|
||||
private:
|
||||
ResizeBaton *baton;
|
||||
PipelineBaton *baton;
|
||||
NanCallback *queueListener;
|
||||
VipsObject *hook;
|
||||
|
||||
@ -1207,13 +1211,13 @@ class ResizeWorker : public NanAsyncWorker {
|
||||
};
|
||||
|
||||
/*
|
||||
resize(options, output, callback)
|
||||
pipeline(options, output, callback)
|
||||
*/
|
||||
NAN_METHOD(resize) {
|
||||
NAN_METHOD(pipeline) {
|
||||
NanScope();
|
||||
|
||||
// V8 objects are converted to non-V8 types held in the baton struct
|
||||
ResizeBaton *baton = new ResizeBaton;
|
||||
PipelineBaton *baton = new PipelineBaton;
|
||||
Local<Object> options = args[0]->ToObject();
|
||||
|
||||
// Input filename
|
||||
@ -1300,7 +1304,7 @@ NAN_METHOD(resize) {
|
||||
|
||||
// Join queue for worker thread
|
||||
NanCallback *callback = new NanCallback(args[1].As<Function>());
|
||||
NanAsyncQueueWorker(new ResizeWorker(callback, baton, queueListener));
|
||||
NanAsyncQueueWorker(new PipelineWorker(callback, baton, queueListener));
|
||||
|
||||
// Increment queued task counter
|
||||
g_atomic_int_inc(&counterQueue);
|
8
src/pipeline.h
Executable file
8
src/pipeline.h
Executable file
@ -0,0 +1,8 @@
|
||||
#ifndef SRC_PIPELINE_H_
|
||||
#define SRC_PIPELINE_H_
|
||||
|
||||
#include "nan.h"
|
||||
|
||||
NAN_METHOD(pipeline);
|
||||
|
||||
#endif // SRC_PIPELINE_H_
|
@ -1,8 +0,0 @@
|
||||
#ifndef SRC_RESIZE_H_
|
||||
#define SRC_RESIZE_H_
|
||||
|
||||
#include "nan.h"
|
||||
|
||||
NAN_METHOD(resize);
|
||||
|
||||
#endif // SRC_RESIZE_H_
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "metadata.h"
|
||||
#include "resize.h"
|
||||
#include "pipeline.h"
|
||||
#include "utilities.h"
|
||||
|
||||
extern "C" void init(v8::Handle<v8::Object> target) {
|
||||
@ -18,7 +18,7 @@ extern "C" void init(v8::Handle<v8::Object> target) {
|
||||
|
||||
// Methods available to JavaScript
|
||||
NODE_SET_METHOD(target, "metadata", metadata);
|
||||
NODE_SET_METHOD(target, "resize", resize);
|
||||
NODE_SET_METHOD(target, "pipeline", pipeline);
|
||||
NODE_SET_METHOD(target, "cache", cache);
|
||||
NODE_SET_METHOD(target, "concurrency", concurrency);
|
||||
NODE_SET_METHOD(target, "counters", counters);
|
||||
|
@ -4,8 +4,8 @@
|
||||
#include "nan.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "operations.h"
|
||||
#include "utilities.h"
|
||||
#include "composite.h"
|
||||
|
||||
using v8::Local;
|
||||
using v8::Object;
|
||||
@ -13,13 +13,6 @@ using v8::Number;
|
||||
using v8::String;
|
||||
using v8::Boolean;
|
||||
|
||||
using sharp::DetermineImageType;
|
||||
using sharp::ImageType;
|
||||
using sharp::InitImage;
|
||||
using sharp::HasAlpha;
|
||||
using sharp::counterQueue;
|
||||
using sharp::counterProcess;
|
||||
|
||||
/*
|
||||
Get and set cache memory and item limits
|
||||
*/
|
||||
@ -68,6 +61,9 @@ NAN_METHOD(concurrency) {
|
||||
Get internal counters (queued tasks, processing tasks)
|
||||
*/
|
||||
NAN_METHOD(counters) {
|
||||
using sharp::counterProcess;
|
||||
using sharp::counterQueue;
|
||||
|
||||
NanScope();
|
||||
Local<Object> counters = NanNew<Object>();
|
||||
counters->Set(NanNew<String>("queue"), NanNew<Number>(counterQueue));
|
||||
@ -154,6 +150,12 @@ 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;
|
||||
using sharp::HasAlpha;
|
||||
|
||||
NanScope();
|
||||
|
||||
// Create "hook" VipsObject to hang image references from
|
||||
|
Loading…
x
Reference in New Issue
Block a user