sharp 0.23.0 → 0.23.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/binding.gyp +16 -10
- package/docs/api-composite.md +1 -0
- package/docs/api-constructor.md +1 -1
- package/docs/api-input.md +1 -0
- package/docs/api-output.md +96 -84
- package/docs/api-resize.md +2 -0
- package/docs/changelog.md +58 -0
- package/docs/index.md +7 -2
- package/docs/install.md +11 -4
- package/docs/performance.md +12 -13
- package/install/libvips.js +12 -7
- package/lib/agent.js +5 -2
- package/lib/colour.js +16 -12
- package/lib/composite.js +11 -1
- package/lib/constructor.js +2 -1
- package/lib/input.js +5 -0
- package/lib/operation.js +1 -1
- package/lib/output.js +29 -9
- package/lib/platform.js +1 -0
- package/lib/resize.js +17 -8
- package/package.json +29 -18
- package/src/common.cc +20 -13
- package/src/common.h +7 -5
- package/src/metadata.cc +14 -0
- package/src/metadata.h +5 -1
- package/src/operations.cc +26 -5
- package/src/pipeline.cc +17 -6
- package/src/pipeline.h +5 -1
- package/src/utilities.cc +3 -2
package/src/operations.cc
CHANGED
|
@@ -191,12 +191,20 @@ namespace sharp {
|
|
|
191
191
|
VImage alpha = image[image.bands() - 1];
|
|
192
192
|
return RemoveAlpha(image)
|
|
193
193
|
.colourspace(VIPS_INTERPRETATION_LCH)
|
|
194
|
-
.linear(
|
|
194
|
+
.linear(
|
|
195
|
+
{ brightness, saturation, 1},
|
|
196
|
+
{ 0.0, 0.0, static_cast<double>(hue) }
|
|
197
|
+
)
|
|
198
|
+
.colourspace(VIPS_INTERPRETATION_sRGB)
|
|
195
199
|
.bandjoin(alpha);
|
|
196
200
|
} else {
|
|
197
201
|
return image
|
|
198
202
|
.colourspace(VIPS_INTERPRETATION_LCH)
|
|
199
|
-
.linear(
|
|
203
|
+
.linear(
|
|
204
|
+
{ brightness, saturation, 1 },
|
|
205
|
+
{ 0.0, 0.0, static_cast<double>(hue) }
|
|
206
|
+
)
|
|
207
|
+
.colourspace(VIPS_INTERPRETATION_sRGB);
|
|
200
208
|
}
|
|
201
209
|
}
|
|
202
210
|
|
|
@@ -250,17 +258,30 @@ namespace sharp {
|
|
|
250
258
|
Trim an image
|
|
251
259
|
*/
|
|
252
260
|
VImage Trim(VImage image, double const threshold) {
|
|
261
|
+
if (image.width() < 3 && image.height() < 3) {
|
|
262
|
+
throw VError("Image to trim must be at least 3x3 pixels");
|
|
263
|
+
}
|
|
253
264
|
// Top-left pixel provides the background colour
|
|
254
265
|
VImage background = image.extract_area(0, 0, 1, 1);
|
|
255
266
|
if (HasAlpha(background)) {
|
|
256
267
|
background = background.flatten();
|
|
257
268
|
}
|
|
258
|
-
int top, width, height;
|
|
259
|
-
|
|
269
|
+
int left, top, width, height;
|
|
270
|
+
left = image.find_trim(&top, &width, &height, VImage::option()
|
|
260
271
|
->set("background", background(0, 0))
|
|
261
272
|
->set("threshold", threshold));
|
|
262
273
|
if (width == 0 || height == 0) {
|
|
263
|
-
|
|
274
|
+
if (HasAlpha(image)) {
|
|
275
|
+
// Search alpha channel
|
|
276
|
+
VImage alpha = image[image.bands() - 1];
|
|
277
|
+
VImage backgroundAlpha = alpha.extract_area(0, 0, 1, 1);
|
|
278
|
+
left = alpha.find_trim(&top, &width, &height, VImage::option()
|
|
279
|
+
->set("background", backgroundAlpha(0, 0))
|
|
280
|
+
->set("threshold", threshold));
|
|
281
|
+
}
|
|
282
|
+
if (width == 0 || height == 0) {
|
|
283
|
+
throw VError("Unexpected error while trimming. Try to lower the tolerance");
|
|
284
|
+
}
|
|
264
285
|
}
|
|
265
286
|
return image.extract_area(left, top, width, height);
|
|
266
287
|
}
|
package/src/pipeline.cc
CHANGED
|
@@ -38,6 +38,9 @@
|
|
|
38
38
|
#elif defined(__APPLE__)
|
|
39
39
|
#define STAT64_STRUCT stat
|
|
40
40
|
#define STAT64_FUNCTION stat
|
|
41
|
+
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
|
|
42
|
+
#define STAT64_STRUCT stat
|
|
43
|
+
#define STAT64_FUNCTION stat
|
|
41
44
|
#else
|
|
42
45
|
#define STAT64_STRUCT stat64
|
|
43
46
|
#define STAT64_FUNCTION stat64
|
|
@@ -101,7 +104,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
101
104
|
if (baton->rotateBeforePreExtract) {
|
|
102
105
|
if (rotation != VIPS_ANGLE_D0) {
|
|
103
106
|
image = image.rot(rotation);
|
|
104
|
-
sharp::RemoveExifOrientation(image);
|
|
107
|
+
image = sharp::RemoveExifOrientation(image);
|
|
105
108
|
}
|
|
106
109
|
if (baton->rotationAngle != 0.0) {
|
|
107
110
|
std::vector<double> background;
|
|
@@ -401,20 +404,20 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
401
404
|
// Rotate post-extract 90-angle
|
|
402
405
|
if (!baton->rotateBeforePreExtract && rotation != VIPS_ANGLE_D0) {
|
|
403
406
|
image = image.rot(rotation);
|
|
404
|
-
sharp::RemoveExifOrientation(image);
|
|
407
|
+
image = sharp::RemoveExifOrientation(image);
|
|
405
408
|
}
|
|
406
409
|
|
|
407
410
|
|
|
408
411
|
// Flip (mirror about Y axis)
|
|
409
412
|
if (baton->flip) {
|
|
410
413
|
image = image.flip(VIPS_DIRECTION_VERTICAL);
|
|
411
|
-
sharp::RemoveExifOrientation(image);
|
|
414
|
+
image = sharp::RemoveExifOrientation(image);
|
|
412
415
|
}
|
|
413
416
|
|
|
414
417
|
// Flop (mirror about X axis)
|
|
415
418
|
if (baton->flop) {
|
|
416
419
|
image = image.flip(VIPS_DIRECTION_HORIZONTAL);
|
|
417
|
-
sharp::RemoveExifOrientation(image);
|
|
420
|
+
image = sharp::RemoveExifOrientation(image);
|
|
418
421
|
}
|
|
419
422
|
|
|
420
423
|
// Join additional color channels to the image
|
|
@@ -591,7 +594,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
591
594
|
if (!HasAlpha(compositeImage)) {
|
|
592
595
|
compositeImage = sharp::EnsureAlpha(compositeImage);
|
|
593
596
|
}
|
|
594
|
-
compositeImage = compositeImage.premultiply();
|
|
597
|
+
if (!composite->premultiplied) compositeImage = compositeImage.premultiply();
|
|
595
598
|
// Calculate position
|
|
596
599
|
int left;
|
|
597
600
|
int top;
|
|
@@ -697,7 +700,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
697
700
|
|
|
698
701
|
// Override EXIF Orientation tag
|
|
699
702
|
if (baton->withMetadata && baton->withMetadataOrientation != -1) {
|
|
700
|
-
sharp::SetExifOrientation(image, baton->withMetadataOrientation);
|
|
703
|
+
image = sharp::SetExifOrientation(image, baton->withMetadataOrientation);
|
|
701
704
|
}
|
|
702
705
|
|
|
703
706
|
// Number of channels used in output image
|
|
@@ -959,6 +962,11 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
959
962
|
};
|
|
960
963
|
suffix = AssembleSuffixString(extname, options);
|
|
961
964
|
}
|
|
965
|
+
|
|
966
|
+
// Remove alpha channel from tile background if image does not contain an alpha channel
|
|
967
|
+
if (!HasAlpha(image)) {
|
|
968
|
+
baton->tileBackground.pop_back();
|
|
969
|
+
}
|
|
962
970
|
// Write DZ to file
|
|
963
971
|
vips::VOption *options = VImage::option()
|
|
964
972
|
->set("strip", !baton->withMetadata)
|
|
@@ -968,6 +976,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|
|
968
976
|
->set("layout", baton->tileLayout)
|
|
969
977
|
->set("suffix", const_cast<char*>(suffix.data()))
|
|
970
978
|
->set("angle", CalculateAngleRotation(baton->tileAngle))
|
|
979
|
+
->set("background", baton->tileBackground)
|
|
971
980
|
->set("skip_blanks", baton->tileSkipBlanks);
|
|
972
981
|
|
|
973
982
|
// libvips chooses a default depth based on layout. Instead of replicating that logic here by
|
|
@@ -1230,6 +1239,7 @@ NAN_METHOD(pipeline) {
|
|
|
1230
1239
|
composite->left = AttrTo<int32_t>(compositeObject, "left");
|
|
1231
1240
|
composite->top = AttrTo<int32_t>(compositeObject, "top");
|
|
1232
1241
|
composite->tile = AttrTo<bool>(compositeObject, "tile");
|
|
1242
|
+
composite->premultiplied = AttrTo<bool>(compositeObject, "premultiplied");
|
|
1233
1243
|
baton->composite.push_back(composite);
|
|
1234
1244
|
}
|
|
1235
1245
|
// Resize options
|
|
@@ -1373,6 +1383,7 @@ NAN_METHOD(pipeline) {
|
|
|
1373
1383
|
baton->tileOverlap = AttrTo<uint32_t>(options, "tileOverlap");
|
|
1374
1384
|
std::string tileContainer = AttrAsStr(options, "tileContainer");
|
|
1375
1385
|
baton->tileAngle = AttrTo<int32_t>(options, "tileAngle");
|
|
1386
|
+
baton->tileBackground = AttrAsRgba(options, "tileBackground");
|
|
1376
1387
|
baton->tileSkipBlanks = AttrTo<int32_t>(options, "tileSkipBlanks");
|
|
1377
1388
|
if (tileContainer == "zip") {
|
|
1378
1389
|
baton->tileContainer = VIPS_FOREIGN_DZ_CONTAINER_ZIP;
|
package/src/pipeline.h
CHANGED
|
@@ -41,6 +41,7 @@ struct Composite {
|
|
|
41
41
|
int left;
|
|
42
42
|
int top;
|
|
43
43
|
bool tile;
|
|
44
|
+
bool premultiplied;
|
|
44
45
|
|
|
45
46
|
Composite():
|
|
46
47
|
input(nullptr),
|
|
@@ -48,7 +49,8 @@ struct Composite {
|
|
|
48
49
|
gravity(0),
|
|
49
50
|
left(-1),
|
|
50
51
|
top(-1),
|
|
51
|
-
tile(false)
|
|
52
|
+
tile(false),
|
|
53
|
+
premultiplied(false) {}
|
|
52
54
|
};
|
|
53
55
|
|
|
54
56
|
struct PipelineBaton {
|
|
@@ -173,6 +175,7 @@ struct PipelineBaton {
|
|
|
173
175
|
VipsForeignDzLayout tileLayout;
|
|
174
176
|
std::string tileFormat;
|
|
175
177
|
int tileAngle;
|
|
178
|
+
std::vector<double> tileBackground;
|
|
176
179
|
int tileSkipBlanks;
|
|
177
180
|
VipsForeignDzDepth tileDepth;
|
|
178
181
|
std::unique_ptr<double[]> recombMatrix;
|
|
@@ -278,6 +281,7 @@ struct PipelineBaton {
|
|
|
278
281
|
tileContainer(VIPS_FOREIGN_DZ_CONTAINER_FS),
|
|
279
282
|
tileLayout(VIPS_FOREIGN_DZ_LAYOUT_DZ),
|
|
280
283
|
tileAngle(0),
|
|
284
|
+
tileBackground{ 255.0, 255.0, 255.0, 255.0 },
|
|
281
285
|
tileSkipBlanks(-1),
|
|
282
286
|
tileDepth(VIPS_FOREIGN_DZ_DEPTH_LAST) {}
|
|
283
287
|
};
|
package/src/utilities.cc
CHANGED
|
@@ -150,8 +150,9 @@ NAN_METHOD(format) {
|
|
|
150
150
|
|
|
151
151
|
// Which load/save operations are available for each compressed format?
|
|
152
152
|
Local<Object> format = New<Object>();
|
|
153
|
-
for (std::string f : {
|
|
154
|
-
"jpeg", "png", "webp", "tiff", "magick", "openslide", "dz",
|
|
153
|
+
for (std::string const f : {
|
|
154
|
+
"jpeg", "png", "webp", "tiff", "magick", "openslide", "dz",
|
|
155
|
+
"ppm", "fits", "gif", "svg", "heif", "pdf", "vips"
|
|
155
156
|
}) {
|
|
156
157
|
// Input
|
|
157
158
|
Local<Boolean> hasInputFile =
|