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 * Object representing an image item (a photo). | 6 * Object representing an image item (a photo). |
7 * | 7 * |
8 * @param {!FileEntry} entry Image entry. | 8 * @param {!FileEntry} entry Image entry. |
9 * @param {!EntryLocation} locationInfo Entry location information. | 9 * @param {!EntryLocation} locationInfo Entry location information. |
10 * @param {!Object} metadata Metadata for the entry. | |
11 * @param {!MetadataItem} metadataItem | 10 * @param {!MetadataItem} metadataItem |
12 * @param {!MetadataCache} metadataCache Metadata cache instance. | 11 * @param {!ThumbnailMetadataItem} thumbnailMetadataItem |
13 * @param {!MetadataModel} metadataModel File system metadata. | |
14 * @param {boolean} original Whether the entry is original or edited. | 12 * @param {boolean} original Whether the entry is original or edited. |
15 * @constructor | 13 * @constructor |
16 * @struct | 14 * @struct |
17 */ | 15 */ |
18 Gallery.Item = function( | 16 Gallery.Item = function( |
19 entry, locationInfo, metadata, metadataItem, metadataCache, | 17 entry, locationInfo, metadataItem, thumbnailMetadataItem, original) { |
20 metadataModel, original) { | |
21 /** | 18 /** |
22 * @type {!FileEntry} | 19 * @private {!FileEntry} |
23 * @private | |
24 */ | 20 */ |
25 this.entry_ = entry; | 21 this.entry_ = entry; |
26 | 22 |
27 /** | 23 /** |
28 * @type {!EntryLocation} | 24 * @private {!EntryLocation} |
29 * @private | |
30 */ | 25 */ |
31 this.locationInfo_ = locationInfo; | 26 this.locationInfo_ = locationInfo; |
32 | 27 |
33 /** | 28 /** |
34 * @type {!Object} | 29 * @private {!MetadataItem} |
35 * @private | |
36 */ | |
37 this.metadata_ = Object.preventExtensions(metadata); | |
38 | |
39 /** | |
40 * @type {!MetadataItem} | |
41 */ | 30 */ |
42 this.metadataItem_ = metadataItem; | 31 this.metadataItem_ = metadataItem; |
43 | 32 |
44 /** | 33 /** |
45 * @type {!MetadataCache} | 34 * @private {!ThumbnailMetadataItem} |
46 * @private | |
47 * @const | |
48 */ | 35 */ |
49 this.metadataCache_ = metadataCache; | 36 this.thumbnailMetadataItem_ = metadataItem; |
50 | |
51 /** | |
52 * @type {!MetadataModel} | |
53 * @private | |
54 * @const | |
55 */ | |
56 this.metadataModel_ = metadataModel; | |
57 | 37 |
58 // TODO(yawano): Change this.contentImage and this.screenImage to private | 38 // TODO(yawano): Change this.contentImage and this.screenImage to private |
59 // fields and provide utility methods for them (e.g. revokeFullImageCache). | 39 // fields and provide utility methods for them (e.g. revokeFullImageCache). |
60 /** | 40 /** |
61 * The content cache is used for prefetching the next image when going through | 41 * The content cache is used for prefetching the next image when going through |
62 * the images sequentially. The real life photos can be large (18Mpix = 72Mb | 42 * the images sequentially. The real life photos can be large (18Mpix = 72Mb |
63 * pixel array) so we want only the minimum amount of caching. | 43 * pixel array) so we want only the minimum amount of caching. |
64 * @type {(HTMLCanvasElement|HTMLImageElement)} | 44 * @type {(HTMLCanvasElement|HTMLImageElement)} |
65 */ | 45 */ |
66 this.contentImage = null; | 46 this.contentImage = null; |
(...skipping 27 matching lines...) Expand all Loading... |
94 Gallery.Item.prototype.getEntry = function() { return this.entry_; }; | 74 Gallery.Item.prototype.getEntry = function() { return this.entry_; }; |
95 | 75 |
96 /** | 76 /** |
97 * @return {!EntryLocation} Entry location information. | 77 * @return {!EntryLocation} Entry location information. |
98 */ | 78 */ |
99 Gallery.Item.prototype.getLocationInfo = function() { | 79 Gallery.Item.prototype.getLocationInfo = function() { |
100 return this.locationInfo_; | 80 return this.locationInfo_; |
101 }; | 81 }; |
102 | 82 |
103 /** | 83 /** |
104 * @return {!Object} Metadata. | 84 * @return {!MetadataItem} Metadata. |
105 */ | 85 */ |
106 Gallery.Item.prototype.getMetadata = function() { return this.metadata_; }; | 86 Gallery.Item.prototype.getMetadataItem = function() { |
| 87 return this.metadataItem_; |
| 88 }; |
107 | 89 |
108 /** | 90 /** |
109 * @return {!MetadataItem} Metadata. | 91 * @return {!MetadataItem} Metadata. |
110 */ | 92 */ |
111 Gallery.Item.prototype.getMetadataItem = function() { | 93 Gallery.Item.prototype.getMetadataItem = function() { |
112 return this.metadataItem_; | 94 return this.metadataItem_; |
113 }; | 95 }; |
114 | 96 |
115 /** | 97 /** |
| 98 * @return {!ThumbnailMetadataItem} Thumbnail metadata item. |
| 99 */ |
| 100 Gallery.Item.prototype.getThumbnailMetadataItem = function() { |
| 101 return this.thumbnailMetadataItem_; |
| 102 }; |
| 103 |
| 104 /** |
116 * @return {string} File name. | 105 * @return {string} File name. |
117 */ | 106 */ |
118 Gallery.Item.prototype.getFileName = function() { | 107 Gallery.Item.prototype.getFileName = function() { |
119 return this.entry_.name; | 108 return this.entry_.name; |
120 }; | 109 }; |
121 | 110 |
122 /** | 111 /** |
123 * @return {boolean} True if this image has not been created in this session. | 112 * @return {boolean} True if this image has not been created in this session. |
124 */ | 113 */ |
125 Gallery.Item.prototype.isOriginal = function() { return this.original_; }; | 114 Gallery.Item.prototype.isOriginal = function() { return this.original_; }; |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 callback.bind(null, name + ext)); | 206 callback.bind(null, name + ext)); |
218 } | 207 } |
219 | 208 |
220 tryNext(10); | 209 tryNext(10); |
221 }; | 210 }; |
222 | 211 |
223 /** | 212 /** |
224 * Writes the new item content to either the existing or a new file. | 213 * Writes the new item content to either the existing or a new file. |
225 * | 214 * |
226 * @param {!VolumeManager} volumeManager Volume manager instance. | 215 * @param {!VolumeManager} volumeManager Volume manager instance. |
| 216 * @param {!MetadataModel} metadataModel |
227 * @param {DirectoryEntry} fallbackDir Fallback directory in case the current | 217 * @param {DirectoryEntry} fallbackDir Fallback directory in case the current |
228 * directory is read only. | 218 * directory is read only. |
229 * @param {boolean} overwrite Whether to overwrite the image to the item or not. | 219 * @param {boolean} overwrite Whether to overwrite the image to the item or not. |
230 * @param {!HTMLCanvasElement} canvas Source canvas. | 220 * @param {!HTMLCanvasElement} canvas Source canvas. |
231 * @param {function(boolean)} callback Callback accepting true for success. | 221 * @param {function(boolean)} callback Callback accepting true for success. |
232 */ | 222 */ |
233 Gallery.Item.prototype.saveToFile = function( | 223 Gallery.Item.prototype.saveToFile = function( |
234 volumeManager, fallbackDir, overwrite, canvas, callback) { | 224 volumeManager, metadataModel, fallbackDir, overwrite, canvas, callback) { |
235 ImageUtil.metrics.startInterval(ImageUtil.getMetricName('SaveTime')); | 225 ImageUtil.metrics.startInterval(ImageUtil.getMetricName('SaveTime')); |
236 | 226 |
237 var name = this.getFileName(); | 227 var name = this.getFileName(); |
238 | 228 |
239 var onSuccess = function(entry) { | 229 var onSuccess = function(entry) { |
240 var locationInfo = volumeManager.getLocationInfo(entry); | 230 var locationInfo = volumeManager.getLocationInfo(entry); |
241 if (!locationInfo) { | 231 if (!locationInfo) { |
242 // Reuse old location info if it fails to obtain location info. | 232 // Reuse old location info if it fails to obtain location info. |
243 locationInfo = this.locationInfo_; | 233 locationInfo = this.locationInfo_; |
244 } | 234 } |
245 ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('SaveResult'), 1, 2); | 235 ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('SaveResult'), 1, 2); |
246 ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('SaveTime')); | 236 ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('SaveTime')); |
247 | 237 |
248 this.entry_ = entry; | 238 this.entry_ = entry; |
249 this.locationInfo_ = locationInfo; | 239 this.locationInfo_ = locationInfo; |
250 | 240 |
251 // Updates the metadata. | 241 // Updates the metadata. |
252 this.metadataCache_.clear([this.entry_], '*'); | 242 metadataModel.notifyEntriesChanged([this.entry_]); |
253 var oldMetadataPromise = new Promise(function(fulfill, reject) { | 243 Promise.all([ |
254 this.metadataCache_.getLatest( | 244 metadataModel.get([entry], Gallery.PREFETCH_PROPERTY_NAMES), |
255 [this.entry_], | 245 new ThumbnailModel(metadataModel).get([entry]) |
256 Gallery.METADATA_TYPE, | 246 ]).then(function(metadataLists) { |
257 function(metadataList) { | 247 this.metadataItem_ = metadataLists[0][0]; |
258 if (metadataList.length === 1) { | 248 this.thumbnailMetadataItem_ = metadataLists[1][0]; |
259 this.metadata_ = metadataList[0]; | 249 callback(true); |
260 fulfill(); | 250 }.bind(this), function() { |
261 } else { | 251 callback(false); |
262 reject(); | 252 }); |
263 } | |
264 }.bind(this)); | |
265 }.bind(this)); | |
266 this.metadataModel_.notifyEntriesChanged([this.entry_]); | |
267 var newMetadataPromise = this.metadataModel_.get( | |
268 [entry], Gallery.PREFETCH_PROPERTY_NAMES).then( | |
269 function(metadataItems) { | |
270 this.metadataItem_ = metadataItems[0]; | |
271 }.bind(this)); | |
272 if (callback) { | |
273 Promise.all([oldMetadataPromise, newMetadataPromise]).then( | |
274 callback.bind(null, true), | |
275 callback.bind(null, false)); | |
276 } | |
277 }.bind(this); | 253 }.bind(this); |
278 | 254 |
279 var onError = function(error) { | 255 var onError = function(error) { |
280 console.error('Error saving from gallery', name, error); | 256 console.error('Error saving from gallery', name, error); |
281 ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('SaveResult'), 0, 2); | 257 ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('SaveResult'), 0, 2); |
282 if (callback) | 258 if (callback) |
283 callback(false); | 259 callback(false); |
284 }; | 260 }; |
285 | 261 |
286 var doSave = function(newFile, fileEntry) { | 262 var doSave = function(newFile, fileEntry) { |
287 var metadataPromise = this.metadataModel_.get( | 263 var metadataPromise = metadataModel.get( |
288 [fileEntry], | 264 [fileEntry], |
289 ['mediaMimeType', 'contentMimeType', 'ifd', 'exifLittleEndian']); | 265 ['mediaMimeType', 'contentMimeType', 'ifd', 'exifLittleEndian']); |
290 metadataPromise.then(function(metadataItems) { | 266 metadataPromise.then(function(metadataItems) { |
291 fileEntry.createWriter(function(fileWriter) { | 267 fileEntry.createWriter(function(fileWriter) { |
292 var writeContent = function() { | 268 var writeContent = function() { |
293 fileWriter.onwriteend = onSuccess.bind(null, fileEntry); | 269 fileWriter.onwriteend = onSuccess.bind(null, fileEntry); |
294 var metadataItem = metadataItems[0]; | 270 var metadataItem = metadataItems[0]; |
295 metadataItem.modificationTime = new Date(); | 271 metadataItem.modificationTime = new Date(); |
296 var metadataEncoder = ImageEncoder.encodeMetadata( | 272 var metadataEncoder = ImageEncoder.encodeMetadata( |
297 metadataItem, canvas, /* quality for thumbnail*/ 0.8); | 273 metadataItem, canvas, /* quality for thumbnail*/ 0.8); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
379 return Promise.reject(str('GALLERY_FILE_EXISTS')); | 355 return Promise.reject(str('GALLERY_FILE_EXISTS')); |
380 }, function() { | 356 }, function() { |
381 return new Promise( | 357 return new Promise( |
382 this.entry_.moveTo.bind(this.entry_, parentDirectory, newFileName)); | 358 this.entry_.moveTo.bind(this.entry_, parentDirectory, newFileName)); |
383 }.bind(this)); | 359 }.bind(this)); |
384 }.bind(this)); | 360 }.bind(this)); |
385 }.bind(this)).then(function(entry) { | 361 }.bind(this)).then(function(entry) { |
386 this.entry_ = entry; | 362 this.entry_ = entry; |
387 }.bind(this)); | 363 }.bind(this)); |
388 }; | 364 }; |
OLD | NEW |