View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host.canvas;
16  
17  import org.htmlunit.WebDriverTestCase;
18  import org.htmlunit.junit.annotation.Alerts;
19  import org.junit.jupiter.api.Test;
20  
21  /**
22   * Tests for {@link ImageData}.
23   *
24   * @author Ahmed Ashour
25   * @author Ronald Brill
26   */
27  public class ImageDataTest extends WebDriverTestCase {
28  
29      /**
30       * @throws Exception if an error occurs
31       */
32      @Test
33      @Alerts({"8", "1", "2",
34               "0", "190", "3", "255", "0", "190", "3", "255",
35               "8", "2", "1",
36               "0", "190", "3", "255", "0", "190", "3", "255"})
37      public void ctorArray() throws Exception {
38          final String html = DOCTYPE_HTML
39              + "<html><head><script>\n"
40              + LOG_TITLE_FUNCTION
41              + "function test() {\n"
42              + "  if (typeof ImageData != 'function') { log('no ctor'); return; }"
43  
44              + "  var arr = new Uint8ClampedArray(8);\n"
45              + "  for (var i = 0; i < arr.length; i += 4) {\n"
46              + "    arr[i + 0] = 0;\n"
47              + "    arr[i + 1] = 190;\n"
48              + "    arr[i + 2] = 3;\n"
49              + "    arr[i + 3] = 255;\n"
50              + "  }\n"
51  
52              + "  var imageData = new ImageData(arr, 1);\n"
53              + "  log(imageData.data.length);\n"
54              + "  log(imageData.width);\n"
55              + "  log(imageData.height);\n"
56  
57              + "  var data = imageData.data;\n"
58              + "  for (var i = 0; i < data.length; i++) {\n"
59              + "    log(data[i]);\n"
60              + "  }\n"
61  
62              + "  var imageData = new ImageData(arr, 2);\n"
63              + "  log(imageData.data.length);\n"
64              + "  log(imageData.width);\n"
65              + "  log(imageData.height);\n"
66  
67              + "  var data = imageData.data;\n"
68              + "  for (var i = 0; i < data.length; i++) {\n"
69              + "    log(data[i]);\n"
70              + "  }\n"
71  
72              + "}\n"
73              + "</script>\n"
74              + "</head>\n"
75              + "<body onload='test()'><canvas id='myCanvas'></canvas></body>\n"
76              + "</html>";
77          loadPageVerifyTitle2(html);
78      }
79  
80      /**
81       * @throws Exception if an error occurs
82       */
83      @Test
84      @Alerts({"8", "1", "2",
85               "0", "190", "3", "255", "0", "190", "3", "255"})
86      public void ctorArrayWidthHeight() throws Exception {
87          final String html = DOCTYPE_HTML
88              + "<html><head><script>\n"
89              + LOG_TITLE_FUNCTION
90              + "function test() {\n"
91              + "  if (typeof ImageData != 'function') { log('no ctor'); return; }"
92  
93              + "  var arr = new Uint8ClampedArray(8);\n"
94              + "  for (var i = 0; i < arr.length; i += 4) {\n"
95              + "    arr[i + 0] = 0;\n"
96              + "    arr[i + 1] = 190;\n"
97              + "    arr[i + 2] = 3;\n"
98              + "    arr[i + 3] = 255;\n"
99              + "  }\n"
100 
101             + "  var imageData = new ImageData(arr, 1, 2);\n"
102             + "  log(imageData.data.length);\n"
103             + "  log(imageData.width);\n"
104             + "  log(imageData.height);\n"
105 
106             + "  var data = imageData.data;\n"
107             + "  for (var i = 0; i < data.length; i++) {\n"
108             + "    log(data[i]);\n"
109             + "  }\n"
110             + "}\n"
111             + "</script>\n"
112             + "</head>\n"
113             + "<body onload='test()'><canvas id='myCanvas'></canvas></body>\n"
114             + "</html>";
115         loadPageVerifyTitle2(html);
116     }
117 
118     /**
119      * @throws Exception if an error occurs
120      */
121     @Test
122     @Alerts({"TypeError", "IndexSizeError/DOMException", "IndexSizeError/DOMException",
123              "IndexSizeError/DOMException", "IndexSizeError/DOMException",
124              "InvalidStateError/DOMException", "IndexSizeError/DOMException"})
125     public void ctorArrayInvalid() throws Exception {
126         final String html = DOCTYPE_HTML
127             + "<html><head><script>\n"
128             + LOG_TITLE_FUNCTION
129             + "function test() {\n"
130 
131             + "  try {\n"
132             + "    var imageData = new ImageData();\n"
133             + "  } catch(e) { logEx(e);}\n"
134 
135             + "  try {\n"
136             + "    var imageData = new ImageData(-2, 1);\n"
137             + "  } catch(e) { logEx(e);}\n"
138 
139             + "  try {\n"
140             + "    var imageData = new ImageData(2, -1);\n"
141             + "  } catch(e) { logEx(e);}\n"
142 
143             + "  try {\n"
144             + "    var imageData = new ImageData(-2, -1);\n"
145             + "  } catch(e) { logEx(e);}\n"
146 
147             + "  var arr = new Uint8ClampedArray(8);\n"
148             + "  try {\n"
149             + "    var imageData = new ImageData(arr, 3);\n"
150             + "  } catch(e) { logEx(e);}\n"
151 
152             + "  arr = new Uint8ClampedArray(11);\n"
153             + "  try {\n"
154             + "    var imageData = new ImageData(arr, 2);\n"
155             + "  } catch(e) { logEx(e);}\n"
156 
157             + "  arr = new Uint8ClampedArray(8);\n"
158             + "  try {\n"
159             + "    var imageData = new ImageData(arr, 2, 2);\n"
160             + "  } catch(e) { logEx(e);}\n"
161 
162             + "}\n"
163             + "</script>\n"
164             + "</head>\n"
165             + "<body onload='test()'><canvas id='myCanvas'></canvas></body>\n"
166             + "</html>";
167         loadPageVerifyTitle2(html);
168     }
169 
170     /**
171      * @throws Exception if an error occurs
172      */
173     @Test
174     @Alerts({"8", "2", "1", "0", "0", "0", "0", "0", "0", "0", "0"})
175     public void ctorWidthHeight() throws Exception {
176         final String html = DOCTYPE_HTML
177             + "<html><head><script>\n"
178             + LOG_TITLE_FUNCTION
179             + "function test() {\n"
180             + "  if (typeof ImageData != 'function') { log('no ctor'); return; }"
181 
182             + "  var imageData = new ImageData(2, 1);\n"
183             + "  log(imageData.data.length);\n"
184             + "  log(imageData.width);\n"
185             + "  log(imageData.height);\n"
186 
187             + "  var data = imageData.data;\n"
188             + "  for (var i = 0; i < data.length; i++) {\n"
189             + "    log(data[i]);\n"
190             + "  }\n"
191             + "}\n"
192             + "</script>\n"
193             + "</head>\n"
194             + "<body onload='test()'><canvas id='myCanvas'></canvas></body>\n"
195             + "</html>";
196         loadPageVerifyTitle2(html);
197     }
198 
199     /**
200      * @throws Exception if an error occurs
201      */
202     @Test
203     @Alerts({"200", "100", "50", "255", "100", "50", "125", "255", "123", "111", "222", "255"})
204     public void getImageData() throws Exception {
205         final String html = DOCTYPE_HTML
206             + "<html><head><script>\n"
207             + LOG_TITLE_FUNCTION
208             + "function test() {\n"
209             + "  var canvas = document.getElementById('myCanvas');\n"
210             + "  if (canvas.getContext) {\n"
211             + "    var ctx = canvas.getContext('2d');\n"
212             + "    ctx.fillStyle = 'rgb(200,100,50)';\n"
213             + "    ctx.fillRect(0, 0, 2, 2);\n"
214             + "    ctx.fillStyle = 'rgba(0, 0, 200, 0.5)';\n"
215             + "    ctx.fillRect(1, 0, 2, 2);\n"
216             + "    ctx.fillStyle = 'rgb(123,111,222)';\n"
217             + "    ctx.fillRect(2, 0, 2, 2);\n"
218             + "    var imageData = ctx.getImageData(0, 0, 3, 1);\n"
219             + "    var data = imageData.data;\n"
220             + "    for (var i = 0; i < data.length; i++) {\n"
221             + "      log(data[i]);\n"
222             + "    }\n"
223             + "  }\n"
224             + "}\n"
225             + "</script>\n"
226             + "</head>\n"
227             + "<body onload='test()'><canvas id='myCanvas'></canvas></body>\n"
228             + "</html>";
229         loadPageVerifyTitle2(html);
230     }
231 
232     /**
233      * @throws Exception if an error occurs
234      */
235     @Test
236     @Alerts({"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"})
237     public void getImageDataOutside() throws Exception {
238         final String html = DOCTYPE_HTML
239             + "<html><head><script>\n"
240             + LOG_TITLE_FUNCTION
241             + "function test() {\n"
242             + "  var canvas = document.getElementById('myCanvas');\n"
243             + "  if (canvas.getContext) {\n"
244             + "    var ctx = canvas.getContext('2d');\n"
245             + "    ctx.fillStyle = 'rgb(200,100,50)';\n"
246             + "    ctx.fillRect(0, 0, 2, 2);\n"
247             + "    ctx.fillStyle = 'rgba(0, 0, 200, 0.5)';\n"
248             + "    ctx.fillRect(1, 0, 2, 2);\n"
249             + "    ctx.fillStyle = 'rgb(123,111,222)';\n"
250             + "    ctx.fillRect(2, 0, 2, 2);\n"
251             + "    var imageData = ctx.getImageData(-10, -10, 3, 1);\n"
252             + "    var data = imageData.data;\n"
253             + "    for (var i = 0; i < data.length; i++) {\n"
254             + "      log(data[i]);\n"
255             + "    }\n"
256             + "  }\n"
257             + "}\n"
258             + "</script>\n"
259             + "</head>\n"
260             + "<body onload='test()'><canvas id='myCanvas'></canvas></body>\n"
261             + "</html>";
262         loadPageVerifyTitle2(html);
263     }
264 
265     /**
266      * @throws Exception if an error occurs
267      */
268     @Test
269     @Alerts({"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"})
270     public void getImageDataOutside2() throws Exception {
271         final String html = DOCTYPE_HTML
272             + "<html><head><script>\n"
273             + LOG_TITLE_FUNCTION
274             + "function test() {\n"
275             + "  var canvas = document.getElementById('myCanvas');\n"
276             + "  if (canvas.getContext) {\n"
277             + "    var ctx = canvas.getContext('2d');\n"
278             + "    ctx.fillStyle = 'rgb(200,100,50)';\n"
279             + "    ctx.fillRect(0, 0, 2, 2);\n"
280             + "    ctx.fillStyle = 'rgba(0, 0, 200, 0.5)';\n"
281             + "    ctx.fillRect(1, 0, 2, 2);\n"
282             + "    ctx.fillStyle = 'rgb(123,111,222)';\n"
283             + "    ctx.fillRect(2, 0, 2, 2);\n"
284             + "    var imageData = ctx.getImageData(500, 500, 3, 1);\n"
285             + "    var data = imageData.data;\n"
286             + "    for (var i = 0; i < data.length; i++) {\n"
287             + "      log(data[i]);\n"
288             + "    }\n"
289             + "  }\n"
290             + "}\n"
291             + "</script>\n"
292             + "</head>\n"
293             + "<body onload='test()'><canvas id='myCanvas'></canvas></body>\n"
294             + "</html>";
295         loadPageVerifyTitle2(html);
296     }
297 
298     /**
299      * @throws Exception if an error occurs
300      */
301     @Test
302     @Alerts({"0", "0", "0", "0", "200", "100", "50", "255", "100", "50", "125", "255"})
303     public void getImageDataPartlyOutside() throws Exception {
304         final String html = DOCTYPE_HTML
305             + "<html><head><script>\n"
306             + LOG_TITLE_FUNCTION
307             + "function test() {\n"
308             + "  var canvas = document.getElementById('myCanvas');\n"
309             + "  if (canvas.getContext) {\n"
310             + "    var ctx = canvas.getContext('2d');\n"
311             + "    ctx.fillStyle = 'rgb(200,100,50)';\n"
312             + "    ctx.fillRect(0, 0, 2, 2);\n"
313             + "    ctx.fillStyle = 'rgba(0, 0, 200, 0.5)';\n"
314             + "    ctx.fillRect(1, 0, 2, 2);\n"
315             + "    ctx.fillStyle = 'rgb(123,111,222)';\n"
316             + "    ctx.fillRect(2, 0, 2, 2);\n"
317             + "    var imageData = ctx.getImageData(-1, 0, 3, 1);\n"
318             + "    var data = imageData.data;\n"
319             + "    for (var i = 0; i < data.length; i++) {\n"
320             + "      log(data[i]);\n"
321             + "    }\n"
322             + "  }\n"
323             + "}\n"
324             + "</script>\n"
325             + "</head>\n"
326             + "<body onload='test()'><canvas id='myCanvas'></canvas></body>\n"
327             + "</html>";
328         loadPageVerifyTitle2(html);
329     }
330 
331     /**
332      * @throws Exception if an error occurs
333      */
334     @Test
335     @Alerts({"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"})
336     public void getImageDataPartlyOutside2() throws Exception {
337         final String html = DOCTYPE_HTML
338             + "<html><head><script>\n"
339             + LOG_TITLE_FUNCTION
340             + "function test() {\n"
341             + "  var canvas = document.getElementById('myCanvas');\n"
342             + "  if (canvas.getContext) {\n"
343             + "    var ctx = canvas.getContext('2d');\n"
344             + "    ctx.fillStyle = 'rgb(200,100,50)';\n"
345             + "    ctx.fillRect(0, 0, 2, 2);\n"
346             + "    ctx.fillStyle = 'rgba(0, 0, 200, 0.5)';\n"
347             + "    ctx.fillRect(1, 0, 2, 2);\n"
348             + "    ctx.fillStyle = 'rgb(123,111,222)';\n"
349             + "    ctx.fillRect(2, 0, 2, 2);\n"
350             + "    var imageData = ctx.getImageData(298, 149, 3, 1);\n"
351             + "    var data = imageData.data;\n"
352             + "    for (var i = 0; i < data.length; i++) {\n"
353             + "      log(data[i]);\n"
354             + "    }\n"
355             + "  }\n"
356             + "}\n"
357             + "</script>\n"
358             + "</head>\n"
359             + "<body onload='test()'><canvas id='myCanvas'></canvas></body>\n"
360             + "</html>";
361         loadPageVerifyTitle2(html);
362     }
363 
364     /**
365      * @throws Exception if an error occurs
366      */
367     @Test
368     @Alerts({"200", "100", "50", "255", "200", "100", "50", "255", "0", "0", "0", "0"})
369     public void getImageDataDrawAfter() throws Exception {
370         final String html = DOCTYPE_HTML
371             + "<html><head><script>\n"
372             + LOG_TITLE_FUNCTION
373             + "function test() {\n"
374             + "  var canvas = document.getElementById('myCanvas');\n"
375             + "  if (canvas.getContext) {\n"
376             + "    var ctx = canvas.getContext('2d');\n"
377             + "    ctx.fillStyle = 'rgb(200,100,50)';\n"
378             + "    ctx.fillRect(0, 0, 2, 2);\n"
379             + "    var imageData = ctx.getImageData(0, 0, 3, 1);\n"
380 
381             + "    ctx.fillStyle = 'rgba(0, 0, 200, 0.5)';\n"
382             + "    ctx.fillRect(1, 0, 2, 2);\n"
383             + "    ctx.fillStyle = 'rgb(123,111,222)';\n"
384             + "    ctx.fillRect(2, 0, 2, 2);\n"
385 
386             + "    var data = imageData.data;\n"
387             + "    for (var i = 0; i < data.length; i++) {\n"
388             + "      log(data[i]);\n"
389             + "    }\n"
390             + "  }\n"
391             + "}\n"
392             + "</script>\n"
393             + "</head>\n"
394             + "<body onload='test()'><canvas id='myCanvas'></canvas></body>\n"
395             + "</html>";
396         loadPageVerifyTitle2(html);
397     }
398 
399     /**
400      * @throws Exception if an error occurs
401      */
402     @Test
403     @Alerts({"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"})
404     public void data() throws Exception {
405         final String html = DOCTYPE_HTML
406             + "<html><head><script>\n"
407             + LOG_TITLE_FUNCTION
408             + "function test() {\n"
409             + "  var canvas = document.getElementById('myCanvas');\n"
410             + "  if (canvas.getContext) {\n"
411             + "    var ctx = canvas.getContext('2d');\n"
412             + "    ctx.fillStyle = 'rgb(200,100,50)';\n"
413             + "    ctx.fillRect(0, 0, 2, 2);\n"
414             + "    ctx.fillStyle = 'rgba(0, 0, 200, 0.5)';\n"
415             + "    ctx.fillRect(1, 0, 2, 2);\n"
416             + "    ctx.fillStyle = 'rgb(123,111,222)';\n"
417             + "    ctx.fillRect(2, 0, 2, 2);\n"
418             + "    var imageData = ctx.getImageData(0, 0, 3, 1);\n"
419             + "    for (var i = 0; i < imageData.data.length; i++) {\n"
420             + "      imageData.data[i] = i;\n"
421             + "      log(imageData.data[i]);\n"
422             + "    }\n"
423             + "  }\n"
424             + "}\n"
425             + "</script>\n"
426             + "</head>\n"
427             + "<body onload='test()'><canvas id='myCanvas'></canvas></body>\n"
428             + "</html>";
429         loadPageVerifyTitle2(html);
430     }
431 
432     /**
433      * @throws Exception if an error occurs
434      */
435     @Test
436     @Alerts({"8", "1", "2",
437                 "13", "0", "17", "0", "0", "0", "0", "42"})
438     public void setValues() throws Exception {
439         final String html = DOCTYPE_HTML
440             + "<html><head><script>\n"
441             + LOG_TITLE_FUNCTION
442             + "function test() {\n"
443             + "  var canvas = document.getElementById('myCanvas');\n"
444             + "  if (canvas.getContext) {\n"
445             + "    var ctx = canvas.getContext('2d');\n"
446 
447             + "    var imageData = ctx.createImageData(1, 2);\n"
448             + "    log(imageData.data.length);\n"
449             + "    log(imageData.width);\n"
450             + "    log(imageData.height);\n"
451 
452             + "    imageData.data[0] = 13;\n"
453             + "    imageData.data[2] = 17;\n"
454             + "    imageData.data[7] = 42;\n"
455             + "    imageData.data[8] = 43;\n"
456             + "    imageData.data[-5] = 7;\n"
457             + "    imageData.data[100] = 11;\n"
458             + "    for (var i = 0; i < imageData.data.length; i++) {\n"
459             + "      log(imageData.data[i]);\n"
460             + "    }\n"
461             + "  }\n"
462             + "}\n"
463             + "</script>\n"
464             + "</head>\n"
465             + "<body onload='test()'><canvas id='myCanvas'></canvas></body>\n"
466             + "</html>";
467         loadPageVerifyTitle2(html);
468     }
469 
470     /**
471      * @throws Exception if an error occurs
472      */
473     @Test
474     @Alerts({"24", "2", "3",
475                 "0", "0", "17", "0", "0", "0", "0", "0", "0", "0", "0", "0",
476                 "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"})
477     public void createImageData() throws Exception {
478         final String html = DOCTYPE_HTML
479             + "<html><head><script>\n"
480             + LOG_TITLE_FUNCTION
481             + "function test() {\n"
482             + "  var canvas = document.getElementById('myCanvas');\n"
483             + "  if (canvas.getContext) {\n"
484             + "    var ctx = canvas.getContext('2d');\n"
485             + "    ctx.fillRect(1, 1, 13, 11);\n"
486 
487             + "    var imageData = ctx.createImageData(2, 3);\n"
488             + "    log(imageData.data.length);\n"
489             + "    log(imageData.width);\n"
490             + "    log(imageData.height);\n"
491 
492             + "    imageData.data[2] = 17;\n"
493             + "    for (var i = 0; i < imageData.data.length; i++) {\n"
494             + "      log(imageData.data[i]);\n"
495             + "    }\n"
496             + "  }\n"
497             + "}\n"
498             + "</script>\n"
499             + "</head>\n"
500             + "<body onload='test()'><canvas id='myCanvas'></canvas></body>\n"
501             + "</html>";
502         loadPageVerifyTitle2(html);
503     }
504 
505     /**
506      * @throws Exception if an error occurs
507      */
508     @Test
509     @Alerts({"24", "2", "3",
510                 "0", "0", "17", "0", "0", "0", "0", "0", "0", "0", "0", "0",
511                 "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"})
512     public void createImageDataFlipped() throws Exception {
513         final String html = DOCTYPE_HTML
514             + "<html><head><script>\n"
515             + LOG_TITLE_FUNCTION
516             + "function test() {\n"
517             + "  var canvas = document.getElementById('myCanvas');\n"
518             + "  if (canvas.getContext) {\n"
519             + "    var ctx = canvas.getContext('2d');\n"
520             + "    ctx.fillRect(1, 1, 13, 11);\n"
521 
522             + "    var imageData = ctx.createImageData(-2, -3);\n"
523             + "    log(imageData.data.length);\n"
524             + "    log(imageData.width);\n"
525             + "    log(imageData.height);\n"
526 
527             + "    imageData.data[2] = 17;\n"
528             + "    for (var i = 0; i < imageData.data.length; i++) {\n"
529             + "      log(imageData.data[i]);\n"
530             + "    }\n"
531             + "  }\n"
532             + "}\n"
533             + "</script>\n"
534             + "</head>\n"
535             + "<body onload='test()'><canvas id='myCanvas'></canvas></body>\n"
536             + "</html>";
537         loadPageVerifyTitle2(html);
538     }
539 
540     /**
541      * @throws Exception if an error occurs
542      */
543     @Test
544     @Alerts({"8",
545                 "0", "0", "17", "0", "0", "0", "0", "0",
546                 "8", "1", "2",
547                 "0", "0", "0", "0", "0", "0", "0", "0"})
548     public void createImageDataFromImageData() throws Exception {
549         final String html = DOCTYPE_HTML
550             + "<html><head><script>\n"
551             + LOG_TITLE_FUNCTION
552             + "function test() {\n"
553             + "  var canvas = document.getElementById('myCanvas');\n"
554             + "  if (canvas.getContext) {\n"
555             + "    var ctx = canvas.getContext('2d');\n"
556             + "    var imageData = ctx.createImageData(1, 2);\n"
557             + "    log(imageData.data.length);\n"
558             + "    imageData.data[2] = 17;\n"
559             + "    for (var i = 0; i < imageData.data.length; i++) {\n"
560             + "      log(imageData.data[i]);\n"
561             + "    }\n"
562 
563             + "    var imageDataCopy = ctx.createImageData(imageData);\n"
564             + "    log(imageDataCopy.data.length);\n"
565             + "    log(imageDataCopy.width);\n"
566             + "    log(imageDataCopy.height);\n"
567             + "    for (var i = 0; i < imageDataCopy.data.length; i++) {\n"
568             + "      log(imageDataCopy.data[i]);\n"
569             + "    }\n"
570             + "  }\n"
571             + "}\n"
572             + "</script>\n"
573             + "</head>\n"
574             + "<body onload='test()'><canvas id='myCanvas'></canvas></body>\n"
575             + "</html>";
576         loadPageVerifyTitle2(html);
577     }
578 }