Skip to content
Browse files

Added automatic image resizing functionality.

Greatly improved the browser responsiveness when loading the preview images.
1 parent c4a615a commit e39278b08f3b7dd8f927ce61d09060b1ee6fd383 @blueimp committed Feb 12, 2012
Showing with 278 additions and 65 deletions.
  1. +3 −1 README.md
  2. +10 −0 css/jquery.fileupload-ui.css
  3. BIN img/loading.gif
  4. +9 −2 index.html
  5. +158 −0 js/jquery.fileupload-ip.js
  6. +88 −57 js/jquery.fileupload-ui.js
  7. +4 −2 js/main.js
  8. +6 −3 package.json
View
4 README.md
@@ -20,8 +20,10 @@
Aborted uploads can be resumed with browsers supporting the Blob API.
* **Chunked uploads:**
Large files can be uploaded in smaller chunks with browsers supporting the Blob API.
+* **Automatic image resizing:**
+ Images can be automatically resized with browsers supporting the required JS APIs.
* **Preview images:**
- A preview of image files can be displayed before uploading with browsers supporting the required HTML5 APIs.
+ A preview of image files can be displayed before uploading with browsers supporting the required JS APIs.
* **No browser plugins (e.g. Adobe Flash) required:**
The implementation is based on open standards like HTML5 and JavaScript and requires no additional browser plugins.
* **Graceful fallback for legacy browsers:**
View
10 css/jquery.fileupload-ui.css
@@ -40,6 +40,16 @@
background: url(../img/progressbar.gif) !important;
filter: none;
}
+.fileupload-loading {
+ position: absolute;
+ left: 50%;
+ width: 128px;
+ height: 0;
+ background: url(../img/loading.gif) center no-repeat;
+}
+.fileupload-processing .fileupload-loading {
+ height: 128px;
+}
/* Fix for IE 6: */
*html .fileinput-button {
View
BIN img/loading.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
11 index.html
@@ -1,7 +1,7 @@
<!DOCTYPE HTML>
<!--
/*
- * jQuery File Upload Plugin Demo 6.2
+ * jQuery File Upload Plugin Demo 6.4
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
@@ -92,6 +92,8 @@
</div>
</div>
</div>
+ <!-- The loading indicator is shown during image processing -->
+ <div class="fileupload-loading"></div>
<br>
<!-- The table listing the files available for upload/download -->
<table class="table table-striped"><tbody class="files" data-toggle="modal-gallery" data-target="#modal-gallery"></tbody></table>
@@ -194,16 +196,21 @@ <h3 class="modal-title"></h3>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
<script src="js/vendor/jquery.ui.widget.js"></script>
-<!-- The Templates and Load Image plugins are included for the FileUpload user interface -->
+<!-- The Templates plugin is included to render the upload/download listings -->
<script src="http://blueimp.github.com/JavaScript-Templates/tmpl.min.js"></script>
+<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
<script src="http://blueimp.github.com/JavaScript-Load-Image/load-image.min.js"></script>
+<!-- The Canvas to Blob plugin is included for image resizing functionality -->
+<script src="http://blueimp.github.com/JavaScript-Canvas-to-Blob/canvas-to-blob.min.js"></script>
<!-- Bootstrap JS and Bootstrap Image Gallery are not required, but included for the demo -->
<script src="http://blueimp.github.com/cdn/js/bootstrap.min.js"></script>
<script src="http://blueimp.github.com/Bootstrap-Image-Gallery/bootstrap-image-gallery.min.js"></script>
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
<script src="js/jquery.iframe-transport.js"></script>
<!-- The basic File Upload plugin -->
<script src="js/jquery.fileupload.js"></script>
+<!-- The File Upload image processing plugin -->
+<script src="js/jquery.fileupload-ip.js"></script>
<!-- The File Upload user interface plugin -->
<script src="js/jquery.fileupload-ui.js"></script>
<!-- The main application script -->
View
158 js/jquery.fileupload-ip.js
@@ -0,0 +1,158 @@
+/*
+ * jQuery File Upload Image Processing Plugin 1.0
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2012, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * http://www.opensource.org/licenses/MIT
+ */
+
+/*jslint nomen: true, unparam: true, regexp: true */
+/*global define, window, document */
+
+(function (factory) {
+ 'use strict';
+ if (typeof define === 'function' && define.amd) {
+ // Register as an anonymous AMD module:
+ define([
+ 'jquery',
+ './load-image.js',
+ './canvas-to-blob.js',
+ './jquery.fileupload.js'
+ ], factory);
+ } else {
+ // Browser globals:
+ factory(
+ window.jQuery,
+ window.loadImage,
+ window.canvasToBlob
+ );
+ }
+}(function ($, loadImage, canvasToBlob) {
+ 'use strict';
+
+ // The File Upload IP version extends the basic fileupload widget
+ // with image processing functionality:
+ $.widget('blueimpIP.fileupload', $.blueimp.fileupload, {
+
+ options: {
+ // The regular expression to define which image files are to be
+ // resized, given that the browser supports the operation:
+ resizeSourceFileTypes: /^image\/(gif|jpeg|png)$/,
+ // The maximum file size of images that are to be resized:
+ resizeSourceMaxFileSize: 20000000, // 20MB
+ // The maximum width of the resized images:
+ resizeMaxWidth: undefined,
+ // The maximum height of the resized images:
+ resizeMaxHeight: undefined,
+ // The minimum width of the resized images:
+ resizeMinWidth: undefined,
+ // The minimum height of the resized images:
+ resizeMinHeight: undefined,
+
+ // The add callback is invoked as soon as files are added to the fileupload
+ // widget (via file input selection, drag & drop or add API call).
+ // See the basic file upload widget for more information:
+ add: function (e, data) {
+ $(this).fileupload('resize', data).done(function () {
+ data.submit();
+ });
+ }
+ },
+
+ // Resizes the image file at the given index and stores the created blob
+ // at the original position of the files list, returns a Promise object:
+ _resizeImage: function (files, index) {
+ var that = this,
+ options = this.options,
+ file = files[index],
+ deferred = $.Deferred(),
+ canvas,
+ blob;
+ loadImage(
+ file,
+ function (img) {
+ var width = img.width,
+ height = img.height;
+ canvas = loadImage.scale(img, {
+ maxWidth: options.resizeMaxWidth,
+ maxHeight: options.resizeMaxHeight,
+ minWidth: options.resizeMinWidth,
+ minHeight: options.resizeMinHeight,
+ canvas: true
+ });
+ if (width !== canvas.width || height !== canvas.height) {
+ canvasToBlob(canvas, function (blob) {
+ if (!blob.name) {
+ if (file.type === blob.type) {
+ blob.name = file.name;
+ } else if (file.name) {
+ blob.name = file.name.replace(
+ /\..+$/,
+ '.' + blob.type.substr(6)
+ );
+ }
+ }
+ files[index] = blob;
+ deferred.resolve();
+ }, file);
+ } else {
+ deferred.resolve();
+ }
+ }
+ );
+ return deferred.promise();
+ },
+
+ // Resizes the images given as files property of the data parameter,
+ // returns a Promise object that allows to bind a done handler, which
+ // will be invoked after processing all images is done:
+ resize: function (data) {
+ var that = this,
+ options = $.extend({}, this.options, data),
+ resizeAll = $.type(options.resizeSourceMaxFileSize) !== 'number';
+ $.each(data.files, function (index, file) {
+ if (that._resizeSupport &&
+ (options.resizeMaxWidth || options.resizeMaxHeight ||
+ options.resizeMinWidth || options.resizeMinHeight) &&
+ (resizeAll || file.size < options.resizeSourceMaxFileSize) &&
+ options.resizeSourceFileTypes.test(file.type)) {
+ that._processing += 1;
+ if (that._processing === 1) {
+ that.element.addClass('fileupload-processing');
+ }
+ that._processingQueue = that._processingQueue.pipe(function () {
+ var deferred = $.Deferred();
+ that._resizeImage(
+ data.files,
+ index
+ ).done(function () {
+ that._processing -= 1;
+ if (that._processing === 0) {
+ that.element
+ .removeClass('fileupload-processing');
+ }
+ deferred.resolve();
+ });
+ return deferred.promise();
+ });
+ }
+ });
+ return this._processingQueue;
+ },
+
+ _create: function () {
+ $.blueimp.fileupload.prototype._create.call(this);
+ this._processing = 0;
+ this._processingQueue = $.Deferred().resolveWith(this).promise();
+ this._resizeSupport = canvasToBlob(
+ document.createElement('canvas'),
+ $.noop
+ );
+ }
+
+ });
+
+}));
View
145 js/jquery.fileupload-ui.js
@@ -1,5 +1,5 @@
/*
- * jQuery File Upload User Interface Plugin 6.3
+ * jQuery File Upload User Interface Plugin 6.4
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
@@ -16,18 +16,26 @@
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
- define(['jquery', 'tmpl', 'loadImage', './jquery.fileupload.js'], factory);
+ define([
+ 'jquery',
+ './tmpl.js',
+ './load-image.js',
+ './jquery.fileupload-ip.js'
+ ], factory);
} else {
// Browser globals:
- factory(window.jQuery, window.tmpl, window.loadImage);
+ factory(
+ window.jQuery,
+ window.tmpl,
+ window.loadImage
+ );
}
}(function ($, tmpl, loadImage) {
'use strict';
- // The UI version extends the basic fileupload widget and adds
- // a complete user interface based on the given upload/download
- // templates.
- $.widget('blueimpUI.fileupload', $.blueimp.fileupload, {
+ // The UI version extends the IP (image processing) version and adds
+ // complete user interface interaction:
+ $.widget('blueimpUI.fileupload', $.blueimpIP.fileupload, {
options: {
// By default, files added to the widget are uploaded as soon
@@ -46,9 +54,9 @@
acceptFileTypes: /.+$/i,
// The regular expression to define for which files a preview
// image is shown, matched against the file type:
- previewFileTypes: /^image\/(gif|jpeg|png)$/,
- // The maximum file size for preview images:
- previewMaxFileSize: 5000000, // 5MB
+ previewSourceFileTypes: /^image\/(gif|jpeg|png)$/,
+ // The maximum file size of images that are to be displayed as preview:
+ previewSourceMaxFileSize: 5000000, // 5MB
// The maximum width of the preview images:
previewMaxWidth: 80,
// The maximum height of the preview images:
@@ -66,25 +74,28 @@
// See the basic file upload widget for more information:
add: function (e, data) {
var that = $(this).data('fileupload'),
+ options = that.options,
files = data.files;
- that._adjustMaxNumberOfFiles(-files.length);
- data.isAdjusted = true;
- data.files.valid = data.isValidated = that._validate(files);
- data.context = that._renderUpload(files)
- .appendTo(that._files)
- .data('data', data);
- // Force reflow:
- that._reflow = $.support.transition && data.context[0].offsetWidth;
- that._transitionCallback(
- data.context.addClass('in'),
- function (node) {
- if ((that._trigger('added', e, data) !== false) &&
- (that.options.autoUpload || data.autoUpload) &&
- data.isValidated) {
- data.submit();
+ $(this).fileupload('resize', data).done(data, function () {
+ that._adjustMaxNumberOfFiles(-files.length);
+ data.isAdjusted = true;
+ data.files.valid = data.isValidated = that._validate(files);
+ data.context = that._renderUpload(files)
+ .appendTo(that._files)
+ .data('data', data);
+ // Force reflow:
+ that._reflow = $.support.transition && data.context[0].offsetWidth;
+ that._transitionCallback(
+ data.context.addClass('in'),
+ function (node) {
+ if ((that._trigger('added', e, data) !== false) &&
+ (options.autoUpload || data.autoUpload) &&
+ data.isValidated) {
+ data.submit();
+ }
}
- }
- );
+ );
+ });
},
// Callback for the start of each file upload request:
send: function (e, data) {
@@ -358,33 +369,53 @@
})).children();
},
- _renderUpload: function (files) {
+ _renderPreview: function (file, node, callback) {
var that = this,
- options = this.options,
- nodes = this._renderTemplate(options.uploadTemplate, files);
- nodes.find('.preview span').each(function (index, node) {
- var file = files[index];
- if (options.previewFileTypes.test(file.type) &&
- (!options.previewMaxFileSize ||
- file.size < options.previewMaxFileSize)) {
- loadImage(
- files[index],
- function (img) {
- $(node).append(img);
- // Force reflow:
- that._reflow = $.support.transition &&
- node.offsetWidth;
- $(node).addClass('in');
- },
- {
- maxWidth: options.previewMaxWidth,
- maxHeight: options.previewMaxHeight,
- canvas: options.previewAsCanvas
- }
+ options = this.options;
+ loadImage(
+ file,
+ function (img) {
+ node.append(img);
+ // Force reflow:
+ that._reflow = $.support.transition &&
+ node[0].offsetWidth;
+ that._transitionCallback(
+ node.addClass('in'),
+ callback || $.noop
);
+ },
+ {
+ maxWidth: options.previewMaxWidth,
+ maxHeight: options.previewMaxHeight,
+ canvas: options.previewAsCanvas
}
- });
- return nodes;
+ );
+ },
+
+ _renderUpload: function (files) {
+ var that = this,
+ options = this.options;
+ return this._renderTemplate(options.uploadTemplate, files)
+ .each(function (index, element) {
+ var file = files[index],
+ node = $(element),
+ previewNode = node.find('.preview span'),
+ hasPreview = previewNode.length &&
+ ($.type(options.previewSourceMaxFileSize) !== 'number' ||
+ file.size < options.previewSourceMaxFileSize) &&
+ options.previewSourceFileTypes.test(file.type);
+ if (hasPreview) {
+ that._processingQueue = that._processingQueue.pipe(function () {
+ var deferred = $.Deferred();
+ that._renderPreview(
+ file,
+ previewNode,
+ deferred.resolve
+ );
+ return deferred.promise();
+ });
+ }
+ });
},
_renderDownload: function (files) {
@@ -485,7 +516,7 @@
},
_initEventHandlers: function () {
- $.blueimp.fileupload.prototype._initEventHandlers.call(this);
+ $.blueimpIP.fileupload.prototype._initEventHandlers.call(this);
var eventData = {fileupload: this};
this._files
.delegate(
@@ -515,7 +546,7 @@
.undelegate('.start button', 'click.' + this.options.namespace)
.undelegate('.cancel button', 'click.' + this.options.namespace)
.undelegate('.delete button', 'click.' + this.options.namespace);
- $.blueimp.fileupload.prototype._destroyEventHandlers.call(this);
+ $.blueimpIP.fileupload.prototype._destroyEventHandlers.call(this);
},
_enableFileInputButton: function () {
@@ -544,24 +575,24 @@
_create: function () {
this._initFiles();
- $.blueimp.fileupload.prototype._create.call(this);
+ $.blueimpIP.fileupload.prototype._create.call(this);
this._initTemplates();
},
destroy: function () {
- $.blueimp.fileupload.prototype.destroy.call(this);
+ $.blueimpIP.fileupload.prototype.destroy.call(this);
},
enable: function () {
- $.blueimp.fileupload.prototype.enable.call(this);
+ $.blueimpIP.fileupload.prototype.enable.call(this);
this.element.find('input, button').prop('disabled', false);
this._enableFileInputButton();
},
disable: function () {
this.element.find('input, button').prop('disabled', true);
this._disableFileInputButton();
- $.blueimp.fileupload.prototype.disable.call(this);
+ $.blueimpIP.fileupload.prototype.disable.call(this);
}
});
View
6 js/main.js
@@ -1,5 +1,5 @@
/*
- * jQuery File Upload Plugin JS Example 6.3
+ * jQuery File Upload Plugin JS Example 6.4
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
@@ -23,7 +23,9 @@ $(function () {
$('#fileupload').fileupload('option', {
url: '//jquery-file-upload.appspot.com/',
maxFileSize: 5000000,
- acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i
+ acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
+ resizeMaxWidth: 1920,
+ resizeMaxHeight: 1200
});
// Upload server status check for browsers with CORS support:
if ($.ajaxSettings.xhr().withCredentials !== undefined) {
View
9 package.json
@@ -1,6 +1,6 @@
{
"name": "blueimp-file-upload",
- "version": "6.3.0",
+ "version": "6.4.0",
"title": "jQuery File Upload",
"description": "File Upload widget with multiple file selection, drag&drop support, progress bar and preview images for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.",
"keywords": [
@@ -49,14 +49,17 @@
"dependencies": {
"jquery": ">=1.6",
"jquery.ui.widget": ">=1.8",
+ "blueimp-tmpl": ">=1.0.2",
"blueimp-load-image": ">=1.1.4",
- "blueimp-tmpl": ">=1.0.2"
+ "blueimp-canvas-to-blob": ">=1.0.1"
},
"files": [
"js/jquery.iframe-transport.js",
"js/jquery.fileupload.js",
+ "js/jquery.fileupload-ip.js",
"js/jquery.fileupload-ui.js",
"css/jquery.fileupload-ui.css",
- "img/progressbar.gif"
+ "img/progressbar.gif",
+ "img/loading.gif"
]
}

0 comments on commit e39278b

Please sign in to comment.
Something went wrong with that request. Please try again.