This commit is contained in:
syuilo 2025-10-30 20:45:46 +09:00
parent 400c7cc408
commit f7800ecda1
8 changed files with 55 additions and 31 deletions

View File

@ -94,7 +94,7 @@ const layers = reactive<ImageEffectorLayer[]>([]);
watch(layers, async () => {
if (renderer != null) {
renderer.setLayers(layers);
renderer.setLayersAndRender(layers);
}
}, { deep: true });
@ -167,9 +167,7 @@ onMounted(async () => {
fxs: FXS,
});
await renderer.setLayers(layers);
renderer.render();
await renderer.setLayersAndRender(layers);
closeWaiting();
});
@ -208,11 +206,10 @@ const enabled = ref(true);
watch(enabled, () => {
if (renderer != null) {
if (enabled.value) {
renderer.setLayers(layers);
renderer.setLayersAndRender(layers);
} else {
renderer.setLayers([]);
renderer.setLayersAndRender([]);
}
renderer.render();
}
});

View File

@ -25,6 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="props.image == null" class="_acrylic" :class="$style.previewControls">
<button class="_button" :class="[$style.previewControlsButton, sampleImageType === '3_2' ? $style.active : null]" @click="sampleImageType = '3_2'"><i class="ti ti-crop-landscape"></i></button>
<button class="_button" :class="[$style.previewControlsButton, sampleImageType === '2_3' ? $style.active : null]" @click="sampleImageType = '2_3'"><i class="ti ti-crop-portrait"></i></button>
<button class="_button" :class="[$style.previewControlsButton]" @click="choiceImage"><i class="ti ti-upload"></i></button>
</div>
</div>
</div>
@ -164,6 +165,7 @@ const sampleImage_2_3_loading = new Promise<void>(resolve => {
const sampleImageType = ref(props.image != null ? 'provided' : '3_2');
watch(sampleImageType, async () => {
if (sampleImageType.value === 'provided') return;
if (renderer != null) {
renderer.destroy(false);
renderer = null;
@ -171,6 +173,20 @@ watch(sampleImageType, async () => {
}
});
let imageFile = props.image;
async function choiceImage() {
const files = await os.chooseFileFromPc({ multiple: false });
if (files.length === 0) return;
imageFile = files[0];
sampleImageType.value = 'provided';
if (renderer != null) {
renderer.destroy(false);
renderer = null;
initRenderer();
}
}
let renderer: ImageLabelRenderer | null = null;
let imageBitmap: ImageBitmap | null = null;
@ -191,20 +207,20 @@ async function initRenderer() {
exif: EXIF_MOCK,
renderAsPreview: true,
});
} else if (props.image != null) {
imageBitmap = await window.createImageBitmap(props.image);
} else if (imageFile != null) {
imageBitmap = await window.createImageBitmap(imageFile);
const exif = ExifReader.load(await imageFile.arrayBuffer());
renderer = new ImageLabelRenderer({
canvas: canvasEl.value,
image: imageBitmap,
exif: EXIF_MOCK,
exif: exif,
renderAsPreview: true,
});
}
await renderer!.update(frame);
renderer!.render();
}
onMounted(async () => {

View File

@ -25,6 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="props.image == null" class="_acrylic" :class="$style.previewControls">
<button class="_button" :class="[$style.previewControlsButton, sampleImageType === '3_2' ? $style.active : null]" @click="sampleImageType = '3_2'"><i class="ti ti-crop-landscape"></i></button>
<button class="_button" :class="[$style.previewControlsButton, sampleImageType === '2_3' ? $style.active : null]" @click="sampleImageType = '2_3'"><i class="ti ti-crop-portrait"></i></button>
<button class="_button" :class="[$style.previewControlsButton]" @click="choiceImage"><i class="ti ti-upload"></i></button>
</div>
</div>
</div>
@ -192,7 +193,7 @@ async function cancel() {
watch(preset, async (newValue, oldValue) => {
if (renderer != null) {
renderer.setLayers(preset.layers);
renderer.setLayersAndRender(preset.layers);
}
}, { deep: true });
@ -212,6 +213,7 @@ const sampleImage_2_3_loading = new Promise<void>(resolve => {
const sampleImageType = ref(props.image != null ? 'provided' : '3_2');
watch(sampleImageType, async () => {
if (sampleImageType.value === 'provided') return;
if (renderer != null) {
renderer.destroy(false);
renderer = null;
@ -219,6 +221,20 @@ watch(sampleImageType, async () => {
}
});
let imageFile = props.image;
async function choiceImage() {
const files = await os.chooseFileFromPc({ multiple: false });
if (files.length === 0) return;
imageFile = files[0];
sampleImageType.value = 'provided';
if (renderer != null) {
renderer.destroy(false);
renderer = null;
initRenderer();
}
}
let renderer: WatermarkRenderer | null = null;
let imageBitmap: ImageBitmap | null = null;
@ -239,8 +255,8 @@ async function initRenderer() {
renderHeight: 1500,
image: sampleImage_2_3,
});
} else if (props.image != null) {
imageBitmap = await window.createImageBitmap(props.image);
} else if (imageFile != null) {
imageBitmap = await window.createImageBitmap(imageFile);
const MAX_W = 1000;
const MAX_H = 1000;
@ -261,9 +277,7 @@ async function initRenderer() {
});
}
await renderer!.setLayers(preset.layers);
renderer!.render();
await renderer!.setLayersAndRender(preset.layers);
}
onMounted(async () => {

View File

@ -558,9 +558,7 @@ export function useUploader(options: {
image: imageBitmap,
});
await renderer.setLayers(preset.layers);
renderer.render();
await renderer.setLayersAndRender(preset.layers);
preprocessedFile = await new Promise<Blob>((resolve) => {
canvas.toBlob((blob) => {

View File

@ -78,9 +78,7 @@ onMounted(() => {
image: sampleImage,
});
await renderer.setLayers(props.preset.layers);
renderer.render();
await renderer.setLayersAndRender(props.preset.layers);
}, { immediate: true });
};
});
@ -94,8 +92,7 @@ onUnmounted(() => {
watch(() => props.preset, async () => {
if (renderer != null) {
await renderer.setLayers(props.preset.layers);
renderer.render();
await renderer.setLayersAndRender(props.preset.layers);
}
}, { deep: true });
</script>

View File

@ -327,7 +327,7 @@ export class ImageEffector<IEX extends ReadonlyArray<ImageEffectorFx<any, any, a
}
}
public async setLayers(layers: ImageEffectorLayer[]) {
public async setLayersAndRender(layers: ImageEffectorLayer[]) {
this.layers = layers;
const unused = new Set(this.paramTextures.keys());

View File

@ -24,6 +24,9 @@ export type ImageLabelParams = {
text: string;
centered: boolean;
withQrCode: boolean;
bgColor: [r: number, g: number, b: number];
fgColor: [r: number, g: number, b: number];
borderRadius: number; // TODO
};
export class ImageLabelRenderer {
@ -192,7 +195,7 @@ export class ImageLabelRenderer {
this.effector.changeResolution(renderWidth, renderHeight);
await this.effector.setLayers([{
await this.effector.setLayersAndRender([{
fxId: 'label',
id: 'a',
params: {

View File

@ -199,10 +199,9 @@ export class WatermarkRenderer {
});
}
public async setLayers(layers: WatermarkPreset['layers']) {
public async setLayersAndRender(layers: WatermarkPreset['layers']) {
this.layers = layers;
await this.effector.setLayers(this.makeImageEffectorLayers());
this.render();
await this.effector.setLayersAndRender(this.makeImageEffectorLayers());
}
public render(): void {