Skip to content

Commit 47566d8

Browse files
committed
Actually convert
1 parent c9f61c2 commit 47566d8

File tree

8 files changed

+222
-108
lines changed

8 files changed

+222
-108
lines changed

custom.d.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
declare module 'libheif-js/wasm-bundle.js' {
2+
export class HeifDecoder {
3+
decode(buffer: ArrayBuffer | Uint8Array): HeifImage[];
4+
decoder: { delete(): void };
5+
}
6+
7+
export interface HeifImage {
8+
get_width(): number;
9+
get_height(): number;
10+
display(
11+
options: { data: Uint8ClampedArray; width: number; height: number },
12+
callback: (result: { data: Uint8ClampedArray } | null) => void
13+
): void;
14+
free(): void;
15+
}
16+
17+
export const ready: Promise<void>;
18+
19+
export const libheif = {
20+
HeifDecoder: HeifDecoder,
21+
HeifImage: HeifImage,
22+
ready: Promise<void>,
23+
};
24+
25+
export default libheif;
26+
}

package.json

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
"version": "2.1.0",
44
"description": "Decode HEIC images to raw data",
55
"main": "dist/index.js",
6+
"type": "module",
67
"scripts": {
78
"build": "tsc --project tsconfig.build.json",
89
"clean": "node -e \"fs.rmSync('./dist', { recursive: true, force: true })\"",
910
"prepack": "npm run clean && npm run build",
10-
"pretest": "node scripts/images.js",
11-
"test": "mocha \"test/**/*.js\" --timeout 20000 --slow 0"
11+
"pretest": "npm run build && node ./scripts/images.ts",
12+
"test": "node --test \"test/**/*.ts\""
1213
},
1314
"repository": {
1415
"type": "git",
@@ -31,14 +32,11 @@
3132
"libheif-js": "^1.19.8"
3233
},
3334
"devDependencies": {
34-
"@types/mocha": "^10.0.10",
35-
"@types/node": "^8.0.0",
35+
"@types/node": "^22.0.0",
3636
"buffer-to-uint8array": "^1.1.0",
37-
"chai": "^4.2.0",
3837
"eslint": "^5.16.0",
3938
"fs-extra": "^8.1.0",
40-
"jimp": "^0.9.3",
41-
"mocha": "^7.0.0",
39+
"jimp": "^1.6.0",
4240
"node-fetch": "^2.6.0",
4341
"pixelmatch": "^5.2.1",
4442
"pngjs": "^5.0.0",

scripts/harness.ts

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,50 @@
11
/* eslint-disable no-console */
2-
const { promisify } = require('util');
3-
const fs = require('fs');
4-
const Jimp = require('jimp');
5-
const decode = require('../');
2+
import { promisify } from 'util';
3+
import fs from 'fs';
4+
import Jimp from 'jimp';
5+
import decode from '../src/index.ts';
66

7-
const readStdin = () => new Promise(resolve => {
8-
const result = [];
7+
const readStdin = () =>
8+
new Promise((resolve) => {
9+
const result: Buffer[] = [];
910

10-
process.stdin.on('readable', () => {
11-
let chunk;
11+
process.stdin.on('readable', () => {
12+
let chunk: string | Buffer;
1213

13-
while ((chunk = process.stdin.read())) {
14-
result.push(chunk);
15-
}
16-
});
14+
while ((chunk = process.stdin.read())) {
15+
if (Buffer.isBuffer(chunk)) {
16+
result.push(chunk);
17+
}
18+
}
19+
});
1720

18-
process.stdin.on('end', () => {
19-
resolve(Buffer.concat(result));
21+
process.stdin.on('end', () => {
22+
resolve(Buffer.concat(result));
23+
});
2024
});
21-
});
2225

23-
const createImage = promisify(({ data, width, height }, callback) => {
24-
try {
25-
new Jimp({ data: Buffer.from(data), width, height }, callback);
26-
} catch (e) {
27-
callback(e);
26+
const createImage = promisify(
27+
(
28+
{ data, width, height }: { data: ArrayBuffer; width: number; height: number },
29+
callback: (err: unknown, image?: any) => void
30+
) => {
31+
try {
32+
new Jimp({ data: Buffer.from(data), width, height }, callback);
33+
} catch (e) {
34+
callback(e);
35+
}
2836
}
29-
});
37+
);
3038

31-
const toJpeg = async ({ data, width, height }) => {
39+
const toJpeg = async ({
40+
data,
41+
width,
42+
height,
43+
}: {
44+
data: ArrayBuffer;
45+
width: number;
46+
height: number;
47+
}) => {
3248
const image = await createImage({ data, width, height });
3349
return image.quality(100).getBufferAsync(Jimp.MIME_JPEG);
3450
};
@@ -44,7 +60,7 @@ const toJpeg = async ({ data, width, height }) => {
4460
const image = images[i];
4561
fs.writeFileSync(`./result-${+i + 1}.jpg`, await toJpeg(await image.decode()));
4662
}
47-
})().catch(err => {
63+
})().catch((err) => {
4864
console.error(err);
4965
process.exitCode = 1;
5066
});

scripts/images.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
/* eslint-disable no-console */
2-
const path = require('path');
3-
const root = require('rootrequire');
4-
const fs = require('fs-extra');
5-
const fetch = require('node-fetch');
2+
3+
import fs from 'fs-extra';
4+
import fetch from 'node-fetch';
5+
import path from 'path';
6+
import root from 'rootrequire';
67

78
const resolve = (name = '') => path.resolve(root, 'temp', name);
8-
const drive = id => `http://drive.google.com/uc?export=view&id=${id}`;
9+
const drive = (id: string) => `http://drive.google.com/uc?export=view&id=${id}`;
910

1011
const images = [{
1112
name: '0001.jpg',
@@ -26,8 +27,12 @@ const images = [{
2627
name: '0003-1-control.png', // multiple images control, index 1, 2
2728
url: drive('1qD4-V6FcU2ffpNm0ZxKO2cpqbol73tok')
2829
}].map(img => {
29-
img.path = resolve(img.name);
30-
return img;
30+
const path = resolve(img.name);
31+
32+
return {
33+
...img,
34+
path,
35+
}
3136
});
3237

3338
(async () => {

src/index.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
const libheif = require('libheif-js/wasm-bundle');
1+
import libheif from 'libheif-js/wasm-bundle.js';
22

3-
const { one, all } = require('./lib.js')(libheif);
3+
import lib from './lib.ts';
44

5-
module.exports = one;
6-
module.exports.all = all;
5+
const { one, all } = lib(libheif);
6+
7+
const decode: typeof one & { all: typeof all } = one as any;
8+
decode.all = all;
9+
10+
export default decode;

src/lib.ts

Lines changed: 70 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
const uint8ArrayUtf8ByteString = (array, start, end) => {
1+
import type libheifType from 'libheif-js/wasm-bundle.js';
2+
import type { HeifImage } from 'libheif-js/wasm-bundle.js';
3+
4+
const uint8ArrayUtf8ByteString = (array: Uint8Array, start: number, end: number) => {
25
return String.fromCharCode(...array.slice(start, end));
36
};
47

58
// brands explained: https://github.com/strukturag/libheif/issues/83
69
// code adapted from: https://github.com/sindresorhus/file-type/blob/6f901bd82b849a85ca4ddba9c9a4baacece63d31/core.js#L428-L438
7-
const isHeic = (buffer) => {
10+
const isHeic = (buffer: Uint8Array) => {
811
const brandMajor = uint8ArrayUtf8ByteString(buffer, 8, 12).replace('\0', ' ').trim();
912

1013
switch (brandMajor) {
@@ -23,25 +26,59 @@ const isHeic = (buffer) => {
2326
return false;
2427
};
2528

26-
const decodeImage = async (image) => {
29+
const decodeImage = async (
30+
image: HeifImage
31+
): Promise<{ width: number; height: number; data: Uint8ClampedArray }> => {
2732
const width = image.get_width();
2833
const height = image.get_height();
2934

30-
const { data } = await new Promise((resolve, reject) => {
31-
image.display({ data: new Uint8ClampedArray(width*height*4), width, height }, (displayData) => {
32-
if (!displayData) {
33-
return reject(new Error('HEIF processing error'));
34-
}
35+
const { data } = await new Promise<{ data: Uint8ClampedArray }>((resolve, reject) => {
36+
image.display(
37+
{ data: new Uint8ClampedArray(width * height * 4), width, height },
38+
(displayData) => {
39+
if (!displayData) {
40+
return reject(new Error('HEIF processing error'));
41+
}
3542

36-
resolve(displayData);
37-
});
43+
resolve(displayData);
44+
}
45+
);
3846
});
3947

4048
return { width, height, data };
4149
};
4250

43-
module.exports = libheif => {
44-
const decodeBuffer = async ({ buffer, all }) => {
51+
type DecodeOneResult = {
52+
width: number;
53+
height: number;
54+
data: Uint8ClampedArray;
55+
};
56+
57+
type DecodeAllResult = {
58+
width: number;
59+
height: number;
60+
decode: () => Promise<DecodeOneResult>;
61+
}[];
62+
63+
export default function lib(libheif: typeof libheifType): {
64+
one: (options: { buffer: Uint8Array }) => Promise<DecodeOneResult>;
65+
all: (options: { buffer: Uint8Array }) => Promise<DecodeAllResult>;
66+
} {
67+
async function decodeBuffer({
68+
buffer,
69+
all,
70+
}: {
71+
buffer: Uint8Array;
72+
all: true;
73+
}): Promise<DecodeAllResult>;
74+
async function decodeBuffer({
75+
buffer,
76+
all,
77+
}: {
78+
buffer: Uint8Array;
79+
all: false;
80+
}): Promise<DecodeOneResult>;
81+
async function decodeBuffer({ buffer, all }: { buffer: Uint8Array; all: boolean }) {
4582
if (!isHeic(buffer)) {
4683
throw new TypeError('input buffer is not a HEIC image');
4784
}
@@ -67,28 +104,32 @@ module.exports = libheif => {
67104

68105
if (!all) {
69106
try {
70-
return await decodeImage(data[0]);
107+
return await decodeImage(data[0]!);
71108
} finally {
72109
dispose();
73110
}
74111
}
75112

76-
return Object.defineProperty(data.map(image => {
77-
return {
78-
width: image.get_width(),
79-
height: image.get_height(),
80-
decode: async () => await decodeImage(image)
81-
};
82-
}), 'dispose', {
83-
enumerable: false,
84-
configurable: false,
85-
writable: false,
86-
value: dispose
87-
});
88-
};
113+
return Object.defineProperty(
114+
data.map((image) => {
115+
return {
116+
width: image.get_width(),
117+
height: image.get_height(),
118+
decode: async () => await decodeImage(image),
119+
};
120+
}),
121+
'dispose',
122+
{
123+
enumerable: false,
124+
configurable: false,
125+
writable: false,
126+
value: dispose,
127+
}
128+
);
129+
}
89130

90131
return {
91-
one: async ({ buffer }) => await decodeBuffer({ buffer, all: false }),
92-
all: async ({ buffer }) => await decodeBuffer({ buffer, all: true })
132+
one: async ({ buffer }: { buffer: Uint8Array }) => await decodeBuffer({ buffer, all: false }),
133+
all: async ({ buffer }: { buffer: Uint8Array }) => await decodeBuffer({ buffer, all: true }),
93134
};
94-
};
135+
}

0 commit comments

Comments
 (0)