test_imagebitmap_cropping.html (11870B)
1 <!DOCTYPE HTML> 2 <title>Test ImageBitmap Cropping (Bug 1190210)</title> 3 <meta charset="utf-8"> 4 <script src="/tests/SimpleTest/SimpleTest.js"></script> 5 <link rel="stylesheet" href="/tests/SimpleTest/test.css"> 6 <body> 7 <script type="text/javascript"> 8 9 SimpleTest.waitForExplicitFinish(); 10 11 /** 12 * [isPixel description] 13 * 14 * @param {[type]} ctx : canvas context 15 * @param {[type]} x : pixel x coordinate 16 * @param {[type]} y : pixel y coordinate 17 * @param {[type]} c : a rgba color code 18 * @param {[type]} d : error duration 19 * @return {Promise} 20 */ 21 function isPixel(ctx, x, y, c, d) { 22 var pos = x + "," + y; 23 var color = c[0] + "," + c[1] + "," + c[2] + "," + c[3]; 24 var pixel = ctx.getImageData(x, y, 1, 1); 25 var pr = pixel.data[0], 26 pg = pixel.data[1], 27 pb = pixel.data[2], 28 pa = pixel.data[3]; 29 ok(c[0]-d <= pr && pr <= c[0]+d && 30 c[1]-d <= pg && pg <= c[1]+d && 31 c[2]-d <= pb && pb <= c[2]+d && 32 c[3]-d <= pa && pa <= c[3]+d, 33 "pixel "+pos+" of "+ctx.canvas.id+" is "+pr+","+pg+","+pb+","+pa+"; expected "+color+" +/- "+d); 34 } 35 36 // 37 // The pattern of the 320x240.webm video. 38 // .------------------------------------------------. 39 // | 255 | 255 | 0 | 0 | 255 | 255 | 0 | 40 // | 255 | 255 | 255 | 255 | 0 | 0 | 0 | 41 // | 255 | 0 | 255 | 0 | 255 | 0 | 255 | 42 // | | | | | | | | 43 // ^ ^ ^ ^ ^ ^ ^ ^ 44 // 0 46 92 138 184 230 276 319 45 // 46 // 47 // TEST_BITMAPS is a collection of test cases. 48 // Each object in the TEST_BITMAPS array is a test case with the following 49 // properties: 50 // 1) croppingArea: indicating the cropping area in format (x, y, width, height). 51 // 2) testedPixels: an array of pixels that is going to be checked. 52 // Each item in the testedPixels array contains: 53 // 2.1) "pixel": the coordinate of this pixel (x, y). 54 // 2.2) "expectedColor": the expected color of this pixel (r, g, b, a). 55 // 2.3) "tolerance": the acceptable tolerance of pixel values. 56 // 57 var TEST_BITMAPS = [ 58 // Cropping area is exactly the same as source surface. 59 {'croppingArea': [0, 0, 320, 240], 60 'testedPixels': [{"pixel": [0, 0], "expectedColor": [255, 255, 255, 255], "tolerance": 5}, 61 {"pixel": [50, 0], "expectedColor": [255, 255, 0, 255], "tolerance": 5}]}, 62 // Cropping area completely covers the source surface. 63 {'croppingArea': [-100, -100, 520, 440], 64 'testedPixels': [{"pixel": [0, 0], "expectedColor": [0, 0, 0, 0], "tolerance": 5}, 65 {"pixel": [519, 0], "expectedColor": [0, 0, 0, 0], "tolerance": 5}, 66 {"pixel": [0, 439], "expectedColor": [0, 0, 0, 0], "tolerance": 5}, 67 {"pixel": [519, 439], "expectedColor": [0, 0, 0, 0], "tolerance": 5}, 68 {"pixel": [100, 100], "expectedColor": [255, 255, 255, 255], "tolerance": 5}, 69 {"pixel": [150, 120], "expectedColor": [255, 255, 0, 255], "tolerance": 5}, 70 {"pixel": [200, 140], "expectedColor": [0, 255, 255, 255], "tolerance": 5}]}, 71 // Cropping area partially covers the left-upper part of the source surface. 72 {'croppingArea': [-100, -100, 320, 240], 73 'testedPixels': [{"pixel": [0, 0], "expectedColor": [0, 0, 0, 0 ], "tolerance": 5}, 74 {"pixel": [100, 100], "expectedColor": [255, 255, 255, 255], "tolerance": 5}, 75 {"pixel": [150, 100], "expectedColor": [255, 255, 0, 255], "tolerance": 5}]}, 76 // Cropping area partially covers the middle-upper part of the source surface. 77 {'croppingArea': [ 100, -100, 220, 240], 78 'testedPixels': [{"pixel": [0, 0], "expectedColor": [0, 0, 0, 0 ], "tolerance": 5}, 79 {"pixel": [0, 100], "expectedColor": [0, 255, 255, 255], "tolerance": 5}, 80 {"pixel": [150, 100], "expectedColor": [255, 0, 0, 255], "tolerance": 5}]}, 81 // Cropping area partially covers the right-upper part of the source surface. 82 {'croppingArea': [ 200, -100, 320, 240], 83 'testedPixels': [{"pixel": [0, 0], "expectedColor": [0, 0, 0, 0 ], "tolerance": 5}, 84 {"pixel": [0, 100], "expectedColor": [255, 0, 255, 255], "tolerance": 5}, 85 {"pixel": [100, 100], "expectedColor": [0, 0, 255, 255], "tolerance": 5}]}, 86 // Cropping area partially covers the left-center part of the source surface. 87 {'croppingArea': [-100, 100, 320, 120], 88 'testedPixels': [{"pixel": [0, 0], "expectedColor": [0, 0, 0, 0 ], "tolerance": 5}, 89 {"pixel": [200, 0], "expectedColor": [0, 255, 255, 255], "tolerance": 5}, 90 {"pixel": [250, 10], "expectedColor": [0, 255, 0, 255], "tolerance": 5}]}, 91 // Cropping area partially covers the left-bottom part of the source surface. 92 {'croppingArea': [-100, 200, 320, 240], 93 'testedPixels': [{"pixel": [0, 0], "expectedColor": [0, 0, 0, 0 ], "tolerance": 5}, 94 {"pixel": [100, 0], "expectedColor": [0, 60, 136, 255], "tolerance": 5}, 95 {"pixel": [180, 10], "expectedColor": [255, 255, 255, 255], "tolerance": 5}]}, 96 // Cropping area partially covers the middle-bottom part of the source surface. 97 {'croppingArea': [ 40, 200, 200, 100], 98 'testedPixels': [{"pixel": [0, 0], "expectedColor": [0, 60, 136, 255], "tolerance": 5}, 99 {"pixel": [100, 20], "expectedColor": [107, 0, 210, 255], "tolerance": 5}, 100 {"pixel": [80, 150], "expectedColor": [0, 0, 0, 0 ], "tolerance": 5}]}, 101 // Cropping area partially covers the right-bottom part of the source surface. 102 {'croppingArea': [ 160, 100, 300, 300], 103 'testedPixels': [{"pixel": [0, 0], "expectedColor": [0, 255, 0, 255], "tolerance": 5}, 104 {"pixel": [120, 20], "expectedColor": [0, 0, 255, 255], "tolerance": 5}, 105 {"pixel": [299, 299], "expectedColor": [0, 0, 0, 0 ], "tolerance": 5}]}, 106 // Cropping area is completely outside the source surface. (upper-left) 107 {'croppingArea': [-500, -500, 20, 20], 108 'testedPixels': [{"pixel": [0, 0], "expectedColor": [0, 0, 0, 0], "tolerance": 5}, 109 {"pixel": [19, 19], "expectedColor": [0, 0, 0, 0], "tolerance": 5}]}, 110 // Cropping area is completely outside the source surface. (upper-right) 111 {'croppingArea': [ 500, -500, 20, 20], 112 'testedPixels': [{"pixel": [0, 0], "expectedColor": [0, 0, 0, 0], "tolerance": 5}, 113 {"pixel": [19, 19], "expectedColor": [0, 0, 0, 0], "tolerance": 5}]}, 114 // Cropping area is completely outside the source surface. (bottom-left) 115 {'croppingArea': [-200, 500, 20, 20], 116 'testedPixels': [{"pixel": [0, 0], "expectedColor": [0, 0, 0, 0], "tolerance": 5}, 117 {"pixel": [19, 19], "expectedColor": [0, 0, 0, 0], "tolerance": 5}]}, 118 // Cropping area is completely outside the source surface. (bottom-right) 119 {'croppingArea': [ 500, 200, 20, 20], 120 'testedPixels': [{"pixel": [0, 0], "expectedColor": [0, 0, 0, 0], "tolerance": 5}, 121 {"pixel": [19, 19], "expectedColor": [0, 0, 0, 0], "tolerance": 5}]}, 122 ]; 123 124 function failed(ex) { 125 ok(false, "Promise failure: " + ex); 126 } 127 128 var gImage; 129 var gVideo; 130 var gCanvas; 131 var gCtx; 132 var gImageData; 133 var gImageBitmap; 134 var gPNGBlob; 135 var gJPEGBlob; 136 137 function prepareSources() { 138 gVideo = document.createElement("video"); 139 gVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/canvas/test/320x240.webm&type=video/webm&cors=anonymous"; 140 gVideo.crossOrigin = "anonymous"; 141 gVideo.autoplay = "true" 142 143 144 gCanvas = document.createElement("canvas"); 145 gCtx = gCanvas.getContext("2d"); 146 147 var resolver; 148 var promise = new Promise(function(resolve, reject) { 149 resolver = resolve; 150 }); 151 152 // Prepare video. 153 gVideo.onloadeddata = function() { 154 ok(gVideo, "[Prepare Sources] gVideo is ok."); 155 156 // Prepare canvas. 157 gCanvas.width = gVideo.videoWidth; 158 gCanvas.height = gVideo.videoHeight; 159 gCtx.drawImage(gVideo, 0, 0); 160 ok(gCanvas, "[Prepare Sources] gCanvas is ok."); 161 ok(gCtx, "[Prepare Sources] gCtx is ok."); 162 163 // Prepare image. 164 gImage = document.createElement("img"); 165 gImage.src = gCanvas.toDataURL(); 166 var resolverImage; 167 var promiseImage = new Promise(function(resolve, reject) { 168 resolverImage = resolve; 169 }); 170 gImage.onload = function() { 171 resolverImage(true); 172 } 173 174 // Prepare ImageData. 175 gImageData = gCtx.getImageData(0, 0, gCanvas.width, gCanvas.height); 176 ok(gImageData, "[Prepare Sources] gImageData is ok."); 177 178 // Prepapre PNG Blob. 179 var promisePNGBlob = new Promise(function(resolve, reject) { 180 gCanvas.toBlob(function(blob) { 181 gPNGBlob = blob; 182 ok(gPNGBlob, "[Prepare Sources] gPNGBlob is ok."); 183 resolve(true); 184 }); 185 }); 186 187 // Prepare JPEG Blob. 188 var promiseJPEGBlob = new Promise(function(resolve, reject) { 189 gCanvas.toBlob(function(blob) { 190 gJPEGBlob = blob; 191 ok(gJPEGBlob, "[Prepare Sources] gJPEGBlob is ok."); 192 resolve(true); 193 }, "image/jpeg", 0.95); 194 }); 195 196 // Prepare ImageBitmap. 197 var promiseImageBitmap = new Promise(function(resolve, reject) { 198 var p = createImageBitmap(gVideo); 199 p.then(function(bitmap) { 200 gImageBitmap = bitmap; 201 ok(gImageBitmap, "[Prepare Sources] gImageBitmap is ok."); 202 resolve(true); 203 }); 204 }); 205 206 resolver(Promise.all([ 207 promiseImage, 208 promisePNGBlob, 209 promiseJPEGBlob, 210 promiseImageBitmap 211 ])) 212 } 213 214 return promise; 215 } 216 217 function testCropping_randomTest(source) { 218 var canvasSrouce = document.createElement("canvas"); 219 var ctxSource = canvasSrouce.getContext("2d"); 220 221 var p = createImageBitmap(source); 222 p.then(function(bitmap) { 223 canvasSrouce.width = bitmap.width; 224 canvasSrouce.height = bitmap.height; 225 }); 226 } 227 228 function testCropping(source) { 229 var canvas = document.createElement("canvas"); 230 var ctx = canvas.getContext("2d"); 231 document.body.appendChild(canvas); 232 233 function createBitmap(def) { 234 return createImageBitmap(source, def.croppingArea[0], def.croppingArea[1], def.croppingArea[2], def.croppingArea[3]) 235 .then(function (bitmap) { def.bitmap = bitmap; }, failed); 236 }; 237 238 var promise = new Promise(function(resolve, reject) { 239 resolve(Promise.all(TEST_BITMAPS.map(createBitmap))) 240 }); 241 242 function testPixel(testedPixel) { 243 isPixel(ctx, testedPixel.pixel[0], testedPixel.pixel[1], testedPixel.expectedColor, testedPixel.tolerance); 244 }; 245 246 return promise.then(function() { 247 TEST_BITMAPS.forEach(function (testCase) { 248 if (!testCase.bitmap) { return; } 249 ctx.clearRect(0, 0, canvas.width, canvas.height); 250 canvas.width = testCase.bitmap.width; 251 canvas.height = testCase.bitmap.height; 252 ctx.drawImage(testCase.bitmap, 0, 0); 253 testCase.testedPixels.forEach(testPixel); 254 }); 255 }); 256 } 257 258 function runTests() { 259 260 prepareSources(). 261 then( function() { return Promise.all([testCropping(gImage), 262 testCropping(gVideo), 263 testCropping(gCanvas), 264 testCropping(gCtx), 265 testCropping(gImageData), 266 testCropping(gImageBitmap), 267 testCropping(gPNGBlob), 268 testCropping(gJPEGBlob)]); }). 269 then(SimpleTest.finish, function(ev) { failed(ev); SimpleTest.finish(); }); 270 } 271 272 addLoadEvent(runTests); 273 274 </script> 275 </body>