@revizly/sharp 0.35.0-revizly7 → 0.35.0-revizly8
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 +1 -1
- package/install/build.js +2 -2
- package/lib/constructor.js +6 -1
- package/lib/index.d.ts +34 -38
- package/lib/input.js +3 -9
- package/lib/operation.js +4 -33
- package/lib/output.js +86 -8
- package/lib/resize.js +16 -0
- package/lib/sharp.js +5 -3
- package/lib/utility.js +1 -1
- package/package.json +10 -11
- package/src/binding.gyp +6 -3
- package/src/common.cc +62 -14
- package/src/common.h +12 -1
- package/src/metadata.cc +62 -5
- package/src/metadata.h +6 -1
- package/src/operations.cc +25 -8
- package/src/operations.h +1 -1
- package/src/pipeline.cc +46 -21
- package/src/pipeline.h +11 -1
- package/src/stats.cc +2 -3
- package/src/utilities.cc +4 -3
- package/install/check.js +0 -14
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@revizly/sharp",
|
|
3
3
|
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images",
|
|
4
|
-
"version": "0.35.0-
|
|
4
|
+
"version": "0.35.0-revizly8",
|
|
5
5
|
"author": "Lovell Fuller <npm@lovell.info>",
|
|
6
6
|
"homepage": "https://sharp.pixelplumbing.com",
|
|
7
7
|
"contributors": [
|
|
@@ -89,12 +89,12 @@
|
|
|
89
89
|
"Lachlan Newman <lachnewman007@gmail.com>",
|
|
90
90
|
"Dennis Beatty <dennis@dcbeatty.com>",
|
|
91
91
|
"Ingvar Stepanyan <me@rreverser.com>",
|
|
92
|
-
"Don Denton <don@happycollision.com>"
|
|
92
|
+
"Don Denton <don@happycollision.com>",
|
|
93
|
+
"Dmytro Tiapukhin <cool.gegeg@gmail.com>"
|
|
93
94
|
],
|
|
94
95
|
"scripts": {
|
|
95
96
|
"build": "node install/build.js",
|
|
96
|
-
"
|
|
97
|
-
"clean": "rm -rf src/build/ .nyc_output/ coverage/ test/fixtures/output.*",
|
|
97
|
+
"clean": "rm -rf src/build/ test/fixtures/output.*",
|
|
98
98
|
"test": "npm run lint && npm run test-unit",
|
|
99
99
|
"lint": "npm run lint-cpp && npm run lint-js && npm run lint-types",
|
|
100
100
|
"lint-cpp": "cpplint --quiet src/*.h src/*.cc",
|
|
@@ -150,24 +150,23 @@
|
|
|
150
150
|
"@revizly/sharp-linux-x64": "0.35.0-revizly1"
|
|
151
151
|
},
|
|
152
152
|
"devDependencies": {
|
|
153
|
-
"@biomejs/biome": "^2.3.
|
|
153
|
+
"@biomejs/biome": "^2.3.10",
|
|
154
154
|
"@cpplint/cli": "^0.1.0",
|
|
155
|
-
"@emnapi/runtime": "^1.7.
|
|
155
|
+
"@emnapi/runtime": "^1.7.1",
|
|
156
156
|
"@revizly/sharp-libvips-dev": "1.0.26",
|
|
157
157
|
"@types/node": "*",
|
|
158
|
-
"emnapi": "^1.7.
|
|
159
|
-
"exif-reader": "^2.0.
|
|
158
|
+
"emnapi": "^1.7.1",
|
|
159
|
+
"exif-reader": "^2.0.3",
|
|
160
160
|
"extract-zip": "^2.0.1",
|
|
161
161
|
"icc": "^3.0.0",
|
|
162
|
-
"jsdoc-to-markdown": "^9.1.3",
|
|
163
162
|
"node-addon-api": "^8.5.0",
|
|
164
|
-
"node-gyp": "^
|
|
163
|
+
"node-gyp": "^12.1.0",
|
|
165
164
|
"tar-fs": "^3.1.1",
|
|
166
165
|
"tsd": "^0.33.0"
|
|
167
166
|
},
|
|
168
167
|
"license": "Apache-2.0",
|
|
169
168
|
"engines": {
|
|
170
|
-
"node": "
|
|
169
|
+
"node": ">=20.9.0"
|
|
171
170
|
},
|
|
172
171
|
"config": {
|
|
173
172
|
"libvips": ">=8.18.0"
|
package/src/binding.gyp
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
'variables': {
|
|
6
6
|
'vips_version': '<!(node -p "require(\'../lib/libvips\').minimumLibvipsVersion")',
|
|
7
7
|
'platform_and_arch': '<!(node -p "require(\'../lib/libvips\').buildPlatformArch()")',
|
|
8
|
+
'sharp_version': '<!(node -p "require(\'../package.json\').version")',
|
|
8
9
|
'sharp_libvips_version': '<!(node -p "require(\'../package.json\').optionalDependencies[\'@revizly/sharp-libvips-<(platform_and_arch)\']")',
|
|
9
10
|
'sharp_libvips_yarn_locator': '<!(node -p "require(\'../lib/libvips\').yarnLocator()")',
|
|
10
11
|
'sharp_libvips_include_dir': '<!(node -p "require(\'../lib/libvips\').buildSharpLibvipsIncludeDir()")',
|
|
@@ -20,6 +21,7 @@
|
|
|
20
21
|
'defines': [
|
|
21
22
|
'_VIPS_PUBLIC=__declspec(dllexport)',
|
|
22
23
|
'_ALLOW_KEYWORD_MACROS',
|
|
24
|
+
'_HAS_EXCEPTIONS=1',
|
|
23
25
|
'G_DISABLE_ASSERT',
|
|
24
26
|
'G_DISABLE_CAST_CHECKS',
|
|
25
27
|
'G_DISABLE_CHECKS'
|
|
@@ -81,7 +83,7 @@
|
|
|
81
83
|
}]
|
|
82
84
|
]
|
|
83
85
|
}, {
|
|
84
|
-
'target_name': 'sharp-<(platform_and_arch)',
|
|
86
|
+
'target_name': 'sharp-<(platform_and_arch)-<(sharp_version)',
|
|
85
87
|
'defines': [
|
|
86
88
|
'G_DISABLE_ASSERT',
|
|
87
89
|
'G_DISABLE_CAST_CHECKS',
|
|
@@ -147,7 +149,8 @@
|
|
|
147
149
|
['OS == "win"', {
|
|
148
150
|
'defines': [
|
|
149
151
|
'_ALLOW_KEYWORD_MACROS',
|
|
150
|
-
'_FILE_OFFSET_BITS=64'
|
|
152
|
+
'_FILE_OFFSET_BITS=64',
|
|
153
|
+
'_HAS_EXCEPTIONS=1'
|
|
151
154
|
],
|
|
152
155
|
'link_settings': {
|
|
153
156
|
'libraries': [
|
|
@@ -282,7 +285,7 @@
|
|
|
282
285
|
'target_name': 'copy-dll',
|
|
283
286
|
'type': 'none',
|
|
284
287
|
'dependencies': [
|
|
285
|
-
'sharp-<(platform_and_arch)'
|
|
288
|
+
'sharp-<(platform_and_arch)-<(sharp_version)'
|
|
286
289
|
],
|
|
287
290
|
'conditions': [
|
|
288
291
|
['OS == "win"', {
|
package/src/common.cc
CHANGED
|
@@ -289,6 +289,7 @@ namespace sharp {
|
|
|
289
289
|
case ImageType::JXL: id = "jxl"; break;
|
|
290
290
|
case ImageType::RAD: id = "rad"; break;
|
|
291
291
|
case ImageType::DCRAW: id = "dcraw"; break;
|
|
292
|
+
case ImageType::UHDR: id = "uhdr"; break;
|
|
292
293
|
case ImageType::VIPS: id = "vips"; break;
|
|
293
294
|
case ImageType::RAW: id = "raw"; break;
|
|
294
295
|
case ImageType::UNKNOWN: id = "unknown"; break;
|
|
@@ -339,6 +340,9 @@ namespace sharp {
|
|
|
339
340
|
{ "VipsForeignLoadRadBuffer", ImageType::RAD },
|
|
340
341
|
{ "VipsForeignLoadDcRawFile", ImageType::DCRAW },
|
|
341
342
|
{ "VipsForeignLoadDcRawBuffer", ImageType::DCRAW },
|
|
343
|
+
{ "VipsForeignLoadUhdr", ImageType::UHDR },
|
|
344
|
+
{ "VipsForeignLoadUhdrFile", ImageType::UHDR },
|
|
345
|
+
{ "VipsForeignLoadUhdrBuffer", ImageType::UHDR },
|
|
342
346
|
{ "VipsForeignLoadVips", ImageType::VIPS },
|
|
343
347
|
{ "VipsForeignLoadVipsFile", ImageType::VIPS },
|
|
344
348
|
{ "VipsForeignLoadRaw", ImageType::RAW }
|
|
@@ -356,6 +360,9 @@ namespace sharp {
|
|
|
356
360
|
imageType = it->second;
|
|
357
361
|
}
|
|
358
362
|
}
|
|
363
|
+
if (imageType == ImageType::UHDR) {
|
|
364
|
+
imageType = ImageType::JPEG;
|
|
365
|
+
}
|
|
359
366
|
return imageType;
|
|
360
367
|
}
|
|
361
368
|
|
|
@@ -375,6 +382,9 @@ namespace sharp {
|
|
|
375
382
|
imageType = ImageType::MISSING;
|
|
376
383
|
}
|
|
377
384
|
}
|
|
385
|
+
if (imageType == ImageType::UHDR) {
|
|
386
|
+
imageType = ImageType::JPEG;
|
|
387
|
+
}
|
|
378
388
|
return imageType;
|
|
379
389
|
}
|
|
380
390
|
|
|
@@ -416,7 +426,7 @@ namespace sharp {
|
|
|
416
426
|
}
|
|
417
427
|
if (ImageTypeSupportsPage(imageType)) {
|
|
418
428
|
option->set("n", descriptor->pages);
|
|
419
|
-
option->set("page", descriptor->page);
|
|
429
|
+
option->set("page", std::max(0, descriptor->page));
|
|
420
430
|
}
|
|
421
431
|
switch (imageType) {
|
|
422
432
|
case ImageType::SVG:
|
|
@@ -446,6 +456,22 @@ namespace sharp {
|
|
|
446
456
|
return option;
|
|
447
457
|
}
|
|
448
458
|
|
|
459
|
+
/*
|
|
460
|
+
Should HEIF image be re-opened using the primary item?
|
|
461
|
+
*/
|
|
462
|
+
static bool HeifPrimaryPageReopen(VImage image, InputDescriptor *descriptor) {
|
|
463
|
+
if (image.get_typeof(VIPS_META_N_PAGES) == G_TYPE_INT && image.get_typeof("heif-primary") == G_TYPE_INT) {
|
|
464
|
+
if (image.get_int(VIPS_META_N_PAGES) > 1 && descriptor->pages == 1 && descriptor->page == -1) {
|
|
465
|
+
int const pagePrimary = image.get_int("heif-primary");
|
|
466
|
+
if (pagePrimary != 0) {
|
|
467
|
+
descriptor->page = pagePrimary;
|
|
468
|
+
return true;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
|
|
449
475
|
/*
|
|
450
476
|
Open an image from the given InputDescriptor (filesystem, compressed buffer, raw pixel data)
|
|
451
477
|
*/
|
|
@@ -480,12 +506,15 @@ namespace sharp {
|
|
|
480
506
|
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
|
481
507
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
|
482
508
|
image = SetDensity(image, descriptor->density);
|
|
509
|
+
} else if (imageType == ImageType::HEIF && HeifPrimaryPageReopen(image, descriptor)) {
|
|
510
|
+
option = GetOptionsForImageType(imageType, descriptor);
|
|
511
|
+
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
|
483
512
|
}
|
|
484
|
-
} catch (
|
|
485
|
-
throw
|
|
513
|
+
} catch (std::runtime_error const &err) {
|
|
514
|
+
throw std::runtime_error(std::string("Input buffer has corrupt header: ") + err.what());
|
|
486
515
|
}
|
|
487
516
|
} else {
|
|
488
|
-
throw
|
|
517
|
+
throw std::runtime_error("Input buffer contains unsupported image format");
|
|
489
518
|
}
|
|
490
519
|
}
|
|
491
520
|
} else {
|
|
@@ -556,10 +585,10 @@ namespace sharp {
|
|
|
556
585
|
imageType = DetermineImageType(descriptor->file.data());
|
|
557
586
|
if (imageType == ImageType::MISSING) {
|
|
558
587
|
if (descriptor->file.find("<svg") != std::string::npos) {
|
|
559
|
-
throw
|
|
588
|
+
throw std::runtime_error("Input file is missing, did you mean "
|
|
560
589
|
"sharp(Buffer.from('" + descriptor->file.substr(0, 8) + "...')?");
|
|
561
590
|
}
|
|
562
|
-
throw
|
|
591
|
+
throw std::runtime_error("Input file is missing: " + descriptor->file);
|
|
563
592
|
}
|
|
564
593
|
if (imageType != ImageType::UNKNOWN) {
|
|
565
594
|
try {
|
|
@@ -567,12 +596,15 @@ namespace sharp {
|
|
|
567
596
|
image = VImage::new_from_file(descriptor->file.data(), option);
|
|
568
597
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
|
569
598
|
image = SetDensity(image, descriptor->density);
|
|
599
|
+
} else if (imageType == ImageType::HEIF && HeifPrimaryPageReopen(image, descriptor)) {
|
|
600
|
+
option = GetOptionsForImageType(imageType, descriptor);
|
|
601
|
+
image = VImage::new_from_file(descriptor->file.data(), option);
|
|
570
602
|
}
|
|
571
|
-
} catch (
|
|
572
|
-
throw
|
|
603
|
+
} catch (std::runtime_error const &err) {
|
|
604
|
+
throw std::runtime_error(std::string("Input file has corrupt header: ") + err.what());
|
|
573
605
|
}
|
|
574
606
|
} else {
|
|
575
|
-
throw
|
|
607
|
+
throw std::runtime_error("Input file contains unsupported image format");
|
|
576
608
|
}
|
|
577
609
|
}
|
|
578
610
|
}
|
|
@@ -580,7 +612,7 @@ namespace sharp {
|
|
|
580
612
|
// Limit input images to a given number of pixels, where pixels = width * height
|
|
581
613
|
if (descriptor->limitInputPixels > 0 &&
|
|
582
614
|
static_cast<uint64_t>(image.width()) * image.height() > descriptor->limitInputPixels) {
|
|
583
|
-
throw
|
|
615
|
+
throw std::runtime_error("Input image exceeds pixel limit");
|
|
584
616
|
}
|
|
585
617
|
return std::make_tuple(image, imageType);
|
|
586
618
|
}
|
|
@@ -756,19 +788,19 @@ namespace sharp {
|
|
|
756
788
|
: image.height();
|
|
757
789
|
if (imageType == ImageType::JPEG) {
|
|
758
790
|
if (image.width() > 65535 || height > 65535) {
|
|
759
|
-
throw
|
|
791
|
+
throw std::runtime_error("Processed image is too large for the JPEG format");
|
|
760
792
|
}
|
|
761
793
|
} else if (imageType == ImageType::WEBP) {
|
|
762
794
|
if (image.width() > 16383 || height > 16383) {
|
|
763
|
-
throw
|
|
795
|
+
throw std::runtime_error("Processed image is too large for the WebP format");
|
|
764
796
|
}
|
|
765
797
|
} else if (imageType == ImageType::GIF) {
|
|
766
798
|
if (image.width() > 65535 || height > 65535) {
|
|
767
|
-
throw
|
|
799
|
+
throw std::runtime_error("Processed image is too large for the GIF format");
|
|
768
800
|
}
|
|
769
801
|
} else if (imageType == ImageType::HEIF) {
|
|
770
802
|
if (image.width() > 16384 || height > 16384) {
|
|
771
|
-
throw
|
|
803
|
+
throw std::runtime_error("Processed image is too large for the HEIF format");
|
|
772
804
|
}
|
|
773
805
|
}
|
|
774
806
|
}
|
|
@@ -1127,4 +1159,20 @@ namespace sharp {
|
|
|
1127
1159
|
}
|
|
1128
1160
|
return image;
|
|
1129
1161
|
}
|
|
1162
|
+
|
|
1163
|
+
/*
|
|
1164
|
+
Does this image have a gain map?
|
|
1165
|
+
*/
|
|
1166
|
+
bool HasGainMap(VImage image) {
|
|
1167
|
+
return image.get_typeof("gainmap-data") == VIPS_TYPE_BLOB;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
/*
|
|
1171
|
+
Removes gain map, if any.
|
|
1172
|
+
*/
|
|
1173
|
+
VImage RemoveGainMap(VImage image) {
|
|
1174
|
+
VImage copy = image.copy();
|
|
1175
|
+
copy.remove("gainmap-data");
|
|
1176
|
+
return copy;
|
|
1177
|
+
}
|
|
1130
1178
|
} // namespace sharp
|
package/src/common.h
CHANGED
|
@@ -105,7 +105,7 @@ namespace sharp {
|
|
|
105
105
|
rawPremultiplied(false),
|
|
106
106
|
rawPageHeight(0),
|
|
107
107
|
pages(1),
|
|
108
|
-
page(
|
|
108
|
+
page(-1),
|
|
109
109
|
createChannels(0),
|
|
110
110
|
createWidth(0),
|
|
111
111
|
createHeight(0),
|
|
@@ -173,6 +173,7 @@ namespace sharp {
|
|
|
173
173
|
JXL,
|
|
174
174
|
RAD,
|
|
175
175
|
DCRAW,
|
|
176
|
+
UHDR,
|
|
176
177
|
VIPS,
|
|
177
178
|
RAW,
|
|
178
179
|
UNKNOWN,
|
|
@@ -397,6 +398,16 @@ namespace sharp {
|
|
|
397
398
|
*/
|
|
398
399
|
VImage StaySequential(VImage image, bool condition = true);
|
|
399
400
|
|
|
401
|
+
/*
|
|
402
|
+
Does this image have a gain map?
|
|
403
|
+
*/
|
|
404
|
+
bool HasGainMap(VImage image);
|
|
405
|
+
|
|
406
|
+
/*
|
|
407
|
+
Removes gain map, if any.
|
|
408
|
+
*/
|
|
409
|
+
VImage RemoveGainMap(VImage image);
|
|
410
|
+
|
|
400
411
|
} // namespace sharp
|
|
401
412
|
|
|
402
413
|
#endif // SRC_COMMON_H_
|
package/src/metadata.cc
CHANGED
|
@@ -31,7 +31,7 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
31
31
|
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
|
|
32
32
|
try {
|
|
33
33
|
std::tie(image, imageType) = OpenInput(baton->input);
|
|
34
|
-
} catch (
|
|
34
|
+
} catch (std::runtime_error const &err) {
|
|
35
35
|
(baton->err).append(err.what());
|
|
36
36
|
}
|
|
37
37
|
if (imageType != sharp::ImageType::UNKNOWN) {
|
|
@@ -141,8 +141,60 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
141
141
|
memcpy(baton->tifftagPhotoshop, tifftagPhotoshop, tifftagPhotoshopLength);
|
|
142
142
|
baton->tifftagPhotoshopLength = tifftagPhotoshopLength;
|
|
143
143
|
}
|
|
144
|
+
// Gain Map
|
|
145
|
+
if (image.get_typeof("gainmap-data") == VIPS_TYPE_BLOB) {
|
|
146
|
+
size_t gainMapLength;
|
|
147
|
+
void const *gainMap = image.get_blob("gainmap-data", &gainMapLength);
|
|
148
|
+
baton->gainMap = static_cast<char *>(g_malloc(gainMapLength));
|
|
149
|
+
memcpy(baton->gainMap, gainMap, gainMapLength);
|
|
150
|
+
baton->gainMapLength = gainMapLength;
|
|
151
|
+
}
|
|
144
152
|
// PNG comments
|
|
145
153
|
vips_image_map(image.get_image(), readPNGComment, &baton->comments);
|
|
154
|
+
// Media type
|
|
155
|
+
std::string mediaType;
|
|
156
|
+
switch (imageType) {
|
|
157
|
+
case sharp::ImageType::JPEG:
|
|
158
|
+
case sharp::ImageType::PNG:
|
|
159
|
+
case sharp::ImageType::WEBP:
|
|
160
|
+
case sharp::ImageType::JP2:
|
|
161
|
+
case sharp::ImageType::TIFF:
|
|
162
|
+
case sharp::ImageType::GIF:
|
|
163
|
+
case sharp::ImageType::FITS:
|
|
164
|
+
case sharp::ImageType::JXL:
|
|
165
|
+
baton->mediaType = "image/" + baton->format;
|
|
166
|
+
break;
|
|
167
|
+
case sharp::ImageType::SVG:
|
|
168
|
+
baton->mediaType = "image/svg+xml";
|
|
169
|
+
break;
|
|
170
|
+
case sharp::ImageType::HEIF:
|
|
171
|
+
if (baton->compression == "av1") {
|
|
172
|
+
baton->mediaType = "image/avif";
|
|
173
|
+
} else if (baton->compression == "hevc") {
|
|
174
|
+
baton->mediaType = "image/heic";
|
|
175
|
+
}
|
|
176
|
+
break;
|
|
177
|
+
case sharp::ImageType::PDF:
|
|
178
|
+
baton->mediaType = "application/pdf";
|
|
179
|
+
break;
|
|
180
|
+
case sharp::ImageType::OPENSLIDE:
|
|
181
|
+
baton->mediaType = "image/tiff";
|
|
182
|
+
break;
|
|
183
|
+
case sharp::ImageType::PPM:
|
|
184
|
+
baton->mediaType = "image/x-portable-pixmap";
|
|
185
|
+
break;
|
|
186
|
+
case sharp::ImageType::EXR:
|
|
187
|
+
baton->mediaType = "image/x-exr";
|
|
188
|
+
break;
|
|
189
|
+
case sharp::ImageType::RAD:
|
|
190
|
+
baton->mediaType = "image/vnd.radiance";
|
|
191
|
+
break;
|
|
192
|
+
case sharp::ImageType::UHDR:
|
|
193
|
+
baton->mediaType = "image/jpeg";
|
|
194
|
+
break;
|
|
195
|
+
default:
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
146
198
|
}
|
|
147
199
|
|
|
148
200
|
// Clean up
|
|
@@ -164,6 +216,9 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
164
216
|
if (baton->err.empty()) {
|
|
165
217
|
Napi::Object info = Napi::Object::New(env);
|
|
166
218
|
info.Set("format", baton->format);
|
|
219
|
+
if (!baton->mediaType.empty()) {
|
|
220
|
+
info.Set("mediaType", baton->mediaType);
|
|
221
|
+
}
|
|
167
222
|
if (baton->input->bufferLength > 0) {
|
|
168
223
|
info.Set("size", baton->input->bufferLength);
|
|
169
224
|
}
|
|
@@ -182,10 +237,6 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
182
237
|
info.Set("isPalette", baton->isPalette);
|
|
183
238
|
if (baton->bitsPerSample > 0) {
|
|
184
239
|
info.Set("bitsPerSample", baton->bitsPerSample);
|
|
185
|
-
if (baton->isPalette) {
|
|
186
|
-
// Deprecated, remove with libvips 8.17.0
|
|
187
|
-
info.Set("paletteBitDepth", baton->bitsPerSample);
|
|
188
|
-
}
|
|
189
240
|
}
|
|
190
241
|
if (baton->pages > 0) {
|
|
191
242
|
info.Set("pages", baton->pages);
|
|
@@ -276,6 +327,12 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
276
327
|
Napi::Buffer<char>::NewOrCopy(env, baton->tifftagPhotoshop,
|
|
277
328
|
baton->tifftagPhotoshopLength, sharp::FreeCallback));
|
|
278
329
|
}
|
|
330
|
+
if (baton->gainMapLength > 0) {
|
|
331
|
+
Napi::Object gainMap = Napi::Object::New(env);
|
|
332
|
+
info.Set("gainMap", gainMap);
|
|
333
|
+
gainMap.Set("image",
|
|
334
|
+
Napi::Buffer<char>::NewOrCopy(env, baton->gainMap, baton->gainMapLength, sharp::FreeCallback));
|
|
335
|
+
}
|
|
279
336
|
if (baton->comments.size() > 0) {
|
|
280
337
|
int i = 0;
|
|
281
338
|
Napi::Array comments = Napi::Array::New(env, baton->comments.size());
|
package/src/metadata.h
CHANGED
|
@@ -19,6 +19,7 @@ struct MetadataBaton {
|
|
|
19
19
|
sharp::InputDescriptor *input;
|
|
20
20
|
// Output
|
|
21
21
|
std::string format;
|
|
22
|
+
std::string mediaType;
|
|
22
23
|
int width;
|
|
23
24
|
int height;
|
|
24
25
|
std::string space;
|
|
@@ -53,6 +54,8 @@ struct MetadataBaton {
|
|
|
53
54
|
size_t xmpLength;
|
|
54
55
|
char *tifftagPhotoshop;
|
|
55
56
|
size_t tifftagPhotoshopLength;
|
|
57
|
+
char *gainMap;
|
|
58
|
+
size_t gainMapLength;
|
|
56
59
|
MetadataComments comments;
|
|
57
60
|
std::string err;
|
|
58
61
|
|
|
@@ -82,7 +85,9 @@ struct MetadataBaton {
|
|
|
82
85
|
xmp(nullptr),
|
|
83
86
|
xmpLength(0),
|
|
84
87
|
tifftagPhotoshop(nullptr),
|
|
85
|
-
tifftagPhotoshopLength(0)
|
|
88
|
+
tifftagPhotoshopLength(0),
|
|
89
|
+
gainMap(nullptr),
|
|
90
|
+
gainMapLength(0) {}
|
|
86
91
|
};
|
|
87
92
|
|
|
88
93
|
Napi::Value metadata(const Napi::CallbackInfo& info);
|
package/src/operations.cc
CHANGED
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
#include "./operations.h"
|
|
15
15
|
|
|
16
16
|
using vips::VImage;
|
|
17
|
-
using vips::VError;
|
|
18
17
|
|
|
19
18
|
namespace sharp {
|
|
20
19
|
/*
|
|
@@ -285,9 +284,9 @@ namespace sharp {
|
|
|
285
284
|
/*
|
|
286
285
|
Trim an image
|
|
287
286
|
*/
|
|
288
|
-
VImage Trim(VImage image, std::vector<double> background, double threshold, bool const lineArt) {
|
|
287
|
+
VImage Trim(VImage image, std::vector<double> background, double threshold, bool const lineArt, int const margin) {
|
|
289
288
|
if (image.width() < 3 && image.height() < 3) {
|
|
290
|
-
throw
|
|
289
|
+
throw std::runtime_error("Image to trim must be at least 3x3 pixels");
|
|
291
290
|
}
|
|
292
291
|
if (background.size() == 0) {
|
|
293
292
|
// Top-left pixel provides the default background colour if none is given
|
|
@@ -320,18 +319,36 @@ namespace sharp {
|
|
|
320
319
|
if (widthA > 0 && heightA > 0) {
|
|
321
320
|
if (width > 0 && height > 0) {
|
|
322
321
|
// Combined bounding box (B)
|
|
323
|
-
int
|
|
324
|
-
int
|
|
325
|
-
int
|
|
326
|
-
int
|
|
322
|
+
int leftB = std::min(left, leftA);
|
|
323
|
+
int topB = std::min(top, topA);
|
|
324
|
+
int widthB = std::max(left + width, leftA + widthA) - leftB;
|
|
325
|
+
int heightB = std::max(top + height, topA + heightA) - topB;
|
|
326
|
+
if (margin > 0) {
|
|
327
|
+
leftB = std::max(0, leftB - margin);
|
|
328
|
+
topB = std::max(0, topB - margin);
|
|
329
|
+
widthB = std::min(image.width() - leftB, widthB + 2 * margin);
|
|
330
|
+
heightB = std::min(image.height() - topB, heightB + 2 * margin);
|
|
331
|
+
}
|
|
327
332
|
return image.extract_area(leftB, topB, widthB, heightB);
|
|
328
333
|
} else {
|
|
329
334
|
// Use alpha only
|
|
335
|
+
if (margin > 0) {
|
|
336
|
+
leftA = std::max(0, leftA - margin);
|
|
337
|
+
topA = std::max(0, topA - margin);
|
|
338
|
+
widthA = std::min(image.width() - leftA, widthA + 2 * margin);
|
|
339
|
+
heightA = std::min(image.height() - topA, heightA + 2 * margin);
|
|
340
|
+
}
|
|
330
341
|
return image.extract_area(leftA, topA, widthA, heightA);
|
|
331
342
|
}
|
|
332
343
|
}
|
|
333
344
|
}
|
|
334
345
|
if (width > 0 && height > 0) {
|
|
346
|
+
if (margin > 0) {
|
|
347
|
+
left = std::max(0, left - margin);
|
|
348
|
+
top = std::max(0, top - margin);
|
|
349
|
+
width = std::min(image.width() - left, width + 2 * margin);
|
|
350
|
+
height = std::min(image.height() - top, height + 2 * margin);
|
|
351
|
+
}
|
|
335
352
|
return image.extract_area(left, top, width, height);
|
|
336
353
|
}
|
|
337
354
|
return image;
|
|
@@ -343,7 +360,7 @@ namespace sharp {
|
|
|
343
360
|
VImage Linear(VImage image, std::vector<double> const a, std::vector<double> const b) {
|
|
344
361
|
size_t const bands = static_cast<size_t>(image.bands());
|
|
345
362
|
if (a.size() > bands) {
|
|
346
|
-
throw
|
|
363
|
+
throw std::runtime_error("Band expansion using linear is unsupported");
|
|
347
364
|
}
|
|
348
365
|
bool const uchar = !Is16Bit(image.interpretation());
|
|
349
366
|
if (image.has_alpha() && a.size() != bands && (a.size() == 1 || a.size() == bands - 1 || bands - 1 == 1)) {
|
package/src/operations.h
CHANGED
|
@@ -82,7 +82,7 @@ namespace sharp {
|
|
|
82
82
|
/*
|
|
83
83
|
Trim an image
|
|
84
84
|
*/
|
|
85
|
-
VImage Trim(VImage image, std::vector<double> background, double threshold, bool const lineArt);
|
|
85
|
+
VImage Trim(VImage image, std::vector<double> background, double threshold, bool const lineArt, int const margin);
|
|
86
86
|
|
|
87
87
|
/*
|
|
88
88
|
* Linear adjustment (a * in + b)
|