Updated 22/02/2015 to detail the iPhone 6 experience)
(This post covers something I was pretty sure wouldn’t work, so I’m rather pleased to be writing about the solution)
As part of my Ticket to Ride Dreamforce session, I built a mobile application that scanned a QR code and retrieved some information from Salesforce. I’ve been trying to figure out since then how I can do the same thing in Salesforce1.
The mobile application used the Google Zebra Crossing (zxing) Cordova plugin, but I don’t have the capability to add plugins to Salesforce1 so that wasn’t an option. Most solutions I’ve looked into rely on capturing a QR code, uploading to a server and receiving a response containing the decoded value. I got this working using a combination of Salesforce1 and Node.js, but its a pretty awful user experience, and I really wouldn’t want to use this mechanism when I was connecting over 3G.
Some googling led me to jsqrcode, a port of zxing to JavaScript, which sounded exactly what I was looking for. This processes a captured image client side (or server side, if you use the equivalent node.js package). Hence the title of this post is “Reading” rather than “Scanning”. The problem with this approach is it is far slower and more error prone than scanning, as you are into a capture, try to scan, repeat if fail loop rather than re-orienting the device until it can scan the code. So why do it, I hear you ask? The big upside is that you remain in the Salesforce1 application. Thus, while using a third party application (or using the mobile SDK to build my own) improves the scanning user experience and the likelihood of success, the best I can do is send the user to a Salesforce URL in the browser afterwards, as Salesforce1 doesn’t have a URL scheme aside from the chatter functionality.
My experiments with jsqrcode indicate that capturing an image and processing it on a phone just doesn’t work. I suspect this is a combination of the size of the images captured (3000x2000 pixels) and the lack of processing power on the device. I’ve tried reducing the size of the image that the library processes, but due to the way that they are prepared for processing (written to a fixed size canvas) the image is downscaled which also causes a problem. The same images can be processed okay on an iPad or desktop, which leads me to believe the processing power is the bigger issue. If you really need to do this then sending the image back to the server is the only way I’ve found that works. Update: 22/02/2015 - trying this on an iPhone 6 with a QR code emailed as an image works fine, so it looks like the processing power was the problem. It still seems pretty flaky when taking a picture though.
I first created a QR code that when decoded gives the id of a Salesforce record. I then downloaded the zip of the jsqrcode plugin and uploaded this to Salesforce as a static resource and added the various JavaScript files in the order mandated on the site:
<script type="text/javascript"
src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="{!URLFOR($Resource.QRCode, 'jsqrcode-master/src/grid.js')}"></script>
<script type="text/javascript" src="{!URLFOR($Resource.QRCode, 'jsqrcode-master/src/version.js')}"></script>
<script type="text/javascript" src="{!URLFOR($Resource.QRCode, 'jsqrcode-master/src/detector.js')}"></script>
<script type="text/javascript" src="{!URLFOR($Resource.QRCode, 'jsqrcode-master/src/formatinf.js')}"></script>
<script type="text/javascript" src="{!URLFOR($Resource.QRCode, 'jsqrcode-master/src/errorlevel.js')}"></script>
<script type="text/javascript" src="{!URLFOR($Resource.QRCode, 'jsqrcode-master/src/bitmat.js')}"></script>
<script type="text/javascript" src="{!URLFOR($Resource.QRCode, 'jsqrcode-master/src/datablock.js')}"></script>
<script type="text/javascript" src="{!URLFOR($Resource.QRCode, 'jsqrcode-master/src/bmparser.js')}"></script>
<script type="text/javascript" src="{!URLFOR($Resource.QRCode, 'jsqrcode-master/src/datamask.js')}"></script>
<script type="text/javascript" src="{!URLFOR($Resource.QRCode, 'jsqrcode-master/src/rsdecoder.js')}"></script>
<script type="text/javascript" src="{!URLFOR($Resource.QRCode, 'jsqrcode-master/src/gf256poly.js')}"></script>
<script type="text/javascript" src="{!URLFOR($Resource.QRCode, 'jsqrcode-master/src/gf256.js')}"></script>
<script type="text/javascript" src="{!URLFOR($Resource.QRCode, 'jsqrcode-master/src/decoder.js')}"></script>
<script type="text/javascript" src="{!URLFOR($Resource.QRCode, 'jsqrcode-master/src/qrcode.js')}"></script>
<script type="text/javascript" src="{!URLFOR($Resource.QRCode, 'jsqrcode-master/src/findpat.js')}"></script>
<script type="text/javascript" src="{!URLFOR($Resource.QRCode, 'jsqrcode-master/src/alignpat.js')}"></script>
<script type="text/javascript" src="{!URLFOR($Resource.QRCode, 'jsqrcode-master/src/databr.js')}"></script>
I then have a simple form with JavaScript functions attached to the buttons:
<form>
<input type="file" onchange="previewFile()" /><br/>
<h1>Preview</h1>
<div style="height:200px">
<img src="" id="preview" height="200" alt="Image preview..." />
</div>
</form>
<p>If the image above looks clear, click the decode button. If not, try again!</p>
<button id="decode" onclick="decode()">Decode</button>
Upon first loading the page, a callback is registered with jsqrcode to alert the result of the code and then redirect to the record matching the id, using the sforce.one JavaScript object if it is available, otherwise using the standard UI URL:
function read(a)
{
alert(a);
if( (typeof sforce != 'undefined') && (sforce != null) ) {
sforce.one.navigateToSObject(a);
}
else {
window.location="/" + a;
}
}
$(document).ready(function() {
qrcode.callback = read;
});
When the user takes a picture via the file input, the following JavaScript produces a preview:
function previewFile() {
var preview = document.querySelector('#preview');
var file = document.querySelector('input[type=file]').files[0];
var reader = new FileReader();
reader.onloadend = function () {
preview.src = reader.result;
}
if (file) {
reader.readAsDataURL(file);
} else {
preview.src = "";
}
}
and if the code looks clear enough, clicking the decode button executes the jsqrcode decode function using the source of the image preview:
function decode() {
try
{
var preview=document.querySelector('#preview');
qrcode.decode(preview.src);
}
catch (e)
{
alert('Error - ' + e);
}
}
The full page is available at this gist, and here are some screen shots of it in action:

Clicking the button to choose a file allows me to capture a new image or pick one already on my iPad:

I choose to capture an image that is being displayed on my macbook air which renders into the preview section:

And if I’m happy with it, I can press the button to decode. This takes a couple of seconds and then, all things being equal, I’m taken to the record:

If there’s a problem, I’ll receive an alert and I can can have another go. I’ve been pleasantly surprised by how well the codes can be processed - I managed to scan my Dreamforce badge without any issues!
Finally, take a step back and appreciate what has been done here - an image has been captured from the device, previewed, and the contained QR code decoded, all on the client in HTML5 and JavaScript. I think that’s pretty amazing and I’m continually impressed by how much more can be done these days without resorting to server side code.