promiseがコールバックを待たないのを修正

This commit is contained in:
kakkokari-gtyih 2024-12-17 18:50:36 +09:00
parent 1a3e96bf7f
commit 88e0b522ea

View file

@ -113,146 +113,151 @@ export function canPreview(config: Partial<WatermarkConfig | WatermarkUserConfig
* @param el * @param el
* @param config * @param config
*/ */
export async function applyWatermark(img: string | Blob, el: HTMLCanvasElement, config: WatermarkConfig | null) { export function applyWatermark(img: string | Blob, el: HTMLCanvasElement | OffscreenCanvas, config: WatermarkConfig | null) {
const canvas = el; return new Promise<void>(async (resolve) => {
const ctx = canvas.getContext('2d')!; const canvas = el;
const imgEl = new Image(); const ctx = canvas.getContext('2d')!;
imgEl.onload = async () => { const imgEl = new Image();
canvas.width = imgEl.width; imgEl.onload = async () => {
canvas.height = imgEl.height; canvas.width = imgEl.width;
ctx.drawImage(imgEl, 0, 0); canvas.height = imgEl.height;
ctx.drawImage(imgEl, 0, 0);
if (config != null) { if (config != null) {
if (config.fileUrl) { if (config.fileUrl) {
const watermark = new Image(); const watermark = new Image();
watermark.onload = () => { watermark.onload = () => {
const canvasAspectRatio = canvas.width / canvas.height; // 横長は1より大きい const canvasAspectRatio = canvas.width / canvas.height; // 横長は1より大きい
const watermarkAspectRatio = watermark.width / watermark.height; // 横長は1より大きい const watermarkAspectRatio = watermark.width / watermark.height; // 横長は1より大きい
const { width, height } = (() => { const { width, height } = (() => {
const desiredWidth = canvas.width * (config.sizeRatio ?? 1); const desiredWidth = canvas.width * (config.sizeRatio ?? 1);
const desiredHeight = canvas.height * (config.sizeRatio ?? 1); const desiredHeight = canvas.height * (config.sizeRatio ?? 1);
if ( if (
(watermarkAspectRatio > 1 && canvasAspectRatio > 1) || // 両方横長 (watermarkAspectRatio > 1 && canvasAspectRatio > 1) || // 両方横長
(watermarkAspectRatio < 1 && canvasAspectRatio < 1) // 両方縦長 (watermarkAspectRatio < 1 && canvasAspectRatio < 1) // 両方縦長
) { ) {
// 横幅を基準にウォーターマークのサイズを決定 // 横幅を基準にウォーターマークのサイズを決定
return { return {
width: desiredWidth, width: desiredWidth,
height: desiredWidth / watermarkAspectRatio, height: desiredWidth / watermarkAspectRatio,
}; };
} else {
// 縦幅を基準にウォーターマークのサイズを決定
return {
width: desiredHeight * watermarkAspectRatio,
height: desiredHeight,
};
}
})();
ctx.globalAlpha = config.opacity ?? 1;
if (config.repeat) {
// 余白をもたせた状態のウォーターマークを作成しておく(それをパターン繰り返しする)
const resizedWatermark = document.createElement('canvas');
resizedWatermark.width = width + (config.padding ? (config.padding.left ?? 0) + (config.padding.right ?? 0) : 0);
resizedWatermark.height = height + (config.padding ? (config.padding.top ?? 0) + (config.padding.bottom ?? 0) : 0);
const resizedCtx = resizedWatermark.getContext('2d')!;
resizedCtx.drawImage(
watermark,
(config.padding ? config.padding.left ?? 0 : 0),
(config.padding ? config.padding.top ?? 0 : 0),
width,
height
);
const pattern = ctx.createPattern(resizedWatermark, 'repeat');
if (pattern) {
ctx.fillStyle = pattern;
if (config.rotate != null && config.rotate !== 0) {
const rotateRad = config.rotate * Math.PI / 180;
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(rotateRad);
ctx.translate(-canvas.width / 2, -canvas.height / 2);
const rotatedWidth = Math.abs(canvas.width * Math.cos(rotateRad)) + Math.abs(canvas.height * Math.sin(rotateRad));
const rotatedHeight = Math.abs(canvas.width * Math.sin(rotateRad)) + Math.abs(canvas.height * Math.cos(rotateRad));
const x = Math.abs(rotatedWidth - canvas.width) / -2;
const y = Math.abs(rotatedHeight - canvas.height) / -2;
ctx.fillRect(x, y, rotatedWidth, rotatedHeight);
} else { } else {
ctx.fillRect(0, 0, canvas.width, canvas.height); // 縦幅を基準にウォーターマークのサイズを決定
} return {
} width: desiredHeight * watermarkAspectRatio,
} else { height: desiredHeight,
const x = (() => { };
switch (config.anchor) {
case 'center':
case 'top':
case 'bottom':
return (canvas.width - width) / 2;
case 'left':
case 'top-left':
case 'bottom-left':
return 0 + (config.padding ? config.padding.left ?? 0 : 0);
case 'right':
case 'top-right':
case 'bottom-right':
return canvas.width - width - (config.padding ? config.padding.right ?? 0 : 0);
} }
})(); })();
const y = (() => { ctx.globalAlpha = config.opacity ?? 1;
let rotateY = 0; // 回転によるY座標の補正
if (config.rotate != null && config.rotate !== 0 && !config.noBoundingBoxExpansion) { if (config.repeat) {
// 余白をもたせた状態のウォーターマークを作成しておく(それをパターン繰り返しする)
const resizedWatermark = document.createElement('canvas');
resizedWatermark.width = width + (config.padding ? (config.padding.left ?? 0) + (config.padding.right ?? 0) : 0);
resizedWatermark.height = height + (config.padding ? (config.padding.top ?? 0) + (config.padding.bottom ?? 0) : 0);
const resizedCtx = resizedWatermark.getContext('2d')!;
resizedCtx.drawImage(
watermark,
(config.padding ? config.padding.left ?? 0 : 0),
(config.padding ? config.padding.top ?? 0 : 0),
width,
height
);
const pattern = ctx.createPattern(resizedWatermark, 'repeat');
if (pattern) {
ctx.fillStyle = pattern;
if (config.rotate != null && config.rotate !== 0) {
const rotateRad = config.rotate * Math.PI / 180;
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(rotateRad);
ctx.translate(-canvas.width / 2, -canvas.height / 2);
const rotatedWidth = Math.abs(canvas.width * Math.cos(rotateRad)) + Math.abs(canvas.height * Math.sin(rotateRad));
const rotatedHeight = Math.abs(canvas.width * Math.sin(rotateRad)) + Math.abs(canvas.height * Math.cos(rotateRad));
const x = Math.abs(rotatedWidth - canvas.width) / -2;
const y = Math.abs(rotatedHeight - canvas.height) / -2;
ctx.fillRect(x, y, rotatedWidth, rotatedHeight);
} else {
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
}
} else {
const x = (() => {
switch (config.anchor) {
case 'center':
case 'top':
case 'bottom':
return (canvas.width - width) / 2;
case 'left':
case 'top-left':
case 'bottom-left':
return 0 + (config.padding ? config.padding.left ?? 0 : 0);
case 'right':
case 'top-right':
case 'bottom-right':
return canvas.width - width - (config.padding ? config.padding.right ?? 0 : 0);
}
})();
const y = (() => {
let rotateY = 0; // 回転によるY座標の補正
if (config.rotate != null && config.rotate !== 0 && !config.noBoundingBoxExpansion) {
const rotateRad = config.rotate * Math.PI / 180;
rotateY = Math.abs(Math.abs(width * Math.sin(rotateRad)) + Math.abs(height * Math.cos(rotateRad)) - height) / 2;
}
switch (config.anchor) {
case 'center':
case 'left':
case 'right':
return (canvas.height - height) / 2;
case 'top':
case 'top-left':
case 'top-right':
return rotateY + (config.padding ? config.padding.top ?? 0 : 0);
case 'bottom':
case 'bottom-left':
case 'bottom-right':
return canvas.height - height - (config.padding ? config.padding.bottom ?? 0 : 0) - rotateY;
}
})();
if (config.rotate) {
const rotateRad = config.rotate * Math.PI / 180; const rotateRad = config.rotate * Math.PI / 180;
rotateY = Math.abs(Math.abs(width * Math.sin(rotateRad)) + Math.abs(height * Math.cos(rotateRad)) - height) / 2; ctx.translate(x + width / 2, y + height / 2);
ctx.rotate(rotateRad);
ctx.translate(-x - width / 2, -y - height / 2);
} }
ctx.drawImage(watermark, x, y, width, height);
switch (config.anchor) {
case 'center':
case 'left':
case 'right':
return (canvas.height - height) / 2;
case 'top':
case 'top-left':
case 'top-right':
return rotateY + (config.padding ? config.padding.top ?? 0 : 0);
case 'bottom':
case 'bottom-left':
case 'bottom-right':
return canvas.height - height - (config.padding ? config.padding.bottom ?? 0 : 0) - rotateY;
}
})();
if (config.rotate) {
const rotateRad = config.rotate * Math.PI / 180;
ctx.translate(x + width / 2, y + height / 2);
ctx.rotate(rotateRad);
ctx.translate(-x - width / 2, -y - height / 2);
} }
ctx.drawImage(watermark, x, y, width, height);
resolve();
};
let watermarkUrl: string;
if (config.fileUrl == null && config.fileId != null) {
const res = await misskeyApi('drive/files/show', { fileId: config.fileId });
watermarkUrl = res.url;
// 抜けてたら保存
defaultStore.set('watermarkConfig', { ...config, fileUrl: watermarkUrl });
} else {
watermarkUrl = config.fileUrl!;
} }
};
let watermarkUrl: string; watermark.src = config.__bypassMediaProxy ? config.fileUrl : getProxiedImageUrl(watermarkUrl, undefined, true);
if (config.fileUrl == null && config.fileId != null) {
const res = await misskeyApi('drive/files/show', { fileId: config.fileId });
watermarkUrl = res.url;
// 抜けてたら保存
defaultStore.set('watermarkConfig', { ...config, fileUrl: watermarkUrl });
} else {
watermarkUrl = config.fileUrl!;
} }
watermark.src = config.__bypassMediaProxy ? config.fileUrl : getProxiedImageUrl(watermarkUrl, undefined, true);
} }
};
if (typeof img === 'string') {
imgEl.src = img;
} else {
imgEl.src = URL.createObjectURL(img);
} }
}; });
if (typeof img === 'string') {
imgEl.src = img;
} else {
imgEl.src = URL.createObjectURL(img);
}
} }
/** /**
@ -262,12 +267,8 @@ export async function applyWatermark(img: string | Blob, el: HTMLCanvasElement,
* @param config * @param config
* @returns Blob * @returns Blob
*/ */
export function getWatermarkAppliedImage(img: Blob, config: WatermarkConfig): Promise<Blob> { export async function getWatermarkAppliedImage(img: Blob, config: WatermarkConfig): Promise<Blob> {
const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas');
applyWatermark(img, canvas, config); await applyWatermark(img, canvas, config);
return new Promise<Blob>(resolve => { return new Promise(resolve => canvas.toBlob(blob => resolve(blob!)));
canvas.toBlob(blob => {
resolve(blob!);
});
});
} }