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 3 // found in the LICENSE file. 4 5 'use strict'; 6 7 /** 8 * The base class for simple filters that only modify the image content 9 * but do not modify the image dimensions. 10 * @constructor 11 * @extends {ImageEditor.Mode} 12 */ 13 ImageEditor.Mode.Adjust = function() { 14 ImageEditor.Mode.apply(this, arguments); 15 this.implicitCommit = true; 16 this.doneMessage_ = null; 17 this.viewportGeneration_ = 0; 18 }; 19 20 ImageEditor.Mode.Adjust.prototype = {__proto__: ImageEditor.Mode.prototype}; 21 22 /** @override */ 23 ImageEditor.Mode.Adjust.prototype.getCommand = function() { 24 if (!this.filter_) return null; 25 26 return new Command.Filter(this.name, this.filter_, this.doneMessage_); 27 }; 28 29 /** @override */ 30 ImageEditor.Mode.Adjust.prototype.cleanUpUI = function() { 31 ImageEditor.Mode.prototype.cleanUpUI.apply(this, arguments); 32 this.hidePreview(); 33 }; 34 35 /** 36 * TODO(JSDOC) 37 */ 38 ImageEditor.Mode.Adjust.prototype.hidePreview = function() { 39 if (this.canvas_) { 40 this.canvas_.parentNode.removeChild(this.canvas_); 41 this.canvas_ = null; 42 } 43 }; 44 45 /** 46 * TODO(JSDOC) 47 */ 48 ImageEditor.Mode.Adjust.prototype.cleanUpCaches = function() { 49 this.filter_ = null; 50 this.previewImageData_ = null; 51 }; 52 53 /** 54 * TODO(JSDOC) 55 */ 56 ImageEditor.Mode.Adjust.prototype.reset = function() { 57 ImageEditor.Mode.prototype.reset.call(this); 58 this.hidePreview(); 59 this.cleanUpCaches(); 60 }; 61 62 /** 63 * TODO(JSDOC) 64 * @param {Object} options // TODO(JSDOC). 65 */ 66 ImageEditor.Mode.Adjust.prototype.update = function(options) { 67 ImageEditor.Mode.prototype.update.apply(this, arguments); 68 69 // We assume filter names are used in the UI directly. 70 // This will have to change with i18n. 71 this.filter_ = this.createFilter(options); 72 this.updatePreviewImage(); 73 ImageUtil.trace.resetTimer('preview'); 74 this.filter_(this.previewImageData_, this.originalImageData, 0, 0); 75 ImageUtil.trace.reportTimer('preview'); 76 this.canvas_.getContext('2d').putImageData( 77 this.previewImageData_, 0, 0); 78 }; 79 80 /** 81 * Copy the source image data for the preview. 82 * Use the cached copy if the viewport has not changed. 83 */ 84 ImageEditor.Mode.Adjust.prototype.updatePreviewImage = function() { 85 if (!this.previewImageData_ || 86 this.viewportGeneration_ != this.getViewport().getCacheGeneration()) { 87 this.viewportGeneration_ = this.getViewport().getCacheGeneration(); 88 89 if (!this.canvas_) { 90 this.canvas_ = this.getImageView().createOverlayCanvas(); 91 } 92 93 this.getImageView().setupDeviceBuffer(this.canvas_); 94 95 this.originalImageData = this.getImageView().copyScreenImageData(); 96 this.previewImageData_ = this.getImageView().copyScreenImageData(); 97 } 98 }; 99 100 /* 101 * Own methods 102 */ 103 104 /** 105 * TODO(JSDOC) 106 * @param {Object} options // TODO(JSDOC). 107 * @return {function(ImageData,ImageData,number,number)} Created function. 108 */ 109 ImageEditor.Mode.Adjust.prototype.createFilter = function(options) { 110 return filter.create(this.name, options); 111 }; 112 113 /** 114 * A base class for color filters that are scale independent. 115 * @constructor 116 */ 117 ImageEditor.Mode.ColorFilter = function() { 118 ImageEditor.Mode.Adjust.apply(this, arguments); 119 }; 120 121 ImageEditor.Mode.ColorFilter.prototype = 122 {__proto__: ImageEditor.Mode.Adjust.prototype}; 123 124 /** 125 * TODO(JSDOC) 126 * @return {{r: Array.<number>, g: Array.<number>, b: Array.<number>}} 127 * histogram. 128 */ 129 ImageEditor.Mode.ColorFilter.prototype.getHistogram = function() { 130 return filter.getHistogram(this.getImageView().getThumbnail()); 131 }; 132 133 /** 134 * Exposure/contrast filter. 135 * @constructor 136 */ 137 ImageEditor.Mode.Exposure = function() { 138 ImageEditor.Mode.ColorFilter.call(this, 'exposure', 'GALLERY_EXPOSURE'); 139 }; 140 141 ImageEditor.Mode.Exposure.prototype = 142 {__proto__: ImageEditor.Mode.ColorFilter.prototype}; 143 144 /** 145 * TODO(JSDOC) 146 * @param {ImageEditor.Toolbar} toolbar The toolbar to populate. 147 */ 148 ImageEditor.Mode.Exposure.prototype.createTools = function(toolbar) { 149 toolbar.addRange('brightness', 'GALLERY_BRIGHTNESS', -1, 0, 1, 100); 150 toolbar.addRange('contrast', 'GALLERY_CONTRAST', -1, 0, 1, 100); 151 }; 152 153 /** 154 * Autofix. 155 * @constructor 156 */ 157 ImageEditor.Mode.Autofix = function() { 158 ImageEditor.Mode.ColorFilter.call(this, 'autofix', 'GALLERY_AUTOFIX'); 159 this.doneMessage_ = 'GALLERY_FIXED'; 160 }; 161 162 ImageEditor.Mode.Autofix.prototype = 163 {__proto__: ImageEditor.Mode.ColorFilter.prototype}; 164 165 /** 166 * TODO(JSDOC) 167 * @param {ImageEditor.Toolbar} toolbar The toolbar to populate. 168 */ 169 ImageEditor.Mode.Autofix.prototype.createTools = function(toolbar) { 170 var self = this; 171 toolbar.addButton('Apply', this.apply.bind(this)); 172 }; 173 174 /** 175 * TODO(JSDOC) 176 * @return {boolean} // TODO(JSDOC). 177 */ 178 ImageEditor.Mode.Autofix.prototype.isApplicable = function() { 179 return this.getImageView().hasValidImage() && 180 filter.autofix.isApplicable(this.getHistogram()); 181 }; 182 183 /** 184 * TODO(JSDOC) 185 */ 186 ImageEditor.Mode.Autofix.prototype.apply = function() { 187 this.update({histogram: this.getHistogram()}); 188 }; 189 190 /** 191 * Instant Autofix. 192 * @constructor 193 */ 194 ImageEditor.Mode.InstantAutofix = function() { 195 ImageEditor.Mode.Autofix.apply(this, arguments); 196 this.instant = true; 197 }; 198 199 ImageEditor.Mode.InstantAutofix.prototype = 200 {__proto__: ImageEditor.Mode.Autofix.prototype}; 201 202 /** 203 * TODO(JSDOC) 204 */ 205 ImageEditor.Mode.InstantAutofix.prototype.setUp = function() { 206 ImageEditor.Mode.Autofix.prototype.setUp.apply(this, arguments); 207 this.apply(); 208 }; 209 210 /** 211 * Blur filter. 212 * @constructor 213 */ 214 ImageEditor.Mode.Blur = function() { 215 ImageEditor.Mode.Adjust.call(this, 'blur'); 216 }; 217 218 ImageEditor.Mode.Blur.prototype = 219 {__proto__: ImageEditor.Mode.Adjust.prototype}; 220 221 /** 222 * TODO(JSDOC) 223 * @param {ImageEditor.Toolbar} toolbar The toolbar to populate. 224 */ 225 ImageEditor.Mode.Blur.prototype.createTools = function(toolbar) { 226 toolbar.addRange('strength', 'GALLERY_STRENGTH', 0, 0, 1, 100); 227 toolbar.addRange('radius', 'GALLERY_RADIUS', 1, 1, 3); 228 }; 229 230 /** 231 * Sharpen filter. 232 * @constructor 233 */ 234 ImageEditor.Mode.Sharpen = function() { 235 ImageEditor.Mode.Adjust.call(this, 'sharpen'); 236 }; 237 238 ImageEditor.Mode.Sharpen.prototype = 239 {__proto__: ImageEditor.Mode.Adjust.prototype}; 240 241 /** 242 * TODO(JSDOC) 243 * @param {ImageEditor.Toolbar} toolbar The toolbar to populate. 244 */ 245 ImageEditor.Mode.Sharpen.prototype.createTools = function(toolbar) { 246 toolbar.addRange('strength', 'GALLERY_STRENGTH', 0, 0, 1, 100); 247 toolbar.addRange('radius', 'GALLERY_RADIUS', 1, 1, 3); 248 }; 249