1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 * Loads and resizes an image.
11 function ImageLoader() {
13 * Persistent cache object.
17 this.cache_ = new Cache();
20 * Manages pending requests and runs them in order of priorities.
24 this.worker_ = new Worker();
26 // Grant permissions to the local file system and initialize the cache.
27 chrome.fileBrowserPrivate.requestFileSystem(
29 function(filesystem) {
30 this.cache_.initialize(function() {
35 chrome.extension.onMessageExternal.addListener(function(request,
38 if (ImageLoader.ALLOWED_CLIENTS.indexOf(sender.id) !== -1) {
39 // Sending a response may fail if the receiver already went offline.
40 // This is not an error, but a normal and quite common situation.
41 var failSafeSendResponse = function(response) {
43 sendResponse(response);
49 return this.onMessage_(sender.id, request, failSafeSendResponse);
55 * List of extensions allowed to perform image requests.
58 * @type {Array.<string>}
60 ImageLoader.ALLOWED_CLIENTS =
61 ['hhaomjibdihmijegdhdafkllkbggdgoj']; // File Manager's extension id.
64 * Handles a request. Depending on type of the request, starts or stops
67 * @param {string} senderId Sender's extension id.
68 * @param {Object} request Request message as a hash array.
69 * @param {function} callback Callback to be called to return response.
70 * @return {boolean} True if the message channel should stay alive until the
74 ImageLoader.prototype.onMessage_ = function(senderId, request, callback) {
75 var requestId = senderId + ':' + request.taskId;
78 this.worker_.remove(requestId);
79 return false; // No callback calls.
81 // Create a request task and add it to the worker (queue).
82 var requestTask = new Request(requestId, this.cache_, request, callback);
83 this.worker_.add(requestTask);
84 return true; // Request will call the callback.
89 * Returns the singleton instance.
90 * @return {ImageLoader} ImageLoader object.
92 ImageLoader.getInstance = function() {
93 if (!ImageLoader.instance_)
94 ImageLoader.instance_ = new ImageLoader();
95 return ImageLoader.instance_;
99 * Checks if the options contain any image processing.
101 * @param {number} width Source width.
102 * @param {number} height Source height.
103 * @param {Object} options Resizing options as a hash array.
104 * @return {boolean} True if yes, false if not.
106 ImageLoader.shouldProcess = function(width, height, options) {
107 var targetDimensions = ImageLoader.resizeDimensions(width, height, options);
109 // Dimensions has to be adjusted.
110 if (targetDimensions.width != width || targetDimensions.height != height)
113 // Orientation has to be adjusted.
114 if (options.orientation)
117 // No changes required.
122 * Calculates dimensions taking into account resize options, such as:
123 * - scale: for scaling,
124 * - maxWidth, maxHeight: for maximum dimensions,
125 * - width, height: for exact requested size.
126 * Returns the target size as hash array with width, height properties.
128 * @param {number} width Source width.
129 * @param {number} height Source height.
130 * @param {Object} options Resizing options as a hash array.
131 * @return {Object} Dimensions, eg. {width: 100, height: 50}.
133 ImageLoader.resizeDimensions = function(width, height, options) {
134 var sourceWidth = width;
135 var sourceHeight = height;
137 // Flip dimensions for odd orientation values: 1 (90deg) and 3 (270deg).
138 if (options.orientation && options.orientation % 2) {
139 sourceWidth = height;
140 sourceHeight = width;
143 var targetWidth = sourceWidth;
144 var targetHeight = sourceHeight;
146 if ('scale' in options) {
147 targetWidth = sourceWidth * options.scale;
148 targetHeight = sourceHeight * options.scale;
151 if (options.maxWidth &&
152 targetWidth > options.maxWidth) {
153 var scale = options.maxWidth / targetWidth;
154 targetWidth *= scale;
155 targetHeight *= scale;
158 if (options.maxHeight &&
159 targetHeight > options.maxHeight) {
160 var scale = options.maxHeight / targetHeight;
161 targetWidth *= scale;
162 targetHeight *= scale;
166 targetWidth = options.width;
169 targetHeight = options.height;
171 targetWidth = Math.round(targetWidth);
172 targetHeight = Math.round(targetHeight);
174 return {width: targetWidth, height: targetHeight};
178 * Performs resizing of the source image into the target canvas.
180 * @param {HTMLCanvasElement|Image} source Source image or canvas.
181 * @param {HTMLCanvasElement} target Target canvas.
182 * @param {Object} options Resizing options as a hash array.
184 ImageLoader.resize = function(source, target, options) {
185 var targetDimensions = ImageLoader.resizeDimensions(
186 source.width, source.height, options);
188 target.width = targetDimensions.width;
189 target.height = targetDimensions.height;
191 // Default orientation is 0deg.
192 var orientation = options.orientation || 0;
194 // For odd orientation values: 1 (90deg) and 3 (270deg) flip dimensions.
197 if (orientation % 2) {
198 drawImageWidth = target.height;
199 drawImageHeight = target.width;
201 drawImageWidth = target.width;
202 drawImageHeight = target.height;
205 var targetContext = target.getContext('2d');
206 targetContext.save();
207 targetContext.translate(target.width / 2, target.height / 2);
208 targetContext.rotate(orientation * Math.PI / 2);
209 targetContext.drawImage(
212 source.width, source.height,
213 -drawImageWidth / 2, -drawImageHeight / 2,
214 drawImageWidth, drawImageHeight);
215 targetContext.restore();