| Index: ui/file_manager/gallery/js/image_editor/exif_encoder.js
|
| diff --git a/ui/file_manager/gallery/js/image_editor/exif_encoder.js b/ui/file_manager/gallery/js/image_editor/exif_encoder.js
|
| index 43f88dadf4b06366125a4751188d82e1c618c587..0a1813ccc3433fce73737870f6c6c3734698824e 100644
|
| --- a/ui/file_manager/gallery/js/image_editor/exif_encoder.js
|
| +++ b/ui/file_manager/gallery/js/image_editor/exif_encoder.js
|
| @@ -5,18 +5,35 @@
|
| /**
|
| * The Exif metadata encoder.
|
| * Uses the metadata format as defined by ExifParser.
|
| - * @param {!Object} originalMetadata Metadata to encode.
|
| + * @param {!MetadataItem} originalMetadata Metadata to encode.
|
| * @constructor
|
| * @extends {ImageEncoder.MetadataEncoder}
|
| * @struct
|
| */
|
| function ExifEncoder(originalMetadata) {
|
| ImageEncoder.MetadataEncoder.apply(this, arguments);
|
| -
|
| - if (this.metadata_.media && this.metadata_.media.ifd)
|
| - this.ifd_ = this.metadata_.media.ifd;
|
| - else
|
| - this.ifd_ = {};
|
| + /**
|
| + * Image File Directory obtained from EXIF header.
|
| + * @private {!Object}
|
| + * @const
|
| + */
|
| + this.ifd_ = /** @type {!Object} */(
|
| + JSON.parse(JSON.stringify(originalMetadata.ifd || {})));
|
| +
|
| + /**
|
| + * Note use little endian if the original metadata does not have the
|
| + * information.
|
| + * @private {boolean}
|
| + * @const
|
| + */
|
| + this.exifLittleEndian_ = !!originalMetadata.exifLittleEndian;
|
| +
|
| + /**
|
| + * Modification time to be stored in EXIF header.
|
| + * @private {!Date}
|
| + * @const
|
| + */
|
| + this.modificationTime_ = assert(originalMetadata.modificationTime);
|
| }
|
|
|
| ExifEncoder.prototype = {__proto__: ImageEncoder.MetadataEncoder.prototype};
|
| @@ -32,11 +49,11 @@ ExifEncoder.SOFTWARE = 'Chrome OS Gallery App\0';
|
|
|
| /**
|
| * @param {!HTMLCanvasElement} canvas
|
| - * @param {Date=} opt_modificationDateTime
|
| * @override
|
| */
|
| -ExifEncoder.prototype.setImageData =
|
| - function(canvas, opt_modificationDateTime) {
|
| +ExifEncoder.prototype.setImageData = function(canvas) {
|
| + ImageEncoder.MetadataEncoder.prototype.setImageData.call(this, canvas);
|
| +
|
| var image = this.ifd_.image;
|
| if (!image)
|
| image = this.ifd_.image = {};
|
| @@ -54,11 +71,7 @@ ExifEncoder.prototype.setImageData =
|
| ExifEncoder.findOrCreateTag(exif, Exif.Tag.X_DIMENSION).value = canvas.width;
|
| ExifEncoder.findOrCreateTag(exif, Exif.Tag.Y_DIMENSION).value = canvas.height;
|
|
|
| - this.metadata_.width = canvas.width;
|
| - this.metadata_.height = canvas.height;
|
| -
|
| // Always save in default orientation.
|
| - delete this.metadata_['imageTransform'];
|
| ExifEncoder.findOrCreateTag(image, Exif.Tag.ORIENTATION).value = 1;
|
|
|
| // Update software name.
|
| @@ -75,15 +88,14 @@ ExifEncoder.prototype.setImageData =
|
| return str;
|
| };
|
|
|
| - var modificationDateTime = opt_modificationDateTime || new Date();
|
| var dateTimeTag = ExifEncoder.findOrCreateTag(image, Exif.Tag.DATETIME, 2);
|
| dateTimeTag.value =
|
| - padNumWithZero(modificationDateTime.getFullYear(), 4) + ':' +
|
| - padNumWithZero(modificationDateTime.getMonth() + 1, 2) + ':' +
|
| - padNumWithZero(modificationDateTime.getDate(), 2) + ' ' +
|
| - padNumWithZero(modificationDateTime.getHours(), 2) + ':' +
|
| - padNumWithZero(modificationDateTime.getMinutes(), 2) + ':' +
|
| - padNumWithZero(modificationDateTime.getSeconds(), 2) + '\0';
|
| + padNumWithZero(this.modificationTime_.getFullYear(), 4) + ':' +
|
| + padNumWithZero(this.modificationTime_.getMonth() + 1, 2) + ':' +
|
| + padNumWithZero(this.modificationTime_.getDate(), 2) + ' ' +
|
| + padNumWithZero(this.modificationTime_.getHours(), 2) + ':' +
|
| + padNumWithZero(this.modificationTime_.getMinutes(), 2) + ':' +
|
| + padNumWithZero(this.modificationTime_.getSeconds(), 2) + '\0';
|
| dateTimeTag.componentCount = 20;
|
| };
|
|
|
| @@ -91,24 +103,28 @@ ExifEncoder.prototype.setImageData =
|
| * @override
|
| */
|
| ExifEncoder.prototype.setThumbnailData = function(canvas, quality) {
|
| - // Empirical formula with reasonable behavior:
|
| - // 10K for 1Mpix, 30K for 5Mpix, 50K for 9Mpix and up.
|
| - var pixelCount = this.metadata_.width * this.metadata_.height;
|
| - var maxEncodedSize = 5000 * Math.min(10, 1 + pixelCount / 1000000);
|
| -
|
| - var DATA_URL_PREFIX = 'data:' + this.metadata_.media.mimeType + ';base64,';
|
| - var BASE64_BLOAT = 4 / 3;
|
| - var maxDataURLLength =
|
| - DATA_URL_PREFIX.length + Math.ceil(maxEncodedSize * BASE64_BLOAT);
|
| -
|
| - for (;; quality *= 0.8) {
|
| - ImageEncoder.MetadataEncoder.prototype.setThumbnailData.call(
|
| - this, canvas, quality);
|
| - if (this.metadata_.thumbnailURL.length <= maxDataURLLength || quality < 0.2)
|
| + if (canvas) {
|
| + // Empirical formula with reasonable behavior:
|
| + // 10K for 1Mpix, 30K for 5Mpix, 50K for 9Mpix and up.
|
| + var pixelCount = this.imageWidth * this.imageHeight;
|
| + var maxEncodedSize = 5000 * Math.min(10, 1 + pixelCount / 1000000);
|
| + var DATA_URL_PREFIX = 'data:image/jpeg;base64,';
|
| + var BASE64_BLOAT = 4 / 3;
|
| + var maxDataURLLength =
|
| + DATA_URL_PREFIX.length + Math.ceil(maxEncodedSize * BASE64_BLOAT);
|
| + for (; quality > 0.2; quality *= 0.8) {
|
| + ImageEncoder.MetadataEncoder.prototype.setThumbnailData.call(
|
| + this, canvas, quality);
|
| + // If the obtained thumbnail URL is too long, reset the URL and try again
|
| + // with less quality value.
|
| + if (this.thumbnailDataUrl.length > maxDataURLLength) {
|
| + this.thumbnailDataUrl = '';
|
| + continue;
|
| + }
|
| break;
|
| + }
|
| }
|
| -
|
| - if (canvas && this.metadata_.thumbnailURL.length <= maxDataURLLength) {
|
| + if (this.thumbnailDataUrl) {
|
| var thumbnail = this.ifd_.thumbnail;
|
| if (!thumbnail)
|
| thumbnail = this.ifd_.thumbnail = {};
|
| @@ -130,13 +146,8 @@ ExifEncoder.prototype.setThumbnailData = function(canvas, quality) {
|
| ExifEncoder.findOrCreateTag(this.ifd_.image, Exif.Tag.COMPRESSION).value =
|
| 6;
|
| } else {
|
| - console.warn(
|
| - 'Thumbnail URL too long: ' + this.metadata_.thumbnailURL.length);
|
| - // Delete thumbnail ifd so that it is not written out to a file, but
|
| - // keep thumbnailURL for display purposes.
|
| - if (this.ifd_.thumbnail) {
|
| + if (this.ifd_.thumbnail)
|
| delete this.ifd_.thumbnail;
|
| - }
|
| }
|
| };
|
|
|
| @@ -207,7 +218,7 @@ ExifEncoder.prototype.encode = function() {
|
| // can be directly mapped to offsets as encoded in the dictionaries.
|
| var bw = new ByteWriter(bytes.buffer, HEADER_SIZE);
|
|
|
| - if (this.metadata_.littleEndian) {
|
| + if (this.exifLittleEndian_) {
|
| bw.setByteOrder(ByteWriter.ByteOrder.LITTLE_ENDIAN);
|
| bw.writeScalar(Exif.Align.LITTLE, 2);
|
| } else {
|
| @@ -246,8 +257,7 @@ ExifEncoder.prototype.encode = function() {
|
| this.ifd_.thumbnail,
|
| [Exif.Tag.JPG_THUMB_OFFSET, Exif.Tag.JPG_THUMB_LENGTH]);
|
|
|
| - var thumbnailDecoded =
|
| - ImageEncoder.decodeDataURL(this.metadata_.thumbnailURL);
|
| + var thumbnailDecoded = ImageEncoder.decodeDataURL(this.thumbnailDataUrl);
|
| bw.resolveOffset(Exif.Tag.JPG_THUMB_OFFSET);
|
| bw.resolve(Exif.Tag.JPG_THUMB_LENGTH, thumbnailDecoded.length);
|
| bw.writeString(thumbnailDecoded);
|
|
|