| Index: ui/file_manager/gallery/js/gallery_item.js
|
| diff --git a/ui/file_manager/gallery/js/gallery_item.js b/ui/file_manager/gallery/js/gallery_item.js
|
| index b8b354f8b267d83ea7debcf7f22b0872f7fbc1f1..c0c29a43d1430c03ed1f11bc2beb7cffc0ae16b7 100644
|
| --- a/ui/file_manager/gallery/js/gallery_item.js
|
| +++ b/ui/file_manager/gallery/js/gallery_item.js
|
| @@ -223,7 +223,7 @@ Gallery.Item.prototype.createCopyName_ = function(
|
| Gallery.Item.prototype.isWritableFormat = function() {
|
| var type = FileType.getType(this.entry_);
|
| return type.type === 'image' &&
|
| - (type.subtype === 'JPEG' || type.subtype === 'PNG')
|
| + (type.subtype === 'JPEG' || type.subtype === 'PNG');
|
| };
|
|
|
| /**
|
| @@ -262,7 +262,7 @@ Gallery.Item.prototype.getCopyName = function(dirEntry) {
|
| *
|
| * @param {!VolumeManagerWrapper} volumeManager Volume manager instance.
|
| * @param {!MetadataModel} metadataModel
|
| - * @param {DirectoryEntry} fallbackDir Fallback directory in case the current
|
| + * @param {!DirectoryEntry} fallbackDir Fallback directory in case the current
|
| * directory is read only.
|
| * @param {!HTMLCanvasElement} canvas Source canvas.
|
| * @param {boolean} overwrite Set true to overwrite original if it's possible.
|
| @@ -271,135 +271,146 @@ Gallery.Item.prototype.getCopyName = function(dirEntry) {
|
| Gallery.Item.prototype.saveToFile = function(
|
| volumeManager, metadataModel, fallbackDir, canvas, overwrite, callback) {
|
| ImageUtil.metrics.startInterval(ImageUtil.getMetricName('SaveTime'));
|
| -
|
| - var name = this.getFileName();
|
| - var newMimeType = this.getNewMimeType_();
|
| -
|
| - var onSuccess = function(entry) {
|
| - var locationInfo = volumeManager.getLocationInfo(entry);
|
| - if (!locationInfo) {
|
| - // Reuse old location info if it fails to obtain location info.
|
| - locationInfo = this.locationInfo_;
|
| - }
|
| - ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('SaveResult'), 1, 2);
|
| - ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('SaveTime'));
|
| -
|
| - this.entry_ = entry;
|
| - this.locationInfo_ = locationInfo;
|
| -
|
| - // Updates the metadata.
|
| - metadataModel.notifyEntriesChanged([this.entry_]);
|
| - Promise.all([
|
| - metadataModel.get([entry], Gallery.PREFETCH_PROPERTY_NAMES),
|
| - new ThumbnailModel(metadataModel).get([entry])
|
| - ]).then(function(metadataLists) {
|
| - this.metadataItem_ = metadataLists[0][0];
|
| - this.thumbnailMetadataItem_ = metadataLists[1][0];
|
| - callback(true);
|
| - }.bind(this), function() {
|
| - callback(false);
|
| - });
|
| - }.bind(this);
|
| -
|
| - var onError = function(error) {
|
| - console.error('Error saving from gallery', name, error);
|
| - ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('SaveResult'), 0, 2);
|
| - if (callback)
|
| - callback(false);
|
| - };
|
| -
|
| - var doSave = function(newFile, fileEntry) {
|
| - var blob;
|
| - var fileWriter;
|
| -
|
| - metadataModel.get(
|
| - [fileEntry],
|
| - ['mediaMimeType', 'contentMimeType', 'ifd', 'exifLittleEndian']
|
| - ).then(function(metadataItems) {
|
| - // Create the blob of new image.
|
| - var metadataItem = metadataItems[0];
|
| - metadataItem.modificationTime = new Date();
|
| - metadataItem.mediaMimeType = newMimeType;
|
| - var metadataEncoder = ImageEncoder.encodeMetadata(
|
| - metadataItem, canvas, /* quality for thumbnail*/ 0.8);
|
| - // Contrary to what one might think 1.0 is not a good default. Opening
|
| - // and saving an typical photo taken with consumer camera increases
|
| - // its file size by 50-100%. Experiments show that 0.9 is much better.
|
| - // It shrinks some photos a bit, keeps others about the same size, but
|
| - // does not visibly lower the quality.
|
| - blob = ImageEncoder.getBlob(canvas, metadataEncoder, 0.9);
|
| - }.bind(this)).then(function() {
|
| - // Create writer.
|
| - return new Promise(function(fullfill, reject) {
|
| - fileEntry.createWriter(fullfill, reject);
|
| - });
|
| - }).then(function(writer) {
|
| - fileWriter = writer;
|
| -
|
| - // Truncates the file to 0 byte if it overwrites.
|
| - return new Promise(function(fulfill, reject) {
|
| - if (!newFile) {
|
| + var saveResultRecorded = false;
|
| +
|
| + Promise.all([this.getEntryToWrite_(overwrite, fallbackDir, volumeManager),
|
| + this.getBlobForSave_(canvas, metadataModel)]).then(function(results) {
|
| + // Write content to the entry.
|
| + var fileEntry = results[0];
|
| + var blob = results[1];
|
| +
|
| + // Create writer.
|
| + return new Promise(function(resolve, reject) {
|
| + fileEntry.createWriter(resolve, reject);
|
| + }).then(function(fileWriter) {
|
| + // Truncates the file to 0 byte if it overwrites existing file.
|
| + return new Promise(function(resolve, reject) {
|
| + if (util.isSameEntry(fileEntry, this.entry_)) {
|
| fileWriter.onerror = reject;
|
| - fileWriter.onwriteend = fulfill;
|
| + fileWriter.onwriteend = resolve;
|
| fileWriter.truncate(0);
|
| } else {
|
| - fulfill(null);
|
| + resolve(null);
|
| }
|
| - });
|
| - }).then(function() {
|
| - // Writes the blob of new image.
|
| - return new Promise(function(fulfill, reject) {
|
| - fileWriter.onerror = reject;
|
| - fileWriter.onwriteend = fulfill;
|
| - fileWriter.write(blob);
|
| - });
|
| - }).then(onSuccess.bind(null, fileEntry))
|
| - .catch(function(error) {
|
| - onError(error);
|
| - if (fileWriter) {
|
| + }.bind(this)).then(function() {
|
| + // Writes the blob of new image.
|
| + return new Promise(function(resolve, reject) {
|
| + fileWriter.onerror = reject;
|
| + fileWriter.onwriteend = resolve;
|
| + fileWriter.write(blob);
|
| + });
|
| + }).catch(function(error) {
|
| // Disable all callbacks on the first error.
|
| fileWriter.onerror = null;
|
| fileWriter.onwriteend = null;
|
| +
|
| + return Promise.reject(error);
|
| + });
|
| + }.bind(this)).then(function() {
|
| + var locationInfo = volumeManager.getLocationInfo(fileEntry);
|
| + if (!locationInfo) {
|
| + // Reuse old location info if it fails to obtain location info.
|
| + locationInfo = this.locationInfo_;
|
| }
|
| - });
|
| - }.bind(this);
|
| -
|
| - var getFile = function(dir, newFile) {
|
| - dir.getFile(name, {create: newFile, exclusive: newFile},
|
| - function(fileEntry) {
|
| - doSave(newFile, fileEntry);
|
| - }.bind(this), onError);
|
| - }.bind(this);
|
| -
|
| - var checkExistence = function(dir) {
|
| - dir.getFile(name, {create: false, exclusive: false},
|
| - getFile.bind(null, dir, false /* existing file */),
|
| - getFile.bind(null, dir, true /* create new file */));
|
| - };
|
| -
|
| - var saveToDir = function(dir) {
|
| - if (overwrite &&
|
| - !this.locationInfo_.isReadOnly &&
|
| - this.isWritableFormat()) {
|
| - checkExistence(dir);
|
| - return;
|
| - }
|
|
|
| - this.createCopyName_(dir, newMimeType, function(copyName) {
|
| - this.original_ = false;
|
| - name = copyName;
|
| - checkExistence(dir);
|
| + ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('SaveResult'), 1, 2);
|
| + saveResultRecorded = true;
|
| + ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('SaveTime'));
|
| +
|
| + this.entry_ = fileEntry;
|
| + this.locationInfo_ = locationInfo;
|
| +
|
| + // Updates the metadata.
|
| + metadataModel.notifyEntriesChanged([this.entry_]);
|
| + Promise.all([
|
| + metadataModel.get([this.entry_], Gallery.PREFETCH_PROPERTY_NAMES),
|
| + new ThumbnailModel(metadataModel).get([this.entry_])
|
| + ]).then(function(metadataLists) {
|
| + this.metadataItem_ = metadataLists[0][0];
|
| + this.thumbnailMetadataItem_ = metadataLists[1][0];
|
| + callback(true);
|
| + }.bind(this), function() {
|
| + callback(false);
|
| + });
|
| }.bind(this));
|
| - }.bind(this);
|
| -
|
| - // Since in-place editing is not supported on MTP volume, Gallery.app handles
|
| - // MTP volume as read only volume.
|
| - if (this.locationInfo_.isReadOnly ||
|
| - GalleryUtil.isOnMTPVolume(this.entry_, volumeManager)) {
|
| - saveToDir(fallbackDir);
|
| - } else {
|
| - this.entry_.getParent(saveToDir, onError);
|
| - }
|
| + }.bind(this)).catch(function(error) {
|
| + console.error('Error saving from gallery', this.entry_.name, error);
|
| +
|
| + if (!saveResultRecorded)
|
| + ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('SaveResult'), 0, 2);
|
| +
|
| + callback(false);
|
| + }.bind(this));
|
| +};
|
| +
|
| +/**
|
| + * Returns file entry to write.
|
| + * @param {boolean} overwrite True to overwrite original file.
|
| + * @param {!DirectoryEntry} fallbackDirectory Directory to fallback if current
|
| + * directory is not writable.
|
| + * @param {!VolumeManagerWrapper} volumeManager
|
| + * @return {!Promise<!FileEntry>}
|
| + * @private
|
| + */
|
| +Gallery.Item.prototype.getEntryToWrite_ = function(
|
| + overwrite, fallbackDirectory, volumeManager) {
|
| + return new Promise(function(resolve, reject) {
|
| + // Since in-place editing is not supported on MTP volume, Gallery.app
|
| + // handles MTP volume as read only volume.
|
| + if (this.locationInfo_.isReadOnly ||
|
| + GalleryUtil.isOnMTPVolume(this.entry_, volumeManager)) {
|
| + resolve(fallbackDirectory);
|
| + } else {
|
| + this.entry_.getParent(resolve, reject);
|
| + }
|
| + }.bind(this)).then(function(directory) {
|
| + return new Promise(function(resolve) {
|
| + // Find file name.
|
| + if (overwrite &&
|
| + !this.locationInfo_.isReadOnly &&
|
| + this.isWritableFormat()) {
|
| + resolve(this.getFileName());
|
| + return;
|
| + }
|
| +
|
| + this.createCopyName_(
|
| + directory, this.getNewMimeType_(), function(copyName) {
|
| + this.original_ = false;
|
| + resolve(copyName);
|
| + }.bind(this));
|
| + }.bind(this)).then(function(name) {
|
| + // Get File entry and return.
|
| + return new Promise(directory.getFile.bind(
|
| + directory, name, { create: true, exclusive: false }));
|
| + });
|
| + }.bind(this));
|
| +};
|
| +
|
| +/**
|
| + * Returns blob to be saved.
|
| + * @param {!HTMLCanvasElement} canvas
|
| + * @param {!MetadataModel} metadataModel
|
| + * @return {!Promise<!Blob>}
|
| + * @private
|
| + */
|
| +Gallery.Item.prototype.getBlobForSave_ = function(canvas, metadataModel) {
|
| + return metadataModel.get(
|
| + [this.entry_],
|
| + ['mediaMimeType', 'contentMimeType', 'ifd', 'exifLittleEndian']
|
| + ).then(function(metadataItems) {
|
| + // Create the blob of new image.
|
| + var metadataItem = metadataItems[0];
|
| + metadataItem.modificationTime = new Date();
|
| + metadataItem.mediaMimeType = this.getNewMimeType_();
|
| + var metadataEncoder = ImageEncoder.encodeMetadata(
|
| + metadataItem, canvas, /* quality for thumbnail*/ 0.8);
|
| + // Contrary to what one might think 1.0 is not a good default. Opening
|
| + // and saving an typical photo taken with consumer camera increases
|
| + // its file size by 50-100%. Experiments show that 0.9 is much better.
|
| + // It shrinks some photos a bit, keeps others about the same size, but
|
| + // does not visibly lower the quality.
|
| + return ImageEncoder.getBlob(canvas, metadataEncoder, 0.9);
|
| + }.bind(this));
|
| };
|
|
|
| /**
|
|
|