Is it possible to cache canvas pages? - javascript

I am using the code in http://jsfiddle.net/epistemex/LUNaJ/
PDFJS.disableWorker = true; // due to CORS
var canvas = document.createElement('canvas'), // single off-screen canvas
ctx = canvas.getContext('2d'), // to render to
pages = [],
currentPage = 1,
url = 'http://www.corsproxy.com/www.ohio.edu/technology/training/upload/Java-Script-Reference-Guide.pdf';
PDFJS.getDocument(url).then(function (pdf) {
PROGRESS.max = pdf.numPages; // just for demo
PROGRESS.value = 1; // just for demo
// init parsing of first page
if (currentPage <= pdf.numPages) getPage();
// main entry point/function for loop
function getPage() {
// when promise is returned do as usual
pdf.getPage(currentPage).then(function(page) {
var scale = 1.5;
var viewport = page.getViewport(scale);
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
// now, tap into the returned promise from render:
page.render(renderContext).then(function() {
// store compressed image data in array
pages.push(canvas.toDataURL());
if (currentPage < pdf.numPages) {
currentPage++;
PROGRESS.value = currentPage; // just for demo
getPage(); // get next page
}
else {
done(); // call done() when all pages are parsed
}
});
});
}
});
function done() {
// NOTE: Just for demo - correct order is not guaranteed here
// as the drawPage is async. use same method as above to make
// sure the order is correct (not for-loop, but use the callback
// to get next page). To present a single page it won't be
// a problem though... (just use drawPage() directly)
for(var i = 0; i < pages.length; i++) {
drawPage(i, addPage);
}
}
function addPage(img) {
img.style.width = '100px';
img.style.height = '120px';
document.body.appendChild(img);
}
function drawPage(index, callback) {
var img = new Image;
img.onload = function() {
ctx.drawImage(this, 0, 0, ctx.canvas.width, ctx.canvas.height);
callback(this); // invoke callback when we're done
}
img.src = pages[index]; // start loading the data-uri as source
}
to render pdf pages to canvas. The problem with this is that it takes along time if the pdf file has large number of files. Is it possible to cache/save these generated files in the users computer/bowser so that if he runs the code a secondary time, he doesn't have to generate them again and instead they can be displayed immediately.

No, dataURI are not "cached" by browser since there is no download involved.
What you can do however, is to store all your pages into a globally accessible array, and check if you already have it before you call PDFJS.getDocument(url) :
PDFJS.disableWorker = true; // due to CORS
var canvas = document.createElement('canvas'), // single off-screen canvas
ctx = canvas.getContext('2d'), // to render to
docs = {}, // an object that will store our pdf documents
urls = ["https://www.ohio.edu/technology/training/upload/html-tag-reference-guide.pdf", "https://www.ohio.edu/technology/training/upload/Java-Script-Reference-Guide.pdf"];
btn0.onclick = getDoc;
btn1.onclick = getDoc;
function getDoc() {
// get the doc's url
var url = urls[+this.id.split('btn')[1]];
// clear the result div
result.innerHTML = '';
// we already have it
if (docs[url]) {
// simply call the callback
done(docs[url]);
}
else {
// create our array for this document
docs[url] = [];
// download and parse the doc
PDFJS.getDocument(url).then(function(pdf) {
PROGRESS.max = pdf.numPages; // just for demo
PROGRESS.value = 1; // just for demo
var currentPage = 1;
// init parsing of first page
if (currentPage <= pdf.numPages) getPage();
// main entry point/function for loop
function getPage() {
// when promise is returned do as usual
pdf.getPage(currentPage).then(function(page) {
var scale = 1.5;
var viewport = page.getViewport(scale);
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
// now, tap into the returned promise from render:
page.render(renderContext).then(function() {
// store compressed image data in array
docs[url].push(canvas.toDataURL());
if (currentPage < pdf.numPages) {
currentPage++;
PROGRESS.value = currentPage; // just for demo
getPage(); // get next page
} else {
done(docs[url]); // call done() when all pages are parsed
}
});
});
}
});
}
}
function done(pages) {
for (var i = 0; i < pages.length; i++) {
drawPage(pages[i], addPage);
}
}
function addPage(img) {
img.style.width = '100px';
img.style.height = '120px';
result.appendChild(img);
}
function drawPage(dataURI, callback) {
var img = new Image;
img.onload = function() {
ctx.drawImage(this, 0, 0, ctx.canvas.width, ctx.canvas.height);
callback(this); // invoke callback when we're done
}
img.src = dataURI; // start loading the data-uri as source
}
#PROGRESS {
width: 100%
}
<script src="https://rawgit.com/mozilla/pdf.js/gh-pages/build/pdf.js"></script>
<button id="btn0">1st Doc</button>
<button id="btn1">2nd Doc</button>
<progress id="PROGRESS" value=0></progress>
<div id="result"></div>

Related

Saving multiple SVGs to canvas with text then getting dataURL

I have built an angularJS application, in this application SVG files represent garments that a user chooses. I have a download button which (currently) saves the first SVG as a PNG into a database and I use a view to display this "preview".
The directive I created looks like this:
.directive('kdExport', function () {
return {
restrict: 'A',
scope: {
target: '#kdExport',
team: '='
},
controller: 'ExportImageController',
link: function (scope, element, attrs, controller) {
console.log(scope.team);
// Bind to the onclick event of our button
element.bind('click', function (e) {
// Prevent the default action
e.preventDefault();
// Generate the image
controller.generateImage(scope.target, scope.team, function (preview) {
// Create our url
var url = '/kits/preview/' + preview.id;
// Open a new window
window.open(url, '_blank');
});
});
}
};
})
and the controller looks like this:
.controller('ExportImageController', ['PreviewService', function (service) {
var self = this;
// Function to remove the hidden layers of an SVG document
var removeHidden = function (element) {
// Get the element children
var children = element.children(),
i = children.length;
// If we have any children
if (children.length) {
// For each child
for (i; i >= 0; i--) {
// Get our child
var child = angular.element(children[i - 1]);
// Remove hidden from the child's children
removeHidden(child);
// Finally, if this child has the class "hidden"
if (child.hasClass("hidden")) {
// Remove the child
child.remove();
}
}
}
};
// Public function to generate the image
self.generateImage = function (element, team, onSuccess) {
// Get our SVG
var target = document.getElementById(element),
container = target.getElementsByClassName('svg-document')[0],
clone = container.cloneNode(true);
// Remove hidden layers
removeHidden(angular.element(clone));
// Create our data
var data = clone.innerHTML,
svg = new Blob([data], { type: 'image/svg+xml;charset=utf-8' });
// Get our context
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
// Create our image
var DOMURL = window.URL || window.webkitURL || window,
url = DOMURL.createObjectURL(svg),
img = new Image();
// When the image has loaded
img.onload = function () {
canvas.width = 1000;
canvas.height = 500;
// Draw our image using the context
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, 1000, 500);
DOMURL.revokeObjectURL(url);
// Get our URL as a base64 string
var dataURL = canvas.toDataURL("image/png");
// Create our model
var model = {
teamName: team.name,
sport: team.sport,
data: dataURL
};
// Create our preview
service.create(model).then(function (response) {
// Invoke our success callback
onSuccess(response);
});
}
// Set the URL of the image
img.src = url;
};
}])
This works fine for a single SVG document, but now the client has asked me to do this for multiple SVGs with a title under each one and they want it all in one PNG.
I have not done a lot of work with canvasing, so I am not sure if this can be done.
Does anyone know how I might achieve this?
Ok, so I figured this out myself using promises.
Basically I created a method called drawImage that allowed me to draw an image for each SVG.
To make sure that all images were drawn before I invoke toDataURL I made the function return a promise and once the image loaded I resolved that promise.
Then I just used a $q.all to get the dataURL and save the data to my database.
The methods looked like this:
// Private function for drawing our images
var drawImage = function (canvas, ctx, clone) {
// Defer our promise
var deferred = $q.defer();
// Create our data
var data = clone.innerHTML,
svg = new Blob([data], { type: 'image/svg+xml;charset=utf-8' });
// Create our image
var DOMURL = window.URL || window.webkitURL || window,
url = DOMURL.createObjectURL(svg),
img = new Image();
// When the image has loaded
img.onload = function () {
// Get our location
getNextLocation(canvas.width, canvas.height, img);
// Draw our image using the context (Only draws half the image because I don't want to show the back)
ctx.drawImage(img, 0, 0, img.width / 2, img.height, location.x, location.y, location.width, location.height);
DOMURL.revokeObjectURL(url);
// Resolve our promise
deferred.resolve();
}
// Set the URL of the image
img.src = url;
// Return our promise
return deferred.promise;
};
// Public function to generate the image
self.generateImage = function (element, team, onSuccess) {
// Get our SVG
var target = document.getElementById('totals'),
containers = angular.element(target.getElementsByClassName('svg-document'));
// Get our context
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
// Set our canvas height and width
canvas.width = 2000;
canvas.height = calculateCanvasHeight(containers.length);
// Create our array of promises
var promises = [];
// For each container
for (var i = 0; i < containers.length; i++) {
// Get our container
var container = containers[i],
clone = container.cloneNode(true);
// Remove hidden layers
removeHidden(angular.element(clone));
// Add our promise to the array
promises.push(drawImage(canvas, ctx, clone));
}
// When all promises have resolve
$q.all(promises).then(function () {
// Get our URL as a base64 string
var dataURL = canvas.toDataURL("image/png");
// Create our model
var model = {
teamName: team.name,
sport: team.sport,
data: dataURL
};
// Create our preview
self.create(model).then(function (response) {
// Invoke our success callback
onSuccess(response);
});
})
};
Obviously there is missing code here, but this code answers my issue, the rest just makes my service work :)

Enable CORS on multiple images at once

I know we can use this code to enable CORS on a single image
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
img.crossOrigin = '';
img.src = 'http://crossdomain.com/image.jpg';
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0, img.width, img.height);
Is there any way to do it for multiple image URLs at once?
URL array
To load several images enabling CORS request, you can use an array which is practical for this purpose.
One thing to be aware of is that requesting CORS can be denied by server. The browser may fail loading the image in those cases so you will need to know in advance if CORS need to be requested or not.
Example loader
var urls = [url1, url2, url3, ...]; // etc. replace with actual URLs
var images = []; // store the loaded images
var i = 0, len = urls.length;
var count = len; // for load and error handlers
for(; i < len; i++) {
var img = new Image();
img.onload = loadHandler;
img.onerror = img.onabort = errorHandler;
img.crossOrigin = ""; // enable CORS request
img.src = urls[i]; // set src last
images.push(img); // store in array
}
function loadHandler() {
if (!--count) callback(); // loading done
}
function errorHandler() {
// handle errors here
loadHandler(); // make sure to update counter/callback
}
function callback() {
// ... ready, continue from here
}
Demo
var urls = [
"http://i.imgur.com/0LINzxs.jpg", // random urls from imgur..
"http://i.imgur.com/6ksiMgS.jpg",
"http://i.imgur.com/aGQSLi9.jpg"
];
var images = []; // store the loaded images
var i = 0, len = urls.length;
var count = len; // for load and error handlers
for(; i < len; i++) {
var img = new Image();
img.onload = loadHandler;
img.onerror = img.onabort = errorHandler;
img.crossOrigin = ""; // enable CORS request
img.src = urls[i]; // set src last
images.push(img); // store in array
}
function loadHandler() {
if (!--count) callback(); // loading done
}
function errorHandler() {
// handle errors here
loadHandler(); // make sure to update
}
function callback() {
// ... ready, continue from here
console.log(images);
var ctx = document.querySelector("canvas").getContext("2d");
ctx.drawImage(images[0], 0, 0);
ctx.drawImage(images[1], 0, 0);
ctx.drawImage(images[2], 0, 0);
console.log(ctx.canvas.toDataURL()); // OK if CORS is OK!
}
<canvas></canvas>
Put the srcs in an array and iterate over them
working fiddle
https://jsfiddle.net/ps50po4z/
This allows you to use multiple images from different sources and display them.
use this function as a template to iterate through all the cors src images
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
function loadImages(sources, callback) {
var images = {};
var loadedImages = 0;
var numImages = 0;
// get num of sources
for(var src in sources) {
numImages++;
}
for(var src in sources) {
images[src] = new Image();
images[src].onload = function() {
if(++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var sources = {
darthVader: 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg',
yoda: 'http://www.html5canvastutorials.com/demos/assets/yoda.jpg'
};
loadImages(sources, function(images) {
context.drawImage(images.darthVader, 100, 30, 200, 137);
context.drawImage(images.yoda, 350, 55, 93, 104);
});
</script>
</body>
</html>

draw image on canvas after load into array

I tried to create an array of Image to be displayed on a canvas, after each image is loaded. No errors, no draw...
var x=...
var y=...
var canvas = document.getElementById(sCanvasName);
var context = canvas.getContext('2d');
var imageCardObj = [];
//vCards contains the images file names
for (var k=0;k<vCards.length;k++){
imageCardObj[k] = new Image();
var func = function(){
var c = arguments[3];
try{
c.drawImage(arguments[0], arguments[1], arguments[2]);
}catch(e){
alert(e.message)
}
}
imageCardObj[k].onload = func(imageCardObj[k], x, y, context);
imageCardObj[k].src = "res/img/"+vCards[k].trim()+".png";
x+=40;
}
You are calling the func() handler and gives the result to it to the image's onload handler. That won't work so well.. and you cannot pass arguments that way to a handler function.
Try this:
var func = function(){
// "this" will be the current image in here
var c = arguments[3];
try{
c.drawImage(this, x, y); // you need to reference x and y
}catch(e){
alert(e.message)
}
}
imageCardObj[k].onload = func; // only a reference here
If you need different x and y's then you need to maintain those on the side, either in an additional array or use objects to embed the image, its intended x and y and use the url to identify the image in question inside the func() callback.
Also note that load order may vary as the last image loaded could finish before the first one so when you draw the image they may not appear in the same order.
You may want to do this instead:
var files = [url1, url2, url, ...],
images = [],
numOfFiles = files.length,
count = numOfFiles;
// function to load all images in one go
function loadImages() {
// go through array of file names
for(var i = 0; i < numOfFiles; i++) {
// create an image element
var img = document.createElement('img');
// use common loader as we need to count files
img.onload = imageLoaded;
//img.onerror = ... handle errors too ...
//img.onabort = ... handle errors too ...
img.src = files[i];
// push image onto array in the same order as file names
images.push(img);
}
}
function imageLoaded(e) {
// for each successful load we count down
count--;
if (count === 0) draw(); //start when all images are loaded
}
Then you can start the drawing after the images has loaded - the images are now in the same order as the original array:
function draw() {
for(var i = 0, img; img = images[i++];)
ctx.drawImage(img, x, y); // or get x and y from an array
}
Hope this helps!
This is the final (working) version
var x=...
var y=...
var canvas = document.getElementById(sCanvasName);
var context = canvas.getContext('2d');
var imageCardObj = [];
for (var k=0;k<vCards.length;k++){
imageCardObj[k] = new Image();
imageCardObj[k].xxx=x;
var func = function(){
try{
context.drawImage(this, this.xxx, yStreet);
}catch(e){
alert(e.message)
}
}
imageCardObj[k].onload = func;
imageCardObj[k].src = 'res/img/'+vCards[k].trim()+".png";
x +=40;

WinJS Low Memory issue with ZXing

I am creating a Barcode scanner module for Windows 8 Metro App.
I some how success with my logic but suddenly I saw my application crash due to low memory issue.
<script>
var canvas = null;
var ctx = null;
var livePreview = null;
var count = 0,rescount=0;
function takepicture() {
var Capture = Windows.Media.Capture;
livePreview = document.getElementById("live-preview");
var mediaCapture = new Capture.MediaCapture();
canvas = document.getElementById("Vcanvas");
ctx=canvas.getContext('2d');
livePreview.addEventListener('play', function () { var i = window.setInterval(function () { ctx.drawImage(livePreview, 0, 0, canvas.width, canvas.height); scanCanvasEasy(); }, 20); }, false);
livePreview.addEventListener('pause', function () { window.clearInterval(i); }, false);
livePreview.addEventListener('ended', function () { clearInterval(i); }, false);
/*
var openPicker = new Windows.Storage.Pickers.FileOpenPicker();
openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.thumbnail;
openPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.videosLibrary;
openPicker.fileTypeFilter.replaceAll([".mp4", ".avi", ".ogg"]);
openPicker.pickSingleFileAsync()
.then(function (file) {
if (file) {
// draw the image
var img = new Image;
//img.onload = function () {
// canvas.width = img.width;
// canvas.height = img.height;
// ctx.drawImage(img, 0, 0, img.width, img.height);
// scanCanvasEasy();
//}
//img.src = URL.createObjectURL(file);
// open a stream from the image
livePreview.src = URL.createObjectURL(file);
livePreview.play();
}
})*/
mediaCapture.initializeAsync().then(function () {
livePreview.src = URL.createObjectURL(mediaCapture);
livePreview.play();
});
}
function scanCanvasEasy() {
var imgd = ctx.getImageData(0, 0,canvas.width,canvas.height);
var pix = imgd.data;
var reader = new ZXing.BarcodeReader();
reader.onresultpointfound = function (resultPoint) {
// do something with the resultpoint location
console.log(resultPoint.toString());
}
// try to decode the raw pixel data
var result = reader.decode(pix, canvas.width, canvas.height, ZXing.BitmapFormat.rgba32);
/*
The above line cause that memory issue, without that line there is no change in memory level.
*/
// show the result
if (result) {
document.getElementById("result").innerText ="Result(+"+rescount++ +")==>"+ result.text;
}
else {
document.getElementById("error").innerText = "no barcode found" + count++;
}
}
</script>
I posted the whole code i used here I Just called the takepicture() method from button click event.
var result = reader.decode(pix, canvas.width, canvas.height, ZXing.BitmapFormat.rgba32);
This line cause memory issue.
Thanks in advance.
var reader = new ZXing.BarcodeReader();
Multiple instance of reader cause this issue. Just created one instance of reader and use it for all subsequent scan will fixed that issue.

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