@revizly/sharp 0.33.2-revizly3
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/LICENSE +191 -0
- package/README.md +118 -0
- package/install/check.js +41 -0
- package/lib/channel.js +174 -0
- package/lib/colour.js +182 -0
- package/lib/composite.js +210 -0
- package/lib/constructor.js +444 -0
- package/lib/index.d.ts +1723 -0
- package/lib/index.js +16 -0
- package/lib/input.js +657 -0
- package/lib/is.js +169 -0
- package/lib/libvips.js +195 -0
- package/lib/operation.js +921 -0
- package/lib/output.js +1572 -0
- package/lib/resize.js +582 -0
- package/lib/sharp.js +115 -0
- package/lib/utility.js +286 -0
- package/package.json +218 -0
- package/src/binding.gyp +280 -0
- package/src/common.cc +1090 -0
- package/src/common.h +393 -0
- package/src/metadata.cc +287 -0
- package/src/metadata.h +82 -0
- package/src/operations.cc +471 -0
- package/src/operations.h +125 -0
- package/src/pipeline.cc +1741 -0
- package/src/pipeline.h +385 -0
- package/src/sharp.cc +40 -0
- package/src/stats.cc +183 -0
- package/src/stats.h +59 -0
- package/src/utilities.cc +269 -0
- package/src/utilities.h +19 -0
package/src/pipeline.h
ADDED
@@ -0,0 +1,385 @@
|
|
1
|
+
// Copyright 2013 Lovell Fuller and others.
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
3
|
+
|
4
|
+
#ifndef SRC_PIPELINE_H_
|
5
|
+
#define SRC_PIPELINE_H_
|
6
|
+
|
7
|
+
#include <memory>
|
8
|
+
#include <string>
|
9
|
+
#include <vector>
|
10
|
+
#include <unordered_map>
|
11
|
+
|
12
|
+
#include <napi.h>
|
13
|
+
#include <vips/vips8>
|
14
|
+
|
15
|
+
#include "./common.h"
|
16
|
+
|
17
|
+
Napi::Value pipeline(const Napi::CallbackInfo& info);
|
18
|
+
|
19
|
+
struct Composite {
|
20
|
+
sharp::InputDescriptor *input;
|
21
|
+
VipsBlendMode mode;
|
22
|
+
int gravity;
|
23
|
+
int left;
|
24
|
+
int top;
|
25
|
+
bool hasOffset;
|
26
|
+
bool tile;
|
27
|
+
bool premultiplied;
|
28
|
+
|
29
|
+
Composite():
|
30
|
+
input(nullptr),
|
31
|
+
mode(VIPS_BLEND_MODE_OVER),
|
32
|
+
gravity(0),
|
33
|
+
left(0),
|
34
|
+
top(0),
|
35
|
+
hasOffset(false),
|
36
|
+
tile(false),
|
37
|
+
premultiplied(false) {}
|
38
|
+
};
|
39
|
+
|
40
|
+
struct PipelineBaton {
|
41
|
+
sharp::InputDescriptor *input;
|
42
|
+
std::string formatOut;
|
43
|
+
std::string fileOut;
|
44
|
+
void *bufferOut;
|
45
|
+
size_t bufferOutLength;
|
46
|
+
std::vector<Composite *> composite;
|
47
|
+
std::vector<sharp::InputDescriptor *> joinChannelIn;
|
48
|
+
int topOffsetPre;
|
49
|
+
int leftOffsetPre;
|
50
|
+
int widthPre;
|
51
|
+
int heightPre;
|
52
|
+
int topOffsetPost;
|
53
|
+
int leftOffsetPost;
|
54
|
+
int widthPost;
|
55
|
+
int heightPost;
|
56
|
+
int width;
|
57
|
+
int height;
|
58
|
+
int channels;
|
59
|
+
VipsKernel kernel;
|
60
|
+
sharp::Canvas canvas;
|
61
|
+
int position;
|
62
|
+
std::vector<double> resizeBackground;
|
63
|
+
bool hasCropOffset;
|
64
|
+
int cropOffsetLeft;
|
65
|
+
int cropOffsetTop;
|
66
|
+
bool hasAttentionCenter;
|
67
|
+
int attentionX;
|
68
|
+
int attentionY;
|
69
|
+
bool premultiplied;
|
70
|
+
bool tileCentre;
|
71
|
+
bool fastShrinkOnLoad;
|
72
|
+
std::vector<double> tint;
|
73
|
+
bool flatten;
|
74
|
+
std::vector<double> flattenBackground;
|
75
|
+
bool unflatten;
|
76
|
+
bool negate;
|
77
|
+
bool negateAlpha;
|
78
|
+
double blurSigma;
|
79
|
+
double brightness;
|
80
|
+
double saturation;
|
81
|
+
int hue;
|
82
|
+
double lightness;
|
83
|
+
int medianSize;
|
84
|
+
double sharpenSigma;
|
85
|
+
double sharpenM1;
|
86
|
+
double sharpenM2;
|
87
|
+
double sharpenX1;
|
88
|
+
double sharpenY2;
|
89
|
+
double sharpenY3;
|
90
|
+
int threshold;
|
91
|
+
bool thresholdGrayscale;
|
92
|
+
std::vector<double> trimBackground;
|
93
|
+
double trimThreshold;
|
94
|
+
bool trimLineArt;
|
95
|
+
int trimOffsetLeft;
|
96
|
+
int trimOffsetTop;
|
97
|
+
std::vector<double> linearA;
|
98
|
+
std::vector<double> linearB;
|
99
|
+
double gamma;
|
100
|
+
double gammaOut;
|
101
|
+
bool greyscale;
|
102
|
+
bool normalise;
|
103
|
+
int normaliseLower;
|
104
|
+
int normaliseUpper;
|
105
|
+
int claheWidth;
|
106
|
+
int claheHeight;
|
107
|
+
int claheMaxSlope;
|
108
|
+
bool useExifOrientation;
|
109
|
+
int angle;
|
110
|
+
double rotationAngle;
|
111
|
+
std::vector<double> rotationBackground;
|
112
|
+
bool rotateBeforePreExtract;
|
113
|
+
bool flip;
|
114
|
+
bool flop;
|
115
|
+
int extendTop;
|
116
|
+
int extendBottom;
|
117
|
+
int extendLeft;
|
118
|
+
int extendRight;
|
119
|
+
std::vector<double> extendBackground;
|
120
|
+
VipsExtend extendWith;
|
121
|
+
bool withoutEnlargement;
|
122
|
+
bool withoutReduction;
|
123
|
+
std::vector<double> affineMatrix;
|
124
|
+
std::vector<double> affineBackground;
|
125
|
+
double affineIdx;
|
126
|
+
double affineIdy;
|
127
|
+
double affineOdx;
|
128
|
+
double affineOdy;
|
129
|
+
std::string affineInterpolator;
|
130
|
+
int jpegQuality;
|
131
|
+
bool jpegProgressive;
|
132
|
+
std::string jpegChromaSubsampling;
|
133
|
+
bool jpegTrellisQuantisation;
|
134
|
+
int jpegQuantisationTable;
|
135
|
+
bool jpegOvershootDeringing;
|
136
|
+
bool jpegOptimiseScans;
|
137
|
+
bool jpegOptimiseCoding;
|
138
|
+
bool pngProgressive;
|
139
|
+
int pngCompressionLevel;
|
140
|
+
bool pngAdaptiveFiltering;
|
141
|
+
bool pngPalette;
|
142
|
+
int pngQuality;
|
143
|
+
int pngEffort;
|
144
|
+
int pngBitdepth;
|
145
|
+
double pngDither;
|
146
|
+
int jp2Quality;
|
147
|
+
bool jp2Lossless;
|
148
|
+
int jp2TileHeight;
|
149
|
+
int jp2TileWidth;
|
150
|
+
std::string jp2ChromaSubsampling;
|
151
|
+
int webpQuality;
|
152
|
+
int webpAlphaQuality;
|
153
|
+
bool webpNearLossless;
|
154
|
+
bool webpLossless;
|
155
|
+
bool webpSmartSubsample;
|
156
|
+
VipsForeignWebpPreset webpPreset;
|
157
|
+
int webpEffort;
|
158
|
+
bool webpMinSize;
|
159
|
+
bool webpMixed;
|
160
|
+
int gifBitdepth;
|
161
|
+
int gifEffort;
|
162
|
+
double gifDither;
|
163
|
+
double gifInterFrameMaxError;
|
164
|
+
double gifInterPaletteMaxError;
|
165
|
+
bool gifReuse;
|
166
|
+
bool gifProgressive;
|
167
|
+
int tiffQuality;
|
168
|
+
VipsForeignTiffCompression tiffCompression;
|
169
|
+
VipsForeignTiffPredictor tiffPredictor;
|
170
|
+
bool tiffPyramid;
|
171
|
+
int tiffBitdepth;
|
172
|
+
bool tiffMiniswhite;
|
173
|
+
bool tiffTile;
|
174
|
+
int tiffTileHeight;
|
175
|
+
int tiffTileWidth;
|
176
|
+
double tiffXres;
|
177
|
+
double tiffYres;
|
178
|
+
VipsForeignTiffResunit tiffResolutionUnit;
|
179
|
+
int heifQuality;
|
180
|
+
VipsForeignHeifCompression heifCompression;
|
181
|
+
int heifEffort;
|
182
|
+
std::string heifChromaSubsampling;
|
183
|
+
bool heifLossless;
|
184
|
+
double jxlDistance;
|
185
|
+
int jxlDecodingTier;
|
186
|
+
int jxlEffort;
|
187
|
+
bool jxlLossless;
|
188
|
+
VipsBandFormat rawDepth;
|
189
|
+
std::string err;
|
190
|
+
int keepMetadata;
|
191
|
+
int withMetadataOrientation;
|
192
|
+
double withMetadataDensity;
|
193
|
+
std::string withIccProfile;
|
194
|
+
std::unordered_map<std::string, std::string> withExif;
|
195
|
+
bool withExifMerge;
|
196
|
+
int timeoutSeconds;
|
197
|
+
std::unique_ptr<double[]> convKernel;
|
198
|
+
int convKernelWidth;
|
199
|
+
int convKernelHeight;
|
200
|
+
double convKernelScale;
|
201
|
+
double convKernelOffset;
|
202
|
+
sharp::InputDescriptor *boolean;
|
203
|
+
VipsOperationBoolean booleanOp;
|
204
|
+
VipsOperationBoolean bandBoolOp;
|
205
|
+
int extractChannel;
|
206
|
+
bool removeAlpha;
|
207
|
+
double ensureAlpha;
|
208
|
+
VipsInterpretation colourspaceInput;
|
209
|
+
VipsInterpretation colourspace;
|
210
|
+
std::vector<int> delay;
|
211
|
+
int loop;
|
212
|
+
int tileSize;
|
213
|
+
int tileOverlap;
|
214
|
+
VipsForeignDzContainer tileContainer;
|
215
|
+
VipsForeignDzLayout tileLayout;
|
216
|
+
std::string tileFormat;
|
217
|
+
int tileAngle;
|
218
|
+
std::vector<double> tileBackground;
|
219
|
+
int tileSkipBlanks;
|
220
|
+
VipsForeignDzDepth tileDepth;
|
221
|
+
std::string tileId;
|
222
|
+
std::string tileBasename;
|
223
|
+
std::unique_ptr<double[]> recombMatrix;
|
224
|
+
|
225
|
+
PipelineBaton():
|
226
|
+
input(nullptr),
|
227
|
+
bufferOutLength(0),
|
228
|
+
topOffsetPre(-1),
|
229
|
+
topOffsetPost(-1),
|
230
|
+
channels(0),
|
231
|
+
kernel(VIPS_KERNEL_LANCZOS3),
|
232
|
+
canvas(sharp::Canvas::CROP),
|
233
|
+
position(0),
|
234
|
+
resizeBackground{ 0.0, 0.0, 0.0, 255.0 },
|
235
|
+
hasCropOffset(false),
|
236
|
+
cropOffsetLeft(0),
|
237
|
+
cropOffsetTop(0),
|
238
|
+
hasAttentionCenter(false),
|
239
|
+
attentionX(0),
|
240
|
+
attentionY(0),
|
241
|
+
premultiplied(false),
|
242
|
+
tint{ -1.0, 0.0, 0.0, 0.0 },
|
243
|
+
flatten(false),
|
244
|
+
flattenBackground{ 0.0, 0.0, 0.0 },
|
245
|
+
unflatten(false),
|
246
|
+
negate(false),
|
247
|
+
negateAlpha(true),
|
248
|
+
blurSigma(0.0),
|
249
|
+
brightness(1.0),
|
250
|
+
saturation(1.0),
|
251
|
+
hue(0),
|
252
|
+
lightness(0),
|
253
|
+
medianSize(0),
|
254
|
+
sharpenSigma(0.0),
|
255
|
+
sharpenM1(1.0),
|
256
|
+
sharpenM2(2.0),
|
257
|
+
sharpenX1(2.0),
|
258
|
+
sharpenY2(10.0),
|
259
|
+
sharpenY3(20.0),
|
260
|
+
threshold(0),
|
261
|
+
thresholdGrayscale(true),
|
262
|
+
trimBackground{},
|
263
|
+
trimThreshold(-1.0),
|
264
|
+
trimLineArt(false),
|
265
|
+
trimOffsetLeft(0),
|
266
|
+
trimOffsetTop(0),
|
267
|
+
linearA{},
|
268
|
+
linearB{},
|
269
|
+
gamma(0.0),
|
270
|
+
greyscale(false),
|
271
|
+
normalise(false),
|
272
|
+
normaliseLower(1),
|
273
|
+
normaliseUpper(99),
|
274
|
+
claheWidth(0),
|
275
|
+
claheHeight(0),
|
276
|
+
claheMaxSlope(3),
|
277
|
+
useExifOrientation(false),
|
278
|
+
angle(0),
|
279
|
+
rotationAngle(0.0),
|
280
|
+
rotationBackground{ 0.0, 0.0, 0.0, 255.0 },
|
281
|
+
flip(false),
|
282
|
+
flop(false),
|
283
|
+
extendTop(0),
|
284
|
+
extendBottom(0),
|
285
|
+
extendLeft(0),
|
286
|
+
extendRight(0),
|
287
|
+
extendBackground{ 0.0, 0.0, 0.0, 255.0 },
|
288
|
+
extendWith(VIPS_EXTEND_BACKGROUND),
|
289
|
+
withoutEnlargement(false),
|
290
|
+
withoutReduction(false),
|
291
|
+
affineMatrix{ 1.0, 0.0, 0.0, 1.0 },
|
292
|
+
affineBackground{ 0.0, 0.0, 0.0, 255.0 },
|
293
|
+
affineIdx(0),
|
294
|
+
affineIdy(0),
|
295
|
+
affineOdx(0),
|
296
|
+
affineOdy(0),
|
297
|
+
affineInterpolator("bicubic"),
|
298
|
+
jpegQuality(80),
|
299
|
+
jpegProgressive(false),
|
300
|
+
jpegChromaSubsampling("4:2:0"),
|
301
|
+
jpegTrellisQuantisation(false),
|
302
|
+
jpegQuantisationTable(0),
|
303
|
+
jpegOvershootDeringing(false),
|
304
|
+
jpegOptimiseScans(false),
|
305
|
+
jpegOptimiseCoding(true),
|
306
|
+
pngProgressive(false),
|
307
|
+
pngCompressionLevel(6),
|
308
|
+
pngAdaptiveFiltering(false),
|
309
|
+
pngPalette(false),
|
310
|
+
pngQuality(100),
|
311
|
+
pngEffort(7),
|
312
|
+
pngBitdepth(8),
|
313
|
+
pngDither(1.0),
|
314
|
+
jp2Quality(80),
|
315
|
+
jp2Lossless(false),
|
316
|
+
jp2TileHeight(512),
|
317
|
+
jp2TileWidth(512),
|
318
|
+
jp2ChromaSubsampling("4:4:4"),
|
319
|
+
webpQuality(80),
|
320
|
+
webpAlphaQuality(100),
|
321
|
+
webpNearLossless(false),
|
322
|
+
webpLossless(false),
|
323
|
+
webpSmartSubsample(false),
|
324
|
+
webpPreset(VIPS_FOREIGN_WEBP_PRESET_DEFAULT),
|
325
|
+
webpEffort(4),
|
326
|
+
webpMinSize(false),
|
327
|
+
webpMixed(false),
|
328
|
+
gifBitdepth(8),
|
329
|
+
gifEffort(7),
|
330
|
+
gifDither(1.0),
|
331
|
+
gifInterFrameMaxError(0.0),
|
332
|
+
gifInterPaletteMaxError(3.0),
|
333
|
+
gifReuse(true),
|
334
|
+
gifProgressive(false),
|
335
|
+
tiffQuality(80),
|
336
|
+
tiffCompression(VIPS_FOREIGN_TIFF_COMPRESSION_JPEG),
|
337
|
+
tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL),
|
338
|
+
tiffPyramid(false),
|
339
|
+
tiffBitdepth(8),
|
340
|
+
tiffMiniswhite(false),
|
341
|
+
tiffTile(false),
|
342
|
+
tiffTileHeight(256),
|
343
|
+
tiffTileWidth(256),
|
344
|
+
tiffXres(1.0),
|
345
|
+
tiffYres(1.0),
|
346
|
+
tiffResolutionUnit(VIPS_FOREIGN_TIFF_RESUNIT_INCH),
|
347
|
+
heifQuality(50),
|
348
|
+
heifCompression(VIPS_FOREIGN_HEIF_COMPRESSION_AV1),
|
349
|
+
heifEffort(4),
|
350
|
+
heifChromaSubsampling("4:4:4"),
|
351
|
+
heifLossless(false),
|
352
|
+
jxlDistance(1.0),
|
353
|
+
jxlDecodingTier(0),
|
354
|
+
jxlEffort(7),
|
355
|
+
jxlLossless(false),
|
356
|
+
rawDepth(VIPS_FORMAT_UCHAR),
|
357
|
+
keepMetadata(0),
|
358
|
+
withMetadataOrientation(-1),
|
359
|
+
withMetadataDensity(0.0),
|
360
|
+
withExifMerge(true),
|
361
|
+
timeoutSeconds(0),
|
362
|
+
convKernelWidth(0),
|
363
|
+
convKernelHeight(0),
|
364
|
+
convKernelScale(0.0),
|
365
|
+
convKernelOffset(0.0),
|
366
|
+
boolean(nullptr),
|
367
|
+
booleanOp(VIPS_OPERATION_BOOLEAN_LAST),
|
368
|
+
bandBoolOp(VIPS_OPERATION_BOOLEAN_LAST),
|
369
|
+
extractChannel(-1),
|
370
|
+
removeAlpha(false),
|
371
|
+
ensureAlpha(-1.0),
|
372
|
+
colourspaceInput(VIPS_INTERPRETATION_LAST),
|
373
|
+
colourspace(VIPS_INTERPRETATION_LAST),
|
374
|
+
loop(-1),
|
375
|
+
tileSize(256),
|
376
|
+
tileOverlap(0),
|
377
|
+
tileContainer(VIPS_FOREIGN_DZ_CONTAINER_FS),
|
378
|
+
tileLayout(VIPS_FOREIGN_DZ_LAYOUT_DZ),
|
379
|
+
tileAngle(0),
|
380
|
+
tileBackground{ 255.0, 255.0, 255.0, 255.0 },
|
381
|
+
tileSkipBlanks(-1),
|
382
|
+
tileDepth(VIPS_FOREIGN_DZ_DEPTH_LAST) {}
|
383
|
+
};
|
384
|
+
|
385
|
+
#endif // SRC_PIPELINE_H_
|
package/src/sharp.cc
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
// Copyright 2013 Lovell Fuller and others.
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
3
|
+
|
4
|
+
#include <mutex> // NOLINT(build/c++11)
|
5
|
+
|
6
|
+
#include <napi.h>
|
7
|
+
#include <vips/vips8>
|
8
|
+
|
9
|
+
#include "common.h"
|
10
|
+
#include "metadata.h"
|
11
|
+
#include "pipeline.h"
|
12
|
+
#include "utilities.h"
|
13
|
+
#include "stats.h"
|
14
|
+
|
15
|
+
Napi::Object init(Napi::Env env, Napi::Object exports) {
|
16
|
+
static std::once_flag sharp_vips_init_once;
|
17
|
+
std::call_once(sharp_vips_init_once, []() {
|
18
|
+
vips_init("sharp");
|
19
|
+
});
|
20
|
+
|
21
|
+
g_log_set_handler("VIPS", static_cast<GLogLevelFlags>(G_LOG_LEVEL_WARNING),
|
22
|
+
static_cast<GLogFunc>(sharp::VipsWarningCallback), nullptr);
|
23
|
+
|
24
|
+
// Methods available to JavaScript
|
25
|
+
exports.Set("metadata", Napi::Function::New(env, metadata));
|
26
|
+
exports.Set("pipeline", Napi::Function::New(env, pipeline));
|
27
|
+
exports.Set("cache", Napi::Function::New(env, cache));
|
28
|
+
exports.Set("concurrency", Napi::Function::New(env, concurrency));
|
29
|
+
exports.Set("counters", Napi::Function::New(env, counters));
|
30
|
+
exports.Set("simd", Napi::Function::New(env, simd));
|
31
|
+
exports.Set("libvipsVersion", Napi::Function::New(env, libvipsVersion));
|
32
|
+
exports.Set("format", Napi::Function::New(env, format));
|
33
|
+
exports.Set("block", Napi::Function::New(env, block));
|
34
|
+
exports.Set("_maxColourDistance", Napi::Function::New(env, _maxColourDistance));
|
35
|
+
exports.Set("_isUsingJemalloc", Napi::Function::New(env, _isUsingJemalloc));
|
36
|
+
exports.Set("stats", Napi::Function::New(env, stats));
|
37
|
+
return exports;
|
38
|
+
}
|
39
|
+
|
40
|
+
NODE_API_MODULE(sharp, init)
|
package/src/stats.cc
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
// Copyright 2013 Lovell Fuller and others.
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
3
|
+
|
4
|
+
#include <numeric>
|
5
|
+
#include <vector>
|
6
|
+
#include <iostream>
|
7
|
+
|
8
|
+
#include <napi.h>
|
9
|
+
#include <vips/vips8>
|
10
|
+
|
11
|
+
#include "common.h"
|
12
|
+
#include "stats.h"
|
13
|
+
|
14
|
+
class StatsWorker : public Napi::AsyncWorker {
|
15
|
+
public:
|
16
|
+
StatsWorker(Napi::Function callback, StatsBaton *baton, Napi::Function debuglog) :
|
17
|
+
Napi::AsyncWorker(callback), baton(baton), debuglog(Napi::Persistent(debuglog)) {}
|
18
|
+
~StatsWorker() {}
|
19
|
+
|
20
|
+
const int STAT_MIN_INDEX = 0;
|
21
|
+
const int STAT_MAX_INDEX = 1;
|
22
|
+
const int STAT_SUM_INDEX = 2;
|
23
|
+
const int STAT_SQ_SUM_INDEX = 3;
|
24
|
+
const int STAT_MEAN_INDEX = 4;
|
25
|
+
const int STAT_STDEV_INDEX = 5;
|
26
|
+
const int STAT_MINX_INDEX = 6;
|
27
|
+
const int STAT_MINY_INDEX = 7;
|
28
|
+
const int STAT_MAXX_INDEX = 8;
|
29
|
+
const int STAT_MAXY_INDEX = 9;
|
30
|
+
|
31
|
+
void Execute() {
|
32
|
+
// Decrement queued task counter
|
33
|
+
sharp::counterQueue--;
|
34
|
+
|
35
|
+
vips::VImage image;
|
36
|
+
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
|
37
|
+
try {
|
38
|
+
std::tie(image, imageType) = OpenInput(baton->input);
|
39
|
+
} catch (vips::VError const &err) {
|
40
|
+
(baton->err).append(err.what());
|
41
|
+
}
|
42
|
+
if (imageType != sharp::ImageType::UNKNOWN) {
|
43
|
+
try {
|
44
|
+
vips::VImage stats = image.stats();
|
45
|
+
int const bands = image.bands();
|
46
|
+
for (int b = 1; b <= bands; b++) {
|
47
|
+
ChannelStats cStats(
|
48
|
+
static_cast<int>(stats.getpoint(STAT_MIN_INDEX, b).front()),
|
49
|
+
static_cast<int>(stats.getpoint(STAT_MAX_INDEX, b).front()),
|
50
|
+
stats.getpoint(STAT_SUM_INDEX, b).front(),
|
51
|
+
stats.getpoint(STAT_SQ_SUM_INDEX, b).front(),
|
52
|
+
stats.getpoint(STAT_MEAN_INDEX, b).front(),
|
53
|
+
stats.getpoint(STAT_STDEV_INDEX, b).front(),
|
54
|
+
static_cast<int>(stats.getpoint(STAT_MINX_INDEX, b).front()),
|
55
|
+
static_cast<int>(stats.getpoint(STAT_MINY_INDEX, b).front()),
|
56
|
+
static_cast<int>(stats.getpoint(STAT_MAXX_INDEX, b).front()),
|
57
|
+
static_cast<int>(stats.getpoint(STAT_MAXY_INDEX, b).front()));
|
58
|
+
baton->channelStats.push_back(cStats);
|
59
|
+
}
|
60
|
+
// Image is not opaque when alpha layer is present and contains a non-mamixa value
|
61
|
+
if (sharp::HasAlpha(image)) {
|
62
|
+
double const minAlpha = static_cast<double>(stats.getpoint(STAT_MIN_INDEX, bands).front());
|
63
|
+
if (minAlpha != sharp::MaximumImageAlpha(image.interpretation())) {
|
64
|
+
baton->isOpaque = false;
|
65
|
+
}
|
66
|
+
}
|
67
|
+
// Convert to greyscale
|
68
|
+
vips::VImage greyscale = image.colourspace(VIPS_INTERPRETATION_B_W)[0];
|
69
|
+
// Estimate entropy via histogram of greyscale value frequency
|
70
|
+
baton->entropy = std::abs(greyscale.hist_find().hist_entropy());
|
71
|
+
// Estimate sharpness via standard deviation of greyscale laplacian
|
72
|
+
if (image.width() > 1 || image.height() > 1) {
|
73
|
+
VImage laplacian = VImage::new_matrixv(3, 3,
|
74
|
+
0.0, 1.0, 0.0,
|
75
|
+
1.0, -4.0, 1.0,
|
76
|
+
0.0, 1.0, 0.0);
|
77
|
+
laplacian.set("scale", 9.0);
|
78
|
+
baton->sharpness = greyscale.conv(laplacian).deviate();
|
79
|
+
}
|
80
|
+
// Most dominant sRGB colour via 4096-bin 3D histogram
|
81
|
+
vips::VImage hist = sharp::RemoveAlpha(image)
|
82
|
+
.colourspace(VIPS_INTERPRETATION_sRGB)
|
83
|
+
.hist_find_ndim(VImage::option()->set("bins", 16));
|
84
|
+
std::complex<double> maxpos = hist.maxpos();
|
85
|
+
int const dx = static_cast<int>(std::real(maxpos));
|
86
|
+
int const dy = static_cast<int>(std::imag(maxpos));
|
87
|
+
std::vector<double> pel = hist(dx, dy);
|
88
|
+
int const dz = std::distance(pel.begin(), std::find(pel.begin(), pel.end(), hist.max()));
|
89
|
+
baton->dominantRed = dx * 16 + 8;
|
90
|
+
baton->dominantGreen = dy * 16 + 8;
|
91
|
+
baton->dominantBlue = dz * 16 + 8;
|
92
|
+
} catch (vips::VError const &err) {
|
93
|
+
(baton->err).append(err.what());
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
// Clean up
|
98
|
+
vips_error_clear();
|
99
|
+
vips_thread_shutdown();
|
100
|
+
}
|
101
|
+
|
102
|
+
void OnOK() {
|
103
|
+
Napi::Env env = Env();
|
104
|
+
Napi::HandleScope scope(env);
|
105
|
+
|
106
|
+
// Handle warnings
|
107
|
+
std::string warning = sharp::VipsWarningPop();
|
108
|
+
while (!warning.empty()) {
|
109
|
+
debuglog.Call(Receiver().Value(), { Napi::String::New(env, warning) });
|
110
|
+
warning = sharp::VipsWarningPop();
|
111
|
+
}
|
112
|
+
|
113
|
+
if (baton->err.empty()) {
|
114
|
+
// Stats Object
|
115
|
+
Napi::Object info = Napi::Object::New(env);
|
116
|
+
Napi::Array channels = Napi::Array::New(env);
|
117
|
+
|
118
|
+
std::vector<ChannelStats>::iterator it;
|
119
|
+
int i = 0;
|
120
|
+
for (it = baton->channelStats.begin(); it < baton->channelStats.end(); it++, i++) {
|
121
|
+
Napi::Object channelStat = Napi::Object::New(env);
|
122
|
+
channelStat.Set("min", it->min);
|
123
|
+
channelStat.Set("max", it->max);
|
124
|
+
channelStat.Set("sum", it->sum);
|
125
|
+
channelStat.Set("squaresSum", it->squaresSum);
|
126
|
+
channelStat.Set("mean", it->mean);
|
127
|
+
channelStat.Set("stdev", it->stdev);
|
128
|
+
channelStat.Set("minX", it->minX);
|
129
|
+
channelStat.Set("minY", it->minY);
|
130
|
+
channelStat.Set("maxX", it->maxX);
|
131
|
+
channelStat.Set("maxY", it->maxY);
|
132
|
+
channels.Set(i, channelStat);
|
133
|
+
}
|
134
|
+
|
135
|
+
info.Set("channels", channels);
|
136
|
+
info.Set("isOpaque", baton->isOpaque);
|
137
|
+
info.Set("entropy", baton->entropy);
|
138
|
+
info.Set("sharpness", baton->sharpness);
|
139
|
+
Napi::Object dominant = Napi::Object::New(env);
|
140
|
+
dominant.Set("r", baton->dominantRed);
|
141
|
+
dominant.Set("g", baton->dominantGreen);
|
142
|
+
dominant.Set("b", baton->dominantBlue);
|
143
|
+
info.Set("dominant", dominant);
|
144
|
+
Callback().Call(Receiver().Value(), { env.Null(), info });
|
145
|
+
} else {
|
146
|
+
Callback().Call(Receiver().Value(), { Napi::Error::New(env, sharp::TrimEnd(baton->err)).Value() });
|
147
|
+
}
|
148
|
+
|
149
|
+
delete baton->input;
|
150
|
+
delete baton;
|
151
|
+
}
|
152
|
+
|
153
|
+
private:
|
154
|
+
StatsBaton* baton;
|
155
|
+
Napi::FunctionReference debuglog;
|
156
|
+
};
|
157
|
+
|
158
|
+
/*
|
159
|
+
stats(options, callback)
|
160
|
+
*/
|
161
|
+
Napi::Value stats(const Napi::CallbackInfo& info) {
|
162
|
+
// V8 objects are converted to non-V8 types held in the baton struct
|
163
|
+
StatsBaton *baton = new StatsBaton;
|
164
|
+
Napi::Object options = info[size_t(0)].As<Napi::Object>();
|
165
|
+
|
166
|
+
// Input
|
167
|
+
baton->input = sharp::CreateInputDescriptor(options.Get("input").As<Napi::Object>());
|
168
|
+
baton->input->access = VIPS_ACCESS_RANDOM;
|
169
|
+
|
170
|
+
// Function to notify of libvips warnings
|
171
|
+
Napi::Function debuglog = options.Get("debuglog").As<Napi::Function>();
|
172
|
+
|
173
|
+
// Join queue for worker thread
|
174
|
+
Napi::Function callback = info[size_t(1)].As<Napi::Function>();
|
175
|
+
StatsWorker *worker = new StatsWorker(callback, baton, debuglog);
|
176
|
+
worker->Receiver().Set("options", options);
|
177
|
+
worker->Queue();
|
178
|
+
|
179
|
+
// Increment queued task counter
|
180
|
+
sharp::counterQueue++;
|
181
|
+
|
182
|
+
return info.Env().Undefined();
|
183
|
+
}
|
package/src/stats.h
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
// Copyright 2013 Lovell Fuller and others.
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
3
|
+
|
4
|
+
#ifndef SRC_STATS_H_
|
5
|
+
#define SRC_STATS_H_
|
6
|
+
|
7
|
+
#include <string>
|
8
|
+
#include <napi.h>
|
9
|
+
|
10
|
+
#include "./common.h"
|
11
|
+
|
12
|
+
struct ChannelStats {
|
13
|
+
// stats per channel
|
14
|
+
int min;
|
15
|
+
int max;
|
16
|
+
double sum;
|
17
|
+
double squaresSum;
|
18
|
+
double mean;
|
19
|
+
double stdev;
|
20
|
+
int minX;
|
21
|
+
int minY;
|
22
|
+
int maxX;
|
23
|
+
int maxY;
|
24
|
+
|
25
|
+
ChannelStats(int minVal, int maxVal, double sumVal, double squaresSumVal,
|
26
|
+
double meanVal, double stdevVal, int minXVal, int minYVal, int maxXVal, int maxYVal):
|
27
|
+
min(minVal), max(maxVal), sum(sumVal), squaresSum(squaresSumVal),
|
28
|
+
mean(meanVal), stdev(stdevVal), minX(minXVal), minY(minYVal), maxX(maxXVal), maxY(maxYVal) {}
|
29
|
+
};
|
30
|
+
|
31
|
+
struct StatsBaton {
|
32
|
+
// Input
|
33
|
+
sharp::InputDescriptor *input;
|
34
|
+
|
35
|
+
// Output
|
36
|
+
std::vector<ChannelStats> channelStats;
|
37
|
+
bool isOpaque;
|
38
|
+
double entropy;
|
39
|
+
double sharpness;
|
40
|
+
int dominantRed;
|
41
|
+
int dominantGreen;
|
42
|
+
int dominantBlue;
|
43
|
+
|
44
|
+
std::string err;
|
45
|
+
|
46
|
+
StatsBaton():
|
47
|
+
input(nullptr),
|
48
|
+
isOpaque(true),
|
49
|
+
entropy(0.0),
|
50
|
+
sharpness(0.0),
|
51
|
+
dominantRed(0),
|
52
|
+
dominantGreen(0),
|
53
|
+
dominantBlue(0)
|
54
|
+
{}
|
55
|
+
};
|
56
|
+
|
57
|
+
Napi::Value stats(const Napi::CallbackInfo& info);
|
58
|
+
|
59
|
+
#endif // SRC_STATS_H_
|