mirror of
https://github.com/infrost/RaptorQR.git
synced 2026-08-31 15:07:50 +08:00
Cleanup test files
This commit is contained in:
@@ -1,98 +0,0 @@
|
||||
/**
|
||||
* Debug: match EXACTLY what the browser app does.
|
||||
*/
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { SenderPacketizer } from '@/core/sender/packetizer';
|
||||
import { generateQRMatrix } from '@/core/qr/qr_encode';
|
||||
import { rasterizeQR } from '@/core/qr/frame_raster';
|
||||
import { createQRGif } from '@/core/gif/gif_render';
|
||||
import { parseGif, renderGifFrame } from '@/core/gif/gif_parser';
|
||||
import { decodeQRFromCanvas } from '@/core/qr/qr_decode';
|
||||
|
||||
describe('browser-accurate pipeline', () => {
|
||||
it('uses raw packets (no FrameScheduler) like encode.worker.ts', async () => {
|
||||
const text = 'Hello world test 123';
|
||||
const data = new TextEncoder().encode(text);
|
||||
|
||||
// Step 1: Packetize (exactly like encode.worker.ts)
|
||||
const sp = new SenderPacketizer();
|
||||
await sp.initialize(data, 'test.txt', 'text/plain');
|
||||
const manifest = sp.getManifest();
|
||||
const packets = sp.getPackets();
|
||||
|
||||
// The browser app uses allPackets = [...manifestPackets, ...packets]
|
||||
// Just use packets directly for this test (includes manifest)
|
||||
console.log('Total packets:', packets.length);
|
||||
|
||||
// Step 2: Generate QR (exactly like gif.worker.ts)
|
||||
const scale = 3;
|
||||
const qrVersion = 20;
|
||||
const eccLevel = 'Q';
|
||||
const frames: Uint8Array[] = [];
|
||||
let fw = 0, fh = 0;
|
||||
for (const packet of packets) {
|
||||
const matrix = generateQRMatrix(packet, qrVersion, eccLevel);
|
||||
const rgba = rasterizeQR(matrix, scale);
|
||||
if (fw === 0) { fw = rgba.width; fh = rgba.height; }
|
||||
frames.push(new Uint8Array(rgba.data.buffer));
|
||||
}
|
||||
console.log('QR frames:', frames.length, `size: ${fw}×${fh}`);
|
||||
|
||||
// Step 3: Create GIF (exactly like gif.worker.ts)
|
||||
const delayMs = 100;
|
||||
const gifBytes = createQRGif(frames, delayMs, fw, fh);
|
||||
console.log('GIF size:', gifBytes.length, 'bytes');
|
||||
|
||||
// Step 4: Parse GIF (exactly like receiver.tsx)
|
||||
const gifData = parseGif(gifBytes);
|
||||
console.log('Parsed frames:', gifData.frames.length);
|
||||
|
||||
// Step 5: Render + decode each frame
|
||||
let decodedOk = 0;
|
||||
let badLen = 0;
|
||||
let badPixels = 0;
|
||||
|
||||
for (let i = 0; i < gifData.frames.length; i++) {
|
||||
const frame = gifData.frames[i]!;
|
||||
const expectedPixels = frame.width * frame.height;
|
||||
|
||||
if (frame.data.length !== expectedPixels) {
|
||||
badLen++;
|
||||
if (badLen <= 3) console.log(` Frame ${i}: data len ${frame.data.length} vs ${expectedPixels}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const rgba = renderGifFrame(gifData, i);
|
||||
const blackCount = countBlack(rgba, fw, fh);
|
||||
const pct = blackCount / (fw * fh) * 100;
|
||||
|
||||
// Check if image is mostly black (broken) or reasonable
|
||||
if (pct > 80 || pct < 1) {
|
||||
badPixels++;
|
||||
if (badPixels <= 3) console.log(` Frame ${i}: ${blackCount}/${fw*fh} black (${pct.toFixed(1)}%) — too extreme`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const imageData = new ImageData(rgba, fw, fh);
|
||||
const qr = decodeQRFromCanvas(imageData);
|
||||
if (qr) {
|
||||
decodedOk++;
|
||||
} else {
|
||||
if (badPixels + decodedOk <= 3) console.log(` Frame ${i}: QR null, ${blackCount}/${fw*fh} black`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\nResults: ${decodedOk}/${gifData.frames.length} decoded`);
|
||||
console.log(` Bad data length: ${badLen}`);
|
||||
console.log(` Bad pixels (extreme): ${badPixels}`);
|
||||
expect(decodedOk).toBe(gifData.frames.length);
|
||||
});
|
||||
});
|
||||
|
||||
function countBlack(rgba: Uint8ClampedArray, w: number, h: number): number {
|
||||
let black = 0;
|
||||
for (let i = 0; i < w * h; i++) {
|
||||
if (rgba[i * 4]! < 128) black++;
|
||||
}
|
||||
return black;
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
/**
|
||||
* Debug: dump GIF structure byte by byte.
|
||||
*/
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { SenderPacketizer } from '@/core/sender/packetizer';
|
||||
import { FrameScheduler } from '@/core/sender/scheduler';
|
||||
import { generateQRMatrix } from '@/core/qr/qr_encode';
|
||||
import { rasterizeQR } from '@/core/qr/frame_raster';
|
||||
import { createQRGif } from '@/core/gif/gif_render';
|
||||
import { parseGif, renderGifFrame, gifFrameToRgba } from '@/core/gif/gif_parser';
|
||||
import { decodeQRFromCanvas } from '@/core/qr/qr_decode';
|
||||
|
||||
describe('gif structure debug', () => {
|
||||
it('dump GIF header, palette, and frame details', async () => {
|
||||
const data = new TextEncoder().encode('Hello test');
|
||||
const sp = new SenderPacketizer();
|
||||
await sp.initialize(data, 'test.txt', 'text/plain');
|
||||
const manifest = sp.getManifest();
|
||||
const packets = sp.getPackets();
|
||||
const scheduler = new FrameScheduler();
|
||||
const schedule = scheduler.schedule(packets, manifest);
|
||||
|
||||
const scale = 3;
|
||||
const frames: Uint8Array[] = [];
|
||||
let fw = 0, fh = 0;
|
||||
for (const p of schedule) {
|
||||
const matrix = generateQRMatrix(p, 20, 'Q');
|
||||
const rgba = rasterizeQR(matrix, scale);
|
||||
if (fw === 0) { fw = rgba.width; fh = rgba.height; }
|
||||
frames.push(new Uint8Array(rgba.data.buffer));
|
||||
}
|
||||
|
||||
const gifBytes = createQRGif(frames, 100, fw, fh);
|
||||
|
||||
// Dump GIF header
|
||||
const header = new TextDecoder().decode(gifBytes.subarray(0, 6));
|
||||
console.log('Header:', header);
|
||||
const width = gifBytes[6]! | (gifBytes[7]! << 8);
|
||||
const height = gifBytes[8]! | (gifBytes[9]! << 8);
|
||||
const packed = gifBytes[10]!;
|
||||
console.log(`LSD: ${width}x${height}, packed=0x${packed.toString(16)}`);
|
||||
console.log(` Global palette: ${!!(packed & 0x80)}, color res: ${(packed >> 4) & 0x07}, sort: ${!!(packed & 0x08)}, size field: ${packed & 0x07}`);
|
||||
|
||||
const paletteSize = (packed & 0x07) + 1;
|
||||
const paletteEntryCount = 1 << paletteSize;
|
||||
console.log(` Palette entries: ${paletteEntryCount}`);
|
||||
|
||||
const gifPaletteOffset = 13; // after bg color index + pixel aspect ratio
|
||||
const gifPalette: number[][] = [];
|
||||
for (let i = 0; i < paletteEntryCount; i++) {
|
||||
const off = gifPaletteOffset + i * 3;
|
||||
gifPalette.push([gifBytes[off]!, gifBytes[off + 1]!, gifBytes[off + 2]!]);
|
||||
}
|
||||
console.log('GIF palette:', gifPalette.map((c, i) => `${i}: rgb(${c.join(',')})`).join('\n '));
|
||||
|
||||
// Parse with our parser
|
||||
const gifData = parseGif(gifBytes);
|
||||
console.log('\nParsed frames:', gifData.frames.length);
|
||||
console.log('Global palette:', gifData.globalPalette?.map((c,i)=>`${i}: rgb(${c.join(',')})`).join('\n '));
|
||||
|
||||
// Check each frame
|
||||
for (let i = 0; i < Math.min(gifData.frames.length, 5); i++) {
|
||||
const f = gifData.frames[i]!;
|
||||
console.log(`\nFrame ${i}:`);
|
||||
console.log(` Size: ${f.width}x${f.height}, data.len: ${f.data.length}, expected: ${f.width * f.height}`);
|
||||
console.log(` Palette:`, f.palette.map((c,i)=>`${i}: rgb(${c.join(',')})`).join(' '));
|
||||
console.log(` Delay: ${f.delay}, disposal: ${f.disposal}, left: ${f.left}, top: ${f.top}`);
|
||||
|
||||
// Check if data length matches
|
||||
const expected = f.width * f.height;
|
||||
if (f.data.length !== expected) {
|
||||
console.log(` ⚠ DATA LENGTH MISMATCH: ${f.data.length} vs ${expected}`);
|
||||
}
|
||||
|
||||
// Sample pixel values
|
||||
const sample = Array.from(f.data.slice(0, 20));
|
||||
console.log(` First 20 pixel indices:`, sample.join(','));
|
||||
|
||||
// Try rendering and decode
|
||||
const rgba = gifFrameToRgba(f);
|
||||
const blackPixels = countBlack(rgba, f.width, f.height);
|
||||
console.log(` Black pixels: ${blackPixels}/${expected} (${(blackPixels/expected*100).toFixed(1)}%)`);
|
||||
|
||||
const canvas = renderGifFrame(gifData, i);
|
||||
const blackCanvas = countBlack(canvas, gifData.width, gifData.height);
|
||||
console.log(` Canvas black: ${blackCanvas}/${gifData.width*gifData.height} (${(blackCanvas/(gifData.width*gifData.height)*100).toFixed(1)}%)`);
|
||||
|
||||
const imageData = new ImageData(canvas, gifData.width, gifData.height);
|
||||
const qr = decodeQRFromCanvas(imageData);
|
||||
console.log(` QR decode: ${qr ? `OK (${qr.length} bytes)` : 'FAIL'}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function countBlack(rgba: Uint8ClampedArray, w: number, h: number): number {
|
||||
let black = 0;
|
||||
for (let i = 0; i < w * h; i++) {
|
||||
if (rgba[i * 4]! < 128) black++;
|
||||
}
|
||||
return black;
|
||||
}
|
||||
Reference in New Issue
Block a user