taglib-wasm
Version:
TagLib for TypeScript platforms: Deno, Node.js, Bun, Electron, browsers, and Cloudflare Workers
121 lines (120 loc) • 3.84 kB
JavaScript
import { PICTURE_TYPE_VALUES } from "./types.js";
import { applyPictures, readPictures } from "./simple.js";
function pictureToDataURL(picture) {
const base64 = btoa(String.fromCharCode(...picture.data));
return `data:${picture.mimeType};base64,${base64}`;
}
function dataURLToPicture(dataURL, type = "FrontCover", description) {
const matches = dataURL.match(/^data:([^;]+);base64,(.+)$/);
if (!matches) {
throw new Error("Invalid data URL format");
}
const [, mimeType, base64] = matches;
const binaryString = atob(base64);
const data = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
data[i] = binaryString.charCodeAt(i);
}
return {
mimeType,
data,
type: typeof type === "string" ? PICTURE_TYPE_VALUES[type] : type,
description
};
}
async function setCoverArtFromCanvas(file, canvas, options = {}) {
const {
format = "image/jpeg",
quality = 0.92,
type = "FrontCover",
description = "Front Cover"
} = options;
const dataURL = canvas.toDataURL(format, quality);
const picture = dataURLToPicture(dataURL, type, description);
return applyPictures(file, [picture]);
}
async function canvasToPicture(canvas, options = {}) {
const {
format = "image/jpeg",
quality = 0.92,
type = "FrontCover",
description
} = options;
return new Promise((resolve, reject) => {
canvas.toBlob(
async (blob) => {
if (!blob) {
reject(new Error("Failed to convert canvas to blob"));
return;
}
const arrayBuffer = await blob.arrayBuffer();
const data = new Uint8Array(arrayBuffer);
resolve({
mimeType: format,
data,
type: typeof type === "string" ? PICTURE_TYPE_VALUES[type] : type,
description
});
},
format,
quality
);
});
}
async function imageFileToPicture(file, type = "FrontCover", description) {
const arrayBuffer = await file.arrayBuffer();
const data = new Uint8Array(arrayBuffer);
return {
mimeType: file.type,
data,
type: typeof type === "string" ? PICTURE_TYPE_VALUES[type] : type,
description: description || file.name
};
}
function displayPicture(picture, imgElement) {
if (imgElement.src.startsWith("blob:")) {
URL.revokeObjectURL(imgElement.src);
}
const blob = new Blob([picture.data], { type: picture.mimeType });
const objectURL = URL.createObjectURL(blob);
imgElement.src = objectURL;
imgElement.addEventListener("load", () => {
setTimeout(() => URL.revokeObjectURL(objectURL), 100);
}, { once: true });
}
function createPictureDownloadURL(picture, filename = "cover") {
const blob = new Blob([picture.data], { type: picture.mimeType });
return URL.createObjectURL(blob);
}
async function createPictureGallery(file, container, options = {}) {
const pictures = await readPictures(file);
container.innerHTML = "";
pictures.forEach((picture, index) => {
const wrapper = document.createElement("div");
wrapper.className = options.className || "picture-item";
const img = document.createElement("img");
displayPicture(picture, img);
img.alt = picture.description || `Picture ${index + 1}`;
if (options.onClick) {
img.style.cursor = "pointer";
img.addEventListener("click", () => options.onClick(picture, index));
}
wrapper.appendChild(img);
if (options.includeDescription && picture.description) {
const caption = document.createElement("p");
caption.textContent = picture.description;
wrapper.appendChild(caption);
}
container.appendChild(wrapper);
});
}
export {
canvasToPicture,
createPictureDownloadURL,
createPictureGallery,
dataURLToPicture,
displayPicture,
imageFileToPicture,
pictureToDataURL,
setCoverArtFromCanvas
};