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) { ...@@ -16,6 +16,9 @@ IN_PROC_BROWSER_TEST_F(ImageLoaderJsTest, ImageLoaderClientTest) {
} }
IN_PROC_BROWSER_TEST_F(ImageLoaderJsTest, CacheTest) { IN_PROC_BROWSER_TEST_F(ImageLoaderJsTest, CacheTest) {
RunTest(base::FilePath(FILE_PATH_LITERAL( RunTest(base::FilePath(FILE_PATH_LITERAL("cache_unittest.html")));
"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) { ...@@ -264,11 +264,27 @@ ThumbnailLoader.prototype.loadAsDataUrl = function(fillMode) {
this.metadata_.filesystem && this.metadata_.filesystem &&
this.metadata_.filesystem.modificationTime && this.metadata_.filesystem.modificationTime &&
this.metadata_.filesystem.modificationTime.getTime(); this.metadata_.filesystem.modificationTime.getTime();
var thumbnailUrl = var thumbnailUrl = this.thumbnailUrl_;
fillMode === ThumbnailLoader.FillMode.OVER_FILL && var options = {
this.croppedThumbnailUrl_ ? maxWidth: ThumbnailLoader.THUMBNAIL_MAX_WIDTH,
this.croppedThumbnailUrl_ : maxHeight: ThumbnailLoader.THUMBNAIL_MAX_HEIGHT,
this.thumbnailUrl_; 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( ImageLoaderClient.getInstance().load(
thumbnailUrl, thumbnailUrl,
function(result) { function(result) {
...@@ -277,13 +293,7 @@ ThumbnailLoader.prototype.loadAsDataUrl = function(fillMode) { ...@@ -277,13 +293,7 @@ ThumbnailLoader.prototype.loadAsDataUrl = function(fillMode) {
else else
reject(result); reject(result);
}, },
{ options);
maxWidth: ThumbnailLoader.THUMBNAIL_MAX_WIDTH,
maxHeight: ThumbnailLoader.THUMBNAIL_MAX_HEIGHT,
cache: true,
priority: this.priority_,
timestamp: modificationTime
});
}.bind(this)).then(function(result) { }.bind(this)).then(function(result) {
if (!this.transform_) if (!this.transform_)
return result; return result;
......
...@@ -7,7 +7,8 @@ ...@@ -7,7 +7,8 @@
'target_name': 'background', 'target_name': 'background',
'variables': { 'variables': {
'depends': [ '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_base.js',
'../file_manager/common/js/metrics.js', '../file_manager/common/js/metrics.js',
'../file_manager/common/js/metrics_events.js', '../file_manager/common/js/metrics_events.js',
......
...@@ -204,34 +204,120 @@ ImageLoader.resizeDimensions = function(width, height, options) { ...@@ -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|Image} source Source image or canvas.
* @param {HTMLCanvasElement} target Target canvas. * @param {HTMLCanvasElement} target Target canvas.
* @param {Object} options Resizing options as a hash array. * @param {Object} options Resizing options as a hash array.
*/ */
ImageLoader.resize = function(source, target, options) { ImageLoader.resizeAndCrop = function(source, target, options) {
var targetDimensions = ImageLoader.resizeDimensions(
source.width, source.height, options);
// Default orientation is 0deg. // Default orientation is 0deg.
var orientation = options.orientation || new ImageOrientation(1, 0, 0, 1); var orientation =
var size = orientation.getSizeAfterCancelling( ImageOrientation.fromDriveOrientation(options.orientation || 0);
targetDimensions.width, targetDimensions.height);
target.width = size.width; // Calculates copy parameters.
target.height = size.height; 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(); targetContext.save();
orientation.cancelImageOrientation( orientation.cancelImageOrientation(
targetContext, targetDimensions.width, targetDimensions.height); targetContext, copyParameters.target.width, copyParameters.target.height);
targetContext.drawImage( targetContext.drawImage(
source, source,
0, 0, source.width, source.height, copyParameters.source.x,
0, 0, targetDimensions.width, targetDimensions.height); copyParameters.source.y,
copyParameters.source.width,
copyParameters.source.height,
copyParameters.target.x,
copyParameters.target.y,
copyParameters.target.width,
copyParameters.target.height);
targetContext.restore(); 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. * Matrix converts AdobeRGB color space into sRGB color space.
* @const {!Array<number>} * @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 @@ ...@@ -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", "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": { "background": {
"scripts": [ "scripts": [
"chrome://resources/js/assert.js",
"chrome://resources/js/analytics.js", "chrome://resources/js/analytics.js",
"cache.js", "cache.js",
"chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/common/js/file_type.js", "chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/common/js/file_type.js",
......
...@@ -487,7 +487,7 @@ Request.prototype.onImageLoad_ = function() { ...@@ -487,7 +487,7 @@ Request.prototype.onImageLoad_ = function() {
ImageLoader.shouldProcess(this.image_.width, ImageLoader.shouldProcess(this.image_.width,
this.image_.height, this.image_.height,
this.request_)) { this.request_)) {
ImageLoader.resize(this.image_, this.canvas_, this.request_); ImageLoader.resizeAndCrop(this.image_, this.canvas_, this.request_);
ImageLoader.convertColorSpace( ImageLoader.convertColorSpace(
this.canvas_, this.request_.colorSpace || ColorSpace.SRGB); this.canvas_, this.request_.colorSpace || ColorSpace.SRGB);
this.sendImage_(true); // Image changed. 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