Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(309)

Side by Side Diff: ui/file_manager/gallery/js/image_editor/image_encoder.js

Issue 936143003: Start to use new metadata item in ImageEncoder. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 * The value 360 px is enough in Files.app grid view for HiDPI devices. 11 * The value 360 px is enough in Files.app grid view for HiDPI devices.
12 * @const {number} 12 * @const {number}
13 */ 13 */
14 ImageEncoder.MAX_THUMBNAIL_DIMENSION = 360; 14 ImageEncoder.MAX_THUMBNAIL_DIMENSION = 360;
15 15
16 /** 16 /**
17 * Tries to create thumbnail if the image width or height longer than the size. 17 * Tries to create thumbnail if the image width or height longer than the size.
18 * @const {number} 18 * @const {number}
19 */ 19 */
20 ImageEncoder.MIN_IMAGE_DIMENSION_FOR_THUMBNAIL = 20 ImageEncoder.MIN_IMAGE_DIMENSION_FOR_THUMBNAIL =
21 ImageEncoder.MAX_THUMBNAIL_DIMENSION * 4; 21 ImageEncoder.MAX_THUMBNAIL_DIMENSION * 4;
22 22
23 /** 23 /**
24 * Metadata encoders. 24 * Metadata encoders.
25 * @type {!Object.<string,function(new:ImageEncoder.MetadataEncoder,!Object)>} 25 * @type {!Object.<string,function(
26 * new:ImageEncoder.MetadataEncoder,!MetadataItem)>}
26 * @const 27 * @const
27 */ 28 */
28 ImageEncoder.metadataEncoders = {}; 29 ImageEncoder.metadataEncoders = {};
29 30
30 /** 31 /**
31 * Registers metadata encoder. 32 * Registers metadata encoder.
32 * @param {function(new:ImageEncoder.MetadataEncoder,!Object)} constructor 33 * @param {function(new:ImageEncoder.MetadataEncoder,!MetadataItem)} constructor
33 * Constructor of a metadata encoder. 34 * Constructor of a metadata encoder.
34 * @param {string} mimeType Mime type of the metadata encoder. 35 * @param {string} mimeType Mime type of the metadata encoder.
35 */ 36 */
36 ImageEncoder.registerMetadataEncoder = function(constructor, mimeType) { 37 ImageEncoder.registerMetadataEncoder = function(constructor, mimeType) {
37 ImageEncoder.metadataEncoders[mimeType] = constructor; 38 ImageEncoder.metadataEncoders[mimeType] = constructor;
38 }; 39 };
39 40
40 /** 41 /**
41 * Create a metadata encoder. 42 * Create a metadata encoder.
42 * 43 *
43 * The encoder will own and modify a copy of the original metadata. 44 * The encoder will own and modify a copy of the original metadata.
44 * 45 *
45 * @param {!Object} metadata Original metadata. 46 * @param {!MetadataItem} metadata Original metadata.
46 * @return {!ImageEncoder.MetadataEncoder} Created metadata encoder. 47 * @return {!ImageEncoder.MetadataEncoder} Created metadata encoder.
47 */ 48 */
48 ImageEncoder.createMetadataEncoder = function(metadata) { 49 ImageEncoder.createMetadataEncoder = function(metadata) {
49 var constructor = 50 var constructor =
50 (metadata && ImageEncoder.metadataEncoders[metadata.media.mimeType]) || 51 ImageEncoder.metadataEncoders[metadata.mediaMimeType || ""] ||
51 ImageEncoder.MetadataEncoder; 52 ImageEncoder.MetadataEncoder;
52 return new constructor(metadata); 53 return new constructor(metadata);
53 }; 54 };
54 55
55 /** 56 /**
56 * Create a metadata encoder object holding a copy of metadata 57 * Create a metadata encoder object holding a copy of metadata
57 * modified according to the properties of the supplied image. 58 * modified according to the properties of the supplied image.
58 * 59 *
59 * @param {!Object} metadata Original metadata. 60 * @param {!MetadataItem} metadata Original metadata.
60 * @param {!HTMLCanvasElement} canvas Canvas to use for metadata. 61 * @param {!HTMLCanvasElement} canvas Canvas to use for metadata.
61 * @param {number} thumbnailQuality Encoding quality of a thumbnail. 62 * @param {number} thumbnailQuality Encoding quality of a thumbnail.
62 * @param {Date=} opt_modificationDateTime Modification date time of an image.
63 * @return {!ImageEncoder.MetadataEncoder} Encoder with encoded metadata. 63 * @return {!ImageEncoder.MetadataEncoder} Encoder with encoded metadata.
64 */ 64 */
65 ImageEncoder.encodeMetadata = function( 65 ImageEncoder.encodeMetadata = function(metadata, canvas, thumbnailQuality) {
66 metadata, canvas, thumbnailQuality, opt_modificationDateTime) {
67 var encoder = ImageEncoder.createMetadataEncoder(metadata); 66 var encoder = ImageEncoder.createMetadataEncoder(metadata);
68 encoder.setImageData(canvas, opt_modificationDateTime); 67 encoder.setImageData(canvas);
69 encoder.setThumbnailData(ImageEncoder.createThumbnail(canvas), 68 encoder.setThumbnailData(ImageEncoder.createThumbnail(canvas),
70 thumbnailQuality); 69 thumbnailQuality);
71 return encoder; 70 return encoder;
72 }; 71 };
73 72
74 /** 73 /**
75 * Return a blob with the encoded image with metadata inserted. 74 * Return a blob with the encoded image with metadata inserted.
76 * @param {!HTMLCanvasElement} canvas The canvas with the image to be encoded. 75 * @param {!HTMLCanvasElement} canvas The canvas with the image to be encoded.
77 * @param {!ImageEncoder.MetadataEncoder} metadataEncoder Encoder to use. 76 * @param {!ImageEncoder.MetadataEncoder} metadataEncoder Encoder to use.
78 * @param {number} imageQuality (0..1], Encoding quality of an image. 77 * @param {number} imageQuality (0..1], Encoding quality of an image.
79 * @return {!Blob} encoded data. 78 * @return {!Blob} encoded data.
80 */ 79 */
81 ImageEncoder.getBlob = function(canvas, metadataEncoder, imageQuality) { 80 ImageEncoder.getBlob = function(canvas, metadataEncoder, imageQuality) {
82 ImageUtil.trace.resetTimer('dataurl'); 81 ImageUtil.trace.resetTimer('dataurl');
83 // WebKit does not support canvas.toBlob yet so canvas.toDataURL is 82 // WebKit does not support canvas.toBlob yet so canvas.toDataURL is
84 // the only way to use the Chrome built-in image encoder. 83 // the only way to use the Chrome built-in image encoder.
85 var dataURL = canvas.toDataURL(metadataEncoder.getMetadata().media.mimeType, 84 var dataURL = canvas.toDataURL(metadataEncoder.mimeType, imageQuality);
86 imageQuality);
87 ImageUtil.trace.reportTimer('dataurl'); 85 ImageUtil.trace.reportTimer('dataurl');
88 86
89 var encodedImage = ImageEncoder.decodeDataURL(dataURL); 87 var encodedImage = ImageEncoder.decodeDataURL(dataURL);
90 88
91 var encodedMetadata = metadataEncoder.encode(); 89 var encodedMetadata = metadataEncoder.encode();
92 90
93 var slices = []; 91 var slices = [];
94 92
95 // TODO(kaznacheev): refactor |stringToArrayBuffer| and |encode| to return 93 // TODO(kaznacheev): refactor |stringToArrayBuffer| and |encode| to return
96 // arrays instead of array buffers. 94 // arrays instead of array buffers.
97 function appendSlice(arrayBuffer) { 95 function appendSlice(arrayBuffer) {
98 slices.push(new DataView(arrayBuffer)); 96 slices.push(new DataView(arrayBuffer));
99 } 97 }
100 98
101 ImageUtil.trace.resetTimer('blob'); 99 ImageUtil.trace.resetTimer('blob');
102 if (encodedMetadata.byteLength != 0) { 100 if (encodedMetadata.byteLength != 0) {
103 var metadataRange = metadataEncoder.findInsertionRange(encodedImage); 101 var metadataRange = metadataEncoder.findInsertionRange(encodedImage);
104 appendSlice(ImageEncoder.stringToArrayBuffer( 102 appendSlice(ImageEncoder.stringToArrayBuffer(
105 encodedImage, 0, metadataRange.from)); 103 encodedImage, 0, metadataRange.from));
106 104
107 appendSlice(metadataEncoder.encode()); 105 appendSlice(metadataEncoder.encode());
108 106
109 appendSlice(ImageEncoder.stringToArrayBuffer( 107 appendSlice(ImageEncoder.stringToArrayBuffer(
110 encodedImage, metadataRange.to, encodedImage.length)); 108 encodedImage, metadataRange.to, encodedImage.length));
111 } else { 109 } else {
112 appendSlice(ImageEncoder.stringToArrayBuffer( 110 appendSlice(ImageEncoder.stringToArrayBuffer(
113 encodedImage, 0, encodedImage.length)); 111 encodedImage, 0, encodedImage.length));
114 } 112 }
115 var blob = new Blob(slices, 113 var blob = new Blob(slices, {type: metadataEncoder.mimeType});
116 {type: metadataEncoder.getMetadata().media.mimeType});
117 ImageUtil.trace.reportTimer('blob'); 114 ImageUtil.trace.reportTimer('blob');
118 return blob; 115 return blob;
119 }; 116 };
120 117
121 /** 118 /**
122 * Decode a dataURL into a binary string containing the encoded image. 119 * Decode a dataURL into a binary string containing the encoded image.
123 * 120 *
124 * Why return a string? Calling atob and having the rest of the code deal 121 * Why return a string? Calling atob and having the rest of the code deal
125 * with a string is several times faster than decoding base64 in Javascript. 122 * with a string is several times faster than decoding base64 in Javascript.
126 * 123 *
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 } 171 }
175 return array.buffer; 172 return array.buffer;
176 }; 173 };
177 174
178 /** 175 /**
179 * A base class for a metadata encoder. 176 * A base class for a metadata encoder.
180 * 177 *
181 * Serves as a default metadata encoder for images that none of the metadata 178 * Serves as a default metadata encoder for images that none of the metadata
182 * parsers recognized. 179 * parsers recognized.
183 * 180 *
184 * @param {!Object} original_metadata Starting metadata. 181 * @param {!MetadataItem} originalMetadata Starting metadata.
185 * @constructor 182 * @constructor
186 * @struct 183 * @struct
187 */ 184 */
188 ImageEncoder.MetadataEncoder = function(original_metadata) { 185 ImageEncoder.MetadataEncoder = function(originalMetadata) {
189 this.metadata_ = MetadataCache.cloneMetadata(original_metadata) || {}; 186 var mimeType = ImageEncoder.MetadataEncoder.getMimeType_(originalMetadata);
190 if (ImageEncoder.MetadataEncoder.getMimeType_(this.metadata_) !== 187
191 'image/jpeg') { 188 /**
192 // Chrome can only encode JPEG and PNG. Force PNG mime type so that we 189 * Chrome can only encode JPEG and PNG. Force PNG mime type so that we
193 // can save to file and generate a thumbnail. 190 * can save to file and generate a thumbnail.
194 // TODO(yawano) Change this not to modify metadata. Mime type comes from 191 * @public {string}
195 // different fields depending on the conditions. Just overriding 192 */
196 // media.mimeType and use the modified metadata could cause a problem. 193 this.mimeType = mimeType === 'image/jpeg' ? 'image/jpeg' : 'image/png';
197 this.metadata_.media.mimeType = 'image/png'; 194
198 } 195 /**
196 * @protected {string}
197 */
198 this.thumbnailDataUrl = '';
199
200 /**
201 * @protected {number}
202 */
203 this.imageWidth = 0;
204
205 /**
206 * @protected {number}
207 */
208 this.imageHeight = 0;
199 }; 209 };
200 210
201 /** 211 /**
202 * Gets mime type from metadata. It reads media.mimeType at first, and if it 212 * Gets mime type from metadata. It reads media.mimeType at first, and if it
203 * fails, it falls back to external.contentMimeType. If both fields are 213 * fails, it falls back to external.contentMimeType. If both fields are
204 * undefined, it means that metadata is broken. Then it throws an exception. 214 * undefined, it means that metadata is broken. Then it throws an exception.
205 * 215 *
206 * @param {!Object} metadata Metadata. 216 * @param {!MetadataItem} metadata Metadata.
207 * @return {string} Mime type. 217 * @return {string} Mime type.
208 * @private 218 * @private
209 */ 219 */
210 ImageEncoder.MetadataEncoder.getMimeType_ = function(metadata) { 220 ImageEncoder.MetadataEncoder.getMimeType_ = function(metadata) {
211 if (metadata.media.mimeType) 221 if (metadata.mediaMimeType)
212 return metadata.media.mimeType; 222 return metadata.mediaMimeType;
213 else if (metadata.external.contentMimeType) 223 else if (metadata.contentMimeType)
214 return metadata.external.contentMimeType; 224 return metadata.contentMimeType;
215 225
216 assertNotReached(); 226 assertNotReached();
217 }; 227 };
218 228
219 /** 229 /**
220 * Returns metadata.
221 * @return {!Object} A metadata.
222 *
223 * TODO(yawano): MetadataEncoder.getMetadata seems not to be used anymore.
224 * Investigate this, and remove if possible. Should not modify a metadata by
225 * using an encoder.
226 */
227 ImageEncoder.MetadataEncoder.prototype.getMetadata = function() {
228 return this.metadata_;
229 };
230
231 /**
232 * Sets an image data. 230 * Sets an image data.
233 * @param {!HTMLCanvasElement} canvas Canvas or anything with width and height 231 * @param {!HTMLCanvasElement} canvas Canvas or anything with width and height
234 * properties. 232 * properties.
235 * @param {Date=} opt_modificationDateTime Modification date time of an image.
236 */ 233 */
237 ImageEncoder.MetadataEncoder.prototype.setImageData = 234 ImageEncoder.MetadataEncoder.prototype.setImageData = function(canvas) {
238 function(canvas, opt_modificationDateTime) { 235 this.imageWidth = canvas.width;
239 this.metadata_.width = canvas.width; 236 this.imageHeight = canvas.height;
240 this.metadata_.height = canvas.height;
241 }; 237 };
242 238
243 /** 239 /**
244 * @param {HTMLCanvasElement} canvas Canvas to use as thumbnail. Note that it 240 * @param {HTMLCanvasElement} canvas Canvas to use as thumbnail. Note that it
245 * can be null. 241 * can be null.
246 * @param {number} quality Thumbnail quality. 242 * @param {number} quality Thumbnail quality.
247 */ 243 */
248 ImageEncoder.MetadataEncoder.prototype.setThumbnailData = 244 ImageEncoder.MetadataEncoder.prototype.setThumbnailData =
249 function(canvas, quality) { 245 function(canvas, quality) {
250 this.metadata_.thumbnailURL = 246 this.thumbnailDataUrl =
251 canvas ? canvas.toDataURL(this.metadata_.media.mimeType, quality) : ''; 247 canvas ? canvas.toDataURL(this.mimeType, quality) : '';
252 delete this.metadata_.thumbnailTransform;
253 }; 248 };
254 249
255 /** 250 /**
256 * Returns a range where the metadata is (or should be) located. 251 * Returns a range where the metadata is (or should be) located.
257 * @param {string} encodedImage An encoded image. 252 * @param {string} encodedImage An encoded image.
258 * @return {{from:number, to:number}} An object with from and to properties. 253 * @return {{from:number, to:number}} An object with from and to properties.
259 */ 254 */
260 ImageEncoder.MetadataEncoder.prototype. 255 ImageEncoder.MetadataEncoder.prototype.
261 findInsertionRange = function(encodedImage) { return {from: 0, to: 0}; }; 256 findInsertionRange = function(encodedImage) { return {from: 0, to: 0}; };
262 257
263 /** 258 /**
264 * Returns serialized metadata ready to write to an image file. 259 * Returns serialized metadata ready to write to an image file.
265 * The return type is optimized for passing to Blob.append. 260 * The return type is optimized for passing to Blob.append.
266 * @return {!ArrayBuffer} Serialized metadata. 261 * @return {!ArrayBuffer} Serialized metadata.
267 */ 262 */
268 ImageEncoder.MetadataEncoder.prototype.encode = function() { 263 ImageEncoder.MetadataEncoder.prototype.encode = function() {
269 return new Uint8Array(0).buffer; 264 return new Uint8Array(0).buffer;
270 }; 265 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698