mirror of
https://github.com/denoland/deno.git
synced 2025-08-04 19:08:15 +00:00
fix(ext/canvas): createImageBitmap
must ignore the Blob.type
value (#28741)
fixes https://github.com/denoland/deno/issues/28723 I might misunderstood the spec. We should always sniff the MIME type from the byte sequence when the input is `Blob`.
This commit is contained in:
parent
f334f903ef
commit
53b51113f5
3 changed files with 38 additions and 41 deletions
|
@ -250,7 +250,9 @@ function createImageBitmap(
|
|||
if (isBlob) {
|
||||
imageBitmapSource = 0;
|
||||
buf = new Uint8Array(await image.arrayBuffer());
|
||||
const mimeTypeString = sniffImage(image.type);
|
||||
// NOTE: The MIME type of image/svg+xml can't support
|
||||
// https://github.com/whatwg/html/pull/10172
|
||||
const mimeTypeString = sniffImage(null, buf);
|
||||
|
||||
if (mimeTypeString === "image/png") {
|
||||
mimeType = 1;
|
||||
|
@ -280,17 +282,6 @@ function createImageBitmap(
|
|||
"InvalidStateError",
|
||||
),
|
||||
);
|
||||
} else if (mimeTypeString === "") {
|
||||
return PromiseReject(
|
||||
new DOMException(
|
||||
`The MIME type of source image is not specified\n
|
||||
hint: When you want to get a "Blob" from "fetch", make sure to go through a file server that returns the appropriate content-type response header,
|
||||
and specify the URL to the file server like "await(await fetch('http://localhost:8000/sample.png').blob()".
|
||||
Alternatively, if you are reading a local file using 'Deno.readFile' etc.,
|
||||
set the appropriate MIME type like "new Blob([await Deno.readFile('sample.png')], { type: 'image/png' })".\n`,
|
||||
"InvalidStateError",
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return PromiseReject(
|
||||
new DOMException(
|
||||
|
|
|
@ -421,22 +421,19 @@ function imageTypePatternMatchingAlgorithm(input) {
|
|||
|
||||
/**
|
||||
* Ref: https://mimesniff.spec.whatwg.org/#rules-for-sniffing-images-specifically
|
||||
* @param {string} mimeTypeString
|
||||
* @returns {string}
|
||||
* @param {string | null} mimeTypeString
|
||||
* @param {Uint8Array} byteSequence
|
||||
* @returns {string | null}
|
||||
*/
|
||||
function sniffImage(mimeTypeString) {
|
||||
const mimeType = parseMimeType(mimeTypeString);
|
||||
if (mimeType === null) {
|
||||
function sniffImage(mimeTypeString, byteSequence) {
|
||||
// NOTE: Do we need to implement the "supplied MIME type" detection exactly?
|
||||
// https://mimesniff.spec.whatwg.org/#supplied-mime-type-detection-algorithm
|
||||
|
||||
if (mimeTypeString !== null && isXML(mimeTypeString)) {
|
||||
return mimeTypeString;
|
||||
}
|
||||
|
||||
if (isXML(mimeType)) {
|
||||
return mimeTypeString;
|
||||
}
|
||||
|
||||
const imageTypeMatched = imageTypePatternMatchingAlgorithm(
|
||||
new TextEncoder().encode(mimeTypeString),
|
||||
);
|
||||
const imageTypeMatched = imageTypePatternMatchingAlgorithm(byteSequence);
|
||||
if (imageTypeMatched !== undefined) {
|
||||
return imageTypeMatched;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ Deno.test(async function imageBitmapDirect() {
|
|||
Deno.test(async function imageBitmapRecivesImageBitmap() {
|
||||
const imageData = new Blob(
|
||||
[await Deno.readFile(`${prefix}/1x1-red16.png`)],
|
||||
{ type: "image/png" },
|
||||
);
|
||||
const imageBitmap1 = await createImageBitmap(imageData);
|
||||
const imageBitmap2 = await createImageBitmap(imageBitmap1);
|
||||
|
@ -111,7 +110,6 @@ Deno.test("imageOrientation", async (t) => {
|
|||
|
||||
const imageData = new Blob(
|
||||
[await Deno.readFile(`${prefix}/squares_6.jpg`)],
|
||||
{ type: "image/jpeg" },
|
||||
);
|
||||
const WIDTH = 320;
|
||||
const CHANNELS = 3;
|
||||
|
@ -188,7 +186,6 @@ Deno.test("imageBitmapPremultiplyAlpha", async (t) => {
|
|||
await t.step('"Blob" premultiplyAlpha: "none"', async () => {
|
||||
const imageData = new Blob(
|
||||
[await Deno.readFile(`${prefix}/2x2-transparent8.png`)],
|
||||
{ type: "image/png" },
|
||||
);
|
||||
const imageBitmap = await createImageBitmap(imageData, {
|
||||
premultiplyAlpha: "none",
|
||||
|
@ -206,7 +203,6 @@ Deno.test("imageBitmapFromBlob", async (t) => {
|
|||
await t.step("8-bit png", async () => {
|
||||
const imageData = new Blob(
|
||||
[await Deno.readFile(`${prefix}/1x1-red8.png`)],
|
||||
{ type: "image/png" },
|
||||
);
|
||||
const imageBitmap = await createImageBitmap(imageData);
|
||||
// @ts-ignore: Deno[Deno.internal].core allowed
|
||||
|
@ -216,7 +212,6 @@ Deno.test("imageBitmapFromBlob", async (t) => {
|
|||
await t.step("16-bit png", async () => {
|
||||
const imageData = new Blob(
|
||||
[await Deno.readFile(`${prefix}/1x1-red16.png`)],
|
||||
{ type: "image/png" },
|
||||
);
|
||||
const imageBitmap = await createImageBitmap(imageData);
|
||||
// @ts-ignore: Deno[Deno.internal].core allowed
|
||||
|
@ -236,7 +231,6 @@ Deno.test("imageBitmapFromBlob", async (t) => {
|
|||
await t.step("8-bit jpeg", async () => {
|
||||
const imageData = new Blob(
|
||||
[await Deno.readFile(`${prefix}/1x1-red8.jpeg`)],
|
||||
{ type: "image/jpeg" },
|
||||
);
|
||||
const imageBitmap = await createImageBitmap(imageData);
|
||||
// @ts-ignore: Deno[Deno.internal].core allowed
|
||||
|
@ -246,7 +240,6 @@ Deno.test("imageBitmapFromBlob", async (t) => {
|
|||
await t.step("8-bit bmp", async () => {
|
||||
const imageData = new Blob(
|
||||
[await Deno.readFile(`${prefix}/1x1-red8.bmp`)],
|
||||
{ type: "image/bmp" },
|
||||
);
|
||||
const imageBitmap = await createImageBitmap(imageData);
|
||||
// @ts-ignore: Deno[Deno.internal].core allowed
|
||||
|
@ -256,7 +249,6 @@ Deno.test("imageBitmapFromBlob", async (t) => {
|
|||
await t.step("8-bit gif", async () => {
|
||||
const imageData = new Blob(
|
||||
[await Deno.readFile(`${prefix}/1x1-red8.gif`)],
|
||||
{ type: "image/gif" },
|
||||
);
|
||||
await assertRejects(() => createImageBitmap(imageData), DOMException);
|
||||
// TODO(Hajime-san): remove the comment out when the implementation is ready
|
||||
|
@ -268,7 +260,6 @@ Deno.test("imageBitmapFromBlob", async (t) => {
|
|||
await t.step("8-bit webp", async () => {
|
||||
const imageData = new Blob(
|
||||
[await Deno.readFile(`${prefix}/1x1-red8.webp`)],
|
||||
{ type: "image/webp" },
|
||||
);
|
||||
await assertRejects(() => createImageBitmap(imageData), DOMException);
|
||||
// TODO(Hajime-san): remove the comment out when the implementation is ready
|
||||
|
@ -280,7 +271,6 @@ Deno.test("imageBitmapFromBlob", async (t) => {
|
|||
await t.step("8-bit ico", async () => {
|
||||
const imageData = new Blob(
|
||||
[await Deno.readFile(`${prefix}/1x1-red8.ico`)],
|
||||
{ type: "image/x-icon" },
|
||||
);
|
||||
const imageBitmap = await createImageBitmap(imageData);
|
||||
// @ts-ignore: Deno[Deno.internal].core allowed
|
||||
|
@ -292,7 +282,7 @@ Deno.test("imageBitmapFromBlob", async (t) => {
|
|||
// https://www.digipres.org/formats/sources/fdd/formats/#fdd000583
|
||||
const imageData = new Blob([
|
||||
await Deno.readFile(`${prefix}/1x1-red32f.exr`),
|
||||
], { type: "image/x-exr" });
|
||||
]);
|
||||
await assertRejects(() => createImageBitmap(imageData), DOMException);
|
||||
});
|
||||
});
|
||||
|
@ -304,7 +294,7 @@ Deno.test("imageBitmapFromBlobAnimatedImage", async (t) => {
|
|||
// 0, 0, 255, 255 ]
|
||||
const imageData = new Blob([
|
||||
await Deno.readFile(`${prefix}/1x1-2f-animated-has-def.png`),
|
||||
], { type: "image/png" });
|
||||
]);
|
||||
const imageBitmap = await createImageBitmap(imageData);
|
||||
// @ts-ignore: Deno[Deno.internal].core allowed
|
||||
// deno-fmt-ignore
|
||||
|
@ -317,7 +307,7 @@ Deno.test("imageBitmapFromBlobAnimatedImage", async (t) => {
|
|||
// 0, 0, 255, 255 ]
|
||||
const imageData = new Blob([
|
||||
await Deno.readFile(`${prefix}/1x1-3f-animated-no-def.png`),
|
||||
], { type: "image/png" });
|
||||
]);
|
||||
const imageBitmap = await createImageBitmap(imageData);
|
||||
// @ts-ignore: Deno[Deno.internal].core allowed
|
||||
// deno-fmt-ignore
|
||||
|
@ -333,7 +323,7 @@ Deno.test("imageBitmapFromBlobAnimatedImage", async (t) => {
|
|||
await Deno.readFile(
|
||||
`${prefix}/1x1-3f-lossless-animated-semi-transparent.webp`,
|
||||
),
|
||||
], { type: "image/webp" });
|
||||
]);
|
||||
await assertRejects(() => createImageBitmap(imageData), DOMException);
|
||||
// TODO(Hajime-san): remove the comment out when the implementation is ready
|
||||
// const imageBitmap = await createImageBitmap(imageData);
|
||||
|
@ -348,7 +338,7 @@ Deno.test("imageBitmapFromBlobAnimatedImage", async (t) => {
|
|||
// 0, 0, 255, 255 ]
|
||||
const imageData = new Blob([
|
||||
await Deno.readFile(`${prefix}/1x1-3f-animated.gif`),
|
||||
], { type: "image/gif" });
|
||||
]);
|
||||
await assertRejects(() => createImageBitmap(imageData), DOMException);
|
||||
// TODO(Hajime-san): remove the comment out when the implementation is ready
|
||||
// const imageBitmap = await createImageBitmap(imageData);
|
||||
|
@ -376,7 +366,7 @@ Deno.test("imageBitmapFromBlobColorspaceConversion", async (t) => {
|
|||
await t.step('"Blob" colorSpaceConversion: "none"', async () => {
|
||||
const imageData = new Blob([
|
||||
await Deno.readFile(`${prefix}/wide-gamut-pattern.png`),
|
||||
], { type: "image/png" });
|
||||
]);
|
||||
const imageBitmap = await createImageBitmap(imageData, {
|
||||
colorSpaceConversion: "none",
|
||||
});
|
||||
|
@ -389,7 +379,7 @@ Deno.test("imageBitmapFromBlobColorspaceConversion", async (t) => {
|
|||
await t.step('"Blob" colorSpaceConversion: "default"', async () => {
|
||||
const imageData = new Blob([
|
||||
await Deno.readFile(`${prefix}/wide-gamut-pattern.png`),
|
||||
], { type: "image/png" });
|
||||
]);
|
||||
const imageBitmap = await createImageBitmap(imageData, {
|
||||
colorSpaceConversion: "default",
|
||||
});
|
||||
|
@ -400,3 +390,22 @@ Deno.test("imageBitmapFromBlobColorspaceConversion", async (t) => {
|
|||
assertEquals(firstPixel, new Uint8Array([255, 0, 0, 255]));
|
||||
});
|
||||
});
|
||||
|
||||
// reference:
|
||||
// https://github.com/web-platform-tests/wpt/blob/ea49709e5880c8133249d919c72d67798afc31ec/html/canvas/element/manual/imagebitmap/createImageBitmap-blob-invalidtype.html
|
||||
Deno.test("imageBitmapFromBlobInvalidtype", async () => {
|
||||
const IMAGE = atob(
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAA" +
|
||||
"ACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=",
|
||||
);
|
||||
|
||||
const bytes = new Array(IMAGE.length);
|
||||
for (let i = 0; i < IMAGE.length; i++) {
|
||||
bytes[i] = IMAGE.charCodeAt(i);
|
||||
}
|
||||
|
||||
const blob = new Blob([new Uint8Array(bytes)], { type: "text/html" });
|
||||
const imageBitmap = await createImageBitmap(blob);
|
||||
assertEquals(imageBitmap.width, 1);
|
||||
assertEquals(imageBitmap.height, 1);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue