Skip to content

Commit 9aa964d

Browse files
authored
Merge pull request #20 from catdad-experiments/19-free-memory
free memory after image decode
2 parents c3b795c + f2a5466 commit 9aa964d

File tree

4 files changed

+28
-3
lines changed

4 files changed

+28
-3
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,14 @@ const decode = require('heic-decode');
5757
data // Uint8ClampedArray containing pixel data
5858
} = await image.decode();
5959
}
60+
61+
// when you are done, make sure to free all memory used to convert the images
62+
images.dispose();
6063
})();
6164
```
6265

66+
> Note: when decoding a single image (i.e. using `decode`), all resources are freed automatically after the conversion. However, when decoding all images in a file (i.e. using `decode.all`), you can decode the images at any time, so there is no safe time for the library to free resources -- you need to make sure to call `dispose` once you are done.
67+
6368
When the images are decoded, the return value is a plain object in the format of [`ImageData`](https://developer.mozilla.org/en-US/docs/Web/API/ImageData). You can use this object to integrate with other imaging libraries for processing.
6469

6570
_Note that while the decoder returns a Promise, it does the majority of the work synchronously, so you should consider using a worker thread in order to not block the main thread in highly concurrent production environments._

lib.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,37 @@ module.exports = libheif => {
5353
const decoder = new libheif.HeifDecoder();
5454
const data = decoder.decode(buffer);
5555

56+
const dispose = () => {
57+
for (const image of data) {
58+
image.free();
59+
}
60+
61+
decoder.decoder.delete();
62+
};
63+
5664
if (!data.length) {
5765
throw new Error('HEIF image not found');
5866
}
5967

6068
if (!all) {
61-
return await decodeImage(data[0]);
69+
try {
70+
return await decodeImage(data[0]);
71+
} finally {
72+
dispose();
73+
}
6274
}
6375

64-
return data.map(image => {
76+
return Object.defineProperty(data.map(image => {
6577
return {
6678
width: image.get_width(),
6779
height: image.get_height(),
6880
decode: async () => await decodeImage(image)
6981
};
82+
}), 'dispose', {
83+
enumerable: false,
84+
configurable: false,
85+
writable: false,
86+
value: dispose
7087
});
7188
};
7289

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
},
2626
"homepage": "https://github.com/catdad-experiments/heic-decode#readme",
2727
"dependencies": {
28-
"libheif-js": "^1.17.1"
28+
"libheif-js": "^1.19.8"
2929
},
3030
"devDependencies": {
3131
"buffer-to-uint8array": "^1.1.0",

test/index.test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ function runTests(decode) {
6363
const images = await decode.all({ buffer });
6464

6565
expect(images).to.have.lengthOf(3);
66+
expect(images).to.have.property('dispose').and.to.be.a('function');
6667

6768
const controls = await Promise.all([
6869
readControl('0003-0-control.png'),
@@ -86,6 +87,8 @@ function runTests(decode) {
8687

8788
compare(control.data, image.data, control.width, control.height, `actual image at index ${i} did not match control`);
8889
}
90+
91+
images.dispose();
8992
});
9093

9194
it('throws if data other than a HEIC image is passed in', async () => {

0 commit comments

Comments
 (0)