Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(88)

Side by Side Diff: ui/file_manager/gallery/js/image_editor/viewport.js

Issue 1138053003: Gallery: Takes into account target canvas size when calculating view port. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/file_manager/gallery/js/image_editor/image_view.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * Formats string by replacing place holder with actual values.
7 * @param {string} str String includes placeholder '$n'. n starts from 1.
8 * @param {...*} var_args Values inserted into the place holders.
9 * @return {string}
10 */
11 function formatString(str, var_args) {
12 var args = arguments;
13 return str.replace(/\$[1-9]/g, function(placeHolder) {
14 return args[placeHolder[1]];
15 });
16 }
17
18 /**
6 * Viewport class controls the way the image is displayed (scale, offset etc). 19 * Viewport class controls the way the image is displayed (scale, offset etc).
7 * @constructor 20 * @constructor
8 * @struct 21 * @struct
9 */ 22 */
10 function Viewport() { 23 function Viewport() {
11 /** 24 /**
12 * Size of the full resolution image. 25 * Size of the full resolution image.
13 * @type {!ImageRect} 26 * @type {!ImageRect}
14 * @private 27 * @private
15 */ 28 */
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 198
186 /** 199 /**
187 * Obtains the rotation value. 200 * Obtains the rotation value.
188 * @return {number} Current rotation value. 201 * @return {number} Current rotation value.
189 */ 202 */
190 Viewport.prototype.getRotation = function() { 203 Viewport.prototype.getRotation = function() {
191 return this.rotation_; 204 return this.rotation_;
192 }; 205 };
193 206
194 /** 207 /**
195 * Obtains the scale for the specified image size. 208 * Returns image scale so that it matches screen size as long as it does not
209 * exceed maximum size.
196 * 210 *
197 * @param {number} width Width of the full resolution image. 211 * @param {number} width Width of image.
198 * @param {number} height Height of the full resolution image. 212 * @param {number} height Height of image.
213 * @param {number} maxWidth Max width of image.
214 * @param {number} maxHeight Max height of image.
199 * @return {number} The ratio of the full resotion image size and the calculated 215 * @return {number} The ratio of the full resotion image size and the calculated
200 * displayed image size. 216 * displayed image size.
201 * @private 217 * @private
202 */ 218 */
203 Viewport.prototype.getFittingScaleForImageSize_ = function(width, height) { 219 Viewport.prototype.getFittingScaleForImageSize_ = function(
204 var scaleX = this.screenBounds_.width / width; 220 width, height, maxWidth, maxHeight) {
205 var scaleY = this.screenBounds_.height / height; 221 return Math.min(
206 return Math.min(scaleX, scaleY, 1); 222 maxWidth / width,
223 maxHeight / height,
224 this.screenBounds_.width / width,
225 this.screenBounds_.height / height);
207 }; 226 };
208 227
209 /** 228 /**
210 * Returns offset X. 229 * Returns offset X.
211 * @return {number} X-offset of the viewport. 230 * @return {number} X-offset of the viewport.
212 */ 231 */
213 Viewport.prototype.getOffsetX = function() { return this.offsetX_; }; 232 Viewport.prototype.getOffsetX = function() { return this.offsetX_; };
214 233
215 /** 234 /**
216 * Returns offset Y. 235 * Returns offset Y.
(...skipping 24 matching lines...) Expand all
241 * Returns screen bounds. 260 * Returns screen bounds.
242 * @return {!ImageRect} The screen bounds in screen coordinates. 261 * @return {!ImageRect} The screen bounds in screen coordinates.
243 */ 262 */
244 Viewport.prototype.getScreenBounds = function() { return this.screenBounds_; }; 263 Viewport.prototype.getScreenBounds = function() { return this.screenBounds_; };
245 264
246 /** 265 /**
247 * Returns device bounds. 266 * Returns device bounds.
248 * @return {!ImageRect} The size of screen cache canvas. 267 * @return {!ImageRect} The size of screen cache canvas.
249 */ 268 */
250 Viewport.prototype.getDeviceBounds = function() { 269 Viewport.prototype.getDeviceBounds = function() {
251 var size = this.getImageElementBoundsOnScreen();
252 return ImageRect.createFromWidthAndHeight( 270 return ImageRect.createFromWidthAndHeight(
253 size.width * window.devicePixelRatio, 271 this.imageElementBoundsOnScreen_.width * window.devicePixelRatio,
254 size.height * window.devicePixelRatio); 272 this.imageElementBoundsOnScreen_.height * window.devicePixelRatio);
255 }; 273 };
256 274
257 /** 275 /**
258 * A counter that is incremented with each viewport state change. 276 * A counter that is incremented with each viewport state change.
259 * Clients that cache anything that depends on the viewport state should keep 277 * Clients that cache anything that depends on the viewport state should keep
260 * track of this counter. 278 * track of this counter.
261 * @return {number} counter. 279 * @return {number} counter.
262 */ 280 */
263 Viewport.prototype.getCacheGeneration = function() { return this.generation_; }; 281 Viewport.prototype.getCacheGeneration = function() { return this.generation_; };
264 282
265 /** 283 /**
266 * Returns image bounds in screen coordinates. 284 * Returns image bounds in screen coordinates.
267 * @return {!ImageRect} The image bounds in screen coordinates. 285 * @return {!ImageRect} The image bounds in screen coordinates.
268 */ 286 */
269 Viewport.prototype.getImageBoundsOnScreen = function() { 287 Viewport.prototype.getImageBoundsOnScreen = function() {
270 assert(this.imageBoundsOnScreen_); 288 assert(this.imageBoundsOnScreen_);
271 return this.imageBoundsOnScreen_; 289 return this.imageBoundsOnScreen_;
272 }; 290 };
273 291
274 /** 292 /**
275 * The image bounds in screen coordinates.
276 * This returns the bounds of element before applying zoom and offset.
277 * @return {!ImageRect}
278 */
279 Viewport.prototype.getImageElementBoundsOnScreen = function() {
280 assert(this.imageElementBoundsOnScreen_);
281 return this.imageElementBoundsOnScreen_;
282 };
283
284 /**
285 * The image bounds on screen, which is clipped with the screen size. 293 * The image bounds on screen, which is clipped with the screen size.
286 * @return {!ImageRect} 294 * @return {!ImageRect}
287 */ 295 */
288 Viewport.prototype.getImageBoundsOnScreenClipped = function() { 296 Viewport.prototype.getImageBoundsOnScreenClipped = function() {
289 assert(this.imageBoundsOnScreenClipped_); 297 assert(this.imageBoundsOnScreenClipped_);
290 return this.imageBoundsOnScreenClipped_; 298 return this.imageBoundsOnScreenClipped_;
291 }; 299 };
292 300
293 /** 301 /**
294 * Returns size in image coordinates. 302 * Returns size in image coordinates.
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
399 this.update_(); 407 this.update_();
400 }; 408 };
401 409
402 /** 410 /**
403 * Recalculate the viewport parameters. 411 * Recalculate the viewport parameters.
404 * @private 412 * @private
405 */ 413 */
406 Viewport.prototype.update_ = function() { 414 Viewport.prototype.update_ = function() {
407 // Update scale. 415 // Update scale.
408 this.scale_ = this.getFittingScaleForImageSize_( 416 this.scale_ = this.getFittingScaleForImageSize_(
417 this.imageBounds_.width, this.imageBounds_.height,
409 this.imageBounds_.width, this.imageBounds_.height); 418 this.imageBounds_.width, this.imageBounds_.height);
410 419
411 // Limit offset values. 420 // Limit offset values.
412 var zoomedWidht; 421 var zoomedWidht;
413 var zoomedHeight; 422 var zoomedHeight;
414 if (this.rotation_ % 2 == 0) { 423 if (this.rotation_ % 2 == 0) {
415 zoomedWidht = ~~(this.imageBounds_.width * this.scale_ * this.zoom_); 424 zoomedWidht = ~~(this.imageBounds_.width * this.scale_ * this.zoom_);
416 zoomedHeight = ~~(this.imageBounds_.height * this.scale_ * this.zoom_); 425 zoomedHeight = ~~(this.imageBounds_.height * this.scale_ * this.zoom_);
417 } else { 426 } else {
418 var scale = this.getFittingScaleForImageSize_( 427 var scale = this.getFittingScaleForImageSize_(
428 this.imageBounds_.height, this.imageBounds_.width,
419 this.imageBounds_.height, this.imageBounds_.width); 429 this.imageBounds_.height, this.imageBounds_.width);
420 zoomedWidht = ~~(this.imageBounds_.height * scale * this.zoom_); 430 zoomedWidht = ~~(this.imageBounds_.height * scale * this.zoom_);
421 zoomedHeight = ~~(this.imageBounds_.width * scale * this.zoom_); 431 zoomedHeight = ~~(this.imageBounds_.width * scale * this.zoom_);
422 } 432 }
423 var dx = Math.max(zoomedWidht - this.screenBounds_.width, 0) / 2; 433 var dx = Math.max(zoomedWidht - this.screenBounds_.width, 0) / 2;
424 var dy = Math.max(zoomedHeight - this.screenBounds_.height, 0) / 2; 434 var dy = Math.max(zoomedHeight - this.screenBounds_.height, 0) / 2;
425 this.offsetX_ = ImageUtil.clamp(-dx, this.offsetX_, dx); 435 this.offsetX_ = ImageUtil.clamp(-dx, this.offsetX_, dx);
426 this.offsetY_ = ImageUtil.clamp(-dy, this.offsetY_, dy); 436 this.offsetY_ = ImageUtil.clamp(-dy, this.offsetY_, dy);
427 437
428 // Image bounds on screen. 438 // Image bounds on screen.
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
465 viewport.zoom_ = this.zoom_; 475 viewport.zoom_ = this.zoom_;
466 viewport.offsetX_ = this.offsetX_; 476 viewport.offsetX_ = this.offsetX_;
467 viewport.offsetY_ = this.offsetY_; 477 viewport.offsetY_ = this.offsetY_;
468 viewport.rotation_ = this.rotation_; 478 viewport.rotation_ = this.rotation_;
469 viewport.generation_ = this.generation_; 479 viewport.generation_ = this.generation_;
470 viewport.update_(); 480 viewport.update_();
471 return viewport; 481 return viewport;
472 }; 482 };
473 483
474 /** 484 /**
485 * Obtains CSS transformation string that matches the image dimension with
486 * |screenRect|.
487 * @param {number} width Width of image.
488 * @param {number} height Height of image.
489 * @param {!ImageRect} screenRect Rectangle in window coordinate system. The
490 * origin of the coordinate system at the left upper of the window.
491 */
492 Viewport.prototype.getScreenRectTransformation = function(
493 width, height, screenRect) {
494 var dx = screenRect.left + (screenRect.width - width) / 2;
495 var dy = screenRect.top + (screenRect.height - height) / 2;
496
497 return formatString(
498 'translate($1px,$2px) scale($3,$4)',
499 dx, dy, screenRect.width / width, screenRect.height / height);
500 };
501
502 /**
503 * Obtains CSS transformation string that places the cropped image at the
504 * original position in the whole image.
505 * @param {number} width Width of cropped image.
506 * @param {number} height Width of cropped image.
507 * @param {number} wholeWidthMax Max width value that is used for layouting
508 * whole image.
509 * @param {number} wholeHeightMax Max height value that is used for layouting
510 * whole image.
511 * @param {!ImageRect} cropRect Crop rectangle in the whole image. The origin is
512 * left upper of the whole image.
513 */
514 Viewport.prototype.getCroppingTransformation = function(
515 width,
516 height,
517 wholeWidthMax,
518 wholeHeightMax,
519 cropRect) {
520 var fittingScale = this.getFittingScaleForImageSize_(
521 wholeWidthMax, wholeHeightMax, wholeWidthMax, wholeHeightMax);
522 var wholeWidth = wholeWidthMax * fittingScale;
523 var wholeHeight = wholeHeightMax * fittingScale;
524 var wholeLeft = (this.screenBounds_.width - wholeWidth) / 2;
525 var wholeTop = (this.screenBounds_.height - wholeHeight) / 2;
526 return this.getScreenRectTransformation(
527 width,
528 height,
529 new ImageRect(
530 wholeLeft + cropRect.left * fittingScale,
531 wholeTop + cropRect.top * fittingScale,
532 cropRect.width * fittingScale,
533 cropRect.height * fittingScale));
534 };
535
536 /**
475 * Obtains CSS transformation for the screen image. 537 * Obtains CSS transformation for the screen image.
538 * @param {number} width Width of image.
539 * @param {number} height Height of image.
540 * @param {number=} opt_dx Amount of horizontal shift.
476 * @return {string} Transformation description. 541 * @return {string} Transformation description.
477 */ 542 */
478 Viewport.prototype.getTransformation = function() { 543 Viewport.prototype.getTransformation = function(width, height, opt_dx) {
479 var rotationScaleAdjustment; 544 return this.getTransformationInternal_(
480 if (this.rotation_ % 2) { 545 width,
481 rotationScaleAdjustment = this.getFittingScaleForImageSize_( 546 height,
482 this.imageBounds_.height, this.imageBounds_.width) / this.scale_; 547 this.rotation_,
483 } else { 548 this.zoom_,
484 rotationScaleAdjustment = 1; 549 this.offsetX_ + (opt_dx || 0),
485 } 550 this.offsetY_);
486 return [
487 'translate(' + this.offsetX_ + 'px, ' + this.offsetY_ + 'px) ',
488 'rotate(' + (this.rotation_ * 90) + 'deg)',
489 'scale(' + (this.zoom_ * rotationScaleAdjustment) + ')'
490 ].join(' ');
491 }; 551 };
492 552
493 /** 553 /**
494 * Obtains shift CSS transformation for the screen image.
495 * @param {number} dx Amount of shift.
496 * @return {string} Transformation description.
497 */
498 Viewport.prototype.getShiftTransformation = function(dx) {
499 return 'translateX(' + dx + 'px) ' + this.getTransformation();
500 };
501
502 /**
503 * Obtains CSS transformation that makes the rotated image fit the original 554 * Obtains CSS transformation that makes the rotated image fit the original
504 * image. The new rotated image that the transformation is applied to looks the 555 * image. The new rotated image that the transformation is applied to looks the
505 * same with original image. 556 * same with original image.
506 * 557 *
507 * @param {boolean} orientation Orientation of the rotation from the original 558 * @param {number} width Width of image.
508 * image to the rotated image. True is for clockwise and false is for 559 * @param {number} height Height of image.
509 * counterclockwise. 560 * @param {number} rotation Number of clockwise 90 degree rotation. The rotation
561 * angle of the image is rotation * 90.
510 * @return {string} Transformation description. 562 * @return {string} Transformation description.
511 */ 563 */
512 Viewport.prototype.getInverseTransformForRotatedImage = function(orientation) { 564 Viewport.prototype.getRotatingTransformation = function(
513 var previousImageWidth = this.imageBounds_.height; 565 width, height, rotation) {
514 var previousImageHeight = this.imageBounds_.width; 566 return this.getTransformationInternal_(
515 var oldScale = this.getFittingScaleForImageSize_( 567 width, height, rotation, 1, 0, 0);
516 previousImageWidth, previousImageHeight);
517 var scaleRatio = oldScale / this.scale_;
518 var degree = orientation ? '-90deg' : '90deg';
519 return [
520 'scale(' + scaleRatio + ')',
521 'rotate(' + degree + ')',
522 this.getTransformation()
523 ].join(' ');
524 }; 568 };
525 569
526 /** 570 /**
527 * Obtains CSS transformation that makes the cropped image fit the original 571 * Obtains CSS transformation that placed the image in the application window.
528 * image. The new cropped image that the transformation is applied to fits to 572 * @param {number} width Width of image.
529 * the cropped rectangle in the original image. 573 * @param {number} height Height of image.
530 * 574 * @param {number} rotation Number of clockwise 90 degree rotation. The rotation
531 * @param {number} imageWidth Width of the original image. 575 * angle of the image is rotation * 90.
532 * @param {number} imageHeight Height of the original image. 576 * @param {number} zoom Zoom rate.
533 * @param {!ImageRect} imageCropRect Crop rectangle in the image's coordinate 577 * @param {number} offsetX Horizontal offset.
534 * system. 578 * @param {number} offsetY Vertical offset.
535 * @return {string} Transformation description. 579 * @private
536 */ 580 */
537 Viewport.prototype.getInverseTransformForCroppedImage = 581 Viewport.prototype.getTransformationInternal_ = function(
538 function(imageWidth, imageHeight, imageCropRect) { 582 width,
539 var wholeScale = this.getFittingScaleForImageSize_( 583 height,
540 imageWidth, imageHeight); 584 rotation,
541 var croppedScale = this.getFittingScaleForImageSize_( 585 zoom,
542 imageCropRect.width, imageCropRect.height); 586 offsetX,
543 var dx = 587 offsetY) {
544 (imageCropRect.left + imageCropRect.width / 2 - imageWidth / 2) * 588 var rotatedWidth = rotation % 2 ? height : width;
545 wholeScale; 589 var rotatedHeight = rotation % 2 ? width : height;
546 var dy = 590 var rotatedMaxWidth = rotation % 2 ?
547 (imageCropRect.top + imageCropRect.height / 2 - imageHeight / 2) * 591 this.imageBounds_.height : this.imageBounds_.width;
548 wholeScale; 592 var rotatedMaxHeight = rotation % 2 ?
549 return [ 593 this.imageBounds_.width : this.imageBounds_.height;
550 'translate(' + dx + 'px,' + dy + 'px)', 594
551 'scale(' + wholeScale / croppedScale + ')', 595 // Scale.
552 this.getTransformation() 596 var fittingScale = this.getFittingScaleForImageSize_(
553 ].join(' '); 597 rotatedWidth, rotatedHeight, rotatedMaxWidth, rotatedMaxHeight);
598
599 // Offset for centering.
600 var dx = (this.screenBounds_.width - width) / 2;
601 var dy = (this.screenBounds_.height - height) / 2;
602
603 return formatString(
604 'translate($1px,$2px) scale($3) rotate($4deg)',
605 dx + offsetX,
606 dy + offsetY,
607 fittingScale * zoom,
608 rotation * 90);
554 }; 609 };
555
556 /**
557 * Obtains CSS transformation that makes the image fit to the screen rectangle.
558 *
559 * @param {!ImageRect} screenRect Screen rectangle.
560 * @return {string} Transformation description.
561 */
562 Viewport.prototype.getScreenRectTransformForImage = function(screenRect) {
563 var imageBounds = this.getImageElementBoundsOnScreen();
564 var scaleX = screenRect.width / imageBounds.width;
565 var scaleY = screenRect.height / imageBounds.height;
566 var screenWidth = this.screenBounds_.width;
567 var screenHeight = this.screenBounds_.height;
568 var dx = screenRect.left + screenRect.width / 2 - screenWidth / 2;
569 var dy = screenRect.top + screenRect.height / 2 - screenHeight / 2;
570 return [
571 'translate(' + dx + 'px,' + dy + 'px)',
572 'scale(' + scaleX + ',' + scaleY + ')',
573 this.getTransformation()
574 ].join(' ');
575 };
OLDNEW
« no previous file with comments | « ui/file_manager/gallery/js/image_editor/image_view.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698