diff options
Diffstat (limited to 'testing/web-platform/tests/webcodecs/image-decoder-utils.js')
-rw-r--r-- | testing/web-platform/tests/webcodecs/image-decoder-utils.js | 206 |
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'); +} |