s3_cors_fileupload 0.1.5 → 0.2.0.pre1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.document +4 -3
- data/.gitignore +3 -7
- data/CHANGELOG.md +9 -1
- data/Gemfile +11 -11
- data/Gemfile.lock +66 -74
- data/README.md +4 -3
- data/Rakefile +7 -9
- data/lib/generators/s3_cors_fileupload/install/templates/s3_uploads.js +16 -22
- data/lib/generators/s3_cors_fileupload/install/templates/s3_uploads_controller.rb +1 -1
- data/lib/generators/s3_cors_fileupload/install/templates/source_file.rb +2 -2
- data/lib/generators/s3_cors_fileupload/install/templates/views/erb/_template_download.html.erb +2 -2
- data/lib/generators/s3_cors_fileupload/install/templates/views/erb/_template_upload.html.erb +4 -4
- data/lib/generators/s3_cors_fileupload/install/templates/views/erb/_template_uploaded.html.erb +1 -1
- data/lib/generators/s3_cors_fileupload/install/templates/views/erb/index.html.erb +2 -2
- data/lib/generators/s3_cors_fileupload/install/templates/views/haml/_template_download.html.haml +2 -2
- data/lib/generators/s3_cors_fileupload/install/templates/views/haml/_template_upload.html.haml +4 -4
- data/lib/generators/s3_cors_fileupload/install/templates/views/haml/_template_uploaded.html.haml +2 -2
- data/lib/generators/s3_cors_fileupload/install/templates/views/haml/index.html.haml +2 -2
- data/lib/s3_cors_fileupload/rails/config.rb +0 -1
- data/lib/s3_cors_fileupload/rails/form_helper.rb +2 -4
- data/lib/s3_cors_fileupload/rails/policy_helper.rb +2 -2
- data/lib/s3_cors_fileupload/version.rb +3 -3
- data/s3_cors_fileupload.gemspec +12 -15
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/amazon_s3.yml +17 -0
- data/spec/dummy/config/application.rb +64 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/db/.gitkeep +0 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/lib/generators/install/install_generator_spec.rb +160 -0
- data/spec/lib/s3_cors_fileupload/rails/config_spec.rb +43 -0
- data/spec/{s3_cors_fileupload → lib/s3_cors_fileupload}/version_spec.rb +0 -0
- data/spec/spec_helper.rb +11 -2
- data/vendor/assets/javascripts/s3_cors_fileupload/jquery.fileupload-ui.js +117 -43
- data/vendor/assets/javascripts/s3_cors_fileupload/jquery.fileupload.js +187 -92
- data/vendor/assets/javascripts/s3_cors_fileupload/jquery.iframe-transport.js +20 -7
- data/vendor/assets/javascripts/s3_cors_fileupload/vendor/jquery.ui.widget.js +72 -53
- data/vendor/assets/javascripts/s3_cors_fileupload/vendor/load-image.js +225 -37
- data/vendor/assets/stylesheets/jquery.fileupload-ui.css.erb +6 -8
- metadata +78 -21
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
* jQuery Iframe Transport Plugin 1.
|
2
|
+
* jQuery Iframe Transport Plugin 1.6.1
|
3
3
|
* https://github.com/blueimp/jQuery-File-Upload
|
4
4
|
*
|
5
5
|
* Copyright 2011, Sebastian Tschan
|
@@ -36,13 +36,26 @@
|
|
36
36
|
// equivalent to the return data of .serializeArray(), e.g.:
|
37
37
|
// [{name: 'a', value: 1}, {name: 'b', value: 2}]
|
38
38
|
$.ajaxTransport('iframe', function (options) {
|
39
|
-
if (options.async
|
39
|
+
if (options.async) {
|
40
40
|
var form,
|
41
|
-
iframe
|
41
|
+
iframe,
|
42
|
+
addParamChar;
|
42
43
|
return {
|
43
44
|
send: function (_, completeCallback) {
|
44
45
|
form = $('<form style="display:none;"></form>');
|
45
46
|
form.attr('accept-charset', options.formAcceptCharset);
|
47
|
+
addParamChar = /\?/.test(options.url) ? '&' : '?';
|
48
|
+
// XDomainRequest only supports GET and POST:
|
49
|
+
if (options.type === 'DELETE') {
|
50
|
+
options.url = options.url + addParamChar + '_method=DELETE';
|
51
|
+
options.type = 'POST';
|
52
|
+
} else if (options.type === 'PUT') {
|
53
|
+
options.url = options.url + addParamChar + '_method=PUT';
|
54
|
+
options.type = 'POST';
|
55
|
+
} else if (options.type === 'PATCH') {
|
56
|
+
options.url = options.url + addParamChar + '_method=PATCH';
|
57
|
+
options.type = 'POST';
|
58
|
+
}
|
46
59
|
// javascript:false as initial iframe src
|
47
60
|
// prevents warning popups on HTTPS in IE6.
|
48
61
|
// IE versions below IE8 cannot set the name property of
|
@@ -155,16 +168,16 @@
|
|
155
168
|
$.ajaxSetup({
|
156
169
|
converters: {
|
157
170
|
'iframe text': function (iframe) {
|
158
|
-
return $(iframe[0].body).text();
|
171
|
+
return iframe && $(iframe[0].body).text();
|
159
172
|
},
|
160
173
|
'iframe json': function (iframe) {
|
161
|
-
return $.parseJSON($(iframe[0].body).text());
|
174
|
+
return iframe && $.parseJSON($(iframe[0].body).text());
|
162
175
|
},
|
163
176
|
'iframe html': function (iframe) {
|
164
|
-
return $(iframe[0].body).html();
|
177
|
+
return iframe && $(iframe[0].body).html();
|
165
178
|
},
|
166
179
|
'iframe script': function (iframe) {
|
167
|
-
return $.globalEval($(iframe[0].body).text());
|
180
|
+
return iframe && $.globalEval($(iframe[0].body).text());
|
168
181
|
}
|
169
182
|
}
|
170
183
|
});
|
@@ -1,8 +1,8 @@
|
|
1
1
|
/*
|
2
|
-
* jQuery UI Widget 1.
|
2
|
+
* jQuery UI Widget 1.10.1+amd
|
3
3
|
* https://github.com/blueimp/jQuery-File-Upload
|
4
4
|
*
|
5
|
-
* Copyright
|
5
|
+
* Copyright 2013 jQuery Foundation and other contributors
|
6
6
|
* Released under the MIT license.
|
7
7
|
* http://jquery.org/license
|
8
8
|
*
|
@@ -34,6 +34,9 @@ $.cleanData = function( elems ) {
|
|
34
34
|
|
35
35
|
$.widget = function( name, base, prototype ) {
|
36
36
|
var fullName, existingConstructor, constructor, basePrototype,
|
37
|
+
// proxiedPrototype allows the provided prototype to remain unmodified
|
38
|
+
// so that it can be used as a mixin for multiple widgets (#8876)
|
39
|
+
proxiedPrototype = {},
|
37
40
|
namespace = name.split( "." )[ 0 ];
|
38
41
|
|
39
42
|
name = name.split( "." )[ 1 ];
|
@@ -80,43 +83,43 @@ $.widget = function( name, base, prototype ) {
|
|
80
83
|
// inheriting from
|
81
84
|
basePrototype.options = $.widget.extend( {}, basePrototype.options );
|
82
85
|
$.each( prototype, function( prop, value ) {
|
83
|
-
if (
|
84
|
-
|
85
|
-
|
86
|
-
return base.prototype[ prop ].apply( this, arguments );
|
87
|
-
},
|
88
|
-
_superApply = function( args ) {
|
89
|
-
return base.prototype[ prop ].apply( this, args );
|
90
|
-
};
|
91
|
-
return function() {
|
92
|
-
var __super = this._super,
|
93
|
-
__superApply = this._superApply,
|
94
|
-
returnValue;
|
95
|
-
|
96
|
-
this._super = _super;
|
97
|
-
this._superApply = _superApply;
|
98
|
-
|
99
|
-
returnValue = value.apply( this, arguments );
|
100
|
-
|
101
|
-
this._super = __super;
|
102
|
-
this._superApply = __superApply;
|
103
|
-
|
104
|
-
return returnValue;
|
105
|
-
};
|
106
|
-
})();
|
86
|
+
if ( !$.isFunction( value ) ) {
|
87
|
+
proxiedPrototype[ prop ] = value;
|
88
|
+
return;
|
107
89
|
}
|
90
|
+
proxiedPrototype[ prop ] = (function() {
|
91
|
+
var _super = function() {
|
92
|
+
return base.prototype[ prop ].apply( this, arguments );
|
93
|
+
},
|
94
|
+
_superApply = function( args ) {
|
95
|
+
return base.prototype[ prop ].apply( this, args );
|
96
|
+
};
|
97
|
+
return function() {
|
98
|
+
var __super = this._super,
|
99
|
+
__superApply = this._superApply,
|
100
|
+
returnValue;
|
101
|
+
|
102
|
+
this._super = _super;
|
103
|
+
this._superApply = _superApply;
|
104
|
+
|
105
|
+
returnValue = value.apply( this, arguments );
|
106
|
+
|
107
|
+
this._super = __super;
|
108
|
+
this._superApply = __superApply;
|
109
|
+
|
110
|
+
return returnValue;
|
111
|
+
};
|
112
|
+
})();
|
108
113
|
});
|
109
114
|
constructor.prototype = $.widget.extend( basePrototype, {
|
110
115
|
// TODO: remove support for widgetEventPrefix
|
111
116
|
// always use the name + a colon as the prefix, e.g., draggable:start
|
112
117
|
// don't prefix for widgets that aren't DOM-based
|
113
|
-
widgetEventPrefix: name
|
114
|
-
},
|
118
|
+
widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
|
119
|
+
}, proxiedPrototype, {
|
115
120
|
constructor: constructor,
|
116
121
|
namespace: namespace,
|
117
122
|
widgetName: name,
|
118
|
-
// TODO remove widgetBaseClass, see #8155
|
119
|
-
widgetBaseClass: fullName,
|
120
123
|
widgetFullName: fullName
|
121
124
|
});
|
122
125
|
|
@@ -151,8 +154,17 @@ $.widget.extend = function( target ) {
|
|
151
154
|
for ( ; inputIndex < inputLength; inputIndex++ ) {
|
152
155
|
for ( key in input[ inputIndex ] ) {
|
153
156
|
value = input[ inputIndex ][ key ];
|
154
|
-
if (input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
|
155
|
-
|
157
|
+
if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
|
158
|
+
// Clone objects
|
159
|
+
if ( $.isPlainObject( value ) ) {
|
160
|
+
target[ key ] = $.isPlainObject( target[ key ] ) ?
|
161
|
+
$.widget.extend( {}, target[ key ], value ) :
|
162
|
+
// Don't extend strings, arrays, etc. with objects
|
163
|
+
$.widget.extend( {}, value );
|
164
|
+
// Copy everything else by reference
|
165
|
+
} else {
|
166
|
+
target[ key ] = value;
|
167
|
+
}
|
156
168
|
}
|
157
169
|
}
|
158
170
|
}
|
@@ -160,7 +172,7 @@ $.widget.extend = function( target ) {
|
|
160
172
|
};
|
161
173
|
|
162
174
|
$.widget.bridge = function( name, object ) {
|
163
|
-
var fullName = object.prototype.widgetFullName;
|
175
|
+
var fullName = object.prototype.widgetFullName || name;
|
164
176
|
$.fn[ name ] = function( options ) {
|
165
177
|
var isMethodCall = typeof options === "string",
|
166
178
|
args = slice.call( arguments, 1 ),
|
@@ -196,7 +208,7 @@ $.widget.bridge = function( name, object ) {
|
|
196
208
|
if ( instance ) {
|
197
209
|
instance.option( options || {} )._init();
|
198
210
|
} else {
|
199
|
-
new object( options, this );
|
211
|
+
$.data( this, fullName, new object( options, this ) );
|
200
212
|
}
|
201
213
|
});
|
202
214
|
}
|
@@ -205,7 +217,7 @@ $.widget.bridge = function( name, object ) {
|
|
205
217
|
};
|
206
218
|
};
|
207
219
|
|
208
|
-
$.Widget = function( options, element ) {};
|
220
|
+
$.Widget = function( /* options, element */ ) {};
|
209
221
|
$.Widget._childConstructors = [];
|
210
222
|
|
211
223
|
$.Widget.prototype = {
|
@@ -233,11 +245,14 @@ $.Widget.prototype = {
|
|
233
245
|
this.focusable = $();
|
234
246
|
|
235
247
|
if ( element !== this ) {
|
236
|
-
// 1.9 BC for #7810
|
237
|
-
// TODO remove dual storage
|
238
|
-
$.data( element, this.widgetName, this );
|
239
248
|
$.data( element, this.widgetFullName, this );
|
240
|
-
this._on(
|
249
|
+
this._on( true, this.element, {
|
250
|
+
remove: function( event ) {
|
251
|
+
if ( event.target === element ) {
|
252
|
+
this.destroy();
|
253
|
+
}
|
254
|
+
}
|
255
|
+
});
|
241
256
|
this.document = $( element.style ?
|
242
257
|
// element within the document
|
243
258
|
element.ownerDocument :
|
@@ -355,25 +370,36 @@ $.Widget.prototype = {
|
|
355
370
|
return this._setOption( "disabled", true );
|
356
371
|
},
|
357
372
|
|
358
|
-
_on: function( element, handlers ) {
|
373
|
+
_on: function( suppressDisabledCheck, element, handlers ) {
|
374
|
+
var delegateElement,
|
375
|
+
instance = this;
|
376
|
+
|
377
|
+
// no suppressDisabledCheck flag, shuffle arguments
|
378
|
+
if ( typeof suppressDisabledCheck !== "boolean" ) {
|
379
|
+
handlers = element;
|
380
|
+
element = suppressDisabledCheck;
|
381
|
+
suppressDisabledCheck = false;
|
382
|
+
}
|
383
|
+
|
359
384
|
// no element argument, shuffle and use this.element
|
360
385
|
if ( !handlers ) {
|
361
386
|
handlers = element;
|
362
387
|
element = this.element;
|
388
|
+
delegateElement = this.widget();
|
363
389
|
} else {
|
364
390
|
// accept selectors, DOM elements
|
365
|
-
element = $( element );
|
391
|
+
element = delegateElement = $( element );
|
366
392
|
this.bindings = this.bindings.add( element );
|
367
393
|
}
|
368
394
|
|
369
|
-
var instance = this;
|
370
395
|
$.each( handlers, function( event, handler ) {
|
371
396
|
function handlerProxy() {
|
372
397
|
// allow widgets to customize the disabled handling
|
373
398
|
// - disabled as an array instead of boolean
|
374
399
|
// - disabled class as method for disabling individual parts
|
375
|
-
if (
|
376
|
-
|
400
|
+
if ( !suppressDisabledCheck &&
|
401
|
+
( instance.options.disabled === true ||
|
402
|
+
$( this ).hasClass( "ui-state-disabled" ) ) ) {
|
377
403
|
return;
|
378
404
|
}
|
379
405
|
return ( typeof handler === "string" ? instance[ handler ] : handler )
|
@@ -390,7 +416,7 @@ $.Widget.prototype = {
|
|
390
416
|
eventName = match[1] + instance.eventNamespace,
|
391
417
|
selector = match[2];
|
392
418
|
if ( selector ) {
|
393
|
-
|
419
|
+
delegateElement.delegate( selector, eventName, handlerProxy );
|
394
420
|
} else {
|
395
421
|
element.bind( eventName, handlerProxy );
|
396
422
|
}
|
@@ -485,7 +511,7 @@ $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
|
|
485
511
|
if ( options.delay ) {
|
486
512
|
element.delay( options.delay );
|
487
513
|
}
|
488
|
-
if ( hasOptions && $.effects &&
|
514
|
+
if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
|
489
515
|
element[ method ]( options );
|
490
516
|
} else if ( effectName !== method && element[ effectName ] ) {
|
491
517
|
element[ effectName ]( options.duration, options.easing, callback );
|
@@ -501,11 +527,4 @@ $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
|
|
501
527
|
};
|
502
528
|
});
|
503
529
|
|
504
|
-
// DEPRECATED
|
505
|
-
if ( $.uiBackCompat !== false ) {
|
506
|
-
$.Widget.prototype._getCreateOptions = function() {
|
507
|
-
return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ];
|
508
|
-
};
|
509
|
-
}
|
510
|
-
|
511
530
|
}));
|
@@ -1,18 +1,20 @@
|
|
1
1
|
/*
|
2
|
-
* JavaScript Load Image 1.
|
2
|
+
* JavaScript Load Image 1.5
|
3
3
|
* https://github.com/blueimp/JavaScript-Load-Image
|
4
4
|
*
|
5
5
|
* Copyright 2011, Sebastian Tschan
|
6
6
|
* https://blueimp.net
|
7
7
|
*
|
8
|
+
* iOS image scaling fixes based on
|
9
|
+
* https://github.com/stomita/ios-imagefile-megapixel
|
10
|
+
*
|
8
11
|
* Licensed under the MIT license:
|
9
12
|
* http://www.opensource.org/licenses/MIT
|
10
13
|
*/
|
11
14
|
|
12
|
-
/*jslint nomen: true */
|
15
|
+
/*jslint nomen: true, bitwise: true */
|
13
16
|
/*global window, document, URL, webkitURL, Blob, File, FileReader, define */
|
14
17
|
|
15
|
-
|
16
18
|
(function ($) {
|
17
19
|
'use strict';
|
18
20
|
|
@@ -28,22 +30,38 @@
|
|
28
30
|
if (oUrl && !(options && options.noRevoke)) {
|
29
31
|
loadImage.revokeObjectURL(oUrl);
|
30
32
|
}
|
31
|
-
callback
|
33
|
+
if (callback) {
|
34
|
+
callback(loadImage.scale(img, options));
|
35
|
+
}
|
32
36
|
};
|
33
|
-
if ((
|
34
|
-
|
35
|
-
|
36
|
-
(
|
37
|
+
if (loadImage.isInstanceOf('Blob', file) ||
|
38
|
+
// Files are also Blob instances, but some browsers
|
39
|
+
// (Firefox 3.6) support the File API but not Blobs:
|
40
|
+
loadImage.isInstanceOf('File', file)) {
|
37
41
|
url = oUrl = loadImage.createObjectURL(file);
|
38
|
-
|
42
|
+
// Store the file type for resize processing:
|
43
|
+
img._type = file.type;
|
44
|
+
} else if (typeof file === 'string') {
|
39
45
|
url = file;
|
46
|
+
if (options && options.crossOrigin) {
|
47
|
+
img.crossOrigin = options.crossOrigin;
|
48
|
+
}
|
49
|
+
} else {
|
50
|
+
return false;
|
40
51
|
}
|
41
52
|
if (url) {
|
42
53
|
img.src = url;
|
43
54
|
return img;
|
44
55
|
}
|
45
|
-
return loadImage.readFile(file, function (
|
46
|
-
|
56
|
+
return loadImage.readFile(file, function (e) {
|
57
|
+
var target = e.target;
|
58
|
+
if (target && target.result) {
|
59
|
+
img.src = target.result;
|
60
|
+
} else {
|
61
|
+
if (callback) {
|
62
|
+
callback(e);
|
63
|
+
}
|
64
|
+
}
|
47
65
|
});
|
48
66
|
},
|
49
67
|
// The check for URL.revokeObjectURL fixes an issue with Opera 12,
|
@@ -52,41 +70,212 @@
|
|
52
70
|
(window.URL && URL.revokeObjectURL && URL) ||
|
53
71
|
(window.webkitURL && webkitURL);
|
54
72
|
|
73
|
+
loadImage.isInstanceOf = function (type, obj) {
|
74
|
+
// Cross-frame instanceof check
|
75
|
+
return Object.prototype.toString.call(obj) === '[object ' + type + ']';
|
76
|
+
};
|
77
|
+
|
78
|
+
// Detects subsampling in JPEG images:
|
79
|
+
loadImage.detectSubsampling = function (img) {
|
80
|
+
var canvas,
|
81
|
+
context;
|
82
|
+
if (img.width * img.height > 1024 * 1024) { // only consider mexapixel images
|
83
|
+
canvas = document.createElement('canvas');
|
84
|
+
canvas.width = canvas.height = 1;
|
85
|
+
context = canvas.getContext('2d');
|
86
|
+
context.drawImage(img, -img.width + 1, 0);
|
87
|
+
// subsampled image becomes half smaller in rendering size.
|
88
|
+
// check alpha channel value to confirm image is covering edge pixel or not.
|
89
|
+
// if alpha value is 0 image is not covering, hence subsampled.
|
90
|
+
return context.getImageData(0, 0, 1, 1).data[3] === 0;
|
91
|
+
}
|
92
|
+
return false;
|
93
|
+
};
|
94
|
+
|
95
|
+
// Detects vertical squash in JPEG images:
|
96
|
+
loadImage.detectVerticalSquash = function (img, correctedHeight) {
|
97
|
+
var canvas = document.createElement('canvas'),
|
98
|
+
context = canvas.getContext('2d'),
|
99
|
+
data,
|
100
|
+
sy,
|
101
|
+
ey,
|
102
|
+
py,
|
103
|
+
alpha;
|
104
|
+
canvas.width = 1;
|
105
|
+
canvas.height = correctedHeight;
|
106
|
+
context.drawImage(img, 0, 0);
|
107
|
+
data = context.getImageData(0, 0, 1, correctedHeight).data;
|
108
|
+
// search image edge pixel position in case it is squashed vertically:
|
109
|
+
sy = 0;
|
110
|
+
ey = correctedHeight;
|
111
|
+
py = correctedHeight;
|
112
|
+
while (py > sy) {
|
113
|
+
alpha = data[(py - 1) * 4 + 3];
|
114
|
+
if (alpha === 0) {
|
115
|
+
ey = py;
|
116
|
+
} else {
|
117
|
+
sy = py;
|
118
|
+
}
|
119
|
+
py = (ey + sy) >> 1;
|
120
|
+
}
|
121
|
+
return (py / correctedHeight) || 1;
|
122
|
+
};
|
123
|
+
|
124
|
+
// Renders image to canvas while working around iOS image scaling bugs:
|
125
|
+
// https://github.com/blueimp/JavaScript-Load-Image/issues/13
|
126
|
+
loadImage.renderImageToCanvas = function (
|
127
|
+
canvas,
|
128
|
+
img,
|
129
|
+
sourceX,
|
130
|
+
sourceY,
|
131
|
+
sourceWidth,
|
132
|
+
sourceHeight,
|
133
|
+
destX,
|
134
|
+
destY,
|
135
|
+
destWidth,
|
136
|
+
destHeight
|
137
|
+
) {
|
138
|
+
var context = canvas.getContext('2d'),
|
139
|
+
tmpCanvas = document.createElement('canvas'),
|
140
|
+
tileSize = tmpCanvas.width = tmpCanvas.height = 1024,
|
141
|
+
tmpContext = tmpCanvas.getContext('2d'),
|
142
|
+
vertSquashRatio,
|
143
|
+
tileX,
|
144
|
+
tileY;
|
145
|
+
context.save();
|
146
|
+
if (loadImage.detectSubsampling(img)) {
|
147
|
+
sourceWidth /= 2;
|
148
|
+
sourceHeight /= 2;
|
149
|
+
}
|
150
|
+
vertSquashRatio = loadImage.detectVerticalSquash(img, sourceHeight);
|
151
|
+
destWidth = Math.ceil(tileSize * destWidth / sourceWidth);
|
152
|
+
destHeight = Math.ceil(
|
153
|
+
tileSize * destHeight / sourceHeight / vertSquashRatio
|
154
|
+
);
|
155
|
+
destY = 0;
|
156
|
+
tileY = 0;
|
157
|
+
while (tileY < sourceHeight) {
|
158
|
+
destX = 0;
|
159
|
+
tileX = 0;
|
160
|
+
while (tileX < sourceWidth) {
|
161
|
+
tmpContext.clearRect(0, 0, tileSize, tileSize);
|
162
|
+
tmpContext.drawImage(
|
163
|
+
img,
|
164
|
+
sourceX,
|
165
|
+
sourceY,
|
166
|
+
sourceWidth,
|
167
|
+
sourceHeight,
|
168
|
+
-tileX,
|
169
|
+
-tileY,
|
170
|
+
sourceWidth,
|
171
|
+
sourceHeight
|
172
|
+
);
|
173
|
+
context.drawImage(
|
174
|
+
tmpCanvas,
|
175
|
+
0,
|
176
|
+
0,
|
177
|
+
tileSize,
|
178
|
+
tileSize,
|
179
|
+
destX,
|
180
|
+
destY,
|
181
|
+
destWidth,
|
182
|
+
destHeight
|
183
|
+
);
|
184
|
+
tileX += tileSize;
|
185
|
+
destX += destWidth;
|
186
|
+
}
|
187
|
+
tileY += tileSize;
|
188
|
+
destY += destHeight;
|
189
|
+
}
|
190
|
+
context.restore();
|
191
|
+
};
|
192
|
+
|
55
193
|
// Scales the given image (img or canvas HTML element)
|
56
194
|
// using the given options.
|
57
195
|
// Returns a canvas object if the browser supports canvas
|
58
|
-
// and the canvas option is true or a canvas object
|
59
|
-
// as image, else the scaled image:
|
196
|
+
// and the canvas or crop option is true or a canvas object
|
197
|
+
// is passed as image, else the scaled image:
|
60
198
|
loadImage.scale = function (img, options) {
|
61
199
|
options = options || {};
|
62
200
|
var canvas = document.createElement('canvas'),
|
201
|
+
useCanvas = img.getContext ||
|
202
|
+
((options.canvas || options.crop) && canvas.getContext),
|
63
203
|
width = img.width,
|
64
204
|
height = img.height,
|
205
|
+
maxWidth = options.maxWidth,
|
206
|
+
maxHeight = options.maxHeight,
|
207
|
+
sourceWidth = width,
|
208
|
+
sourceHeight = height,
|
209
|
+
sourceX = 0,
|
210
|
+
sourceY = 0,
|
211
|
+
destX = 0,
|
212
|
+
destY = 0,
|
213
|
+
destWidth,
|
214
|
+
destHeight,
|
215
|
+
scale;
|
216
|
+
if (useCanvas && maxWidth && maxHeight && options.crop) {
|
217
|
+
destWidth = maxWidth;
|
218
|
+
destHeight = maxHeight;
|
219
|
+
if (width / height < maxWidth / maxHeight) {
|
220
|
+
sourceHeight = maxHeight * width / maxWidth;
|
221
|
+
sourceY = (height - sourceHeight) / 2;
|
222
|
+
} else {
|
223
|
+
sourceWidth = maxWidth * height / maxHeight;
|
224
|
+
sourceX = (width - sourceWidth) / 2;
|
225
|
+
}
|
226
|
+
} else {
|
227
|
+
destWidth = width;
|
228
|
+
destHeight = height;
|
65
229
|
scale = Math.max(
|
66
|
-
(options.minWidth ||
|
67
|
-
(options.minHeight ||
|
230
|
+
(options.minWidth || destWidth) / destWidth,
|
231
|
+
(options.minHeight || destHeight) / destHeight
|
68
232
|
);
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
233
|
+
if (scale > 1) {
|
234
|
+
destWidth = Math.ceil(destWidth * scale);
|
235
|
+
destHeight = Math.ceil(destHeight * scale);
|
236
|
+
}
|
237
|
+
scale = Math.min(
|
238
|
+
(maxWidth || destWidth) / destWidth,
|
239
|
+
(maxHeight || destHeight) / destHeight
|
240
|
+
);
|
241
|
+
if (scale < 1) {
|
242
|
+
destWidth = Math.ceil(destWidth * scale);
|
243
|
+
destHeight = Math.ceil(destHeight * scale);
|
244
|
+
}
|
80
245
|
}
|
81
|
-
if (
|
82
|
-
canvas.width =
|
83
|
-
canvas.height =
|
84
|
-
|
85
|
-
.
|
246
|
+
if (useCanvas) {
|
247
|
+
canvas.width = destWidth;
|
248
|
+
canvas.height = destHeight;
|
249
|
+
if (img._type === 'image/jpeg') {
|
250
|
+
loadImage.renderImageToCanvas(
|
251
|
+
canvas,
|
252
|
+
img,
|
253
|
+
sourceX,
|
254
|
+
sourceY,
|
255
|
+
sourceWidth,
|
256
|
+
sourceHeight,
|
257
|
+
destX,
|
258
|
+
destY,
|
259
|
+
destWidth,
|
260
|
+
destHeight
|
261
|
+
);
|
262
|
+
} else {
|
263
|
+
canvas.getContext('2d').drawImage(
|
264
|
+
img,
|
265
|
+
sourceX,
|
266
|
+
sourceY,
|
267
|
+
sourceWidth,
|
268
|
+
sourceHeight,
|
269
|
+
destX,
|
270
|
+
destY,
|
271
|
+
destWidth,
|
272
|
+
destHeight
|
273
|
+
);
|
274
|
+
}
|
86
275
|
return canvas;
|
87
276
|
}
|
88
|
-
img.width =
|
89
|
-
img.height =
|
277
|
+
img.width = destWidth;
|
278
|
+
img.height = destHeight;
|
90
279
|
return img;
|
91
280
|
};
|
92
281
|
|
@@ -99,13 +288,12 @@
|
|
99
288
|
};
|
100
289
|
|
101
290
|
// Loads a given File object via FileReader interface,
|
102
|
-
// invokes the callback with
|
291
|
+
// invokes the callback with the event object (load or error).
|
292
|
+
// The result can be read via event.target.result:
|
103
293
|
loadImage.readFile = function (file, callback) {
|
104
294
|
if (window.FileReader && FileReader.prototype.readAsDataURL) {
|
105
295
|
var fileReader = new FileReader();
|
106
|
-
fileReader.onload =
|
107
|
-
callback(e.target.result);
|
108
|
-
};
|
296
|
+
fileReader.onload = fileReader.onerror = callback;
|
109
297
|
fileReader.readAsDataURL(file);
|
110
298
|
return fileReader;
|
111
299
|
}
|