Skip to content

Commit

Permalink
perf: Some refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
vHeemstra authored Aug 12, 2024
1 parent 55bdfa7 commit 8a2109f
Showing 1 changed file with 29 additions and 36 deletions.
65 changes: 29 additions & 36 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,18 @@ function convertToInt(bytes: Uint8Array) {
return bytes.reduce((value, byte) => (value << 8) + byte)
}

function isEqual(first, second) {
return (
first[0] === second[0] &&
first[1] === second[1] &&
first[2] === second[2] &&
first[3] === second[3]
)
}

const encoder = new TextEncoder()
const chunkTypes = {
animationControl: encoder.encode('acTL'),
imageData: encoder.encode('IDAT'),
function isEqual(first, second, length = 4) {
while (length > 0) {
length--
if (first[length] !== second[length]) {
return false
}
}
return true;

Check failure on line 12 in src/index.ts

View workflow job for this annotation

GitHub Actions / Node.js 18.x

Delete `;`

Check failure on line 12 in src/index.ts

View workflow job for this annotation

GitHub Actions / Node.js 20.x

Delete `;`

Check failure on line 12 in src/index.ts

View workflow job for this annotation

GitHub Actions / Node.js 22.x

Delete `;`
}

/**
* @see http://www.libpng.org/pub/png/spec/1.2/PNG-Structure.html
* @see https://www.w3.org/TR/png/#5DataRep
*/
const headerSizes = {
/** Number of bytes reserved for PNG signature */
Expand All @@ -31,55 +26,53 @@ const headerSizes = {
CRC: 4,
}

const chunkTypes = {
signature: [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a],
animationControl: [0x61, 0x63, 0x54, 0x4c], // 'acTL'
imageData: [0x49, 0x44, 0x41, 0x54], // 'IDAT'
}

export default function isApng(buffer: Buffer | Uint8Array): boolean {
const minChunkSize = headerSizes.LENGTH + headerSizes.TYPE + headerSizes.CRC

Check failure on line 37 in src/index.ts

View workflow job for this annotation

GitHub Actions / Node.js 18.x

Delete `··`

Check failure on line 37 in src/index.ts

View workflow job for this annotation

GitHub Actions / Node.js 20.x

Delete `··`

Check failure on line 37 in src/index.ts

View workflow job for this annotation

GitHub Actions / Node.js 22.x

Delete `··`
if (
!buffer ||
!(
(typeof Buffer !== 'undefined' && Buffer.isBuffer(buffer)) ||
buffer instanceof Uint8Array
) ||
buffer.length < 16
buffer.length < headerSizes.SIGNATURE + minChunkSize
) {
return false
}

const isPNG =
buffer[0] === 0x89 &&
buffer[1] === 0x50 &&
buffer[2] === 0x4e &&
buffer[3] === 0x47 &&
buffer[4] === 0x0d &&
buffer[5] === 0x0a &&
buffer[6] === 0x1a &&
buffer[7] === 0x0a

if (!isPNG) {
/** Check for PNG signature */
if (!isEqual(buffer, chunkTypes.signature, headerSizes.SIGNATURE)) {
return false
}

// APNGs have an animation control chunk (acTL) preceding any IDAT(s).
// See: https://en.wikipedia.org/wiki/APNG#File_format

buffer = buffer.subarray(headerSizes.SIGNATURE)

const minBufferSize = headerSizes.LENGTH + headerSizes.TYPE
while (buffer.length >= minBufferSize) {
const chunkLength = convertToInt(buffer.subarray(0, headerSizes.LENGTH))
/**
* APNGs have an animation control (acTL) chunk preceding any image data (IDAT) chunks.
* @see: https://www.w3.org/TR/png/#5ChunkOrdering
*/

while (buffer.length >= minChunkSize) {
const chunkType = buffer.subarray(
headerSizes.LENGTH,
headerSizes.LENGTH + headerSizes.TYPE,
)

if (isEqual(chunkType, chunkTypes.animationControl)) {
if (isEqual(chunkType, chunkTypes.animationControl, headerSizes.TYPE)) {
return true
}

if (isEqual(chunkType, chunkTypes.imageData)) {
if (isEqual(chunkType, chunkTypes.imageData, headerSizes.TYPE)) {
return false
}

const nextChunkPosition =
headerSizes.LENGTH + headerSizes.TYPE + chunkLength + headerSizes.CRC
const nextChunkPosition = minChunkSize + convertToInt(buffer.subarray(0, headerSizes.LENGTH))

Check failure on line 75 in src/index.ts

View workflow job for this annotation

GitHub Actions / Node.js 18.x

Insert `⏎·····`

Check failure on line 75 in src/index.ts

View workflow job for this annotation

GitHub Actions / Node.js 20.x

Insert `⏎·····`

Check failure on line 75 in src/index.ts

View workflow job for this annotation

GitHub Actions / Node.js 22.x

Insert `⏎·····`

buffer = buffer.subarray(nextChunkPosition)
}
Expand Down

0 comments on commit 8a2109f

Please sign in to comment.