Added helper module for extracting EXIF; Rotating the processing image according to EXIF orientation; Relates to #121

feature/121
Christoph Oberhofer 9 years ago
parent ee0fec3321
commit 6d5fd9d7ac

4150
dist/quagga.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -35,7 +35,7 @@
<div class="controls">
<fieldset class="input-group">
<input type="file" capture/>
<input type="file" accept="image/*" capture="camera"/>
<button>Rerun</button>
</fieldset>
<fieldset class="reader-config-group">

File diff suppressed because one or more lines are too long

@ -0,0 +1,132 @@
// Scraped from https://github.com/exif-js/exif-js
const ExifTags = {0x0112: "orientation"};
export const AvailableTags = Object.keys(ExifTags).map(key => ExifTags[key]);
export function findTagsInObjectURL(src, tags = AvailableTags) {
if (/^blob\:/i.test(src)) {
return objectURLToBlob(src)
.then(readToBuffer)
.then(buffer => findTagsInBuffer(buffer, tags));
}
return Promise.resolve(null);
}
function readToBuffer(blob) {
return new Promise(resolve => {
const fileReader = new FileReader();
fileReader.onload = function(e) {
return resolve(e.target.result);
};
fileReader.readAsArrayBuffer(blob);
});
}
function objectURLToBlob(url) {
return new Promise(resolve => {
const http = new XMLHttpRequest();
http.open("GET", url, true);
http.responseType = "blob";
http.onload = function() {
if (this.status === 200 || this.status === 0) {
resolve(this.response);
}
};
http.send();
});
}
function findTagsInBuffer(file, selectedTags = AvailableTags) {
const dataView = new DataView(file),
length = file.byteLength,
exifTags = selectedTags.reduce((result, selectedTag) => {
const exifTag = Object.keys(ExifTags).filter(tag => ExifTags[tag] === selectedTag)[0];
if (exifTag) {
result[exifTag] = selectedTag;
}
return result;
}, {});
let offset = 2,
marker;
if ((dataView.getUint8(0) !== 0xFF) || (dataView.getUint8(1) !== 0xD8)) {
return false;
}
while (offset < length) {
if (dataView.getUint8(offset) !== 0xFF) {
return false;
}
marker = dataView.getUint8(offset + 1);
if (marker === 0xE1) {
return readEXIFData(dataView, offset + 4, exifTags);
} else {
offset += 2 + dataView.getUint16(offset + 2);
}
}
}
function readEXIFData(file, start, exifTags) {
if (getStringFromBuffer(file, start, 4) !== "Exif") {
return false;
}
const tiffOffset = start + 6;
let bigEnd,
tags;
if (file.getUint16(tiffOffset) === 0x4949) {
bigEnd = false;
} else if (file.getUint16(tiffOffset) === 0x4D4D) {
bigEnd = true;
} else {
return false;
}
if (file.getUint16(tiffOffset + 2, !bigEnd) !== 0x002A) {
return false;
}
const firstIFDOffset = file.getUint32(tiffOffset + 4, !bigEnd);
if (firstIFDOffset < 0x00000008) {
return false;
}
tags = readTags(file, tiffOffset, tiffOffset + firstIFDOffset, exifTags, bigEnd);
return tags;
}
function readTags(file, tiffStart, dirStart, strings, bigEnd) {
const entries = file.getUint16(dirStart, !bigEnd),
tags = {};
for (let i = 0; i < entries; i++) {
const entryOffset = dirStart + i * 12 + 2,
tag = strings[file.getUint16(entryOffset, !bigEnd)];
if (tag) {
tags[tag] = readTagValue(file, entryOffset, tiffStart, dirStart, bigEnd);
}
}
return tags;
}
function readTagValue(file, entryOffset, tiffStart, dirStart, bigEnd) {
const type = file.getUint16(entryOffset + 2, !bigEnd),
numValues = file.getUint32(entryOffset + 4, !bigEnd);
switch (type) {
case 3:
if (numValues === 1) {
return file.getUint16(entryOffset + 8, !bigEnd);
}
}
}
function getStringFromBuffer(buffer, start, length) {
let outstr = "";
for (let n = start; n < start + length; n++) {
outstr += String.fromCharCode(buffer.getUint8(n));
}
return outstr;
}

@ -4,6 +4,23 @@ import {
computeGray
} from '../common/cv_utils';
const TO_RADIANS = Math.PI / 180;
function adjustCanvasSize(canvas, targetSize) {
if (canvas.width !== targetSize.x) {
if (ENV.development) {
console.log("WARNING: canvas-size needs to be adjusted");
}
canvas.width = targetSize.x;
}
if (canvas.height !== targetSize.y) {
if (ENV.development) {
console.log("WARNING: canvas-size needs to be adjusted");
}
canvas.height = targetSize.y;
}
}
var FrameGrabber = {};
FrameGrabber.create = function(inputStream, canvas) {
@ -54,9 +71,35 @@ FrameGrabber.create = function(inputStream, canvas) {
_that.grab = function() {
var doHalfSample = _streamConfig.halfSample,
frame = inputStream.getFrame(),
drawable = frame,
drawAngle = 0,
ctxData;
if (frame) {
_ctx.drawImage(frame, 0, 0, _canvasSize.x, _canvasSize.y);
if (drawable) {
adjustCanvasSize(_canvas, _canvasSize);
if (_streamConfig.type === 'ImageStream') {
drawable = frame.img;
if (frame.tags && frame.tags.orientation) {
switch (frame.tags.orientation) {
case 6:
drawAngle = 90 * TO_RADIANS;
break;
case 8:
drawAngle = -90 * TO_RADIANS;
break;
}
}
}
if (drawAngle !== 0) {
_ctx.translate(_canvasSize.x / 2, _canvasSize.y / 2);
_ctx.rotate(drawAngle);
_ctx.drawImage(drawable, -_canvasSize.y / 2, -_canvasSize.x / 2, _canvasSize.y, _canvasSize.x);
_ctx.rotate(-drawAngle);
_ctx.translate(-_canvasSize.x / 2, -_canvasSize.y / 2);
} else {
_ctx.drawImage(drawable, 0, 0, _canvasSize.x, _canvasSize.y);
}
ctxData = _ctx.getImageData(_sx, _sy, _size.x, _size.y).data;
if (doHalfSample){
grayAndHalfSampleFromCanvasData(ctxData, _size, _data);

@ -1,3 +1,5 @@
import {findTagsInObjectURL} from './exif_helper';
var ImageLoader = {};
ImageLoader.load = function(directory, callback, offset, size, sequence) {
var htmlImagesSrcArray = new Array(size),
@ -26,7 +28,7 @@ ImageLoader.load = function(directory, callback, offset, size, sequence) {
for (var y = 0; y < htmlImagesSrcArray.length; y++) {
var imgName = htmlImagesSrcArray[y].substr(htmlImagesSrcArray[y].lastIndexOf("/"));
if (loadedImg.src.lastIndexOf(imgName) !== -1) {
htmlImagesArray[y] = loadedImg;
htmlImagesArray[y] = {img: loadedImg};
break;
}
}
@ -37,7 +39,18 @@ ImageLoader.load = function(directory, callback, offset, size, sequence) {
if (ENV.development) {
console.log("Images loaded");
}
callback.apply(null, [htmlImagesArray]);
if (sequence === false) {
findTagsInObjectURL(directory, ['orientation'])
.then(tags => {
htmlImagesArray[0].tags = tags;
callback(htmlImagesArray);
}).catch(e => {
console.log(e);
callback(htmlImagesArray);
});
} else {
callback(htmlImagesArray);
}
}
};

@ -176,8 +176,21 @@ InputStream.createImageStream = function() {
loaded = false;
ImageLoader.load(baseUrl, function(imgs) {
imgArray = imgs;
width = imgs[0].width;
height = imgs[0].height;
if (imgs[0].tags && imgs[0].tags.orientation) {
switch (imgs[0].tags.orientation) {
case 6:
case 8:
width = imgs[0].img.height;
height = imgs[0].img.width;
break;
default:
width = imgs[0].img.width;
height = imgs[0].img.height;
}
} else {
width = imgs[0].img.width;
height = imgs[0].img.height;
}
calculatedWidth =
_config.size ? width / height > 1 ? _config.size : Math.floor((width / height) * _config.size) : width;
calculatedHeight =

Loading…
Cancel
Save