/** * 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; } };