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. | 10 * @param {!Object} metadata Metadata for the entry. |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 function(metadata) { | 105 function(metadata) { |
106 if (metadata[0]) | 106 if (metadata[0]) |
107 fulfill(metadata[0]); | 107 fulfill(metadata[0]); |
108 else | 108 else |
109 reject('Failed to load metadata.'); | 109 reject('Failed to load metadata.'); |
110 }); | 110 }); |
111 }.bind(this)); | 111 }.bind(this)); |
112 }; | 112 }; |
113 | 113 |
114 /** | 114 /** |
115 * Sets the metadata. | |
116 * @param {!Object} metadata New metadata. | |
117 */ | |
118 Gallery.Item.prototype.setMetadata = function(metadata) { | |
119 this.metadata_ = Object.preventExtensions(metadata); | |
120 }; | |
121 | |
122 /** | |
123 * @return {string} File name. | 115 * @return {string} File name. |
124 */ | 116 */ |
125 Gallery.Item.prototype.getFileName = function() { | 117 Gallery.Item.prototype.getFileName = function() { |
126 return this.entry_.name; | 118 return this.entry_.name; |
127 }; | 119 }; |
128 | 120 |
129 /** | 121 /** |
130 * @return {boolean} True if this image has not been created in this session. | 122 * @return {boolean} True if this image has not been created in this session. |
131 */ | 123 */ |
132 Gallery.Item.prototype.isOriginal = function() { return this.original_; }; | 124 Gallery.Item.prototype.isOriginal = function() { return this.original_; }; |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 callback.bind(null, name + ext)); | 216 callback.bind(null, name + ext)); |
225 } | 217 } |
226 | 218 |
227 tryNext(10); | 219 tryNext(10); |
228 }; | 220 }; |
229 | 221 |
230 /** | 222 /** |
231 * Writes the new item content to either the existing or a new file. | 223 * Writes the new item content to either the existing or a new file. |
232 * | 224 * |
233 * @param {!VolumeManager} volumeManager Volume manager instance. | 225 * @param {!VolumeManager} volumeManager Volume manager instance. |
234 * @param {string} fallbackDir Fallback directory in case the current directory | 226 * @param {DirectoryEntry} fallbackDir Fallback directory in case the current |
235 * is read only. | 227 * directory is read only. |
236 * @param {boolean} overwrite Whether to overwrite the image to the item or not. | 228 * @param {boolean} overwrite Whether to overwrite the image to the item or not. |
237 * @param {!HTMLCanvasElement} canvas Source canvas. | 229 * @param {!HTMLCanvasElement} canvas Source canvas. |
238 * @param {!ImageEncoder.MetadataEncoder} metadataEncoder MetadataEncoder. | |
239 * @param {function(boolean)=} opt_callback Callback accepting true for success. | 230 * @param {function(boolean)=} opt_callback Callback accepting true for success. |
240 */ | 231 */ |
241 Gallery.Item.prototype.saveToFile = function( | 232 Gallery.Item.prototype.saveToFile = function( |
242 volumeManager, fallbackDir, overwrite, canvas, metadataEncoder, | 233 volumeManager, fallbackDir, overwrite, canvas, opt_callback) { |
243 opt_callback) { | |
244 ImageUtil.metrics.startInterval(ImageUtil.getMetricName('SaveTime')); | 234 ImageUtil.metrics.startInterval(ImageUtil.getMetricName('SaveTime')); |
245 | 235 |
246 var name = this.getFileName(); | 236 var name = this.getFileName(); |
247 | 237 |
248 var onSuccess = function(entry, locationInfo) { | 238 var onSuccess = function(entry) { |
| 239 var locationInfo = volumeManager.getLocationInfo(entry); |
| 240 if (!locationInfo) { |
| 241 // Reuse old location info if it fails to obtain location info. |
| 242 locationInfo = this.locationInfo_; |
| 243 } |
249 ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('SaveResult'), 1, 2); | 244 ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('SaveResult'), 1, 2); |
250 ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('SaveTime')); | 245 ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('SaveTime')); |
251 | 246 |
252 this.entry_ = entry; | 247 this.entry_ = entry; |
253 this.locationInfo_ = locationInfo; | 248 this.locationInfo_ = locationInfo; |
254 | 249 |
255 this.metadataCache_.clear([this.entry_], 'fetchedMedia'); | 250 // Updates the metadata. |
256 if (opt_callback) | 251 this.metadataCache_.clear([this.entry_], '*'); |
257 opt_callback(true); | 252 this.metadataCache_.getLatest( |
| 253 [this.entry_], |
| 254 Gallery.METADATA_TYPE, |
| 255 function(metadataList) { |
| 256 if (metadataList.length === 1) { |
| 257 this.metadata_ = metadataList[0]; |
| 258 if (opt_callback) |
| 259 opt_callback(true); |
| 260 } else { |
| 261 if (opt_callback) |
| 262 opt_callback(false); |
| 263 } |
| 264 }.bind(this)); |
258 }.bind(this); | 265 }.bind(this); |
259 | 266 |
260 var onError = function(error) { | 267 var onError = function(error) { |
261 console.error('Error saving from gallery', name, error); | 268 console.error('Error saving from gallery', name, error); |
262 ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('SaveResult'), 0, 2); | 269 ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('SaveResult'), 0, 2); |
263 if (opt_callback) | 270 if (opt_callback) |
264 opt_callback(false); | 271 opt_callback(false); |
265 }; | 272 }; |
266 | 273 |
267 var doSave = function(newFile, fileEntry) { | 274 var doSave = function(newFile, fileEntry) { |
268 fileEntry.createWriter(function(fileWriter) { | 275 fileEntry.createWriter(function(fileWriter) { |
269 function writeContent() { | 276 var writeContent = function() { |
270 fileWriter.onwriteend = onSuccess.bind(null, fileEntry); | 277 fileWriter.onwriteend = onSuccess.bind(null, fileEntry); |
| 278 // TODO(hirono): Remove the quality 1 for thumbanils. The code path is |
| 279 // no longer used. |
| 280 var metadataEncoder = ImageEncoder.encodeMetadata( |
| 281 this.metadata_, canvas, 1 /* quality */); |
271 // Contrary to what one might think 1.0 is not a good default. Opening | 282 // Contrary to what one might think 1.0 is not a good default. Opening |
272 // and saving an typical photo taken with consumer camera increases its | 283 // and saving an typical photo taken with consumer camera increases its |
273 // file size by 50-100%. Experiments show that 0.9 is much better. It | 284 // file size by 50-100%. Experiments show that 0.9 is much better. It |
274 // shrinks some photos a bit, keeps others about the same size, but does | 285 // shrinks some photos a bit, keeps others about the same size, but does |
275 // not visibly lower the quality. | 286 // not visibly lower the quality. |
276 fileWriter.write(ImageEncoder.getBlob(canvas, metadataEncoder, 0.9)); | 287 fileWriter.write(ImageEncoder.getBlob(canvas, metadataEncoder, 0.9)); |
277 } | 288 }.bind(this); |
278 fileWriter.onerror = function(error) { | 289 fileWriter.onerror = function(error) { |
279 onError(error); | 290 onError(error); |
280 // Disable all callbacks on the first error. | 291 // Disable all callbacks on the first error. |
281 fileWriter.onerror = null; | 292 fileWriter.onerror = null; |
282 fileWriter.onwriteend = null; | 293 fileWriter.onwriteend = null; |
283 }; | 294 }; |
284 if (newFile) { | 295 if (newFile) { |
285 writeContent(); | 296 writeContent(); |
286 } else { | 297 } else { |
287 fileWriter.onwriteend = writeContent; | 298 fileWriter.onwriteend = writeContent; |
288 fileWriter.truncate(0); | 299 fileWriter.truncate(0); |
289 } | 300 } |
290 }, onError); | 301 }.bind(this), onError); |
291 }; | 302 }.bind(this); |
292 | 303 |
293 var getFile = function(dir, newFile) { | 304 var getFile = function(dir, newFile) { |
294 dir.getFile(name, {create: newFile, exclusive: newFile}, | 305 dir.getFile(name, {create: newFile, exclusive: newFile}, |
295 function(fileEntry) { | 306 function(fileEntry) { |
296 var locationInfo = volumeManager.getLocationInfo(fileEntry); | |
297 // If the volume is gone, then abort the saving operation. | |
298 if (!locationInfo) { | |
299 onError('NotFound'); | |
300 return; | |
301 } | |
302 doSave(newFile, fileEntry); | 307 doSave(newFile, fileEntry); |
303 }.bind(this), onError); | 308 }.bind(this), onError); |
304 }.bind(this); | 309 }.bind(this); |
305 | 310 |
306 var checkExistence = function(dir) { | 311 var checkExistence = function(dir) { |
307 dir.getFile(name, {create: false, exclusive: false}, | 312 dir.getFile(name, {create: false, exclusive: false}, |
308 getFile.bind(null, dir, false /* existing file */), | 313 getFile.bind(null, dir, false /* existing file */), |
309 getFile.bind(null, dir, true /* create new file */)); | 314 getFile.bind(null, dir, true /* create new file */)); |
310 }; | 315 }; |
311 | 316 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
357 return Promise.reject(str('GALLERY_FILE_EXISTS')); | 362 return Promise.reject(str('GALLERY_FILE_EXISTS')); |
358 }, function() { | 363 }, function() { |
359 return new Promise( | 364 return new Promise( |
360 this.entry_.moveTo.bind(this.entry_, parentDirectory, newFileName)); | 365 this.entry_.moveTo.bind(this.entry_, parentDirectory, newFileName)); |
361 }.bind(this)); | 366 }.bind(this)); |
362 }.bind(this)); | 367 }.bind(this)); |
363 }.bind(this)).then(function(entry) { | 368 }.bind(this)).then(function(entry) { |
364 this.entry_ = entry; | 369 this.entry_ = entry; |
365 }.bind(this)); | 370 }.bind(this)); |
366 }; | 371 }; |
OLD | NEW |