mirror of
https://github.com/denoland/deno.git
synced 2025-02-01 20:25:12 -05:00
ad67750587
- https://github.com/denoland/deno/pull/25517#discussion_r1801666281 - https://github.com/denoland/deno/pull/25517#discussion_r1801666872
350 lines
8.9 KiB
JavaScript
350 lines
8.9 KiB
JavaScript
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
|
|
import { internals, primordials } from "ext:core/mod.js";
|
|
import { op_create_image_bitmap } from "ext:core/ops";
|
|
import * as webidl from "ext:deno_webidl/00_webidl.js";
|
|
import { DOMException } from "ext:deno_web/01_dom_exception.js";
|
|
import { createFilteredInspectProxy } from "ext:deno_console/01_console.js";
|
|
import { BlobPrototype } from "ext:deno_web/09_file.js";
|
|
import { sniffImage } from "ext:deno_web/01_mimesniff.js";
|
|
const {
|
|
ObjectPrototypeIsPrototypeOf,
|
|
Symbol,
|
|
SymbolFor,
|
|
TypedArrayPrototypeGetBuffer,
|
|
Uint8Array,
|
|
PromiseReject,
|
|
RangeError,
|
|
ArrayPrototypeJoin,
|
|
} = primordials;
|
|
import {
|
|
_data,
|
|
_height,
|
|
_width,
|
|
ImageDataPrototype,
|
|
} from "ext:deno_web/16_image_data.js";
|
|
|
|
webidl.converters["ImageOrientation"] = webidl.createEnumConverter(
|
|
"ImageOrientation",
|
|
[
|
|
"from-image",
|
|
"flipY",
|
|
],
|
|
);
|
|
|
|
webidl.converters["PremultiplyAlpha"] = webidl.createEnumConverter(
|
|
"PremultiplyAlpha",
|
|
[
|
|
"none",
|
|
"premultiply",
|
|
"default",
|
|
],
|
|
);
|
|
|
|
webidl.converters["ColorSpaceConversion"] = webidl.createEnumConverter(
|
|
"ColorSpaceConversion",
|
|
[
|
|
"none",
|
|
"default",
|
|
],
|
|
);
|
|
|
|
webidl.converters["ResizeQuality"] = webidl.createEnumConverter(
|
|
"ResizeQuality",
|
|
[
|
|
"pixelated",
|
|
"low",
|
|
"medium",
|
|
"high",
|
|
],
|
|
);
|
|
|
|
webidl.converters["ImageBitmapOptions"] = webidl.createDictionaryConverter(
|
|
"ImageBitmapOptions",
|
|
[
|
|
{
|
|
key: "imageOrientation",
|
|
converter: webidl.converters["ImageOrientation"],
|
|
defaultValue: "from-image",
|
|
},
|
|
{
|
|
key: "premultiplyAlpha",
|
|
converter: webidl.converters["PremultiplyAlpha"],
|
|
defaultValue: "default",
|
|
},
|
|
{
|
|
key: "colorSpaceConversion",
|
|
converter: webidl.converters["ColorSpaceConversion"],
|
|
defaultValue: "default",
|
|
},
|
|
{
|
|
key: "resizeWidth",
|
|
converter: (v, prefix, context, opts) =>
|
|
webidl.converters["unsigned long"](v, prefix, context, {
|
|
...opts,
|
|
enforceRange: true,
|
|
}),
|
|
},
|
|
{
|
|
key: "resizeHeight",
|
|
converter: (v, prefix, context, opts) =>
|
|
webidl.converters["unsigned long"](v, prefix, context, {
|
|
...opts,
|
|
enforceRange: true,
|
|
}),
|
|
},
|
|
{
|
|
key: "resizeQuality",
|
|
converter: webidl.converters["ResizeQuality"],
|
|
defaultValue: "low",
|
|
},
|
|
],
|
|
);
|
|
|
|
const _bitmapData = Symbol("[[bitmapData]]");
|
|
const _detached = Symbol("[[detached]]");
|
|
class ImageBitmap {
|
|
[_width];
|
|
[_height];
|
|
[_bitmapData];
|
|
[_detached];
|
|
|
|
constructor() {
|
|
webidl.illegalConstructor();
|
|
}
|
|
|
|
get width() {
|
|
webidl.assertBranded(this, ImageBitmapPrototype);
|
|
if (this[_detached]) {
|
|
return 0;
|
|
}
|
|
|
|
return this[_width];
|
|
}
|
|
|
|
get height() {
|
|
webidl.assertBranded(this, ImageBitmapPrototype);
|
|
if (this[_detached]) {
|
|
return 0;
|
|
}
|
|
|
|
return this[_height];
|
|
}
|
|
|
|
close() {
|
|
webidl.assertBranded(this, ImageBitmapPrototype);
|
|
this[_detached] = true;
|
|
this[_bitmapData] = null;
|
|
}
|
|
|
|
[SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) {
|
|
return inspect(
|
|
createFilteredInspectProxy({
|
|
object: this,
|
|
evaluate: ObjectPrototypeIsPrototypeOf(ImageBitmapPrototype, this),
|
|
keys: [
|
|
"width",
|
|
"height",
|
|
],
|
|
}),
|
|
inspectOptions,
|
|
);
|
|
}
|
|
}
|
|
const ImageBitmapPrototype = ImageBitmap.prototype;
|
|
|
|
function createImageBitmap(
|
|
image,
|
|
sxOrOptions = undefined,
|
|
sy = undefined,
|
|
sw = undefined,
|
|
sh = undefined,
|
|
options = undefined,
|
|
) {
|
|
const prefix = "Failed to execute 'createImageBitmap'";
|
|
// Add the value when implementing to add support for ImageBitmapSource
|
|
const imageBitmapSources = [
|
|
"Blob",
|
|
"ImageData",
|
|
];
|
|
|
|
// Overload: createImageBitmap(image [, options ])
|
|
if (arguments.length < 3) {
|
|
options = webidl.converters["ImageBitmapOptions"](
|
|
sxOrOptions,
|
|
prefix,
|
|
"Argument 2",
|
|
);
|
|
} else {
|
|
// Overload: createImageBitmap(image, sx, sy, sw, sh [, options ])
|
|
sxOrOptions = webidl.converters["long"](sxOrOptions, prefix, "Argument 2");
|
|
sy = webidl.converters["long"](sy, prefix, "Argument 3");
|
|
sw = webidl.converters["long"](sw, prefix, "Argument 4");
|
|
sh = webidl.converters["long"](sh, prefix, "Argument 5");
|
|
options = webidl.converters["ImageBitmapOptions"](
|
|
options,
|
|
prefix,
|
|
"Argument 6",
|
|
);
|
|
|
|
// 1.
|
|
if (sw === 0) {
|
|
return PromiseReject(new RangeError("sw has to be greater than 0"));
|
|
}
|
|
|
|
if (sh === 0) {
|
|
return PromiseReject(new RangeError("sh has to be greater than 0"));
|
|
}
|
|
}
|
|
|
|
// 2.
|
|
if (options.resizeWidth === 0) {
|
|
return PromiseReject(
|
|
new DOMException(
|
|
"options.resizeWidth has to be greater than 0",
|
|
"InvalidStateError",
|
|
),
|
|
);
|
|
}
|
|
if (options.resizeHeight === 0) {
|
|
return PromiseReject(
|
|
new DOMException(
|
|
"options.resizeHeight has to be greater than 0",
|
|
"InvalidStateError",
|
|
),
|
|
);
|
|
}
|
|
|
|
const imageBitmap = webidl.createBranded(ImageBitmap);
|
|
|
|
// 3.
|
|
const isBlob = ObjectPrototypeIsPrototypeOf(BlobPrototype, image);
|
|
const isImageData = ObjectPrototypeIsPrototypeOf(ImageDataPrototype, image);
|
|
if (!isBlob && !isImageData) {
|
|
return PromiseReject(
|
|
new DOMException(
|
|
`${prefix}: The provided value for 'image' is not of type '(${
|
|
ArrayPrototypeJoin(imageBitmapSources, " or ")
|
|
})'.`,
|
|
"InvalidStateError",
|
|
),
|
|
);
|
|
}
|
|
|
|
// 4.
|
|
return (async () => {
|
|
//
|
|
// For performance reasons, the arguments passed to op are represented as numbers that don't need to be serialized.
|
|
//
|
|
|
|
let width = 0;
|
|
let height = 0;
|
|
// If the of image doesn't have a MIME type, mark it as 0.
|
|
let mimeType = 0;
|
|
let imageBitmapSource, buf;
|
|
if (isBlob) {
|
|
imageBitmapSource = 0;
|
|
buf = new Uint8Array(await image.arrayBuffer());
|
|
const mimeTypeString = sniffImage(image.type);
|
|
|
|
if (mimeTypeString === "image/png") {
|
|
mimeType = 1;
|
|
} else if (mimeTypeString === "image/jpeg") {
|
|
mimeType = 2;
|
|
} else if (mimeTypeString === "image/gif") {
|
|
mimeType = 3;
|
|
} else if (mimeTypeString === "image/bmp") {
|
|
mimeType = 4;
|
|
} else if (mimeTypeString === "image/x-icon") {
|
|
mimeType = 5;
|
|
} else if (mimeTypeString === "image/webp") {
|
|
mimeType = 6;
|
|
} else if (mimeTypeString === "") {
|
|
return PromiseReject(
|
|
new DOMException(
|
|
`The MIME type of source image is not specified.`,
|
|
"InvalidStateError",
|
|
),
|
|
);
|
|
} else {
|
|
return PromiseReject(
|
|
new DOMException(
|
|
`The MIME type ${mimeTypeString} of source image is not a supported format.`,
|
|
"InvalidStateError",
|
|
),
|
|
);
|
|
}
|
|
} else if (isImageData) {
|
|
width = image[_width];
|
|
height = image[_height];
|
|
imageBitmapSource = 1;
|
|
buf = new Uint8Array(TypedArrayPrototypeGetBuffer(image[_data]));
|
|
}
|
|
|
|
// If those options are not provided, assign 0 to mean undefined(None).
|
|
const _sx = typeof sxOrOptions === "number" ? sxOrOptions : 0;
|
|
const _sy = sy ?? 0;
|
|
const _sw = sw ?? 0;
|
|
const _sh = sh ?? 0;
|
|
|
|
// If those options are not provided, assign 0 to mean undefined(None).
|
|
const resizeWidth = options.resizeWidth ?? 0;
|
|
const resizeHeight = options.resizeHeight ?? 0;
|
|
|
|
// If the imageOrientation option is set "from-image" or not set, assign 0.
|
|
const imageOrientation = options.imageOrientation === "flipY" ? 1 : 0;
|
|
|
|
// If the premultiplyAlpha option is "default" or not set, assign 0.
|
|
let premultiplyAlpha = 0;
|
|
if (options.premultiplyAlpha === "premultiply") {
|
|
premultiplyAlpha = 1;
|
|
} else if (options.premultiplyAlpha === "none") {
|
|
premultiplyAlpha = 2;
|
|
}
|
|
|
|
// If the colorSpaceConversion option is "default" or not set, assign 0.
|
|
const colorSpaceConversion = options.colorSpaceConversion === "none"
|
|
? 1
|
|
: 0;
|
|
|
|
// If the resizeQuality option is "low" or not set, assign 0.
|
|
let resizeQuality = 0;
|
|
if (options.resizeQuality === "pixelated") {
|
|
resizeQuality = 1;
|
|
} else if (options.resizeQuality === "medium") {
|
|
resizeQuality = 2;
|
|
} else if (options.resizeQuality === "high") {
|
|
resizeQuality = 3;
|
|
}
|
|
|
|
const processedImage = op_create_image_bitmap(
|
|
buf,
|
|
width,
|
|
height,
|
|
_sx,
|
|
_sy,
|
|
_sw,
|
|
_sh,
|
|
imageOrientation,
|
|
premultiplyAlpha,
|
|
colorSpaceConversion,
|
|
resizeWidth,
|
|
resizeHeight,
|
|
resizeQuality,
|
|
imageBitmapSource,
|
|
mimeType,
|
|
);
|
|
imageBitmap[_bitmapData] = processedImage[0];
|
|
imageBitmap[_width] = processedImage[1];
|
|
imageBitmap[_height] = processedImage[2];
|
|
return imageBitmap;
|
|
})();
|
|
}
|
|
|
|
function getBitmapData(imageBitmap) {
|
|
return imageBitmap[_bitmapData];
|
|
}
|
|
|
|
internals.getBitmapData = getBitmapData;
|
|
|
|
export { _bitmapData, _detached, createImageBitmap, ImageBitmap };
|