OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * A namespace class for image encoding functions. All methods are static. | 6 * A namespace class for image encoding functions. All methods are static. |
7 */ | 7 */ |
8 function ImageEncoder() {} | 8 function ImageEncoder() {} |
9 | 9 |
10 /** | 10 /** |
11 * @type {Array.<Object>} | 11 * Metadata encoders. |
12 * @type {!Object.<string,function(new:ImageEncoder.MetadataEncoder,!Object)>} | |
13 * @const | |
12 */ | 14 */ |
13 ImageEncoder.metadataEncoders = {}; | 15 ImageEncoder.metadataEncoders = {}; |
14 | 16 |
15 /** | 17 /** |
16 * @param {function(new:ImageEncoder.MetadataEncoder)} constructor | 18 * Registers metadata encoder. |
17 * // TODO(JSDOC). | 19 * @param {function(new:ImageEncoder.MetadataEncoder,!Object)} constructor |
18 * @param {string} mimeType // TODO(JSDOC). | 20 * Constructor of a metadata encoder. |
21 * @param {string} mimeType Mime type of the metadata encoder. | |
19 */ | 22 */ |
20 ImageEncoder.registerMetadataEncoder = function(constructor, mimeType) { | 23 ImageEncoder.registerMetadataEncoder = function(constructor, mimeType) { |
21 ImageEncoder.metadataEncoders[mimeType] = constructor; | 24 ImageEncoder.metadataEncoders[mimeType] = constructor; |
22 }; | 25 }; |
23 | 26 |
24 /** | 27 /** |
25 * Create a metadata encoder. | 28 * Create a metadata encoder. |
26 * | 29 * |
27 * The encoder will own and modify a copy of the original metadata. | 30 * The encoder will own and modify a copy of the original metadata. |
28 * | 31 * |
29 * @param {Object} metadata Original metadata. | 32 * @param {!Object} metadata Original metadata. |
30 * @return {ImageEncoder.MetadataEncoder} Created metadata encoder. | 33 * @return {!ImageEncoder.MetadataEncoder} Created metadata encoder. |
31 */ | 34 */ |
32 ImageEncoder.createMetadataEncoder = function(metadata) { | 35 ImageEncoder.createMetadataEncoder = function(metadata) { |
33 var constructor = | 36 var constructor = |
34 (metadata && ImageEncoder.metadataEncoders[metadata.mimeType]) || | 37 (metadata && ImageEncoder.metadataEncoders[metadata.mimeType]) || |
35 ImageEncoder.MetadataEncoder; | 38 ImageEncoder.MetadataEncoder; |
36 return new constructor(metadata); | 39 return new constructor(metadata); |
37 }; | 40 }; |
38 | 41 |
39 | 42 |
40 /** | 43 /** |
41 * Create a metadata encoder object holding a copy of metadata | 44 * Create a metadata encoder object holding a copy of metadata |
42 * modified according to the properties of the supplied image. | 45 * modified according to the properties of the supplied image. |
43 * | 46 * |
44 * @param {Object} metadata Original metadata. | 47 * @param {!Object} metadata Original metadata. |
45 * @param {HTMLCanvasElement} canvas Canvas to use for metadata. | 48 * @param {!HTMLCanvasElement} canvas Canvas to use for metadata. |
46 * @param {number} quality Encoding quality (defaults to 1). | 49 * @param {number} quality Encoding quality (defaults to 1). |
47 * @return {ImageEncoder.MetadataEncoder} Encoder with encoded metadata. | 50 * @return {!ImageEncoder.MetadataEncoder} Encoder with encoded metadata. |
48 */ | 51 */ |
49 ImageEncoder.encodeMetadata = function(metadata, canvas, quality) { | 52 ImageEncoder.encodeMetadata = function(metadata, canvas, quality) { |
50 var encoder = ImageEncoder.createMetadataEncoder(metadata); | 53 var encoder = ImageEncoder.createMetadataEncoder(metadata); |
51 encoder.setImageData(canvas); | 54 encoder.setImageData(canvas); |
52 encoder.setThumbnailData(ImageEncoder.createThumbnail(canvas), quality || 1); | 55 encoder.setThumbnailData(ImageEncoder.createThumbnail(canvas), quality || 1); |
53 return encoder; | 56 return encoder; |
54 }; | 57 }; |
55 | 58 |
56 | 59 |
57 /** | 60 /** |
58 * Return a blob with the encoded image with metadata inserted. | 61 * Return a blob with the encoded image with metadata inserted. |
59 * @param {HTMLCanvasElement} canvas The canvas with the image to be encoded. | 62 * @param {!HTMLCanvasElement} canvas The canvas with the image to be encoded. |
60 * @param {ImageEncoder.MetadataEncoder} metadataEncoder Encoder to use. | 63 * @param {!ImageEncoder.MetadataEncoder} metadataEncoder Encoder to use. |
61 * @param {number} quality (0..1], Encoding quality, defaults to 0.9. | 64 * @param {number} quality (0..1], Encoding quality, defaults to 0.9. |
62 * @return {Blob} encoded data. | 65 * @return {!Blob} encoded data. |
63 */ | 66 */ |
64 ImageEncoder.getBlob = function(canvas, metadataEncoder, quality) { | 67 ImageEncoder.getBlob = function(canvas, metadataEncoder, quality) { |
65 // Contrary to what one might think 1.0 is not a good default. Opening and | 68 // Contrary to what one might think 1.0 is not a good default. Opening and |
66 // saving an typical photo taken with consumer camera increases its file size | 69 // saving an typical photo taken with consumer camera increases its file size |
67 // by 50-100%. | 70 // by 50-100%. |
68 // Experiments show that 0.9 is much better. It shrinks some photos a bit, | 71 // Experiments show that 0.9 is much better. It shrinks some photos a bit, |
69 // keeps others about the same size, but does not visibly lower the quality. | 72 // keeps others about the same size, but does not visibly lower the quality. |
70 quality = quality || 0.9; | 73 quality = quality || 0.9; |
71 | 74 |
72 ImageUtil.trace.resetTimer('dataurl'); | 75 ImageUtil.trace.resetTimer('dataurl'); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
112 * | 115 * |
113 * Why return a string? Calling atob and having the rest of the code deal | 116 * Why return a string? Calling atob and having the rest of the code deal |
114 * with a string is several times faster than decoding base64 in Javascript. | 117 * with a string is several times faster than decoding base64 in Javascript. |
115 * | 118 * |
116 * @param {string} dataURL Data URL to decode. | 119 * @param {string} dataURL Data URL to decode. |
117 * @return {string} A binary string (char codes are the actual byte values). | 120 * @return {string} A binary string (char codes are the actual byte values). |
118 */ | 121 */ |
119 ImageEncoder.decodeDataURL = function(dataURL) { | 122 ImageEncoder.decodeDataURL = function(dataURL) { |
120 // Skip the prefix ('data:image/<type>;base64,') | 123 // Skip the prefix ('data:image/<type>;base64,') |
121 var base64string = dataURL.substring(dataURL.indexOf(',') + 1); | 124 var base64string = dataURL.substring(dataURL.indexOf(',') + 1); |
122 return atob(base64string); | 125 return window.atob(base64string); |
123 }; | 126 }; |
124 | 127 |
125 /** | 128 /** |
126 * Return a thumbnail for an image. | 129 * Return a thumbnail for an image. |
127 * @param {HTMLCanvasElement} canvas Original image. | 130 * @param {!HTMLCanvasElement} canvas Original image. |
128 * @param {number=} opt_shrinkage Thumbnail should be at least this much smaller | 131 * @param {number=} opt_shrinkage Thumbnail should be at least this much smaller |
129 * than the original image (in each dimension). | 132 * than the original image (in each dimension). |
130 * @return {HTMLCanvasElement} Thumbnail canvas. | 133 * @return {!HTMLCanvasElement} Thumbnail canvas. |
131 */ | 134 */ |
132 ImageEncoder.createThumbnail = function(canvas, opt_shrinkage) { | 135 ImageEncoder.createThumbnail = function(canvas, opt_shrinkage) { |
133 var MAX_THUMBNAIL_DIMENSION = 320; | 136 var MAX_THUMBNAIL_DIMENSION = 320; |
134 | 137 |
135 opt_shrinkage = Math.max(opt_shrinkage || 4, | 138 opt_shrinkage = Math.max(opt_shrinkage || 4, |
136 canvas.width / MAX_THUMBNAIL_DIMENSION, | 139 canvas.width / MAX_THUMBNAIL_DIMENSION, |
137 canvas.height / MAX_THUMBNAIL_DIMENSION); | 140 canvas.height / MAX_THUMBNAIL_DIMENSION); |
138 | 141 |
139 var thumbnailCanvas = canvas.ownerDocument.createElement('canvas'); | 142 var thumbnailCanvas = assertInstanceof( |
143 canvas.ownerDocument.createElement('canvas'), HTMLCanvasElement); | |
140 thumbnailCanvas.width = Math.round(canvas.width / opt_shrinkage); | 144 thumbnailCanvas.width = Math.round(canvas.width / opt_shrinkage); |
141 thumbnailCanvas.height = Math.round(canvas.height / opt_shrinkage); | 145 thumbnailCanvas.height = Math.round(canvas.height / opt_shrinkage); |
142 | 146 |
143 var context = thumbnailCanvas.getContext('2d'); | 147 var context = thumbnailCanvas.getContext('2d'); |
144 context.drawImage(canvas, | 148 context.drawImage(canvas, |
145 0, 0, canvas.width, canvas.height, | 149 0, 0, canvas.width, canvas.height, |
146 0, 0, thumbnailCanvas.width, thumbnailCanvas.height); | 150 0, 0, thumbnailCanvas.width, thumbnailCanvas.height); |
147 | 151 |
148 return thumbnailCanvas; | 152 return thumbnailCanvas; |
149 }; | 153 }; |
150 | 154 |
151 /** | 155 /** |
152 * TODO(JSDOC) | 156 * Convert string to an array buffer. |
hirono
2014/11/18 01:43:55
nit: Converts
yawano
2014/11/18 04:26:53
Done.
| |
153 * @param {string} string // TODO(JSDOC). | 157 * @param {string} string A string. |
154 * @param {number} from // TODO(JSDOC). | 158 * @param {number} from Strt index. |
155 * @param {number} to // TODO(JSDOC). | 159 * @param {number} to End index. |
156 * @return {ArrayBuffer} // TODO(JSDOC). | 160 * @return {!ArrayBuffer} A created array buffer is returned. |
157 */ | 161 */ |
158 ImageEncoder.stringToArrayBuffer = function(string, from, to) { | 162 ImageEncoder.stringToArrayBuffer = function(string, from, to) { |
159 var size = to - from; | 163 var size = to - from; |
160 var array = new Uint8Array(size); | 164 var array = new Uint8Array(size); |
161 for (var i = 0; i != size; i++) { | 165 for (var i = 0; i != size; i++) { |
162 array[i] = string.charCodeAt(from + i); | 166 array[i] = string.charCodeAt(from + i); |
163 } | 167 } |
164 return array.buffer; | 168 return array.buffer; |
165 }; | 169 }; |
166 | 170 |
167 /** | 171 /** |
168 * A base class for a metadata encoder. | 172 * A base class for a metadata encoder. |
169 * | 173 * |
170 * Serves as a default metadata encoder for images that none of the metadata | 174 * Serves as a default metadata encoder for images that none of the metadata |
171 * parsers recognized. | 175 * parsers recognized. |
172 * | 176 * |
173 * @param {Object} original_metadata Starting metadata. | 177 * @param {!Object} original_metadata Starting metadata. |
174 * @constructor | 178 * @constructor |
179 * @struct | |
175 */ | 180 */ |
176 ImageEncoder.MetadataEncoder = function(original_metadata) { | 181 ImageEncoder.MetadataEncoder = function(original_metadata) { |
177 this.metadata_ = MetadataCache.cloneMetadata(original_metadata) || {}; | 182 this.metadata_ = MetadataCache.cloneMetadata(original_metadata) || {}; |
178 if (this.metadata_.mimeType != 'image/jpeg') { | 183 if (this.metadata_.mimeType != 'image/jpeg') { |
179 // Chrome can only encode JPEG and PNG. Force PNG mime type so that we | 184 // Chrome can only encode JPEG and PNG. Force PNG mime type so that we |
180 // can save to file and generate a thumbnail. | 185 // can save to file and generate a thumbnail. |
181 this.metadata_.mimeType = 'image/png'; | 186 this.metadata_.mimeType = 'image/png'; |
182 } | 187 } |
183 }; | 188 }; |
184 | 189 |
185 /** | 190 /** |
186 * TODO(JSDOC) | 191 * Returns metadata. |
187 * @return {Object} // TODO(JSDOC). | 192 * @return {!Object} A metadata. |
188 */ | 193 */ |
189 ImageEncoder.MetadataEncoder.prototype.getMetadata = function() { | 194 ImageEncoder.MetadataEncoder.prototype.getMetadata = function() { |
190 return this.metadata_; | 195 return this.metadata_; |
191 }; | 196 }; |
192 | 197 |
193 /** | 198 /** |
194 * @param {HTMLCanvasElement|Object} canvas Canvas or or anything with | 199 * @param {!HTMLCanvasElement} canvas Canvas or or anything with |
195 * width and height properties. | 200 * width and height properties. |
196 */ | 201 */ |
197 ImageEncoder.MetadataEncoder.prototype.setImageData = function(canvas) { | 202 ImageEncoder.MetadataEncoder.prototype.setImageData = function(canvas) { |
198 this.metadata_.width = canvas.width; | 203 this.metadata_.width = canvas.width; |
199 this.metadata_.height = canvas.height; | 204 this.metadata_.height = canvas.height; |
200 }; | 205 }; |
201 | 206 |
202 /** | 207 /** |
203 * @param {HTMLCanvasElement} canvas Canvas to use as thumbnail. | 208 * @param {!HTMLCanvasElement} canvas Canvas to use as thumbnail. |
204 * @param {number} quality Thumbnail quality. | 209 * @param {number} quality Thumbnail quality. |
205 */ | 210 */ |
206 ImageEncoder.MetadataEncoder.prototype.setThumbnailData = | 211 ImageEncoder.MetadataEncoder.prototype.setThumbnailData = |
207 function(canvas, quality) { | 212 function(canvas, quality) { |
208 this.metadata_.thumbnailURL = | 213 this.metadata_.thumbnailURL = |
209 canvas.toDataURL(this.metadata_.mimeType, quality); | 214 canvas.toDataURL(this.metadata_.mimeType, quality); |
210 delete this.metadata_.thumbnailTransform; | 215 delete this.metadata_.thumbnailTransform; |
211 }; | 216 }; |
212 | 217 |
213 /** | 218 /** |
214 * Return a range where the metadata is (or should be) located. | 219 * Return a range where the metadata is (or should be) located. |
hirono
2014/11/18 01:43:55
Please fix it with 'Returns'.
yawano
2014/11/18 04:26:53
Done.
| |
215 * @param {string} encodedImage // TODO(JSDOC). | 220 * @param {string} encodedImage An encoded image. |
216 * @return {Object} An object with from and to properties. | 221 * @return {!{from:number, to:number}} An object with from and to properties. |
hirono
2014/11/18 01:43:55
I think we don't need to add '!'. Record type (suc
yawano
2014/11/18 04:26:53
Done.
| |
217 */ | 222 */ |
218 ImageEncoder.MetadataEncoder.prototype. | 223 ImageEncoder.MetadataEncoder.prototype. |
219 findInsertionRange = function(encodedImage) { return {from: 0, to: 0}; }; | 224 findInsertionRange = function(encodedImage) { return {from: 0, to: 0}; }; |
220 | 225 |
221 /** | 226 /** |
222 * Return serialized metadata ready to write to an image file. | 227 * Return serialized metadata ready to write to an image file. |
hirono
2014/11/18 01:43:55
ditto.
yawano
2014/11/18 04:26:53
Done.
| |
223 * The return type is optimized for passing to Blob.append. | 228 * The return type is optimized for passing to Blob.append. |
224 * @return {ArrayBuffer} // TODO(JSDOC). | 229 * @return {ArrayBuffer} Serialized metadata. |
hirono
2014/11/18 01:43:55
!ArrayBuffer ?
yawano
2014/11/18 04:26:53
Done.
| |
225 */ | 230 */ |
226 ImageEncoder.MetadataEncoder.prototype.encode = function() { | 231 ImageEncoder.MetadataEncoder.prototype.encode = function() { |
227 return new Uint8Array(0).buffer; | 232 return new Uint8Array(0).buffer; |
228 }; | 233 }; |
OLD | NEW |