Skip to content

Commit

Permalink
Merge pull request #9 from catdad/apple-silicon
Browse files Browse the repository at this point in the history
breaking: using latest svg-render to fix Apple silicon issue with canvas, dropping support for old node versions
  • Loading branch information
catdad authored Apr 27, 2024
2 parents 450776d + da86b86 commit 8905952
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 49 deletions.
8 changes: 0 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,6 @@ jobs:
matrix:
node: [16, 18, 20]
os: [ubuntu-latest, windows-latest, macOS-latest]
# technically still supported, but not as necessary to test absolutely every combination
include:
- os: macOS-latest
node: 10
- os: windows-latest
node: 12
- os: ubuntu-latest
node: 14
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node }}
Expand Down
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,21 @@
"del": "^5.1.0",
"eslint": "^5.16.0",
"file-type": "^14.6.2",
"jimp": "^0.22.12",
"lodash": "^4.17.21",
"mocha": "^8.0.1",
"nyc": "^15.1.0",
"pngjs": "^5.0.0",
"tempy": "^0.6.0"
},
"dependencies": {
"@catdad/to-ico": "^1.0.0",
"@fiahfy/icns": "0.0.6",
"canvas": "^2.8.0",
"cheerio": "^1.0.0-rc.10",
"getopts": "^2.2.5",
"svg-render": "^1.3.0"
"svg-render": "^2.0.0"
},
"engines": {
"node": ">=10.0.0"
"node": ">=16.0.0"
},
"files": [
"bin",
Expand Down
26 changes: 9 additions & 17 deletions src/generator.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
const renderSvg = require('svg-render');
const toIco = require('@catdad/to-ico');
const { Icns, IcnsImage } = require('@fiahfy/icns');
const { createCanvas, loadImage } = require('canvas');
const cheerio = require('cheerio');

const { toArray } = require('./helpers.js');

const createPng = async (buffers, size) => {
const canvas = createCanvas(size, size);
const ctx = canvas.getContext('2d');

for (const buffer of buffers) {
const png = await renderSvg({ buffer, width: size, height: size });
const image = await loadImage(png);
ctx.drawImage(image, 0, 0);
}

return canvas.toBuffer('image/png');
const createPng = async (buffer, size) => {
return await renderSvg({ buffer, width: size, height: size });
};

const createIco = async svg => await toIco(
Expand Down Expand Up @@ -61,29 +51,31 @@ const getInputArray = input => {
};

async function* generateIcons(input, { icns = true, ico = true, png = true, svg = true, pngSizes = [32, 256, 512] } = {}) {
const buffers = getInputArray(input);
// merge individual layers to single layered svg
// we will render this single svg for the rest of the icons
const mergedSvg = Buffer.from(await createSvg(getInputArray(input)));

if (svg) {
yield {
name: 'icon.svg',
ext: 'svg',
buffer: Buffer.from(await createSvg(buffers))
buffer: mergedSvg
};
}

if (ico) {
yield {
name: 'icon.ico',
ext: 'ico',
buffer: Buffer.from(await createIco(buffers))
buffer: Buffer.from(await createIco(mergedSvg))
};
}

if (icns) {
yield {
name: 'icon.icns',
ext: 'icns',
buffer: Buffer.from(await createIcns(buffers))
buffer: Buffer.from(await createIcns(mergedSvg))
};
}

Expand All @@ -92,7 +84,7 @@ async function* generateIcons(input, { icns = true, ico = true, png = true, svg
yield {
name: `${size}x${size}.png`,
ext: 'png',
buffer: Buffer.from(await createPng(buffers, size)),
buffer: Buffer.from(await createPng(mergedSvg, size)),
size
};
}
Expand Down
4 changes: 2 additions & 2 deletions test/bin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ describe('app-icon-maker CLI', () => {

const buffer = await fs.readFile(path.resolve(outdir, `${size}x${size}.png`));
expect(await type.fromBuffer(buffer)).to.deep.equal({ ext: 'png', mime: 'image/png' });
const { width, height, depth } = png.read(buffer);
const { width, height, depth } = await png(buffer);

expect(width).to.equal(size);
expect(height).to.equal(size);
Expand All @@ -163,7 +163,7 @@ describe('app-icon-maker CLI', () => {
for (let size of pngSizes) {
const buffer = await fs.readFile(path.resolve(outdir, `${size}x${size}.png`));
expect(await type.fromBuffer(buffer)).to.deep.equal({ ext: 'png', mime: 'image/png' });
const { width, height, depth } = png.read(buffer);
const { width, height, depth } = await png(buffer);

expect(width).to.equal(size);
expect(height).to.equal(size);
Expand Down
2 changes: 1 addition & 1 deletion test/generator.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ describe('app-icon-maker API generateIcons', () => {
]);

for (let size of pngSizes) {
const { width, height, depth } = png.read(icons[`${size}x${size}.png`]);
const { width, height, depth } = await png(icons[`${size}x${size}.png`]);

expect(width).to.equal(size);
expect(height).to.equal(size);
Expand Down
49 changes: 33 additions & 16 deletions test/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ const crypto = require('crypto');
const path = require('path');

const { expect } = require('chai');
const { sync: png } = require('pngjs').PNG;
const jimp = require('jimp');
const type = require('file-type');
const svgRender = require('svg-render');

const png = async buffer => (await jimp.read(buffer)).bitmap;

const svg = '<svg viewBox="0 0 10 10"><circle cx="5" cy="5" r="5" fill="pink"/></svg>';
const layers = [svg, `<svg viewBox="0 0 500 500">
<ellipse cx="183" cy="155.5" rx="45" ry="33.5" style="fill:rgb(146,255,0);"/>
Expand All @@ -16,12 +18,18 @@ const layers = [svg, `<svg viewBox="0 0 500 500">
<ellipse cx="222.25" cy="412.5" rx="54.75" ry="39.5" style="fill:rgb(255,110,0);"/>
</svg>`];

const defaultHashes = {
'32x32.png': '8000w0a02E0',
'256x256.png': '8000w0a02E0',
'512x512.png': '8000w0a02E0',
'icon.svg': '8000w0a02E0'
};

const layerHashes = {
'32x32.png': 'c450e4c48d310cac5e1432dc3d8855b9a08da0c1e456eeacdbe4b809c8eb5b27',
'256x256.png': '7413a0717534701a7518a4e35633cae0edb63002c31ef58f092c555f2fa4bdfb',
// it's weird that these two are different?
'512x512.png': '926163d94eb5dd6309861db76e952d8562c83b815583440508f79b8213ed44b7',
'icon.svg': 'bba03b4311a86f6e6f6b7e8b37d444604bca27d95984bd56894ab98857a43cdf'
'32x32.png': 'cii4gQqoyWi',
'256x256.png': 'cgi4gQqoyWi',
'512x512.png': 'cgi4gQqoyWi',
'icon.svg': 'cgi4gQqoyWi'
};

const hash = buffer => crypto.createHash('sha256').update(buffer).digest('hex');
Expand All @@ -33,37 +41,40 @@ const validators = {
'icon.ico': async (buffer) => {
expect(await type.fromBuffer(buffer)).to.deep.equal({ ext: 'ico', mime: 'image/x-icon' });
},
'32x32.png': async (buffer, filehash = '84983735a5aa163aed058191c920e4b87831227182a9d800b0d0796c54d9635d') => {
'32x32.png': async (buffer, filehash = defaultHashes['32x32.png']) => {
expect(await type.fromBuffer(buffer)).to.deep.equal({ ext: 'png', mime: 'image/png' });
const { width, height, depth, data } = png.read(buffer);
const image = await jimp.read(buffer);
const { width, height, depth } = image.bitmap;

expect(width).to.equal(32);
expect(height).to.equal(32);
expect(depth).to.equal(8);

expect(hash(data), '32x32.png has different pixels').to.equal(filehash);
expect(image.hash(), '32x32.png has different pixels').to.equal(filehash);
},
'256x256.png': async (buffer, filehash = '4db3b3bbfa792b966042487401d098e0ff6e477f32620020ff43c57e5ad1fa8b') => {
'256x256.png': async (buffer, filehash = defaultHashes['256x256.png']) => {
expect(await type.fromBuffer(buffer)).to.deep.equal({ ext: 'png', mime: 'image/png' });
const { width, height, depth, data } = png.read(buffer);
const image = await jimp.read(buffer);
const { width, height, depth } = image.bitmap;

expect(width).to.equal(256);
expect(height).to.equal(256);
expect(depth).to.equal(8);

expect(hash(data), '256x256.png has different pixels').to.equal(filehash);
expect(image.hash(), '256x256.png has different pixels').to.equal(filehash);
},
'512x512.png': async (buffer, filehash = '4314abee99d494ab7a6675107fb5005c7a17367c3800a9b980ce207b1334cb36') => {
'512x512.png': async (buffer, filehash = defaultHashes['512x512.png']) => {
expect(await type.fromBuffer(buffer)).to.deep.equal({ ext: 'png', mime: 'image/png' });
const { width, height, depth, data } = png.read(buffer);
const image = await jimp.read(buffer);
const { width, height, depth } = image.bitmap;

expect(width).to.equal(512);
expect(height).to.equal(512);
expect(depth).to.equal(8);

expect(hash(data), '512x512.png has different pixels').to.equal(filehash);
expect(image.hash(), '512x512.png has different pixels').to.equal(filehash);
},
'icon.svg': async (buffer, filehash) => {
'icon.svg': async (buffer, filehash = defaultHashes['icon.svg']) => {
// soo... because of layers, the svg won't be just a passthrough, but rather
// an svg that renders equivalently, so...
const size = 512;
Expand All @@ -84,6 +95,12 @@ const validateIcons = async (data, { icns = true, ico = true, png = true, svg =

expect(actualIcons.sort()).to.deep.equal(expectedIcons.sort());

// for (const name of expectedIcons) {
// if (/png$/.test(name)) {
// require('fs').writeFileSync(`./temp/${Date.now()}.png`, data[name]);
// }
// }

for (const name of expectedIcons) {
expect(data).to.have.property(name);
await validators[name](data[name], hashes[name]);
Expand Down
2 changes: 1 addition & 1 deletion test/maker.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ describe('app-icon-maker API filesystem icons', () => {
for (let size of pngSizes) {
const buffer = await fs.readFile(path.resolve(destination, `${size}x${size}.png`));
expect(await type.fromBuffer(buffer)).to.deep.equal({ ext: 'png', mime: 'image/png' });
const { width, height, depth } = png.read(buffer);
const { width, height, depth } = await png(buffer);

expect(width).to.equal(size);
expect(height).to.equal(size);
Expand Down

0 comments on commit 8905952

Please sign in to comment.