Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
heycam authored Oct 23, 2021
1 parent 04499b8 commit ee92e46
Show file tree
Hide file tree
Showing 13 changed files with 202 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,33 @@
<link rel="stylesheet" href="/html/canvas/resources/canvas-tests.css">
<body>
<script>
function testCanvasDisplayingPattern(canvas, width, height)
function testCanvasDisplayingPattern(canvas, width, height, sourceIsVideo)
{
var tolerance = 10; // for creating ImageBitmap from a video, the tolerance needs to be high
const check = (x, y, r, g, b, a) =>
var tolerance = 1;
let topLeft = [255, 0, 0, 255];
let topRight = [0, 255, 0, 255];
let bottomLeft = [0, 0, 255, 255];
let bottomRight = [0, 0, 0, 255];
if (sourceIsVideo) {
// The source video uses colors in the Rec.601 color space whose
// values are close to full red, full green, full blue, and black,
// but when converted to sRGB, are somewhat different.
topLeft = [247, 37, 0, 255];
topRight = [63, 251, 0, 255];
bottomLeft = [28, 35, 255, 255];
bottomRight = [5, 0, 2, 255];
}
const check = (x, y, [r, g, b, a]) =>
_assertPixelApprox(canvas, x,y, r,g,b,a, `${x},${y}`, `${r},${g},${b},${a}`, tolerance);
check(1 * width / 4, 1 * height / 4, 255,0,0,255);
check(3 * width / 4, 1 * height / 4, 0,255,0,255);
check(1 * width / 4, 3 * height / 4, 0,0,255,255);
check(3 * width / 4, 3 * height / 4, 0,0,0,255);
check(1 * width / 4, 1 * height / 4, topLeft);
check(3 * width / 4, 1 * height / 4, topRight);
check(1 * width / 4, 3 * height / 4, bottomLeft);
check(3 * width / 4, 3 * height / 4, bottomRight);
}

function testDrawImageBitmap(source, args = [], { resizeWidth = 20, resizeHeight = 20 } = {})
{
let sourceIsVideo = source instanceof HTMLVideoElement;
var canvas = document.createElement("canvas");
canvas.width = resizeWidth;
canvas.height = resizeHeight;
Expand All @@ -30,7 +44,7 @@
assert_equals(imageBitmap.width, resizeWidth);
assert_equals(imageBitmap.height, resizeHeight);
ctx.drawImage(imageBitmap, 0, 0);
testCanvasDisplayingPattern(canvas, resizeWidth, resizeHeight);
testCanvasDisplayingPattern(canvas, resizeWidth, resizeHeight, sourceIsVideo);
});
}

Expand Down
39 changes: 25 additions & 14 deletions html/canvas/element/manual/imagebitmap/createImageBitmap-flipY.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,37 @@
<link rel="stylesheet" href="/html/canvas/resources/canvas-tests.css">
<body>
<script>
function testCanvasDisplayingPattern(canvas, width, height, flipped)
function testCanvasDisplayingPattern(canvas, width, height, sourceIsVideo, flipped)
{
var tolerance = 10; // for creating ImageBitmap from a video, the tolerance needs to be high
const check = (x, y, r, g, b, a) =>
_assertPixelApprox(canvas, x,y, r,g,b,a, `${x},${y}`, `${r},${g},${b},${a}`, tolerance);
var tolerance = 1;
let topLeft = [255, 0, 0, 255];
let topRight = [0, 255, 0, 255];
let bottomLeft = [0, 0, 255, 255];
let bottomRight = [0, 0, 0, 255];
if (sourceIsVideo) {
// The source video uses colors in the Rec.601 color space whose
// values are close to full red, full green, full blue, and black,
// but when converted to sRGB, are somewhat different.
topLeft = [247, 37, 0, 255];
topRight = [63, 251, 0, 255];
bottomLeft = [28, 35, 255, 255];
bottomRight = [5, 0, 2, 255];
}
if (flipped) {
check(1 * width / 4, 3 * height / 4, 255,0,0,255);
check(3 * width / 4, 3 * height / 4, 0,255,0,255);
check(1 * width / 4, 1 * height / 4, 0,0,255,255);
check(3 * width / 4, 1 * height / 4, 0,0,0,255);
} else {
check(1 * width / 4, 1 * height / 4, 255,0,0,255);
check(3 * width / 4, 1 * height / 4, 0,255,0,255);
check(1 * width / 4, 3 * height / 4, 0,0,255,255);
check(3 * width / 4, 3 * height / 4, 0,0,0,255);
[topLeft, bottomLeft] = [bottomLeft, topLeft];
[topRight, bottomRight] = [bottomRight, topRight];
}
const check = (x, y, [r, g, b, a]) =>
_assertPixelApprox(canvas, x,y, r,g,b,a, `${x},${y}`, `${r},${g},${b},${a}`, tolerance);
check(1 * width / 4, 1 * height / 4, topLeft);
check(3 * width / 4, 1 * height / 4, topRight);
check(1 * width / 4, 3 * height / 4, bottomLeft);
check(3 * width / 4, 3 * height / 4, bottomRight);
}

function testDrawImageBitmap(source, args = [], flipped, { resizeWidth = 20, resizeHeight = 20 } = {})
{
let sourceIsVideo = source instanceof HTMLVideoElement;
var canvas = document.createElement("canvas");
canvas.width = resizeWidth;
canvas.height = resizeHeight;
Expand All @@ -37,7 +48,7 @@
assert_equals(imageBitmap.width, resizeWidth);
assert_equals(imageBitmap.height, resizeHeight);
ctx.drawImage(imageBitmap, 0, 0);
testCanvasDisplayingPattern(canvas, resizeWidth, resizeHeight, flipped);
testCanvasDisplayingPattern(canvas, resizeWidth, resizeHeight, sourceIsVideo, flipped);
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<!DOCTYPE HTML>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="canvas-display-p3.js"></script>
<body>
<script>
// Test that drawing ImageBitmaps with different video source color profiles
// into sRGB and Display P3 canvases works, by reading pixels with
// getImageData() as sRGB and Display P3 values.
for (let [filenameBase, expectedPixels] of Object.entries(videoTests)) {
for (let contextColorSpace of ["srgb", "display-p3"]) {
for (let imageDataColorSpace of ["srgb", "display-p3"]) {
for (let cropSource of [false, true]) {
async_test(function(t) {
let video = document.createElement("video");
video.onloadeddata = t.step_func(function() {

let canvas = document.createElement("canvas");
canvas.width = 2;
canvas.height = 2;

let ctx = canvas.getContext("2d", { colorSpace: contextColorSpace });

let imageBitmapPromise;
if (cropSource)
imageBitmapPromise = createImageBitmap(video, 1, 1, 1, 1);
else
imageBitmapPromise = createImageBitmap(video);

imageBitmapPromise.then(t.step_func_done(function(imageBitmap) {
video.remove();
ctx.drawImage(imageBitmap, 0, 0);

let imageData = ctx.getImageData(0, 0, 1, 1, { colorSpace: imageDataColorSpace });

let expected = expectedPixels[`${contextColorSpace} ${imageDataColorSpace}`];
assert_true(pixelsApproximatelyEqual(imageData.data, expected), `Actual pixel value ${[...imageData.data]} is approximately equal to ${expected}.`);
}), t.step_func(function(error) {
video.remove();
throw error;
}));
});
for (let format of ["mp4", "webm"]) {
let source = document.createElement("source");
source.src = `resources/${filenameBase}.${format}`;
source.type = `video/${format}`;
video.append(source);
}
document.body.append(video);
}, `${filenameBase}, Context ${contextColorSpace}, ImageData ${imageDataColorSpace}, cropSource=${cropSource}`);
}
}
}
}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!DOCTYPE HTML>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="canvas-display-p3.js"></script>
<body>
<script>
// Test that drawing videos with different color spaces into sRGB and Display P3
// canvases works, by reading pixels with getImageData() as sRGB and Display P3
// values.
for (let [filenameBase, expectedPixels] of Object.entries(videoTests)) {
for (let contextColorSpace of ["srgb", "display-p3"]) {
for (let imageDataColorSpace of ["srgb", "display-p3"]) {
for (let scaleImage of [false, true]) {
async_test(function(t) {
let video = document.createElement("video");
video.onloadeddata = t.step_func_done(function() {

let canvas = document.createElement("canvas");
canvas.width = 2;
canvas.height = 2;

let ctx = canvas.getContext("2d", { colorSpace: contextColorSpace });
if (scaleImage)
ctx.drawImage(video, 0, 0, 10, 10);
else
ctx.drawImage(video, 0, 0);
video.remove();

let imageData = ctx.getImageData(0, 0, 1, 1, { colorSpace: imageDataColorSpace });

let expected = expectedPixels[`${contextColorSpace} ${imageDataColorSpace}`];
assert_true(pixelsApproximatelyEqual(imageData.data, expected), `Actual pixel value ${[...imageData.data]} is approximately equal to ${expected}.`);
});
for (let format of ["mp4", "webm"]) {
let source = document.createElement("source");
source.src = `resources/${filenameBase}.${format}`;
source.type = `video/${format}`;
video.append(source);
}
document.body.append(video);
}, `${filenameBase}, Context ${contextColorSpace}, ImageData ${imageDataColorSpace}, scaleImage=${scaleImage}`);
}
}
}
}
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,59 @@ const svgImageTests = {
},
};

// Each video:
// * is 300x200 and has a single color
// * has a filename base that indicates its contents:
//
// <color-space>-<8-or-10-bit-color-value>
//
// * was generated using commands like:
//
// W=300 H=200 Y=3F Cb=66 Cr=F0 ; \
// perl -e "print pack('c', 0x$Y) x ($W * $H), pack('c', 0x$Cb) x ($W * $H / 4), pack('c', 0x$Cr) x ($W * $H / 4)" | \
// ffmpeg -f rawvideo -pix_fmt yuv420p -s:v ${W}x$H -r 25 -i - -pix_fmt yuv420p -colorspace bt709 -color_primaries bt709 -color_trc iec61966_2_1 sRGB-FF0100.webm
//
// W=300 H=200 Y=0BB Cb=1BD Cr=2EF ; \
// perl -e "print pack('s', 0x$Y) x ($W * $H), pack('s', 0x$Cb) x ($W * $H / 4), pack('s', 0x$Cr) x ($W * $H / 4)" | \
// ffmpeg -f rawvideo -pix_fmt yuv420p10le -s:v ${W}x$H -r 25 -i - -c:v libx265 -vtag hvc1 -pix_fmt yuv420p10le -colorspace bt2020nc -color_primaries bt2020 -color_trc bt2020-10 Rec2020-222000000.mp4
//
// W=300 H=200 Y=0BB Cb=1BD Cr=2EF ; \
// perl -e "print pack('s', 0x$Y) x ($W * $H), pack('s', 0x$Cb) x ($W * $H / 4), pack('s', 0x$Cr) x ($W * $H / 4)" | \
// ffmpeg -f rawvideo -pix_fmt yuv420p10le -s:v ${W}x$H -r 25 -i - -vcodec libvpx-vp9 -profile:v 2 -pix_fmt yuv420p10le -colorspace bt2020nc -color_primaries bt2020 -color_trc bt2020-10 Rec2020-222000000.webm
//
// where the Y'CbCr values were computed using https://jdashg.github.io/misc/colors/from-coeffs.html.
const videoTests = {
// Rec.709 Y'CbCr (0x3F, 0x66, 0xF0) = sRGB (0xFF, 0x01, 0x00)
"sRGB-FF0100": {
"srgb srgb": [255, 1, 0, 255],
"srgb display-p3": [234, 51, 35, 255],
"display-p3 srgb": [255, 0, 0, 255],
"display-p3 display-p3": [234, 51, 35, 255],
},
// Rec.709 Y'CbCr (0x32, 0x6D, 0xD2) = sRGB (0xBB, 0x00, 0x00)
"sRGB-BB0000": {
"srgb srgb": [187, 0, 0, 255],
"srgb display-p3": [171, 35, 23, 255],
"display-p3 srgb": [187, 1, 0, 255],
"display-p3 display-p3": [171, 35, 23, 255],
},

// 10 bit Rec.2020 Y'CbCr (0x126, 0x183, 0x3C0) = Rec.2020 (0x3FF, 0x000, 0x000)
"Rec2020-3FF000000": {
"srgb srgb": [255, 0, 0, 255],
"srgb display-p3": [234, 51, 35, 255],
"display-p3 srgb": [255, 0, 0, 255],
"display-p3 display-p3": [255, 0, 9, 255],
},
// 10 bit Rec.2020 Y'CbCr (0x0BB, 0x1BD, 0x2EF) = Rec.2020 (0x222, 0x000, 0x000)
"Rec2020-222000000": {
"srgb srgb": [186, 0, 0, 255],
"srgb display-p3": [170, 34, 23, 255],
"display-p3 srgb": [186, 0, 0, 255],
"display-p3 display-p3": [169, 0, 3, 255],
},
};

const fromSRGBToDisplayP3 = {
"255,0,0,255": [234, 51, 35, 255],
"255,0,0,204": [234, 51, 35, 204],
Expand All @@ -223,7 +276,7 @@ const fromDisplayP3ToSRGB = {

function pixelsApproximatelyEqual(p1, p2) {
for (let i = 0; i < 4; ++i) {
if (Math.abs(p1[i] - p2[i]) > 2)
if (Math.abs(p1[i] - p2[i]) > 3)
return false;
}
return true;
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 comments on commit ee92e46

Please sign in to comment.