mirror of
https://github.com/misskey-dev/misskey.git
synced 2024-12-28 18:48:31 +01:00
とりあえず出るようにした
This commit is contained in:
parent
47ef78afe4
commit
8f3241a6ae
2 changed files with 48 additions and 20 deletions
|
@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="$style.watermarkEditorInputRoot">
|
<div :class="$style.watermarkEditorInputRoot">
|
||||||
<div :class="$style.watermarkEditorPreviewRoot">
|
<div :class="$style.watermarkEditorPreviewRoot">
|
||||||
<MkLoading v-if="canvasLoading" :class="$style.watermarkEditorPreviewSpinner"/>
|
<MkLoading v-if="canvasLoading" :class="$style.watermarkEditorPreviewSpinner"/>
|
||||||
<canvas ref="canvas" :class="$style.watermarkEditorPreviewCanvas"></canvas>
|
<canvas ref="canvasEl" :class="$style.watermarkEditorPreviewCanvas"></canvas>
|
||||||
<div :class="$style.watermarkEditorPreviewWrapper">
|
<div :class="$style.watermarkEditorPreviewWrapper">
|
||||||
<div class="_acrylic" :class="$style.watermarkEditorPreviewTitle">{{ i18n.ts.preview }}</div>
|
<div class="_acrylic" :class="$style.watermarkEditorPreviewTitle">{{ i18n.ts.preview }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -37,12 +37,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { shallowRef, ref, computed } from 'vue';
|
import { shallowRef, ref, useTemplateRef, computed, onMounted } from 'vue';
|
||||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
import MkSwitch from '@/components/MkSwitch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
|
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
import { applyWatermark, WatermarkConfig } from '@/scripts/watermark.js';
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'ok'): void;
|
(ev: 'ok'): void;
|
||||||
|
@ -66,11 +67,25 @@ function save() {
|
||||||
|
|
||||||
//#region 設定
|
//#region 設定
|
||||||
const useWatermark = computed(defaultStore.makeGetterSetter('useWatermark'));
|
const useWatermark = computed(defaultStore.makeGetterSetter('useWatermark'));
|
||||||
const watermarkConfig = ref(defaultStore.state.watermarkConfig);
|
const watermarkConfig = ref<WatermarkConfig>(defaultStore.state.watermarkConfig ?? {
|
||||||
|
fileUrl: '/client-assets/default-watermark.png',
|
||||||
|
enlargement: 'contain',
|
||||||
|
opacity: 0.5,
|
||||||
|
anchor: 'bottom-right',
|
||||||
|
gravity: 'auto',
|
||||||
|
repeat: false,
|
||||||
|
__bypassMediaProxy: true,
|
||||||
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Canvasの制御
|
//#region Canvasの制御
|
||||||
const canvasLoading = ref(true);
|
const canvasLoading = ref(true);
|
||||||
|
const canvasEl = useTemplateRef('canvasEl');
|
||||||
|
onMounted(() => {
|
||||||
|
if (canvasEl.value) {
|
||||||
|
applyWatermark('/client-assets/hill.webp', canvasEl.value, watermarkConfig.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -3,37 +3,41 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
import { getProxiedImageUrl } from "@/scripts/media-proxy.js";
|
import { getProxiedImageUrl } from "@/scripts/media-proxy.js";
|
||||||
|
import { misskeyApi } from "@/scripts/misskey-api.js";
|
||||||
|
|
||||||
export type WatermarkConfig = {
|
export type WatermarkConfig = {
|
||||||
fileId: string | null;
|
fileId?: string;
|
||||||
fileUrl: string | null;
|
fileUrl?: string;
|
||||||
width: number | null;
|
width?: number;
|
||||||
height: number | null;
|
height?: number;
|
||||||
enlargement: 'scale-down' | 'contain' | 'cover' | 'crop' | 'pad';
|
enlargement: 'scale-down' | 'contain' | 'cover' | 'crop' | 'pad';
|
||||||
gravity: 'auto' | 'left' | 'right' | 'top' | 'bottom';
|
gravity: 'auto' | 'left' | 'right' | 'top' | 'bottom';
|
||||||
opacity: number;
|
opacity?: number;
|
||||||
repeat: true | false | 'x' | 'y';
|
repeat: true | false | 'x' | 'y';
|
||||||
anchor: 'center' | 'top' | 'left' | 'bottom' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
anchor: 'center' | 'top' | 'left' | 'bottom' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
||||||
offsetTop: number | null;
|
offsetTop?: number;
|
||||||
offsetLeft: number | null;
|
offsetLeft?: number;
|
||||||
offsetBottom: number | null;
|
offsetBottom?: number;
|
||||||
offsetRight: number | null;
|
offsetRight?: number;
|
||||||
backgroundColor: string | null;
|
backgroundColor?: string;
|
||||||
rotate: number | null;
|
rotate?: number;
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
__bypassMediaProxy?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ウォーターマークを適用してキャンバスに描画する
|
* ウォーターマークを適用してキャンバスに描画する
|
||||||
*
|
*
|
||||||
* @param img ウォーターマークを適用する画像(stringは画像URL。**プレビュー用途専用**)
|
* @param img ウォーターマークを適用する画像(stringは画像URL)
|
||||||
* @param el ウォーターマークを適用するキャンバス
|
* @param el ウォーターマークを適用するキャンバス
|
||||||
* @param config ウォーターマークの設定
|
* @param config ウォーターマークの設定
|
||||||
*/
|
*/
|
||||||
export function applyWatermark(img: string | Blob, el: HTMLCanvasElement, config: WatermarkConfig) {
|
export async function applyWatermark(img: string | Blob, el: HTMLCanvasElement, config: WatermarkConfig) {
|
||||||
const canvas = el;
|
const canvas = el;
|
||||||
const ctx = canvas.getContext('2d')!;
|
const ctx = canvas.getContext('2d')!;
|
||||||
const imgEl = new Image();
|
const imgEl = new Image();
|
||||||
imgEl.onload = () => {
|
imgEl.onload = async () => {
|
||||||
canvas.width = imgEl.width;
|
canvas.width = imgEl.width;
|
||||||
canvas.height = imgEl.height;
|
canvas.height = imgEl.height;
|
||||||
ctx.drawImage(imgEl, 0, 0);
|
ctx.drawImage(imgEl, 0, 0);
|
||||||
|
@ -42,7 +46,7 @@ export function applyWatermark(img: string | Blob, el: HTMLCanvasElement, config
|
||||||
watermark.onload = () => {
|
watermark.onload = () => {
|
||||||
const width = config.width || watermark.width;
|
const width = config.width || watermark.width;
|
||||||
const height = config.height || watermark.height;
|
const height = config.height || watermark.height;
|
||||||
ctx.globalAlpha = config.opacity;
|
ctx.globalAlpha = config.opacity ?? 1;
|
||||||
if (config.repeat !== false) {
|
if (config.repeat !== false) {
|
||||||
const resizedWatermark = document.createElement('canvas');
|
const resizedWatermark = document.createElement('canvas');
|
||||||
resizedWatermark.width = width;
|
resizedWatermark.width = width;
|
||||||
|
@ -90,11 +94,20 @@ export function applyWatermark(img: string | Blob, el: HTMLCanvasElement, config
|
||||||
ctx.drawImage(watermark, x, y, width, height);
|
ctx.drawImage(watermark, x, y, width, height);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
watermark.src = config.fileUrl;
|
|
||||||
|
let watermarkUrl: string;
|
||||||
|
if (config.fileUrl == null && config.fileId != null) {
|
||||||
|
const res = await misskeyApi('drive/files/show', { fileId: config.fileId });
|
||||||
|
watermarkUrl = res.url;
|
||||||
|
} else {
|
||||||
|
watermarkUrl = config.fileUrl!;
|
||||||
|
}
|
||||||
|
|
||||||
|
watermark.src = config.__bypassMediaProxy ? config.fileUrl : getProxiedImageUrl(watermarkUrl, undefined, true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (typeof img === 'string') {
|
if (typeof img === 'string') {
|
||||||
imgEl.src = getProxiedImageUrl(img, undefined, true);
|
imgEl.src = img;
|
||||||
} else {
|
} else {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
|
|
Loading…
Reference in a new issue