HEIF support

This commit is contained in:
Dustin Brett 2024-03-01 20:24:09 -08:00
parent 325047b681
commit a65ebb0fc0
9 changed files with 107 additions and 0 deletions

View File

@ -150,6 +150,7 @@
### Photos ### Photos
- [Supported Formats](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#supported_image_formats) - [Supported Formats](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#supported_image_formats)
- [HEIF](https://github.com/catdad-experiments/libheif-js) (**_.heic, .heif_**)
- [JPEG XL](https://github.com/niutech/jxl.js) (**_.jxl_**) - [JPEG XL](https://github.com/niutech/jxl.js) (**_.jxl_**)
- [QOI](https://gist.github.com/nicolaslegland/f0577cb49b1e56b729a2c0fc0aa151ba) (**_.qoi_**) - [QOI](https://gist.github.com/nicolaslegland/f0577cb49b1e56b729a2c0fc0aa151ba) (**_.qoi_**)
- [TIFF](https://github.com/photopea/UTIF.js) (**_.tif, .tiff_**) - [TIFF](https://github.com/photopea/UTIF.js) (**_.tif, .tiff_**)

View File

@ -17,11 +17,13 @@ import { useViewport } from "contexts/viewport";
import useDoubleClick from "hooks/useDoubleClick"; import useDoubleClick from "hooks/useDoubleClick";
import Button from "styles/common/Button"; import Button from "styles/common/Button";
import { import {
HEIF_IMAGE_FORMATS,
HIGH_PRIORITY_ELEMENT, HIGH_PRIORITY_ELEMENT,
IMAGE_FILE_EXTENSIONS, IMAGE_FILE_EXTENSIONS,
TIFF_IMAGE_FORMATS, TIFF_IMAGE_FORMATS,
} from "utils/constants"; } from "utils/constants";
import { import {
decodeHeic,
decodeJxl, decodeJxl,
getExtension, getExtension,
haltEvent, haltEvent,
@ -62,6 +64,8 @@ const Photos: FC<ComponentProcessProps> = ({ id }) => {
const { decodeQoi } = await import("components/apps/Photos/qoi"); const { decodeQoi } = await import("components/apps/Photos/qoi");
fileContents = decodeQoi(fileContents); fileContents = decodeQoi(fileContents);
} else if (HEIF_IMAGE_FORMATS.has(ext)) {
fileContents = await decodeHeic(fileContents);
} else if (TIFF_IMAGE_FORMATS.has(ext)) { } else if (TIFF_IMAGE_FORMATS.has(ext)) {
fileContents = (await import("utif")) fileContents = (await import("utif"))
.bufferToURI(fileContents) .bufferToURI(fileContents)

View File

@ -18,6 +18,7 @@ import {
FOLDER_BACK_ICON, FOLDER_BACK_ICON,
FOLDER_FRONT_ICON, FOLDER_FRONT_ICON,
FOLDER_ICON, FOLDER_ICON,
HEIF_IMAGE_FORMATS,
ICON_CACHE, ICON_CACHE,
ICON_CACHE_EXTENSION, ICON_CACHE_EXTENSION,
ICON_GIF_FPS, ICON_GIF_FPS,
@ -45,6 +46,7 @@ import {
blobToBase64, blobToBase64,
bufferToUrl, bufferToUrl,
cleanUpBufferUrl, cleanUpBufferUrl,
decodeHeic,
decodeJxl, decodeJxl,
getExtension, getExtension,
getGifJs, getGifJs,
@ -785,6 +787,18 @@ export const getInfoWithExtension = (
} }
}) })
); );
} else if (HEIF_IMAGE_FORMATS.has(extension)) {
getInfoByFileExtension(PHOTO_ICON, (signal) =>
fs.readFile(path, async (error, contents = Buffer.from("")) => {
if (!error && contents.length > 0 && !signal.aborted) {
const icon = await decodeHeic(contents);
if (icon && !signal.aborted) {
getInfoByFileExtension(imageToBufferUrl(path, icon));
}
}
})
);
} else if (IMAGE_FILE_EXTENSIONS.has(extension)) { } else if (IMAGE_FILE_EXTENSIONS.has(extension)) {
getInfoByFileExtension(PHOTO_ICON, (signal) => getInfoByFileExtension(PHOTO_ICON, (signal) =>
fs.readFile(path, (error, contents = Buffer.from("")) => { fs.readFile(path, (error, contents = Buffer.from("")) => {

View File

@ -56,6 +56,7 @@
"idb": "^8.0.0", "idb": "^8.0.0",
"ini": "^4.1.1", "ini": "^4.1.1",
"isomorphic-git": "^1.25.6", "isomorphic-git": "^1.25.6",
"libheif-js": "^1.17.1",
"mediainfo.js": "^0.2.1", "mediainfo.js": "^0.2.1",
"minimist": "^1.2.8", "minimist": "^1.2.8",
"multiformats": "^13.1.0", "multiformats": "^13.1.0",

View File

@ -46,6 +46,7 @@ This project is greatly augmented by code from the open source community. Thank
- [Matrix](https://github.com/Rezmason/matrix) - [Matrix](https://github.com/Rezmason/matrix)
- [QOI Decoder](https://gist.github.com/nicolaslegland/f0577cb49b1e56b729a2c0fc0aa151ba) - [QOI Decoder](https://gist.github.com/nicolaslegland/f0577cb49b1e56b729a2c0fc0aa151ba)
- [jxl.js](https://github.com/niutech/jxl.js) - [jxl.js](https://github.com/niutech/jxl.js)
- [libheif-js](https://github.com/catdad-experiments/libheif-js)
- [fix-webm-duration](https://github.com/yusitnikov/fix-webm-duration) - [fix-webm-duration](https://github.com/yusitnikov/fix-webm-duration)
- [UAParser.js](https://github.com/faisalman/ua-parser-js) - [UAParser.js](https://github.com/faisalman/ua-parser-js)
- [Web Stable Diffusion](https://github.com/mlc-ai/web-stable-diffusion) - [Web Stable Diffusion](https://github.com/mlc-ai/web-stable-diffusion)

File diff suppressed because one or more lines are too long

View File

@ -77,6 +77,15 @@ export const LIST_VIEW_ANIMATION = {
transition: { duration: 0.15 }, transition: { duration: 0.15 },
}; };
export const HEIF_IMAGE_FORMATS = new Set([
".heic",
".heics",
".heif",
".heifs",
".avci",
".avcs",
]);
export const TIFF_IMAGE_FORMATS = new Set([ export const TIFF_IMAGE_FORMATS = new Set([
".cr2", ".cr2",
".dng", ".dng",
@ -88,6 +97,7 @@ export const TIFF_IMAGE_FORMATS = new Set([
export const CLIPBOARD_FILE_EXTENSIONS = new Set([".jpeg", ".jpg", ".png"]); export const CLIPBOARD_FILE_EXTENSIONS = new Set([".jpeg", ".jpg", ".png"]);
export const IMAGE_FILE_EXTENSIONS = new Set([ export const IMAGE_FILE_EXTENSIONS = new Set([
...HEIF_IMAGE_FORMATS,
...TIFF_IMAGE_FORMATS, ...TIFF_IMAGE_FORMATS,
".ani", ".ani",
".apng", ".apng",
@ -112,6 +122,7 @@ export const IMAGE_FILE_EXTENSIONS = new Set([
]); ]);
export const UNSUPPORTED_BACKGROUND_EXTENSIONS = new Set([ export const UNSUPPORTED_BACKGROUND_EXTENSIONS = new Set([
...HEIF_IMAGE_FORMATS,
...TIFF_IMAGE_FORMATS, ...TIFF_IMAGE_FORMATS,
".jxl", ".jxl",
".qoi", ".qoi",

View File

@ -358,6 +358,47 @@ export const getHtmlToImage = async (): Promise<
return htmlToImage; return htmlToImage;
}; };
type LibHeif = {
libheif: () => {
HeifDecoder: new () => {
decode: (file: Buffer) => {
display: (
imageData: ImageData,
callback: (data: ImageData) => void
) => void;
get_height: () => number;
get_width: () => number;
}[];
};
ready: Promise<void>;
};
};
export const decodeHeic = async (image: Buffer): Promise<Buffer> => {
await loadFiles(["/System/libheif/libheif-bundle.js"], false, true);
const { libheif } = window as unknown as Window & LibHeif;
const { HeifDecoder, ready } = libheif();
await ready;
const [decodedImage] = new HeifDecoder().decode(image);
const width = decodedImage.get_width();
const height = decodedImage.get_height();
const { data } = await new Promise<ImageData>((resolve) => {
decodedImage.display(
{
data: new Uint8ClampedArray(width * height * 4),
height,
width,
} as ImageData,
resolve
);
});
return imgDataToBuffer(new ImageData(data, width, height));
};
export const pxToNum = (value: number | string = 0): number => export const pxToNum = (value: number | string = 0): number =>
typeof value === "number" ? value : Number.parseFloat(value); typeof value === "number" ? value : Number.parseFloat(value);

View File

@ -4942,6 +4942,11 @@ levn@^0.4.1:
prelude-ls "^1.2.1" prelude-ls "^1.2.1"
type-check "~0.4.0" type-check "~0.4.0"
libheif-js@^1.17.1:
version "1.17.1"
resolved "https://registry.yarnpkg.com/libheif-js/-/libheif-js-1.17.1.tgz#7772cc5a31098df0354f0fadb49a939030765acd"
integrity sha512-g9wBm/CasGZMjmH3B2sD9+AO7Y5+79F0oPS+sdAulSxQeYeCeiTIP+lDqvlPofD+y76wvfVtotKZ8AuvZQnWgg==
lie@~3.3.0: lie@~3.3.0:
version "3.3.0" version "3.3.0"
resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a"