Skip to content

Instantly share code, notes, and snippets.

@cuter44
Last active August 29, 2015 14:03
Show Gist options
  • Save cuter44/fe256687b9bcd6e65c14 to your computer and use it in GitHub Desktop.
Save cuter44/fe256687b9bcd6e65c14 to your computer and use it in GitHub Desktop.
Parse ISBN-13 from image taken by camera, with pure js.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="ISBN13Parser.js"></script>
</head>
<body>
<input type="file" accept="image/*" onchange="loadAndParse(this);"/>
<script>
var parser = new ISBN13Parser();
function loadAndParse(input)
{
console.log(input.value);
var reader = new window.FileReader();
reader.onloadend = function(){
var img = new Image();
img.src = this.result;
alert(parser.parseImage(img));
};
reader.readAsDataURL(input.files[0]);
}
</script>
</body>
</html>
/** ISBN-13 decoder
* author by galin<cuter44@foxmail.com>
* free to use if reserve the author info.
*/
function ISBN13Parser(){
this.sResult = null;
this.iaResult = null;
this.baResult = null;
this.thresold = 80;
this.cb = (function (){
var a = new Array();
a[13]=0; a[39]=0; a[114]=0;
a[25]=1; a[51]=1; a[102]=1;
a[19]=2; a[27]=2; a[108]=2;
a[61]=3; a[33]=3; a[ 66]=3;
a[35]=4; a[29]=4; a[ 92]=4;
a[49]=5; a[57]=5; a[ 78]=5;
a[47]=6; a[ 5]=6; a[ 80]=6;
a[59]=7; a[17]=7; a[ 68]=7;
a[55]=8; a[ 9]=8; a[ 72]=8;
a[11]=9; a[23]=9; a[116]=9;
return(a);
})();
this.parseImage = function (img)
{
return(
this.parseCanvas(this.img2Canvas(img))
);
}
this.parseCanvas = function (cvs)
{
this.baResult =
this.parseBits(this.binarize(this.discolor(cvs)));
this.iaResult = this.decodeBits(this.baResult);
var sResult = "";
for (var i=0; i<13; i++)
sResult = sResult.concat(this.iaResult[i]);
this.sResult = sResult;
return(this.sResult);
}
this.decodeBits = function (bits)
{
var offset = 3,
decoded = new Array(13);
for (var i=1; i<=6; i++)
{
var b = 0;
for (var j=0; j<7; j++)
b = (b<<1)+bits[offset++];
decoded[i]=this.cb[b];
//console.log(b.toString(2) + " -> " + decoded[i]);
}
offset = 50;
for (var i=7; i<=12; i++)
{
var b = 0;
for (var j=0; j<7; j++)
b = (b<<1)+bits[offset++];
decoded[i]=this.cb[b];
//console.log(b.toString(2) + " -> " + decoded[i]);
}
decoded[0] = 9;
return(decoded);
}
this.parseBits = function (cvs)
{
var w = cvs.width,
h = cvs.height,
w_mid = Math.floor(w/2),
h_mid = Math.floor(h/2),
ctx = cvs.getContext("2d"),
data = ctx.getImageData(0, h_mid, w, 1).data,
edge_l, edge_r, wh_l, wh_r, ln_found;
wh_l = wh_r = 0;
edge_l = edge_r = w_mid*4;
ln_found = (data[4*w_mid]==0) ? -1 : 0;
while (ln_found<30)
{
if (wh_l<wh_r)
{
var p = data[edge_l];
edge_l -= 4;
if (edge_l<0)
throw("左边缘溢出");
if (data[edge_l]-p==255)
ln_found++;
wh_l += (data[edge_l]==255) ? 1 : -wh_l;
}
else
{
var p = data[edge_r];
edge_r += 4;
if (edge_r>(w-1)*4)
throw("右边缘溢出");
if (data[edge_r]-p==255)
ln_found++;
wh_r += (data[edge_r]==255) ? 1 : -wh_r;
}
}
// shrink
while (data[edge_l]==255)
edge_l+=4;
while (data[edge_r]==255)
edge_r-=4;
var l=edge_l/4, r=edge_r/4, p=l, s=(r-l)/95;
var bits = new Array(95);
for (var i=0; i<95; i++)
{
var p_l = Math.ceil(p), p_r = Math.floor(p+s);
c = 0;
for (var j=p_l; j<=p_r; j++)
c += (data[j*4]==0)?1:0;
bits[i] = Math.round(c/(p_r-p_l+1));
//console.log(p_l+" -> "+p_r+", "+c+"/"+(p_r-p_l+1)+"="+bits[i]);
ctx.fillStyle = (i%2==0)? "rgba(255,0,0,0.5)" : "rgba(0,255,0,0.5)";
ctx.fillRect(p_l, h_mid-1, p_r-p_l+1, 3);
p+=s;
}
this.dump(cvs);
return(bits);
}
this.binarize = function (cvs)
{
var w = cvs.width, h = cvs.height,
ctx = cvs.getContext("2d"),
imgd = ctx.getImageData(0, 0, w, h),
data = imgd.data,
px_count = w*h,
b_count = new Array(256),
b_convert = new Array(256),
pr_accel = 0;
for (var i=0; i<px_count; i++)
b_count[data[i*4]] = (b_count[data[i*4]]===undefined) ? 1 : b_count[data[i*4]]+1;
for (var i=0; i<256; i++)
{
var pr = (b_count[i]===undefined) ? 0 : b_count[i]/px_count;
pr_accel += pr;
b_convert[i] = Math.round(pr_accel*256);
}
for (var i=0; i<px_count; i++)
data[i*4] = data[i*4+1] = data[i*4+2] =
((b_convert[data[i*4]]<this.thresold)?0:255);
ctx.putImageData(imgd, 0, 0);
this.dump(cvs);
return(cvs);
}
this.discolor = function (cvs)
{
var w = cvs.width, h = cvs.height,
ctx = cvs.getContext("2d"),
imgd = ctx.getImageData(0, 0, w, h),
data = imgd.data,
px_count = w*h;
for (var i=0; i<px_count; i++)
{
var b = Math.round((data[i*4]*299+data[i*4+1]*587+data[i*4+2]*114)/1000);
data[i*4] = data[i*4+1] = data[i*4+2] = b;
}
ctx.putImageData(imgd, 0, 0);
this.dump(cvs);
return(cvs);
}
this.img2Canvas = function (img)
{
var cvs = document.createElement("canvas");
cvs.width = img.width;
cvs.height = img.height;
var ctx = cvs.getContext("2d");
ctx.drawImage(img, 0, 0);
this.dump(cvs);
return(cvs);
};
this.dump = function (cvs)
{
var c = document.createElement("canvas");
c.width = cvs.width;
c.height = cvs.height;
c.getContext("2d").drawImage(cvs, 0, 0);
document.body.appendChild(c);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment