| OLD | NEW |
| 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 'use strict'; | 5 'use strict'; |
| 6 | 6 |
| 7 | 7 |
| 8 // Namespace object for the utilities. | 8 // Namespace object for the utilities. |
| 9 function ImageUtil() {} | 9 function ImageUtil() {} |
| 10 | 10 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 return (value - min) * (value - max) <= 0; | 75 return (value - min) * (value - max) <= 0; |
| 76 }; | 76 }; |
| 77 | 77 |
| 78 /** | 78 /** |
| 79 * Rectangle class. | 79 * Rectangle class. |
| 80 */ | 80 */ |
| 81 | 81 |
| 82 /** | 82 /** |
| 83 * Rectangle constructor takes 0, 1, 2 or 4 arguments. | 83 * Rectangle constructor takes 0, 1, 2 or 4 arguments. |
| 84 * Supports following variants: | 84 * Supports following variants: |
| 85 * new Rect(left, top, width, height) | 85 * new ImageRect(left, top, width, height) |
| 86 * new Rect(width, height) | 86 * new ImageRect(width, height) |
| 87 * new Rect(rect) // anything with left, top, width, height properties | 87 * new ImageRect(rect) // anything with left, top, width, height. |
| 88 * new Rect(bounds) // anything with left, top, right, bottom properties | 88 * new ImageRect(bounds) // anything with left, top, right, bottom. |
| 89 * new Rect(canvas|image) // anything with width and height properties. | 89 * new ImageRect(canvas|image) // anything with width and height. |
| 90 * new Rect() // empty rectangle. | 90 * new ImageRect() // empty rectangle. |
| 91 * @constructor | 91 * @constructor |
| 92 */ | 92 */ |
| 93 function Rect() { | 93 function ImageRect() { |
| 94 switch (arguments.length) { | 94 switch (arguments.length) { |
| 95 case 4: | 95 case 4: |
| 96 this.left = arguments[0]; | 96 this.left = arguments[0]; |
| 97 this.top = arguments[1]; | 97 this.top = arguments[1]; |
| 98 this.width = arguments[2]; | 98 this.width = arguments[2]; |
| 99 this.height = arguments[3]; | 99 this.height = arguments[3]; |
| 100 return; | 100 return; |
| 101 | 101 |
| 102 case 2: | 102 case 2: |
| 103 this.left = 0; | 103 this.left = 0; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 128 break; // Fall through to the error message. | 128 break; // Fall through to the error message. |
| 129 } | 129 } |
| 130 | 130 |
| 131 case 0: | 131 case 0: |
| 132 this.left = 0; | 132 this.left = 0; |
| 133 this.top = 0; | 133 this.top = 0; |
| 134 this.width = 0; | 134 this.width = 0; |
| 135 this.height = 0; | 135 this.height = 0; |
| 136 return; | 136 return; |
| 137 } | 137 } |
| 138 console.error('Invalid Rect constructor arguments:', | 138 console.error('Invalid ImageRect constructor arguments:', |
| 139 Array.apply(null, arguments)); | 139 Array.apply(null, arguments)); |
| 140 } | 140 } |
| 141 | 141 |
| 142 Rect.prototype = { | 142 ImageRect.prototype = { |
| 143 /** | 143 /** |
| 144 * Obtains the x coordinate of right edge. The most right pixels in the | 144 * Obtains the x coordinate of right edge. The most right pixels in the |
| 145 * rectangle are (x = right - 1) and the pixels (x = right) are not included | 145 * rectangle are (x = right - 1) and the pixels (x = right) are not included |
| 146 * in the rectangle. | 146 * in the rectangle. |
| 147 * @return {number} | 147 * @return {number} |
| 148 */ | 148 */ |
| 149 get right() { | 149 get right() { |
| 150 return this.left + this.width; | 150 return this.left + this.width; |
| 151 }, | 151 }, |
| 152 | 152 |
| 153 /** | 153 /** |
| 154 * Obtains the y coordinate of bottom edge. The most bottom pixels in the | 154 * Obtains the y coordinate of bottom edge. The most bottom pixels in the |
| 155 * rectangle are (y = bottom - 1) and the pixels (y = bottom) are not included | 155 * rectangle are (y = bottom - 1) and the pixels (y = bottom) are not included |
| 156 * in the rectangle. | 156 * in the rectangle. |
| 157 * @return {number} | 157 * @return {number} |
| 158 */ | 158 */ |
| 159 get bottom() { | 159 get bottom() { |
| 160 return this.top + this.height; | 160 return this.top + this.height; |
| 161 } | 161 } |
| 162 }; | 162 }; |
| 163 | 163 |
| 164 /** | 164 /** |
| 165 * @param {number} factor Factor to scale. | 165 * @param {number} factor Factor to scale. |
| 166 * @return {Rect} A rectangle with every dimension scaled. | 166 * @return {ImageRect} A rectangle with every dimension scaled. |
| 167 */ | 167 */ |
| 168 Rect.prototype.scale = function(factor) { | 168 ImageRect.prototype.scale = function(factor) { |
| 169 return new Rect( | 169 return new ImageRect( |
| 170 this.left * factor, | 170 this.left * factor, |
| 171 this.top * factor, | 171 this.top * factor, |
| 172 this.width * factor, | 172 this.width * factor, |
| 173 this.height * factor); | 173 this.height * factor); |
| 174 }; | 174 }; |
| 175 | 175 |
| 176 /** | 176 /** |
| 177 * @param {number} dx Difference in X. | 177 * @param {number} dx Difference in X. |
| 178 * @param {number} dy Difference in Y. | 178 * @param {number} dy Difference in Y. |
| 179 * @return {Rect} A rectangle shifted by (dx,dy), same size. | 179 * @return {ImageRect} A rectangle shifted by (dx,dy), same size. |
| 180 */ | 180 */ |
| 181 Rect.prototype.shift = function(dx, dy) { | 181 ImageRect.prototype.shift = function(dx, dy) { |
| 182 return new Rect(this.left + dx, this.top + dy, this.width, this.height); | 182 return new ImageRect(this.left + dx, this.top + dy, this.width, this.height); |
| 183 }; | 183 }; |
| 184 | 184 |
| 185 /** | 185 /** |
| 186 * @param {number} x Coordinate of the left top corner. | 186 * @param {number} x Coordinate of the left top corner. |
| 187 * @param {number} y Coordinate of the left top corner. | 187 * @param {number} y Coordinate of the left top corner. |
| 188 * @return {Rect} A rectangle with left==x and top==y, same size. | 188 * @return {ImageRect} A rectangle with left==x and top==y, same size. |
| 189 */ | 189 */ |
| 190 Rect.prototype.moveTo = function(x, y) { | 190 ImageRect.prototype.moveTo = function(x, y) { |
| 191 return new Rect(x, y, this.width, this.height); | 191 return new ImageRect(x, y, this.width, this.height); |
| 192 }; | 192 }; |
| 193 | 193 |
| 194 /** | 194 /** |
| 195 * @param {number} dx Difference in X. | 195 * @param {number} dx Difference in X. |
| 196 * @param {number} dy Difference in Y. | 196 * @param {number} dy Difference in Y. |
| 197 * @return {Rect} A rectangle inflated by (dx, dy), same center. | 197 * @return {ImageRect} A rectangle inflated by (dx, dy), same center. |
| 198 */ | 198 */ |
| 199 Rect.prototype.inflate = function(dx, dy) { | 199 ImageRect.prototype.inflate = function(dx, dy) { |
| 200 return new Rect( | 200 return new ImageRect( |
| 201 this.left - dx, this.top - dy, this.width + 2 * dx, this.height + 2 * dy); | 201 this.left - dx, this.top - dy, this.width + 2 * dx, this.height + 2 * dy); |
| 202 }; | 202 }; |
| 203 | 203 |
| 204 /** | 204 /** |
| 205 * @param {number} x Coordinate of the point. | 205 * @param {number} x Coordinate of the point. |
| 206 * @param {number} y Coordinate of the point. | 206 * @param {number} y Coordinate of the point. |
| 207 * @return {boolean} True if the point lies inside the rectangle. | 207 * @return {boolean} True if the point lies inside the rectangle. |
| 208 */ | 208 */ |
| 209 Rect.prototype.inside = function(x, y) { | 209 ImageRect.prototype.inside = function(x, y) { |
| 210 return this.left <= x && x < this.left + this.width && | 210 return this.left <= x && x < this.left + this.width && |
| 211 this.top <= y && y < this.top + this.height; | 211 this.top <= y && y < this.top + this.height; |
| 212 }; | 212 }; |
| 213 | 213 |
| 214 /** | 214 /** |
| 215 * @param {Rect} rect Rectangle to check. | 215 * @param {ImageRect} rect Rectangle to check. |
| 216 * @return {boolean} True if this rectangle intersects with the |rect|. | 216 * @return {boolean} True if this rectangle intersects with the |rect|. |
| 217 */ | 217 */ |
| 218 Rect.prototype.intersects = function(rect) { | 218 ImageRect.prototype.intersects = function(rect) { |
| 219 return (this.left + this.width) > rect.left && | 219 return (this.left + this.width) > rect.left && |
| 220 (rect.left + rect.width) > this.left && | 220 (rect.left + rect.width) > this.left && |
| 221 (this.top + this.height) > rect.top && | 221 (this.top + this.height) > rect.top && |
| 222 (rect.top + rect.height) > this.top; | 222 (rect.top + rect.height) > this.top; |
| 223 }; | 223 }; |
| 224 | 224 |
| 225 /** | 225 /** |
| 226 * @param {Rect} rect Rectangle to check. | 226 * @param {ImageRect} rect Rectangle to check. |
| 227 * @return {boolean} True if this rectangle containing the |rect|. | 227 * @return {boolean} True if this rectangle containing the |rect|. |
| 228 */ | 228 */ |
| 229 Rect.prototype.contains = function(rect) { | 229 ImageRect.prototype.contains = function(rect) { |
| 230 return (this.left <= rect.left) && | 230 return (this.left <= rect.left) && |
| 231 (rect.left + rect.width) <= (this.left + this.width) && | 231 (rect.left + rect.width) <= (this.left + this.width) && |
| 232 (this.top <= rect.top) && | 232 (this.top <= rect.top) && |
| 233 (rect.top + rect.height) <= (this.top + this.height); | 233 (rect.top + rect.height) <= (this.top + this.height); |
| 234 }; | 234 }; |
| 235 | 235 |
| 236 /** | 236 /** |
| 237 * @return {boolean} True if rectangle is empty. | 237 * @return {boolean} True if rectangle is empty. |
| 238 */ | 238 */ |
| 239 Rect.prototype.isEmpty = function() { | 239 ImageRect.prototype.isEmpty = function() { |
| 240 return this.width === 0 || this.height === 0; | 240 return this.width === 0 || this.height === 0; |
| 241 }; | 241 }; |
| 242 | 242 |
| 243 /** | 243 /** |
| 244 * Clamp the rectangle to the bounds by moving it. | 244 * Clamp the rectangle to the bounds by moving it. |
| 245 * Decrease the size only if necessary. | 245 * Decrease the size only if necessary. |
| 246 * @param {Rect} bounds Bounds. | 246 * @param {ImageRect} bounds Bounds. |
| 247 * @return {Rect} Calculated rectangle. | 247 * @return {ImageRect} Calculated rectangle. |
| 248 */ | 248 */ |
| 249 Rect.prototype.clamp = function(bounds) { | 249 ImageRect.prototype.clamp = function(bounds) { |
| 250 var rect = new Rect(this); | 250 var rect = new ImageRect(this); |
| 251 | 251 |
| 252 if (rect.width > bounds.width) { | 252 if (rect.width > bounds.width) { |
| 253 rect.left = bounds.left; | 253 rect.left = bounds.left; |
| 254 rect.width = bounds.width; | 254 rect.width = bounds.width; |
| 255 } else if (rect.left < bounds.left) { | 255 } else if (rect.left < bounds.left) { |
| 256 rect.left = bounds.left; | 256 rect.left = bounds.left; |
| 257 } else if (rect.left + rect.width > | 257 } else if (rect.left + rect.width > |
| 258 bounds.left + bounds.width) { | 258 bounds.left + bounds.width) { |
| 259 rect.left = bounds.left + bounds.width - rect.width; | 259 rect.left = bounds.left + bounds.width - rect.width; |
| 260 } | 260 } |
| 261 | 261 |
| 262 if (rect.height > bounds.height) { | 262 if (rect.height > bounds.height) { |
| 263 rect.top = bounds.top; | 263 rect.top = bounds.top; |
| 264 rect.height = bounds.height; | 264 rect.height = bounds.height; |
| 265 } else if (rect.top < bounds.top) { | 265 } else if (rect.top < bounds.top) { |
| 266 rect.top = bounds.top; | 266 rect.top = bounds.top; |
| 267 } else if (rect.top + rect.height > | 267 } else if (rect.top + rect.height > |
| 268 bounds.top + bounds.height) { | 268 bounds.top + bounds.height) { |
| 269 rect.top = bounds.top + bounds.height - rect.height; | 269 rect.top = bounds.top + bounds.height - rect.height; |
| 270 } | 270 } |
| 271 | 271 |
| 272 return rect; | 272 return rect; |
| 273 }; | 273 }; |
| 274 | 274 |
| 275 /** | 275 /** |
| 276 * @return {string} String representation. | 276 * @return {string} String representation. |
| 277 */ | 277 */ |
| 278 Rect.prototype.toString = function() { | 278 ImageRect.prototype.toString = function() { |
| 279 return '(' + this.left + ',' + this.top + '):' + | 279 return '(' + this.left + ',' + this.top + '):' + |
| 280 '(' + (this.left + this.width) + ',' + (this.top + this.height) + ')'; | 280 '(' + (this.left + this.width) + ',' + (this.top + this.height) + ')'; |
| 281 }; | 281 }; |
| 282 /* | 282 /* |
| 283 * Useful shortcuts for drawing (static functions). | 283 * Useful shortcuts for drawing (static functions). |
| 284 */ | 284 */ |
| 285 | 285 |
| 286 /** | 286 /** |
| 287 * Draw the image in context with appropriate scaling. | 287 * Draw the image in context with appropriate scaling. |
| 288 * @param {CanvasRenderingContext2D} context Context to draw. | 288 * @param {CanvasRenderingContext2D} context Context to draw. |
| 289 * @param {Image} image Image to draw. | 289 * @param {Image} image Image to draw. |
| 290 * @param {Rect=} opt_dstRect Rectangle in the canvas (whole canvas by default). | 290 * @param {ImageRect=} opt_dstRect Rectangle in the canvas (whole canvas by |
| 291 * @param {Rect=} opt_srcRect Rectangle in the image (whole image by default). | 291 * default). |
| 292 * @param {ImageRect=} opt_srcRect Rectangle in the image (whole image by |
| 293 * default). |
| 292 */ | 294 */ |
| 293 Rect.drawImage = function(context, image, opt_dstRect, opt_srcRect) { | 295 ImageRect.drawImage = function(context, image, opt_dstRect, opt_srcRect) { |
| 294 opt_dstRect = opt_dstRect || new Rect(context.canvas); | 296 opt_dstRect = opt_dstRect || new ImageRect(context.canvas); |
| 295 opt_srcRect = opt_srcRect || new Rect(image); | 297 opt_srcRect = opt_srcRect || new ImageRect(image); |
| 296 if (opt_dstRect.isEmpty() || opt_srcRect.isEmpty()) | 298 if (opt_dstRect.isEmpty() || opt_srcRect.isEmpty()) |
| 297 return; | 299 return; |
| 298 context.drawImage(image, | 300 context.drawImage(image, |
| 299 opt_srcRect.left, opt_srcRect.top, opt_srcRect.width, opt_srcRect.height, | 301 opt_srcRect.left, opt_srcRect.top, opt_srcRect.width, opt_srcRect.height, |
| 300 opt_dstRect.left, opt_dstRect.top, opt_dstRect.width, opt_dstRect.height); | 302 opt_dstRect.left, opt_dstRect.top, opt_dstRect.width, opt_dstRect.height); |
| 301 }; | 303 }; |
| 302 | 304 |
| 303 /** | 305 /** |
| 304 * Draw a box around the rectangle. | 306 * Draw a box around the rectangle. |
| 305 * @param {CanvasRenderingContext2D} context Context to draw. | 307 * @param {CanvasRenderingContext2D} context Context to draw. |
| 306 * @param {Rect} rect Rectangle. | 308 * @param {ImageRect} rect Rectangle. |
| 307 */ | 309 */ |
| 308 Rect.outline = function(context, rect) { | 310 ImageRect.outline = function(context, rect) { |
| 309 context.strokeRect( | 311 context.strokeRect( |
| 310 rect.left - 0.5, rect.top - 0.5, rect.width + 1, rect.height + 1); | 312 rect.left - 0.5, rect.top - 0.5, rect.width + 1, rect.height + 1); |
| 311 }; | 313 }; |
| 312 | 314 |
| 313 /** | 315 /** |
| 314 * Fill the rectangle. | 316 * Fill the rectangle. |
| 315 * @param {CanvasRenderingContext2D} context Context to draw. | 317 * @param {CanvasRenderingContext2D} context Context to draw. |
| 316 * @param {Rect} rect Rectangle. | 318 * @param {ImageRect} rect Rectangle. |
| 317 */ | 319 */ |
| 318 Rect.fill = function(context, rect) { | 320 ImageRect.fill = function(context, rect) { |
| 319 context.fillRect(rect.left, rect.top, rect.width, rect.height); | 321 context.fillRect(rect.left, rect.top, rect.width, rect.height); |
| 320 }; | 322 }; |
| 321 | 323 |
| 322 /** | 324 /** |
| 323 * Fills the space between the two rectangles. | 325 * Fills the space between the two rectangles. |
| 324 * @param {CanvasRenderingContext2D} context Context to draw. | 326 * @param {CanvasRenderingContext2D} context Context to draw. |
| 325 * @param {Rect} inner Inner rectangle. | 327 * @param {ImageRect} inner Inner rectangle. |
| 326 * @param {Rect} outer Outer rectangle. | 328 * @param {ImageRect} outer Outer rectangle. |
| 327 */ | 329 */ |
| 328 Rect.fillBetween = function(context, inner, outer) { | 330 ImageRect.fillBetween = function(context, inner, outer) { |
| 329 var innerRight = inner.left + inner.width; | 331 var innerRight = inner.left + inner.width; |
| 330 var innerBottom = inner.top + inner.height; | 332 var innerBottom = inner.top + inner.height; |
| 331 var outerRight = outer.left + outer.width; | 333 var outerRight = outer.left + outer.width; |
| 332 var outerBottom = outer.top + outer.height; | 334 var outerBottom = outer.top + outer.height; |
| 333 if (inner.top > outer.top) { | 335 if (inner.top > outer.top) { |
| 334 context.fillRect( | 336 context.fillRect( |
| 335 outer.left, outer.top, outer.width, inner.top - outer.top); | 337 outer.left, outer.top, outer.width, inner.top - outer.top); |
| 336 } | 338 } |
| 337 if (inner.left > outer.left) { | 339 if (inner.left > outer.left) { |
| 338 context.fillRect( | 340 context.fillRect( |
| (...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 685 * @return {string} Full name. | 687 * @return {string} Full name. |
| 686 */ | 688 */ |
| 687 ImageUtil.getMetricName = function(name) { | 689 ImageUtil.getMetricName = function(name) { |
| 688 return 'PhotoEditor.' + name; | 690 return 'PhotoEditor.' + name; |
| 689 }; | 691 }; |
| 690 | 692 |
| 691 /** | 693 /** |
| 692 * Used for metrics reporting, keep in sync with the histogram description. | 694 * Used for metrics reporting, keep in sync with the histogram description. |
| 693 */ | 695 */ |
| 694 ImageUtil.FILE_TYPES = ['jpg', 'png', 'gif', 'bmp', 'webp']; | 696 ImageUtil.FILE_TYPES = ['jpg', 'png', 'gif', 'bmp', 'webp']; |
| OLD | NEW |