sharp 0.32.6 → 0.33.0-alpha.11
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 +6 -2
- package/install/check.js +36 -0
- package/lib/constructor.js +6 -5
- package/lib/index.d.ts +13 -16
- package/lib/input.js +34 -8
- package/lib/is.js +28 -14
- package/lib/libvips.js +86 -55
- package/lib/output.js +41 -24
- package/lib/resize.js +46 -46
- package/lib/sharp.js +71 -26
- package/lib/utility.js +25 -25
- package/package.json +56 -41
- package/{binding.gyp → src/binding.gyp} +89 -43
- package/src/common.cc +5 -4
- package/src/common.h +6 -5
- package/src/metadata.cc +5 -5
- package/src/operations.cc +5 -2
- package/src/operations.h +1 -1
- package/src/pipeline.cc +19 -19
- package/src/pipeline.h +5 -1
- package/src/sharp.cc +6 -7
- package/src/stats.cc +5 -5
- package/src/utilities.cc +20 -5
- package/install/can-compile.js +0 -14
- package/install/dll-copy.js +0 -40
- package/install/libvips.js +0 -222
- package/lib/agent.js +0 -44
- package/lib/platform.js +0 -30
- package/src/libvips/cplusplus/VConnection.cpp +0 -151
- package/src/libvips/cplusplus/VError.cpp +0 -49
- package/src/libvips/cplusplus/VImage.cpp +0 -1548
- package/src/libvips/cplusplus/VInterpolate.cpp +0 -62
- package/src/libvips/cplusplus/VRegion.cpp +0 -27
- package/src/libvips/cplusplus/vips-operators.cpp +0 -3760
package/src/pipeline.cc
CHANGED
|
@@ -44,9 +44,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
44
44
|
// libuv worker
|
|
45
45
|
void Execute() {
|
|
46
46
|
// Decrement queued task counter
|
|
47
|
-
|
|
47
|
+
sharp::counterQueue--;
|
|
48
48
|
// Increment processing task counter
|
|
49
|
-
|
|
49
|
+
sharp::counterProcess++;
|
|
50
50
|
|
|
51
51
|
try {
|
|
52
52
|
// Open input
|
|
@@ -126,10 +126,10 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
// Trim
|
|
129
|
-
if (baton->trimThreshold
|
|
129
|
+
if (baton->trimThreshold >= 0.0) {
|
|
130
130
|
MultiPageUnsupported(nPages, "Trim");
|
|
131
131
|
image = sharp::StaySequential(image, access);
|
|
132
|
-
image = sharp::Trim(image, baton->trimBackground, baton->trimThreshold);
|
|
132
|
+
image = sharp::Trim(image, baton->trimBackground, baton->trimThreshold, baton->trimLineArt);
|
|
133
133
|
baton->trimOffsetLeft = image.xoffset();
|
|
134
134
|
baton->trimOffsetTop = image.yoffset();
|
|
135
135
|
}
|
|
@@ -182,7 +182,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
182
182
|
// - trimming or pre-resize extract isn't required;
|
|
183
183
|
// - input colourspace is not specified;
|
|
184
184
|
bool const shouldPreShrink = (targetResizeWidth > 0 || targetResizeHeight > 0) &&
|
|
185
|
-
baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold
|
|
185
|
+
baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold < 0.0 &&
|
|
186
186
|
baton->colourspaceInput == VIPS_INTERPRETATION_LAST && !shouldRotateBefore;
|
|
187
187
|
|
|
188
188
|
if (shouldPreShrink) {
|
|
@@ -485,9 +485,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
485
485
|
image = sharp::StaySequential(image, access);
|
|
486
486
|
image = image.smartcrop(baton->width, baton->height, VImage::option()
|
|
487
487
|
->set("interesting", baton->position == 16 ? VIPS_INTERESTING_ENTROPY : VIPS_INTERESTING_ATTENTION)
|
|
488
|
-
#if (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 15)
|
|
489
488
|
->set("premultiplied", shouldPremultiplyAlpha)
|
|
490
|
-
#endif
|
|
491
489
|
->set("attention_x", &attention_x)
|
|
492
490
|
->set("attention_y", &attention_y));
|
|
493
491
|
baton->hasCropOffset = true;
|
|
@@ -940,6 +938,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
940
938
|
->set("Q", baton->tiffQuality)
|
|
941
939
|
->set("bitdepth", baton->tiffBitdepth)
|
|
942
940
|
->set("compression", baton->tiffCompression)
|
|
941
|
+
->set("miniswhite", baton->tiffMiniswhite)
|
|
943
942
|
->set("predictor", baton->tiffPredictor)
|
|
944
943
|
->set("pyramid", baton->tiffPyramid)
|
|
945
944
|
->set("tile", baton->tiffTile)
|
|
@@ -1136,6 +1135,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1136
1135
|
->set("Q", baton->tiffQuality)
|
|
1137
1136
|
->set("bitdepth", baton->tiffBitdepth)
|
|
1138
1137
|
->set("compression", baton->tiffCompression)
|
|
1138
|
+
->set("miniswhite", baton->tiffMiniswhite)
|
|
1139
1139
|
->set("predictor", baton->tiffPredictor)
|
|
1140
1140
|
->set("pyramid", baton->tiffPyramid)
|
|
1141
1141
|
->set("tile", baton->tiffTile)
|
|
@@ -1215,7 +1215,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1215
1215
|
// Handle warnings
|
|
1216
1216
|
std::string warning = sharp::VipsWarningPop();
|
|
1217
1217
|
while (!warning.empty()) {
|
|
1218
|
-
debuglog.
|
|
1218
|
+
debuglog.Call(Receiver().Value(), { Napi::String::New(env, warning) });
|
|
1219
1219
|
warning = sharp::VipsWarningPop();
|
|
1220
1220
|
}
|
|
1221
1221
|
|
|
@@ -1248,11 +1248,10 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1248
1248
|
info.Set("attentionX", static_cast<int32_t>(baton->attentionX));
|
|
1249
1249
|
info.Set("attentionY", static_cast<int32_t>(baton->attentionY));
|
|
1250
1250
|
}
|
|
1251
|
-
if (baton->trimThreshold
|
|
1251
|
+
if (baton->trimThreshold >= 0.0) {
|
|
1252
1252
|
info.Set("trimOffsetLeft", static_cast<int32_t>(baton->trimOffsetLeft));
|
|
1253
1253
|
info.Set("trimOffsetTop", static_cast<int32_t>(baton->trimOffsetTop));
|
|
1254
1254
|
}
|
|
1255
|
-
|
|
1256
1255
|
if (baton->input->textAutofitDpi) {
|
|
1257
1256
|
info.Set("textAutofitDpi", static_cast<uint32_t>(baton->input->textAutofitDpi));
|
|
1258
1257
|
}
|
|
@@ -1263,17 +1262,17 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1263
1262
|
// Pass ownership of output data to Buffer instance
|
|
1264
1263
|
Napi::Buffer<char> data = Napi::Buffer<char>::NewOrCopy(env, static_cast<char*>(baton->bufferOut),
|
|
1265
1264
|
baton->bufferOutLength, sharp::FreeCallback);
|
|
1266
|
-
Callback().
|
|
1265
|
+
Callback().Call(Receiver().Value(), { env.Null(), data, info });
|
|
1267
1266
|
} else {
|
|
1268
1267
|
// Add file size to info
|
|
1269
1268
|
struct STAT64_STRUCT st;
|
|
1270
1269
|
if (STAT64_FUNCTION(baton->fileOut.data(), &st) == 0) {
|
|
1271
1270
|
info.Set("size", static_cast<uint32_t>(st.st_size));
|
|
1272
1271
|
}
|
|
1273
|
-
Callback().
|
|
1272
|
+
Callback().Call(Receiver().Value(), { env.Null(), info });
|
|
1274
1273
|
}
|
|
1275
1274
|
} else {
|
|
1276
|
-
Callback().
|
|
1275
|
+
Callback().Call(Receiver().Value(), { Napi::Error::New(env, sharp::TrimEnd(baton->err)).Value() });
|
|
1277
1276
|
}
|
|
1278
1277
|
|
|
1279
1278
|
// Delete baton
|
|
@@ -1289,9 +1288,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1289
1288
|
delete baton;
|
|
1290
1289
|
|
|
1291
1290
|
// Decrement processing task counter
|
|
1292
|
-
|
|
1293
|
-
Napi::Number queueLength = Napi::Number::New(env, static_cast<
|
|
1294
|
-
queueListener.
|
|
1291
|
+
sharp::counterProcess--;
|
|
1292
|
+
Napi::Number queueLength = Napi::Number::New(env, static_cast<int>(sharp::counterQueue));
|
|
1293
|
+
queueListener.Call(Receiver().Value(), { queueLength });
|
|
1295
1294
|
}
|
|
1296
1295
|
|
|
1297
1296
|
private:
|
|
@@ -1519,6 +1518,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1519
1518
|
baton->thresholdGrayscale = sharp::AttrAsBool(options, "thresholdGrayscale");
|
|
1520
1519
|
baton->trimBackground = sharp::AttrAsVectorOfDouble(options, "trimBackground");
|
|
1521
1520
|
baton->trimThreshold = sharp::AttrAsDouble(options, "trimThreshold");
|
|
1521
|
+
baton->trimLineArt = sharp::AttrAsBool(options, "trimLineArt");
|
|
1522
1522
|
baton->gamma = sharp::AttrAsDouble(options, "gamma");
|
|
1523
1523
|
baton->gammaOut = sharp::AttrAsDouble(options, "gammaOut");
|
|
1524
1524
|
baton->linearA = sharp::AttrAsVectorOfDouble(options, "linearA");
|
|
@@ -1647,6 +1647,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1647
1647
|
baton->gifProgressive = sharp::AttrAsBool(options, "gifProgressive");
|
|
1648
1648
|
baton->tiffQuality = sharp::AttrAsUint32(options, "tiffQuality");
|
|
1649
1649
|
baton->tiffPyramid = sharp::AttrAsBool(options, "tiffPyramid");
|
|
1650
|
+
baton->tiffMiniswhite = sharp::AttrAsBool(options, "tiffMiniswhite");
|
|
1650
1651
|
baton->tiffBitdepth = sharp::AttrAsUint32(options, "tiffBitdepth");
|
|
1651
1652
|
baton->tiffTile = sharp::AttrAsBool(options, "tiffTile");
|
|
1652
1653
|
baton->tiffTileWidth = sharp::AttrAsUint32(options, "tiffTileWidth");
|
|
@@ -1707,9 +1708,8 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1707
1708
|
worker->Queue();
|
|
1708
1709
|
|
|
1709
1710
|
// Increment queued task counter
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
queueListener.MakeCallback(info.This(), { queueLength });
|
|
1711
|
+
Napi::Number queueLength = Napi::Number::New(info.Env(), static_cast<int>(++sharp::counterQueue));
|
|
1712
|
+
queueListener.Call(info.This(), { queueLength });
|
|
1713
1713
|
|
|
1714
1714
|
return info.Env().Undefined();
|
|
1715
1715
|
}
|
package/src/pipeline.h
CHANGED
|
@@ -92,6 +92,7 @@ struct PipelineBaton {
|
|
|
92
92
|
bool thresholdGrayscale;
|
|
93
93
|
std::vector<double> trimBackground;
|
|
94
94
|
double trimThreshold;
|
|
95
|
+
bool trimLineArt;
|
|
95
96
|
int trimOffsetLeft;
|
|
96
97
|
int trimOffsetTop;
|
|
97
98
|
std::vector<double> linearA;
|
|
@@ -169,6 +170,7 @@ struct PipelineBaton {
|
|
|
169
170
|
VipsForeignTiffPredictor tiffPredictor;
|
|
170
171
|
bool tiffPyramid;
|
|
171
172
|
int tiffBitdepth;
|
|
173
|
+
bool tiffMiniswhite;
|
|
172
174
|
bool tiffTile;
|
|
173
175
|
int tiffTileHeight;
|
|
174
176
|
int tiffTileWidth;
|
|
@@ -259,7 +261,8 @@ struct PipelineBaton {
|
|
|
259
261
|
threshold(0),
|
|
260
262
|
thresholdGrayscale(true),
|
|
261
263
|
trimBackground{},
|
|
262
|
-
trimThreshold(
|
|
264
|
+
trimThreshold(-1.0),
|
|
265
|
+
trimLineArt(false),
|
|
263
266
|
trimOffsetLeft(0),
|
|
264
267
|
trimOffsetTop(0),
|
|
265
268
|
linearA{},
|
|
@@ -335,6 +338,7 @@ struct PipelineBaton {
|
|
|
335
338
|
tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL),
|
|
336
339
|
tiffPyramid(false),
|
|
337
340
|
tiffBitdepth(8),
|
|
341
|
+
tiffMiniswhite(false),
|
|
338
342
|
tiffTile(false),
|
|
339
343
|
tiffTileHeight(256),
|
|
340
344
|
tiffTileWidth(256),
|
package/src/sharp.cc
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Copyright 2013 Lovell Fuller and others.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
+
#include <mutex> // NOLINT(build/c++11)
|
|
5
|
+
|
|
4
6
|
#include <napi.h>
|
|
5
7
|
#include <vips/vips8>
|
|
6
8
|
|
|
@@ -10,14 +12,11 @@
|
|
|
10
12
|
#include "utilities.h"
|
|
11
13
|
#include "stats.h"
|
|
12
14
|
|
|
13
|
-
static void* sharp_vips_init(void*) {
|
|
14
|
-
vips_init("sharp");
|
|
15
|
-
return nullptr;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
15
|
Napi::Object init(Napi::Env env, Napi::Object exports) {
|
|
19
|
-
static
|
|
20
|
-
|
|
16
|
+
static std::once_flag sharp_vips_init_once;
|
|
17
|
+
std::call_once(sharp_vips_init_once, []() {
|
|
18
|
+
vips_init("sharp");
|
|
19
|
+
});
|
|
21
20
|
|
|
22
21
|
g_log_set_handler("VIPS", static_cast<GLogLevelFlags>(G_LOG_LEVEL_WARNING),
|
|
23
22
|
static_cast<GLogFunc>(sharp::VipsWarningCallback), nullptr);
|
package/src/stats.cc
CHANGED
|
@@ -30,7 +30,7 @@ class StatsWorker : public Napi::AsyncWorker {
|
|
|
30
30
|
|
|
31
31
|
void Execute() {
|
|
32
32
|
// Decrement queued task counter
|
|
33
|
-
|
|
33
|
+
sharp::counterQueue--;
|
|
34
34
|
|
|
35
35
|
vips::VImage image;
|
|
36
36
|
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
|
|
@@ -106,7 +106,7 @@ class StatsWorker : public Napi::AsyncWorker {
|
|
|
106
106
|
// Handle warnings
|
|
107
107
|
std::string warning = sharp::VipsWarningPop();
|
|
108
108
|
while (!warning.empty()) {
|
|
109
|
-
debuglog.
|
|
109
|
+
debuglog.Call(Receiver().Value(), { Napi::String::New(env, warning) });
|
|
110
110
|
warning = sharp::VipsWarningPop();
|
|
111
111
|
}
|
|
112
112
|
|
|
@@ -141,9 +141,9 @@ class StatsWorker : public Napi::AsyncWorker {
|
|
|
141
141
|
dominant.Set("g", baton->dominantGreen);
|
|
142
142
|
dominant.Set("b", baton->dominantBlue);
|
|
143
143
|
info.Set("dominant", dominant);
|
|
144
|
-
Callback().
|
|
144
|
+
Callback().Call(Receiver().Value(), { env.Null(), info });
|
|
145
145
|
} else {
|
|
146
|
-
Callback().
|
|
146
|
+
Callback().Call(Receiver().Value(), { Napi::Error::New(env, sharp::TrimEnd(baton->err)).Value() });
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
delete baton->input;
|
|
@@ -177,7 +177,7 @@ Napi::Value stats(const Napi::CallbackInfo& info) {
|
|
|
177
177
|
worker->Queue();
|
|
178
178
|
|
|
179
179
|
// Increment queued task counter
|
|
180
|
-
|
|
180
|
+
sharp::counterQueue++;
|
|
181
181
|
|
|
182
182
|
return info.Env().Undefined();
|
|
183
183
|
}
|
package/src/utilities.cc
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
#include <cmath>
|
|
5
5
|
#include <string>
|
|
6
|
+
#include <cstdio>
|
|
6
7
|
|
|
7
8
|
#include <napi.h>
|
|
8
9
|
#include <vips/vips8>
|
|
@@ -70,8 +71,8 @@ Napi::Value concurrency(const Napi::CallbackInfo& info) {
|
|
|
70
71
|
*/
|
|
71
72
|
Napi::Value counters(const Napi::CallbackInfo& info) {
|
|
72
73
|
Napi::Object counters = Napi::Object::New(info.Env());
|
|
73
|
-
counters.Set("queue", sharp::counterQueue);
|
|
74
|
-
counters.Set("process", sharp::counterProcess);
|
|
74
|
+
counters.Set("queue", static_cast<int>(sharp::counterQueue));
|
|
75
|
+
counters.Set("process", static_cast<int>(sharp::counterProcess));
|
|
75
76
|
return counters;
|
|
76
77
|
}
|
|
77
78
|
|
|
@@ -91,9 +92,23 @@ Napi::Value simd(const Napi::CallbackInfo& info) {
|
|
|
91
92
|
Get libvips version
|
|
92
93
|
*/
|
|
93
94
|
Napi::Value libvipsVersion(const Napi::CallbackInfo& info) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
Napi::Env env = info.Env();
|
|
96
|
+
Napi::Object version = Napi::Object::New(env);
|
|
97
|
+
|
|
98
|
+
char semver[9];
|
|
99
|
+
std::snprintf(semver, sizeof(semver), "%d.%d.%d", vips_version(0), vips_version(1), vips_version(2));
|
|
100
|
+
version.Set("semver", Napi::String::New(env, semver));
|
|
101
|
+
#ifdef SHARP_USE_GLOBAL_LIBVIPS
|
|
102
|
+
version.Set("isGlobal", Napi::Boolean::New(env, true));
|
|
103
|
+
#else
|
|
104
|
+
version.Set("isGlobal", Napi::Boolean::New(env, false));
|
|
105
|
+
#endif
|
|
106
|
+
#ifdef __EMSCRIPTEN__
|
|
107
|
+
version.Set("isWasm", Napi::Boolean::New(env, true));
|
|
108
|
+
#else
|
|
109
|
+
version.Set("isWasm", Napi::Boolean::New(env, false));
|
|
110
|
+
#endif
|
|
111
|
+
return version;
|
|
97
112
|
}
|
|
98
113
|
|
|
99
114
|
/*
|
package/install/can-compile.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// Copyright 2013 Lovell Fuller and others.
|
|
2
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
|
|
4
|
-
'use strict';
|
|
5
|
-
|
|
6
|
-
const libvips = require('../lib/libvips');
|
|
7
|
-
|
|
8
|
-
try {
|
|
9
|
-
if (!(libvips.useGlobalLibvips() || libvips.hasVendoredLibvips())) {
|
|
10
|
-
process.exitCode = 1;
|
|
11
|
-
}
|
|
12
|
-
} catch (err) {
|
|
13
|
-
process.exitCode = 1;
|
|
14
|
-
}
|
package/install/dll-copy.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
// Copyright 2013 Lovell Fuller and others.
|
|
2
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
|
|
4
|
-
'use strict';
|
|
5
|
-
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
|
|
9
|
-
const libvips = require('../lib/libvips');
|
|
10
|
-
const platform = require('../lib/platform');
|
|
11
|
-
|
|
12
|
-
const minimumLibvipsVersion = libvips.minimumLibvipsVersion;
|
|
13
|
-
|
|
14
|
-
const platformAndArch = platform();
|
|
15
|
-
|
|
16
|
-
if (platformAndArch.startsWith('win32')) {
|
|
17
|
-
const buildReleaseDir = path.join(__dirname, '..', 'build', 'Release');
|
|
18
|
-
libvips.log(`Creating ${buildReleaseDir}`);
|
|
19
|
-
try {
|
|
20
|
-
libvips.mkdirSync(buildReleaseDir);
|
|
21
|
-
} catch (err) {}
|
|
22
|
-
const vendorLibDir = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion, platformAndArch, 'lib');
|
|
23
|
-
libvips.log(`Copying DLLs from ${vendorLibDir} to ${buildReleaseDir}`);
|
|
24
|
-
try {
|
|
25
|
-
fs
|
|
26
|
-
.readdirSync(vendorLibDir)
|
|
27
|
-
.filter(function (filename) {
|
|
28
|
-
return /\.dll$/.test(filename);
|
|
29
|
-
})
|
|
30
|
-
.forEach(function (filename) {
|
|
31
|
-
fs.copyFileSync(
|
|
32
|
-
path.join(vendorLibDir, filename),
|
|
33
|
-
path.join(buildReleaseDir, filename)
|
|
34
|
-
);
|
|
35
|
-
});
|
|
36
|
-
} catch (err) {
|
|
37
|
-
libvips.log(err);
|
|
38
|
-
process.exit(1);
|
|
39
|
-
}
|
|
40
|
-
}
|
package/install/libvips.js
DELETED
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
// Copyright 2013 Lovell Fuller and others.
|
|
2
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
|
|
4
|
-
'use strict';
|
|
5
|
-
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
const os = require('os');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
const stream = require('stream');
|
|
10
|
-
const zlib = require('zlib');
|
|
11
|
-
const { createHash } = require('crypto');
|
|
12
|
-
|
|
13
|
-
const detectLibc = require('detect-libc');
|
|
14
|
-
const semverCoerce = require('semver/functions/coerce');
|
|
15
|
-
const semverLessThan = require('semver/functions/lt');
|
|
16
|
-
const semverSatisfies = require('semver/functions/satisfies');
|
|
17
|
-
const simpleGet = require('simple-get');
|
|
18
|
-
const tarFs = require('tar-fs');
|
|
19
|
-
|
|
20
|
-
const agent = require('../lib/agent');
|
|
21
|
-
const libvips = require('../lib/libvips');
|
|
22
|
-
const platform = require('../lib/platform');
|
|
23
|
-
|
|
24
|
-
const minimumGlibcVersionByArch = {
|
|
25
|
-
arm: '2.28',
|
|
26
|
-
arm64: '2.17',
|
|
27
|
-
x64: '2.17'
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const hasSharpPrebuild = [
|
|
31
|
-
'darwin-x64',
|
|
32
|
-
'darwin-arm64',
|
|
33
|
-
'linux-arm64',
|
|
34
|
-
'linux-x64',
|
|
35
|
-
'linuxmusl-x64',
|
|
36
|
-
'linuxmusl-arm64',
|
|
37
|
-
'win32-ia32',
|
|
38
|
-
'win32-x64'
|
|
39
|
-
];
|
|
40
|
-
|
|
41
|
-
const { minimumLibvipsVersion, minimumLibvipsVersionLabelled } = libvips;
|
|
42
|
-
const localLibvipsDir = process.env.npm_config_sharp_libvips_local_prebuilds || '';
|
|
43
|
-
const distHost = process.env.npm_config_sharp_libvips_binary_host || 'https://github.com/lovell/sharp-libvips/releases/download';
|
|
44
|
-
const distBaseUrl = process.env.npm_config_sharp_dist_base_url || process.env.SHARP_DIST_BASE_URL || `${distHost}/v${minimumLibvipsVersionLabelled}/`;
|
|
45
|
-
const installationForced = !!(process.env.npm_config_sharp_install_force || process.env.SHARP_INSTALL_FORCE);
|
|
46
|
-
|
|
47
|
-
const fail = function (err) {
|
|
48
|
-
libvips.log(err);
|
|
49
|
-
if (err.code === 'EACCES') {
|
|
50
|
-
libvips.log('Are you trying to install as a root or sudo user?');
|
|
51
|
-
libvips.log('- For npm <= v6, try again with the "--unsafe-perm" flag');
|
|
52
|
-
libvips.log('- For npm >= v8, the user must own the directory "npm install" is run in');
|
|
53
|
-
}
|
|
54
|
-
libvips.log('Please see https://sharp.pixelplumbing.com/install for required dependencies');
|
|
55
|
-
process.exit(1);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const handleError = function (err) {
|
|
59
|
-
if (installationForced) {
|
|
60
|
-
libvips.log(`Installation warning: ${err.message}`);
|
|
61
|
-
} else {
|
|
62
|
-
throw err;
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const verifyIntegrity = function (platformAndArch) {
|
|
67
|
-
const expected = libvips.integrity(platformAndArch);
|
|
68
|
-
if (installationForced || !expected) {
|
|
69
|
-
libvips.log(`Integrity check skipped for ${platformAndArch}`);
|
|
70
|
-
return new stream.PassThrough();
|
|
71
|
-
}
|
|
72
|
-
const hash = createHash('sha512');
|
|
73
|
-
return new stream.Transform({
|
|
74
|
-
transform: function (chunk, _encoding, done) {
|
|
75
|
-
hash.update(chunk);
|
|
76
|
-
done(null, chunk);
|
|
77
|
-
},
|
|
78
|
-
flush: function (done) {
|
|
79
|
-
const digest = `sha512-${hash.digest('base64')}`;
|
|
80
|
-
if (expected !== digest) {
|
|
81
|
-
try {
|
|
82
|
-
libvips.removeVendoredLibvips();
|
|
83
|
-
} catch (err) {
|
|
84
|
-
libvips.log(err.message);
|
|
85
|
-
}
|
|
86
|
-
libvips.log(`Integrity expected: ${expected}`);
|
|
87
|
-
libvips.log(`Integrity received: ${digest}`);
|
|
88
|
-
done(new Error(`Integrity check failed for ${platformAndArch}`));
|
|
89
|
-
} else {
|
|
90
|
-
libvips.log(`Integrity check passed for ${platformAndArch}`);
|
|
91
|
-
done();
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
const extractTarball = function (tarPath, platformAndArch) {
|
|
98
|
-
const versionedVendorPath = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion, platformAndArch);
|
|
99
|
-
libvips.mkdirSync(versionedVendorPath);
|
|
100
|
-
|
|
101
|
-
const ignoreVendorInclude = hasSharpPrebuild.includes(platformAndArch) && !process.env.npm_config_build_from_source;
|
|
102
|
-
const ignore = function (name) {
|
|
103
|
-
return ignoreVendorInclude && name.includes('include/');
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
stream.pipeline(
|
|
107
|
-
fs.createReadStream(tarPath),
|
|
108
|
-
verifyIntegrity(platformAndArch),
|
|
109
|
-
new zlib.BrotliDecompress(),
|
|
110
|
-
tarFs.extract(versionedVendorPath, { ignore }),
|
|
111
|
-
function (err) {
|
|
112
|
-
if (err) {
|
|
113
|
-
if (/unexpected end of file/.test(err.message)) {
|
|
114
|
-
fail(new Error(`Please delete ${tarPath} as it is not a valid tarball`));
|
|
115
|
-
}
|
|
116
|
-
fail(err);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
);
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
try {
|
|
123
|
-
const useGlobalLibvips = libvips.useGlobalLibvips();
|
|
124
|
-
|
|
125
|
-
if (useGlobalLibvips) {
|
|
126
|
-
const globalLibvipsVersion = libvips.globalLibvipsVersion();
|
|
127
|
-
libvips.log(`Detected globally-installed libvips v${globalLibvipsVersion}`);
|
|
128
|
-
libvips.log('Building from source via node-gyp');
|
|
129
|
-
process.exit(1);
|
|
130
|
-
} else if (libvips.hasVendoredLibvips()) {
|
|
131
|
-
libvips.log(`Using existing vendored libvips v${minimumLibvipsVersion}`);
|
|
132
|
-
} else {
|
|
133
|
-
// Is this arch/platform supported?
|
|
134
|
-
const arch = process.env.npm_config_arch || process.arch;
|
|
135
|
-
const platformAndArch = platform();
|
|
136
|
-
if (arch === 'ia32' && !platformAndArch.startsWith('win32')) {
|
|
137
|
-
throw new Error(`Intel Architecture 32-bit systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
|
|
138
|
-
}
|
|
139
|
-
if (platformAndArch === 'freebsd-x64' || platformAndArch === 'openbsd-x64' || platformAndArch === 'sunos-x64') {
|
|
140
|
-
throw new Error(`BSD/SunOS systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
|
|
141
|
-
}
|
|
142
|
-
// Linux libc version check
|
|
143
|
-
const libcVersionRaw = detectLibc.versionSync();
|
|
144
|
-
if (libcVersionRaw) {
|
|
145
|
-
const libcFamily = detectLibc.familySync();
|
|
146
|
-
const libcVersion = semverCoerce(libcVersionRaw).version;
|
|
147
|
-
if (libcFamily === detectLibc.GLIBC && minimumGlibcVersionByArch[arch]) {
|
|
148
|
-
if (semverLessThan(libcVersion, semverCoerce(minimumGlibcVersionByArch[arch]).version)) {
|
|
149
|
-
handleError(new Error(`Use with glibc ${libcVersionRaw} requires manual installation of libvips >= ${minimumLibvipsVersion}`));
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
if (libcFamily === detectLibc.MUSL) {
|
|
153
|
-
if (semverLessThan(libcVersion, '1.1.24')) {
|
|
154
|
-
handleError(new Error(`Use with musl ${libcVersionRaw} requires manual installation of libvips >= ${minimumLibvipsVersion}`));
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
// Node.js minimum version check
|
|
159
|
-
const supportedNodeVersion = process.env.npm_package_engines_node || require('../package.json').engines.node;
|
|
160
|
-
if (!semverSatisfies(process.versions.node, supportedNodeVersion)) {
|
|
161
|
-
handleError(new Error(`Expected Node.js version ${supportedNodeVersion} but found ${process.versions.node}`));
|
|
162
|
-
}
|
|
163
|
-
// Download to per-process temporary file
|
|
164
|
-
const tarFilename = ['libvips', minimumLibvipsVersionLabelled, platformAndArch].join('-') + '.tar.br';
|
|
165
|
-
const tarPathCache = path.join(libvips.cachePath(), tarFilename);
|
|
166
|
-
if (fs.existsSync(tarPathCache)) {
|
|
167
|
-
libvips.log(`Using cached ${tarPathCache}`);
|
|
168
|
-
extractTarball(tarPathCache, platformAndArch);
|
|
169
|
-
} else if (localLibvipsDir) {
|
|
170
|
-
// If localLibvipsDir is given try to use binaries from local directory
|
|
171
|
-
const tarPathLocal = path.join(path.resolve(localLibvipsDir), `v${minimumLibvipsVersionLabelled}`, tarFilename);
|
|
172
|
-
libvips.log(`Using local libvips from ${tarPathLocal}`);
|
|
173
|
-
extractTarball(tarPathLocal, platformAndArch);
|
|
174
|
-
} else {
|
|
175
|
-
const url = distBaseUrl + tarFilename;
|
|
176
|
-
libvips.log(`Downloading ${url}`);
|
|
177
|
-
simpleGet({ url: url, agent: agent(libvips.log) }, function (err, response) {
|
|
178
|
-
if (err) {
|
|
179
|
-
fail(err);
|
|
180
|
-
} else if (response.statusCode === 404) {
|
|
181
|
-
fail(new Error(`Prebuilt libvips ${minimumLibvipsVersion} binaries are not yet available for ${platformAndArch}`));
|
|
182
|
-
} else if (response.statusCode !== 200) {
|
|
183
|
-
fail(new Error(`Status ${response.statusCode} ${response.statusMessage}`));
|
|
184
|
-
} else {
|
|
185
|
-
const tarPathTemp = path.join(os.tmpdir(), `${process.pid}-${tarFilename}`);
|
|
186
|
-
const tmpFileStream = fs.createWriteStream(tarPathTemp);
|
|
187
|
-
response
|
|
188
|
-
.on('error', function (err) {
|
|
189
|
-
tmpFileStream.destroy(err);
|
|
190
|
-
})
|
|
191
|
-
.on('close', function () {
|
|
192
|
-
if (!response.complete) {
|
|
193
|
-
tmpFileStream.destroy(new Error('Download incomplete (connection was terminated)'));
|
|
194
|
-
}
|
|
195
|
-
})
|
|
196
|
-
.pipe(tmpFileStream);
|
|
197
|
-
tmpFileStream
|
|
198
|
-
.on('error', function (err) {
|
|
199
|
-
// Clean up temporary file
|
|
200
|
-
try {
|
|
201
|
-
fs.unlinkSync(tarPathTemp);
|
|
202
|
-
} catch (e) {}
|
|
203
|
-
fail(err);
|
|
204
|
-
})
|
|
205
|
-
.on('close', function () {
|
|
206
|
-
try {
|
|
207
|
-
// Attempt to rename
|
|
208
|
-
fs.renameSync(tarPathTemp, tarPathCache);
|
|
209
|
-
} catch (err) {
|
|
210
|
-
// Fall back to copy and unlink
|
|
211
|
-
fs.copyFileSync(tarPathTemp, tarPathCache);
|
|
212
|
-
fs.unlinkSync(tarPathTemp);
|
|
213
|
-
}
|
|
214
|
-
extractTarball(tarPathCache, platformAndArch);
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
} catch (err) {
|
|
221
|
-
fail(err);
|
|
222
|
-
}
|
package/lib/agent.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// Copyright 2013 Lovell Fuller and others.
|
|
2
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
|
|
4
|
-
'use strict';
|
|
5
|
-
|
|
6
|
-
const url = require('url');
|
|
7
|
-
const tunnelAgent = require('tunnel-agent');
|
|
8
|
-
|
|
9
|
-
const is = require('./is');
|
|
10
|
-
|
|
11
|
-
const proxies = [
|
|
12
|
-
'HTTPS_PROXY',
|
|
13
|
-
'https_proxy',
|
|
14
|
-
'HTTP_PROXY',
|
|
15
|
-
'http_proxy',
|
|
16
|
-
'npm_config_https_proxy',
|
|
17
|
-
'npm_config_proxy'
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
function env (key) {
|
|
21
|
-
return process.env[key];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
module.exports = function (log) {
|
|
25
|
-
try {
|
|
26
|
-
const proxy = new url.URL(proxies.map(env).find(is.string));
|
|
27
|
-
const tunnel = proxy.protocol === 'https:'
|
|
28
|
-
? tunnelAgent.httpsOverHttps
|
|
29
|
-
: tunnelAgent.httpsOverHttp;
|
|
30
|
-
const proxyAuth = proxy.username && proxy.password
|
|
31
|
-
? `${decodeURIComponent(proxy.username)}:${decodeURIComponent(proxy.password)}`
|
|
32
|
-
: null;
|
|
33
|
-
log(`Via proxy ${proxy.protocol}//${proxy.hostname}:${proxy.port} ${proxyAuth ? 'with' : 'no'} credentials`);
|
|
34
|
-
return tunnel({
|
|
35
|
-
proxy: {
|
|
36
|
-
port: Number(proxy.port),
|
|
37
|
-
host: proxy.hostname,
|
|
38
|
-
proxyAuth
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
} catch (err) {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
};
|
package/lib/platform.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
// Copyright 2013 Lovell Fuller and others.
|
|
2
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
|
|
4
|
-
'use strict';
|
|
5
|
-
|
|
6
|
-
const detectLibc = require('detect-libc');
|
|
7
|
-
|
|
8
|
-
const env = process.env;
|
|
9
|
-
|
|
10
|
-
module.exports = function () {
|
|
11
|
-
const arch = env.npm_config_arch || process.arch;
|
|
12
|
-
const platform = env.npm_config_platform || process.platform;
|
|
13
|
-
const libc = process.env.npm_config_libc ||
|
|
14
|
-
/* istanbul ignore next */
|
|
15
|
-
(detectLibc.isNonGlibcLinuxSync() ? detectLibc.familySync() : '');
|
|
16
|
-
const libcId = platform !== 'linux' || libc === detectLibc.GLIBC ? '' : libc;
|
|
17
|
-
|
|
18
|
-
const platformId = [`${platform}${libcId}`];
|
|
19
|
-
|
|
20
|
-
if (arch === 'arm') {
|
|
21
|
-
const fallback = process.versions.electron ? '7' : '6';
|
|
22
|
-
platformId.push(`armv${env.npm_config_arm_version || process.config.variables.arm_version || fallback}`);
|
|
23
|
-
} else if (arch === 'arm64') {
|
|
24
|
-
platformId.push(`arm64v${env.npm_config_arm_version || '8'}`);
|
|
25
|
-
} else {
|
|
26
|
-
platformId.push(arch);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return platformId.join('-');
|
|
30
|
-
};
|