mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 18:40:16 +02:00
Less C, more C++ e.g. namespace, enum class
Improve image reference handling
This commit is contained in:
parent
e465306d97
commit
ee513ac7a7
146
src/common.cc
146
src/common.cc
@ -4,30 +4,35 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
namespace sharp {
|
||||||
|
|
||||||
// How many tasks are in the queue?
|
// How many tasks are in the queue?
|
||||||
volatile int counter_queue = 0;
|
volatile int counterQueue = 0;
|
||||||
|
|
||||||
// How many tasks are being processed?
|
// How many tasks are being processed?
|
||||||
volatile int counter_process = 0;
|
volatile int counterProcess = 0;
|
||||||
|
|
||||||
// Filename extension checkers
|
// Filename extension checkers
|
||||||
static bool ends_with(std::string const &str, std::string const &end) {
|
static bool EndsWith(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);
|
||||||
}
|
}
|
||||||
bool is_jpeg(std::string const &str) {
|
bool IsJpeg(std::string const &str) {
|
||||||
return ends_with(str, ".jpg") || ends_with(str, ".jpeg") || ends_with(str, ".JPG") || ends_with(str, ".JPEG");
|
return EndsWith(str, ".jpg") || EndsWith(str, ".jpeg") || EndsWith(str, ".JPG") || EndsWith(str, ".JPEG");
|
||||||
}
|
}
|
||||||
bool is_png(std::string const &str) {
|
bool IsPng(std::string const &str) {
|
||||||
return ends_with(str, ".png") || ends_with(str, ".PNG");
|
return EndsWith(str, ".png") || EndsWith(str, ".PNG");
|
||||||
}
|
}
|
||||||
bool is_webp(std::string const &str) {
|
bool IsWebp(std::string const &str) {
|
||||||
return ends_with(str, ".webp") || ends_with(str, ".WEBP");
|
return EndsWith(str, ".webp") || EndsWith(str, ".WEBP");
|
||||||
}
|
}
|
||||||
bool is_tiff(std::string const &str) {
|
bool IsTiff(std::string const &str) {
|
||||||
return ends_with(str, ".tif") || ends_with(str, ".tiff") || ends_with(str, ".TIF") || ends_with(str, ".TIFF");
|
return EndsWith(str, ".tif") || EndsWith(str, ".tiff") || EndsWith(str, ".TIF") || EndsWith(str, ".TIFF");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buffer content checkers
|
// Buffer content checkers
|
||||||
|
unsigned char const MARKER_JPEG[] = {0xff, 0xd8};
|
||||||
|
unsigned char const MARKER_PNG[] = {0x89, 0x50};
|
||||||
|
unsigned char const MARKER_WEBP[] = {0x52, 0x49};
|
||||||
|
|
||||||
#if (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 40)
|
#if (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 40)
|
||||||
static bool buffer_is_tiff(char *buffer, size_t len) {
|
static bool buffer_is_tiff(char *buffer, size_t len) {
|
||||||
@ -40,76 +45,89 @@ static bool buffer_is_tiff(char *buffer, size_t len) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
unsigned char const MARKER_JPEG[] = {0xff, 0xd8};
|
|
||||||
unsigned char const MARKER_PNG[] = {0x89, 0x50};
|
|
||||||
unsigned char const MARKER_WEBP[] = {0x52, 0x49};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initialise a VipsImage from a buffer. Supports JPEG, PNG, WebP and TIFF.
|
Determine image format of a buffer.
|
||||||
Returns the ImageType detected, if any.
|
|
||||||
*/
|
*/
|
||||||
ImageType
|
ImageType DetermineImageType(void *buffer, size_t const length) {
|
||||||
sharp_init_image_from_buffer(VipsImage **image, void *buffer, size_t const length, VipsAccess const access) {
|
ImageType imageType = ImageType::UNKNOWN;
|
||||||
ImageType imageType = UNKNOWN;
|
if (length >= 4) {
|
||||||
if (memcmp(MARKER_JPEG, buffer, 2) == 0) {
|
if (memcmp(MARKER_JPEG, buffer, 2) == 0) {
|
||||||
if (!vips_jpegload_buffer(buffer, length, image, "access", access, NULL)) {
|
imageType = ImageType::JPEG;
|
||||||
imageType = JPEG;
|
|
||||||
}
|
|
||||||
} else if (memcmp(MARKER_PNG, buffer, 2) == 0) {
|
} else if (memcmp(MARKER_PNG, buffer, 2) == 0) {
|
||||||
if (!vips_pngload_buffer(buffer, length, image, "access", access, NULL)) {
|
imageType = ImageType::PNG;
|
||||||
imageType = PNG;
|
|
||||||
}
|
|
||||||
} else if (memcmp(MARKER_WEBP, buffer, 2) == 0) {
|
} else if (memcmp(MARKER_WEBP, buffer, 2) == 0) {
|
||||||
if (!vips_webpload_buffer(buffer, length, image, "access", access, NULL)) {
|
imageType = ImageType::WEBP;
|
||||||
imageType = WEBP;
|
|
||||||
}
|
|
||||||
#if (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 40)
|
#if (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 40)
|
||||||
} else if (buffer_is_tiff(static_cast<char*>(buffer), length)) {
|
} else if (buffer_is_tiff(static_cast<char*>(buffer), length)) {
|
||||||
if (!vips_tiffload_buffer(buffer, length, image, "access", access, NULL)) {
|
imageType = ImageType::TIFF;
|
||||||
imageType = TIFF;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return imageType;
|
return imageType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initialise a VipsImage from a file.
|
Initialise and return a VipsImage from a buffer. Supports JPEG, PNG, WebP and TIFF.
|
||||||
Returns the ImageType detected, if any.
|
|
||||||
*/
|
*/
|
||||||
ImageType
|
VipsImage* InitImage(ImageType imageType, void *buffer, size_t const length, VipsAccess const access) {
|
||||||
sharp_init_image_from_file(VipsImage **image, char const *file, VipsAccess const access) {
|
VipsImage *image = NULL;
|
||||||
ImageType imageType = UNKNOWN;
|
if (imageType == ImageType::JPEG) {
|
||||||
|
vips_jpegload_buffer(buffer, length, &image, "access", access, NULL);
|
||||||
|
} else if (imageType == ImageType::PNG) {
|
||||||
|
vips_pngload_buffer(buffer, length, &image, "access", access, NULL);
|
||||||
|
} else if (imageType == ImageType::WEBP) {
|
||||||
|
vips_webpload_buffer(buffer, length, &image, "access", access, NULL);
|
||||||
|
#if (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 40)
|
||||||
|
} else if (imageType == ImageType::TIFF) {
|
||||||
|
vips_tiffload_buffer(buffer, length, &image, "access", access, NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Inpect the first 2-4 bytes of a file to determine image format
|
||||||
|
*/
|
||||||
|
ImageType DetermineImageType(char const *file) {
|
||||||
|
ImageType imageType = ImageType::UNKNOWN;
|
||||||
if (vips_foreign_is_a("jpegload", file)) {
|
if (vips_foreign_is_a("jpegload", file)) {
|
||||||
if (!vips_jpegload(file, image, "access", access, NULL)) {
|
imageType = ImageType::JPEG;
|
||||||
imageType = JPEG;
|
|
||||||
}
|
|
||||||
} else if (vips_foreign_is_a("pngload", file)) {
|
} else if (vips_foreign_is_a("pngload", file)) {
|
||||||
if (!vips_pngload(file, image, "access", access, NULL)) {
|
imageType = ImageType::PNG;
|
||||||
imageType = PNG;
|
|
||||||
}
|
|
||||||
} else if (vips_foreign_is_a("webpload", file)) {
|
} else if (vips_foreign_is_a("webpload", file)) {
|
||||||
if (!vips_webpload(file, image, "access", access, NULL)) {
|
imageType = ImageType::WEBP;
|
||||||
imageType = WEBP;
|
|
||||||
}
|
|
||||||
} else if (vips_foreign_is_a("tiffload", file)) {
|
} else if (vips_foreign_is_a("tiffload", file)) {
|
||||||
if (!vips_tiffload(file, image, "access", access, NULL)) {
|
imageType = ImageType::TIFF;
|
||||||
imageType = TIFF;
|
|
||||||
}
|
|
||||||
} else if(vips_foreign_is_a("magickload", file)) {
|
} else if(vips_foreign_is_a("magickload", file)) {
|
||||||
if (!vips_magickload(file, image, "access", access, NULL)) {
|
imageType = ImageType::MAGICK;
|
||||||
imageType = MAGICK;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return imageType;
|
return imageType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Initialise and return a VipsImage from a file.
|
||||||
|
*/
|
||||||
|
VipsImage* InitImage(ImageType imageType, char const *file, VipsAccess const access) {
|
||||||
|
VipsImage *image = NULL;
|
||||||
|
if (imageType == ImageType::JPEG) {
|
||||||
|
vips_jpegload(file, &image, "access", access, NULL);
|
||||||
|
} else if (imageType == ImageType::PNG) {
|
||||||
|
vips_pngload(file, &image, "access", access, NULL);
|
||||||
|
} else if (imageType == ImageType::WEBP) {
|
||||||
|
vips_webpload(file, &image, "access", access, NULL);
|
||||||
|
} else if (imageType == ImageType::TIFF) {
|
||||||
|
vips_tiffload(file, &image, "access", access, NULL);
|
||||||
|
} else if (imageType == ImageType::MAGICK) {
|
||||||
|
vips_magickload(file, &image, "access", access, NULL);
|
||||||
|
}
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Does this image have an alpha channel?
|
Does this image have an alpha channel?
|
||||||
Uses colour space interpretation with number of channels to guess this.
|
Uses colour space interpretation with number of channels to guess this.
|
||||||
*/
|
*/
|
||||||
bool
|
bool HasAlpha(VipsImage *image) {
|
||||||
sharp_image_has_alpha(VipsImage *image) {
|
|
||||||
return (
|
return (
|
||||||
(image->Bands == 2 && image->Type == VIPS_INTERPRETATION_B_W) ||
|
(image->Bands == 2 && image->Type == VIPS_INTERPRETATION_B_W) ||
|
||||||
(image->Bands == 4 && image->Type != VIPS_INTERPRETATION_CMYK) ||
|
(image->Bands == 4 && image->Type != VIPS_INTERPRETATION_CMYK) ||
|
||||||
@ -117,14 +135,30 @@ sharp_image_has_alpha(VipsImage *image) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get EXIF Orientation of image, if any.
|
||||||
|
*/
|
||||||
|
int ExifOrientation(VipsImage const *image) {
|
||||||
|
int orientation = 0;
|
||||||
|
const char *exif;
|
||||||
|
if (
|
||||||
|
vips_image_get_typeof(image, "exif-ifd0-Orientation") != 0 &&
|
||||||
|
!vips_image_get_string(image, "exif-ifd0-Orientation", &exif)
|
||||||
|
) {
|
||||||
|
orientation = atoi(&exif[0]);
|
||||||
|
}
|
||||||
|
return orientation;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Returns the window size for the named interpolator. For example,
|
Returns the window size for the named interpolator. For example,
|
||||||
a window size of 3 means a 3x3 pixel grid is used for the calculation.
|
a window size of 3 means a 3x3 pixel grid is used for the calculation.
|
||||||
*/
|
*/
|
||||||
int
|
int InterpolatorWindowSize(char const *name) {
|
||||||
sharp_interpolator_window_size(char const *name) {
|
|
||||||
VipsInterpolate *interpolator = vips_interpolate_new(name);
|
VipsInterpolate *interpolator = vips_interpolate_new(name);
|
||||||
int window_size = vips_interpolate_get_window_size(interpolator);
|
int window_size = vips_interpolate_get_window_size(interpolator);
|
||||||
g_object_unref(interpolator);
|
g_object_unref(interpolator);
|
||||||
return window_size;
|
return window_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
57
src/common.h
57
src/common.h
@ -1,53 +1,66 @@
|
|||||||
#ifndef SHARP_COMMON_H
|
#ifndef SHARP_COMMON_H
|
||||||
#define SHARP_COMMON_H
|
#define SHARP_COMMON_H
|
||||||
|
|
||||||
typedef enum {
|
namespace sharp {
|
||||||
|
|
||||||
|
enum class ImageType {
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
JPEG,
|
JPEG,
|
||||||
PNG,
|
PNG,
|
||||||
WEBP,
|
WEBP,
|
||||||
TIFF,
|
TIFF,
|
||||||
MAGICK
|
MAGICK
|
||||||
} ImageType;
|
};
|
||||||
|
|
||||||
// Filename extension checkers
|
|
||||||
bool is_jpeg(std::string const &str);
|
|
||||||
bool is_png(std::string const &str);
|
|
||||||
bool is_webp(std::string const &str);
|
|
||||||
bool is_tiff(std::string const &str);
|
|
||||||
|
|
||||||
// How many tasks are in the queue?
|
// How many tasks are in the queue?
|
||||||
extern volatile int counter_queue;
|
extern volatile int counterQueue;
|
||||||
|
|
||||||
// How many tasks are being processed?
|
// How many tasks are being processed?
|
||||||
extern volatile int counter_process;
|
extern volatile int counterProcess;
|
||||||
|
|
||||||
|
// Filename extension checkers
|
||||||
|
bool IsJpeg(std::string const &str);
|
||||||
|
bool IsPng(std::string const &str);
|
||||||
|
bool IsWebp(std::string const &str);
|
||||||
|
bool IsTiff(std::string const &str);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initialise a VipsImage from a buffer. Supports JPEG, PNG and WebP.
|
Determine image format of a buffer.
|
||||||
Returns the ImageType detected, if any.
|
|
||||||
*/
|
*/
|
||||||
ImageType
|
ImageType DetermineImageType(void *buffer, size_t const length);
|
||||||
sharp_init_image_from_buffer(VipsImage **image, void *buffer, size_t const length, VipsAccess const access);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initialise a VipsImage from a file.
|
Determine image format of a file.
|
||||||
Returns the ImageType detected, if any.
|
|
||||||
*/
|
*/
|
||||||
ImageType
|
ImageType DetermineImageType(char const *file);
|
||||||
sharp_init_image_from_file(VipsImage **image, char const *file, VipsAccess const access);
|
|
||||||
|
/*
|
||||||
|
Initialise and return a VipsImage from a buffer. Supports JPEG, PNG, WebP and TIFF.
|
||||||
|
*/
|
||||||
|
VipsImage* InitImage(ImageType imageType, void *buffer, size_t const length, VipsAccess const access);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Initialise and return a VipsImage from a file.
|
||||||
|
*/
|
||||||
|
VipsImage* InitImage(ImageType imageType, char const *file, VipsAccess const access);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Does this image have an alpha channel?
|
Does this image have an alpha channel?
|
||||||
Uses colour space interpretation with number of channels to guess this.
|
Uses colour space interpretation with number of channels to guess this.
|
||||||
*/
|
*/
|
||||||
bool
|
bool HasAlpha(VipsImage *image);
|
||||||
sharp_image_has_alpha(VipsImage *image);
|
|
||||||
|
/*
|
||||||
|
Get EXIF Orientation of image, if any.
|
||||||
|
*/
|
||||||
|
int ExifOrientation(VipsImage const *image);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Returns the window size for the named interpolator. For example,
|
Returns the window size for the named interpolator. For example,
|
||||||
a window size of 3 means a 3x3 pixel grid is used for the calculation.
|
a window size of 3 means a 3x3 pixel grid is used for the calculation.
|
||||||
*/
|
*/
|
||||||
int
|
int InterpolatorWindowSize(char const *name);
|
||||||
sharp_interpolator_window_size(char const *name);
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
|
|
||||||
using namespace v8;
|
using namespace v8;
|
||||||
|
using namespace sharp;
|
||||||
|
|
||||||
struct MetadataBaton {
|
struct MetadataBaton {
|
||||||
// Input
|
// Input
|
||||||
@ -36,49 +37,49 @@ class MetadataWorker : public NanAsyncWorker {
|
|||||||
|
|
||||||
void Execute() {
|
void Execute() {
|
||||||
// Decrement queued task counter
|
// Decrement queued task counter
|
||||||
g_atomic_int_dec_and_test(&counter_queue);
|
g_atomic_int_dec_and_test(&counterQueue);
|
||||||
|
|
||||||
ImageType imageType = UNKNOWN;
|
ImageType imageType = ImageType::UNKNOWN;
|
||||||
VipsImage *image;
|
VipsImage *image = NULL;
|
||||||
if (baton->bufferInLength > 1) {
|
if (baton->bufferInLength > 1) {
|
||||||
// From buffer
|
// From buffer
|
||||||
imageType = sharp_init_image_from_buffer(&image, baton->bufferIn, baton->bufferInLength, VIPS_ACCESS_RANDOM);
|
imageType = DetermineImageType(baton->bufferIn, baton->bufferInLength);
|
||||||
if (imageType == UNKNOWN) {
|
if (imageType != ImageType::UNKNOWN) {
|
||||||
|
image = InitImage(imageType, baton->bufferIn, baton->bufferInLength, VIPS_ACCESS_RANDOM);
|
||||||
|
} else {
|
||||||
(baton->err).append("Input buffer contains unsupported image format");
|
(baton->err).append("Input buffer contains unsupported image format");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// From file
|
// From file
|
||||||
imageType = sharp_init_image_from_file(&image, baton->fileIn.c_str(), VIPS_ACCESS_RANDOM);
|
imageType = DetermineImageType(baton->fileIn.c_str());
|
||||||
if (imageType == UNKNOWN) {
|
if (imageType != ImageType::UNKNOWN) {
|
||||||
|
image = InitImage(imageType, baton->fileIn.c_str(), VIPS_ACCESS_RANDOM);
|
||||||
|
} else {
|
||||||
(baton->err).append("File is of an unsupported image format");
|
(baton->err).append("File is of an unsupported image format");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (imageType != UNKNOWN) {
|
if (image != NULL && imageType != ImageType::UNKNOWN) {
|
||||||
// Image type
|
// Image type
|
||||||
switch (imageType) {
|
switch (imageType) {
|
||||||
case JPEG: baton->format = "jpeg"; break;
|
case ImageType::JPEG: baton->format = "jpeg"; break;
|
||||||
case PNG: baton->format = "png"; break;
|
case ImageType::PNG: baton->format = "png"; break;
|
||||||
case WEBP: baton->format = "webp"; break;
|
case ImageType::WEBP: baton->format = "webp"; break;
|
||||||
case TIFF: baton->format = "tiff"; break;
|
case ImageType::TIFF: baton->format = "tiff"; break;
|
||||||
case MAGICK: baton->format = "magick"; break;
|
case ImageType::MAGICK: baton->format = "magick"; break;
|
||||||
case UNKNOWN: default: baton->format = "";
|
case ImageType::UNKNOWN: break;
|
||||||
}
|
}
|
||||||
// VipsImage attributes
|
// VipsImage attributes
|
||||||
baton->width = image->Xsize;
|
baton->width = image->Xsize;
|
||||||
baton->height = image->Ysize;
|
baton->height = image->Ysize;
|
||||||
baton->space = vips_enum_nick(VIPS_TYPE_INTERPRETATION, image->Type);
|
baton->space = vips_enum_nick(VIPS_TYPE_INTERPRETATION, image->Type);
|
||||||
baton->channels = image->Bands;
|
baton->channels = image->Bands;
|
||||||
baton->hasAlpha = sharp_image_has_alpha(image);
|
// Derived attributes
|
||||||
// EXIF Orientation
|
baton->hasAlpha = HasAlpha(image);
|
||||||
const char *exif;
|
baton->orientation = ExifOrientation(image);
|
||||||
if (!vips_image_get_string(image, "exif-ifd0-Orientation", &exif)) {
|
// Drop image reference
|
||||||
baton->orientation = atoi(&exif[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Clean up
|
|
||||||
if (imageType != UNKNOWN) {
|
|
||||||
g_object_unref(image);
|
g_object_unref(image);
|
||||||
}
|
}
|
||||||
|
// Clean up
|
||||||
vips_error_clear();
|
vips_error_clear();
|
||||||
vips_thread_shutdown();
|
vips_thread_shutdown();
|
||||||
}
|
}
|
||||||
@ -138,7 +139,7 @@ NAN_METHOD(metadata) {
|
|||||||
NanAsyncQueueWorker(new MetadataWorker(callback, baton));
|
NanAsyncQueueWorker(new MetadataWorker(callback, baton));
|
||||||
|
|
||||||
// Increment queued task counter
|
// Increment queued task counter
|
||||||
g_atomic_int_inc(&counter_queue);
|
g_atomic_int_inc(&counterQueue);
|
||||||
|
|
||||||
NanReturnUndefined();
|
NanReturnUndefined();
|
||||||
}
|
}
|
||||||
|
288
src/resize.cc
288
src/resize.cc
@ -11,20 +11,21 @@
|
|||||||
#include "resize.h"
|
#include "resize.h"
|
||||||
|
|
||||||
using namespace v8;
|
using namespace v8;
|
||||||
|
using namespace sharp;
|
||||||
|
|
||||||
typedef enum {
|
enum class Canvas {
|
||||||
CROP,
|
CROP,
|
||||||
MAX,
|
MAX,
|
||||||
EMBED
|
EMBED
|
||||||
} Canvas;
|
};
|
||||||
|
|
||||||
typedef enum {
|
enum class Angle {
|
||||||
ANGLE_0,
|
D0,
|
||||||
ANGLE_90,
|
D90,
|
||||||
ANGLE_180,
|
D180,
|
||||||
ANGLE_270,
|
D270,
|
||||||
ANGLE_LAST
|
DLAST
|
||||||
} Angle;
|
};
|
||||||
|
|
||||||
struct ResizeBaton {
|
struct ResizeBaton {
|
||||||
std::string fileIn;
|
std::string fileIn;
|
||||||
@ -74,7 +75,7 @@ struct ResizeBaton {
|
|||||||
bufferOutLength(0),
|
bufferOutLength(0),
|
||||||
topOffsetPre(-1),
|
topOffsetPre(-1),
|
||||||
topOffsetPost(-1),
|
topOffsetPost(-1),
|
||||||
canvas(CROP),
|
canvas(Canvas::CROP),
|
||||||
gravity(0),
|
gravity(0),
|
||||||
flatten(false),
|
flatten(false),
|
||||||
blurRadius(0),
|
blurRadius(0),
|
||||||
@ -83,10 +84,14 @@ struct ResizeBaton {
|
|||||||
sharpenJagged(2.0),
|
sharpenJagged(2.0),
|
||||||
gamma(0.0),
|
gamma(0.0),
|
||||||
greyscale(false),
|
greyscale(false),
|
||||||
|
angle(0),
|
||||||
flip(false),
|
flip(false),
|
||||||
flop(false),
|
flop(false),
|
||||||
progressive(false),
|
progressive(false),
|
||||||
withoutEnlargement(false),
|
withoutEnlargement(false),
|
||||||
|
quality(80),
|
||||||
|
compressionLevel(6),
|
||||||
|
withoutAdaptiveFiltering(false),
|
||||||
withMetadata(false) {
|
withMetadata(false) {
|
||||||
background[0] = 0.0;
|
background[0] = 0.0;
|
||||||
background[1] = 0.0;
|
background[1] = 0.0;
|
||||||
@ -106,43 +111,45 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
*/
|
*/
|
||||||
void Execute() {
|
void Execute() {
|
||||||
// Decrement queued task counter
|
// Decrement queued task counter
|
||||||
g_atomic_int_dec_and_test(&counter_queue);
|
g_atomic_int_dec_and_test(&counterQueue);
|
||||||
// Increment processing task counter
|
// Increment processing task counter
|
||||||
g_atomic_int_inc(&counter_process);
|
g_atomic_int_inc(&counterProcess);
|
||||||
|
|
||||||
// Hang image references from this hook object
|
// Hang image references from this hook object
|
||||||
VipsObject *hook = reinterpret_cast<VipsObject*>(vips_image_new());
|
VipsObject *hook = reinterpret_cast<VipsObject*>(vips_image_new());
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
ImageType inputImageType = UNKNOWN;
|
ImageType inputImageType = ImageType::UNKNOWN;
|
||||||
VipsImage *image = vips_image_new();
|
VipsImage *image;
|
||||||
vips_object_local(hook, image);
|
|
||||||
|
|
||||||
if (baton->bufferInLength > 1) {
|
if (baton->bufferInLength > 1) {
|
||||||
// From buffer
|
// From buffer
|
||||||
inputImageType = sharp_init_image_from_buffer(&image, baton->bufferIn, baton->bufferInLength, baton->accessMethod);
|
inputImageType = DetermineImageType(baton->bufferIn, baton->bufferInLength);
|
||||||
if (inputImageType == UNKNOWN) {
|
if (inputImageType != ImageType::UNKNOWN) {
|
||||||
|
image = InitImage(inputImageType, baton->bufferIn, baton->bufferInLength, baton->accessMethod);
|
||||||
|
} else {
|
||||||
(baton->err).append("Input buffer contains unsupported image format");
|
(baton->err).append("Input buffer contains unsupported image format");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// From file
|
// From file
|
||||||
inputImageType = sharp_init_image_from_file(&image, baton->fileIn.c_str(), baton->accessMethod);
|
inputImageType = DetermineImageType(baton->fileIn.c_str());
|
||||||
if (inputImageType == UNKNOWN) {
|
if (inputImageType != ImageType::UNKNOWN) {
|
||||||
|
image = InitImage(inputImageType, baton->fileIn.c_str(), baton->accessMethod);
|
||||||
|
} else {
|
||||||
(baton->err).append("File is of an unsupported image format");
|
(baton->err).append("File is of an unsupported image format");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (inputImageType == UNKNOWN) {
|
if (inputImageType == ImageType::UNKNOWN) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
|
vips_object_local(hook, image);
|
||||||
|
|
||||||
// Pre extraction
|
// Pre extraction
|
||||||
if (baton->topOffsetPre != -1) {
|
if (baton->topOffsetPre != -1) {
|
||||||
VipsImage *extractedPre = vips_image_new();
|
VipsImage *extractedPre;
|
||||||
vips_object_local(hook, extractedPre);
|
|
||||||
if (vips_extract_area(image, &extractedPre, baton->leftOffsetPre, baton->topOffsetPre, baton->widthPre, baton->heightPre, NULL)) {
|
if (vips_extract_area(image, &extractedPre, baton->leftOffsetPre, baton->topOffsetPre, baton->widthPre, baton->heightPre, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, extractedPre);
|
||||||
image = extractedPre;
|
image = extractedPre;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +161,7 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
Angle rotation;
|
Angle rotation;
|
||||||
bool flip;
|
bool flip;
|
||||||
std::tie(rotation, flip) = CalculateRotationAndFlip(baton->angle, image);
|
std::tie(rotation, flip) = CalculateRotationAndFlip(baton->angle, image);
|
||||||
if (rotation == ANGLE_90 || rotation == ANGLE_270) {
|
if (rotation == Angle::D90 || rotation == Angle::D270) {
|
||||||
// Swap input output width and height when rotating by 90 or 270 degrees
|
// Swap input output width and height when rotating by 90 or 270 degrees
|
||||||
int swap = inputWidth;
|
int swap = inputWidth;
|
||||||
inputWidth = inputHeight;
|
inputWidth = inputHeight;
|
||||||
@ -166,7 +173,7 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get window size of interpolator, used for determining shrink vs affine
|
// Get window size of interpolator, used for determining shrink vs affine
|
||||||
int interpolatorWindowSize = sharp_interpolator_window_size(baton->interpolator.c_str());
|
int interpolatorWindowSize = InterpolatorWindowSize(baton->interpolator.c_str());
|
||||||
|
|
||||||
// Scaling calculations
|
// Scaling calculations
|
||||||
double factor;
|
double factor;
|
||||||
@ -174,9 +181,9 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
// Fixed width and height
|
// Fixed width and height
|
||||||
double xfactor = static_cast<double>(inputWidth) / static_cast<double>(baton->width);
|
double xfactor = static_cast<double>(inputWidth) / static_cast<double>(baton->width);
|
||||||
double yfactor = static_cast<double>(inputHeight) / static_cast<double>(baton->height);
|
double yfactor = static_cast<double>(inputHeight) / static_cast<double>(baton->height);
|
||||||
factor = (baton->canvas == CROP) ? std::min(xfactor, yfactor) : std::max(xfactor, yfactor);
|
factor = (baton->canvas == Canvas::CROP) ? std::min(xfactor, yfactor) : std::max(xfactor, yfactor);
|
||||||
// if max is set, we need to compute the real size of the thumb image
|
// if max is set, we need to compute the real size of the thumb image
|
||||||
if (baton->canvas == MAX) {
|
if (baton->canvas == Canvas::MAX) {
|
||||||
if (xfactor > yfactor) {
|
if (xfactor > yfactor) {
|
||||||
baton->height = round(static_cast<double>(inputHeight) / xfactor);
|
baton->height = round(static_cast<double>(inputHeight) / xfactor);
|
||||||
} else {
|
} else {
|
||||||
@ -226,7 +233,7 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
|
|
||||||
// Try to use libjpeg shrink-on-load, but not when applying gamma correction or pre-resize extract
|
// Try to use libjpeg shrink-on-load, but not when applying gamma correction or pre-resize extract
|
||||||
int shrink_on_load = 1;
|
int shrink_on_load = 1;
|
||||||
if (inputImageType == JPEG && shrink >= 2 && baton->gamma == 0 && baton->topOffsetPre == -1) {
|
if (inputImageType == ImageType::JPEG && shrink >= 2 && baton->gamma == 0 && baton->topOffsetPre == -1) {
|
||||||
if (shrink >= 8) {
|
if (shrink >= 8) {
|
||||||
factor = factor / 8;
|
factor = factor / 8;
|
||||||
shrink_on_load = 8;
|
shrink_on_load = 8;
|
||||||
@ -248,52 +255,51 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
}
|
}
|
||||||
residual = static_cast<double>(shrink) / factor;
|
residual = static_cast<double>(shrink) / factor;
|
||||||
// Reload input using shrink-on-load
|
// Reload input using shrink-on-load
|
||||||
g_object_unref(image);
|
VipsImage *shrunkOnLoad;
|
||||||
if (baton->bufferInLength > 1) {
|
if (baton->bufferInLength > 1) {
|
||||||
if (vips_jpegload_buffer(baton->bufferIn, baton->bufferInLength, &image, "shrink", shrink_on_load, NULL)) {
|
if (vips_jpegload_buffer(baton->bufferIn, baton->bufferInLength, &shrunkOnLoad, "shrink", shrink_on_load, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (vips_jpegload((baton->fileIn).c_str(), &image, "shrink", shrink_on_load, NULL)) {
|
if (vips_jpegload((baton->fileIn).c_str(), &shrunkOnLoad, "shrink", shrink_on_load, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
vips_object_local(hook, shrunkOnLoad);
|
||||||
|
image = shrunkOnLoad;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle colour profile, if any, for non sRGB images
|
// Handle colour profile, if any, for non sRGB images
|
||||||
if (image->Type != VIPS_INTERPRETATION_sRGB) {
|
if (image->Type != VIPS_INTERPRETATION_sRGB) {
|
||||||
// Get the input colour profile
|
// Get the input colour profile
|
||||||
if (vips_image_get_typeof(image, VIPS_META_ICC_NAME)) {
|
if (vips_image_get_typeof(image, VIPS_META_ICC_NAME)) {
|
||||||
|
VipsImage *profile;
|
||||||
// Use embedded profile
|
// Use embedded profile
|
||||||
VipsImage *profile = vips_image_new();
|
|
||||||
vips_object_local(hook, profile);
|
|
||||||
if (vips_icc_import(image, &profile, "pcs", VIPS_PCS_XYZ, "embedded", TRUE, NULL)) {
|
if (vips_icc_import(image, &profile, "pcs", VIPS_PCS_XYZ, "embedded", TRUE, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, profile);
|
||||||
image = profile;
|
image = profile;
|
||||||
} else if (image->Type == VIPS_INTERPRETATION_CMYK) {
|
} else if (image->Type == VIPS_INTERPRETATION_CMYK) {
|
||||||
|
VipsImage *profile;
|
||||||
// CMYK with no embedded profile
|
// CMYK with no embedded profile
|
||||||
VipsImage *profile = vips_image_new();
|
|
||||||
vips_object_local(hook, profile);
|
|
||||||
if (vips_icc_import(image, &profile, "pcs", VIPS_PCS_XYZ, "input_profile", (baton->iccProfileCmyk).c_str(), NULL)) {
|
if (vips_icc_import(image, &profile, "pcs", VIPS_PCS_XYZ, "input_profile", (baton->iccProfileCmyk).c_str(), NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, profile);
|
||||||
image = profile;
|
image = profile;
|
||||||
}
|
}
|
||||||
// Attempt to convert to sRGB colour space
|
// Attempt to convert to sRGB colour space
|
||||||
VipsImage *colourspaced = vips_image_new();
|
VipsImage *colourspaced;
|
||||||
vips_object_local(hook, colourspaced);
|
|
||||||
if (vips_colourspace(image, &colourspaced, VIPS_INTERPRETATION_sRGB, NULL)) {
|
if (vips_colourspace(image, &colourspaced, VIPS_INTERPRETATION_sRGB, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, colourspaced);
|
||||||
image = colourspaced;
|
image = colourspaced;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flatten image to remove alpha channel
|
// Flatten image to remove alpha channel
|
||||||
if (baton->flatten && sharp_image_has_alpha(image)) {
|
if (baton->flatten && HasAlpha(image)) {
|
||||||
// Background colour
|
// Background colour
|
||||||
VipsArrayDouble *background = vips_array_double_newv(
|
VipsArrayDouble *background = vips_array_double_newv(
|
||||||
3, // Ignore alpha channel as we're about to remove it
|
3, // Ignore alpha channel as we're about to remove it
|
||||||
@ -301,52 +307,48 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
baton->background[1],
|
baton->background[1],
|
||||||
baton->background[2]
|
baton->background[2]
|
||||||
);
|
);
|
||||||
VipsImage *flattened = vips_image_new();
|
VipsImage *flattened;
|
||||||
vips_object_local(hook, flattened);
|
|
||||||
if (vips_flatten(image, &flattened, "background", background, NULL)) {
|
if (vips_flatten(image, &flattened, "background", background, NULL)) {
|
||||||
vips_area_unref(reinterpret_cast<VipsArea*>(background));
|
vips_area_unref(reinterpret_cast<VipsArea*>(background));
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
};
|
};
|
||||||
vips_area_unref(reinterpret_cast<VipsArea*>(background));
|
vips_area_unref(reinterpret_cast<VipsArea*>(background));
|
||||||
g_object_unref(image);
|
vips_object_local(hook, flattened);
|
||||||
image = flattened;
|
image = flattened;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gamma encoding (darken)
|
// Gamma encoding (darken)
|
||||||
if (baton->gamma >= 1 && baton->gamma <= 3) {
|
if (baton->gamma >= 1 && baton->gamma <= 3) {
|
||||||
VipsImage *gammaEncoded = vips_image_new();
|
VipsImage *gammaEncoded;
|
||||||
vips_object_local(hook, gammaEncoded);
|
|
||||||
if (vips_gamma(image, &gammaEncoded, "exponent", 1.0 / baton->gamma, NULL)) {
|
if (vips_gamma(image, &gammaEncoded, "exponent", 1.0 / baton->gamma, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, gammaEncoded);
|
||||||
image = gammaEncoded;
|
image = gammaEncoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to greyscale (linear, therefore after gamma encoding, if any)
|
// Convert to greyscale (linear, therefore after gamma encoding, if any)
|
||||||
if (baton->greyscale) {
|
if (baton->greyscale) {
|
||||||
VipsImage *greyscale = vips_image_new();
|
VipsImage *greyscale;
|
||||||
vips_object_local(hook, greyscale);
|
|
||||||
if (vips_colourspace(image, &greyscale, VIPS_INTERPRETATION_B_W, NULL)) {
|
if (vips_colourspace(image, &greyscale, VIPS_INTERPRETATION_B_W, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, greyscale);
|
||||||
image = greyscale;
|
image = greyscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shrink > 1) {
|
if (shrink > 1) {
|
||||||
VipsImage *shrunk = vips_image_new();
|
VipsImage *shrunk;
|
||||||
vips_object_local(hook, shrunk);
|
|
||||||
// Use vips_shrink with the integral reduction
|
// Use vips_shrink with the integral reduction
|
||||||
if (vips_shrink(image, &shrunk, shrink, shrink, NULL)) {
|
if (vips_shrink(image, &shrunk, shrink, shrink, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, shrunk);
|
||||||
image = shrunk;
|
image = shrunk;
|
||||||
// Recalculate residual float based on dimensions of required vs shrunk images
|
// Recalculate residual float based on dimensions of required vs shrunk images
|
||||||
double shrunkWidth = shrunk->Xsize;
|
double shrunkWidth = shrunk->Xsize;
|
||||||
double shrunkHeight = shrunk->Ysize;
|
double shrunkHeight = shrunk->Ysize;
|
||||||
if (rotation == ANGLE_90 || rotation == ANGLE_270) {
|
if (rotation == Angle::D90 || rotation == Angle::D270) {
|
||||||
// Swap input output width and height when rotating by 90 or 270 degrees
|
// Swap input output width and height when rotating by 90 or 270 degrees
|
||||||
int swap = shrunkWidth;
|
int swap = shrunkWidth;
|
||||||
shrunkWidth = shrunkHeight;
|
shrunkWidth = shrunkHeight;
|
||||||
@ -354,7 +356,7 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
}
|
}
|
||||||
double residualx = static_cast<double>(baton->width) / static_cast<double>(shrunkWidth);
|
double residualx = static_cast<double>(baton->width) / static_cast<double>(shrunkWidth);
|
||||||
double residualy = static_cast<double>(baton->height) / static_cast<double>(shrunkHeight);
|
double residualy = static_cast<double>(baton->height) / static_cast<double>(shrunkHeight);
|
||||||
if (baton->canvas == EMBED) {
|
if (baton->canvas == Canvas::EMBED) {
|
||||||
residual = std::min(residualx, residualy);
|
residual = std::min(residualx, residualy);
|
||||||
} else {
|
} else {
|
||||||
residual = std::max(residualx, residualy);
|
residual = std::max(residualx, residualy);
|
||||||
@ -365,98 +367,88 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
if (residual != 0) {
|
if (residual != 0) {
|
||||||
// Apply variable blur radius of floor(residual) before large affine reductions
|
// Apply variable blur radius of floor(residual) before large affine reductions
|
||||||
if (residual >= 1) {
|
if (residual >= 1) {
|
||||||
VipsImage *blurred = vips_image_new();
|
VipsImage *blurred;
|
||||||
vips_object_local(hook, blurred);
|
|
||||||
if (vips_gaussblur(image, &blurred, floor(residual), NULL)) {
|
if (vips_gaussblur(image, &blurred, floor(residual), NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, blurred);
|
||||||
image = blurred;
|
image = blurred;
|
||||||
}
|
}
|
||||||
// Create interpolator - "bilinear" (default), "bicubic" or "nohalo"
|
// Create interpolator - "bilinear" (default), "bicubic" or "nohalo"
|
||||||
VipsInterpolate *interpolator = vips_interpolate_new(baton->interpolator.c_str());
|
VipsInterpolate *interpolator = vips_interpolate_new(baton->interpolator.c_str());
|
||||||
|
vips_object_local(hook, interpolator);
|
||||||
// Perform affine transformation
|
// Perform affine transformation
|
||||||
VipsImage *affined = vips_image_new();
|
VipsImage *affined;
|
||||||
vips_object_local(hook, affined);
|
|
||||||
if (vips_affine(image, &affined, residual, 0, 0, residual, "interpolate", interpolator, NULL)) {
|
if (vips_affine(image, &affined, residual, 0, 0, residual, "interpolate", interpolator, NULL)) {
|
||||||
g_object_unref(interpolator);
|
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(interpolator);
|
vips_object_local(hook, affined);
|
||||||
g_object_unref(image);
|
|
||||||
image = affined;
|
image = affined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rotate
|
// Rotate
|
||||||
if (rotation != ANGLE_0) {
|
if (rotation != Angle::D0) {
|
||||||
VipsImage *rotated = vips_image_new();
|
VipsImage *rotated;
|
||||||
vips_object_local(hook, rotated);
|
|
||||||
if (vips_rot(image, &rotated, static_cast<VipsAngle>(rotation), NULL)) {
|
if (vips_rot(image, &rotated, static_cast<VipsAngle>(rotation), NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, rotated);
|
||||||
image = rotated;
|
image = rotated;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flip (mirror about Y axis)
|
// Flip (mirror about Y axis)
|
||||||
if (baton->flip) {
|
if (baton->flip) {
|
||||||
VipsImage *flipped = vips_image_new();
|
VipsImage *flipped;
|
||||||
vips_object_local(hook, flipped);
|
|
||||||
if (vips_flip(image, &flipped, VIPS_DIRECTION_VERTICAL, NULL)) {
|
if (vips_flip(image, &flipped, VIPS_DIRECTION_VERTICAL, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, flipped);
|
||||||
image = flipped;
|
image = flipped;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flop (mirror about X axis)
|
// Flop (mirror about X axis)
|
||||||
if (baton->flop) {
|
if (baton->flop) {
|
||||||
VipsImage *flopped = vips_image_new();
|
VipsImage *flopped;
|
||||||
vips_object_local(hook, flopped);
|
|
||||||
if (vips_flip(image, &flopped, VIPS_DIRECTION_HORIZONTAL, NULL)) {
|
if (vips_flip(image, &flopped, VIPS_DIRECTION_HORIZONTAL, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, flopped);
|
||||||
image = flopped;
|
image = flopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crop/embed
|
// Crop/embed
|
||||||
if (image->Xsize != baton->width || image->Ysize != baton->height) {
|
if (image->Xsize != baton->width || image->Ysize != baton->height) {
|
||||||
if (baton->canvas == EMBED) {
|
if (baton->canvas == Canvas::EMBED) {
|
||||||
// Match background colour space, namely sRGB
|
// Match background colour space, namely sRGB
|
||||||
if (image->Type != VIPS_INTERPRETATION_sRGB) {
|
if (image->Type != VIPS_INTERPRETATION_sRGB) {
|
||||||
// Convert to sRGB colour space
|
// Convert to sRGB colour space
|
||||||
VipsImage *colourspaced = vips_image_new();
|
VipsImage *colourspaced;
|
||||||
vips_object_local(hook, colourspaced);
|
|
||||||
if (vips_colourspace(image, &colourspaced, VIPS_INTERPRETATION_sRGB, NULL)) {
|
if (vips_colourspace(image, &colourspaced, VIPS_INTERPRETATION_sRGB, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, colourspaced);
|
||||||
image = colourspaced;
|
image = colourspaced;
|
||||||
}
|
}
|
||||||
// Add non-transparent alpha channel, if required
|
// Add non-transparent alpha channel, if required
|
||||||
if (baton->background[3] < 255.0 && !sharp_image_has_alpha(image)) {
|
if (baton->background[3] < 255.0 && !HasAlpha(image)) {
|
||||||
// Create single-channel transparency
|
// Create single-channel transparency
|
||||||
VipsImage *black = vips_image_new();
|
VipsImage *black;
|
||||||
vips_object_local(hook, black);
|
|
||||||
if (vips_black(&black, image->Xsize, image->Ysize, "bands", 1, NULL)) {
|
if (vips_black(&black, image->Xsize, image->Ysize, "bands", 1, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
|
vips_object_local(hook, black);
|
||||||
// Invert to become non-transparent
|
// Invert to become non-transparent
|
||||||
VipsImage *alpha = vips_image_new();
|
VipsImage *alpha;
|
||||||
vips_object_local(hook, alpha);
|
|
||||||
if (vips_invert(black, &alpha, NULL)) {
|
if (vips_invert(black, &alpha, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(black);
|
vips_object_local(hook, alpha);
|
||||||
// Append alpha channel to existing image
|
// Append alpha channel to existing image
|
||||||
VipsImage *joined = vips_image_new();
|
VipsImage *joined;
|
||||||
vips_object_local(hook, joined);
|
|
||||||
if (vips_bandjoin2(image, alpha, &joined, NULL)) {
|
if (vips_bandjoin2(image, alpha, &joined, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(alpha);
|
vips_object_local(hook, joined);
|
||||||
g_object_unref(image);
|
|
||||||
image = joined;
|
image = joined;
|
||||||
}
|
}
|
||||||
// Create background
|
// Create background
|
||||||
@ -473,8 +465,7 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
// Embed
|
// Embed
|
||||||
int left = (baton->width - image->Xsize) / 2;
|
int left = (baton->width - image->Xsize) / 2;
|
||||||
int top = (baton->height - image->Ysize) / 2;
|
int top = (baton->height - image->Ysize) / 2;
|
||||||
VipsImage *embedded = vips_image_new();
|
VipsImage *embedded;
|
||||||
vips_object_local(hook, embedded);
|
|
||||||
if (vips_embed(image, &embedded, left, top, baton->width, baton->height,
|
if (vips_embed(image, &embedded, left, top, baton->width, baton->height,
|
||||||
"extend", VIPS_EXTEND_BACKGROUND, "background", background, NULL
|
"extend", VIPS_EXTEND_BACKGROUND, "background", background, NULL
|
||||||
)) {
|
)) {
|
||||||
@ -482,7 +473,7 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
vips_area_unref(reinterpret_cast<VipsArea*>(background));
|
vips_area_unref(reinterpret_cast<VipsArea*>(background));
|
||||||
g_object_unref(image);
|
vips_object_local(hook, embedded);
|
||||||
image = embedded;
|
image = embedded;
|
||||||
} else {
|
} else {
|
||||||
// Crop/max
|
// Crop/max
|
||||||
@ -491,31 +482,28 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
std::tie(left, top) = CalculateCrop(image->Xsize, image->Ysize, baton->width, baton->height, baton->gravity);
|
std::tie(left, top) = CalculateCrop(image->Xsize, image->Ysize, baton->width, baton->height, baton->gravity);
|
||||||
int width = std::min(image->Xsize, baton->width);
|
int width = std::min(image->Xsize, baton->width);
|
||||||
int height = std::min(image->Ysize, baton->height);
|
int height = std::min(image->Ysize, baton->height);
|
||||||
VipsImage *extracted = vips_image_new();
|
VipsImage *extracted;
|
||||||
vips_object_local(hook, extracted);
|
|
||||||
if (vips_extract_area(image, &extracted, left, top, width, height, NULL)) {
|
if (vips_extract_area(image, &extracted, left, top, width, height, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, extracted);
|
||||||
image = extracted;
|
image = extracted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post extraction
|
// Post extraction
|
||||||
if (baton->topOffsetPost != -1) {
|
if (baton->topOffsetPost != -1) {
|
||||||
VipsImage *extractedPost = vips_image_new();
|
VipsImage *extractedPost;
|
||||||
vips_object_local(hook, extractedPost);
|
|
||||||
if (vips_extract_area(image, &extractedPost, baton->leftOffsetPost, baton->topOffsetPost, baton->widthPost, baton->heightPost, NULL)) {
|
if (vips_extract_area(image, &extractedPost, baton->leftOffsetPost, baton->topOffsetPost, baton->widthPost, baton->heightPost, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, extractedPost);
|
||||||
image = extractedPost;
|
image = extractedPost;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blur
|
// Blur
|
||||||
if (baton->blurRadius != 0) {
|
if (baton->blurRadius != 0) {
|
||||||
VipsImage *blurred = vips_image_new();
|
VipsImage *blurred;
|
||||||
vips_object_local(hook, blurred);
|
|
||||||
if (baton->blurRadius == -1) {
|
if (baton->blurRadius == -1) {
|
||||||
// Fast, mild blur
|
// Fast, mild blur
|
||||||
VipsImage *blur = vips_image_new_matrixv(3, 3,
|
VipsImage *blur = vips_image_new_matrixv(3, 3,
|
||||||
@ -533,14 +521,13 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, blurred);
|
||||||
image = blurred;
|
image = blurred;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sharpen
|
// Sharpen
|
||||||
if (baton->sharpenRadius != 0) {
|
if (baton->sharpenRadius != 0) {
|
||||||
VipsImage *sharpened = vips_image_new();
|
VipsImage *sharpened;
|
||||||
vips_object_local(hook, sharpened);
|
|
||||||
if (baton->sharpenRadius == -1) {
|
if (baton->sharpenRadius == -1) {
|
||||||
// Fast, mild sharpen
|
// Fast, mild sharpen
|
||||||
VipsImage *sharpen = vips_image_new_matrixv(3, 3,
|
VipsImage *sharpen = vips_image_new_matrixv(3, 3,
|
||||||
@ -558,54 +545,51 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, sharpened);
|
||||||
image = sharpened;
|
image = sharpened;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gamma decoding (brighten)
|
// Gamma decoding (brighten)
|
||||||
if (baton->gamma >= 1 && baton->gamma <= 3) {
|
if (baton->gamma >= 1 && baton->gamma <= 3) {
|
||||||
VipsImage *gammaDecoded = vips_image_new();
|
VipsImage *gammaDecoded;
|
||||||
vips_object_local(hook, gammaDecoded);
|
|
||||||
if (vips_gamma(image, &gammaDecoded, "exponent", baton->gamma, NULL)) {
|
if (vips_gamma(image, &gammaDecoded, "exponent", baton->gamma, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, gammaDecoded);
|
||||||
image = gammaDecoded;
|
image = gammaDecoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to sRGB colour space, if not already
|
// Convert to sRGB colour space, if not already
|
||||||
if (image->Type != VIPS_INTERPRETATION_sRGB) {
|
if (image->Type != VIPS_INTERPRETATION_sRGB) {
|
||||||
VipsImage *colourspaced = vips_image_new();
|
VipsImage *colourspaced;
|
||||||
vips_object_local(hook, colourspaced);
|
|
||||||
if (vips_colourspace(image, &colourspaced, VIPS_INTERPRETATION_sRGB, NULL)) {
|
if (vips_colourspace(image, &colourspaced, VIPS_INTERPRETATION_sRGB, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, colourspaced);
|
||||||
image = colourspaced;
|
image = colourspaced;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !(VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 40 && VIPS_MINOR_VERSION >= 5)
|
#if !(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+
|
// Generate image tile cache when interlace output is required - no longer required as of libvips 7.40.5+
|
||||||
if (baton->progressive) {
|
if (baton->progressive) {
|
||||||
VipsImage *cached = vips_image_new();
|
VipsImage *cached;
|
||||||
vips_object_local(hook, cached);
|
|
||||||
if (vips_tilecache(image, &cached, "threaded", TRUE, "persistent", TRUE, "max_tiles", -1, NULL)) {
|
if (vips_tilecache(image, &cached, "threaded", TRUE, "persistent", TRUE, "max_tiles", -1, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
g_object_unref(image);
|
vips_object_local(hook, cached);
|
||||||
image = cached;
|
image = cached;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Output
|
// Output
|
||||||
if (baton->output == "__jpeg" || (baton->output == "__input" && inputImageType == JPEG)) {
|
if (baton->output == "__jpeg" || (baton->output == "__input" && inputImageType == ImageType::JPEG)) {
|
||||||
// Write JPEG to buffer
|
// Write JPEG to buffer
|
||||||
if (vips_jpegsave_buffer(image, &baton->bufferOut, &baton->bufferOutLength, "strip", !baton->withMetadata,
|
if (vips_jpegsave_buffer(image, &baton->bufferOut, &baton->bufferOutLength, "strip", !baton->withMetadata,
|
||||||
"Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progressive, NULL)) {
|
"Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progressive, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
baton->outputFormat = "jpeg";
|
baton->outputFormat = "jpeg";
|
||||||
} else if (baton->output == "__png" || (baton->output == "__input" && inputImageType == PNG)) {
|
} else if (baton->output == "__png" || (baton->output == "__input" && inputImageType == ImageType::PNG)) {
|
||||||
#if (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 41)
|
#if (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 41)
|
||||||
// Select PNG row filter
|
// Select PNG row filter
|
||||||
int filter = baton->withoutAdaptiveFiltering ? VIPS_FOREIGN_PNG_FILTER_NONE : VIPS_FOREIGN_PNG_FILTER_ALL;
|
int filter = baton->withoutAdaptiveFiltering ? VIPS_FOREIGN_PNG_FILTER_NONE : VIPS_FOREIGN_PNG_FILTER_ALL;
|
||||||
@ -622,7 +606,7 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
baton->outputFormat = "png";
|
baton->outputFormat = "png";
|
||||||
} else if (baton->output == "__webp" || (baton->output == "__input" && inputImageType == WEBP)) {
|
} else if (baton->output == "__webp" || (baton->output == "__input" && inputImageType == ImageType::WEBP)) {
|
||||||
// Write WEBP to buffer
|
// Write WEBP to buffer
|
||||||
if (vips_webpsave_buffer(image, &baton->bufferOut, &baton->bufferOutLength, "strip", !baton->withMetadata,
|
if (vips_webpsave_buffer(image, &baton->bufferOut, &baton->bufferOutLength, "strip", !baton->withMetadata,
|
||||||
"Q", baton->quality, NULL)) {
|
"Q", baton->quality, NULL)) {
|
||||||
@ -630,19 +614,19 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
}
|
}
|
||||||
baton->outputFormat = "webp";
|
baton->outputFormat = "webp";
|
||||||
} else {
|
} else {
|
||||||
bool output_jpeg = is_jpeg(baton->output);
|
bool outputJpeg = IsJpeg(baton->output);
|
||||||
bool output_png = is_png(baton->output);
|
bool outputPng = IsPng(baton->output);
|
||||||
bool output_webp = is_webp(baton->output);
|
bool outputWebp = IsWebp(baton->output);
|
||||||
bool output_tiff = is_tiff(baton->output);
|
bool outputTiff = IsTiff(baton->output);
|
||||||
bool match_input = !(output_jpeg || output_png || output_webp || output_tiff);
|
bool matchInput = !(outputJpeg || outputPng || outputWebp || outputTiff);
|
||||||
if (output_jpeg || (match_input && inputImageType == 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,
|
||||||
"Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progressive, NULL)) {
|
"Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progressive, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
baton->outputFormat = "jpeg";
|
baton->outputFormat = "jpeg";
|
||||||
} else if (output_png || (match_input && inputImageType == PNG)) {
|
} else if (outputPng || (matchInput && inputImageType == ImageType::PNG)) {
|
||||||
#if (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 41)
|
#if (VIPS_MAJOR_VERSION >= 7 && VIPS_MINOR_VERSION >= 41)
|
||||||
// Select PNG row filter
|
// Select PNG row filter
|
||||||
int filter = baton->withoutAdaptiveFiltering ? VIPS_FOREIGN_PNG_FILTER_NONE : VIPS_FOREIGN_PNG_FILTER_ALL;
|
int filter = baton->withoutAdaptiveFiltering ? VIPS_FOREIGN_PNG_FILTER_NONE : VIPS_FOREIGN_PNG_FILTER_ALL;
|
||||||
@ -659,14 +643,14 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
baton->outputFormat = "png";
|
baton->outputFormat = "png";
|
||||||
} else if (output_webp || (match_input && inputImageType == WEBP)) {
|
} else if (outputWebp || (matchInput && inputImageType == ImageType::WEBP)) {
|
||||||
// Write WEBP to file
|
// Write WEBP to file
|
||||||
if (vips_webpsave(image, baton->output.c_str(), "strip", !baton->withMetadata,
|
if (vips_webpsave(image, baton->output.c_str(), "strip", !baton->withMetadata,
|
||||||
"Q", baton->quality, NULL)) {
|
"Q", baton->quality, NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
baton->outputFormat = "webp";
|
baton->outputFormat = "webp";
|
||||||
} else if (output_tiff || (match_input && inputImageType == TIFF)) {
|
} else if (outputTiff || (matchInput && inputImageType == ImageType::TIFF)) {
|
||||||
// Write TIFF to file
|
// Write TIFF to file
|
||||||
if (vips_tiffsave(image, baton->output.c_str(), "strip", !baton->withMetadata,
|
if (vips_tiffsave(image, baton->output.c_str(), "strip", !baton->withMetadata,
|
||||||
"compression", VIPS_FOREIGN_TIFF_COMPRESSION_JPEG, "Q", baton->quality, NULL)) {
|
"compression", VIPS_FOREIGN_TIFF_COMPRESSION_JPEG, "Q", baton->quality, NULL)) {
|
||||||
@ -675,12 +659,10 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
baton->outputFormat = "tiff";
|
baton->outputFormat = "tiff";
|
||||||
} else {
|
} else {
|
||||||
(baton->err).append("Unsupported output " + baton->output);
|
(baton->err).append("Unsupported output " + baton->output);
|
||||||
g_object_unref(image);
|
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Clean up any dangling image references
|
// Clean up any dangling image references
|
||||||
g_object_unref(image);
|
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
// Clean up libvips' per-request data and threads
|
// Clean up libvips' per-request data and threads
|
||||||
vips_error_clear();
|
vips_error_clear();
|
||||||
@ -724,7 +706,7 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
delete baton;
|
delete baton;
|
||||||
|
|
||||||
// Decrement processing task counter
|
// Decrement processing task counter
|
||||||
g_atomic_int_dec_and_test(&counter_process);
|
g_atomic_int_dec_and_test(&counterProcess);
|
||||||
|
|
||||||
// Return to JavaScript
|
// Return to JavaScript
|
||||||
callback->Call(3, argv);
|
callback->Call(3, argv);
|
||||||
@ -742,40 +724,25 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
*/
|
*/
|
||||||
std::tuple<Angle, bool>
|
std::tuple<Angle, bool>
|
||||||
CalculateRotationAndFlip(int const angle, VipsImage const *input) {
|
CalculateRotationAndFlip(int const angle, VipsImage const *input) {
|
||||||
Angle rotate = ANGLE_0;
|
Angle rotate = Angle::D0;
|
||||||
bool flip = FALSE;
|
bool flip = FALSE;
|
||||||
if (angle == -1) {
|
if (angle == -1) {
|
||||||
const char *exif;
|
switch(ExifOrientation(input)) {
|
||||||
if (
|
case 6: rotate = Angle::D90; break;
|
||||||
vips_image_get_typeof(input, "exif-ifd0-Orientation") != 0 &&
|
case 3: rotate = Angle::D180; break;
|
||||||
!vips_image_get_string(input, "exif-ifd0-Orientation", &exif)
|
case 8: rotate = Angle::D270; break;
|
||||||
) {
|
case 2: flip = TRUE; break; // flip 1
|
||||||
if (exif[0] == 0x36) { // "6"
|
case 7: flip = TRUE; rotate = Angle::D90; break; // flip 6
|
||||||
rotate = ANGLE_90;
|
case 4: flip = TRUE; rotate = Angle::D180; break; // flip 3
|
||||||
} else if (exif[0] == 0x33) { // "3"
|
case 5: flip = TRUE; rotate = Angle::D270; break; // flip 8
|
||||||
rotate = ANGLE_180;
|
|
||||||
} else if (exif[0] == 0x38) { // "8"
|
|
||||||
rotate = ANGLE_270;
|
|
||||||
} else if (exif[0] == 0x32) { // "2" (flip 1)
|
|
||||||
flip = TRUE;
|
|
||||||
} else if (exif[0] == 0x37) { // "7" (flip 6)
|
|
||||||
rotate = ANGLE_90;
|
|
||||||
flip = TRUE;
|
|
||||||
} else if (exif[0] == 0x34) { // "4" (flip 3)
|
|
||||||
rotate = ANGLE_180;
|
|
||||||
flip = TRUE;
|
|
||||||
} else if (exif[0] == 0x35) { // "5" (flip 8)
|
|
||||||
rotate = ANGLE_270;
|
|
||||||
flip = TRUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (angle == 90) {
|
if (angle == 90) {
|
||||||
rotate = ANGLE_90;
|
rotate = Angle::D90;
|
||||||
} else if (angle == 180) {
|
} else if (angle == 180) {
|
||||||
rotate = ANGLE_180;
|
rotate = Angle::D180;
|
||||||
} else if (angle == 270) {
|
} else if (angle == 270) {
|
||||||
rotate = ANGLE_270;
|
rotate = Angle::D270;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::make_tuple(rotate, flip);
|
return std::make_tuple(rotate, flip);
|
||||||
@ -817,9 +784,12 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
Clear all thread-local data.
|
Clear all thread-local data.
|
||||||
*/
|
*/
|
||||||
void Error(ResizeBaton *baton, VipsObject *hook) {
|
void Error(ResizeBaton *baton, VipsObject *hook) {
|
||||||
|
// Get libvips' error message
|
||||||
(baton->err).append(vips_error_buffer());
|
(baton->err).append(vips_error_buffer());
|
||||||
vips_error_clear();
|
// Clean up any dangling image references
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
|
// Clean up libvips' per-request data and threads
|
||||||
|
vips_error_clear();
|
||||||
vips_thread_shutdown();
|
vips_thread_shutdown();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -860,11 +830,11 @@ NAN_METHOD(resize) {
|
|||||||
// Canvas option
|
// Canvas option
|
||||||
Local<String> canvas = options->Get(NanNew<String>("canvas"))->ToString();
|
Local<String> canvas = options->Get(NanNew<String>("canvas"))->ToString();
|
||||||
if (canvas->Equals(NanNew<String>("c"))) {
|
if (canvas->Equals(NanNew<String>("c"))) {
|
||||||
baton->canvas = CROP;
|
baton->canvas = Canvas::CROP;
|
||||||
} else if (canvas->Equals(NanNew<String>("m"))) {
|
} else if (canvas->Equals(NanNew<String>("m"))) {
|
||||||
baton->canvas = MAX;
|
baton->canvas = Canvas::MAX;
|
||||||
} else if (canvas->Equals(NanNew<String>("e"))) {
|
} else if (canvas->Equals(NanNew<String>("e"))) {
|
||||||
baton->canvas = EMBED;
|
baton->canvas = Canvas::EMBED;
|
||||||
}
|
}
|
||||||
// Background colour
|
// Background colour
|
||||||
Local<Array> background = Local<Array>::Cast(options->Get(NanNew<String>("background")));
|
Local<Array> background = Local<Array>::Cast(options->Get(NanNew<String>("background")));
|
||||||
@ -900,7 +870,7 @@ NAN_METHOD(resize) {
|
|||||||
NanAsyncQueueWorker(new ResizeWorker(callback, baton));
|
NanAsyncQueueWorker(new ResizeWorker(callback, baton));
|
||||||
|
|
||||||
// Increment queued task counter
|
// Increment queued task counter
|
||||||
g_atomic_int_inc(&counter_queue);
|
g_atomic_int_inc(&counterQueue);
|
||||||
|
|
||||||
NanReturnUndefined();
|
NanReturnUndefined();
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
using namespace v8;
|
using namespace v8;
|
||||||
|
using namespace sharp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get and set cache memory and item limits
|
Get and set cache memory and item limits
|
||||||
@ -58,8 +59,8 @@ NAN_METHOD(concurrency) {
|
|||||||
NAN_METHOD(counters) {
|
NAN_METHOD(counters) {
|
||||||
NanScope();
|
NanScope();
|
||||||
Local<Object> counters = NanNew<Object>();
|
Local<Object> counters = NanNew<Object>();
|
||||||
counters->Set(NanNew<String>("queue"), NanNew<Number>(counter_queue));
|
counters->Set(NanNew<String>("queue"), NanNew<Number>(counterQueue));
|
||||||
counters->Set(NanNew<String>("process"), NanNew<Number>(counter_process));
|
counters->Set(NanNew<String>("process"), NanNew<Number>(counterProcess));
|
||||||
NanReturnValue(counters);
|
NanReturnValue(counters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user