u
This commit is contained in:
25
src/utils/pasteImage.js
Normal file
25
src/utils/pasteImage.js
Normal file
@@ -0,0 +1,25 @@
|
||||
export async function readClipboardImage() {
|
||||
const items = await navigator.clipboard.read();
|
||||
for (const item of items) {
|
||||
for (const type of item.types) {
|
||||
if (type.startsWith('image/')) {
|
||||
return item.getType(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try clipboard image first; run onMissing when none found or clipboard unavailable.
|
||||
*/
|
||||
export async function pasteImageOrFallback(onMissing) {
|
||||
try {
|
||||
const image = await readClipboardImage();
|
||||
if (image) return image;
|
||||
} catch {
|
||||
// Clipboard API unavailable or denied.
|
||||
}
|
||||
onMissing();
|
||||
return null;
|
||||
}
|
||||
61
src/utils/prepareArticlePhoto.js
Normal file
61
src/utils/prepareArticlePhoto.js
Normal file
@@ -0,0 +1,61 @@
|
||||
const MAX_EDGE = 1000;
|
||||
const AVIF_MIME = 'image/avif';
|
||||
const AVIF_QUALITY = 0.8;
|
||||
|
||||
function scaledDimensions(width, height) {
|
||||
const scale = Math.min(1, MAX_EDGE / width, MAX_EDGE / height);
|
||||
return {
|
||||
width: Math.round(width * scale),
|
||||
height: Math.round(height * scale),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize to fit within 1000×1000 (aspect ratio kept, no upscale) and encode as AVIF.
|
||||
* @param {Blob|File} input
|
||||
* @returns {Promise<File>}
|
||||
*/
|
||||
export async function prepareArticlePhoto(input) {
|
||||
if (!(input instanceof Blob)) {
|
||||
throw new Error('Kein Bild.');
|
||||
}
|
||||
if (!input.type.startsWith('image/')) {
|
||||
throw new Error('Kein Bild.');
|
||||
}
|
||||
|
||||
const bitmap = await createImageBitmap(input);
|
||||
try {
|
||||
const { width, height } = scaledDimensions(bitmap.width, bitmap.height);
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) {
|
||||
throw new Error('Canvas nicht verfügbar.');
|
||||
}
|
||||
ctx.drawImage(bitmap, 0, 0, width, height);
|
||||
|
||||
const avifBlob = await new Promise((resolve, reject) => {
|
||||
canvas.toBlob(
|
||||
(blob) => {
|
||||
if (!blob || blob.type !== AVIF_MIME) {
|
||||
reject(new Error('AVIF wird von diesem Browser nicht unterstützt.'));
|
||||
return;
|
||||
}
|
||||
resolve(blob);
|
||||
},
|
||||
AVIF_MIME,
|
||||
AVIF_QUALITY,
|
||||
);
|
||||
});
|
||||
|
||||
const baseName = input instanceof File && input.name
|
||||
? input.name.replace(/\.[^.]+$/, '')
|
||||
: 'photo';
|
||||
|
||||
return new File([avifBlob], `${baseName}.avif`, { type: AVIF_MIME });
|
||||
} finally {
|
||||
bitmap.close();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user