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 |