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

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

Issue 1608143002: support animated GIF (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix nits Created 4 years, 11 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
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 // Namespace object for the utilities. 5 // Namespace object for the utilities.
6 var ImageUtil = {}; 6 var ImageUtil = {};
7 7
8 /** 8 /**
9 * Performance trace. 9 * Performance trace.
10 */ 10 */
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after
433 */ 433 */
434 ImageUtil.ImageLoader = function(document, metadataModel) { 434 ImageUtil.ImageLoader = function(document, metadataModel) {
435 this.document_ = document; 435 this.document_ = document;
436 436
437 /** 437 /**
438 * @private {!MetadataModel} 438 * @private {!MetadataModel}
439 * @const 439 * @const
440 */ 440 */
441 this.metadataModel_ = metadataModel; 441 this.metadataModel_ = metadataModel;
442 442
443 this.image_ = new Image();
444 this.generation_ = 0; 443 this.generation_ = 0;
445 444
446 /** 445 /**
447 * @type {number} 446 * @type {number}
448 * @private 447 * @private
449 */ 448 */
450 this.timeout_ = 0; 449 this.timeout_ = 0;
451 450
452 /** 451 /**
453 * @type {?function(!HTMLCanvasElement, string=)} 452 * @type {?function(!HTMLCanvasElement, string=)}
(...skipping 19 matching lines...) Expand all
473 * @param {number=} opt_delay Load delay in milliseconds, useful to let the 472 * @param {number=} opt_delay Load delay in milliseconds, useful to let the
474 * animations play out before the computation heavy image loading starts. 473 * animations play out before the computation heavy image loading starts.
475 */ 474 */
476 ImageUtil.ImageLoader.prototype.load = function(item, callback, opt_delay) { 475 ImageUtil.ImageLoader.prototype.load = function(item, callback, opt_delay) {
477 var entry = item.getEntry(); 476 var entry = item.getEntry();
478 477
479 this.cancel(); 478 this.cancel();
480 this.entry_ = entry; 479 this.entry_ = entry;
481 this.callback_ = callback; 480 this.callback_ = callback;
482 481
483 var targetImage = this.image_; 482 var targetImage = assertInstanceof(this.document_.createElement('img'),
483 HTMLImageElement);
484 // The transform fetcher is not cancellable so we need a generation counter. 484 // The transform fetcher is not cancellable so we need a generation counter.
485 var generation = ++this.generation_; 485 var generation = ++this.generation_;
486 486
487 /** 487 /**
488 * @param {!HTMLImageElement} image Image to be transformed. 488 * @param {!HTMLImageElement} image Image to be transformed.
489 * @param {Object=} opt_transform Transformation. 489 * @param {Object=} opt_transform Transformation.
490 */ 490 */
491 var onTransform = function(image, opt_transform) { 491 var onTransform = function(image, opt_transform) {
492 if (generation === this.generation_) { 492 if (generation === this.generation_) {
493 this.convertImage_( 493 this.convertImage_(image, opt_transform);
494 image, opt_transform || { scaleX: 1, scaleY: 1, rotate90: 0});
495 } 494 }
496 }; 495 };
497 onTransform = onTransform.bind(this); 496 onTransform = onTransform.bind(this);
498 497
499 /** 498 /**
500 * @param {string=} opt_error Error. 499 * @param {string=} opt_error Error.
501 */ 500 */
502 var onError = function(opt_error) { 501 var onError = function(opt_error) {
503 targetImage.onerror = null; 502 targetImage.onerror = null;
504 targetImage.onload = null; 503 targetImage.onload = null;
(...skipping 10 matching lines...) Expand all
515 var loadImage = function(url) { 514 var loadImage = function(url) {
516 if (generation !== this.generation_) 515 if (generation !== this.generation_)
517 return; 516 return;
518 517
519 ImageUtil.metrics.startInterval(ImageUtil.getMetricName('LoadTime')); 518 ImageUtil.metrics.startInterval(ImageUtil.getMetricName('LoadTime'));
520 this.timeout_ = 0; 519 this.timeout_ = 0;
521 520
522 targetImage.onload = function() { 521 targetImage.onload = function() {
523 targetImage.onerror = null; 522 targetImage.onerror = null;
524 targetImage.onload = null; 523 targetImage.onload = null;
525 this.metadataModel_.get([entry], ['contentImageTransform']).then( 524 this.metadataModel_.get([entry], ['contentImageTransform']).then(
yawano 2016/01/21 08:08:14 nit: How about to add generation check here not to
ryoh 2016/01/21 08:42:31 It sounds nice. I will add checks.
526 function(metadataItems) { 525 function(metadataItems) {
527 onTransform(targetImage, metadataItems[0].contentImageTransform); 526 onTransform(targetImage, metadataItems[0].contentImageTransform);
528 }.bind(this)); 527 }.bind(this));
529 }.bind(this); 528 }.bind(this);
530 529
531 // The error callback has an optional error argument, which in case of a 530 // The error callback has an optional error argument, which in case of a
532 // general error should not be specified 531 // general error should not be specified
533 targetImage.onerror = onError.bind(null, 'GALLERY_IMAGE_ERROR'); 532 targetImage.onerror = onError.bind(null, 'GALLERY_IMAGE_ERROR');
534 533
535 targetImage.src = url; 534 targetImage.src = url;
536 }.bind(this); 535 }.bind(this);
537 536
538 // Loads the image. If already loaded, then forces a reload. 537 // Loads the image. If already loaded, then forces a reload.
539 var startLoad = function() { 538 var startLoad = function() {
540 if (generation !== this.generation_) 539 if (generation !== this.generation_)
541 return; 540 return;
542 541
543 // Target current image.
544 targetImage = this.image_;
545
546 // Obtain target URL. 542 // Obtain target URL.
547 if (FileType.isRaw(entry)) { 543 if (FileType.isRaw(entry)) {
548 var timestamp = 544 var timestamp =
549 item.getMetadataItem() && 545 item.getMetadataItem() &&
550 item.getMetadataItem().modificationTime && 546 item.getMetadataItem().modificationTime &&
551 item.getMetadataItem().modificationTime.getTime(); 547 item.getMetadataItem().modificationTime.getTime();
552 ImageLoaderClient.getInstance().load(entry.toURL(), function(result) { 548 ImageLoaderClient.getInstance().load(entry.toURL(), function(result) {
553 if (generation !== this.generation_) 549 if (generation !== this.generation_)
554 return; 550 return;
555 if (result.status === 'success') 551 if (result.status === 'success')
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
603 * Stops loading image. 599 * Stops loading image.
604 */ 600 */
605 ImageUtil.ImageLoader.prototype.cancel = function() { 601 ImageUtil.ImageLoader.prototype.cancel = function() {
606 if (!this.callback_) 602 if (!this.callback_)
607 return; 603 return;
608 this.callback_ = null; 604 this.callback_ = null;
609 if (this.timeout_) { 605 if (this.timeout_) {
610 clearTimeout(this.timeout_); 606 clearTimeout(this.timeout_);
611 this.timeout_ = 0; 607 this.timeout_ = 0;
612 } 608 }
613 if (this.image_) {
614 this.image_.onload = function() {};
yawano 2016/01/21 05:14:38 Sorry, I didn't pointed this out in the last revie
ryoh 2016/01/21 07:28:53 I think it's controlled by "this.generation_" to c
yawano 2016/01/21 08:08:14 Yes, this.generation_ works. I've missed the last
615 this.image_.onerror = function() {};
616 // Force to free internal image by assigning empty image.
617 this.image_.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAA' +
618 'AAABAAEAAAICTAEAOw==';
619 this.image_ = document.createElement('img');
620 }
621 this.generation_++; // Silence the transform fetcher if it is in progress. 609 this.generation_++; // Silence the transform fetcher if it is in progress.
622 }; 610 };
623 611
624 /** 612 /**
625 * @param {!HTMLImageElement} image Image to be transformed. 613 * @param {!HTMLImageElement} image Image to be transformed.
626 * @param {!Object} transform transformation description to apply to the image. 614 * @param {!Object} transform transformation description to apply to the image.
627 * @private 615 * @private
628 */ 616 */
629 ImageUtil.ImageLoader.prototype.convertImage_ = function(image, transform) { 617 ImageUtil.ImageLoader.prototype.convertImage_ = function(image, transform) {
618 if (!transform ||
619 (transform.rotate90 === 0 &&
620 transform.scaleX === 1 &&
621 transform.scaleY === 1)) {
622 setTimeout(this.callback_, 0, image);
623 this.callback_ = null;
624 return;
625 }
630 var canvas = this.document_.createElement('canvas'); 626 var canvas = this.document_.createElement('canvas');
631 627
632 if (transform.rotate90 & 1) { // Rotated +/-90deg, swap the dimensions. 628 if (transform.rotate90 & 1) { // Rotated +/-90deg, swap the dimensions.
633 canvas.width = image.height; 629 canvas.width = image.height;
634 canvas.height = image.width; 630 canvas.height = image.width;
635 } else { 631 } else {
636 canvas.width = image.width; 632 canvas.width = image.width;
637 canvas.height = image.height; 633 canvas.height = image.height;
638 } 634 }
639 635
(...skipping 23 matching lines...) Expand all
663 context.drawImage( 659 context.drawImage(
664 image, 0, firstRow, image.width, lastRow - firstRow, 660 image, 0, firstRow, image.width, lastRow - firstRow,
665 -image.width / 2, firstRow - image.height / 2, 661 -image.width / 2, firstRow - image.height / 2,
666 image.width, lastRow - firstRow); 662 image.width, lastRow - firstRow);
667 663
668 if (lastRow === image.height) { 664 if (lastRow === image.height) {
669 context.restore(); 665 context.restore();
670 if (this.entry_.toURL().substr(0, 5) !== 'data:') { // Ignore data urls. 666 if (this.entry_.toURL().substr(0, 5) !== 'data:') { // Ignore data urls.
671 ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('LoadTime')); 667 ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('LoadTime'));
672 } 668 }
673 try { 669 setTimeout(this.callback_, 0, context.canvas);
674 setTimeout(this.callback_, 0, context.canvas);
675 } catch (e) {
676 console.error(e);
677 }
678 this.callback_ = null; 670 this.callback_ = null;
679 } else { 671 } else {
680 var self = this; 672 var self = this;
681 this.timeout_ = setTimeout( 673 this.timeout_ = setTimeout(
682 function() { 674 function() {
683 self.timeout_ = 0; 675 self.timeout_ = 0;
684 self.copyStrip_(context, image, lastRow, rowCount); 676 self.copyStrip_(context, image, lastRow, rowCount);
685 }, 0); 677 }, 0);
686 } 678 }
687 }; 679 };
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
725 717
726 /** 718 /**
727 * @param {string} name Local name. 719 * @param {string} name Local name.
728 * @return {string} Full name. 720 * @return {string} Full name.
729 */ 721 */
730 ImageUtil.getMetricName = function(name) { 722 ImageUtil.getMetricName = function(name) {
731 return 'PhotoEditor.' + name; 723 return 'PhotoEditor.' + name;
732 }; 724 };
733 725
734 /** 726 /**
727 * Ensures argument is canvas. If it's not, creates new canvas and copy.
728 *
729 * @param {!HTMLCanvasElement|!HTMLImageElement} imgOrCanvas image or canvas
730 * element
731 * @return {!HTMLCanvasElement} canvas.
732 */
733 ImageUtil.ensureCanvas = function(imgOrCanvas) {
734 if(imgOrCanvas.tagName === 'canvas') {
735 return assertInstanceof(imgOrCanvas, HTMLCanvasElement);
736 }
737 var canvas = assertInstanceof(document.createElement('canvas'),
738 HTMLCanvasElement);
739 canvas.width = imgOrCanvas.width;
740 canvas.height = imgOrCanvas.height;
741 var context = canvas.getContext('2d');
742 context.drawImage(imgOrCanvas, 0, 0);
743 return canvas;
744 };
745
746 /**
735 * Used for metrics reporting, keep in sync with the histogram description. 747 * Used for metrics reporting, keep in sync with the histogram description.
736 * @type {Array<string>} 748 * @type {Array<string>}
737 * @const 749 * @const
738 */ 750 */
739 ImageUtil.FILE_TYPES = ['jpg', 'png', 'gif', 'bmp', 'webp']; 751 ImageUtil.FILE_TYPES = ['jpg', 'png', 'gif', 'bmp', 'webp'];
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698