Files
JOB/JOB.js
2023-08-01 13:44:46 +02:00

353 lines
12 KiB
JavaScript

/**
* CallBacks:
* __________________________________________________________________________________
* All the callback function should have one parameter:
* function(result){};
* And the result parameter will contain an array of objects that look like JOB.
* result = [{Format: the barcode type, Value: the value of the barcode}];
* __________________________________________________________________________________
*
* You can use either the set functions or just access the properties directly to set callback or
* other properties. Just always remember to call Init() before starting to decode something never mess
* around with the SupportedFormats property.
*
*/
JOB = {
Config : {
// Set to false if the decoder should look for one barcode and then stop. Increases performance.
Multiple : true,
// The formats that the decoder will look for.
DecodeFormats : ["Code128","Code93","Code39","EAN-13", "2Of5", "Inter2Of5", "Codabar"],
// ForceUnique just must makes sure that the callback function isn't repeatedly called
// with the same barcode. Especially in the case of a video stream.
ForceUnique: true,
// Set to true if information about the localization should be recieved from the worker.
LocalizationFeedback: false,
// Set to true if checking orientation of the image should be skipped.
// Checking orientation takes a bit of time for larger images, so if
// you are sure that the image orientation is 1 you should skip it.
SkipOrientation : false
},
SupportedFormats : ["Code128","Code93","Code39","EAN-13", "2Of5", "Inter2Of5", "Codabar"],// Don't touch.
ScanCanvas : null, // Don't touch the canvas either.
ScanContext : null,
SquashCanvas : document.createElement("canvas"),
ImageCallback : null, // Callback for the decoding of an image.
StreamCallback : null, // Callback for the decoding of a video.
LocalizationCallback : null, // Callback for localization.
Stream : null, // The actual video.
DecodeStreamActive : false, // Will be set to false when StopStreamDecode() is called.
Decoded : [], // Used to enfore the ForceUnique property.
DecoderWorker : new Worker("DecoderWorker.js"),
OrientationCallback : null,
// Always call the Init().
Init : function() {
JOB.ScanCanvas = JOB.FixCanvas(document.createElement("canvas"));
JOB.ScanCanvas.width = 640;
JOB.ScanCanvas.height = 480;
JOB.ScanContext = JOB.ScanCanvas.getContext("2d");
var script = document.createElement('script');
script.src = "exif.js";
script.type = 'text/javascript';
document.getElementsByTagName('head').item(0).appendChild(script);
},
// Value should be true or false.
SetRotationSkip : function(value) {
JOB.Config.SkipOrientation = value;
},
// Sets the callback function for the image decoding.
SetImageCallback : function(callBack) {
JOB.ImageCallback = callBack;
},
// Sets the callback function for the video decoding.
SetStreamCallback : function(callBack) {
JOB.StreamCallback = callBack;
},
// Sets callback for localization, the callback function should take one argument.
// This will be an array with objects with format.
// {x, y, width, height}
// This represents a localization rectangle.
// The rectangle comes from a 320, 240 area i.e the search canvas.
SetLocalizationCallback : function(callBack) {
JOB.LocalizationCallback = callBack;
JOB.Config.LocalizationFeedback = true;
},
// Set to true if LocalizationCallback is set and you would like to
// receive the feedback or false if
SwitchLocalizationFeedback : function(bool) {
JOB.Config.LocalizationFeedback = bool;
},
// Switches for changing the Multiple property.
DecodeSingleBarcode : function() {
JOB.Config.Multiple = false;
},
DecodeMultiple : function() {
JOB.Config.Multiple = true;
},
// Sets the formats to decode, formats should be an array of a subset of the supported formats.
SetDecodeFormats : function(formats) {
JOB.Config.DecodeFormats = [];
for(var i = 0; i < formats.length; i++) {
if(JOB.SupportedFormats.indexOf(formats[i]) != -1) {
JOB.Config.DecodeFormats.push(formats[i]);
}
}
if(JOB.Config.DecodeFormats.length == 0) {
JOB.Config.DecodeFormats = JOB.SupportedFormats.slice();
}
},
// Removes a list of formats from the formats to decode.
SkipFormats : function(formats) {
for(var i = 0; i < formats.length; i++) {
var index = JOB.Config.DecodeFormats.indexOf(formats[i]);
if(index >= 0) {
JOB.Config.DecodeFormats.splice(index,1);
}
}
},
// Adds a list of formats to the formats to decode.
AddFormats : function(formats) {
for(var i = 0; i < formats.length; i++) {
if(JOB.SupportedFormats.indexOf(formats[i]) != -1) {
if(JOB.Config.DecodeFormats.indexOf(formats[i]) == -1) {
JOB.Config.DecodeFormats.push(formats[i]);
}
}
}
},
// The callback function for image decoding used internally by JOB.
JOBImageCallback : function(e) {
if(e.data.success == "localization") {
if(JOB.Config.LocalizationFeedback) {
JOB.LocalizationCallback(e.data.result);
}
return;
}
if(e.data.success == "orientationData") {
JOB.OrientationCallback(e.data.result);
return;
}
var filteredData = [];
for(var i = 0; i < e.data.result.length; i++) {
if(JOB.Decoded.indexOf(e.data.result[i].Value) == -1 || JOB.Config.ForceUnique == false) {
filteredData.push(e.data.result[i]);
if(JOB.Config.ForceUnique) JOB.Decoded.push(e.data.result[i].Value);
}
}
JOB.ImageCallback(filteredData);
JOB.Decoded = [];
},
// The callback function for stream decoding used internally by JOB.
JOBStreamCallback : function(e) {
if(e.data.success == "localization") {
if(JOB.Config.LocalizationFeedback) {
JOB.LocalizationCallback(e.data.result);
}
return;
}
if(e.data.success && JOB.DecodeStreamActive) {
var filteredData = [];
for(var i = 0; i < e.data.result; i++) {
if(JOB.Decoded.indexOf(e.data.result[i].Value) == -1 || JOB.ForceUnique == false) {
filteredData.push(e.data.result[i]);
if(JOB.ForceUnique) JOB.Decoded.push(e.data.result[i].Value);
}
}
if(filteredData.length > 0) {
JOB.StreamCallback(filteredData);
}
}
if(JOB.DecodeStreamActive) {
JOB.ScanContext.drawImage(JOB.Stream,0,0,JOB.ScanCanvas.width,JOB.ScanCanvas.height);
JOB.DecoderWorker.postMessage({
scan : JOB.ScanContext.getImageData(0,0,JOB.ScanCanvas.width,JOB.ScanCanvas.height).data,
scanWidth : JOB.ScanCanvas.width,
scanHeight : JOB.ScanCanvas.height,
multiple : JOB.Config.Multiple,
decodeFormats : JOB.Config.DecodeFormats,
cmd : "normal",
rotation : 1,
});
}
if(!JOB.DecodeStreamActive) {
JOB.Decoded = [];
}
},
// The image decoding function, image is a data source for an image or an image element.
DecodeImage : function(image) {
if(image instanceof Image || image instanceof HTMLImageElement)
{
image.exifdata = false;
if(image.complete) {
if(JOB.Config.SkipOrientation) {
JOB.JOBDecodeImage(image,1,"");
} else {
EXIF.getData(image, function(exifImage) {
var orientation = EXIF.getTag(exifImage,"Orientation");
var sceneType = EXIF.getTag(exifImage,"SceneCaptureType");
if(typeof orientation != 'number') orientation = 1;
JOB.JOBDecodeImage(exifImage,orientation,sceneType);
});
}
} else {
var img = new Image();
img.onload = function() {
if(JOB.Config.SkipOrientation) {
JOB.JOBDecodeImage(img,1,"");
} else {
EXIF.getData(this, function(exifImage) {
var orientation = EXIF.getTag(exifImage,"Orientation");
var sceneType = EXIF.getTag(exifImage,"SceneCaptureType");
if(typeof orientation != 'number') orientation = 1;
JOB.JOBDecodeImage(exifImage,orientation,sceneType);
});
}
};
img.src = image.src;
}
} else {
var img = new Image();
img.onload = function() {
if(JOB.Config.SkipOrientation) {
JOB.JOBDecodeImage(img,1,"");
} else {
EXIF.getData(this, function(exifImage) {
var orientation = EXIF.getTag(exifImage,"Orientation");
var sceneType = EXIF.getTag(exifImage,"SceneCaptureType");
if(typeof orientation != 'number') orientation = 1;
JOB.JOBDecodeImage(exifImage,orientation,sceneType);
});
}
};
img.src = image;
}
},
// Starts the decoding of a stream, the stream is a video not a blob i.e it's an element.
DecodeStream : function(stream) {
JOB.Stream = stream;
JOB.DecodeStreamActive = true;
JOB.DecoderWorker.onmessage = JOB.JOBStreamCallback;
JOB.ScanContext.drawImage(stream,0,0,JOB.ScanCanvas.width,JOB.ScanCanvas.height);
JOB.DecoderWorker.postMessage({
scan : JOB.ScanContext.getImageData(0,0,JOB.ScanCanvas.width,JOB.ScanCanvas.height).data,
scanWidth : JOB.ScanCanvas.width,
scanHeight : JOB.ScanCanvas.height,
multiple : JOB.Config.Multiple,
decodeFormats : JOB.Config.DecodeFormats,
cmd : "normal",
rotation : 1,
});
var onmessage = JOB.DecoderWorker.onmessage;
JOB.DecoderWorker.onmessage = function (data) {
onmessage(data);
if (data.data.success !== 'localization') {
console.log('onmessage', data);
}
};
},
// Stops the decoding of a stream.
StopStreamDecode : function() {
JOB.DecodeStreamActive = false;
JOB.Decoded = [];
},
JOBDecodeImage : function (image,orientation,sceneCaptureType) {
if(orientation == 8 || orientation == 6) {
if(sceneCaptureType == "Landscape" && image.width > image.height) {
orientation = 1;
JOB.ScanCanvas.width = 640;
JOB.ScanCanvas.height = 480;
} else {
JOB.ScanCanvas.width = 480;
JOB.ScanCanvas.height = 640;
}
} else {
JOB.ScanCanvas.width = 640;
JOB.ScanCanvas.height = 480;
}
JOB.DecoderWorker.onmessage = JOB.JOBImageCallback;
JOB.ScanContext.drawImage(image,0,0,JOB.ScanCanvas.width,JOB.ScanCanvas.height);
JOB.Orientation = orientation;
JOB.DecoderWorker.postMessage({
scan : JOB.ScanContext.getImageData(0,0,JOB.ScanCanvas.width,JOB.ScanCanvas.height).data,
scanWidth : JOB.ScanCanvas.width,
scanHeight : JOB.ScanCanvas.height,
multiple : JOB.Config.Multiple,
decodeFormats : JOB.Config.DecodeFormats,
cmd : "normal",
rotation : orientation,
postOrientation : JOB.PostOrientation
});
},
DetectVerticalSquash : function (img) {
var ih = img.naturalHeight;
var canvas = JOB.SquashCanvas;
canvas.width = 1;
canvas.height = ih;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
try {
var data = ctx.getImageData(0, 0, 1, ih).data;
} catch (err) {
console.log("Cannot check verticalSquash: CORS?");
return 1;
}
var sy = 0;
var ey = ih;
var py = ih;
while (py > sy) {
var alpha = data[(py - 1) * 4 + 3];
if (alpha === 0) {
ey = py;
} else {
sy = py;
}
py = (ey + sy) >> 1;
}
var ratio = (py / ih);
return (ratio===0)?1:ratio;
},
FixCanvas : function (canvas)
{
var ctx = canvas.getContext('2d');
var drawImage = ctx.drawImage;
ctx.drawImage = function(img, sx, sy, sw, sh, dx, dy, dw, dh)
{
var vertSquashRatio = 1;
if (!!img && img.nodeName == 'IMG')
{
vertSquashRatio = JOB.DetectVerticalSquash(img);
sw || (sw = img.naturalWidth);
sh || (sh = img.naturalHeight);
}
if (arguments.length == 9)
drawImage.call(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio);
else if (typeof sw != 'undefined')
drawImage.call(ctx, img, sx, sy, sw, sh / vertSquashRatio);
else
drawImage.call(ctx, img, sx, sy);
};
return canvas;
}
};