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

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: add assert to pass closure compiler Created 4 years, 10 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;
524 if (generation !== this.generation_)
525 return;
525 this.metadataModel_.get([entry], ['contentImageTransform']).then( 526 this.metadataModel_.get([entry], ['contentImageTransform']).then(
526 function(metadataItems) { 527 function(metadataItems) {
527 onTransform(targetImage, metadataItems[0].contentImageTransform); 528 onTransform(targetImage, metadataItems[0].contentImageTransform);
528 }.bind(this)); 529 }.bind(this));
529 }.bind(this); 530 }.bind(this);
530 531
531 // The error callback has an optional error argument, which in case of a 532 // The error callback has an optional error argument, which in case of a
532 // general error should not be specified 533 // general error should not be specified
533 targetImage.onerror = onError.bind(null, 'GALLERY_IMAGE_ERROR'); 534 targetImage.onerror = onError.bind(null, 'GALLERY_IMAGE_ERROR');
534 535
535 targetImage.src = url; 536 targetImage.src = url;
536 }.bind(this); 537 }.bind(this);
537 538
538 // Loads the image. If already loaded, then forces a reload. 539 // Loads the image. If already loaded, then forces a reload.
539 var startLoad = function() { 540 var startLoad = function() {
540 if (generation !== this.generation_) 541 if (generation !== this.generation_)
541 return; 542 return;
542 543
543 // Target current image.
544 targetImage = this.image_;
545
546 // Obtain target URL. 544 // Obtain target URL.
547 if (FileType.isRaw(entry)) { 545 if (FileType.isRaw(entry)) {
548 var timestamp = 546 var timestamp =
549 item.getMetadataItem() && 547 item.getMetadataItem() &&
550 item.getMetadataItem().modificationTime && 548 item.getMetadataItem().modificationTime &&
551 item.getMetadataItem().modificationTime.getTime(); 549 item.getMetadataItem().modificationTime.getTime();
552 ImageLoaderClient.getInstance().load(entry.toURL(), function(result) { 550 ImageLoaderClient.getInstance().load(entry.toURL(), function(result) {
553 if (generation !== this.generation_) 551 if (generation !== this.generation_)
554 return; 552 return;
555 if (result.status === 'success') 553 if (result.status === 'success')
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
603 * Stops loading image. 601 * Stops loading image.
604 */ 602 */
605 ImageUtil.ImageLoader.prototype.cancel = function() { 603 ImageUtil.ImageLoader.prototype.cancel = function() {
606 if (!this.callback_) 604 if (!this.callback_)
607 return; 605 return;
608 this.callback_ = null; 606 this.callback_ = null;
609 if (this.timeout_) { 607 if (this.timeout_) {
610 clearTimeout(this.timeout_); 608 clearTimeout(this.timeout_);
611 this.timeout_ = 0; 609 this.timeout_ = 0;
612 } 610 }
613 if (this.image_) {
614 this.image_.onload = function() {};
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. 611 this.generation_++; // Silence the transform fetcher if it is in progress.
622 }; 612 };
623 613
624 /** 614 /**
625 * @param {!HTMLImageElement} image Image to be transformed. 615 * @param {!HTMLImageElement} image Image to be transformed.
626 * @param {!Object} transform transformation description to apply to the image. 616 * @param {!Object} transform transformation description to apply to the image.
627 * @private 617 * @private
628 */ 618 */
629 ImageUtil.ImageLoader.prototype.convertImage_ = function(image, transform) { 619 ImageUtil.ImageLoader.prototype.convertImage_ = function(image, transform) {
620 if (!transform ||
621 (transform.rotate90 === 0 &&
622 transform.scaleX === 1 &&
623 transform.scaleY === 1)) {
624 setTimeout(this.callback_, 0, image);
625 this.callback_ = null;
626 return;
627 }
630 var canvas = this.document_.createElement('canvas'); 628 var canvas = this.document_.createElement('canvas');
631 629
632 if (transform.rotate90 & 1) { // Rotated +/-90deg, swap the dimensions. 630 if (transform.rotate90 & 1) { // Rotated +/-90deg, swap the dimensions.
633 canvas.width = image.height; 631 canvas.width = image.height;
634 canvas.height = image.width; 632 canvas.height = image.width;
635 } else { 633 } else {
636 canvas.width = image.width; 634 canvas.width = image.width;
637 canvas.height = image.height; 635 canvas.height = image.height;
638 } 636 }
639 637
(...skipping 23 matching lines...) Expand all
663 context.drawImage( 661 context.drawImage(
664 image, 0, firstRow, image.width, lastRow - firstRow, 662 image, 0, firstRow, image.width, lastRow - firstRow,
665 -image.width / 2, firstRow - image.height / 2, 663 -image.width / 2, firstRow - image.height / 2,
666 image.width, lastRow - firstRow); 664 image.width, lastRow - firstRow);
667 665
668 if (lastRow === image.height) { 666 if (lastRow === image.height) {
669 context.restore(); 667 context.restore();
670 if (this.entry_.toURL().substr(0, 5) !== 'data:') { // Ignore data urls. 668 if (this.entry_.toURL().substr(0, 5) !== 'data:') { // Ignore data urls.
671 ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('LoadTime')); 669 ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('LoadTime'));
672 } 670 }
673 try { 671 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; 672 this.callback_ = null;
679 } else { 673 } else {
680 var self = this; 674 var self = this;
681 this.timeout_ = setTimeout( 675 this.timeout_ = setTimeout(
682 function() { 676 function() {
683 self.timeout_ = 0; 677 self.timeout_ = 0;
684 self.copyStrip_(context, image, lastRow, rowCount); 678 self.copyStrip_(context, image, lastRow, rowCount);
685 }, 0); 679 }, 0);
686 } 680 }
687 }; 681 };
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
725 719
726 /** 720 /**
727 * @param {string} name Local name. 721 * @param {string} name Local name.
728 * @return {string} Full name. 722 * @return {string} Full name.
729 */ 723 */
730 ImageUtil.getMetricName = function(name) { 724 ImageUtil.getMetricName = function(name) {
731 return 'PhotoEditor.' + name; 725 return 'PhotoEditor.' + name;
732 }; 726 };
733 727
734 /** 728 /**
729 * Ensures argument is canvas. If it's not, creates new canvas and copy.
730 *
731 * @param {!HTMLCanvasElement|!HTMLImageElement} imgOrCanvas image or canvas
732 * element
733 * @return {!HTMLCanvasElement} canvas.
734 */
735 ImageUtil.ensureCanvas = function(imgOrCanvas) {
736 if(imgOrCanvas.tagName === 'canvas') {
737 return assertInstanceof(imgOrCanvas, HTMLCanvasElement);
738 }
739 var canvas = assertInstanceof(document.createElement('canvas'),
740 HTMLCanvasElement);
741 canvas.width = imgOrCanvas.width;
742 canvas.height = imgOrCanvas.height;
743 var context = canvas.getContext('2d');
744 context.drawImage(imgOrCanvas, 0, 0);
745 return canvas;
746 };
747
748 /**
735 * Used for metrics reporting, keep in sync with the histogram description. 749 * Used for metrics reporting, keep in sync with the histogram description.
736 * @type {Array<string>} 750 * @type {Array<string>}
737 * @const 751 * @const
738 */ 752 */
739 ImageUtil.FILE_TYPES = ['jpg', 'png', 'gif', 'bmp', 'webp']; 753 ImageUtil.FILE_TYPES = ['jpg', 'png', 'gif', 'bmp', 'webp'];
OLDNEW
« no previous file with comments | « ui/file_manager/gallery/js/image_editor/image_editor.js ('k') | ui/file_manager/gallery/js/image_editor/image_view.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698