65 lines
2.7 KiB
JavaScript
65 lines
2.7 KiB
JavaScript
'use strict';
|
|
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const vm = require('node:vm');
|
|
const { encode } = require('../js/apng-encoder');
|
|
|
|
function chunks(buffer) {
|
|
const result = [];
|
|
let offset = 8;
|
|
while (offset < buffer.length) {
|
|
const length = buffer.readUInt32BE(offset);
|
|
const type = buffer.toString('ascii', offset + 4, offset + 8);
|
|
result.push({ type, data: buffer.subarray(offset + 8, offset + 8 + length) });
|
|
offset += length + 12;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
const red = new Uint8Array(16);
|
|
const blue = new Uint8Array(16);
|
|
for (let index = 0; index < 16; index += 4) {
|
|
red.set([255, 0, 0, 255], index);
|
|
blue.set([0, 0, 255, 255], index);
|
|
}
|
|
const png = encode({
|
|
width: 2,
|
|
height: 2,
|
|
frames: [
|
|
{ rgba: red, delayNumerator: 125, delayDenominator: 1000 },
|
|
{ rgba: blue, delayNumerator: 125, delayDenominator: 1000 },
|
|
],
|
|
});
|
|
assert.deepEqual([...png.subarray(0, 8)], [137, 80, 78, 71, 13, 10, 26, 10]);
|
|
const parsed = chunks(png);
|
|
assert.deepEqual(parsed.map((entry) => entry.type), ['IHDR', 'acTL', 'fcTL', 'IDAT', 'fcTL', 'fdAT', 'IEND']);
|
|
assert.equal(parsed.find((entry) => entry.type === 'acTL').data.readUInt32BE(0), 2);
|
|
assert.equal(parsed[2].data.readUInt32BE(0), 0);
|
|
assert.equal(parsed[4].data.readUInt32BE(0), 1);
|
|
assert.equal(parsed[5].data.readUInt32BE(0), 2);
|
|
|
|
for (const root of ['.', 'release/UNIVERSAL_SpineViewer']) {
|
|
const html = fs.readFileSync(root + '/viewer/spine.html', 'utf8');
|
|
const script = html.match(/<script>([\s\S]*?)<\/script>/)[1];
|
|
new vm.Script(script);
|
|
assert.match(script, /addEventListener\('contextmenu'[\s\S]*generateAnimatedThumbnail\(\)/);
|
|
assert.match(script, /const size = 400;/, 'animated output must remain fixed at 400x400');
|
|
assert.match(script, /async function encodeAnimatedThumbnailToLimit/);
|
|
assert.match(script, /const targetBytes = maxKilobytes \* 1024/);
|
|
assert.match(script, /if \(buffer\.length <= targetBytes\) return/);
|
|
assert.match(script, /count: 2, bits: 3, block: 12/);
|
|
assert.match(script, /extension: '\.png'/);
|
|
assert.match(script, /const totalFrames = Math\.max\(1, frameOf\(animationLength\)\)/);
|
|
assert.match(script, /start: startFrame \/ FPS/);
|
|
assert.match(html, /id="animatedThumbStart" type="number" min="0" step="1"/);
|
|
assert.match(html, /id="animatedThumbEnd" type="number" min="0" step="1"/);
|
|
assert.match(html, /data-i18n="viewer\.framesUnit"/);
|
|
assert.match(html, /id="animatedThumbMaxSize" type="number" min="50" max="10240" step="50" value="100"/);
|
|
assert.doesNotMatch(html, /id="animatedThumbQuality"/);
|
|
assert.doesNotMatch(html, /viewer\.secondsUnit/);
|
|
assert.match(html, /id="animatedThumbDialog"/);
|
|
}
|
|
|
|
console.log('PASS: APNG structure, fixed 400x400 output, quality profiles and right-click wiring');
|