'use strict'; const { test } = require('node:test'), assert = require('node:assert/strict'); const fs = require('node:fs'), path = require('node:path'), vm = require('node:vm'); const jpeg = 'data:image/jpeg;base64,/9j/2Q=='; function setup() { const writes = [], dimensions = [], module = { exports: {} }; const context = { putImageData(value) { writes.push(value); value.success(); }, toDataURL(value) { value.success(jpeg); } }; vm.runInNewContext(fs.readFileSync(path.resolve(__dirname, '../utils/image.js'), 'utf8'), { module, Promise, setTimeout, clearTimeout, Uint8Array, Uint8ClampedArray, ArrayBuffer, my: { createCanvasContext(id) { assert.equal(id, 'compress-canvas'); return context; }, getImageInfo() { throw Error('raw pixels were incorrectly treated as an encoded file'); }, canvasPutImageData() { throw Error('Taobao context.putImageData must be used when available'); } } }); return { image: module.exports, writes, dimensions, page: { alive: true, setData(value, callback) { dimensions.push(value); callback(); } } }; } function frame(bytes = [9, 33, 201, 255, 41, 52, 63, 255]) { return { width: 2, height: 1, capturedImage: new Uint8Array(bytes).buffer, anchors: [{ private: true }] }; } test('unknown raw pixels stay blocked until explicit confirmation; a preview alone never chooses the production layout', async () => { const f = setup(), source = frame(); assert.deepEqual(Array.from(f.image.frameCalibrationFormats(source)), ['RGBA', 'BGRA', 'ARGB', 'ABGR']); await assert.rejects(f.image.captureFrameToBase64(source, f.page), /格式尚未确认/); assert.equal(await f.image.captureFrameToBase64(source, f.page, { pixelFormat: 'BGRA', maxSide: 480 }), jpeg); assert.deepEqual(Array.from(f.writes[0].data), [201, 33, 9, 255, 63, 52, 41, 255]); assert.equal(f.image.confirmedFramePixelFormat(), ''); await assert.rejects(f.image.captureFrameToBase64(source, f.page), /格式尚未确认/); assert.equal(f.image.confirmFramePixelFormat(source, 'BGRA'), 'BGRA'); assert.equal(await f.image.captureFrameToBase64(source, f.page), jpeg); assert.deepEqual(Array.from(f.writes[1].data), [201, 33, 9, 255, 63, 52, 41, 255]); assert.equal(f.image.confirmedFramePixelFormat(), 'BGRA'); await assert.rejects(f.image.captureFrameToBase64({ width: 2, height: 1, data: source.capturedImage }, f.page), /格式尚未确认/); assert.equal(setup().image.confirmedFramePixelFormat(), '', 'a cold runtime does not restore the choice from Storage'); }); test('candidate decoders produce the same RGB colors for all four explicitly described byte orders', async () => { const rgb = [17, 58, 203, 255, 91, 34, 16, 255]; const candidates = { RGBA: [17, 58, 203, 255, 91, 34, 16, 255], BGRA: [203, 58, 17, 255, 16, 34, 91, 255], ARGB: [255, 17, 58, 203, 255, 91, 34, 16], ABGR: [255, 203, 58, 17, 255, 16, 34, 91] }; for (const [format, bytes] of Object.entries(candidates)) { const f = setup(); await f.image.captureFrameToBase64(frame(bytes), f.page, { pixelFormat: format }); assert.deepEqual(Array.from(f.writes[0].data), rgb, format); } }); test('calibration freezes only the raw image once, preserving its field path while excluding face landmarks', async () => { const f = setup(), source = frame(); const snapshot = f.image.freezeCalibrationFrame(source); assert.equal(snapshot.anchors, undefined); assert.notEqual(snapshot.capturedImage, source.capturedImage); new Uint8Array(source.capturedImage).fill(0); await f.image.captureFrameToBase64(snapshot, f.page, { pixelFormat: 'RGBA' }); assert.deepEqual(Array.from(f.writes[0].data), [9, 33, 201, 255, 41, 52, 63, 255]); const nested = { width: 2, height: 1, capture: { image: { bytes: frame().capturedImage } } }; const nestedSnapshot = f.image.freezeCalibrationFrame(nested); f.image.confirmFramePixelFormat(nestedSnapshot, 'RGBA'); await f.image.captureFrameToBase64(nested, f.page); assert.equal(f.writes.length, 2); }); test('native format declarations cannot be overwritten by a calibration choice and invalid choices never unlock capture', async () => { const f = setup(), source = frame(); assert.throws(() => f.image.confirmFramePixelFormat(source, 'NV21'), /未通过/); assert.equal(f.image.confirmedFramePixelFormat(), ''); const unsupported = { ...source, pixelFormat: 'NV21' }; assert.deepEqual(Array.from(f.image.frameCalibrationFormats(unsupported)), []); await assert.rejects(f.image.captureFrameToBase64(unsupported, f.page, { pixelFormat: 'RGBA' }), /格式尚未确认/); const declared = { ...frame(), pixelFormat: 'RGBA8888' }; await f.image.captureFrameToBase64(declared, f.page, { pixelFormat: 'BGRA' }); assert.deepEqual(Array.from(f.writes[0].data), [9, 33, 201, 255, 41, 52, 63, 255]); }); test('calibration thumbnails use the Taobao canvas and a 480px limit while formal capture retains its 1280px limit', async () => { const f = setup(), source = { width: 720, height: 1280, capturedImage: new Uint8Array(720 * 1280 * 4).buffer }; await f.image.captureFrameToBase64(source, f.page, { pixelFormat: 'RGBA', maxSide: 480 }); assert.equal(f.writes[0].width, 270); assert.equal(f.writes[0].height, 480); f.image.confirmFramePixelFormat(source, 'RGBA'); await f.image.captureFrameToBase64(source, f.page); assert.equal(f.writes[1].width, 720); assert.equal(f.writes[1].height, 1280); }); test('raw pixel values resembling JPEG or PNG headers are never decoded as compressed images', async () => { for (const pixels of [[255, 216, 255, 255, 1, 2, 3, 255], [137, 80, 78, 71, 1, 2, 3, 255]]) { const f = setup(); await f.image.captureFrameToBase64(frame(pixels), f.page, { pixelFormat: 'RGBA' }); assert.equal(f.writes.length, 1); assert.deepEqual(Array.from(f.writes[0].data).slice(0, 3), pixels.slice(0, 3)); } }); test('the application default exports unlabelled four-channel photos without calibration and never records confirmation', async () => { const f = setup(), source = frame(); assert.equal(await f.image.captureFrameToBase64(source, f.page, { defaultPixelFormat: 'RGBA' }), jpeg); assert.deepEqual(Array.from(f.writes[0].data), [9, 33, 201, 255, 41, 52, 63, 255]); assert.equal(f.image.confirmedFramePixelFormat(), ''); await assert.rejects(f.image.captureFrameToBase64(source, f.page), /格式尚未确认/); }); test('application default is lower priority than platform metadata and an optional confirmed format', async () => { const f = setup(), source = frame(); await f.image.captureFrameToBase64({ ...source, pixelFormat: 'BGRA' }, f.page, { defaultPixelFormat: 'RGBA' }); assert.deepEqual(Array.from(f.writes[0].data), [201, 33, 9, 255, 63, 52, 41, 255]); f.image.confirmFramePixelFormat(source, 'BGRA'); await f.image.captureFrameToBase64(source, f.page, { defaultPixelFormat: 'RGBA' }); assert.deepEqual(Array.from(f.writes[1].data), [201, 33, 9, 255, 63, 52, 41, 255]); await assert.rejects(f.image.captureFrameToBase64({ ...source, pixelFormat: 'NV21' }, f.page, { defaultPixelFormat: 'RGBA' }), /格式尚未确认/); await assert.rejects(f.image.captureFrameToBase64({ width: 2, height: 1, capturedImage: new Uint8Array(3).buffer }, f.page, { defaultPixelFormat: 'RGBA' }), /未收到可导出/); });