Skip to content

Commit

Permalink
Async API
Browse files Browse the repository at this point in the history
  • Loading branch information
JrMasterModelBuilder committed Sep 24, 2023
1 parent 227b0df commit 7c3f881
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 58 deletions.
40 changes: 20 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ const png = null;
const raw = false;

const ico = new IconIco();
ico.addFromPng(await readFile('icon/256x256.png'), png, raw);
ico.addFromPng(await readFile('icon/128x128.png'), png, raw);
ico.addFromPng(await readFile('icon/64x64.png'), png, raw);
ico.addFromPng(await readFile('icon/48x48.png'), png, raw);
ico.addFromPng(await readFile('icon/32x32.png'), png, raw);
ico.addFromPng(await readFile('icon/16x16.png'), png, raw);
await ico.addFromPng(await readFile('icon/256x256.png'), png, raw);
await ico.addFromPng(await readFile('icon/128x128.png'), png, raw);
await ico.addFromPng(await readFile('icon/64x64.png'), png, raw);
await ico.addFromPng(await readFile('icon/48x48.png'), png, raw);
await ico.addFromPng(await readFile('icon/32x32.png'), png, raw);
await ico.addFromPng(await readFile('icon/16x16.png'), png, raw);
await writeFile('icon.ico', ico.encode());
```

Expand All @@ -80,16 +80,16 @@ const raw = false;

// This order matches that of iconutil with the same image set in macOS 10.14.
// Images with @2x are just 2x the size their file name suggests.
icns.addFromPng(await readFile('icon/[email protected]'), ['ic12'], raw);
icns.addFromPng(await readFile('icon/128x128.png'), ['ic07'], raw);
icns.addFromPng(await readFile('icon/[email protected]'), ['ic13'], raw);
icns.addFromPng(await readFile('icon/256x256.png'), ['ic08'], raw);
icns.addFromPng(await readFile('icon/16x16.png'), ['ic04'], raw);
icns.addFromPng(await readFile('icon/[email protected]'), ['ic14'], raw);
icns.addFromPng(await readFile('icon/512x512.png'), ['ic09'], raw);
icns.addFromPng(await readFile('icon/32x32.png'), ['ic05'], raw);
icns.addFromPng(await readFile('icon/[email protected]'), ['ic10'], raw);
icns.addFromPng(await readFile('icon/[email protected]'), ['ic11'], raw);
await icns.addFromPng(await readFile('icon/[email protected]'), ['ic12'], raw);
await icns.addFromPng(await readFile('icon/128x128.png'), ['ic07'], raw);
await icns.addFromPng(await readFile('icon/[email protected]'), ['ic13'], raw);
await icns.addFromPng(await readFile('icon/256x256.png'), ['ic08'], raw);
await icns.addFromPng(await readFile('icon/16x16.png'), ['ic04'], raw);
await icns.addFromPng(await readFile('icon/[email protected]'), ['ic14'], raw);
await icns.addFromPng(await readFile('icon/512x512.png'), ['ic09'], raw);
await icns.addFromPng(await readFile('icon/32x32.png'), ['ic05'], raw);
await icns.addFromPng(await readFile('icon/[email protected]'), ['ic10'], raw);
await icns.addFromPng(await readFile('icon/[email protected]'), ['ic11'], raw);
await writeFile('icon.icns', icns.encode());
```

Expand All @@ -100,10 +100,10 @@ import {readFile, writeFile} from 'node:fs/promises';
import {IconIcns} from '@shockpkg/icon-encoder';

const icns = new IconIcns();
icns.addFromPng(await readFile('icon/16x16.png'), ['is32', 's8mk']);
icns.addFromPng(await readFile('icon/32x32.png'), ['il32', 'l8mk']);
icns.addFromPng(await readFile('icon/48x48.png'), ['ih32', 'h8mk']);
icns.addFromPng(await readFile('icon/128x128.png'), ['it32', 't8mk']);
await icns.addFromPng(await readFile('icon/16x16.png'), ['is32', 's8mk']);
await icns.addFromPng(await readFile('icon/32x32.png'), ['il32', 'l8mk']);
await icns.addFromPng(await readFile('icon/48x48.png'), ['ih32', 'h8mk']);
await icns.addFromPng(await readFile('icon/128x128.png'), ['it32', 't8mk']);
await writeFile('icon.icns', icns.encode());
```

Expand Down
8 changes: 5 additions & 3 deletions bin/icon-encoder.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env node

const {readFile, writeFile} = require('fs/promises');
const {readFile, writeFile} = require('node:fs/promises');

const {VERSION, IconIcns, IconIco} = require('..');

Expand Down Expand Up @@ -52,7 +52,8 @@ async function createIcns(pngs, toc, raw) {
}
for (const [file, type, data] of read) {
try {
icon.addFromPng(data, [type], raw);
// eslint-disable-next-line no-await-in-loop
await icon.addFromPng(data, [type], raw);
} catch (err) {
return [`${file}: ${err.message}`, null];
}
Expand All @@ -70,7 +71,8 @@ async function createIco(pngs, png, raw) {
}
for (const [file, data] of read) {
try {
icon.addFromPng(data, png, raw);
// eslint-disable-next-line no-await-in-loop
await icon.addFromPng(data, png, raw);
} catch (err) {
return [`${file}: ${err.message}`, null];
}
Expand Down
44 changes: 31 additions & 13 deletions src/icon.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {PNG} from 'pngjs';

import {IImageData} from './types';
import {concatUint8Arrays} from './util';

/**
* Icon object.
Expand All @@ -17,14 +18,21 @@ export abstract class Icon {
* @param data PNG data.
* @returns Image data.
*/
protected _decodePngToRgba(data: Readonly<Uint8Array>) {
const {
width,
height,
data: d
} = PNG.sync.read(
Buffer.from(data.buffer, data.byteOffset, data.byteLength)
);
protected async _decodePngToRgba(data: Readonly<Uint8Array>) {
const png = new PNG();
await new Promise((resolve, reject) => {
png.parse(
Buffer.from(data.buffer, data.byteOffset, data.byteLength),
err => {
if (err) {
reject(err);
return;
}
resolve(png);
}
);
});
const {width, height, data: d} = png;
return {
width,
height,
Expand All @@ -38,16 +46,26 @@ export abstract class Icon {
* @param imageData Image data.
* @returns PNG data.
*/
protected _encodeRgbaToPng(imageData: Readonly<IImageData>) {
protected async _encodeRgbaToPng(imageData: Readonly<IImageData>) {
const {width, height, data} = imageData;
const png = new PNG({width, height});
png.data = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
const d = PNG.sync.write(png, {
const png = new PNG({
width,
height,
deflateLevel: 9,
deflateStrategy: 1,
deflateChunkSize: 32 * 1024
});
return new Uint8Array(d.buffer, d.byteOffset, d.byteLength);
png.data = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
const packed: Uint8Array[] = [];
await new Promise((resolve, reject) => {
png.on('data', (d: Buffer) => {
packed.push(d);
});
png.on('error', reject);
png.on('end', resolve);
png.pack();
});
return concatUint8Arrays(packed);
}

/**
Expand Down
5 changes: 3 additions & 2 deletions src/icon/icns.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ void describe('icon/icns', () => {
const png = await readFile(
specIconFilePng(name, size)
);
icns.addFromPng(png, types);
// eslint-disable-next-line no-await-in-loop
await icns.addFromPng(png, types);
}
const data = Buffer.from(icns.encode());
await mkdir(dirname(dest), {recursive: true});
Expand All @@ -86,7 +87,7 @@ void describe('icon/icns', () => {
const png = await readFile(
specIconFilePng(name, size)
);
icns.addFromPng(png, types, raw);
await icns.addFromPng(png, types, raw);
const data = Buffer.from(icns.encode());
await mkdir(dirname(dest), {recursive: true});
await writeFile(dest, data);
Expand Down
24 changes: 15 additions & 9 deletions src/icon/icns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,13 @@ export class IconIcns extends Icon {
* @param types Types to encode as.
* @param raw Use raw PNG data without re-encoding for the PNG types.
*/
public addFromPng(
public async addFromPng(
data: Readonly<Uint8Array>,
types: readonly string[],
raw = false
) {
if (!raw) {
this.addFromRgba(this._decodePngToRgba(data), types);
await this.addFromRgba(await this._decodePngToRgba(data), types);
return;
}
let rgba: IImageData | null = null;
Expand All @@ -104,8 +104,10 @@ export class IconIcns extends Icon {
});
continue;
}
rgba ||= this._decodePngToRgba(data);
this.addFromRgba(rgba, [type]);
// eslint-disable-next-line no-await-in-loop
rgba ||= await this._decodePngToRgba(data);
// eslint-disable-next-line no-await-in-loop
await this.addFromRgba(rgba, [type]);
}
}

Expand All @@ -115,12 +117,13 @@ export class IconIcns extends Icon {
* @param imageData RGBA image data.
* @param types Types to encode as.
*/
public addFromRgba(
public async addFromRgba(
imageData: Readonly<IImageData>,
types: readonly string[]
) {
for (const type of types) {
this._addFromRgbaType(imageData, type);
// eslint-disable-next-line no-await-in-loop
await this._addFromRgbaType(imageData, type);
}
}

Expand Down Expand Up @@ -187,11 +190,14 @@ export class IconIcns extends Icon {
* @param imageData RGBA image data.
* @param type Type to encode as.
*/
protected _addFromRgbaType(imageData: Readonly<IImageData>, type: string) {
protected async _addFromRgbaType(
imageData: Readonly<IImageData>,
type: string
) {
if (this._typePng.has(type)) {
this.entries.push({
type,
data: this._encodeRgbaToTypePng(imageData, type)
data: await this._encodeRgbaToTypePng(imageData, type)
});
return;
}
Expand Down Expand Up @@ -226,7 +232,7 @@ export class IconIcns extends Icon {
* @param _type Icon type.
* @returns Encoded data.
*/
protected _encodeRgbaToTypePng(
protected async _encodeRgbaToTypePng(
imageData: Readonly<IImageData>,
_type: string
) {
Expand Down
17 changes: 10 additions & 7 deletions src/icon/ico.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ void describe('icon/ico', () => {
// eslint-disable-next-line no-await-in-loop
await readFile(specIconFilePng(name, size))
);
ico.addFromPng(png);
// eslint-disable-next-line no-await-in-loop
await ico.addFromPng(png);
}
const data = Buffer.from(ico.encode());
await mkdir(dirname(dest), {recursive: true});
Expand All @@ -36,7 +37,8 @@ void describe('icon/ico', () => {
// eslint-disable-next-line no-await-in-loop
await readFile(specIconFilePng(name, size))
);
ico.addFromPng(png, false);
// eslint-disable-next-line no-await-in-loop
await ico.addFromPng(png, false);
}
const data = Buffer.from(ico.encode());
await mkdir(dirname(dest), {recursive: true});
Expand All @@ -51,7 +53,8 @@ void describe('icon/ico', () => {
// eslint-disable-next-line no-await-in-loop
await readFile(specIconFilePng(name, size))
);
ico.addFromPng(png, true);
// eslint-disable-next-line no-await-in-loop
await ico.addFromPng(png, true);
}
const data = Buffer.from(ico.encode());
await mkdir(dirname(dest), {recursive: true});
Expand All @@ -65,7 +68,7 @@ void describe('icon/ico', () => {
const png = new Uint8Array(
await readFile(specIconFilePng(name, size))
);
ico.addFromPng(png);
await ico.addFromPng(png);
const data = Buffer.from(ico.encode());
await mkdir(dirname(dest), {recursive: true});
await writeFile(dest, data);
Expand All @@ -79,7 +82,7 @@ void describe('icon/ico', () => {
const png = new Uint8Array(
await readFile(specIconFilePng(name, size))
);
ico.addFromPng(png, false);
await ico.addFromPng(png, false);
const data = Buffer.from(ico.encode());
await mkdir(dirname(dest), {recursive: true});
await writeFile(dest, data);
Expand All @@ -93,7 +96,7 @@ void describe('icon/ico', () => {
const png = new Uint8Array(
await readFile(specIconFilePng(name, size))
);
ico.addFromPng(png, true);
await ico.addFromPng(png, true);
const data = Buffer.from(ico.encode());
await mkdir(dirname(dest), {recursive: true});
await writeFile(dest, data);
Expand All @@ -111,7 +114,7 @@ void describe('icon/ico', () => {
const png = new Uint8Array(
await readFile(specIconFilePng(name, size))
);
ico.addFromPng(png, true, true);
await ico.addFromPng(png, true, true);
const data = Buffer.from(ico.encode());
await mkdir(dirname(dest), {recursive: true});
await writeFile(dest, data);
Expand Down
8 changes: 4 additions & 4 deletions src/icon/ico.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class IconIco extends Icon {
* @param png Encode entry as PNG.
* @param raw Use raw PNG data without re-encoding, if using PNG format.
*/
public addFromPng(
public async addFromPng(
data: Readonly<Uint8Array>,
png: boolean | null = null,
raw = false
Expand All @@ -64,7 +64,7 @@ export class IconIco extends Icon {
return;
}
}
this.addFromRgba(this._decodePngToRgba(data), png);
await this.addFromRgba(await this._decodePngToRgba(data), png);
}

/**
Expand All @@ -73,7 +73,7 @@ export class IconIco extends Icon {
* @param imageData RGBA image data.
* @param png Encode entry as PNG.
*/
public addFromRgba(
public async addFromRgba(
imageData: Readonly<IImageData>,
png: boolean | null = null
) {
Expand All @@ -90,7 +90,7 @@ export class IconIco extends Icon {
width: imageData.width,
height: imageData.height,
data: isPng
? this._encodeRgbaToPng(imageData)
? await this._encodeRgbaToPng(imageData)
: this._encodeRgbaToBmp(imageData)
});
}
Expand Down

0 comments on commit 7c3f881

Please sign in to comment.