diff options
Diffstat (limited to 'testing/web-platform/tests/html/canvas/element/manual/imagebitmap/imagebitmap-replication-exif-orientation.html')
-rw-r--r-- | testing/web-platform/tests/html/canvas/element/manual/imagebitmap/imagebitmap-replication-exif-orientation.html | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/canvas/element/manual/imagebitmap/imagebitmap-replication-exif-orientation.html b/testing/web-platform/tests/html/canvas/element/manual/imagebitmap/imagebitmap-replication-exif-orientation.html new file mode 100644 index 0000000000..ab4331adef --- /dev/null +++ b/testing/web-platform/tests/html/canvas/element/manual/imagebitmap/imagebitmap-replication-exif-orientation.html @@ -0,0 +1,146 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Verify that image orientation is propagated when ImageBitmap objects are replicated.</title> +<link rel="author" title="Justin Novosad" href="mailto:junov@chromium.org"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> + +<body> +<script> +// This test is most relevant for browser implementations that apply EXIF image +// orientation lazily. That is to say that the transform is applied at rasterization +// time rather than at image decode time. This implies that image orientation metadata +// is stored internally in the decoded image's data structure. This test ensures +// that the orientation metadata is correctly carried over when ImageBitmap objects +// are replicated (serialized/deserialized, copied or transferred). + +function checkImageBitmapRotated(bitmap) { + assert_equals(bitmap.width, 320, 'Bitmap width'); + assert_equals(bitmap.height, 160, 'Bitmap height'); + + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + + const expected_colors = [ + // row, col, r, g, b, a + [0, 0, 255, 0, 0, 255], + [0, 1, 0, 255, 0, 255], + [0, 2, 0, 0, 255, 255], + [0, 3, 0, 0, 0, 255], + [1, 0, 255, 128, 128, 255], + [1, 1, 128, 255, 128, 255], + [1, 2, 128, 128, 255, 255], + [1, 3, 128, 128, 128, 255], + ]; + + canvas.width = bitmap.width; + canvas.height = bitmap.height; + ctx.drawImage(bitmap, 0, 0); + + let data = ctx.getImageData(0, 0, canvas.width, canvas.height).data; + for (let [row, col, r, g, b, a] of expected_colors) { + let x = col * 80 + 40; + let y = row * 80 + 40; + let i = (x + y * canvas.width) * 4; + let expected = [r, g, b, a]; + let actual = [data[i], data[i + 1], data[i + 2], data[i + 3]]; + assert_array_approx_equals(actual, expected, 1, `Pixel value at (${x},${y}) ${expected} =~ ${actual}.`); + } +} + +promise_test(async t => { + const response = await fetch("resources/squares_6.jpg"); + const blob = await response.blob(); + const image = await createImageBitmap(blob) + const image_copy = structuredClone(image); + checkImageBitmapRotated(image_copy); +}, "ImageBitmap from file with EXIF rotation, duplicated via structuredClone"); + +promise_test(async t => { + const image = new Image(); + image.src = "resources/squares_6.jpg" + await new Promise(resolve => image.onload = resolve); + const image_copy = await createImageBitmap(image); + checkImageBitmapRotated(image_copy); +}, "ImageBitmap from file with EXIF rotation, loaded via <img>"); + +promise_test(async t => { + const image = new Image(); + image.src = "resources/squares_6.jpg" + // The following has no effect because the image's style is not + // processed unless the element is connected to the DOM. + image.style.imageOrientation = "none"; + await new Promise(resolve => image.onload = resolve); + const image_copy = await createImageBitmap(image); + checkImageBitmapRotated(image_copy); +}, "ImageBitmap from file with EXIF rotation, loaded via <img> not in DOM, imageOrientation = none"); + +promise_test(async t => { + const image = new Image(); + document.body.appendChild(image); + image.src = "resources/squares_6.jpg" + // The style is being processed in this case, but the imageOrientation + // CSS property must still have no effect because createImageBitmap + // accesses the element's underlying media directly, without being + // affected by the image's style (unlike drawImage). + image.style.imageOrientation = "none"; + await new Promise(resolve => image.onload = resolve); + const image_copy = await createImageBitmap(image); + checkImageBitmapRotated(image_copy); +}, "ImageBitmap from file with EXIF rotation, loaded via <img> in DOM, imageOrientation = none"); + + +promise_test(async t => { + const response = await fetch("resources/squares_6.jpg"); + const blob = await response.blob(); + const image = await createImageBitmap(blob); + const image_copy = await createImageBitmap(image); + checkImageBitmapRotated(image_copy); +}, "ImageBitmap from file with EXIF rotation, duplicated via createImageBitmap"); + +promise_test(async t => { + const worker = new Worker("serialize-worker.js"); + const response = await fetch("resources/squares_6.jpg"); + const blob = await response.blob() + const image = await createImageBitmap(blob); + worker.postMessage({bitmap: image}); + const bitmap = (await new Promise(resolve => {worker.addEventListener("message", resolve)})).data.bitmap; + checkImageBitmapRotated(bitmap); +}, "ImageBitmap from file with EXIF rotation, duplicated via worker serialization round-trip"); + +promise_test(async t => { + const worker = new Worker("transfer-worker.js"); + let response = await fetch("resources/squares_6.jpg"); + let blob = await response.blob(); + let image = await createImageBitmap(blob); + worker.postMessage({bitmap: image}, [image]); + const bitmap = (await new Promise(resolve => {worker.addEventListener("message", resolve)})).data.bitmap; + checkImageBitmapRotated(bitmap); +}, "ImageBitmap from file with EXIF rotation, duplicated via worker transfer round-trip"); + +promise_test(async t => { + // This test variant ensures additional code coverage. + // By creating a canvas pattern, a reference to the ImageBitmap's + // underlying pixel data is held in the source realm. This forces + // implementations that do lazy copying to duplicate the pixel + // data at transfer time. This test verifies that the lazy + // duplication code path (if applicable) carries over the image + // orientation metadata. + const worker = new Worker("transfer-worker.js"); + let response = await fetch("resources/squares_6.jpg"); + let blob = await response.blob(); + let image = await createImageBitmap(blob); + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + const pattern = ctx.createPattern(image, 'repeat'); + worker.postMessage({bitmap: image}, [image]); + const bitmap = (await new Promise(resolve => {worker.addEventListener("message", resolve)})).data.bitmap; + checkImageBitmapRotated(bitmap); +}, "ImageBitmap from file with EXIF rotation, duplicated via worker transfer round-trip, while referenced by a CanvasPattern"); + + +</script> +</body>
\ No newline at end of file |