refactor: simplify barcode detection by removing canvas splitting

Remove canvas splitting logic since zxing-wasm natively supports multiple barcode detection with maxNumberOfSymbols parameter. Reduces code by 69 lines and improves performance by requiring only a single decode call per canvas. Set maxNumberOfSymbols to 10 for realistic utility bill use case.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Knee Cola
2025-12-20 01:00:46 +01:00
parent 5b0497891a
commit fcc1ede4d0

View File

@@ -240,96 +240,27 @@ const decodeFromCanvas = async (canvas:HTMLCanvasElement): Promise<Array<DecodeR
const readerOptions: ReaderOptions = {
tryHarder: true,
formats: ['PDF417'],
maxNumberOfSymbols: 255,
maxNumberOfSymbols: 10,
};
const width = canvas.width;
const height = canvas.height;
// Canvas can contain multiple PDF417 codes, so we need to try to find them all
// The issue is that zxing-wasm can only decode one code at a time in some cases
// and it will throw an error if it finds more than one code.
// To solve this, we will try splitting the canvas into different number of subsections
// and decode each subsection separately. The best result will be the one with the most codes found.
const splits = [5,4,3,2,1,0];
let bestResult: Array<DecodeResult>|null = null;
for(let splitIx = 0; splitIx < splits.length; splitIx++) {
const split = splits[splitIx];
const overlap = split === 0 ? 0 : Math.round(height / 50); // 50% overlap ensuring that we don't miss any codes that might be split between sections
const sectionHeight = split === 0 ? height : (Math.floor( Math.floor(height / split) + overlap));
const canvasSections = Array.from({ length: split+1 }, (_, i) => {
const sectionCanvas = document.createElement('canvas');
sectionCanvas.width = width;
sectionCanvas.height = sectionHeight;
const sectionContext = sectionCanvas.getContext('2d');
if (!sectionContext) {
throw new Error('Failed to get canvas context');
}
// Calculate the starting Y position for each section
const startY = i===0 ? 0 : i * (sectionHeight) - overlap;
// Draw the section of the original canvas onto the new section canvas
sectionContext.drawImage(canvas, 0, startY, width, sectionHeight, 0, 0, width, sectionHeight);
return sectionCanvas;
});
const codesFoundInSection: Array<DecodeResult> = [];
// Try to decode each section
for (const sectionCanvas of canvasSections) {
try {
// give browser a chance to re-paint
// this is needed to avoid UI freezing when decoding large images
await yieldToBrowser('decodeFromCanvas');
const imageData = canvasToImageData(sectionCanvas);
const imageData = canvasToImageData(canvas);
const results = await readBarcodes(imageData, readerOptions);
for (const result of results) {
const hub3aText = result.text;
const codesFound: Array<DecodeResult> = results
.filter(result => result.text)
.map((result) => ({
hub3aText: result.text,
billInfo: parseHubText(result.text),
}));
if (hub3aText) {
codesFoundInSection.push({
hub3aText,
billInfo: parseHubText(hub3aText),
});
}
}
return (codesFound);
} catch (error) {
// If no code was found in the current section an error will be thrown
// -> we can ignore it
} finally {
}
}
await yieldToBrowser('after decodeFromCanvas');
// IF in this iteration we found less codes than in the previous best result,
// we can stop searching for more codes
// This is because the number of codes found in each section will only decrease
// as we increase the number of sections (split)
if(bestResult && codesFoundInSection.length <= bestResult.length) {
return(bestResult);
}
bestResult = codesFoundInSection;
};
return(bestResult);
} catch(ex:any) {
console.log(ex);
console.log(error);
return (null);
}
}