Skip to content

Commit

Permalink
Dark mode icns nesting
Browse files Browse the repository at this point in the history
  • Loading branch information
JrMasterModelBuilder committed Jan 24, 2024
1 parent 0d673aa commit 94c5e79
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 2 deletions.
57 changes: 55 additions & 2 deletions src/icon/icns.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import {describe, it} from 'node:test';
import {mkdir, readFile, writeFile} from 'node:fs/promises';
import {copyFile, mkdir, readFile, rm, writeFile} from 'node:fs/promises';
import {dirname} from 'node:path';

import {specIconsPng, specIconFilePng, encodeFile} from '../util.spec';
import {
specIconsPng,
specIconFilePng,
encodeFile,
fixtureFile
} from '../util.spec';

import {IconIcns} from './icns';

Expand Down Expand Up @@ -96,5 +101,53 @@ void describe('icon/icns', () => {
}
});
}

void describe('darkmode', () => {
void it('alphas', async () => {
const icns = new IconIcns();
icns.toc = true;
for (const [, size, types] of sizesCurrent) {
// eslint-disable-next-line no-await-in-loop
const png = await readFile(
specIconFilePng('alphagradientcolor', size)
);
// eslint-disable-next-line no-await-in-loop
await icns.addFromPng(png, types);
}

{
const dark = new IconIcns();
dark.toc = true;
for (const [, size, types] of sizesCurrent) {
// eslint-disable-next-line no-await-in-loop
const png = await readFile(
specIconFilePng('alphagradientgrey', size)
);
// eslint-disable-next-line no-await-in-loop
await dark.addFromPng(png, types);
}
icns.addDarkIcns(dark.encode());
}

const data = icns.encode();

const base = ['icns', 'darkmode', 'test.app'];
const cnts = [...base, 'Contents'];
const app = encodeFile(...base);
const bin = encodeFile(...cnts, 'MacOS', 'test');
const icon = encodeFile(...cnts, 'Resources', 'test.icns');
const plist = encodeFile(...cnts, 'Info.plist');

await rm(app, {recursive: true, force: true});

await mkdir(dirname(bin), {recursive: true});
await copyFile(fixtureFile('darkmode', 'test'), bin);

await mkdir(dirname(icon), {recursive: true});
await writeFile(icon, data);

await copyFile(fixtureFile('darkmode', 'Info.plist'), plist);
});
});
});
});
29 changes: 29 additions & 0 deletions src/icon/icns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,35 @@ export class IconIcns extends Icon {
});
}

/**
* Add dark mode icns.
*
* @param data Full encoded icns data.
*/
public addDarkIcns(data: Readonly<Uint8Array>) {
const {length} = data;
if (
length < 8 ||
data[0] !== 105 ||
data[1] !== 99 ||
data[2] !== 110 ||
data[3] !== 115 ||
new DataView(
data.buffer,
data.byteOffset,
data.byteLength
).getUint32(4) !== length
) {
throw new Error('Invalid icns header data');
}
const body = new Uint8Array(length - 8);
body.set(data.subarray(8));
this.entries.push({
type: '\xFD\xD9\x2F\xA8',
data: body
});
}

/**
* Encode icon.
*
Expand Down

0 comments on commit 94c5e79

Please sign in to comment.