forked from mirrors/gecko-dev
Automatic update from web-platform-tests [WebCodecs] Ensure orientation is set on YUV image decodes. While the RGB decoding path was always setting the orientation, it was overlooked on the YUV decoding path. As such, this change adds code to set it and tests to ensure it doesn't regress. Fixed: 1342672 Change-Id: I7b8f7f05502a040525cc84fc60f2dd12a42211c0 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3751369 Reviewed-by: Thomas Guilbert <tguilbert@chromium.org> Commit-Queue: Thomas Guilbert <tguilbert@chromium.org> Auto-Submit: Dale Curtis <dalecurtis@chromium.org> Commit-Queue: Dale Curtis <dalecurtis@chromium.org> Cr-Commit-Position: refs/heads/main@{#1021792} -- wpt-commits: 8016ebe321801a0a80e948b8dbb75b9cc0109ac5 wpt-pr: 34737
206 lines
7.2 KiB
JavaScript
206 lines
7.2 KiB
JavaScript
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');
|
|
}
|