Commit 1fc74097 authored by yawano's avatar yawano Committed by Commit bot

Crop image at image_loader.

To avoid wide image becomes blurry thumbnail, crop image at image_loader.
Currently it is used only for thumbnails, we only support to crop an image into square.

BUG=480679
TEST=ImageLoaderJsTest.ImageLoaderTest

Review URL: https://codereview.chromium.org/1137993007

Cr-Commit-Position: refs/heads/master@{#329609}
parent 8b02218a
......@@ -16,6 +16,9 @@ IN_PROC_BROWSER_TEST_F(ImageLoaderJsTest, ImageLoaderClientTest) {
}
IN_PROC_BROWSER_TEST_F(ImageLoaderJsTest, CacheTest) {
RunTest(base::FilePath(FILE_PATH_LITERAL(
"cache_unittest.html")));
RunTest(base::FilePath(FILE_PATH_LITERAL("cache_unittest.html")));
}
IN_PROC_BROWSER_TEST_F(ImageLoaderJsTest, ImageLoaderTest) {
RunTest(base::FilePath(FILE_PATH_LITERAL("image_loader_unittest.html")));
}
......@@ -264,11 +264,27 @@ ThumbnailLoader.prototype.loadAsDataUrl = function(fillMode) {
this.metadata_.filesystem &&
this.metadata_.filesystem.modificationTime &&
this.metadata_.filesystem.modificationTime.getTime();
var thumbnailUrl =
fillMode === ThumbnailLoader.FillMode.OVER_FILL &&
this.croppedThumbnailUrl_ ?
this.croppedThumbnailUrl_ :
this.thumbnailUrl_;
var thumbnailUrl = this.thumbnailUrl_;
var options = {
maxWidth: ThumbnailLoader.THUMBNAIL_MAX_WIDTH,
maxHeight: ThumbnailLoader.THUMBNAIL_MAX_HEIGHT,
cache: true,
priority: this.priority_,
timestamp: modificationTime
};
if (fillMode === ThumbnailLoader.FillMode.OVER_FILL) {
// Use cropped thumbnail url if available.
thumbnailUrl = this.croppedThumbnailUrl_ ?
this.croppedThumbnailUrl_ : this.thumbnailUrl_;
// Set crop option to image loader. Since image of croppedThumbnailUrl_ is
// 360x360 with current implemenation, it's no problem to crop it.
options['width'] = 360;
options['height'] = 360;
options['crop'] = true;
}
ImageLoaderClient.getInstance().load(
thumbnailUrl,
function(result) {
......@@ -277,13 +293,7 @@ ThumbnailLoader.prototype.loadAsDataUrl = function(fillMode) {
else
reject(result);
},
{
maxWidth: ThumbnailLoader.THUMBNAIL_MAX_WIDTH,
maxHeight: ThumbnailLoader.THUMBNAIL_MAX_HEIGHT,
cache: true,
priority: this.priority_,
timestamp: modificationTime
});
options);
}.bind(this)).then(function(result) {
if (!this.transform_)
return result;
......
......@@ -7,7 +7,8 @@
'target_name': 'background',
'variables': {
'depends': [
"../file_manager/common/js/file_type.js",
'../../webui/resources/js/assert.js',
'../file_manager/common/js/file_type.js',
'../file_manager/common/js/metrics_base.js',
'../file_manager/common/js/metrics.js',
'../file_manager/common/js/metrics_events.js',
......
......@@ -204,34 +204,120 @@ ImageLoader.resizeDimensions = function(width, height, options) {
};
/**
* Performs resizing of the source image into the target canvas.
* Performs resizing and cropping of the source image into the target canvas.
*
* @param {HTMLCanvasElement|Image} source Source image or canvas.
* @param {HTMLCanvasElement} target Target canvas.
* @param {Object} options Resizing options as a hash array.
*/
ImageLoader.resize = function(source, target, options) {
var targetDimensions = ImageLoader.resizeDimensions(
source.width, source.height, options);
ImageLoader.resizeAndCrop = function(source, target, options) {
// Default orientation is 0deg.
var orientation = options.orientation || new ImageOrientation(1, 0, 0, 1);
var size = orientation.getSizeAfterCancelling(
targetDimensions.width, targetDimensions.height);
target.width = size.width;
target.height = size.height;
var orientation =
ImageOrientation.fromDriveOrientation(options.orientation || 0);
// Calculates copy parameters.
var copyParameters = ImageLoader.calculateCopyParameters(source, options);
target.width = copyParameters.canvas.width;
target.height = copyParameters.canvas.height;
var targetContext = target.getContext('2d');
// Apply.
var targetContext =
/** @type {CanvasRenderingContext2D} */ (target.getContext('2d'));
targetContext.save();
orientation.cancelImageOrientation(
targetContext, targetDimensions.width, targetDimensions.height);
targetContext, copyParameters.target.width, copyParameters.target.height);
targetContext.drawImage(
source,
0, 0, source.width, source.height,
0, 0, targetDimensions.width, targetDimensions.height);
copyParameters.source.x,
copyParameters.source.y,
copyParameters.source.width,
copyParameters.source.height,
copyParameters.target.x,
copyParameters.target.y,
copyParameters.target.width,
copyParameters.target.height);
targetContext.restore();
};
/**
* @typedef {{
* source: {x:number, y:number, width:number, height:number},
* target: {x:number, y:number, width:number, height:number},
* canvas: {width:number, height:number}
* }}
*/
ImageLoader.CopyParameters;
/**
* Calculates copy parameters.
*
* @param {HTMLCanvasElement|Image} source Source image or canvas.
* @param {Object} options Resizing options as a hash array.
* @return {!ImageLoader.CopyParameters} Calculated copy parameters.
*/
ImageLoader.calculateCopyParameters = function(source, options) {
if (options.crop) {
// When an image is cropped, target should be a fixed size square.
assert(options.width);
assert(options.height);
assert(options.width === options.height);
// The length of shorter edge becomes dimension of cropped area in the
// source.
var cropSourceDimension = Math.min(source.width, source.height);
return {
source: {
x: Math.floor((source.width / 2) - (cropSourceDimension / 2)),
y: Math.floor((source.height / 2) - (cropSourceDimension / 2)),
width: cropSourceDimension,
height: cropSourceDimension
},
target: {
x: 0,
y: 0,
width: options.width,
height: options.height
},
canvas: {
width: options.width,
height: options.height
}
};
}
// Target dimension is calculated in the rotated(transformed) coordinate.
var targetCanvasDimensions = ImageLoader.resizeDimensions(
source.width, source.height, options);
var targetDimensions = targetCanvasDimensions;
if (options.orientation && options.orientation % 2) {
targetDimensions = {
width: targetCanvasDimensions.height,
height: targetCanvasDimensions.width
};
}
return {
source: {
x: 0,
y: 0,
width: source.width,
height: source.height
},
target: {
x: 0,
y: 0,
width: targetDimensions.width,
height: targetDimensions.height
},
canvas: {
width: targetCanvasDimensions.width,
height: targetCanvasDimensions.height
}
};
};
/**
* Matrix converts AdobeRGB color space into sRGB color space.
* @const {!Array<number>}
......
<!DOCTYPE html>
<!-- Copyright 2015 The Chromium Authors. All rights reserved.
-- Use of this source code is governed by a BSD-style license that can be
-- found in the LICENSE file.
-->
<script src="../../webui/resources/js/assert.js"></script>
<script src="../file_manager/foreground/js/metadata/image_orientation.js"></script>
<script src="image_loader.js"></script>
<script src="image_loader_unittest.js"></script>
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Test case:
* - Source image: 200x50
* - Target: max size is 100x100
*/
function testNormalImage() {
var source = new Image();
source.width = 200;
source.height = 50;
var options = {
maxWidth: 100,
maxHeight: 100
};
var result = ImageLoader.calculateCopyParameters(source, options);
assertEquals(0, result.source.x);
assertEquals(0, result.source.y);
assertEquals(200, result.source.width);
assertEquals(50, result.source.height);
assertEquals(0, result.target.x);
assertEquals(0, result.target.y);
assertEquals(100, result.target.width);
assertEquals(25, result.target.height);
assertEquals(100, result.canvas.width);
assertEquals(25, result.canvas.height);
};
/**
* Test case:
* - Source image: 50x200 90 deg clock-wise rotated image.
* - Target: max size is 100x100
*/
function testRotatedImage() {
var source = new Image();
source.width = 50;
source.height = 200;
var options = {
maxWidth: 100,
maxHeight: 100,
orientation: 1
};
var result = ImageLoader.calculateCopyParameters(source, options);
assertEquals(0, result.source.x);
assertEquals(0, result.source.y);
assertEquals(50, result.source.width);
assertEquals(200, result.source.height);
assertEquals(0, result.target.x);
assertEquals(0, result.target.y);
assertEquals(25, result.target.width);
assertEquals(100, result.target.height);
assertEquals(100, result.canvas.width);
assertEquals(25, result.canvas.height);
}
/**
* Test case:
* - Source image: 800x100
* - Target: 50x50 cropped image.
*/
function testCroppedImage() {
var source = new Image();
source.width = 800;
source.height = 100;
var options = {
width: 50,
height: 50,
crop: true
};
var result = ImageLoader.calculateCopyParameters(source, options);
assertEquals(350, result.source.x);
assertEquals(0, result.source.y);
assertEquals(100, result.source.width);
assertEquals(100, result.source.height);
assertEquals(0, result.target.x);
assertEquals(0, result.target.y);
assertEquals(50, result.target.width);
assertEquals(50, result.target.height);
assertEquals(50, result.canvas.width);
assertEquals(50, result.canvas.height);
}
/**
* Test case:
* - Source image: 200x25
* - Target: 50x50 cropped image.
*/
function testCroppedImageWithResize() {
var source = new Image();
source.width = 200;
source.height = 25;
var options = {
width: 50,
height: 50,
crop: true
};
var result = ImageLoader.calculateCopyParameters(source, options);
assertEquals(87, result.source.x);
assertEquals(0, result.source.y);
assertEquals(25, result.source.width);
assertEquals(25, result.source.height);
assertEquals(0, result.target.x);
assertEquals(0, result.target.y);
assertEquals(50, result.target.width);
assertEquals(50, result.target.height);
assertEquals(50, result.canvas.width);
assertEquals(50, result.canvas.height);
}
/**
* Test case:
* - Source image: 20x10
* - Target: 50x50 cropped image.
*/
function testCroppedTinyImage() {
var source = new Image();
source.width = 20;
source.height = 10;
var options = {
width: 50,
height: 50,
crop: true
};
var result = ImageLoader.calculateCopyParameters(source, options);
assertEquals(5, result.source.x);
assertEquals(0, result.source.y);
assertEquals(10, result.source.width);
assertEquals(10, result.source.height);
assertEquals(0, result.target.x);
assertEquals(0, result.target.y);
assertEquals(50, result.target.width);
assertEquals(50, result.target.height);
assertEquals(50, result.canvas.width);
assertEquals(50, result.canvas.height);
}
/**
* Test case:
* - Source image: 100x400 90 degree clock-wise rotated.
* - Target: 50x50 cropped image
*/
function testCroppedRotatedImage() {
var source = new Image();
source.width = 100;
source.height = 400;
var options = {
width: 50,
height: 50,
crop: true,
orientation: 1
};
var result = ImageLoader.calculateCopyParameters(source, options);
assertEquals(0, result.source.x);
assertEquals(150, result.source.y);
assertEquals(100, result.source.width);
assertEquals(100, result.source.height);
assertEquals(0, result.target.x);
assertEquals(0, result.target.y);
assertEquals(50, result.target.width);
assertEquals(50, result.target.height);
assertEquals(50, result.canvas.width);
assertEquals(50, result.canvas.height);
}
......@@ -19,6 +19,7 @@
"content_security_policy": "default-src 'none'; script-src 'self' chrome://resources chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj; style-src 'self'; frame-src 'self'; img-src 'self' data:; media-src 'self'; connect-src 'self' https://www.googledrive.com",
"background": {
"scripts": [
"chrome://resources/js/assert.js",
"chrome://resources/js/analytics.js",
"cache.js",
"chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/common/js/file_type.js",
......
......@@ -487,7 +487,7 @@ Request.prototype.onImageLoad_ = function() {
ImageLoader.shouldProcess(this.image_.width,
this.image_.height,
this.request_)) {
ImageLoader.resize(this.image_, this.canvas_, this.request_);
ImageLoader.resizeAndCrop(this.image_, this.canvas_, this.request_);
ImageLoader.convertColorSpace(
this.canvas_, this.request_.colorSpace || ColorSpace.SRGB);
this.sendImage_(true); // Image changed.
......
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