Skip to content

Commit

Permalink
Utility function
Browse files Browse the repository at this point in the history
  • Loading branch information
JrMasterModelBuilder committed Sep 25, 2023
1 parent b9ef636 commit ed2803d
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 36 deletions.
37 changes: 2 additions & 35 deletions src/icon.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {PNG} from 'pngjs';

import {IImageData} from './types';
import {concatUint8Arrays, pngReader, pngEncode} from './util';
import {concatUint8Arrays, pngRepack} from './util';

/**
* Icon object.
Expand Down Expand Up @@ -69,40 +69,7 @@ export abstract class Icon {
png.on('end', resolve);
png.pack();
});
let ihdr: Uint8Array | null = null;
let iend: Uint8Array | null = null;
const idats = [];
for (const [tag, data] of pngReader(concatUint8Arrays(packed))) {
switch (tag) {
// IDAT
case 0x49444154: {
idats.push(data);
break;
}
// IHDR
case 0x49484452: {
ihdr = data;
break;
}
// IEND
case 0x49454e44: {
iend = data;
break;
}
default: {
// Discard others.
}
}
}
if (!ihdr || !iend) {
throw new Error('Encode error');
}
const pieces: [number, Uint8Array][] = [[0x49484452, ihdr]];
if (srgb !== null) {
pieces.push([0x73524742, new Uint8Array([srgb])]);
}
pieces.push([0x49444154, concatUint8Arrays(idats)], [0x49454e44, iend]);
return pngEncode(pieces);
return pngRepack(concatUint8Arrays(packed));
}

/**
Expand Down
50 changes: 49 additions & 1 deletion src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import {IPngIhdr} from './types';

const PNG_MAGIC = [137, 80, 78, 71, 13, 10, 26, 10];
const PNG_MAGIC_SIZE = 8;
const IHDR = 0x49484452;
const SRGB = 0x73524742;
const IDAT = 0x49444154;
const IEND = 0x49454e44;

const CRC32_TABLE: number[] = [];

Expand Down Expand Up @@ -110,6 +114,50 @@ export function pngEncode(tags: Readonly<[number, Readonly<Uint8Array>][]>) {
return r;
}

/**
* Repack PNG tag data with a single IDAT.
*
* @param data PNG data.
* @param srgb Set an SRGB value.
* @returns PNG data.
*/
export function pngRepack(
data: Readonly<Uint8Array>,
srgb: number | null = null
) {
let ihdr: Uint8Array | null = null;
let iend: Uint8Array | null = null;
const idats = [];
for (const [tag, d] of pngReader(data)) {
switch (tag) {
case IDAT: {
idats.push(d);
break;
}
case IHDR: {
ihdr = d;
break;
}
case IEND: {
iend = d;
break;
}
default: {
// Discard others.
}
}
}
if (!ihdr || !iend) {
throw new Error('Invalid PNG');
}
const pieces: [number, Uint8Array][] = [[IHDR, ihdr]];
if (srgb !== null) {
pieces.push([SRGB, new Uint8Array([srgb])]);
}
pieces.push([IDAT, concatUint8Arrays(idats)], [IEND, iend]);
return pngEncode(pieces);
}

/**
* Read PNG IHDR data.
*
Expand All @@ -118,7 +166,7 @@ export function pngEncode(tags: Readonly<[number, Readonly<Uint8Array>][]>) {
*/
export function pngIhdr(data: Readonly<Uint8Array>): IPngIhdr {
for (const [tag, td] of pngReader(data)) {
if (tag === 0x49484452) {
if (tag === IHDR) {
const d = new DataView(td.buffer, td.byteOffset, td.byteLength);
return {
width: d.getUint32(0, false),
Expand Down

0 comments on commit ed2803d

Please sign in to comment.