diff --git a/locales/index.d.ts b/locales/index.d.ts index 2d5a5c18bb..61ba015e04 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -10690,6 +10690,14 @@ export interface Locale extends ILocale { * 余白 */ "padding": string; + /** + * 回転した分の面積を確保する + */ + "preserveBoundingRect": string; + /** + * 通常はオンで問題ありません。ウォーターマークを回転させた際に余白が不自然になった場合はオフにしてみてください。 + */ + "preserveBoundingRectDescription": string; }; } declare const locales: { diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 3bfb4de4f6..1abb285d33 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2850,3 +2850,5 @@ _watermarkEditor: repeatSetting: "描画モード" repeat: "全体を埋め尽くす" padding: "余白" + preserveBoundingRect: "回転した分の面積を確保する" + preserveBoundingRectDescription: "通常はオンで問題ありません。ウォーターマークを回転させた際に余白が不自然になった場合はオフにしてみてください。" diff --git a/packages/frontend/src/components/MkWatermarkEditorDialog.vue b/packages/frontend/src/components/MkWatermarkEditorDialog.vue index acc0a9ca16..30b73245cd 100644 --- a/packages/frontend/src/components/MkWatermarkEditorDialog.vue +++ b/packages/frontend/src/components/MkWatermarkEditorDialog.vue @@ -87,6 +87,11 @@ SPDX-License-Identifier: AGPL-3.0-only + + + + + @@ -161,6 +166,10 @@ const rotate = computed({ get: () => watermarkConfig.value?.rotate ?? 15, set: (v) => watermarkConfig.value = { ...watermarkConfig.value, rotate: v }, }); +const preserveBoundingRect = computed({ + get: () => !('noBoundingBoxExpansion' in watermarkConfig.value ? watermarkConfig.value?.noBoundingBoxExpansion ?? false : false), + set: (v) => watermarkConfig.value = { ...watermarkConfig.value, noBoundingBoxExpansion: !v }, +}); function setPadding(pos: 'top' | 'left' | 'right' | 'bottom', val: number) { const padding = { diff --git a/packages/frontend/src/scripts/watermark.ts b/packages/frontend/src/scripts/watermark.ts index d840786fc4..101007ce92 100644 --- a/packages/frontend/src/scripts/watermark.ts +++ b/packages/frontend/src/scripts/watermark.ts @@ -4,6 +4,7 @@ */ import { getProxiedImageUrl } from "@/scripts/media-proxy.js"; import { misskeyApi } from "@/scripts/misskey-api.js"; +import { defaultStore } from "@/store.js"; export const watermarkAnchor = [ 'top-left', @@ -45,6 +46,8 @@ export type WatermarkConfig = { repeat?: false; /** 画像の始祖点 */ anchor: WatermarkAnchor; + /** 回転の際に領域を自動で拡張するかどうか */ + noBoundingBoxExpansion?: boolean; } | { /** 繰り返し */ repeat: true; @@ -54,7 +57,11 @@ export type WatermarkConfig = { * プレビューに必要な値が全部揃っているかどうかを判定する */ export function canPreview(config: Partial | null): config is WatermarkConfig { - return config != null && (config.fileUrl != null || config.fileId != null); + return ( + config != null && + (config.fileUrl != null || config.fileId != null) && + ((config.repeat !== true && 'anchor' in config && config.anchor != null) || (config.repeat === true)) + ); } /** @@ -155,7 +162,7 @@ export async function applyWatermark(img: string | Blob, el: HTMLCanvasElement, const y = (() => { let rotateY = 0; // 回転によるY座標の補正 - if (config.rotate) { + 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; } @@ -189,6 +196,8 @@ export async function applyWatermark(img: string | Blob, el: HTMLCanvasElement, 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!; }