mirror of
https://github.com/servo/servo.git
synced 2025-06-25 17:44:33 +01:00
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');
|
|
}
|