Preparing pdf417 decoding
parent
7ec6eb28d3
commit
a8b2d3ed9a
@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
export function getCenterLineFromBox(box) {
|
||||||
|
return [{
|
||||||
|
x: (box[1][0] - box[0][0]) / 2 + box[0][0],
|
||||||
|
y: (box[1][1] - box[0][1]) / 2 + box[0][1]
|
||||||
|
}, {
|
||||||
|
x: (box[3][0] - box[2][0]) / 2 + box[2][0],
|
||||||
|
y: (box[3][1] - box[2][1]) / 2 + box[2][1]
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLineLength(line) {
|
||||||
|
return Math.sqrt(
|
||||||
|
Math.pow(Math.abs(line[1].y - line[0].y), 2) +
|
||||||
|
Math.pow(Math.abs(line[1].x - line[0].x), 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLineAngle(line) {
|
||||||
|
return Math.atan2(line[1].y - line[0].y, line[1].x - line[0].x);
|
||||||
|
}
|
||||||
|
|
||||||
|
function extendLine(line, angle, ext) {
|
||||||
|
const extension = {
|
||||||
|
y: ext * Math.sin(angle),
|
||||||
|
x: ext * Math.cos(angle)
|
||||||
|
};
|
||||||
|
|
||||||
|
line[0].y -= extension.y;
|
||||||
|
line[0].x -= extension.x;
|
||||||
|
line[1].y += extension.y;
|
||||||
|
line[1].x += extension.x;
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getExtendedLine(inputImageWrapper, line, angle, ext) {
|
||||||
|
line = extendLine(line, angle, ext);
|
||||||
|
while (ext > 1 && (!inputImageWrapper.inImageWithBorder(line[0], 0)
|
||||||
|
|| !inputImageWrapper.inImageWithBorder(line[1], 0))) {
|
||||||
|
ext -= Math.ceil(ext / 2);
|
||||||
|
line = extendLine(line, angle, -ext);
|
||||||
|
}
|
||||||
|
return line;
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
import {
|
||||||
|
getCenterLineFromBox as getLine,
|
||||||
|
getLineLength,
|
||||||
|
getLineAngle,
|
||||||
|
getExtendedLine
|
||||||
|
} from '../common/geometric';
|
||||||
|
import ImageDebug from '../common/image_debug';
|
||||||
|
import Bresenham from '../decoder/bresenham';
|
||||||
|
import {findPattern} from '../reader/common';
|
||||||
|
|
||||||
|
const vec2 = {
|
||||||
|
clone: require('gl-vec2/clone'),
|
||||||
|
dot: require('gl-vec2/dot')
|
||||||
|
}
|
||||||
|
|
||||||
|
const START_PATTERN = [8, 1, 1, 1, 1, 1, 1, 3],
|
||||||
|
STOP_PATTERN = [7, 1, 1, 3, 1, 1, 1, 2, 1],
|
||||||
|
MODULO = START_PATTERN.reduce((sum, i) => (sum + i),0);
|
||||||
|
|
||||||
|
export default function detect(inputImageWrapper, box, ctx) {
|
||||||
|
let line = getLine(box),
|
||||||
|
lineLength = getLineLength(line),
|
||||||
|
lineAngle = getLineAngle(line),
|
||||||
|
extendedLine = getExtendedLine(inputImageWrapper, line, lineAngle, Math.floor(lineLength * 0.15)),
|
||||||
|
barcodeLine = Bresenham.getBarcodeLine(inputImageWrapper, extendedLine[0], extendedLine[1]);
|
||||||
|
|
||||||
|
if (ENV.development) {
|
||||||
|
if (ctx) {
|
||||||
|
ImageDebug.drawPath(extendedLine, {x: 'x', y: 'y'}, ctx, {color: 'red', lineWidth: 1});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bresenham.toBinaryLine(barcodeLine);
|
||||||
|
|
||||||
|
const match = findPattern(barcodeLine.line, START_PATTERN, {modulo: MODULO});
|
||||||
|
console.log(match);
|
||||||
|
|
||||||
|
return [
|
||||||
|
vec2.clone([199, 84]),
|
||||||
|
vec2.clone([210, 303]),
|
||||||
|
vec2.clone([634, 88]),
|
||||||
|
vec2.clone([660, 271]),
|
||||||
|
vec2.clone([295, 83]),
|
||||||
|
vec2.clone([310, 295]),
|
||||||
|
vec2.clone([554, 83]),
|
||||||
|
vec2.clone([580, 277])
|
||||||
|
]
|
||||||
|
};
|
@ -0,0 +1,126 @@
|
|||||||
|
export function nextSet(line, offset) {
|
||||||
|
var i;
|
||||||
|
|
||||||
|
offset = offset || 0;
|
||||||
|
for (i = offset; i < line.length; i++) {
|
||||||
|
if (line[i]) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return line.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function normalize(counter, modulo) {
|
||||||
|
var i,
|
||||||
|
sum = 0,
|
||||||
|
ratio,
|
||||||
|
numOnes = 0,
|
||||||
|
normalized = [],
|
||||||
|
norm = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < counter.length; i++) {
|
||||||
|
if (counter[i] === 1) {
|
||||||
|
numOnes++;
|
||||||
|
} else {
|
||||||
|
sum += counter[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ratio = sum / (modulo - numOnes);
|
||||||
|
if (ratio > 1.0) {
|
||||||
|
for (i = 0; i < counter.length; i++) {
|
||||||
|
norm = counter[i] === 1 ? counter[i] : counter[i] / ratio;
|
||||||
|
normalized.push(norm);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ratio = (sum + numOnes) / modulo;
|
||||||
|
for (i = 0; i < counter.length; i++) {
|
||||||
|
norm = counter[i] / ratio;
|
||||||
|
normalized.push(norm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function matchPattern(counter, code, modulo, maxSingleError=1) {
|
||||||
|
var i,
|
||||||
|
error = 0,
|
||||||
|
singleError = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < counter.length; i++) {
|
||||||
|
singleError = Math.abs(code[i] - counter[i]);
|
||||||
|
if (singleError > maxSingleError) {
|
||||||
|
return Number.MAX_VALUE;
|
||||||
|
}
|
||||||
|
error += singleError;
|
||||||
|
}
|
||||||
|
return error / modulo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findPattern(row, pattern, {
|
||||||
|
offset,
|
||||||
|
isWhite=false,
|
||||||
|
tryHarder=true,
|
||||||
|
epsilon=0.5,
|
||||||
|
maxSingleError=0.5,
|
||||||
|
modulo}) {
|
||||||
|
var counter = [],
|
||||||
|
i,
|
||||||
|
counterPos = 0,
|
||||||
|
bestMatch = {
|
||||||
|
error: Number.MAX_VALUE,
|
||||||
|
code: -1,
|
||||||
|
start: 0,
|
||||||
|
end: 0
|
||||||
|
},
|
||||||
|
error,
|
||||||
|
j,
|
||||||
|
sum,
|
||||||
|
normalized;
|
||||||
|
|
||||||
|
if (!offset) {
|
||||||
|
offset = nextSet(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( i = 0; i < pattern.length; i++) {
|
||||||
|
counter[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( i = offset; i < row.length; i++) {
|
||||||
|
if (row[i] ^ isWhite) {
|
||||||
|
counter[counterPos]++;
|
||||||
|
} else {
|
||||||
|
if (counterPos === counter.length - 1) {
|
||||||
|
sum = 0;
|
||||||
|
for ( j = 0; j < counter.length; j++) {
|
||||||
|
sum += counter[j];
|
||||||
|
}
|
||||||
|
normalized = normalize(counter, modulo);
|
||||||
|
if (normalized) {
|
||||||
|
error = matchPattern(normalized, pattern, modulo, maxSingleError);
|
||||||
|
|
||||||
|
if (error < epsilon) {
|
||||||
|
bestMatch.error = error;
|
||||||
|
bestMatch.start = i - sum;
|
||||||
|
bestMatch.end = i;
|
||||||
|
return bestMatch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tryHarder) {
|
||||||
|
for ( j = 0; j < counter.length - 2; j++) {
|
||||||
|
counter[j] = counter[j + 2];
|
||||||
|
}
|
||||||
|
counter[counter.length - 2] = 0;
|
||||||
|
counter[counter.length - 1] = 0;
|
||||||
|
counterPos--;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
counterPos++;
|
||||||
|
}
|
||||||
|
counter[counterPos] = 1;
|
||||||
|
isWhite = !isWhite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
import BarcodeReader from './barcode_reader';
|
||||||
|
import detect from '../detector/pdf_147_detector';
|
||||||
|
import ImageDebug from '../common/image_debug';
|
||||||
|
|
||||||
|
function Pdf147Reader() {
|
||||||
|
BarcodeReader.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
const properties = {
|
||||||
|
SINGLE_CODE_ERROR: {value: 1},
|
||||||
|
AVG_CODE_ERROR: {value: 0.5},
|
||||||
|
FORMAT: {value: "pdf147", writeable: false}
|
||||||
|
};
|
||||||
|
|
||||||
|
Pdf147Reader.prototype = Object.create(BarcodeReader.prototype, properties);
|
||||||
|
Pdf147Reader.prototype.constructor = Pdf147Reader;
|
||||||
|
|
||||||
|
Pdf147Reader.prototype.decode = function(inputImageWrapper, box, ctx) {
|
||||||
|
console.log("Pdf147Reader...");
|
||||||
|
const detectionInfo = detect(inputImageWrapper, box, ctx);
|
||||||
|
console.log(detectionInfo);
|
||||||
|
if (ENV.development) {
|
||||||
|
if (ctx) {
|
||||||
|
ImageDebug.drawVertices(detectionInfo, {x: 0, y: 1}, ctx, {color: "red", lineWidth: 1});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log("Pdf147Reader... END")
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Pdf147Reader;
|
Loading…
Reference in New Issue