Skip to content

Commit

Permalink
createImageBitmap: Fuse all operations
Browse files Browse the repository at this point in the history
Consider the function CropImageAndApplyColorSpaceConversion. This
function has separate steps for:
- Crops
- Down-scale
- Flip
- Color-convert (ish)
- Re-orient (maybe)
- Multiply or un-multiply alpha
- Up-scale

These are all separate steps that take an input image and produce an
output image. These operations can (almost) all be fused into a single
blit. Add the function ApplyImageBitmapOptionsTransformsWithBlit to
do this single blit.

Move only one createImageBitmap path to this. Once all paths move
to this, we will remove the functions FlipImageVertically, ScaleImage,
ApplyColorSpaceConversion, BakeOrientation, MakeBlankImage,
CropImageAndApplyColorSpaceConversion, and the guts of a handful
of ImageBitmap::ImageBitmap instances (ImageData I'm looking at you).

This happens to fix one WPT test. Add a bunch more sub-tests for
that test (all other browsers pass that test, along with the new
sub-tests).

This does not handle the case of unpremultiplied alpha, and falls
back to the old path. A similar unpremultiplied alpha path will be
added.

Bug: 40773069, 362431889
Change-Id: Id39ec3aaa5e9b373397b5932ffd31984bcc8c4b5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5890810
Commit-Queue: ccameron chromium <ccameron@chromium.org>
Reviewed-by: Fernando Serboncini <fserb@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1362628}
  • Loading branch information
ccameron-chromium authored and chromium-wpt-export-bot committed Oct 1, 2024
1 parent 819c975 commit 2bf79d5
Showing 1 changed file with 75 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
});
}

function checkColors(ctx, w, h, expectedColors) {
function checkColors(ctx, w, h, tileW, tileH, expectedColors) {
let data = ctx.getImageData(0, 0, w, h).data;
for (let [row, col, r, g, b, a] of expectedColors) {
let x = col * 80 + 40;
let y = row * 80 + 40;
let x = col * tileW + tileW / 2;
let y = row * tileH + tileH / 2;
let i = (x + y * w) * 4;

let expected = [r, g, b, a];
Expand All @@ -38,7 +38,7 @@
.then((image) => createImageBitmap(image))
.then(t.step_func_done(function(imageBitmap) {
ctx.drawImage(imageBitmap, 0, 0);
checkColors(ctx, canvas.width, canvas.height, [
checkColors(ctx, canvas.width, canvas.height, 80, 80, [
// row, col, r, g, b, a
[0, 0, 255, 0, 0, 255],
[0, 1, 0, 255, 0, 255],
Expand All @@ -63,7 +63,7 @@
.then((image) => createImageBitmap(image, { imageOrientation: "flipY" }))
.then(t.step_func_done(function(imageBitmap) {
ctx.drawImage(imageBitmap, 0, 0);
checkColors(ctx, canvas.width, canvas.height, [
checkColors(ctx, canvas.width, canvas.height, 80, 80, [
// row, col, r, g, b, a
[0, 0, 255, 128, 128, 255],
[0, 1, 128, 255, 128, 255],
Expand All @@ -88,7 +88,7 @@
.then(image => createImageBitmap(image, 80, 0, 160, 160))
.then(t.step_func_done(function(imageBitmap) {
ctx.drawImage(imageBitmap, 0, 0);
checkColors(ctx, canvas.width, canvas.height, [
checkColors(ctx, canvas.width, canvas.height, 80, 80, [
// row, col, r, g, b, a
[0, 0, 0, 255, 0, 255],
[0, 1, 0, 0, 255, 255],
Expand All @@ -109,7 +109,7 @@
.then(image => createImageBitmap(image, 80, 0, 160, 160, { imageOrientation: "flipY" }))
.then(t.step_func_done(function(imageBitmap) {
ctx.drawImage(imageBitmap, 0, 0);
checkColors(ctx, canvas.width, canvas.height, [
checkColors(ctx, canvas.width, canvas.height, 80, 80, [
// row, col, r, g, b, a
[0, 0, 128, 255, 128, 255],
[0, 1, 128, 128, 255, 255],
Expand All @@ -118,4 +118,72 @@
]);
}));
}, "createImageBitmap with EXIF rotation, imageOrientation flipY, and cropping");

async_test(function(t) {
const canvas = document.createElement("canvas");
canvas.width = 160;
canvas.height = 80;
document.body.append(canvas);

const ctx = canvas.getContext("2d");
loadImage("resources/squares_6.jpg")
.then((image) => createImageBitmap(image, { resizeWidth:160, resizeHeight:80} ))
.then(t.step_func_done(function(imageBitmap) {
ctx.drawImage(imageBitmap, 0, 0);
checkColors(ctx, canvas.width, canvas.height, 40, 40, [
// row, col, r, g, b, a
[0, 0, 255, 0, 0, 255],
[0, 1, 0, 255, 0, 255],
[0, 2, 0, 0, 255, 255],
[0, 3, 0, 0, 0, 255],
[1, 0, 255, 128, 128, 255],
[1, 1, 128, 255, 128, 255],
[1, 2, 128, 128, 255, 255],
[1, 3, 128, 128, 128, 255],
]);
}));
}, "createImageBitmap with EXIF rotation, imageOrientation from-image, no cropping, and resize");

async_test(function(t) {
const canvas = document.createElement("canvas");
canvas.width = 80;
canvas.height = 80;
document.body.append(canvas);

const ctx = canvas.getContext("2d");
loadImage("resources/squares_6.jpg")
.then(image => createImageBitmap(image, 80, 0, 160, 160, { imageOrientation: "flipY", resizeWidth:80, resizeHeight:80 }))
.then(t.step_func_done(function(imageBitmap) {
ctx.drawImage(imageBitmap, 0, 0);
checkColors(ctx, canvas.width, canvas.height, 40, 40, [
// row, col, r, g, b, a
[0, 0, 128, 255, 128, 255],
[0, 1, 128, 128, 255, 255],
[1, 0, 0, 255, 0, 255],
[1, 1, 0, 0, 255, 255],
]);
}));
}, "createImageBitmap with EXIF rotation, imageOrientation flipY, cropping, and resize");

async_test(function(t) {
const canvas = document.createElement("canvas");
canvas.width = 80;
canvas.height = 40;
document.body.append(canvas);

const ctx = canvas.getContext("2d");
loadImage("resources/squares_6.jpg")
.then(image => createImageBitmap(image, 80, 0, 160, 160, { imageOrientation: "flipY", resizeWidth:80, resizeHeight:40 }))
.then(t.step_func_done(function(imageBitmap) {
ctx.drawImage(imageBitmap, 0, 0);
checkColors(ctx, canvas.width, canvas.height, 40, 20, [
// row, col, r, g, b, a
[0, 0, 128, 255, 128, 255],
[0, 1, 128, 128, 255, 255],
[1, 0, 0, 255, 0, 255],
[1, 1, 0, 0, 255, 255],
]);
}));
}, "createImageBitmap with EXIF rotation, imageOrientation flipY, cropping, and nonuniform resize");

</script>

0 comments on commit 2bf79d5

Please sign in to comment.