libavif-with-gainmap 0.1.0

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.
@@ -0,0 +1,343 @@
1
+ // Small package-specific helper built next to libavif.
2
+ // It decodes an AVIF gain map image, scales the base image and gain map image
3
+ // with libavif's scaler, then writes a new AVIF with caller-controlled quality.
4
+
5
+ #include "avif/avif.h"
6
+
7
+ #include <errno.h>
8
+ #include <stdint.h>
9
+ #include <stdio.h>
10
+ #include <stdlib.h>
11
+ #include <string.h>
12
+
13
+ typedef struct ResizeOptions {
14
+ const char * input;
15
+ const char * output;
16
+ uint32_t width;
17
+ uint32_t height;
18
+ uint32_t maxWidth;
19
+ uint32_t maxHeight;
20
+ int quality;
21
+ int qualityAlpha;
22
+ int qualityGainMap;
23
+ int speed;
24
+ int jobs;
25
+ } ResizeOptions;
26
+
27
+ static void printUsage(void)
28
+ {
29
+ fprintf(stderr,
30
+ "Usage: avifgainmapresize <input.avif> <output.avif> [options]\n"
31
+ "\n"
32
+ "Options:\n"
33
+ " --width N Exact output width. Keeps aspect if --height is omitted.\n"
34
+ " --height N Exact output height. Keeps aspect if --width is omitted.\n"
35
+ " --max-width N Downscale to fit this width.\n"
36
+ " --max-height N Downscale to fit this height.\n"
37
+ " --qcolor N Color quality, 0-100. Default: 80.\n"
38
+ " --qalpha N Alpha quality, 0-100. Default: same as --qcolor.\n"
39
+ " --qgain-map N Gain map quality, 0-100. Default: 60.\n"
40
+ " --speed N Encoder speed, 0-10. Default: 6.\n"
41
+ " --jobs N Worker threads.\n"
42
+ " --help Show this help.\n");
43
+ }
44
+
45
+ static avifBool parseUnsigned(const char * value, const char * name, uint32_t min, uint32_t max, uint32_t * out)
46
+ {
47
+ char * end = NULL;
48
+ errno = 0;
49
+ const unsigned long parsed = strtoul(value, &end, 10);
50
+ if (errno != 0 || end == value || *end != '\0' || parsed < min || parsed > max) {
51
+ fprintf(stderr, "%s must be between %u and %u.\n", name, min, max);
52
+ return AVIF_FALSE;
53
+ }
54
+ *out = (uint32_t)parsed;
55
+ return AVIF_TRUE;
56
+ }
57
+
58
+ static avifBool parseInt(const char * value, const char * name, int min, int max, int * out)
59
+ {
60
+ char * end = NULL;
61
+ errno = 0;
62
+ const long parsed = strtol(value, &end, 10);
63
+ if (errno != 0 || end == value || *end != '\0' || parsed < min || parsed > max) {
64
+ fprintf(stderr, "%s must be between %d and %d.\n", name, min, max);
65
+ return AVIF_FALSE;
66
+ }
67
+ *out = (int)parsed;
68
+ return AVIF_TRUE;
69
+ }
70
+
71
+ static avifBool readOptionValue(int argc, char ** argv, int * index, const char ** value)
72
+ {
73
+ if (*index + 1 >= argc) {
74
+ fprintf(stderr, "%s requires a value.\n", argv[*index]);
75
+ return AVIF_FALSE;
76
+ }
77
+ *index += 1;
78
+ *value = argv[*index];
79
+ return AVIF_TRUE;
80
+ }
81
+
82
+ static avifBool parseArgs(int argc, char ** argv, ResizeOptions * options)
83
+ {
84
+ options->quality = 80;
85
+ options->qualityAlpha = -1;
86
+ options->qualityGainMap = 60;
87
+ options->speed = 6;
88
+
89
+ if (argc == 2 && strcmp(argv[1], "--help") == 0) {
90
+ printUsage();
91
+ exit(0);
92
+ }
93
+ if (argc < 3) {
94
+ printUsage();
95
+ return AVIF_FALSE;
96
+ }
97
+
98
+ options->input = argv[1];
99
+ options->output = argv[2];
100
+
101
+ for (int i = 3; i < argc; ++i) {
102
+ const char * value = NULL;
103
+ if (strcmp(argv[i], "--help") == 0) {
104
+ printUsage();
105
+ exit(0);
106
+ } else if (strcmp(argv[i], "--width") == 0) {
107
+ if (!readOptionValue(argc, argv, &i, &value) ||
108
+ !parseUnsigned(value, "--width", 1, AVIF_DEFAULT_IMAGE_DIMENSION_LIMIT, &options->width)) {
109
+ return AVIF_FALSE;
110
+ }
111
+ } else if (strcmp(argv[i], "--height") == 0) {
112
+ if (!readOptionValue(argc, argv, &i, &value) ||
113
+ !parseUnsigned(value, "--height", 1, AVIF_DEFAULT_IMAGE_DIMENSION_LIMIT, &options->height)) {
114
+ return AVIF_FALSE;
115
+ }
116
+ } else if (strcmp(argv[i], "--max-width") == 0) {
117
+ if (!readOptionValue(argc, argv, &i, &value) ||
118
+ !parseUnsigned(value, "--max-width", 1, AVIF_DEFAULT_IMAGE_DIMENSION_LIMIT, &options->maxWidth)) {
119
+ return AVIF_FALSE;
120
+ }
121
+ } else if (strcmp(argv[i], "--max-height") == 0) {
122
+ if (!readOptionValue(argc, argv, &i, &value) ||
123
+ !parseUnsigned(value, "--max-height", 1, AVIF_DEFAULT_IMAGE_DIMENSION_LIMIT, &options->maxHeight)) {
124
+ return AVIF_FALSE;
125
+ }
126
+ } else if (strcmp(argv[i], "--qcolor") == 0) {
127
+ if (!readOptionValue(argc, argv, &i, &value) ||
128
+ !parseInt(value, "--qcolor", AVIF_QUALITY_WORST, AVIF_QUALITY_BEST, &options->quality)) {
129
+ return AVIF_FALSE;
130
+ }
131
+ } else if (strcmp(argv[i], "--qalpha") == 0) {
132
+ if (!readOptionValue(argc, argv, &i, &value) ||
133
+ !parseInt(value, "--qalpha", AVIF_QUALITY_WORST, AVIF_QUALITY_BEST, &options->qualityAlpha)) {
134
+ return AVIF_FALSE;
135
+ }
136
+ } else if (strcmp(argv[i], "--qgain-map") == 0) {
137
+ if (!readOptionValue(argc, argv, &i, &value) ||
138
+ !parseInt(value, "--qgain-map", AVIF_QUALITY_WORST, AVIF_QUALITY_BEST, &options->qualityGainMap)) {
139
+ return AVIF_FALSE;
140
+ }
141
+ } else if (strcmp(argv[i], "--speed") == 0) {
142
+ if (!readOptionValue(argc, argv, &i, &value) ||
143
+ !parseInt(value, "--speed", AVIF_SPEED_SLOWEST, AVIF_SPEED_FASTEST, &options->speed)) {
144
+ return AVIF_FALSE;
145
+ }
146
+ } else if (strcmp(argv[i], "--jobs") == 0) {
147
+ if (!readOptionValue(argc, argv, &i, &value) || !parseInt(value, "--jobs", 1, 1024, &options->jobs)) {
148
+ return AVIF_FALSE;
149
+ }
150
+ } else {
151
+ fprintf(stderr, "Unknown option %s.\n", argv[i]);
152
+ return AVIF_FALSE;
153
+ }
154
+ }
155
+
156
+ if ((options->width || options->height) && (options->maxWidth || options->maxHeight)) {
157
+ fprintf(stderr, "Use --width/--height or --max-width/--max-height, not both.\n");
158
+ return AVIF_FALSE;
159
+ }
160
+ if (options->qualityAlpha < 0) {
161
+ options->qualityAlpha = options->quality;
162
+ }
163
+ return AVIF_TRUE;
164
+ }
165
+
166
+ static uint32_t scaleDimension(uint32_t value, uint32_t numerator, uint32_t denominator)
167
+ {
168
+ if (denominator == 0) {
169
+ return 1;
170
+ }
171
+ uint64_t scaled = ((uint64_t)value * numerator) + (denominator / 2);
172
+ scaled /= denominator;
173
+ if (scaled < 1) {
174
+ return 1;
175
+ }
176
+ if (scaled > AVIF_DEFAULT_IMAGE_DIMENSION_LIMIT) {
177
+ return AVIF_DEFAULT_IMAGE_DIMENSION_LIMIT;
178
+ }
179
+ return (uint32_t)scaled;
180
+ }
181
+
182
+ static avifBool computeTargetSize(const ResizeOptions * options,
183
+ uint32_t sourceWidth,
184
+ uint32_t sourceHeight,
185
+ uint32_t * targetWidth,
186
+ uint32_t * targetHeight)
187
+ {
188
+ *targetWidth = sourceWidth;
189
+ *targetHeight = sourceHeight;
190
+
191
+ if (options->width && options->height) {
192
+ *targetWidth = options->width;
193
+ *targetHeight = options->height;
194
+ } else if (options->width) {
195
+ *targetWidth = options->width;
196
+ *targetHeight = scaleDimension(sourceHeight, options->width, sourceWidth);
197
+ } else if (options->height) {
198
+ *targetWidth = scaleDimension(sourceWidth, options->height, sourceHeight);
199
+ *targetHeight = options->height;
200
+ } else {
201
+ if (options->maxWidth && *targetWidth > options->maxWidth) {
202
+ *targetHeight = scaleDimension(*targetHeight, options->maxWidth, *targetWidth);
203
+ *targetWidth = options->maxWidth;
204
+ }
205
+ if (options->maxHeight && *targetHeight > options->maxHeight) {
206
+ *targetWidth = scaleDimension(*targetWidth, options->maxHeight, *targetHeight);
207
+ *targetHeight = options->maxHeight;
208
+ }
209
+ }
210
+
211
+ const uint64_t pixels = (uint64_t)(*targetWidth) * (*targetHeight);
212
+ if (*targetWidth == 0 || *targetHeight == 0 || pixels > AVIF_DEFAULT_IMAGE_SIZE_LIMIT) {
213
+ fprintf(stderr, "Target size %u x %u exceeds libavif's default image limits.\n", *targetWidth, *targetHeight);
214
+ return AVIF_FALSE;
215
+ }
216
+ return AVIF_TRUE;
217
+ }
218
+
219
+ static avifResult scaleImage(avifImage * image, uint32_t width, uint32_t height, const char * label)
220
+ {
221
+ if (image->width == width && image->height == height) {
222
+ return AVIF_RESULT_OK;
223
+ }
224
+ avifDiagnostics diag;
225
+ memset(&diag, 0, sizeof(diag));
226
+ const avifResult result = avifImageScale(image, width, height, &diag);
227
+ if (result != AVIF_RESULT_OK) {
228
+ fprintf(stderr, "Failed to scale %s to %u x %u: %s (%s)\n", label, width, height, avifResultToString(result), diag.error);
229
+ }
230
+ return result;
231
+ }
232
+
233
+ static avifBool writeFile(const char * path, const avifRWData * data)
234
+ {
235
+ FILE * file = fopen(path, "wb");
236
+ if (!file) {
237
+ fprintf(stderr, "Failed to open %s for writing.\n", path);
238
+ return AVIF_FALSE;
239
+ }
240
+ const size_t written = fwrite(data->data, 1, data->size, file);
241
+ const int closeResult = fclose(file);
242
+ if (written != data->size || closeResult != 0) {
243
+ fprintf(stderr, "Failed to write %s.\n", path);
244
+ return AVIF_FALSE;
245
+ }
246
+ return AVIF_TRUE;
247
+ }
248
+
249
+ int main(int argc, char ** argv)
250
+ {
251
+ ResizeOptions options;
252
+ memset(&options, 0, sizeof(options));
253
+ if (!parseArgs(argc, argv, &options)) {
254
+ return 1;
255
+ }
256
+
257
+ avifImage * image = avifImageCreateEmpty();
258
+ avifDecoder * decoder = avifDecoderCreate();
259
+ avifEncoder * encoder = NULL;
260
+ avifRWData encoded = AVIF_DATA_EMPTY;
261
+ int exitCode = 1;
262
+
263
+ if (!image || !decoder) {
264
+ fprintf(stderr, "Out of memory.\n");
265
+ goto cleanup;
266
+ }
267
+
268
+ decoder->imageContentToDecode = AVIF_IMAGE_CONTENT_ALL;
269
+ if (options.jobs > 0) {
270
+ decoder->maxThreads = options.jobs;
271
+ }
272
+
273
+ avifResult result = avifDecoderReadFile(decoder, image, options.input);
274
+ if (result != AVIF_RESULT_OK) {
275
+ fprintf(stderr, "Failed to decode %s: %s (%s)\n", options.input, avifResultToString(result), decoder->diag.error);
276
+ goto cleanup;
277
+ }
278
+ if (!image->gainMap || !image->gainMap->image) {
279
+ fprintf(stderr, "Input AVIF does not contain a decoded gain map.\n");
280
+ goto cleanup;
281
+ }
282
+
283
+ const uint32_t sourceWidth = image->width;
284
+ const uint32_t sourceHeight = image->height;
285
+ const uint32_t sourceGainMapWidth = image->gainMap->image->width;
286
+ const uint32_t sourceGainMapHeight = image->gainMap->image->height;
287
+ uint32_t targetWidth = 0;
288
+ uint32_t targetHeight = 0;
289
+
290
+ if (!computeTargetSize(&options, sourceWidth, sourceHeight, &targetWidth, &targetHeight)) {
291
+ goto cleanup;
292
+ }
293
+
294
+ result = scaleImage(image, targetWidth, targetHeight, "base image");
295
+ if (result != AVIF_RESULT_OK) {
296
+ goto cleanup;
297
+ }
298
+
299
+ const uint32_t targetGainMapWidth = scaleDimension(sourceGainMapWidth, targetWidth, sourceWidth);
300
+ const uint32_t targetGainMapHeight = scaleDimension(sourceGainMapHeight, targetHeight, sourceHeight);
301
+ result = scaleImage(image->gainMap->image, targetGainMapWidth, targetGainMapHeight, "gain map image");
302
+ if (result != AVIF_RESULT_OK) {
303
+ goto cleanup;
304
+ }
305
+
306
+ encoder = avifEncoderCreate();
307
+ if (!encoder) {
308
+ fprintf(stderr, "Out of memory.\n");
309
+ goto cleanup;
310
+ }
311
+ encoder->quality = options.quality;
312
+ encoder->qualityAlpha = options.qualityAlpha;
313
+ encoder->qualityGainMap = options.qualityGainMap;
314
+ encoder->speed = options.speed;
315
+ encoder->autoTiling = AVIF_TRUE;
316
+ if (options.jobs > 0) {
317
+ encoder->maxThreads = options.jobs;
318
+ }
319
+
320
+ result = avifEncoderWrite(encoder, image, &encoded);
321
+ if (result != AVIF_RESULT_OK) {
322
+ fprintf(stderr, "Failed to encode %s: %s (%s)\n", options.output, avifResultToString(result), encoder->diag.error);
323
+ goto cleanup;
324
+ }
325
+ if (!writeFile(options.output, &encoded)) {
326
+ goto cleanup;
327
+ }
328
+
329
+ exitCode = 0;
330
+
331
+ cleanup:
332
+ avifRWDataFree(&encoded);
333
+ if (encoder) {
334
+ avifEncoderDestroy(encoder);
335
+ }
336
+ if (decoder) {
337
+ avifDecoderDestroy(decoder);
338
+ }
339
+ if (image) {
340
+ avifImageDestroy(image);
341
+ }
342
+ return exitCode;
343
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "libavif-with-gainmap",
3
+ "version": "0.1.0",
4
+ "description": "Convert JPEG gain map images to AVIF gain map images using libavif.",
5
+ "license": "MIT",
6
+ "type": "commonjs",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/eeg1412/libavif-with-gainmap.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/eeg1412/libavif-with-gainmap/issues"
13
+ },
14
+ "homepage": "https://github.com/eeg1412/libavif-with-gainmap#readme",
15
+ "main": "src/index.js",
16
+ "bin": {
17
+ "avif-gainmap": "bin/avif-gainmap.js"
18
+ },
19
+ "files": [
20
+ "bin",
21
+ "docs",
22
+ "native",
23
+ "scripts",
24
+ "src",
25
+ "vendor",
26
+ "README.md",
27
+ "LICENSE"
28
+ ],
29
+ "engines": {
30
+ "node": ">=18"
31
+ },
32
+ "scripts": {
33
+ "test": "node --test",
34
+ "build:libavif": "node scripts/build-libavif.js",
35
+ "check-prebuilt": "node scripts/check-prebuilt.js --current",
36
+ "check-prebuilt:all": "node scripts/check-prebuilt.js --all"
37
+ },
38
+ "keywords": [
39
+ "avif",
40
+ "gainmap",
41
+ "hdr",
42
+ "ultrahdr",
43
+ "libavif",
44
+ "jpeg"
45
+ ]
46
+ }
@@ -0,0 +1,177 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const { spawnSync } = require('node:child_process');
6
+
7
+ const {
8
+ TOOL_GAINMAP_RESIZE,
9
+ TOOL_GAINMAP_UTIL,
10
+ executableName,
11
+ getPlatformKey,
12
+ packageRoot
13
+ } = require('../src/platform');
14
+
15
+ const LIBAVIF_VERSION = process.env.LIBAVIF_VERSION || 'v1.4.2';
16
+ const root = packageRoot();
17
+ const cacheDir = path.join(root, '.cache');
18
+ const sourceDir = process.env.LIBAVIF_SOURCE_DIR || path.join(cacheDir, `libavif-${LIBAVIF_VERSION}`);
19
+ const buildDir = process.env.LIBAVIF_BUILD_DIR || path.join(cacheDir, `build-${LIBAVIF_VERSION}`);
20
+ const installDir = process.env.LIBAVIF_INSTALL_DIR || path.join(cacheDir, `install-${LIBAVIF_VERSION}`);
21
+ const platformKey = process.env.TARGET_PLATFORM_KEY || getPlatformKey();
22
+ const vendorDir = path.join(root, 'vendor', platformKey);
23
+
24
+ function run(command, args, options = {}) {
25
+ const result = spawnSync(command, args, {
26
+ cwd: options.cwd || root,
27
+ env: { ...process.env, ...options.env },
28
+ shell: false,
29
+ stdio: 'inherit'
30
+ });
31
+ if (result.status !== 0) {
32
+ throw new Error(`${command} ${args.join(' ')} failed with exit code ${result.status}.`);
33
+ }
34
+ }
35
+
36
+ function splitExtraArgs(value) {
37
+ if (!value) {
38
+ return [];
39
+ }
40
+ return value.split(/\s+/).filter(Boolean);
41
+ }
42
+
43
+ function ensureSource() {
44
+ fs.mkdirSync(cacheDir, { recursive: true });
45
+ if (fs.existsSync(path.join(sourceDir, 'CMakeLists.txt'))) {
46
+ return;
47
+ }
48
+ run('git', [
49
+ 'clone',
50
+ '--depth',
51
+ '1',
52
+ '--branch',
53
+ LIBAVIF_VERSION,
54
+ 'https://github.com/AOMediaCodec/libavif.git',
55
+ sourceDir
56
+ ]);
57
+ }
58
+
59
+ function installResizeToolSource() {
60
+ fs.copyFileSync(
61
+ path.join(root, 'native', 'avifgainmapresize.c'),
62
+ path.join(sourceDir, 'apps', 'avifgainmapresize.c')
63
+ );
64
+ }
65
+
66
+ function patchCMake() {
67
+ const cmakePath = path.join(sourceDir, 'CMakeLists.txt');
68
+ let content = fs.readFileSync(cmakePath, 'utf8');
69
+ if (!content.includes('avifgainmapresize')) {
70
+ const linkNeedle = 'target_link_libraries(avifgainmaputil libargparse avif_apps avif avif_enable_warnings)';
71
+ if (!content.includes(linkNeedle)) {
72
+ throw new Error('Unable to patch libavif CMakeLists.txt: avifgainmaputil target not found.');
73
+ }
74
+ content = content.replace(
75
+ linkNeedle,
76
+ `${linkNeedle}
77
+
78
+ add_executable(avifgainmapresize apps/avifgainmapresize.c)
79
+ if(AVIF_LIB_USE_CXX)
80
+ set_target_properties(avifgainmapresize PROPERTIES LINKER_LANGUAGE "CXX")
81
+ endif()
82
+ target_link_libraries(avifgainmapresize avif avif_enable_warnings)`
83
+ );
84
+
85
+ }
86
+
87
+ content = content.replace(
88
+ /TARGETS\s+avifenc\s+avifdec\s+avifgainmaputil(?!\s+avifgainmapresize)/,
89
+ 'TARGETS avifenc avifdec avifgainmaputil avifgainmapresize'
90
+ );
91
+ fs.writeFileSync(cmakePath, content);
92
+ }
93
+
94
+ function configureAndBuild() {
95
+ const generator = process.env.CMAKE_GENERATOR || 'Ninja';
96
+ const cmakeArgs = [
97
+ '-S',
98
+ sourceDir,
99
+ '-B',
100
+ buildDir,
101
+ '-G',
102
+ generator,
103
+ '-DCMAKE_BUILD_TYPE=Release',
104
+ '-DBUILD_SHARED_LIBS=OFF',
105
+ '-DAVIF_BUILD_APPS=ON',
106
+ '-DAVIF_BUILD_TESTS=OFF',
107
+ '-DAVIF_CODEC_AOM=LOCAL',
108
+ '-DAVIF_JPEG=LOCAL',
109
+ '-DAVIF_LIBSHARPYUV=LOCAL',
110
+ '-DAVIF_LIBXML2=LOCAL',
111
+ '-DAVIF_LIBYUV=LOCAL',
112
+ '-DAVIF_ZLIBPNG=LOCAL',
113
+ '-DAVIF_ENABLE_WERROR=OFF',
114
+ `-DCMAKE_INSTALL_PREFIX=${installDir}`,
115
+ ...splitExtraArgs(process.env.LIBAVIF_CMAKE_ARGS)
116
+ ];
117
+
118
+ if (process.platform === 'win32') {
119
+ cmakeArgs.push('-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded');
120
+ }
121
+
122
+ run('cmake', cmakeArgs);
123
+ run('cmake', ['--build', buildDir, '--config', 'Release', '--parallel']);
124
+ run('cmake', ['--install', buildDir, '--config', 'Release']);
125
+ }
126
+
127
+ function findBuiltBinary(fileName) {
128
+ const candidates = [
129
+ path.join(installDir, 'bin', fileName),
130
+ path.join(buildDir, fileName),
131
+ path.join(buildDir, 'Release', fileName)
132
+ ];
133
+ for (const candidate of candidates) {
134
+ if (fs.existsSync(candidate)) {
135
+ return candidate;
136
+ }
137
+ }
138
+
139
+ const stack = [buildDir];
140
+ while (stack.length > 0) {
141
+ const dir = stack.pop();
142
+ if (!fs.existsSync(dir)) {
143
+ continue;
144
+ }
145
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
146
+ const fullPath = path.join(dir, entry.name);
147
+ if (entry.isDirectory()) {
148
+ stack.push(fullPath);
149
+ } else if (entry.isFile() && entry.name === fileName) {
150
+ return fullPath;
151
+ }
152
+ }
153
+ }
154
+ return null;
155
+ }
156
+
157
+ function copyBinaries() {
158
+ fs.mkdirSync(vendorDir, { recursive: true });
159
+ for (const tool of [TOOL_GAINMAP_UTIL, TOOL_GAINMAP_RESIZE]) {
160
+ const name = executableName(tool, platformKey);
161
+ const from = findBuiltBinary(name);
162
+ const to = path.join(vendorDir, name);
163
+ if (!from) {
164
+ throw new Error(`Expected built binary was not found: ${name}`);
165
+ }
166
+ fs.copyFileSync(from, to);
167
+ if (!platformKey.startsWith('win32-')) {
168
+ fs.chmodSync(to, 0o755);
169
+ }
170
+ }
171
+ }
172
+
173
+ ensureSource();
174
+ installResizeToolSource();
175
+ patchCMake();
176
+ configureAndBuild();
177
+ copyBinaries();
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const {
6
+ SUPPORTED_PLATFORM_KEYS,
7
+ TOOL_NAMES,
8
+ executableName,
9
+ getPlatformKey,
10
+ packageRoot
11
+ } = require('../src/platform');
12
+
13
+ const mode = process.argv.includes('--all') ? 'all' : 'current';
14
+ const keys = mode === 'all' ? SUPPORTED_PLATFORM_KEYS : [process.env.TARGET_PLATFORM_KEY || getPlatformKey()];
15
+ const missing = [];
16
+
17
+ for (const key of keys) {
18
+ for (const tool of TOOL_NAMES) {
19
+ const file = path.join(packageRoot(), 'vendor', key, executableName(tool, key));
20
+ if (!fs.existsSync(file)) {
21
+ missing.push(file);
22
+ }
23
+ }
24
+ }
25
+
26
+ if (missing.length > 0) {
27
+ process.stderr.write(`Missing native binaries:\n${missing.map((file) => ` - ${file}`).join('\n')}\n`);
28
+ process.exitCode = 1;
29
+ } else {
30
+ process.stdout.write(`Prebuilt binary check passed for ${keys.join(', ')}.\n`);
31
+ }