summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webcodecs/image-decoder-utils.js
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/webcodecs/image-decoder-utils.js')
-rw-r--r--testing/web-platform/tests/webcodecs/image-decoder-utils.js206
1 files changed, 206 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webcodecs/image-decoder-utils.js b/testing/web-platform/tests/webcodecs/image-decoder-utils.js
new file mode 100644
index 0000000000..eccab9b09a
--- /dev/null
+++ b/testing/web-platform/tests/webcodecs/image-decoder-utils.js
@@ -0,0 +1,206 @@
+const kYellow = 0xFFFF00FF;
+const kRed = 0xFF0000FF;
+const kBlue = 0x0000FFFF;
+const kGreen = 0x00FF00FF;
+
+function getColorName(color) {
+ switch (color) {
+ case kYellow:
+ return "Yellow";
+ case kRed:
+ return "Red";
+ case kBlue:
+ return "Blue";
+ case kGreen:
+ return "Green";
+ }
+ return "#" + color.toString(16);
+}
+
+function toUInt32(pixelArray, roundForYuv) {
+ let p = pixelArray.data;
+
+ // YUV to RGB conversion introduces some loss, so provide some leeway.
+ if (roundForYuv) {
+ const tolerance = 3;
+ for (var i = 0; i < p.length; ++i) {
+ if (p[i] >= 0xFF - tolerance)
+ p[i] = 0xFF;
+ if (p[i] <= 0x00 + tolerance)
+ p[i] = 0x00;
+ }
+ }
+
+ return ((p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]) >>> 0;
+}
+
+function flipMatrix(m) {
+ return m.map(row => row.reverse());
+}
+
+function rotateMatrix(m, count) {
+ for (var i = 0; i < count; ++i)
+ m = m[0].map((val, index) => m.map(row => row[index]).reverse());
+ return m;
+}
+
+function testFourColorsDecodeBuffer(buffer, mimeType, options = {}) {
+ var decoder = new ImageDecoder(
+ {data: buffer, type: mimeType, preferAnimation: options.preferAnimation});
+ return decoder.decode().then(result => {
+ assert_equals(result.image.displayWidth, 320);
+ assert_equals(result.image.displayHeight, 240);
+ if (options.preferAnimation !== undefined) {
+ assert_greater_than(decoder.tracks.length, 1);
+ assert_equals(
+ options.preferAnimation, decoder.tracks.selectedTrack.animated);
+ }
+ if (options.yuvFormat !== undefined)
+ assert_equals(result.image.format, options.yuvFormat);
+ if (options.tolerance === undefined)
+ options.tolerance = 0;
+
+ let canvas = new OffscreenCanvas(
+ result.image.displayWidth, result.image.displayHeight);
+ let ctx = canvas.getContext('2d');
+ ctx.drawImage(result.image, 0, 0);
+
+ let top_left = ctx.getImageData(0, 0, 1, 1);
+ let top_right = ctx.getImageData(result.image.displayWidth - 1, 0, 1, 1);
+ let bottom_left = ctx.getImageData(0, result.image.displayHeight - 1, 1, 1);
+ let left_corner = ctx.getImageData(
+ result.image.displayWidth - 1, result.image.displayHeight - 1, 1, 1);
+
+ assert_array_approx_equals(
+ top_left.data, [0xFF, 0xFF, 0x00, 0xFF], options.tolerance,
+ 'top left corner is yellow');
+ assert_array_approx_equals(
+ top_right.data, [0xFF, 0x00, 0x00, 0xFF], options.tolerance,
+ 'top right corner is red');
+ assert_array_approx_equals(
+ bottom_left.data, [0x00, 0x00, 0xFF, 0xFF], options.tolerance,
+ 'bottom left corner is blue');
+ assert_array_approx_equals(
+ left_corner.data, [0x00, 0xFF, 0x00, 0xFF], options.tolerance,
+ 'bottom right corner is green');
+ });
+}
+
+function testFourColorDecodeWithExifOrientation(orientation, canvas, useYuv) {
+ return ImageDecoder.isTypeSupported('image/jpeg').then(support => {
+ assert_implements_optional(
+ support, 'Optional codec image/jpeg not supported.');
+ const testFile =
+ useYuv ? 'four-colors-limited-range-420-8bpc.jpg' : 'four-colors.jpg';
+ return fetch(testFile)
+ .then(response => {
+ return response.arrayBuffer();
+ })
+ .then(buffer => {
+ let u8buffer = new Uint8Array(buffer);
+ u8buffer[useYuv ? 0x31 : 0x1F] =
+ orientation; // Location derived via diff.
+ let decoder = new ImageDecoder({data: u8buffer, type: 'image/jpeg'});
+ return decoder.decode();
+ })
+ .then(result => {
+ let respectOrientation = true;
+ if (canvas)
+ respectOrientation = canvas.style.imageOrientation != 'none';
+
+ let expectedWidth = 320;
+ let expectedHeight = 240;
+ if (orientation > 4 && respectOrientation)
+ [expectedWidth, expectedHeight] = [expectedHeight, expectedWidth];
+
+ if (respectOrientation) {
+ assert_equals(result.image.displayWidth, expectedWidth);
+ assert_equals(result.image.displayHeight, expectedHeight);
+ } else if (orientation > 4) {
+ assert_equals(result.image.displayHeight, expectedWidth);
+ assert_equals(result.image.displayWidth, expectedHeight);
+ }
+
+ if (!canvas) {
+ canvas = new OffscreenCanvas(
+ result.image.displayWidth, result.image.displayHeight);
+ } else {
+ canvas.width = expectedWidth;
+ canvas.height = expectedHeight;
+ }
+
+ let ctx = canvas.getContext('2d');
+ ctx.drawImage(result.image, 0, 0);
+
+ let matrix = [
+ [kYellow, kRed],
+ [kBlue, kGreen],
+ ];
+ if (respectOrientation) {
+ switch (orientation) {
+ case 1: // kOriginTopLeft, default
+ break;
+ case 2: // kOriginTopRight, mirror along y-axis
+ matrix = flipMatrix(matrix);
+ break;
+ case 3: // kOriginBottomRight, 180 degree rotation
+ matrix = rotateMatrix(matrix, 2);
+ break;
+ case 4: // kOriginBottomLeft, mirror along the x-axis
+ matrix = flipMatrix(rotateMatrix(matrix, 2));
+ break;
+ case 5: // kOriginLeftTop, mirror along x-axis + 270 degree CW
+ // rotation
+ matrix = flipMatrix(rotateMatrix(matrix, 1));
+ break;
+ case 6: // kOriginRightTop, 90 degree CW rotation
+ matrix = rotateMatrix(matrix, 1);
+ break;
+ case 7: // kOriginRightBottom, mirror along x-axis + 90 degree CW
+ // rotation
+ matrix = flipMatrix(rotateMatrix(matrix, 3));
+ break;
+ case 8: // kOriginLeftBottom, 270 degree CW rotation
+ matrix = rotateMatrix(matrix, 3);
+ break;
+ default:
+ assert_between_inclusive(
+ orientation, 1, 8, 'unknown image orientation');
+ break;
+ };
+ }
+
+ verifyFourColorsImage(
+ expectedWidth, expectedHeight, ctx, matrix, useYuv);
+ });
+ });
+}
+
+function verifyFourColorsImage(width, height, ctx, matrix, isYuv) {
+ if (!matrix) {
+ matrix = [
+ [kYellow, kRed],
+ [kBlue, kGreen],
+ ];
+ }
+
+ let expectedTopLeft = matrix[0][0];
+ let expectedTopRight = matrix[0][1];
+ let expectedBottomLeft = matrix[1][0];
+ let expectedBottomRight = matrix[1][1];
+
+ let topLeft = toUInt32(ctx.getImageData(0, 0, 1, 1), isYuv);
+ let topRight = toUInt32(ctx.getImageData(width - 1, 0, 1, 1), isYuv);
+ let bottomLeft = toUInt32(ctx.getImageData(0, height - 1, 1, 1), isYuv);
+ let bottomRight =
+ toUInt32(ctx.getImageData(width - 1, height - 1, 1, 1), isYuv);
+
+ assert_equals(getColorName(topLeft), getColorName(expectedTopLeft),
+ 'top left corner');
+ assert_equals(getColorName(topRight), getColorName(expectedTopRight),
+ 'top right corner');
+ assert_equals(getColorName(bottomLeft), getColorName(expectedBottomLeft),
+ 'bottom left corner');
+ assert_equals(getColorName(bottomRight), getColorName(expectedBottomRight),
+ 'bottom right corner');
+}