This commit is contained in:
syuilo 2025-05-28 09:44:09 +09:00
parent e3aae009b4
commit cd296d60d8
3 changed files with 78 additions and 22 deletions

View File

@ -5,10 +5,6 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div :class="$style.root" class="_gaps">
<div>
<MkButton inline rounded primary @click="chooseFile">{{ i18n.ts.selectFile }}</MkButton>
</div>
<template v-if="layer.type === 'text'">
<MkInput v-model="layer.text">
<template #label>{{ i18n.ts._watermarkEditor.text }}</template>
@ -42,6 +38,41 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #label>{{ i18n.ts._watermarkEditor.opacity }}</template>
</MkRange>
<MkSwitch v-model="layer.repeat">
<template #label>{{ i18n.ts._watermarkEditor.repeat }}</template>
</MkSwitch>
</template>
<template v-else-if="layer.type === 'image'">
<MkButton inline rounded primary @click="chooseFile">{{ i18n.ts.selectFile }}</MkButton>
<FormSlot>
<template #label>{{ i18n.ts._watermarkEditor.position }}</template>
<MkPositionSelector
v-model:x="layer.alignX"
v-model:y="layer.alignY"
></MkPositionSelector>
</FormSlot>
<MkRange
v-model="layer.scale"
:min="0"
:max="1"
:step="0.01"
continuousUpdate
>
<template #label>{{ i18n.ts._watermarkEditor.scale }}</template>
</MkRange>
<MkRange
v-model="layer.opacity"
:min="0"
:max="1"
:step="0.01"
continuousUpdate
>
<template #label>{{ i18n.ts._watermarkEditor.opacity }}</template>
</MkRange>
<MkSwitch v-model="layer.repeat">
<template #label>{{ i18n.ts._watermarkEditor.repeat }}</template>
</MkSwitch>
@ -84,14 +115,7 @@ onMounted(async () => {
});
function chooseFile(ev: MouseEvent) {
selectFile({
anchorElement: ev.currentTarget ?? ev.target,
multiple: false,
label: i18n.ts.selectFile,
features: {
watermark: false,
},
}).then((file) => {
selectFile(ev.currentTarget ?? ev.target, i18n.ts.selectFile).then((file) => {
if (!file.type.startsWith('image')) {
os.alert({
type: 'warning',
@ -101,9 +125,8 @@ function chooseFile(ev: MouseEvent) {
return;
}
fileId.value = file.id;
fileUrl.value = file.url;
fileName.value = file.name;
layer.value.imageId = file.id;
layer.value.imageUrl = file.url;
driveFileError.value = false;
});
}

View File

@ -97,6 +97,32 @@ function cancel() {
}
const type = ref(preset.layers[0].type);
watch(type, () => {
if (type.value === 'text') {
preset.layers = [{
id: uuid(),
type: type.value,
text: `(c) @${$i.username}`,
alignX: 'right',
alignY: 'bottom',
scale: 0.3,
opacity: 0.75,
repeat: false,
}];
} else if (type.value === 'image') {
preset.layers = [{
id: uuid(),
type: type.value,
imageId: null,
imageUrl: null,
alignX: 'right',
alignY: 'bottom',
scale: 0.3,
opacity: 0.75,
repeat: false,
}];
}
});
watch(preset, async (newValue, oldValue) => {
if (renderer != null) {

View File

@ -68,11 +68,11 @@ type WatermarkerTextLayer = {
opacity: number;
};
export type WatermarkerImageLayer = {
type WatermarkerImageLayer = {
id: string;
type: 'image';
imageUrl: string;
imageId: string;
imageUrl: string | null;
imageId: string | null;
repeat: boolean;
scale: number;
alignX: 'left' | 'center' | 'right';
@ -234,10 +234,17 @@ export class Watermarker {
img.src = layer.imageUrl;
});
const texture = this.createTexture();
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, this.originalImageTexture);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, image.width, image.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, image);
gl.bindTexture(gl.TEXTURE_2D, null);
this.bakedTextures.set(layer.id, {
texture: texture,
width: image.width,
height: image.height,
});
} else if (layer.type === 'text') {
const measureCtx = window.document.createElement('canvas').getContext('2d')!;
measureCtx.canvas.width = this.renderWidth;
@ -323,7 +330,7 @@ export class Watermarker {
return shaderProgram;
}
private renderTextLayer(layer: WatermarkerTextLayer) {
private renderTextOrImageLayer(layer: WatermarkerTextLayer | WatermarkerImageLayer) {
const gl = this.gl;
if (gl == null) {
throw new Error('gl is not initialized');
@ -385,9 +392,9 @@ export class Watermarker {
private renderLayer(layer: WatermarkerLayer) {
if (layer.type === 'image') {
this.renderImageLayer(layer);
this.renderTextOrImageLayer(layer);
} else if (layer.type === 'text') {
this.renderTextLayer(layer);
this.renderTextOrImageLayer(layer);
}
}