Skip to content

Commit 921c816

Browse files
committed
Retain EXIF and ICC headers with client-side image processing. Closes blueimp#1207.
Use Exif data thumbnails if available, which increases UI performance largely when displaying thumbnails of large image files.
1 parent 69224bb commit 921c816

File tree

1 file changed

+82
-9
lines changed

1 file changed

+82
-9
lines changed

js/jquery.fileupload-image.js

Lines changed: 82 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* jQuery File Upload Image Preview & Resize Plugin 1.0
2+
* jQuery File Upload Image Preview & Resize Plugin 1.1
33
* https://github.com/blueimp/jQuery-File-Upload
44
*
55
* Copyright 2013, Sebastian Tschan
@@ -10,7 +10,7 @@
1010
*/
1111

1212
/*jslint nomen: true, unparam: true, regexp: true */
13-
/*global define, window */
13+
/*global define, window, document, DataView, Blob, Uint8Array */
1414

1515
(function (factory) {
1616
'use strict';
@@ -44,6 +44,15 @@
4444
noRevoke: '@loadImageNoRevoke',
4545
disabled: '@disableImageLoad'
4646
},
47+
{
48+
action: 'loadImageMetaData',
49+
disabled: '@disableImageMetaDataLoad',
50+
disableImageHead: '@disableImageHead',
51+
disableExif: '@disableExif',
52+
disableExifThumbnail: '@disableExifThumbnail',
53+
disableExifSub: '@disableExifSub',
54+
disableExifGps: '@disableExifGps'
55+
},
4756
{
4857
action: 'resizeImage',
4958
maxWidth: '@imageMaxWidth',
@@ -57,13 +66,19 @@
5766
action: 'saveImage',
5867
disabled: '@disableImageResize'
5968
},
69+
{
70+
action: 'saveImageMetaData',
71+
disabled: '@disableImageMetaDataSave'
72+
},
6073
{
6174
action: 'resizeImage',
6275
maxWidth: '@previewMaxWidth',
6376
maxHeight: '@previewMaxHeight',
6477
minWidth: '@previewMinWidth',
6578
minHeight: '@previewMinHeight',
6679
crop: '@previewCrop',
80+
orientation: '@previewOrientation',
81+
thumbnail: '@previewThumbnail',
6782
canvas: '@previewAsCanvas',
6883
disabled: '@disableImagePreview'
6984
},
@@ -96,6 +111,11 @@
96111
previewMaxWidth: 80,
97112
// The maximum height of the preview images:
98113
previewMaxHeight: 80,
114+
// Defines the preview orientation (1-8) or takes the orientation
115+
// value from Exif data if set to true:
116+
previewOrientation: true,
117+
// Create the preview using the Exif data thumbnail:
118+
previewThumbnail: true,
99119
// Define if preview images should be cropped or only scaled:
100120
previewCrop: false,
101121
// Define if preview images should be resized as canvas elements:
@@ -140,14 +160,38 @@
140160
// Accepts the options maxWidth, maxHeight, minWidth,
141161
// minHeight, canvas and crop:
142162
resizeImage: function (data, options) {
163+
if (options.disabled) {
164+
return data;
165+
}
166+
var that = this,
167+
dfd = $.Deferred(),
168+
resolve = function (newImg) {
169+
data[newImg.getContext ? 'canvas' : 'img'] = newImg;
170+
dfd.resolveWith(that, [data]);
171+
},
172+
thumbnail,
173+
img,
174+
newImg;
143175
options = $.extend({canvas: true}, options);
144-
var img = (options.canvas && data.canvas) || data.img,
145-
canvas;
146-
if (img && !options.disabled) {
147-
canvas = loadImage.scale(img, options);
148-
if (canvas && (canvas.width !== img.width ||
149-
canvas.height !== img.height)) {
150-
data[canvas.getContext ? 'canvas' : 'img'] = canvas;
176+
if (data.exif) {
177+
if (options.orientation === true) {
178+
options.orientation = data.exif.get('Orientation');
179+
}
180+
if (options.thumbnail) {
181+
thumbnail = data.exif.get('Thumbnail');
182+
if (thumbnail) {
183+
loadImage(thumbnail, resolve, options);
184+
return dfd.promise();
185+
}
186+
}
187+
}
188+
img = (options.canvas && data.canvas) || data.img;
189+
if (img) {
190+
newImg = loadImage.scale(img, options);
191+
if (newImg.width !== img.width ||
192+
newImg.height !== img.height) {
193+
resolve(newImg);
194+
return dfd.promise();
151195
}
152196
}
153197
return data;
@@ -196,6 +240,35 @@
196240
return dfd.promise();
197241
},
198242

243+
loadImageMetaData: function (data, options) {
244+
if (options.disabled) {
245+
return data;
246+
}
247+
var that = this,
248+
dfd = $.Deferred();
249+
loadImage.parseMetaData(data.files[data.index], function (result) {
250+
$.extend(data, result);
251+
dfd.resolveWith(that, [data]);
252+
}, options);
253+
return dfd.promise();
254+
},
255+
256+
saveImageMetaData: function (data, options) {
257+
if (!data.imageHead || options.disabled) {
258+
return data;
259+
}
260+
var file = data.files[data.index],
261+
blob = new Blob([
262+
data.imageHead,
263+
// Resized images always have a head size of 20,
264+
// including the JPEG marker and a minimal JFIF header:
265+
this._blobSlice.call(file, 20)
266+
], {type: file.type});
267+
blob.name = file.name;
268+
data.files[data.index] = blob;
269+
return data;
270+
},
271+
199272
// Sets the resized version of the image as a property of the
200273
// file object, must be called after "saveImage":
201274
setImage: function (data, options) {

0 commit comments

Comments
 (0)