cv not defined, when trying to convert image to binary - javascript

So, I'm trying to convert image to binary, I have 2 canvas, first one is to display original file(image), second one is to display binary images. At first when I only show original image, it worked just fine, but when I wrote code to convert it to binary image, the console shows error :
script.js:26 Uncaught ReferenceError: cv is not defined
at file:///***script.js:26:11
Here is the HTML code:
<p id="status">OpenCV.js is loading...</p>
<div>
<div class="inputoutput">
<img id="imageSrc" alt="No Image" />
<div class="caption">imageSrc <input type="file" id="fileInput" name="file" /></div>
</div>
<div class="inputoutput">
<canvas id="canvasOutput" ></canvas>
<div class="caption">canvasOutput</div>
</div>
<div class="inputoutput">
<canvas id="canvasBinary"></canvas>
<div class="caption">Binary</canvas>
</div>
</div>
<script type="text/javascript" src="scriptOCV.js">
</script>
<script async src="opencv.js" type="text/javascript"></script>
and here is my script
let imgElement = document.getElementById('imageSrc');
let inputElement = document.getElementById('fileInput');
inputElement.addEventListener('change', (e) => {
imgElement.src = URL.createObjectURL(e.target.files[0]);
}, false);
//read image
imgElement.onload = function () {
let mat = cv.imread(imgElement);
cv.imshow('canvasOutput', mat);
mat.delete();
};
//check openCV
var Module = {
// https://emscripten.org/docs/api_reference/module.html#Module.onRuntimeInitialized
onRuntimeInitialized() {
document.getElementById('status').innerHTML = 'OpenCV.js is ready.';
}
};
//convert img -> binary
let src = cv.imread('canvasOutput');
let dst = new cv.Mat();
cv.cvtColor(src, src, cv.COLOR_RGBA2GRAY, 0);
cv.adaptiveThreshold(src, dst, 200, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 3, 2);
cv.imshow('canvasBinary', dst);
src.delete();
dst.delete();
imgElement function works just fine. But in convert img->binary it shows cv is not defined. I have no idea what's wrong with my code.

I don't know if it's the best solution, but we may execute the "convert img" code after "OpenCV.js is ready".
After document.getElementById('status').innerHTML = 'OpenCV.js is ready.';, add a call to onOpenCvReady();:
Place the "convert img" code inside onOpenCvReady() function.
JavaScript code:
let imgElement = document.getElementById('imageSrc');
let inputElement = document.getElementById('fileInput');
inputElement.addEventListener('change', (e) => {
imgElement.src = URL.createObjectURL(e.target.files[0]);
}, false);
//read image
imgElement.onload = function () {
let mat = cv.imread(imgElement);
cv.imshow('canvasOutput', mat);
mat.delete();
};
//check openCV
var Module = {
// https://emscripten.org/docs/api_reference/module.html#Module.onRuntimeInitialized
onRuntimeInitialized() {
document.getElementById('status').innerHTML = 'OpenCV.js is ready.';
//Execute the function after OpenCV.js is ready.
onOpenCvReady();
}
};
function onOpenCvReady() {
//convert img -> binary
let src = cv.imread('canvasOutput');
let dst = new cv.Mat();
cv.cvtColor(src, src, cv.COLOR_RGBA2GRAY, 0);
cv.adaptiveThreshold(src, dst, 200, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 3, 2);
cv.imshow('canvasBinary', dst);
src.delete();
dst.delete();
};

So i have figured it out now, I don't think this is the best solution but it makes the code work. :). I just have to move
move 'convert img -> binary' to onload function.
so final script.js would be like this:
let imgElement = document.getElementById('imageSrc');
let inputElement = document.getElementById('fileInput');
inputElement.addEventListener('change', (e) => {
imgElement.src = URL.createObjectURL(e.target.files[0]);
}, false);
//read image
imgElement.onload = function () {
let mat = cv.imread(imgElement);
cv.imshow('canvasOutput', mat);
mat.delete();
//convert img -> binary
let src = cv.imread('canvasOutput');
let dst = new cv.Mat();
cv.cvtColor(src, src, cv.COLOR_RGBA2GRAY, 0);
cv.adaptiveThreshold(src, dst, 200, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 3, 2);
cv.imshow('canvasBinary', dst);
src.delete();
dst.delete();
};
//check openCV
var Module = {
// https://emscripten.org/docs/api_reference/module.html#Module.onRuntimeInitialized
onRuntimeInitialized() {
document.getElementById('status').innerHTML = 'OpenCV.js is ready.';
//Execute the function after OpenCV.js is ready.
}
};

Related

Can't recognize image using OCR

I was trying to use ocrad.js to convert an image to a string, but I didn't get the result string. I was also previewing the image, the problem is only in the image recognition.
This is my code:
function pr_image(event) {
var reader = new FileReader();
reader.onload = function() {
var output = document.getElementById('output_image');
output.src = reader.result;
}
reader.readAsDataURL(event.target.files[0]);
var stringletter = OCRAD(event.target.files[0]);
document.getElementById('letter').value = stringletter;
}
and this is the browser's capture:
unchanged value
no error message in console
I've tried to change the recognition code into this one function, but i get . as the image recognition's result:
function str_img(event) {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var img = new Image();
img.onload = function() {
context.drawImage(this, 0, 0);
}
var imageData = context.getImageData(0, 0, 100, 100);
var stringletter = OCRAD(imageData);
document.getElementById('letter').value = stringletter;
}
I suspect that I failed at converting the input file as image data. What should I do? Any help is appreciated!
Solved:
I've changed my code into this by Chris G and it works! Thank you
function preview_image(event)
{
var reader = new FileReader();
var output = document.getElementById('output_image');
reader.onload = function()
{
output.src = reader.result;
}
reader.readAsDataURL(event.target.files[0]);
output.onload = function()
{
var stringletter = OCRAD(output);
document.getElementById('letter').value = stringletter;
}
}

Fabric JS: Performance of very large images (20mb+)

I'm using Fabric JS to manipulate very large images (20mb+). I have found that Fabric is considerably slower at handling large images in a canvas as compared to using the standard Canvas API.
The below code snippet has two input buttons, one for adding an image to canvas using standard Canvas API and the other using Fabric JS. Each method will also convert the canvas to a data url using toDataUrl(). Each method also logs three times: start time, time when img.onload function completes, and when toDataUrl() completes.
Here is a table comparing import+export times that I tested for varying image sizes:
import times for 500kb to 50mb photos
Here is a graph displaying the performance of Fabric import+export times vs Canvas API: graph
Questions:
Why is Fabric performance so much slower than Canvas API at importing+exporting large images on a canvas?
Is there a way to increase Fabric performance when using large images?
Are my test cases accurately representing Fabric performance?
// Standard Import
function handleFiles(e) {
var t0 = performance.now();
console.log('Standard Import')
console.log('Start Time: ', Math.round(t0/1000))
var promise = new Promise(function(resolve) {
var URL = window.webkitURL || window.URL;
var ctx = document.getElementById('canvas').getContext('2d');
canvas = document.getElementById('canvas');
var url = URL.createObjectURL(e.target.files[0]);
var img = new Image();
img.onload = function() {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
resolve("done")
};
img.src = url;
});
promise.then(function(result) {
var t1 = performance.now()
console.log('Done img.onload() Elapsed Time: ', Math.round(t1 - t0)/1000);
var dataURL = canvas.toDataURL('image/png')
return
}).then(function(result){
t2 = performance.now()
console.log('Done canvas.ToDataURL() Elapsed Time: ', Math.round(t2 - t0)/1000)
return
});
}
// Fabric Import
function handleFilesFabric(e) {
var t0 = performance.now();
console.log('Fabric Import')
console.log('Start Time: ', Math.round(t0/1000))
var promise = new Promise(function(resolve) {
var canvas = new fabric.Canvas('canvas');
var reader = new FileReader();
reader.onload = function (event){
var imgObj = new Image();
imgObj.src = event.target.result;
imgObj.onload = function () {
var image = new fabric.Image(imgObj);
canvas.setHeight(imgObj.height);
canvas.setWidth(imgObj.width);
canvas.add(image);
canvas.renderAll();
canvas.forEachObject(function(object){
object.selectable = false;
});
resolve("done")
}
}
reader.readAsDataURL(e.target.files[0]);
});
promise.then(function(result) {
var t1 = performance.now()
console.log('Done img.onload() Elapsed Time: ', Math.round(t1 - t0)/1000);
var dataURL = canvas.toDataURL('image/png')
return
}).then(function(result){
t2 = performance.now()
console.log('Done canvas.ToDataURL() Elapsed Time: ', Math.round(t2 - t0)/1000)
return
});
}
window.onload = function() {
// Standard Import
var input = document.getElementById('input');
input.addEventListener('change', handleFiles, false);
// Fabric Import
var input2 = document.getElementById('input2');
input2.addEventListener('change', handleFilesFabric, false);
};
canvas {
border: 2px solid;
}
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Upload & Display Image w/ Canvas</title>
<link rel="stylesheet" href="css/style.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.min.js"></script>
</head>
<body>
<h1> Upload & Display Image</h1>
<canvas width="400" height="400" id="canvas"></canvas>
<br>
<b>Standard Add Image</b><br>
<input type="file" id="input"/>
<br>
<b>Fabric Add Image</b><br>
<input type="file" id="input2"/>
<script src="js/index.js"></script>
</body>
</html>
I refactored the code a bit to be more fair:
Same way of loading the image and both event run after the other on 2 different canvases.
Also remove additional fabricJS functionality that for this test do not make sense. I think that for bigger image the differnce should be lower now, can you try in the snippet with a big image?
By the way you cannot compare a URL.createObjectUrl from a file with a file reader on a dataUrl. Is just unfair.
createObjectUrl create a reference in memory to the file you uploaded.
ReadAsDataUrl read the file, encode in base64, create a string object, then the browser has to read that string again, decode from base64.
The difference could also be in the fact fabricJS paint the image with drawImage and 9 args, while you used the 3 args version.
// Standard Import
fabric.Object.prototype.objectCaching = false;
function handleFiles(e) {
var t0 = performance.now();
var promise = new Promise(function(resolve) {
var URL = window.webkitURL || window.URL;
var ctx = document.getElementById('canvas').getContext('2d');
canvas = document.getElementById('canvas');
var url = URL.createObjectURL(e.target.files[0]);
var img = new Image();
img.onload = function() {
console.log('Standard Import')
console.log('Start Time: ', Math.round(t0/1000))
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
resolve("done")
};
img.src = url;
});
promise.then(function(result) {
var t1 = performance.now()
console.log('Done img.onload() Elapsed Time: ', Math.round(t1 - t0)/1000);
var dataURL = canvas.toDataURL('image/png')
return
}).then(function(result){
t2 = performance.now()
console.log('Done canvas.ToDataURL() Elapsed Time: ', Math.round(t2 - t0)/1000)
return
});
}
// Fabric Import
function handleFilesFabric(e) {
var t0 = performance.now();
var canvas = new fabric.StaticCanvas('canvas2', {enableRetinaScaling: false, renderOnAddRemove: false });
var promise = new Promise(function(resolve) {
var reader = new FileReader();
var URL = window.webkitURL || window.URL;
var url = URL.createObjectURL(e.target.files[0]);
var imgObj = new Image();
imgObj.onload = function () {
console.log('Fabric Import')
console.log('Start Time: ', Math.round(t0/1000))
var image = new fabric.Image(imgObj);
canvas.setDimensions({ width: imgObj.width, height: imgObj.height});
canvas.add(image);
resolve("done")
}
imgObj.src = url;
});
promise.then(function(result) {
var t1 = performance.now()
console.log('Done img.onload() Elapsed Time: ', Math.round(t1 - t0)/1000);
canvas.renderAll();
var dataURL = canvas.lowerCanvasEl.toDataURL('image/png')
return
}).then(function(result){
t2 = performance.now()
console.log('Done canvas.ToDataURL() Elapsed Time: ', Math.round(t2 - t0)/1000)
return
});
}
window.onload = function() {
// Standard Import
var input = document.getElementById('input');
input.addEventListener('change', handleFiles, false);
input.addEventListener('change', handleFilesFabric, false);
};
canvas {
border: 2px solid;
}
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Upload & Display Image w/ Canvas</title>
<link rel="stylesheet" href="css/style.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.min.js"></script>
</head>
<body>
<h1> Upload & Display Image</h1>
<canvas width="400" height="400" id="canvas"></canvas>
<canvas width="400" height="400" id="canvas2"></canvas>
<br>
<b>Standard Add Image</b><br>
<input type="file" id="input"/>
<br>
</body>
</html>

javascript fabricjs filter do not return filtered canvas to url

export function filter(url) {
var c = document.createElement('canvas')
c.id = "canvas_greyscale"
var canvas = new fabric.Canvas('canvas_greyscale')
fabric.Image.fromURL(url, function(oImg) {
c.height = oImg.height
c.width = oImg.width
oImg.filters.push(new fabric.Image.filters.Grayscale())
oImg.applyFilters(canvas.renderAll.bind(canvas))
canvas.add(oImg)
var img = canvas.toDataURL('image/png')
console.log(img)
return img
}, {crossOrigin: "Anonymous"})
}
Here my canvas is rendered with grayscale filter. It does not have issue but when I try to convert canvas to url it is giving me the canvas without filter.
I dont know whats wrong in here..
What am I doing wrong. I want to convert the canvas that have filter to url
var img = canvas.toDataURL('image/png') gives me image without filter
Need help
applyFilters is asynchronous (that's why you pass a renderAll callback in it).
You need to call toDataURL in its callback otherwise you're exporting the canvas before the filter is applied.
Here is a rough adaptation of your code :
function filter(url, callback) {
var c = document.createElement('canvas');
c.id = "canvas_greyscale";
var canvas = new fabric.Canvas('canvas_greyscale');
// the applyFilters' callback
var onend = function() {
canvas.renderAll();
var img = canvas.toDataURL('image/png');
callback(img);
}
fabric.Image.fromURL(url, function(oImg) {
canvas.setDimensions({width:oImg.width, height:oImg.height});
oImg.filters.push(new fabric.Image.filters.Grayscale())
// here we pass the export function
oImg.applyFilters(onend)
canvas.add(oImg)
}, {
crossOrigin: "Anonymous"
})
}
var url = 'https://upload.wikimedia.org/wikipedia/commons/5/5b/Supernumerary_rainbow_03_contrast.jpg'
filter(url, function(dataURI) {
output.src = dataURI;
original.src = url
})
img{ width: 50%}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.4/fabric.js"></script>
<img id="output"><br>
original Image: © Andrew Dunn CC-By-SA 2.0 <br>
<img id="original">

In an HTML/JavaScript file, how can I select a data file to include?

I have written a graphing program, but each time it runs it should prompt the user for a data file to plot.
Here is a very simplified program that has the data file (Data.js) hard coded in line 7:
<!DOCTYPE html>
<html>
<head>
<title>Warm-up</title>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.1.min.js"></script/>
<script src="./Data.js"></script>
<script>
function drawHorizontalLine(c, startX, startY, endX, endY) {
c.lineWidth = 3;
c.strokeStyle = '#888';
c.beginPath();
c.moveTo(startX, startY);
c.lineTo(endX, endY);
c.stroke();
}
$(document).ready(function() {
// Set the canvas width according to the length of time of the recording
var myCanvas = document.getElementById("graph");
var resultOfCalculation = 100;
myCanvas.width += resultOfCalculation;
graphWidened = $('#graph');
var graphCanvas = graphWidened[0].getContext('2d');
drawHorizontalLine(graphCanvas, 10, 20, endWidth, endHeight);
});
</script/>
</head>
<body>
<canvas id="graph" width="600" height="450">
</body>
</html>
... where Data.js contains:
var endWidth = 200;
var endHeight = 150;
But I want to select the data file, something like this, perhaps:
<input type="file" id="sourcedFile" />
<p id="chosenFile" ></p>
<script type="text/javascript">
function readSingleFile(evt) {
//Retrieve the first (and only!) File from the FileList object
var f = evt.target.files[0];
if (f) {
document.getElementById("chosenFile").innerHTML = f.name;
} else {
alert("Failed to load file");
}
}
document.getElementById('sourcedFile').addEventListener('change', readSingleFile, false);
</script>
But I am having difficulty fitting the two pieces together in one file.
Obviously it should first request the data file and then draw the graph using the file name stored in the "chosenFile" variable.
I am new to HTML and JavaScript.
Thanks.
--- Edit ---
Thanks for your response, #TheGr8_Nik. I incorporated it in this file:
<!DOCTYPE html>
<html>
<head>
<title>Warm-up</title>
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<input type="file" id="sourcedFile" />
<p id="makeButtonGoAboveCanvas" ></p>
<script type="text/javascript">
var script;
//
// This function is called when sourcedFile changes as a result of user selection.
// It inserts the code lines (actually graph data) contained in sourceFile into this location.
//
// Selected files must be in the same directory as this file. (Why??)
// When running on a local computer the file selection only works in Firefox browser.
//
function insertDataFromSelectedFile(evt) {
//Retrieve the first (and only!) File from the FileList object
var f = evt.target.files[0];
if (!f) {
alert("Failed to load file");
}
else {
script,
script_id = 'loaded_script',
//file_name = "./Data.js";
//file_name = "http://127.0.0.1:8887/Data.js";
//file_name = this.value.replace("C:\\fakepath\\", "http://127.0.0.1:8887/");
//file_name = this.value.replace("C:\\fakepath\\", "");
file_name = f.name;
script = document.createElement('script');
script.id = script_id; // assign an id so you can delete it after use
delete(endWidth); // To test if sourcing worked
script.src = file_name; // set the url to load
$('head').append( $(script) ); // append the new script in the header
if (typeof endWidth == 'undefined') {
alert ("endWidth is undefined. The selected file was not read or did not define endWidth");
}
else {
drawGraph();
}
$('#'+ script_id ).remove(); // remove the last loaded script - Seems to be unnecessary
}
}
function drawHorizontalLine(c, startX, startY, endX, endY) {
c.lineWidth = 3;
c.strokeStyle = '#888';
c.beginPath();
c.moveTo(startX, startY);
c.lineTo(endX, endY);
c.stroke();
}
function drawGraph() {
// Draw the graph
var myCanvas = document.getElementById("graph");
var resultOfCalculation = 100;
myCanvas.width += resultOfCalculation;
graphWidened = $('#graph');
var graphCanvas = graphWidened[0].getContext('2d');
drawHorizontalLine(graphCanvas, 10, 20, endWidth, endHeight);
//drawHorizontalLine(graphCanvas, 10, 20, 400, 80);
}
document.getElementById('sourcedFile').addEventListener('change', insertDataFromSelectedFile, false);
</script>
</head>
<body>
<canvas id="graph" width="600" height="450">
</body>
</html>
I ran this on a local Windows machine with Chrome browser. Chrome caused huge problems by changing the file path to C:\fakepath\ and by complaining about "Cross origin requests are only supported for protocol schemes: http, .....". Changing to Firefox fixed those.
To get the script to work I deleted this line and its closing brace because the onload event didn't seem to be happening: script.onload = function () {
You can use js to inject a script tag in your html:
$( function () {
$('#sourcedFile').on( 'change', function () {
var script,
script_id = 'loaded_script',
file_name = this.value;
// check if the name is not empty
if ( file_name !== '' ) {
// creates the script element
script = document.createElement( 'script' );
// assign an id so you can delete id the next time
script.id = script_id;
// set the url to load
script.src = file_name;
// when the script is loaded executes your code
script.onload = function () {
var myCanvas = document.getElementById("graph");
var resultOfCalculation = 100;
myCanvas.width += resultOfCalculation;
graphWidened = $('#graph');
var graphCanvas = graphWidened[0].getContext('2d');
drawHorizontalLine(graphCanvas, 10, 20, endWidth, endHeight);
};
// remove the last loaded script
$('#'+ script_id ).remove();
// append the new script in the header
$('head').append( $(script) );
}
});
});

WinJS barcode reader issues(Image not loading in canvas)

Am working on a winjs based barcode reader application. Initially I will capture the image using camera capture API and will pass that file object to a canvas element and read its barcode using ZXing library. But the image passed to the canvas is not getting rendered completely as follows.
Following is my html code
<body>
<p>Decoding test for static images</p>
<canvas id="canvasDecode" height="200" width="200"></canvas>
<h3 id="result"></h3>
<p>Put some content here and leave the text box</p>
<input id="input" class="win-textarea" onchange="generate_barcode()">
<h3 id="content"></h3>
<canvas id="canvasEncode" height="200" width="200"></canvas>
<img class="imageHolder" id="capturedPhoto" alt="image holder" />
</body>
following is my javascript code
(function () {
"use strict";
WinJS.Binding.optimizeBindingReferences = true;
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
// TODO: This application has been newly launched. Initialize
// your application here.
var dialog = new Windows.Media.Capture.CameraCaptureUI();
var aspectRatio = { width: 1, height: 1 };
dialog.photoSettings.croppedAspectRatio = aspectRatio;
dialog.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo).then(function (file) {
if (file) {
// draw the image
var canvas = document.getElementById('canvasDecode')
var ctx = canvas.getContext('2d');
var img = new Image;
img.onload = function () {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0, img.width, img.height);
}
img.src = URL.createObjectURL(file);
// open a stream from the image
return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
}
})
.then(function (stream) {
if (stream) {
// create a decoder from the image stream
return Windows.Graphics.Imaging.BitmapDecoder.createAsync(stream);
}
})
.done(function (decoder) {
if (decoder) {
// get the raw pixel data from the decoder
decoder.getPixelDataAsync().then(function (pixelDataProvider) {
var rawPixels = pixelDataProvider.detachPixelData();
var pixels, format; // Assign these in the below switch block.
switch (decoder.bitmapPixelFormat) {
case Windows.Graphics.Imaging.BitmapPixelFormat.rgba16:
// Allocate a typed array with the raw pixel data
var pixelBufferView_U8 = new Uint8Array(rawPixels);
// Uint16Array provides a typed view into the raw 8 bit pixel data.
pixels = new Uint16Array(pixelBufferView_U8.buffer);
if (decoder.bitmapAlphaMode == Windows.Graphics.Imaging.BitmapAlphaMode.straight)
format = ZXing.BitmapFormat.rgba32;
else
format = ZXing.BitmapFormat.rgb32;
break;
case Windows.Graphics.Imaging.BitmapPixelFormat.rgba8:
// For 8 bit pixel formats, just use the returned pixel array.
pixels = rawPixels;
if (decoder.bitmapAlphaMode == Windows.Graphics.Imaging.BitmapAlphaMode.straight)
format = ZXing.BitmapFormat.rgba32;
else
format = ZXing.BitmapFormat.rgb32;
break;
case Windows.Graphics.Imaging.BitmapPixelFormat.bgra8:
// For 8 bit pixel formats, just use the returned pixel array.
pixels = rawPixels;
if (decoder.bitmapAlphaMode == Windows.Graphics.Imaging.BitmapAlphaMode.straight)
format = ZXing.BitmapFormat.bgra32;
else
format = ZXing.BitmapFormat.bgr32;
break;
}
// create a barcode reader
var reader = new ZXing.BarcodeReader();
reader.onresultpointfound = function (resultPoint) {
// do something with the resultpoint location
}
// try to decode the raw pixel data
var result = reader.decode(pixels, decoder.pixelWidth, decoder.pixelHeight, format);
// show the result
if (result) {
document.getElementById("result").innerText = result.text;
}
else {
document.getElementById("result").innerText = "no barcode found";
}
});
}
});
} else {
// TODO: This application has been reactivated from suspension.
// Restore application state here.
}
args.setPromise(WinJS.UI.processAll());
}
};
app.oncheckpoint = function (args) {
// TODO: This application is about to be suspended. Save any state
// that needs to persist across suspensions here. You might use the
// WinJS.Application.sessionState object, which is automatically
// saved and restored across suspension. If you need to complete an
// asynchronous operation before your application is suspended, call
// args.setPromise().
};
app.start();
})();
function generate_barcode() {
// get the content which the user puts into the textbox
var content = document.getElementById("input").value;
// create the barcode writer and set some options
var writer = new ZXing.BarcodeWriter();
writer.options = new ZXing.Common.EncodingOptions();
writer.options.height = 200;
writer.options.width = 200;
writer.format = ZXing.BarcodeFormat.qr_CODE;
// encode the content to a byte array with 4 byte per pixel as BGRA
var imagePixelData = writer.write(content);
// draw the pixel data to the canvas
var ctx = document.getElementById('canvasEncode').getContext('2d');
var imageData = ctx.createImageData(imagePixelData.width, imagePixelData.heigth);
var pixel = imagePixelData.pixel
for (var index = 0; index < pixel.length; index++) {
imageData.data[index] = pixel[index];
}
ctx.putImageData(imageData, 0, 0);
}
The same code worked well when I was using the file picker API. Let me knew where I went wrong.
I think that you're running into some problems with asynchronicity here. I applaud your use of chained calls to then(), but there's a hidden problem - assignment to img.src begins an asynchronous operation while the image is loaded. Your code continues on BEFORE the img.onload event has been raised, and so the closure which img.onload reaches into for the img variable (the pointer to the file URL) changes before the image has fully loaded.
Here's some code that worked for me.
// Inside handler for app.activated ...
var dialog = new Windows.Media.Capture.CameraCaptureUI();
var aspectRatio = { width: 1, height: 1 };
dialog.photoSettings.croppedAspectRatio = aspectRatio;
dialog.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo)
.then(function (file) {
// draw the image
var canvas = document.getElementById('canvasDecode')
var ctx = canvas.getContext('2d');
var img = new Image;
img.onload = function () {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0, img.width, img.height);
// open a stream from the image
decodePic(file);
}
img.onerror = function (err) {
WinJS.log && WinJS.log("Error loading image");
}
img.src = URL.createObjectURL(file);
});
And then I moved the file decoding / barcode reading stuff to a new function.
function decodePic(file) {
file.openAsync(Windows.Storage.FileAccessMode.readWrite)
.then(function (stream) {
if (stream) {
// create a decoder from the image stream
return Windows.Graphics.Imaging.BitmapDecoder.createAsync(stream);
}
})
.done(function (decoder) {
if (decoder) {
// get the raw pixel data from the decoder
decoder.getPixelDataAsync().then(function (pixelDataProvider) {
// YOUR BARCODE READING CODE HERE.
});
}
});
}
I hope this helps!

Categories

Resources