Commit 0b953348 authored by Noel Gordon's avatar Noel Gordon Committed by Chromium LUCI CQ

[imageloader] Add JPEG EXIF orientation override

When Blink renders a JPEG that has EXIF orientation via new Image() it
now reports the image width / height with the EXIF orientation applied
for some JPEG images [1].

The FilesApp file list also examines the JPEG image metadata and works
out it has EXIF orientation, and requests that EXIF orientation in the
thumbnail request it sends to the image loader. That combined with the
Blink change causes the image loader cropping/resizing code to produce
an output image that has the EXIF orientation applied twice.

Fix this: override the image loader request's orientation during image
processing operations of JPEG images to use EXIF orientation 1 so that
the image orientation is applied by Blink alone. Restore the request's
orientation after the processing operations.

[1] Observation in testing: not every JPEG the image loader deals with
is affected. The bug seems to depend on how the JPEG image is served:

 • Load the JPEG image from a file-system URL (normal files app case)
   or from a window.createObjectURL (piex-wasm) and the bug occurs.
 • Load the JPEG image from dataURL and the bug does not occur so the
   must apply the request orientation in that case.

Bug: 1152084
Change-Id: I478dcf756846bf9e67ee37fe2009319c2af3b79b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2567071Reviewed-by: default avatarAlex Danilo <adanilo@chromium.org>
Reviewed-by: default avatarNoel Gordon <noel@chromium.org>
Reviewed-by: default avatarLuciano Pacheco <lucmult@chromium.org>
Commit-Queue: Noel Gordon <noel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#832591}
parent 95ce1615
......@@ -82,6 +82,11 @@ function ImageRequestTask(id, cache, request, callback) {
this.context_ =
/** @type {CanvasRenderingContext2D} */ (this.canvas_.getContext('2d'));
/**
* @type {ImageOrientation|null}
*/
this.renderOrientation_ = null;
/**
* Callback to be called once downloading is finished.
* @type {?function()}
......@@ -391,6 +396,7 @@ ImageRequestTask.prototype.downloadThumbnail_ = function(onSuccess, onFailure) {
PiexLoader.load(this.request_.url, chrome.runtime.reload)
.then(
function(data) {
// TODO(crbug.com/1152084): use this.renderOrientation_.
this.request_.orientation =
ImageOrientation.fromExifOrientation(data.orientation);
this.ifd_ = data.ifd;
......@@ -422,6 +428,9 @@ ImageRequestTask.prototype.downloadThumbnail_ = function(onSuccess, onFailure) {
this.load(this.request_.url, (contentType, blob) => {
this.image_.src = blob ? URL.createObjectURL(blob) : '!';
this.contentType_ = contentType || null;
if (this.contentType_ === 'image/jpeg') {
this.renderOrientation_ = ImageOrientation.fromExifOrientation(1);
}
}, onFailure);
};
......@@ -619,6 +628,13 @@ ImageRequestTask.prototype.sendImageData_ = function(width, height, data) {
* @private
*/
ImageRequestTask.prototype.onImageLoad_ = function() {
const requestOrientation = this.request_.orientation;
// Override the request orientation before processing if needed.
if (this.renderOrientation_) {
this.request_.orientation = this.renderOrientation_;
}
// Perform processing if the url is not a data url, or if there are some
// operations requested.
let imageChanged = false;
......@@ -630,6 +646,12 @@ ImageRequestTask.prototype.onImageLoad_ = function() {
imageChanged = true; // The image is now on the <canvas>.
}
// Restore the request orientation after processing.
if (this.renderOrientation_) {
this.request_.orientation = requestOrientation;
}
// Finalize the request.
this.sendImage_(imageChanged);
this.cleanup_();
this.downloadCallback_();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment