From d2371a9943a3a27dcfbf426e71f84412de4c9744 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Sat, 24 May 2025 19:48:24 +0900 Subject: [PATCH 01/18] enhance: refine uploadFile --- .../src/components/MkFormDialog.file.vue | 5 +- .../frontend/src/components/MkPostForm.vue | 8 +++- .../src/components/MkUploaderDialog.vue | 48 ++++++++++++++++--- .../MkWatermarkEditorDialog.Layer.vue | 13 +++-- .../components/MkWatermarkEditorDialog.vue | 7 +-- packages/frontend/src/os.ts | 3 ++ .../custom-emojis-manager.local.list.vue | 5 +- .../frontend/src/pages/channel-editor.vue | 5 +- .../frontend/src/pages/chat/room.form.vue | 6 ++- .../src/pages/custom-emojis-manager.vue | 5 +- .../frontend/src/pages/emoji-edit-dialog.vue | 5 +- packages/frontend/src/pages/gallery/edit.vue | 9 ++-- .../src/pages/page-editor/page-editor.vue | 5 +- .../src/pages/settings/account-data.vue | 25 ++++++++-- packages/frontend/src/pages/settings/deck.vue | 5 +- .../src/pages/settings/sounds.sound.vue | 6 ++- packages/frontend/src/preferences/def.ts | 2 +- packages/frontend/src/utility/drive.ts | 26 ++++++---- 18 files changed, 146 insertions(+), 42 deletions(-) diff --git a/packages/frontend/src/components/MkFormDialog.file.vue b/packages/frontend/src/components/MkFormDialog.file.vue index a11075c3429..182ff3ccf57 100644 --- a/packages/frontend/src/components/MkFormDialog.file.vue +++ b/packages/frontend/src/components/MkFormDialog.file.vue @@ -51,7 +51,10 @@ if (props.fileId) { } function selectButton(ev: MouseEvent) { - selectFile(ev.currentTarget ?? ev.target).then(async (file) => { + selectFile({ + anchorElement: ev.currentTarget ?? ev.target, + multiple: false, + }).then(async (file) => { if (!file) return; if (props.validate && !await props.validate(file)) return; diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index 982ed880032..cd4fabea02a 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -120,7 +120,7 @@ import { formatTimeString } from '@/utility/format-time-string.js'; import { Autocomplete } from '@/utility/autocomplete.js'; import * as os from '@/os.js'; import { misskeyApi } from '@/utility/misskey-api.js'; -import { selectFiles } from '@/utility/drive.js'; +import { selectFile } from '@/utility/drive.js'; import { store } from '@/store.js'; import MkInfo from '@/components/MkInfo.vue'; import { i18n } from '@/i18n.js'; @@ -437,7 +437,11 @@ function focus() { function chooseFileFrom(ev) { if (props.mock) return; - selectFiles(ev.currentTarget ?? ev.target, i18n.ts.attachFile).then(files_ => { + selectFile({ + anchorElement: ev.currentTarget ?? ev.target, + multiple: true, + label: i18n.ts.attachFile, + }).then(files_ => { for (const file of files_) { files.value.push(file); } diff --git a/packages/frontend/src/components/MkUploaderDialog.vue b/packages/frontend/src/components/MkUploaderDialog.vue index b2e4896ed35..77ee36b2a20 100644 --- a/packages/frontend/src/components/MkUploaderDialog.vue +++ b/packages/frontend/src/components/MkUploaderDialog.vue @@ -79,8 +79,16 @@ SPDX-License-Identifier: AGPL-3.0-only + + diff --git a/packages/frontend/src/components/MkUploaderDialog.vue b/packages/frontend/src/components/MkUploaderDialog.vue index 77ee36b2a20..6096cb858a4 100644 --- a/packages/frontend/src/components/MkUploaderDialog.vue +++ b/packages/frontend/src/components/MkUploaderDialog.vue @@ -560,7 +560,7 @@ async function preprocess(item: (typeof items)['value'][number]): Promise await renderer.setLayers(preset.layers); - renderer.render(); + await renderer.render(); file = await new Promise((resolve) => { canvas.toBlob((blob) => { diff --git a/packages/frontend/src/pages/settings/drive.WatermarkItem.vue b/packages/frontend/src/pages/settings/drive.WatermarkItem.vue index b466f35fc5a..7123b214f1f 100644 --- a/packages/frontend/src/pages/settings/drive.WatermarkItem.vue +++ b/packages/frontend/src/pages/settings/drive.WatermarkItem.vue @@ -80,7 +80,7 @@ onMounted(() => { await renderer.setLayers(props.preset.layers); - renderer.render(); + await renderer.render(); }, { immediate: true }); }; }); @@ -95,7 +95,7 @@ onUnmounted(() => { watch(() => props.preset, async () => { if (renderer != null) { await renderer.setLayers(props.preset.layers); - renderer.render(); + await renderer.render(); } }, { deep: true }); diff --git a/packages/frontend/src/utility/image-effector/ImageEffector.ts b/packages/frontend/src/utility/image-effector/ImageEffector.ts index 472d21bb1bc..16169d359a6 100644 --- a/packages/frontend/src/utility/image-effector/ImageEffector.ts +++ b/packages/frontend/src/utility/image-effector/ImageEffector.ts @@ -27,7 +27,7 @@ export function defineImageEffectorFx = { id: ID; name: string; - shader: string; + shader: string | (() => Promise); uniforms: US; params: PS, main: (ctx: { @@ -196,22 +196,37 @@ export class ImageEffector fx.id === layer.fxId); if (fx == null) return; const cachedShader = this.shaderCache.get(fx.id); - const shaderProgram = cachedShader ?? this.initShaderProgram(`#version 300 es - in vec2 position; - out vec2 in_uv; + let shaderProgram: WebGLProgram; - void main() { - in_uv = (position + 1.0) / 2.0; - gl_Position = vec4(position, 0.0, 1.0); + if (cachedShader != null) { + shaderProgram = cachedShader; + } else { + let shaderSource: string; + + if (typeof fx.shader === 'string') { + shaderSource = fx.shader; + } else { + shaderSource = await fx.shader(); } - `, fx.shader); + + shaderProgram = this.initShaderProgram(`#version 300 es + in vec2 position; + out vec2 in_uv; + + void main() { + in_uv = (position + 1.0) / 2.0; + gl_Position = vec4(position, 0.0, 1.0); + } + `, shaderSource); + } + if (cachedShader == null) { this.shaderCache.set(fx.id, shaderProgram); } @@ -230,7 +245,7 @@ export class ImageEffector { + Object.entries(fx.params as ImageEffectorFxParamDefs).map(([key, param]) => { return [key, layer.params[key] ?? param.default]; }), ), @@ -238,7 +253,7 @@ export class ImageEffector { + Object.entries(fx.params as ImageEffectorFxParamDefs).map(([k, v]) => { if (v.type !== 'texture') return [k, null]; const param = getValue(layer.params, k); if (param == null) return [k, null]; @@ -250,7 +265,7 @@ export class ImageEffector[]; +] satisfies ReadonlyArray>; export const WATERMARK_FXS = [ FX_watermarkPlacement, FX_stripe, FX_polkadot, FX_checker, -] as const satisfies ImageEffectorFx[]; +] satisfies ReadonlyArray>; diff --git a/packages/frontend/src/utility/image-effector/fxs/checker.glsl b/packages/frontend/src/utility/image-effector/fxs/checker.glsl new file mode 100644 index 00000000000..b1625e6b17c --- /dev/null +++ b/packages/frontend/src/utility/image-effector/fxs/checker.glsl @@ -0,0 +1,43 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#version 300 es +precision mediump float; + +const float PI = 3.141592653589793; +const float TWO_PI = 6.283185307179586; +const float HALF_PI = 1.5707963267948966; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform float u_angle; +uniform float u_scale; +uniform vec3 u_color; +uniform float u_opacity; +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float x_ratio = max(in_resolution.x / in_resolution.y, 1.0); + float y_ratio = max(in_resolution.y / in_resolution.x, 1.0); + + float angle = -(u_angle * PI); + vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio); + vec2 rotatedUV = vec2( + centeredUv.x * cos(angle) - centeredUv.y * sin(angle), + centeredUv.x * sin(angle) + centeredUv.y * cos(angle) + ); + + float fmodResult = mod(floor(u_scale * rotatedUV.x) + floor(u_scale * rotatedUV.y), 2.0); + float fin = max(sign(fmodResult), 0.0); + + out_color = vec4( + mix(in_color.r, u_color.r, fin * u_opacity), + mix(in_color.g, u_color.g, fin * u_opacity), + mix(in_color.b, u_color.b, fin * u_opacity), + in_color.a + ); +} diff --git a/packages/frontend/src/utility/image-effector/fxs/checker.ts b/packages/frontend/src/utility/image-effector/fxs/checker.ts index b799bd0d13d..9b1210fd56f 100644 --- a/packages/frontend/src/utility/image-effector/fxs/checker.ts +++ b/packages/frontend/src/utility/image-effector/fxs/checker.ts @@ -6,50 +6,10 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; -const shader = `#version 300 es -precision mediump float; - -const float PI = 3.141592653589793; -const float TWO_PI = 6.283185307179586; -const float HALF_PI = 1.5707963267948966; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform float u_angle; -uniform float u_scale; -uniform vec3 u_color; -uniform float u_opacity; -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float x_ratio = max(in_resolution.x / in_resolution.y, 1.0); - float y_ratio = max(in_resolution.y / in_resolution.x, 1.0); - - float angle = -(u_angle * PI); - vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio); - vec2 rotatedUV = vec2( - centeredUv.x * cos(angle) - centeredUv.y * sin(angle), - centeredUv.x * sin(angle) + centeredUv.y * cos(angle) - ); - - float fmodResult = mod(floor(u_scale * rotatedUV.x) + floor(u_scale * rotatedUV.y), 2.0); - float fin = max(sign(fmodResult), 0.0); - - out_color = vec4( - mix(in_color.r, u_color.r, fin * u_opacity), - mix(in_color.g, u_color.g, fin * u_opacity), - mix(in_color.b, u_color.b, fin * u_opacity), - in_color.a - ); -} -`; - export const FX_checker = defineImageEffectorFx({ id: 'checker' as const, name: i18n.ts._imageEffector._fxs.checker, - shader, + shader: () => import('./checker.glsl?raw').then(m => m.default), uniforms: ['angle', 'scale', 'color', 'opacity'] as const, params: { angle: { diff --git a/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl b/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl new file mode 100644 index 00000000000..cc5d3ddaf38 --- /dev/null +++ b/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +out vec4 out_color; +uniform float u_amount; +uniform float u_start; +uniform bool u_normalize; + +void main() { + int samples = 64; + float r_strength = 1.0; + float g_strength = 1.5; + float b_strength = 2.0; + + vec2 size = vec2(in_resolution.x, in_resolution.y); + + vec4 accumulator = vec4(0.0); + float normalisedValue = length((in_uv - 0.5) * 2.0); + float strength = clamp((normalisedValue - u_start) * (1.0 / (1.0 - u_start)), 0.0, 1.0); + + vec2 vector = (u_normalize ? normalize(in_uv - vec2(0.5)) : in_uv - vec2(0.5)); + vec2 velocity = vector * strength * u_amount; + + vec2 rOffset = -vector * strength * (u_amount * r_strength); + vec2 gOffset = -vector * strength * (u_amount * g_strength); + vec2 bOffset = -vector * strength * (u_amount * b_strength); + + for (int i = 0; i < samples; i++) { + accumulator.r += texture(in_texture, in_uv + rOffset).r; + rOffset -= velocity / float(samples); + + accumulator.g += texture(in_texture, in_uv + gOffset).g; + gOffset -= velocity / float(samples); + + accumulator.b += texture(in_texture, in_uv + bOffset).b; + bOffset -= velocity / float(samples); + } + + out_color = vec4(vec3(accumulator / float(samples)), 1.0); +} diff --git a/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.ts b/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.ts index 82d7d883aa9..905d82bd6d0 100644 --- a/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.ts +++ b/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.ts @@ -6,55 +6,10 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; -const shader = `#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -out vec4 out_color; -uniform float u_amount; -uniform float u_start; -uniform bool u_normalize; - -void main() { - int samples = 64; - float r_strength = 1.0; - float g_strength = 1.5; - float b_strength = 2.0; - - vec2 size = vec2(in_resolution.x, in_resolution.y); - - vec4 accumulator = vec4(0.0); - float normalisedValue = length((in_uv - 0.5) * 2.0); - float strength = clamp((normalisedValue - u_start) * (1.0 / (1.0 - u_start)), 0.0, 1.0); - - vec2 vector = (u_normalize ? normalize(in_uv - vec2(0.5)) : in_uv - vec2(0.5)); - vec2 velocity = vector * strength * u_amount; - - vec2 rOffset = -vector * strength * (u_amount * r_strength); - vec2 gOffset = -vector * strength * (u_amount * g_strength); - vec2 bOffset = -vector * strength * (u_amount * b_strength); - - for (int i = 0; i < samples; i++) { - accumulator.r += texture(in_texture, in_uv + rOffset).r; - rOffset -= velocity / float(samples); - - accumulator.g += texture(in_texture, in_uv + gOffset).g; - gOffset -= velocity / float(samples); - - accumulator.b += texture(in_texture, in_uv + bOffset).b; - bOffset -= velocity / float(samples); - } - - out_color = vec4(vec3(accumulator / float(samples)), 1.0); -} -`; - export const FX_chromaticAberration = defineImageEffectorFx({ id: 'chromaticAberration' as const, name: i18n.ts._imageEffector._fxs.chromaticAberration, - shader, + shader: () => import('./chromaticAberration.glsl?raw').then(m => m.default), uniforms: ['amount', 'start', 'normalize'] as const, params: { normalize: { diff --git a/packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl b/packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl new file mode 100644 index 00000000000..b0691241777 --- /dev/null +++ b/packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform float u_max; +uniform float u_min; +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float r = min(max(in_color.r, u_min), u_max); + float g = min(max(in_color.g, u_min), u_max); + float b = min(max(in_color.b, u_min), u_max); + out_color = vec4(r, g, b, in_color.a); +} diff --git a/packages/frontend/src/utility/image-effector/fxs/colorClamp.ts b/packages/frontend/src/utility/image-effector/fxs/colorClamp.ts index 5393d73df0b..b53def8a817 100644 --- a/packages/frontend/src/utility/image-effector/fxs/colorClamp.ts +++ b/packages/frontend/src/utility/image-effector/fxs/colorClamp.ts @@ -6,29 +6,10 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; -const shader = `#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform float u_max; -uniform float u_min; -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float r = min(max(in_color.r, u_min), u_max); - float g = min(max(in_color.g, u_min), u_max); - float b = min(max(in_color.b, u_min), u_max); - out_color = vec4(r, g, b, in_color.a); -} -`; - export const FX_colorClamp = defineImageEffectorFx({ id: 'colorClamp' as const, name: i18n.ts._imageEffector._fxs.colorClamp, - shader, + shader: () => import('./colorClamp.glsl?raw').then(m => m.default), uniforms: ['max', 'min'] as const, params: { max: { diff --git a/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.glsl b/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.glsl new file mode 100644 index 00000000000..f9c0ed9d4df --- /dev/null +++ b/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.glsl @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform float u_rMax; +uniform float u_rMin; +uniform float u_gMax; +uniform float u_gMin; +uniform float u_bMax; +uniform float u_bMin; +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float r = min(max(in_color.r, u_rMin), u_rMax); + float g = min(max(in_color.g, u_gMin), u_gMax); + float b = min(max(in_color.b, u_bMin), u_bMax); + out_color = vec4(r, g, b, in_color.a); +} diff --git a/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.ts b/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.ts index c66d75a83fc..ea318ab0e20 100644 --- a/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.ts +++ b/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.ts @@ -6,33 +6,10 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; -const shader = `#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform float u_rMax; -uniform float u_rMin; -uniform float u_gMax; -uniform float u_gMin; -uniform float u_bMax; -uniform float u_bMin; -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float r = min(max(in_color.r, u_rMin), u_rMax); - float g = min(max(in_color.g, u_gMin), u_gMax); - float b = min(max(in_color.b, u_bMin), u_bMax); - out_color = vec4(r, g, b, in_color.a); -} -`; - export const FX_colorClampAdvanced = defineImageEffectorFx({ id: 'colorClampAdvanced' as const, name: i18n.ts._imageEffector._fxs.colorClampAdvanced, - shader, + shader: () => import('./colorClampAdvanced.glsl?raw').then(m => m.default), uniforms: ['rMax', 'rMin', 'gMax', 'gMin', 'bMax', 'bMin'] as const, params: { rMax: { diff --git a/packages/frontend/src/utility/image-effector/fxs/distort.glsl b/packages/frontend/src/utility/image-effector/fxs/distort.glsl new file mode 100644 index 00000000000..9f27fda5c97 --- /dev/null +++ b/packages/frontend/src/utility/image-effector/fxs/distort.glsl @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform float u_phase; +uniform float u_frequency; +uniform float u_strength; +uniform int u_direction; // 0: vertical, 1: horizontal +out vec4 out_color; + +void main() { + float v = u_direction == 0 ? + sin(u_phase + in_uv.y * u_frequency) * u_strength : + sin(u_phase + in_uv.x * u_frequency) * u_strength; + vec4 in_color = u_direction == 0 ? + texture(in_texture, vec2(in_uv.x + v, in_uv.y)) : + texture(in_texture, vec2(in_uv.x, in_uv.y + v)); + out_color = in_color; +} diff --git a/packages/frontend/src/utility/image-effector/fxs/distort.ts b/packages/frontend/src/utility/image-effector/fxs/distort.ts index f91287c0386..21ec4e130af 100644 --- a/packages/frontend/src/utility/image-effector/fxs/distort.ts +++ b/packages/frontend/src/utility/image-effector/fxs/distort.ts @@ -6,33 +6,10 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; -const shader = `#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform float u_phase; -uniform float u_frequency; -uniform float u_strength; -uniform int u_direction; // 0: vertical, 1: horizontal -out vec4 out_color; - -void main() { - float v = u_direction == 0 ? - sin(u_phase + in_uv.y * u_frequency) * u_strength : - sin(u_phase + in_uv.x * u_frequency) * u_strength; - vec4 in_color = u_direction == 0 ? - texture(in_texture, vec2(in_uv.x + v, in_uv.y)) : - texture(in_texture, vec2(in_uv.x, in_uv.y + v)); - out_color = in_color; -} -`; - export const FX_distort = defineImageEffectorFx({ id: 'distort' as const, name: i18n.ts._imageEffector._fxs.distort, - shader, + shader: () => import('./distort.glsl?raw').then(m => m.default), uniforms: ['phase', 'frequency', 'strength', 'direction'] as const, params: { direction: { diff --git a/packages/frontend/src/utility/image-effector/fxs/glitch.glsl b/packages/frontend/src/utility/image-effector/fxs/glitch.glsl new file mode 100644 index 00000000000..1ce8c21d638 --- /dev/null +++ b/packages/frontend/src/utility/image-effector/fxs/glitch.glsl @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform int u_amount; +uniform float u_shiftStrengths[128]; +uniform float u_shiftOrigins[128]; +uniform float u_shiftHeights[128]; +uniform float u_channelShift; +out vec4 out_color; + +void main() { + float v = 0.0; + + for (int i = 0; i < u_amount; i++) { + if (in_uv.y > (u_shiftOrigins[i] - u_shiftHeights[i]) && in_uv.y < (u_shiftOrigins[i] + u_shiftHeights[i])) { + v += u_shiftStrengths[i]; + } + } + + float r = texture(in_texture, vec2(in_uv.x + (v * (1.0 + u_channelShift)), in_uv.y)).r; + float g = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).g; + float b = texture(in_texture, vec2(in_uv.x + (v * (1.0 + (u_channelShift / 2.0))), in_uv.y)).b; + float a = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).a; + out_color = vec4(r, g, b, a); +} diff --git a/packages/frontend/src/utility/image-effector/fxs/glitch.ts b/packages/frontend/src/utility/image-effector/fxs/glitch.ts index e4939a43020..17b898b249d 100644 --- a/packages/frontend/src/utility/image-effector/fxs/glitch.ts +++ b/packages/frontend/src/utility/image-effector/fxs/glitch.ts @@ -7,40 +7,10 @@ import seedrandom from 'seedrandom'; import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; -const shader = `#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform int u_amount; -uniform float u_shiftStrengths[128]; -uniform float u_shiftOrigins[128]; -uniform float u_shiftHeights[128]; -uniform float u_channelShift; -out vec4 out_color; - -void main() { - float v = 0.0; - - for (int i = 0; i < u_amount; i++) { - if (in_uv.y > (u_shiftOrigins[i] - u_shiftHeights[i]) && in_uv.y < (u_shiftOrigins[i] + u_shiftHeights[i])) { - v += u_shiftStrengths[i]; - } - } - - float r = texture(in_texture, vec2(in_uv.x + (v * (1.0 + u_channelShift)), in_uv.y)).r; - float g = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).g; - float b = texture(in_texture, vec2(in_uv.x + (v * (1.0 + (u_channelShift / 2.0))), in_uv.y)).b; - float a = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).a; - out_color = vec4(r, g, b, a); -} -`; - export const FX_glitch = defineImageEffectorFx({ id: 'glitch' as const, name: i18n.ts._imageEffector._fxs.glitch, - shader, + shader: () => import('./glitch.glsl?raw').then(m => m.default), uniforms: ['amount', 'channelShift'] as const, params: { amount: { diff --git a/packages/frontend/src/utility/image-effector/fxs/grayscale.glsl b/packages/frontend/src/utility/image-effector/fxs/grayscale.glsl new file mode 100644 index 00000000000..4d37e339614 --- /dev/null +++ b/packages/frontend/src/utility/image-effector/fxs/grayscale.glsl @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +out vec4 out_color; + +float getBrightness(vec4 color) { + return (color.r + color.g + color.b) / 3.0; +} + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float brightness = getBrightness(in_color); + out_color = vec4(brightness, brightness, brightness, in_color.a); +} diff --git a/packages/frontend/src/utility/image-effector/fxs/grayscale.ts b/packages/frontend/src/utility/image-effector/fxs/grayscale.ts index 8f33706ae71..38c2230a278 100644 --- a/packages/frontend/src/utility/image-effector/fxs/grayscale.ts +++ b/packages/frontend/src/utility/image-effector/fxs/grayscale.ts @@ -6,29 +6,10 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; -const shader = `#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -out vec4 out_color; - -float getBrightness(vec4 color) { - return (color.r + color.g + color.b) / 3.0; -} - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float brightness = getBrightness(in_color); - out_color = vec4(brightness, brightness, brightness, in_color.a); -} -`; - export const FX_grayscale = defineImageEffectorFx({ id: 'grayscale' as const, name: i18n.ts._imageEffector._fxs.grayscale, - shader, + shader: () => import('./grayscale.glsl?raw').then(m => m.default), uniforms: [] as const, params: { }, diff --git a/packages/frontend/src/utility/image-effector/fxs/invert.glsl b/packages/frontend/src/utility/image-effector/fxs/invert.glsl new file mode 100644 index 00000000000..38726d3c87c --- /dev/null +++ b/packages/frontend/src/utility/image-effector/fxs/invert.glsl @@ -0,0 +1,23 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform bool u_r; +uniform bool u_g; +uniform bool u_b; +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + out_color.r = u_r ? 1.0 - in_color.r : in_color.r; + out_color.g = u_g ? 1.0 - in_color.g : in_color.g; + out_color.b = u_b ? 1.0 - in_color.b : in_color.b; + out_color.a = in_color.a; +} diff --git a/packages/frontend/src/utility/image-effector/fxs/invert.ts b/packages/frontend/src/utility/image-effector/fxs/invert.ts index 220a2dea303..65e6e8d4c7a 100644 --- a/packages/frontend/src/utility/image-effector/fxs/invert.ts +++ b/packages/frontend/src/utility/image-effector/fxs/invert.ts @@ -6,30 +6,10 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; -const shader = `#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform bool u_r; -uniform bool u_g; -uniform bool u_b; -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - out_color.r = u_r ? 1.0 - in_color.r : in_color.r; - out_color.g = u_g ? 1.0 - in_color.g : in_color.g; - out_color.b = u_b ? 1.0 - in_color.b : in_color.b; - out_color.a = in_color.a; -} -`; - export const FX_invert = defineImageEffectorFx({ id: 'invert' as const, name: i18n.ts._imageEffector._fxs.invert, - shader, + shader: () => import('./invert.glsl?raw').then(m => m.default), uniforms: ['r', 'g', 'b'] as const, params: { r: { diff --git a/packages/frontend/src/utility/image-effector/fxs/mirror.glsl b/packages/frontend/src/utility/image-effector/fxs/mirror.glsl new file mode 100644 index 00000000000..4ef807aaba0 --- /dev/null +++ b/packages/frontend/src/utility/image-effector/fxs/mirror.glsl @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform int u_h; +uniform int u_v; +out vec4 out_color; + +void main() { + vec2 uv = in_uv; + if (u_h == -1 && in_uv.x > 0.5) { + uv.x = 1.0 - uv.x; + } + if (u_h == 1 && in_uv.x < 0.5) { + uv.x = 1.0 - uv.x; + } + if (u_v == -1 && in_uv.y > 0.5) { + uv.y = 1.0 - uv.y; + } + if (u_v == 1 && in_uv.y < 0.5) { + uv.y = 1.0 - uv.y; + } + out_color = texture(in_texture, uv); +} diff --git a/packages/frontend/src/utility/image-effector/fxs/mirror.ts b/packages/frontend/src/utility/image-effector/fxs/mirror.ts index 5946a2e0dc9..4220a6ac62d 100644 --- a/packages/frontend/src/utility/image-effector/fxs/mirror.ts +++ b/packages/frontend/src/utility/image-effector/fxs/mirror.ts @@ -6,38 +6,10 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; -const shader = `#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform int u_h; -uniform int u_v; -out vec4 out_color; - -void main() { - vec2 uv = in_uv; - if (u_h == -1 && in_uv.x > 0.5) { - uv.x = 1.0 - uv.x; - } - if (u_h == 1 && in_uv.x < 0.5) { - uv.x = 1.0 - uv.x; - } - if (u_v == -1 && in_uv.y > 0.5) { - uv.y = 1.0 - uv.y; - } - if (u_v == 1 && in_uv.y < 0.5) { - uv.y = 1.0 - uv.y; - } - out_color = texture(in_texture, uv); -} -`; - export const FX_mirror = defineImageEffectorFx({ id: 'mirror' as const, name: i18n.ts._imageEffector._fxs.mirror, - shader, + shader: () => import('./mirror.glsl?raw').then(m => m.default), uniforms: ['h', 'v'] as const, params: { h: { diff --git a/packages/frontend/src/utility/image-effector/fxs/polkadot.glsl b/packages/frontend/src/utility/image-effector/fxs/polkadot.glsl new file mode 100644 index 00000000000..a7c7940d70f --- /dev/null +++ b/packages/frontend/src/utility/image-effector/fxs/polkadot.glsl @@ -0,0 +1,75 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#version 300 es +precision mediump float; + +const float PI = 3.141592653589793; +const float TWO_PI = 6.283185307179586; +const float HALF_PI = 1.5707963267948966; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform float u_angle; +uniform float u_scale; +uniform float u_major_radius; +uniform float u_major_opacity; +uniform float u_minor_divisions; +uniform float u_minor_radius; +uniform float u_minor_opacity; +uniform vec3 u_color; +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float x_ratio = max(in_resolution.x / in_resolution.y, 1.0); + float y_ratio = max(in_resolution.y / in_resolution.x, 1.0); + + float angle = -(u_angle * PI); + vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio); + vec2 rotatedUV = vec2( + centeredUv.x * cos(angle) - centeredUv.y * sin(angle), + centeredUv.x * sin(angle) + centeredUv.y * cos(angle) + ); + + float major_modX = mod(rotatedUV.x, (1.0 / u_scale)); + float major_modY = mod(rotatedUV.y, (1.0 / u_scale)); + float major_threshold = ((u_major_radius / 2.0) / u_scale); + if ( + length(vec2(major_modX, major_modY)) < major_threshold || + length(vec2((1.0 / u_scale) - major_modX, major_modY)) < major_threshold || + length(vec2(major_modX, (1.0 / u_scale) - major_modY)) < major_threshold || + length(vec2((1.0 / u_scale) - major_modX, (1.0 / u_scale) - major_modY)) < major_threshold + ) { + out_color = vec4( + mix(in_color.r, u_color.r, u_major_opacity), + mix(in_color.g, u_color.g, u_major_opacity), + mix(in_color.b, u_color.b, u_major_opacity), + in_color.a + ); + return; + } + + float minor_modX = mod(rotatedUV.x, (1.0 / u_scale / u_minor_divisions)); + float minor_modY = mod(rotatedUV.y, (1.0 / u_scale / u_minor_divisions)); + float minor_threshold = ((u_minor_radius / 2.0) / (u_minor_divisions * u_scale)); + if ( + length(vec2(minor_modX, minor_modY)) < minor_threshold || + length(vec2((1.0 / u_scale / u_minor_divisions) - minor_modX, minor_modY)) < minor_threshold || + length(vec2(minor_modX, (1.0 / u_scale / u_minor_divisions) - minor_modY)) < minor_threshold || + length(vec2((1.0 / u_scale / u_minor_divisions) - minor_modX, (1.0 / u_scale / u_minor_divisions) - minor_modY)) < minor_threshold + ) { + out_color = vec4( + mix(in_color.r, u_color.r, u_minor_opacity), + mix(in_color.g, u_color.g, u_minor_opacity), + mix(in_color.b, u_color.b, u_minor_opacity), + in_color.a + ); + return; + } + + out_color = in_color; +} diff --git a/packages/frontend/src/utility/image-effector/fxs/polkadot.ts b/packages/frontend/src/utility/image-effector/fxs/polkadot.ts index 198dd9bad01..c6a4cff5cd9 100644 --- a/packages/frontend/src/utility/image-effector/fxs/polkadot.ts +++ b/packages/frontend/src/utility/image-effector/fxs/polkadot.ts @@ -6,82 +6,10 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; -const shader = `#version 300 es -precision mediump float; - -const float PI = 3.141592653589793; -const float TWO_PI = 6.283185307179586; -const float HALF_PI = 1.5707963267948966; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform float u_angle; -uniform float u_scale; -uniform float u_major_radius; -uniform float u_major_opacity; -uniform float u_minor_divisions; -uniform float u_minor_radius; -uniform float u_minor_opacity; -uniform vec3 u_color; -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float x_ratio = max(in_resolution.x / in_resolution.y, 1.0); - float y_ratio = max(in_resolution.y / in_resolution.x, 1.0); - - float angle = -(u_angle * PI); - vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio); - vec2 rotatedUV = vec2( - centeredUv.x * cos(angle) - centeredUv.y * sin(angle), - centeredUv.x * sin(angle) + centeredUv.y * cos(angle) - ); - - float major_modX = mod(rotatedUV.x, (1.0 / u_scale)); - float major_modY = mod(rotatedUV.y, (1.0 / u_scale)); - float major_threshold = ((u_major_radius / 2.0) / u_scale); - if ( - length(vec2(major_modX, major_modY)) < major_threshold || - length(vec2((1.0 / u_scale) - major_modX, major_modY)) < major_threshold || - length(vec2(major_modX, (1.0 / u_scale) - major_modY)) < major_threshold || - length(vec2((1.0 / u_scale) - major_modX, (1.0 / u_scale) - major_modY)) < major_threshold - ) { - out_color = vec4( - mix(in_color.r, u_color.r, u_major_opacity), - mix(in_color.g, u_color.g, u_major_opacity), - mix(in_color.b, u_color.b, u_major_opacity), - in_color.a - ); - return; - } - - float minor_modX = mod(rotatedUV.x, (1.0 / u_scale / u_minor_divisions)); - float minor_modY = mod(rotatedUV.y, (1.0 / u_scale / u_minor_divisions)); - float minor_threshold = ((u_minor_radius / 2.0) / (u_minor_divisions * u_scale)); - if ( - length(vec2(minor_modX, minor_modY)) < minor_threshold || - length(vec2((1.0 / u_scale / u_minor_divisions) - minor_modX, minor_modY)) < minor_threshold || - length(vec2(minor_modX, (1.0 / u_scale / u_minor_divisions) - minor_modY)) < minor_threshold || - length(vec2((1.0 / u_scale / u_minor_divisions) - minor_modX, (1.0 / u_scale / u_minor_divisions) - minor_modY)) < minor_threshold - ) { - out_color = vec4( - mix(in_color.r, u_color.r, u_minor_opacity), - mix(in_color.g, u_color.g, u_minor_opacity), - mix(in_color.b, u_color.b, u_minor_opacity), - in_color.a - ); - return; - } - - out_color = in_color; -} -`; - export const FX_polkadot = defineImageEffectorFx({ id: 'polkadot' as const, name: i18n.ts._imageEffector._fxs.polkadot, - shader, + shader: () => import('./polkadot.glsl?raw').then(m => m.default), uniforms: ['angle', 'scale', 'major_radius', 'major_opacity', 'minor_divisions', 'minor_radius', 'minor_opacity', 'color'] as const, params: { angle: { diff --git a/packages/frontend/src/utility/image-effector/fxs/stripe.glsl b/packages/frontend/src/utility/image-effector/fxs/stripe.glsl new file mode 100644 index 00000000000..d54827658c4 --- /dev/null +++ b/packages/frontend/src/utility/image-effector/fxs/stripe.glsl @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#version 300 es +precision mediump float; + +const float PI = 3.141592653589793; +const float TWO_PI = 6.283185307179586; +const float HALF_PI = 1.5707963267948966; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform float u_angle; +uniform float u_frequency; +uniform float u_phase; +uniform float u_threshold; +uniform vec3 u_color; +uniform float u_opacity; +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float x_ratio = max(in_resolution.x / in_resolution.y, 1.0); + float y_ratio = max(in_resolution.y / in_resolution.x, 1.0); + + float angle = -(u_angle * PI); + vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio); + vec2 rotatedUV = vec2( + centeredUv.x * cos(angle) - centeredUv.y * sin(angle), + centeredUv.x * sin(angle) + centeredUv.y * cos(angle) + ); + + float phase = u_phase * TWO_PI; + float value = (1.0 + sin((rotatedUV.x * u_frequency - HALF_PI) + phase)) / 2.0; + value = value < u_threshold ? 1.0 : 0.0; + out_color = vec4( + mix(in_color.r, u_color.r, value * u_opacity), + mix(in_color.g, u_color.g, value * u_opacity), + mix(in_color.b, u_color.b, value * u_opacity), + in_color.a + ); +} diff --git a/packages/frontend/src/utility/image-effector/fxs/stripe.ts b/packages/frontend/src/utility/image-effector/fxs/stripe.ts index 37766e185dc..46fb98db5e3 100644 --- a/packages/frontend/src/utility/image-effector/fxs/stripe.ts +++ b/packages/frontend/src/utility/image-effector/fxs/stripe.ts @@ -6,52 +6,10 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; -const shader = `#version 300 es -precision mediump float; - -const float PI = 3.141592653589793; -const float TWO_PI = 6.283185307179586; -const float HALF_PI = 1.5707963267948966; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform float u_angle; -uniform float u_frequency; -uniform float u_phase; -uniform float u_threshold; -uniform vec3 u_color; -uniform float u_opacity; -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float x_ratio = max(in_resolution.x / in_resolution.y, 1.0); - float y_ratio = max(in_resolution.y / in_resolution.x, 1.0); - - float angle = -(u_angle * PI); - vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio); - vec2 rotatedUV = vec2( - centeredUv.x * cos(angle) - centeredUv.y * sin(angle), - centeredUv.x * sin(angle) + centeredUv.y * cos(angle) - ); - - float phase = u_phase * TWO_PI; - float value = (1.0 + sin((rotatedUV.x * u_frequency - HALF_PI) + phase)) / 2.0; - value = value < u_threshold ? 1.0 : 0.0; - out_color = vec4( - mix(in_color.r, u_color.r, value * u_opacity), - mix(in_color.g, u_color.g, value * u_opacity), - mix(in_color.b, u_color.b, value * u_opacity), - in_color.a - ); -} -`; - export const FX_stripe = defineImageEffectorFx({ id: 'stripe' as const, name: i18n.ts._imageEffector._fxs.stripe, - shader, + shader: () => import('./stripe.glsl?raw').then(m => m.default), uniforms: ['angle', 'frequency', 'phase', 'threshold', 'color', 'opacity'] as const, params: { angle: { diff --git a/packages/frontend/src/utility/image-effector/fxs/threshold.glsl b/packages/frontend/src/utility/image-effector/fxs/threshold.glsl new file mode 100644 index 00000000000..f938b2d520b --- /dev/null +++ b/packages/frontend/src/utility/image-effector/fxs/threshold.glsl @@ -0,0 +1,23 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform float u_r; +uniform float u_g; +uniform float u_b; +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float r = in_color.r < u_r ? 0.0 : 1.0; + float g = in_color.g < u_g ? 0.0 : 1.0; + float b = in_color.b < u_b ? 0.0 : 1.0; + out_color = vec4(r, g, b, in_color.a); +} diff --git a/packages/frontend/src/utility/image-effector/fxs/threshold.ts b/packages/frontend/src/utility/image-effector/fxs/threshold.ts index f2b8b107fda..fc6d73dcb09 100644 --- a/packages/frontend/src/utility/image-effector/fxs/threshold.ts +++ b/packages/frontend/src/utility/image-effector/fxs/threshold.ts @@ -6,30 +6,10 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; -const shader = `#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform float u_r; -uniform float u_g; -uniform float u_b; -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float r = in_color.r < u_r ? 0.0 : 1.0; - float g = in_color.g < u_g ? 0.0 : 1.0; - float b = in_color.b < u_b ? 0.0 : 1.0; - out_color = vec4(r, g, b, in_color.a); -} -`; - export const FX_threshold = defineImageEffectorFx({ id: 'threshold' as const, name: i18n.ts._imageEffector._fxs.threshold, - shader, + shader: () => import('./threshold.glsl?raw').then(m => m.default), uniforms: ['r', 'g', 'b'] as const, params: { r: { diff --git a/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl b/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl new file mode 100644 index 00000000000..1bcda303c53 --- /dev/null +++ b/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl @@ -0,0 +1,80 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#version 300 es +precision mediump float; + +const float PI = 3.141592653589793; +const float TWO_PI = 6.283185307179586; +const float HALF_PI = 1.5707963267948966; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform sampler2D u_texture_watermark; +uniform vec2 u_resolution_watermark; +uniform float u_scale; +uniform float u_angle; +uniform float u_opacity; +uniform bool u_repeat; +uniform int u_alignX; // 0: left, 1: center, 2: right +uniform int u_alignY; // 0: top, 1: center, 2: bottom +uniform int u_fitMode; // 0: contain, 1: cover +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float in_x_ratio = max(in_resolution.x / in_resolution.y, 1.0); + float in_y_ratio = max(in_resolution.y / in_resolution.x, 1.0); + + bool contain = u_fitMode == 0; + + float x_ratio = u_resolution_watermark.x / in_resolution.x; + float y_ratio = u_resolution_watermark.y / in_resolution.y; + + float aspect_ratio = contain ? + (min(x_ratio, y_ratio) / max(x_ratio, y_ratio)) : + (max(x_ratio, y_ratio) / min(x_ratio, y_ratio)); + + float x_scale = contain ? + (x_ratio > y_ratio ? 1.0 * u_scale : aspect_ratio * u_scale) : + (x_ratio > y_ratio ? aspect_ratio * u_scale : 1.0 * u_scale); + + float y_scale = contain ? + (y_ratio > x_ratio ? 1.0 * u_scale : aspect_ratio * u_scale) : + (y_ratio > x_ratio ? aspect_ratio * u_scale : 1.0 * u_scale); + + float x_offset = u_alignX == 0 ? x_scale / 2.0 : u_alignX == 2 ? 1.0 - (x_scale / 2.0) : 0.5; + float y_offset = u_alignY == 0 ? y_scale / 2.0 : u_alignY == 2 ? 1.0 - (y_scale / 2.0) : 0.5; + + float angle = -(u_angle * PI); + vec2 center = vec2(x_offset, y_offset); + //vec2 centeredUv = (in_uv - center) * vec2(in_x_ratio, in_y_ratio); + vec2 centeredUv = (in_uv - center); + vec2 rotatedUV = vec2( + centeredUv.x * cos(angle) - centeredUv.y * sin(angle), + centeredUv.x * sin(angle) + centeredUv.y * cos(angle) + ) + center; + + // trim + if (!u_repeat) { + bool isInside = rotatedUV.x > x_offset - (x_scale / 2.0) && rotatedUV.x < x_offset + (x_scale / 2.0) && + rotatedUV.y > y_offset - (y_scale / 2.0) && rotatedUV.y < y_offset + (y_scale / 2.0); + if (!isInside) { + out_color = in_color; + return; + } + } + + vec4 watermark_color = texture(u_texture_watermark, vec2( + (rotatedUV.x - (x_offset - (x_scale / 2.0))) / x_scale, + (rotatedUV.y - (y_offset - (y_scale / 2.0))) / y_scale + )); + + out_color.r = mix(in_color.r, watermark_color.r, u_opacity * watermark_color.a); + out_color.g = mix(in_color.g, watermark_color.g, u_opacity * watermark_color.a); + out_color.b = mix(in_color.b, watermark_color.b, u_opacity * watermark_color.a); + out_color.a = in_color.a * (1.0 - u_opacity * watermark_color.a) + watermark_color.a * u_opacity; +} diff --git a/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.ts b/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.ts index 1c1c95b0c57..d0c901110da 100644 --- a/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.ts +++ b/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.ts @@ -5,87 +5,10 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; -const shader = `#version 300 es -precision mediump float; - -const float PI = 3.141592653589793; -const float TWO_PI = 6.283185307179586; -const float HALF_PI = 1.5707963267948966; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform sampler2D u_texture_watermark; -uniform vec2 u_resolution_watermark; -uniform float u_scale; -uniform float u_angle; -uniform float u_opacity; -uniform bool u_repeat; -uniform int u_alignX; // 0: left, 1: center, 2: right -uniform int u_alignY; // 0: top, 1: center, 2: bottom -uniform int u_fitMode; // 0: contain, 1: cover -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float in_x_ratio = max(in_resolution.x / in_resolution.y, 1.0); - float in_y_ratio = max(in_resolution.y / in_resolution.x, 1.0); - - bool contain = u_fitMode == 0; - - float x_ratio = u_resolution_watermark.x / in_resolution.x; - float y_ratio = u_resolution_watermark.y / in_resolution.y; - - float aspect_ratio = contain ? - (min(x_ratio, y_ratio) / max(x_ratio, y_ratio)) : - (max(x_ratio, y_ratio) / min(x_ratio, y_ratio)); - - float x_scale = contain ? - (x_ratio > y_ratio ? 1.0 * u_scale : aspect_ratio * u_scale) : - (x_ratio > y_ratio ? aspect_ratio * u_scale : 1.0 * u_scale); - - float y_scale = contain ? - (y_ratio > x_ratio ? 1.0 * u_scale : aspect_ratio * u_scale) : - (y_ratio > x_ratio ? aspect_ratio * u_scale : 1.0 * u_scale); - - float x_offset = u_alignX == 0 ? x_scale / 2.0 : u_alignX == 2 ? 1.0 - (x_scale / 2.0) : 0.5; - float y_offset = u_alignY == 0 ? y_scale / 2.0 : u_alignY == 2 ? 1.0 - (y_scale / 2.0) : 0.5; - - float angle = -(u_angle * PI); - vec2 center = vec2(x_offset, y_offset); - //vec2 centeredUv = (in_uv - center) * vec2(in_x_ratio, in_y_ratio); - vec2 centeredUv = (in_uv - center); - vec2 rotatedUV = vec2( - centeredUv.x * cos(angle) - centeredUv.y * sin(angle), - centeredUv.x * sin(angle) + centeredUv.y * cos(angle) - ) + center; - - // trim - if (!u_repeat) { - bool isInside = rotatedUV.x > x_offset - (x_scale / 2.0) && rotatedUV.x < x_offset + (x_scale / 2.0) && - rotatedUV.y > y_offset - (y_scale / 2.0) && rotatedUV.y < y_offset + (y_scale / 2.0); - if (!isInside) { - out_color = in_color; - return; - } - } - - vec4 watermark_color = texture(u_texture_watermark, vec2( - (rotatedUV.x - (x_offset - (x_scale / 2.0))) / x_scale, - (rotatedUV.y - (y_offset - (y_scale / 2.0))) / y_scale - )); - - out_color.r = mix(in_color.r, watermark_color.r, u_opacity * watermark_color.a); - out_color.g = mix(in_color.g, watermark_color.g, u_opacity * watermark_color.a); - out_color.b = mix(in_color.b, watermark_color.b, u_opacity * watermark_color.a); - out_color.a = in_color.a * (1.0 - u_opacity * watermark_color.a) + watermark_color.a * u_opacity; -} -`; - export const FX_watermarkPlacement = defineImageEffectorFx({ id: 'watermarkPlacement' as const, name: '(internal)', - shader, + shader: () => import('./watermarkPlacement.glsl?raw').then(m => m.default), uniforms: ['texture_watermark', 'resolution_watermark', 'scale', 'angle', 'opacity', 'repeat', 'alignX', 'alignY', 'fitMode'] as const, params: { cover: { diff --git a/packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl b/packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl new file mode 100644 index 00000000000..a5faf92bf4d --- /dev/null +++ b/packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform vec2 u_pos; +uniform float u_frequency; +uniform bool u_thresholdEnabled; +uniform float u_threshold; +uniform float u_maskSize; +uniform bool u_black; +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float angle = atan(-u_pos.y + (in_uv.y), -u_pos.x + (in_uv.x)); + float t = (1.0 + sin(angle * u_frequency)) / 2.0; + if (u_thresholdEnabled) t = t < u_threshold ? 1.0 : 0.0; + float d = distance(in_uv * vec2(2.0, 2.0), u_pos * vec2(2.0, 2.0)); + float mask = d < u_maskSize ? 0.0 : ((d - u_maskSize) * (1.0 + (u_maskSize * 2.0))); + out_color = vec4( + mix(in_color.r, u_black ? 0.0 : 1.0, t * mask), + mix(in_color.g, u_black ? 0.0 : 1.0, t * mask), + mix(in_color.b, u_black ? 0.0 : 1.0, t * mask), + in_color.a + ); +} diff --git a/packages/frontend/src/utility/image-effector/fxs/zoomLines.ts b/packages/frontend/src/utility/image-effector/fxs/zoomLines.ts index 2613362a716..b52b947055d 100644 --- a/packages/frontend/src/utility/image-effector/fxs/zoomLines.ts +++ b/packages/frontend/src/utility/image-effector/fxs/zoomLines.ts @@ -6,40 +6,10 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; -const shader = `#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform vec2 u_pos; -uniform float u_frequency; -uniform bool u_thresholdEnabled; -uniform float u_threshold; -uniform float u_maskSize; -uniform bool u_black; -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float angle = atan(-u_pos.y + (in_uv.y), -u_pos.x + (in_uv.x)); - float t = (1.0 + sin(angle * u_frequency)) / 2.0; - if (u_thresholdEnabled) t = t < u_threshold ? 1.0 : 0.0; - float d = distance(in_uv * vec2(2.0, 2.0), u_pos * vec2(2.0, 2.0)); - float mask = d < u_maskSize ? 0.0 : ((d - u_maskSize) * (1.0 + (u_maskSize * 2.0))); - out_color = vec4( - mix(in_color.r, u_black ? 0.0 : 1.0, t * mask), - mix(in_color.g, u_black ? 0.0 : 1.0, t * mask), - mix(in_color.b, u_black ? 0.0 : 1.0, t * mask), - in_color.a - ); -} -`; - export const FX_zoomLines = defineImageEffectorFx({ id: 'zoomLines' as const, name: i18n.ts._imageEffector._fxs.zoomLines, - shader, + shader: () => import('./zoomLines.glsl?raw').then(m => m.default), uniforms: ['pos', 'frequency', 'thresholdEnabled', 'threshold', 'maskSize', 'black'] as const, params: { x: { diff --git a/packages/frontend/src/utility/watermark.ts b/packages/frontend/src/utility/watermark.ts index a70e14d95d1..eb96244d37f 100644 --- a/packages/frontend/src/utility/watermark.ts +++ b/packages/frontend/src/utility/watermark.ts @@ -163,11 +163,11 @@ export class WatermarkRenderer { public async setLayers(layers: WatermarkPreset['layers']) { this.layers = layers; await this.effector.setLayers(this.makeImageEffectorLayers()); - this.render(); + await this.render(); } - public render(): void { - this.effector.render(); + public async render(): Promise { + await this.effector.render(); } /* From 66bffc39c94ec92fce9eaac7489e476d5d87764f Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Tue, 3 Jun 2025 22:57:07 +0900 Subject: [PATCH 05/18] fix(frontend): omit console.log in production environment --- packages/frontend/src/utility/image-effector/ImageEffector.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/utility/image-effector/ImageEffector.ts b/packages/frontend/src/utility/image-effector/ImageEffector.ts index 16169d359a6..282f36778fc 100644 --- a/packages/frontend/src/utility/image-effector/ImageEffector.ts +++ b/packages/frontend/src/utility/image-effector/ImageEffector.ts @@ -344,7 +344,7 @@ export class ImageEffector...`); + if (_DEV_) console.log(`Baking texture of <${textureKey}>...`); const texture = v.type === 'text' ? await createTextureFromText(this.gl, v.text) : v.type === 'url' ? await createTextureFromUrl(this.gl, v.url) : null; if (texture == null) continue; @@ -354,7 +354,7 @@ export class ImageEffector...`); + if (_DEV_) console.log(`Dispose unused texture <${k}>...`); this.gl.deleteTexture(this.paramTextures.get(k)!.texture); this.paramTextures.delete(k); } From afcc37d886106c4acd545e4c2922e67f94e1037b Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Tue, 3 Jun 2025 23:18:36 +0900 Subject: [PATCH 06/18] =?UTF-8?q?fix:=20glsl=E3=81=AE=E3=83=90=E3=83=BC?= =?UTF-8?q?=E3=82=B8=E3=83=A7=E3=83=B3=E8=A1=A8=E8=A8=98=E3=81=AF=E6=9C=80?= =?UTF-8?q?=E5=88=9D=E3=81=AE=E8=A1=8C=E3=81=AB=E3=81=AA=E3=81=91=E3=82=8C?= =?UTF-8?q?=E3=81=B0=E3=81=AA=E3=82=89=E3=81=AA=E3=81=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/utility/image-effector/fxs/checker.glsl | 3 ++- .../src/utility/image-effector/fxs/chromaticAberration.glsl | 3 ++- .../frontend/src/utility/image-effector/fxs/colorClamp.glsl | 3 ++- .../src/utility/image-effector/fxs/colorClampAdvanced.glsl | 3 ++- packages/frontend/src/utility/image-effector/fxs/distort.glsl | 3 ++- packages/frontend/src/utility/image-effector/fxs/glitch.glsl | 3 ++- .../frontend/src/utility/image-effector/fxs/grayscale.glsl | 3 ++- packages/frontend/src/utility/image-effector/fxs/invert.glsl | 3 ++- packages/frontend/src/utility/image-effector/fxs/mirror.glsl | 3 ++- packages/frontend/src/utility/image-effector/fxs/polkadot.glsl | 3 ++- packages/frontend/src/utility/image-effector/fxs/stripe.glsl | 3 ++- .../frontend/src/utility/image-effector/fxs/threshold.glsl | 3 ++- .../src/utility/image-effector/fxs/watermarkPlacement.glsl | 3 ++- .../frontend/src/utility/image-effector/fxs/zoomLines.glsl | 3 ++- 14 files changed, 28 insertions(+), 14 deletions(-) diff --git a/packages/frontend/src/utility/image-effector/fxs/checker.glsl b/packages/frontend/src/utility/image-effector/fxs/checker.glsl index b1625e6b17c..8a06f97ae34 100644 --- a/packages/frontend/src/utility/image-effector/fxs/checker.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/checker.glsl @@ -1,9 +1,10 @@ +#version 300 es + /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -#version 300 es precision mediump float; const float PI = 3.141592653589793; diff --git a/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl b/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl index cc5d3ddaf38..717925a0b2a 100644 --- a/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl @@ -1,9 +1,10 @@ +#version 300 es + /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl b/packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl index b0691241777..24dd0a12153 100644 --- a/packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl @@ -1,9 +1,10 @@ +#version 300 es + /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.glsl b/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.glsl index f9c0ed9d4df..64761b27b70 100644 --- a/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.glsl @@ -1,9 +1,10 @@ +#version 300 es + /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/distort.glsl b/packages/frontend/src/utility/image-effector/fxs/distort.glsl index 9f27fda5c97..29e9566a414 100644 --- a/packages/frontend/src/utility/image-effector/fxs/distort.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/distort.glsl @@ -1,9 +1,10 @@ +#version 300 es + /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/glitch.glsl b/packages/frontend/src/utility/image-effector/fxs/glitch.glsl index 1ce8c21d638..395b5fc17b1 100644 --- a/packages/frontend/src/utility/image-effector/fxs/glitch.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/glitch.glsl @@ -1,9 +1,10 @@ +#version 300 es + /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/grayscale.glsl b/packages/frontend/src/utility/image-effector/fxs/grayscale.glsl index 4d37e339614..206ad115d39 100644 --- a/packages/frontend/src/utility/image-effector/fxs/grayscale.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/grayscale.glsl @@ -1,9 +1,10 @@ +#version 300 es + /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/invert.glsl b/packages/frontend/src/utility/image-effector/fxs/invert.glsl index 38726d3c87c..04e3ba21a5c 100644 --- a/packages/frontend/src/utility/image-effector/fxs/invert.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/invert.glsl @@ -1,9 +1,10 @@ +#version 300 es + /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/mirror.glsl b/packages/frontend/src/utility/image-effector/fxs/mirror.glsl index 4ef807aaba0..222f9d567e5 100644 --- a/packages/frontend/src/utility/image-effector/fxs/mirror.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/mirror.glsl @@ -1,9 +1,10 @@ +#version 300 es + /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/polkadot.glsl b/packages/frontend/src/utility/image-effector/fxs/polkadot.glsl index a7c7940d70f..d3c5c0a5910 100644 --- a/packages/frontend/src/utility/image-effector/fxs/polkadot.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/polkadot.glsl @@ -1,9 +1,10 @@ +#version 300 es + /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -#version 300 es precision mediump float; const float PI = 3.141592653589793; diff --git a/packages/frontend/src/utility/image-effector/fxs/stripe.glsl b/packages/frontend/src/utility/image-effector/fxs/stripe.glsl index d54827658c4..43913f3755a 100644 --- a/packages/frontend/src/utility/image-effector/fxs/stripe.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/stripe.glsl @@ -1,9 +1,10 @@ +#version 300 es + /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -#version 300 es precision mediump float; const float PI = 3.141592653589793; diff --git a/packages/frontend/src/utility/image-effector/fxs/threshold.glsl b/packages/frontend/src/utility/image-effector/fxs/threshold.glsl index f938b2d520b..d1aa91ddc76 100644 --- a/packages/frontend/src/utility/image-effector/fxs/threshold.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/threshold.glsl @@ -1,9 +1,10 @@ +#version 300 es + /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl b/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl index 1bcda303c53..8b8e80118a2 100644 --- a/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl @@ -1,9 +1,10 @@ +#version 300 es + /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -#version 300 es precision mediump float; const float PI = 3.141592653589793; diff --git a/packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl b/packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl index a5faf92bf4d..25d8653b776 100644 --- a/packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl @@ -1,9 +1,10 @@ +#version 300 es + /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -#version 300 es precision mediump float; in vec2 in_uv; From e06f37a7d453ca581858252eae422d8a9e470dc3 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Tue, 3 Jun 2025 23:57:40 +0900 Subject: [PATCH 07/18] =?UTF-8?q?fix:=20=E3=82=B7=E3=82=A7=E3=83=BC?= =?UTF-8?q?=E3=83=80=E3=83=BC=E3=81=AE=E8=AA=AD=E3=81=BF=E8=BE=BC=E3=81=BF?= =?UTF-8?q?=E3=81=8C=E5=AE=8C=E4=BA=86=E3=81=97=E3=81=A6=E3=81=8B=E3=82=89?= =?UTF-8?q?=E3=83=AC=E3=83=B3=E3=83=80=E3=83=AA=E3=83=B3=E3=82=B0=E3=82=92?= =?UTF-8?q?=E8=A1=8C=E3=81=86=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/MkImageEffectorDialog.vue | 7 ++- .../components/MkWatermarkEditorDialog.vue | 14 ++++- .../utility/image-effector/ImageEffector.ts | 60 ++++++++++--------- 3 files changed, 50 insertions(+), 31 deletions(-) diff --git a/packages/frontend/src/components/MkImageEffectorDialog.vue b/packages/frontend/src/components/MkImageEffectorDialog.vue index de2c92bbd61..5605baff514 100644 --- a/packages/frontend/src/components/MkImageEffectorDialog.vue +++ b/packages/frontend/src/components/MkImageEffectorDialog.vue @@ -20,6 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
+
{{ i18n.ts.preview }}
@@ -74,6 +75,8 @@ const emit = defineEmits<{ const dialog = useTemplateRef('dialog'); +const canvasLoading = ref(false); + async function cancel() { if (layers.length > 0) { const { canceled } = await os.confirm({ @@ -91,7 +94,9 @@ const layers = reactive([]); watch(layers, async () => { if (renderer != null) { - renderer.setLayers(layers); + canvasLoading.value = true; + await renderer.setLayers(layers); + canvasLoading.value = false; } }, { deep: true }); diff --git a/packages/frontend/src/components/MkWatermarkEditorDialog.vue b/packages/frontend/src/components/MkWatermarkEditorDialog.vue index db231f90d75..46d952ce903 100644 --- a/packages/frontend/src/components/MkWatermarkEditorDialog.vue +++ b/packages/frontend/src/components/MkWatermarkEditorDialog.vue @@ -20,6 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
+
{{ i18n.ts.preview }}
@@ -89,6 +90,8 @@ import { genId } from '@/utility/id.js'; const $i = ensureSignin(); +const canvasLoading = ref(true); + function createTextLayer(): WatermarkPreset['layers'][number] { return { id: genId(), @@ -232,6 +235,13 @@ let imageBitmap: ImageBitmap | null = null; async function initRenderer() { if (canvasEl.value == null) return; + canvasLoading.value = true; + + await Promise.all([ + sampleImage_3_2_loading, + sampleImage_2_3_loading, + ]); + if (sampleImageType.value === '3_2') { renderer = new WatermarkRenderer({ canvas: canvasEl.value, @@ -270,7 +280,9 @@ async function initRenderer() { await renderer!.setLayers(preset.layers); - renderer!.render(); + await renderer!.render(); + + canvasLoading.value = false; } onMounted(async () => { diff --git a/packages/frontend/src/utility/image-effector/ImageEffector.ts b/packages/frontend/src/utility/image-effector/ImageEffector.ts index 282f36778fc..63f5d6fa4b0 100644 --- a/packages/frontend/src/utility/image-effector/ImageEffector.ts +++ b/packages/frontend/src/utility/image-effector/ImageEffector.ts @@ -196,40 +196,35 @@ export class ImageEffector fx.id === layer.fxId); - if (fx == null) return; - - const cachedShader = this.shaderCache.get(fx.id); - let shaderProgram: WebGLProgram; + private async getOrLoadShaderProgram(fx: ImageEffectorFx): Promise { + let shaderProgram = this.shaderCache.get(fx.id); + if (shaderProgram) return shaderProgram; - if (cachedShader != null) { - shaderProgram = cachedShader; + let shaderSource: string; + if (typeof fx.shader === 'string') { + shaderSource = fx.shader; } else { - let shaderSource: string; + shaderSource = await fx.shader(); + } + shaderProgram = this.initShaderProgram(`#version 300 es + in vec2 position; + out vec2 in_uv; - if (typeof fx.shader === 'string') { - shaderSource = fx.shader; - } else { - shaderSource = await fx.shader(); + void main() { + in_uv = (position + 1.0) / 2.0; + gl_Position = vec4(position, 0.0, 1.0); } + `, shaderSource); + this.shaderCache.set(fx.id, shaderProgram); + return shaderProgram; + } - shaderProgram = this.initShaderProgram(`#version 300 es - in vec2 position; - out vec2 in_uv; - - void main() { - in_uv = (position + 1.0) / 2.0; - gl_Position = vec4(position, 0.0, 1.0); - } - `, shaderSource); - } + private async renderLayer(layer: ImageEffectorLayer, preTexture: WebGLTexture) { + const gl = this.gl; + const fx = this.fxs.find(fx => fx.id === layer.fxId); + if (fx == null) return; - if (cachedShader == null) { - this.shaderCache.set(fx.id, shaderProgram); - } + const shaderProgram = await this.getOrLoadShaderProgram(fx); gl.useProgram(shaderProgram); @@ -268,6 +263,13 @@ export class ImageEffector { + const fx = this.fxs.find(fx => fx.id === layer.fxId); + if (!fx) return; + await this.getOrLoadShaderProgram(fx); + })); + { gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, this.originalImageTexture); @@ -359,7 +361,7 @@ export class ImageEffector Date: Wed, 4 Jun 2025 00:01:36 +0900 Subject: [PATCH 08/18] fix merge failure --- packages/frontend/src/pages/gallery/edit.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/pages/gallery/edit.vue b/packages/frontend/src/pages/gallery/edit.vue index 54c23ea880c..9c0078e15a1 100644 --- a/packages/frontend/src/pages/gallery/edit.vue +++ b/packages/frontend/src/pages/gallery/edit.vue @@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ file.name }}
- {{ i18n.ts.attachFile }} + {{ i18n.ts.attachFile }}
{{ i18n.ts.markAsSensitive }} @@ -66,7 +66,7 @@ const isSensitive = ref(false); function chooseFile(evt) { selectFile({ anchorElement: evt.currentTarget ?? evt.target, - multiple: false, + multiple: true, }).then(selected => { files.value = files.value.concat(selected); }); From 609a2cbd2bdcf5acc1d368a05e76b9d5211ac63f Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Wed, 4 Jun 2025 00:30:59 +0900 Subject: [PATCH 09/18] =?UTF-8?q?fix:=20=E3=82=A6=E3=82=A9=E3=83=BC?= =?UTF-8?q?=E3=82=BF=E3=83=BC=E3=83=9E=E3=83=BC=E3=82=AF=E3=81=AE=E3=83=97?= =?UTF-8?q?=E3=83=AA=E3=82=BB=E3=83=83=E3=83=88=E3=81=8C=E3=81=AA=E3=81=84?= =?UTF-8?q?=E5=A0=B4=E5=90=88=E3=81=ABdivider=E3=81=8C2=E9=87=8D=E3=81=AB?= =?UTF-8?q?=E8=A1=A8=E7=A4=BA=E3=81=95=E3=82=8C=E3=82=8B=E5=95=8F=E9=A1=8C?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/components/MkUploaderDialog.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/components/MkUploaderDialog.vue b/packages/frontend/src/components/MkUploaderDialog.vue index 6096cb858a4..1c97f2a5296 100644 --- a/packages/frontend/src/components/MkUploaderDialog.vue +++ b/packages/frontend/src/components/MkUploaderDialog.vue @@ -376,9 +376,9 @@ function showMenu(ev: MouseEvent, item: typeof items.value[0]) { text: preset.name, active: computed(() => item.watermarkPresetId === preset.id), action: () => changeWatermarkPreset(preset.id), - })), { - type: 'divider', - }, { + })), ...(prefer.s.watermarkPresets.length > 0 ? [{ + type: 'divider' as const, + }] : []), { type: 'button', icon: 'ti ti-plus', text: i18n.ts.add, From 86b4ae37bc9375ed03587b170561e93b380c0d27 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Wed, 4 Jun 2025 09:15:13 +0900 Subject: [PATCH 10/18] =?UTF-8?q?fix:=20=E3=82=A2=E3=83=83=E3=83=97?= =?UTF-8?q?=E3=83=AD=E3=83=BC=E3=83=80=E3=83=BC=E3=83=80=E3=82=A4=E3=82=A2?= =?UTF-8?q?=E3=83=AD=E3=82=B0=E3=81=AE=E6=A9=9F=E8=83=BD=E8=A8=AD=E5=AE=9A?= =?UTF-8?q?=E3=81=A7=E3=82=A6=E3=82=A9=E3=83=BC=E3=82=BF=E3=83=BC=E3=83=9E?= =?UTF-8?q?=E3=83=BC=E3=82=AF=E3=81=8C=E7=84=A1=E5=8A=B9=E3=81=AA=E5=A0=B4?= =?UTF-8?q?=E5=90=88=E3=81=A7=E3=82=82=E3=83=87=E3=83=95=E3=82=A9=E3=83=AB?= =?UTF-8?q?=E3=83=88=E3=81=AE=E3=83=97=E3=83=AA=E3=82=BB=E3=83=83=E3=83=88?= =?UTF-8?q?=E3=81=8C=E9=81=A9=E7=94=A8=E3=81=95=E3=82=8C=E3=81=A6=E3=81=97?= =?UTF-8?q?=E3=81=BE=E3=81=86=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../frontend/src/components/MkUploaderDialog.vue | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/frontend/src/components/MkUploaderDialog.vue b/packages/frontend/src/components/MkUploaderDialog.vue index 1c97f2a5296..3b5b0125936 100644 --- a/packages/frontend/src/components/MkUploaderDialog.vue +++ b/packages/frontend/src/components/MkUploaderDialog.vue @@ -157,7 +157,7 @@ const emit = defineEmits<{ (ev: 'closed'): void; }>(); -const items = ref<{ +type UploaderItem = { id: string; name: string; uploadName?: string; @@ -174,7 +174,9 @@ const items = ref<{ file: File; watermarkPresetId: string | null; abort?: (() => void) | null; -}[]>([]); +}; + +const items = ref([]); const dialog = useTemplateRef('dialog'); @@ -268,7 +270,7 @@ async function done() { dialog.value?.close(); } -function showMenu(ev: MouseEvent, item: typeof items.value[0]) { +function showMenu(ev: MouseEvent, item: UploaderItem) { const menu: MenuItem[] = []; menu.push({ @@ -624,9 +626,9 @@ function initializeFile(file: File) { uploaded: null, uploadFailed: false, compressionLevel: prefer.s.defaultImageCompressionLevel, - watermarkPresetId: prefer.s.defaultWatermarkPresetId, + watermarkPresetId: uploaderFeatures.value.watermark ? prefer.s.defaultWatermarkPresetId : null, file: markRaw(file), - }; + } satisfies UploaderItem; items.value.push(item); preprocess(item).then(() => { triggerRef(items); From 9e4a408d7a32e6800f2ae8b4c75acf81dccec755 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Wed, 4 Jun 2025 09:23:25 +0900 Subject: [PATCH 11/18] fix lint --- packages/frontend/src/components/MkUploaderDialog.vue | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/frontend/src/components/MkUploaderDialog.vue b/packages/frontend/src/components/MkUploaderDialog.vue index 3b5b0125936..c14c39cf4e1 100644 --- a/packages/frontend/src/components/MkUploaderDialog.vue +++ b/packages/frontend/src/components/MkUploaderDialog.vue @@ -433,8 +433,7 @@ function showMenu(ev: MouseEvent, item: UploaderItem) { text: i18n.ts.high, active: computed(() => item.compressionLevel === 3), action: () => changeCompressionLevel(3), - }, - ], + }], }); } From c921aa56d9d409b4b5652dd26fde291ed53bef1f Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Wed, 4 Jun 2025 12:52:53 +0900 Subject: [PATCH 12/18] =?UTF-8?q?Revert=20"fix:=20=E3=82=B7=E3=82=A7?= =?UTF-8?q?=E3=83=BC=E3=83=80=E3=83=BC=E3=81=AE=E8=AA=AD=E3=81=BF=E8=BE=BC?= =?UTF-8?q?=E3=81=BF=E3=81=8C=E5=AE=8C=E4=BA=86=E3=81=97=E3=81=A6=E3=81=8B?= =?UTF-8?q?=E3=82=89=E3=83=AC=E3=83=B3=E3=83=80=E3=83=AA=E3=83=B3=E3=82=B0?= =?UTF-8?q?=E3=82=92=E8=A1=8C=E3=81=86=E3=82=88=E3=81=86=E3=81=AB"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit e06f37a7d453ca581858252eae422d8a9e470dc3. --- .../src/components/MkImageEffectorDialog.vue | 7 +-- .../components/MkWatermarkEditorDialog.vue | 14 +---- .../utility/image-effector/ImageEffector.ts | 60 +++++++++---------- 3 files changed, 31 insertions(+), 50 deletions(-) diff --git a/packages/frontend/src/components/MkImageEffectorDialog.vue b/packages/frontend/src/components/MkImageEffectorDialog.vue index 5605baff514..de2c92bbd61 100644 --- a/packages/frontend/src/components/MkImageEffectorDialog.vue +++ b/packages/frontend/src/components/MkImageEffectorDialog.vue @@ -20,7 +20,6 @@ SPDX-License-Identifier: AGPL-3.0-only
-
{{ i18n.ts.preview }}
@@ -75,8 +74,6 @@ const emit = defineEmits<{ const dialog = useTemplateRef('dialog'); -const canvasLoading = ref(false); - async function cancel() { if (layers.length > 0) { const { canceled } = await os.confirm({ @@ -94,9 +91,7 @@ const layers = reactive([]); watch(layers, async () => { if (renderer != null) { - canvasLoading.value = true; - await renderer.setLayers(layers); - canvasLoading.value = false; + renderer.setLayers(layers); } }, { deep: true }); diff --git a/packages/frontend/src/components/MkWatermarkEditorDialog.vue b/packages/frontend/src/components/MkWatermarkEditorDialog.vue index 46d952ce903..db231f90d75 100644 --- a/packages/frontend/src/components/MkWatermarkEditorDialog.vue +++ b/packages/frontend/src/components/MkWatermarkEditorDialog.vue @@ -20,7 +20,6 @@ SPDX-License-Identifier: AGPL-3.0-only
-
{{ i18n.ts.preview }}
@@ -90,8 +89,6 @@ import { genId } from '@/utility/id.js'; const $i = ensureSignin(); -const canvasLoading = ref(true); - function createTextLayer(): WatermarkPreset['layers'][number] { return { id: genId(), @@ -235,13 +232,6 @@ let imageBitmap: ImageBitmap | null = null; async function initRenderer() { if (canvasEl.value == null) return; - canvasLoading.value = true; - - await Promise.all([ - sampleImage_3_2_loading, - sampleImage_2_3_loading, - ]); - if (sampleImageType.value === '3_2') { renderer = new WatermarkRenderer({ canvas: canvasEl.value, @@ -280,9 +270,7 @@ async function initRenderer() { await renderer!.setLayers(preset.layers); - await renderer!.render(); - - canvasLoading.value = false; + renderer!.render(); } onMounted(async () => { diff --git a/packages/frontend/src/utility/image-effector/ImageEffector.ts b/packages/frontend/src/utility/image-effector/ImageEffector.ts index 63f5d6fa4b0..282f36778fc 100644 --- a/packages/frontend/src/utility/image-effector/ImageEffector.ts +++ b/packages/frontend/src/utility/image-effector/ImageEffector.ts @@ -196,35 +196,40 @@ export class ImageEffector { - let shaderProgram = this.shaderCache.get(fx.id); - if (shaderProgram) return shaderProgram; + private async renderLayer(layer: ImageEffectorLayer, preTexture: WebGLTexture) { + const gl = this.gl; + + const fx = this.fxs.find(fx => fx.id === layer.fxId); + if (fx == null) return; + + const cachedShader = this.shaderCache.get(fx.id); + let shaderProgram: WebGLProgram; - let shaderSource: string; - if (typeof fx.shader === 'string') { - shaderSource = fx.shader; + if (cachedShader != null) { + shaderProgram = cachedShader; } else { - shaderSource = await fx.shader(); - } - shaderProgram = this.initShaderProgram(`#version 300 es - in vec2 position; - out vec2 in_uv; + let shaderSource: string; - void main() { - in_uv = (position + 1.0) / 2.0; - gl_Position = vec4(position, 0.0, 1.0); + if (typeof fx.shader === 'string') { + shaderSource = fx.shader; + } else { + shaderSource = await fx.shader(); } - `, shaderSource); - this.shaderCache.set(fx.id, shaderProgram); - return shaderProgram; - } - private async renderLayer(layer: ImageEffectorLayer, preTexture: WebGLTexture) { - const gl = this.gl; - const fx = this.fxs.find(fx => fx.id === layer.fxId); - if (fx == null) return; + shaderProgram = this.initShaderProgram(`#version 300 es + in vec2 position; + out vec2 in_uv; - const shaderProgram = await this.getOrLoadShaderProgram(fx); + void main() { + in_uv = (position + 1.0) / 2.0; + gl_Position = vec4(position, 0.0, 1.0); + } + `, shaderSource); + } + + if (cachedShader == null) { + this.shaderCache.set(fx.id, shaderProgram); + } gl.useProgram(shaderProgram); @@ -263,13 +268,6 @@ export class ImageEffector { - const fx = this.fxs.find(fx => fx.id === layer.fxId); - if (!fx) return; - await this.getOrLoadShaderProgram(fx); - })); - { gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, this.originalImageTexture); @@ -361,7 +359,7 @@ export class ImageEffector Date: Wed, 4 Jun 2025 12:52:59 +0900 Subject: [PATCH 13/18] =?UTF-8?q?Revert=20"fix:=20glsl=E3=81=AE=E3=83=90?= =?UTF-8?q?=E3=83=BC=E3=82=B8=E3=83=A7=E3=83=B3=E8=A1=A8=E8=A8=98=E3=81=AF?= =?UTF-8?q?=E6=9C=80=E5=88=9D=E3=81=AE=E8=A1=8C=E3=81=AB=E3=81=AA=E3=81=91?= =?UTF-8?q?=E3=82=8C=E3=81=B0=E3=81=AA=E3=82=89=E3=81=AA=E3=81=84"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit afcc37d886106c4acd545e4c2922e67f94e1037b. --- packages/frontend/src/utility/image-effector/fxs/checker.glsl | 3 +-- .../src/utility/image-effector/fxs/chromaticAberration.glsl | 3 +-- .../frontend/src/utility/image-effector/fxs/colorClamp.glsl | 3 +-- .../src/utility/image-effector/fxs/colorClampAdvanced.glsl | 3 +-- packages/frontend/src/utility/image-effector/fxs/distort.glsl | 3 +-- packages/frontend/src/utility/image-effector/fxs/glitch.glsl | 3 +-- .../frontend/src/utility/image-effector/fxs/grayscale.glsl | 3 +-- packages/frontend/src/utility/image-effector/fxs/invert.glsl | 3 +-- packages/frontend/src/utility/image-effector/fxs/mirror.glsl | 3 +-- packages/frontend/src/utility/image-effector/fxs/polkadot.glsl | 3 +-- packages/frontend/src/utility/image-effector/fxs/stripe.glsl | 3 +-- .../frontend/src/utility/image-effector/fxs/threshold.glsl | 3 +-- .../src/utility/image-effector/fxs/watermarkPlacement.glsl | 3 +-- .../frontend/src/utility/image-effector/fxs/zoomLines.glsl | 3 +-- 14 files changed, 14 insertions(+), 28 deletions(-) diff --git a/packages/frontend/src/utility/image-effector/fxs/checker.glsl b/packages/frontend/src/utility/image-effector/fxs/checker.glsl index 8a06f97ae34..b1625e6b17c 100644 --- a/packages/frontend/src/utility/image-effector/fxs/checker.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/checker.glsl @@ -1,10 +1,9 @@ -#version 300 es - /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ +#version 300 es precision mediump float; const float PI = 3.141592653589793; diff --git a/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl b/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl index 717925a0b2a..cc5d3ddaf38 100644 --- a/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl @@ -1,10 +1,9 @@ -#version 300 es - /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ +#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl b/packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl index 24dd0a12153..b0691241777 100644 --- a/packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl @@ -1,10 +1,9 @@ -#version 300 es - /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ +#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.glsl b/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.glsl index 64761b27b70..f9c0ed9d4df 100644 --- a/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.glsl @@ -1,10 +1,9 @@ -#version 300 es - /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ +#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/distort.glsl b/packages/frontend/src/utility/image-effector/fxs/distort.glsl index 29e9566a414..9f27fda5c97 100644 --- a/packages/frontend/src/utility/image-effector/fxs/distort.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/distort.glsl @@ -1,10 +1,9 @@ -#version 300 es - /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ +#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/glitch.glsl b/packages/frontend/src/utility/image-effector/fxs/glitch.glsl index 395b5fc17b1..1ce8c21d638 100644 --- a/packages/frontend/src/utility/image-effector/fxs/glitch.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/glitch.glsl @@ -1,10 +1,9 @@ -#version 300 es - /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ +#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/grayscale.glsl b/packages/frontend/src/utility/image-effector/fxs/grayscale.glsl index 206ad115d39..4d37e339614 100644 --- a/packages/frontend/src/utility/image-effector/fxs/grayscale.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/grayscale.glsl @@ -1,10 +1,9 @@ -#version 300 es - /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ +#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/invert.glsl b/packages/frontend/src/utility/image-effector/fxs/invert.glsl index 04e3ba21a5c..38726d3c87c 100644 --- a/packages/frontend/src/utility/image-effector/fxs/invert.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/invert.glsl @@ -1,10 +1,9 @@ -#version 300 es - /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ +#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/mirror.glsl b/packages/frontend/src/utility/image-effector/fxs/mirror.glsl index 222f9d567e5..4ef807aaba0 100644 --- a/packages/frontend/src/utility/image-effector/fxs/mirror.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/mirror.glsl @@ -1,10 +1,9 @@ -#version 300 es - /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ +#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/polkadot.glsl b/packages/frontend/src/utility/image-effector/fxs/polkadot.glsl index d3c5c0a5910..a7c7940d70f 100644 --- a/packages/frontend/src/utility/image-effector/fxs/polkadot.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/polkadot.glsl @@ -1,10 +1,9 @@ -#version 300 es - /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ +#version 300 es precision mediump float; const float PI = 3.141592653589793; diff --git a/packages/frontend/src/utility/image-effector/fxs/stripe.glsl b/packages/frontend/src/utility/image-effector/fxs/stripe.glsl index 43913f3755a..d54827658c4 100644 --- a/packages/frontend/src/utility/image-effector/fxs/stripe.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/stripe.glsl @@ -1,10 +1,9 @@ -#version 300 es - /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ +#version 300 es precision mediump float; const float PI = 3.141592653589793; diff --git a/packages/frontend/src/utility/image-effector/fxs/threshold.glsl b/packages/frontend/src/utility/image-effector/fxs/threshold.glsl index d1aa91ddc76..f938b2d520b 100644 --- a/packages/frontend/src/utility/image-effector/fxs/threshold.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/threshold.glsl @@ -1,10 +1,9 @@ -#version 300 es - /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ +#version 300 es precision mediump float; in vec2 in_uv; diff --git a/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl b/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl index 8b8e80118a2..1bcda303c53 100644 --- a/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl @@ -1,10 +1,9 @@ -#version 300 es - /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ +#version 300 es precision mediump float; const float PI = 3.141592653589793; diff --git a/packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl b/packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl index 25d8653b776..a5faf92bf4d 100644 --- a/packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl +++ b/packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl @@ -1,10 +1,9 @@ -#version 300 es - /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ +#version 300 es precision mediump float; in vec2 in_uv; From 4e5df659312026367079fa460eee07ccdfc89f6c Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Wed, 4 Jun 2025 12:53:07 +0900 Subject: [PATCH 14/18] =?UTF-8?q?Revert=20"refactor:=20=E3=82=B7=E3=82=A7?= =?UTF-8?q?=E3=83=BC=E3=83=80=E3=83=BC=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB?= =?UTF-8?q?=E3=82=92lazy-loading=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit a1ab2fa38c2b7485c069f9cd089bc7de59416c9d. --- .../src/components/MkImageEffectorDialog.vue | 12 +-- .../src/components/MkUploaderDialog.vue | 2 +- .../pages/settings/drive.WatermarkItem.vue | 4 +- .../utility/image-effector/ImageEffector.ts | 41 +++------- .../src/utility/image-effector/fxs.ts | 4 +- .../utility/image-effector/fxs/checker.glsl | 43 ---------- .../src/utility/image-effector/fxs/checker.ts | 42 +++++++++- .../fxs/chromaticAberration.glsl | 48 ----------- .../image-effector/fxs/chromaticAberration.ts | 47 ++++++++++- .../image-effector/fxs/colorClamp.glsl | 22 ----- .../utility/image-effector/fxs/colorClamp.ts | 21 ++++- .../fxs/colorClampAdvanced.glsl | 26 ------ .../image-effector/fxs/colorClampAdvanced.ts | 25 +++++- .../utility/image-effector/fxs/distort.glsl | 26 ------ .../src/utility/image-effector/fxs/distort.ts | 25 +++++- .../utility/image-effector/fxs/glitch.glsl | 33 -------- .../src/utility/image-effector/fxs/glitch.ts | 32 +++++++- .../utility/image-effector/fxs/grayscale.glsl | 22 ----- .../utility/image-effector/fxs/grayscale.ts | 21 ++++- .../utility/image-effector/fxs/invert.glsl | 23 ------ .../src/utility/image-effector/fxs/invert.ts | 22 ++++- .../utility/image-effector/fxs/mirror.glsl | 31 ------- .../src/utility/image-effector/fxs/mirror.ts | 30 ++++++- .../utility/image-effector/fxs/polkadot.glsl | 75 ----------------- .../utility/image-effector/fxs/polkadot.ts | 74 ++++++++++++++++- .../utility/image-effector/fxs/stripe.glsl | 45 ----------- .../src/utility/image-effector/fxs/stripe.ts | 44 +++++++++- .../utility/image-effector/fxs/threshold.glsl | 23 ------ .../utility/image-effector/fxs/threshold.ts | 22 ++++- .../fxs/watermarkPlacement.glsl | 80 ------------------- .../image-effector/fxs/watermarkPlacement.ts | 79 +++++++++++++++++- .../utility/image-effector/fxs/zoomLines.glsl | 33 -------- .../utility/image-effector/fxs/zoomLines.ts | 32 +++++++- packages/frontend/src/utility/watermark.ts | 6 +- 34 files changed, 529 insertions(+), 586 deletions(-) delete mode 100644 packages/frontend/src/utility/image-effector/fxs/checker.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/distort.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/glitch.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/grayscale.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/invert.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/mirror.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/polkadot.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/stripe.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/threshold.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl diff --git a/packages/frontend/src/components/MkImageEffectorDialog.vue b/packages/frontend/src/components/MkImageEffectorDialog.vue index de2c92bbd61..42502ba449c 100644 --- a/packages/frontend/src/components/MkImageEffectorDialog.vue +++ b/packages/frontend/src/components/MkImageEffectorDialog.vue @@ -166,7 +166,7 @@ onMounted(async () => { await renderer.setLayers(layers); - await renderer.render(); + renderer.render(); closeWaiting(); }); @@ -193,7 +193,7 @@ async function save() { await nextTick(); // waitingがレンダリングされるまで待つ renderer.changeResolution(imageBitmap.width, imageBitmap.height); // 本番レンダリングのためオリジナル画質に戻す - await renderer.render(); // toBlobの直前にレンダリングしないと何故か壊れる + renderer.render(); // toBlobの直前にレンダリングしないと何故か壊れる canvasEl.value.toBlob((blob) => { emit('ok', new File([blob!], `image-${Date.now()}.png`, { type: 'image/png' })); dialog.value?.close(); @@ -202,14 +202,14 @@ async function save() { } const enabled = ref(true); -watch(enabled, async () => { +watch(enabled, () => { if (renderer != null) { if (enabled.value) { - await renderer.setLayers(layers); + renderer.setLayers(layers); } else { - await renderer.setLayers([]); + renderer.setLayers([]); } - await renderer.render(); + renderer.render(); } }); diff --git a/packages/frontend/src/components/MkUploaderDialog.vue b/packages/frontend/src/components/MkUploaderDialog.vue index c14c39cf4e1..4c4bc26bfd0 100644 --- a/packages/frontend/src/components/MkUploaderDialog.vue +++ b/packages/frontend/src/components/MkUploaderDialog.vue @@ -561,7 +561,7 @@ async function preprocess(item: (typeof items)['value'][number]): Promise await renderer.setLayers(preset.layers); - await renderer.render(); + renderer.render(); file = await new Promise((resolve) => { canvas.toBlob((blob) => { diff --git a/packages/frontend/src/pages/settings/drive.WatermarkItem.vue b/packages/frontend/src/pages/settings/drive.WatermarkItem.vue index 7123b214f1f..b466f35fc5a 100644 --- a/packages/frontend/src/pages/settings/drive.WatermarkItem.vue +++ b/packages/frontend/src/pages/settings/drive.WatermarkItem.vue @@ -80,7 +80,7 @@ onMounted(() => { await renderer.setLayers(props.preset.layers); - await renderer.render(); + renderer.render(); }, { immediate: true }); }; }); @@ -95,7 +95,7 @@ onUnmounted(() => { watch(() => props.preset, async () => { if (renderer != null) { await renderer.setLayers(props.preset.layers); - await renderer.render(); + renderer.render(); } }, { deep: true }); diff --git a/packages/frontend/src/utility/image-effector/ImageEffector.ts b/packages/frontend/src/utility/image-effector/ImageEffector.ts index 282f36778fc..319dada09a1 100644 --- a/packages/frontend/src/utility/image-effector/ImageEffector.ts +++ b/packages/frontend/src/utility/image-effector/ImageEffector.ts @@ -27,7 +27,7 @@ export function defineImageEffectorFx = { id: ID; name: string; - shader: string | (() => Promise); + shader: string; uniforms: US; params: PS, main: (ctx: { @@ -196,37 +196,22 @@ export class ImageEffector fx.id === layer.fxId); if (fx == null) return; const cachedShader = this.shaderCache.get(fx.id); - let shaderProgram: WebGLProgram; - - if (cachedShader != null) { - shaderProgram = cachedShader; - } else { - let shaderSource: string; + const shaderProgram = cachedShader ?? this.initShaderProgram(`#version 300 es + in vec2 position; + out vec2 in_uv; - if (typeof fx.shader === 'string') { - shaderSource = fx.shader; - } else { - shaderSource = await fx.shader(); + void main() { + in_uv = (position + 1.0) / 2.0; + gl_Position = vec4(position, 0.0, 1.0); } - - shaderProgram = this.initShaderProgram(`#version 300 es - in vec2 position; - out vec2 in_uv; - - void main() { - in_uv = (position + 1.0) / 2.0; - gl_Position = vec4(position, 0.0, 1.0); - } - `, shaderSource); - } - + `, fx.shader); if (cachedShader == null) { this.shaderCache.set(fx.id, shaderProgram); } @@ -245,7 +230,7 @@ export class ImageEffector { + Object.entries(fx.params).map(([key, param]) => { return [key, layer.params[key] ?? param.default]; }), ), @@ -253,7 +238,7 @@ export class ImageEffector { + Object.entries(fx.params).map(([k, v]) => { if (v.type !== 'texture') return [k, null]; const param = getValue(layer.params, k); if (param == null) return [k, null]; @@ -265,7 +250,7 @@ export class ImageEffector>; +] as const satisfies ImageEffectorFx[]; export const WATERMARK_FXS = [ FX_watermarkPlacement, FX_stripe, FX_polkadot, FX_checker, -] satisfies ReadonlyArray>; +] as const satisfies ImageEffectorFx[]; diff --git a/packages/frontend/src/utility/image-effector/fxs/checker.glsl b/packages/frontend/src/utility/image-effector/fxs/checker.glsl deleted file mode 100644 index b1625e6b17c..00000000000 --- a/packages/frontend/src/utility/image-effector/fxs/checker.glsl +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -#version 300 es -precision mediump float; - -const float PI = 3.141592653589793; -const float TWO_PI = 6.283185307179586; -const float HALF_PI = 1.5707963267948966; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform float u_angle; -uniform float u_scale; -uniform vec3 u_color; -uniform float u_opacity; -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float x_ratio = max(in_resolution.x / in_resolution.y, 1.0); - float y_ratio = max(in_resolution.y / in_resolution.x, 1.0); - - float angle = -(u_angle * PI); - vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio); - vec2 rotatedUV = vec2( - centeredUv.x * cos(angle) - centeredUv.y * sin(angle), - centeredUv.x * sin(angle) + centeredUv.y * cos(angle) - ); - - float fmodResult = mod(floor(u_scale * rotatedUV.x) + floor(u_scale * rotatedUV.y), 2.0); - float fin = max(sign(fmodResult), 0.0); - - out_color = vec4( - mix(in_color.r, u_color.r, fin * u_opacity), - mix(in_color.g, u_color.g, fin * u_opacity), - mix(in_color.b, u_color.b, fin * u_opacity), - in_color.a - ); -} diff --git a/packages/frontend/src/utility/image-effector/fxs/checker.ts b/packages/frontend/src/utility/image-effector/fxs/checker.ts index 9b1210fd56f..b799bd0d13d 100644 --- a/packages/frontend/src/utility/image-effector/fxs/checker.ts +++ b/packages/frontend/src/utility/image-effector/fxs/checker.ts @@ -6,10 +6,50 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; +const shader = `#version 300 es +precision mediump float; + +const float PI = 3.141592653589793; +const float TWO_PI = 6.283185307179586; +const float HALF_PI = 1.5707963267948966; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform float u_angle; +uniform float u_scale; +uniform vec3 u_color; +uniform float u_opacity; +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float x_ratio = max(in_resolution.x / in_resolution.y, 1.0); + float y_ratio = max(in_resolution.y / in_resolution.x, 1.0); + + float angle = -(u_angle * PI); + vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio); + vec2 rotatedUV = vec2( + centeredUv.x * cos(angle) - centeredUv.y * sin(angle), + centeredUv.x * sin(angle) + centeredUv.y * cos(angle) + ); + + float fmodResult = mod(floor(u_scale * rotatedUV.x) + floor(u_scale * rotatedUV.y), 2.0); + float fin = max(sign(fmodResult), 0.0); + + out_color = vec4( + mix(in_color.r, u_color.r, fin * u_opacity), + mix(in_color.g, u_color.g, fin * u_opacity), + mix(in_color.b, u_color.b, fin * u_opacity), + in_color.a + ); +} +`; + export const FX_checker = defineImageEffectorFx({ id: 'checker' as const, name: i18n.ts._imageEffector._fxs.checker, - shader: () => import('./checker.glsl?raw').then(m => m.default), + shader, uniforms: ['angle', 'scale', 'color', 'opacity'] as const, params: { angle: { diff --git a/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl b/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl deleted file mode 100644 index cc5d3ddaf38..00000000000 --- a/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -out vec4 out_color; -uniform float u_amount; -uniform float u_start; -uniform bool u_normalize; - -void main() { - int samples = 64; - float r_strength = 1.0; - float g_strength = 1.5; - float b_strength = 2.0; - - vec2 size = vec2(in_resolution.x, in_resolution.y); - - vec4 accumulator = vec4(0.0); - float normalisedValue = length((in_uv - 0.5) * 2.0); - float strength = clamp((normalisedValue - u_start) * (1.0 / (1.0 - u_start)), 0.0, 1.0); - - vec2 vector = (u_normalize ? normalize(in_uv - vec2(0.5)) : in_uv - vec2(0.5)); - vec2 velocity = vector * strength * u_amount; - - vec2 rOffset = -vector * strength * (u_amount * r_strength); - vec2 gOffset = -vector * strength * (u_amount * g_strength); - vec2 bOffset = -vector * strength * (u_amount * b_strength); - - for (int i = 0; i < samples; i++) { - accumulator.r += texture(in_texture, in_uv + rOffset).r; - rOffset -= velocity / float(samples); - - accumulator.g += texture(in_texture, in_uv + gOffset).g; - gOffset -= velocity / float(samples); - - accumulator.b += texture(in_texture, in_uv + bOffset).b; - bOffset -= velocity / float(samples); - } - - out_color = vec4(vec3(accumulator / float(samples)), 1.0); -} diff --git a/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.ts b/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.ts index 905d82bd6d0..82d7d883aa9 100644 --- a/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.ts +++ b/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.ts @@ -6,10 +6,55 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; +const shader = `#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +out vec4 out_color; +uniform float u_amount; +uniform float u_start; +uniform bool u_normalize; + +void main() { + int samples = 64; + float r_strength = 1.0; + float g_strength = 1.5; + float b_strength = 2.0; + + vec2 size = vec2(in_resolution.x, in_resolution.y); + + vec4 accumulator = vec4(0.0); + float normalisedValue = length((in_uv - 0.5) * 2.0); + float strength = clamp((normalisedValue - u_start) * (1.0 / (1.0 - u_start)), 0.0, 1.0); + + vec2 vector = (u_normalize ? normalize(in_uv - vec2(0.5)) : in_uv - vec2(0.5)); + vec2 velocity = vector * strength * u_amount; + + vec2 rOffset = -vector * strength * (u_amount * r_strength); + vec2 gOffset = -vector * strength * (u_amount * g_strength); + vec2 bOffset = -vector * strength * (u_amount * b_strength); + + for (int i = 0; i < samples; i++) { + accumulator.r += texture(in_texture, in_uv + rOffset).r; + rOffset -= velocity / float(samples); + + accumulator.g += texture(in_texture, in_uv + gOffset).g; + gOffset -= velocity / float(samples); + + accumulator.b += texture(in_texture, in_uv + bOffset).b; + bOffset -= velocity / float(samples); + } + + out_color = vec4(vec3(accumulator / float(samples)), 1.0); +} +`; + export const FX_chromaticAberration = defineImageEffectorFx({ id: 'chromaticAberration' as const, name: i18n.ts._imageEffector._fxs.chromaticAberration, - shader: () => import('./chromaticAberration.glsl?raw').then(m => m.default), + shader, uniforms: ['amount', 'start', 'normalize'] as const, params: { normalize: { diff --git a/packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl b/packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl deleted file mode 100644 index b0691241777..00000000000 --- a/packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform float u_max; -uniform float u_min; -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float r = min(max(in_color.r, u_min), u_max); - float g = min(max(in_color.g, u_min), u_max); - float b = min(max(in_color.b, u_min), u_max); - out_color = vec4(r, g, b, in_color.a); -} diff --git a/packages/frontend/src/utility/image-effector/fxs/colorClamp.ts b/packages/frontend/src/utility/image-effector/fxs/colorClamp.ts index b53def8a817..5393d73df0b 100644 --- a/packages/frontend/src/utility/image-effector/fxs/colorClamp.ts +++ b/packages/frontend/src/utility/image-effector/fxs/colorClamp.ts @@ -6,10 +6,29 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; +const shader = `#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform float u_max; +uniform float u_min; +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float r = min(max(in_color.r, u_min), u_max); + float g = min(max(in_color.g, u_min), u_max); + float b = min(max(in_color.b, u_min), u_max); + out_color = vec4(r, g, b, in_color.a); +} +`; + export const FX_colorClamp = defineImageEffectorFx({ id: 'colorClamp' as const, name: i18n.ts._imageEffector._fxs.colorClamp, - shader: () => import('./colorClamp.glsl?raw').then(m => m.default), + shader, uniforms: ['max', 'min'] as const, params: { max: { diff --git a/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.glsl b/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.glsl deleted file mode 100644 index f9c0ed9d4df..00000000000 --- a/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.glsl +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform float u_rMax; -uniform float u_rMin; -uniform float u_gMax; -uniform float u_gMin; -uniform float u_bMax; -uniform float u_bMin; -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float r = min(max(in_color.r, u_rMin), u_rMax); - float g = min(max(in_color.g, u_gMin), u_gMax); - float b = min(max(in_color.b, u_bMin), u_bMax); - out_color = vec4(r, g, b, in_color.a); -} diff --git a/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.ts b/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.ts index ea318ab0e20..c66d75a83fc 100644 --- a/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.ts +++ b/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.ts @@ -6,10 +6,33 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; +const shader = `#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform float u_rMax; +uniform float u_rMin; +uniform float u_gMax; +uniform float u_gMin; +uniform float u_bMax; +uniform float u_bMin; +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float r = min(max(in_color.r, u_rMin), u_rMax); + float g = min(max(in_color.g, u_gMin), u_gMax); + float b = min(max(in_color.b, u_bMin), u_bMax); + out_color = vec4(r, g, b, in_color.a); +} +`; + export const FX_colorClampAdvanced = defineImageEffectorFx({ id: 'colorClampAdvanced' as const, name: i18n.ts._imageEffector._fxs.colorClampAdvanced, - shader: () => import('./colorClampAdvanced.glsl?raw').then(m => m.default), + shader, uniforms: ['rMax', 'rMin', 'gMax', 'gMin', 'bMax', 'bMin'] as const, params: { rMax: { diff --git a/packages/frontend/src/utility/image-effector/fxs/distort.glsl b/packages/frontend/src/utility/image-effector/fxs/distort.glsl deleted file mode 100644 index 9f27fda5c97..00000000000 --- a/packages/frontend/src/utility/image-effector/fxs/distort.glsl +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform float u_phase; -uniform float u_frequency; -uniform float u_strength; -uniform int u_direction; // 0: vertical, 1: horizontal -out vec4 out_color; - -void main() { - float v = u_direction == 0 ? - sin(u_phase + in_uv.y * u_frequency) * u_strength : - sin(u_phase + in_uv.x * u_frequency) * u_strength; - vec4 in_color = u_direction == 0 ? - texture(in_texture, vec2(in_uv.x + v, in_uv.y)) : - texture(in_texture, vec2(in_uv.x, in_uv.y + v)); - out_color = in_color; -} diff --git a/packages/frontend/src/utility/image-effector/fxs/distort.ts b/packages/frontend/src/utility/image-effector/fxs/distort.ts index 21ec4e130af..f91287c0386 100644 --- a/packages/frontend/src/utility/image-effector/fxs/distort.ts +++ b/packages/frontend/src/utility/image-effector/fxs/distort.ts @@ -6,10 +6,33 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; +const shader = `#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform float u_phase; +uniform float u_frequency; +uniform float u_strength; +uniform int u_direction; // 0: vertical, 1: horizontal +out vec4 out_color; + +void main() { + float v = u_direction == 0 ? + sin(u_phase + in_uv.y * u_frequency) * u_strength : + sin(u_phase + in_uv.x * u_frequency) * u_strength; + vec4 in_color = u_direction == 0 ? + texture(in_texture, vec2(in_uv.x + v, in_uv.y)) : + texture(in_texture, vec2(in_uv.x, in_uv.y + v)); + out_color = in_color; +} +`; + export const FX_distort = defineImageEffectorFx({ id: 'distort' as const, name: i18n.ts._imageEffector._fxs.distort, - shader: () => import('./distort.glsl?raw').then(m => m.default), + shader, uniforms: ['phase', 'frequency', 'strength', 'direction'] as const, params: { direction: { diff --git a/packages/frontend/src/utility/image-effector/fxs/glitch.glsl b/packages/frontend/src/utility/image-effector/fxs/glitch.glsl deleted file mode 100644 index 1ce8c21d638..00000000000 --- a/packages/frontend/src/utility/image-effector/fxs/glitch.glsl +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform int u_amount; -uniform float u_shiftStrengths[128]; -uniform float u_shiftOrigins[128]; -uniform float u_shiftHeights[128]; -uniform float u_channelShift; -out vec4 out_color; - -void main() { - float v = 0.0; - - for (int i = 0; i < u_amount; i++) { - if (in_uv.y > (u_shiftOrigins[i] - u_shiftHeights[i]) && in_uv.y < (u_shiftOrigins[i] + u_shiftHeights[i])) { - v += u_shiftStrengths[i]; - } - } - - float r = texture(in_texture, vec2(in_uv.x + (v * (1.0 + u_channelShift)), in_uv.y)).r; - float g = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).g; - float b = texture(in_texture, vec2(in_uv.x + (v * (1.0 + (u_channelShift / 2.0))), in_uv.y)).b; - float a = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).a; - out_color = vec4(r, g, b, a); -} diff --git a/packages/frontend/src/utility/image-effector/fxs/glitch.ts b/packages/frontend/src/utility/image-effector/fxs/glitch.ts index 17b898b249d..e4939a43020 100644 --- a/packages/frontend/src/utility/image-effector/fxs/glitch.ts +++ b/packages/frontend/src/utility/image-effector/fxs/glitch.ts @@ -7,10 +7,40 @@ import seedrandom from 'seedrandom'; import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; +const shader = `#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform int u_amount; +uniform float u_shiftStrengths[128]; +uniform float u_shiftOrigins[128]; +uniform float u_shiftHeights[128]; +uniform float u_channelShift; +out vec4 out_color; + +void main() { + float v = 0.0; + + for (int i = 0; i < u_amount; i++) { + if (in_uv.y > (u_shiftOrigins[i] - u_shiftHeights[i]) && in_uv.y < (u_shiftOrigins[i] + u_shiftHeights[i])) { + v += u_shiftStrengths[i]; + } + } + + float r = texture(in_texture, vec2(in_uv.x + (v * (1.0 + u_channelShift)), in_uv.y)).r; + float g = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).g; + float b = texture(in_texture, vec2(in_uv.x + (v * (1.0 + (u_channelShift / 2.0))), in_uv.y)).b; + float a = texture(in_texture, vec2(in_uv.x + v, in_uv.y)).a; + out_color = vec4(r, g, b, a); +} +`; + export const FX_glitch = defineImageEffectorFx({ id: 'glitch' as const, name: i18n.ts._imageEffector._fxs.glitch, - shader: () => import('./glitch.glsl?raw').then(m => m.default), + shader, uniforms: ['amount', 'channelShift'] as const, params: { amount: { diff --git a/packages/frontend/src/utility/image-effector/fxs/grayscale.glsl b/packages/frontend/src/utility/image-effector/fxs/grayscale.glsl deleted file mode 100644 index 4d37e339614..00000000000 --- a/packages/frontend/src/utility/image-effector/fxs/grayscale.glsl +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -out vec4 out_color; - -float getBrightness(vec4 color) { - return (color.r + color.g + color.b) / 3.0; -} - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float brightness = getBrightness(in_color); - out_color = vec4(brightness, brightness, brightness, in_color.a); -} diff --git a/packages/frontend/src/utility/image-effector/fxs/grayscale.ts b/packages/frontend/src/utility/image-effector/fxs/grayscale.ts index 38c2230a278..8f33706ae71 100644 --- a/packages/frontend/src/utility/image-effector/fxs/grayscale.ts +++ b/packages/frontend/src/utility/image-effector/fxs/grayscale.ts @@ -6,10 +6,29 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; +const shader = `#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +out vec4 out_color; + +float getBrightness(vec4 color) { + return (color.r + color.g + color.b) / 3.0; +} + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float brightness = getBrightness(in_color); + out_color = vec4(brightness, brightness, brightness, in_color.a); +} +`; + export const FX_grayscale = defineImageEffectorFx({ id: 'grayscale' as const, name: i18n.ts._imageEffector._fxs.grayscale, - shader: () => import('./grayscale.glsl?raw').then(m => m.default), + shader, uniforms: [] as const, params: { }, diff --git a/packages/frontend/src/utility/image-effector/fxs/invert.glsl b/packages/frontend/src/utility/image-effector/fxs/invert.glsl deleted file mode 100644 index 38726d3c87c..00000000000 --- a/packages/frontend/src/utility/image-effector/fxs/invert.glsl +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform bool u_r; -uniform bool u_g; -uniform bool u_b; -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - out_color.r = u_r ? 1.0 - in_color.r : in_color.r; - out_color.g = u_g ? 1.0 - in_color.g : in_color.g; - out_color.b = u_b ? 1.0 - in_color.b : in_color.b; - out_color.a = in_color.a; -} diff --git a/packages/frontend/src/utility/image-effector/fxs/invert.ts b/packages/frontend/src/utility/image-effector/fxs/invert.ts index 65e6e8d4c7a..220a2dea303 100644 --- a/packages/frontend/src/utility/image-effector/fxs/invert.ts +++ b/packages/frontend/src/utility/image-effector/fxs/invert.ts @@ -6,10 +6,30 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; +const shader = `#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform bool u_r; +uniform bool u_g; +uniform bool u_b; +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + out_color.r = u_r ? 1.0 - in_color.r : in_color.r; + out_color.g = u_g ? 1.0 - in_color.g : in_color.g; + out_color.b = u_b ? 1.0 - in_color.b : in_color.b; + out_color.a = in_color.a; +} +`; + export const FX_invert = defineImageEffectorFx({ id: 'invert' as const, name: i18n.ts._imageEffector._fxs.invert, - shader: () => import('./invert.glsl?raw').then(m => m.default), + shader, uniforms: ['r', 'g', 'b'] as const, params: { r: { diff --git a/packages/frontend/src/utility/image-effector/fxs/mirror.glsl b/packages/frontend/src/utility/image-effector/fxs/mirror.glsl deleted file mode 100644 index 4ef807aaba0..00000000000 --- a/packages/frontend/src/utility/image-effector/fxs/mirror.glsl +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform int u_h; -uniform int u_v; -out vec4 out_color; - -void main() { - vec2 uv = in_uv; - if (u_h == -1 && in_uv.x > 0.5) { - uv.x = 1.0 - uv.x; - } - if (u_h == 1 && in_uv.x < 0.5) { - uv.x = 1.0 - uv.x; - } - if (u_v == -1 && in_uv.y > 0.5) { - uv.y = 1.0 - uv.y; - } - if (u_v == 1 && in_uv.y < 0.5) { - uv.y = 1.0 - uv.y; - } - out_color = texture(in_texture, uv); -} diff --git a/packages/frontend/src/utility/image-effector/fxs/mirror.ts b/packages/frontend/src/utility/image-effector/fxs/mirror.ts index 4220a6ac62d..5946a2e0dc9 100644 --- a/packages/frontend/src/utility/image-effector/fxs/mirror.ts +++ b/packages/frontend/src/utility/image-effector/fxs/mirror.ts @@ -6,10 +6,38 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; +const shader = `#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform int u_h; +uniform int u_v; +out vec4 out_color; + +void main() { + vec2 uv = in_uv; + if (u_h == -1 && in_uv.x > 0.5) { + uv.x = 1.0 - uv.x; + } + if (u_h == 1 && in_uv.x < 0.5) { + uv.x = 1.0 - uv.x; + } + if (u_v == -1 && in_uv.y > 0.5) { + uv.y = 1.0 - uv.y; + } + if (u_v == 1 && in_uv.y < 0.5) { + uv.y = 1.0 - uv.y; + } + out_color = texture(in_texture, uv); +} +`; + export const FX_mirror = defineImageEffectorFx({ id: 'mirror' as const, name: i18n.ts._imageEffector._fxs.mirror, - shader: () => import('./mirror.glsl?raw').then(m => m.default), + shader, uniforms: ['h', 'v'] as const, params: { h: { diff --git a/packages/frontend/src/utility/image-effector/fxs/polkadot.glsl b/packages/frontend/src/utility/image-effector/fxs/polkadot.glsl deleted file mode 100644 index a7c7940d70f..00000000000 --- a/packages/frontend/src/utility/image-effector/fxs/polkadot.glsl +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -#version 300 es -precision mediump float; - -const float PI = 3.141592653589793; -const float TWO_PI = 6.283185307179586; -const float HALF_PI = 1.5707963267948966; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform float u_angle; -uniform float u_scale; -uniform float u_major_radius; -uniform float u_major_opacity; -uniform float u_minor_divisions; -uniform float u_minor_radius; -uniform float u_minor_opacity; -uniform vec3 u_color; -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float x_ratio = max(in_resolution.x / in_resolution.y, 1.0); - float y_ratio = max(in_resolution.y / in_resolution.x, 1.0); - - float angle = -(u_angle * PI); - vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio); - vec2 rotatedUV = vec2( - centeredUv.x * cos(angle) - centeredUv.y * sin(angle), - centeredUv.x * sin(angle) + centeredUv.y * cos(angle) - ); - - float major_modX = mod(rotatedUV.x, (1.0 / u_scale)); - float major_modY = mod(rotatedUV.y, (1.0 / u_scale)); - float major_threshold = ((u_major_radius / 2.0) / u_scale); - if ( - length(vec2(major_modX, major_modY)) < major_threshold || - length(vec2((1.0 / u_scale) - major_modX, major_modY)) < major_threshold || - length(vec2(major_modX, (1.0 / u_scale) - major_modY)) < major_threshold || - length(vec2((1.0 / u_scale) - major_modX, (1.0 / u_scale) - major_modY)) < major_threshold - ) { - out_color = vec4( - mix(in_color.r, u_color.r, u_major_opacity), - mix(in_color.g, u_color.g, u_major_opacity), - mix(in_color.b, u_color.b, u_major_opacity), - in_color.a - ); - return; - } - - float minor_modX = mod(rotatedUV.x, (1.0 / u_scale / u_minor_divisions)); - float minor_modY = mod(rotatedUV.y, (1.0 / u_scale / u_minor_divisions)); - float minor_threshold = ((u_minor_radius / 2.0) / (u_minor_divisions * u_scale)); - if ( - length(vec2(minor_modX, minor_modY)) < minor_threshold || - length(vec2((1.0 / u_scale / u_minor_divisions) - minor_modX, minor_modY)) < minor_threshold || - length(vec2(minor_modX, (1.0 / u_scale / u_minor_divisions) - minor_modY)) < minor_threshold || - length(vec2((1.0 / u_scale / u_minor_divisions) - minor_modX, (1.0 / u_scale / u_minor_divisions) - minor_modY)) < minor_threshold - ) { - out_color = vec4( - mix(in_color.r, u_color.r, u_minor_opacity), - mix(in_color.g, u_color.g, u_minor_opacity), - mix(in_color.b, u_color.b, u_minor_opacity), - in_color.a - ); - return; - } - - out_color = in_color; -} diff --git a/packages/frontend/src/utility/image-effector/fxs/polkadot.ts b/packages/frontend/src/utility/image-effector/fxs/polkadot.ts index c6a4cff5cd9..198dd9bad01 100644 --- a/packages/frontend/src/utility/image-effector/fxs/polkadot.ts +++ b/packages/frontend/src/utility/image-effector/fxs/polkadot.ts @@ -6,10 +6,82 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; +const shader = `#version 300 es +precision mediump float; + +const float PI = 3.141592653589793; +const float TWO_PI = 6.283185307179586; +const float HALF_PI = 1.5707963267948966; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform float u_angle; +uniform float u_scale; +uniform float u_major_radius; +uniform float u_major_opacity; +uniform float u_minor_divisions; +uniform float u_minor_radius; +uniform float u_minor_opacity; +uniform vec3 u_color; +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float x_ratio = max(in_resolution.x / in_resolution.y, 1.0); + float y_ratio = max(in_resolution.y / in_resolution.x, 1.0); + + float angle = -(u_angle * PI); + vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio); + vec2 rotatedUV = vec2( + centeredUv.x * cos(angle) - centeredUv.y * sin(angle), + centeredUv.x * sin(angle) + centeredUv.y * cos(angle) + ); + + float major_modX = mod(rotatedUV.x, (1.0 / u_scale)); + float major_modY = mod(rotatedUV.y, (1.0 / u_scale)); + float major_threshold = ((u_major_radius / 2.0) / u_scale); + if ( + length(vec2(major_modX, major_modY)) < major_threshold || + length(vec2((1.0 / u_scale) - major_modX, major_modY)) < major_threshold || + length(vec2(major_modX, (1.0 / u_scale) - major_modY)) < major_threshold || + length(vec2((1.0 / u_scale) - major_modX, (1.0 / u_scale) - major_modY)) < major_threshold + ) { + out_color = vec4( + mix(in_color.r, u_color.r, u_major_opacity), + mix(in_color.g, u_color.g, u_major_opacity), + mix(in_color.b, u_color.b, u_major_opacity), + in_color.a + ); + return; + } + + float minor_modX = mod(rotatedUV.x, (1.0 / u_scale / u_minor_divisions)); + float minor_modY = mod(rotatedUV.y, (1.0 / u_scale / u_minor_divisions)); + float minor_threshold = ((u_minor_radius / 2.0) / (u_minor_divisions * u_scale)); + if ( + length(vec2(minor_modX, minor_modY)) < minor_threshold || + length(vec2((1.0 / u_scale / u_minor_divisions) - minor_modX, minor_modY)) < minor_threshold || + length(vec2(minor_modX, (1.0 / u_scale / u_minor_divisions) - minor_modY)) < minor_threshold || + length(vec2((1.0 / u_scale / u_minor_divisions) - minor_modX, (1.0 / u_scale / u_minor_divisions) - minor_modY)) < minor_threshold + ) { + out_color = vec4( + mix(in_color.r, u_color.r, u_minor_opacity), + mix(in_color.g, u_color.g, u_minor_opacity), + mix(in_color.b, u_color.b, u_minor_opacity), + in_color.a + ); + return; + } + + out_color = in_color; +} +`; + export const FX_polkadot = defineImageEffectorFx({ id: 'polkadot' as const, name: i18n.ts._imageEffector._fxs.polkadot, - shader: () => import('./polkadot.glsl?raw').then(m => m.default), + shader, uniforms: ['angle', 'scale', 'major_radius', 'major_opacity', 'minor_divisions', 'minor_radius', 'minor_opacity', 'color'] as const, params: { angle: { diff --git a/packages/frontend/src/utility/image-effector/fxs/stripe.glsl b/packages/frontend/src/utility/image-effector/fxs/stripe.glsl deleted file mode 100644 index d54827658c4..00000000000 --- a/packages/frontend/src/utility/image-effector/fxs/stripe.glsl +++ /dev/null @@ -1,45 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -#version 300 es -precision mediump float; - -const float PI = 3.141592653589793; -const float TWO_PI = 6.283185307179586; -const float HALF_PI = 1.5707963267948966; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform float u_angle; -uniform float u_frequency; -uniform float u_phase; -uniform float u_threshold; -uniform vec3 u_color; -uniform float u_opacity; -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float x_ratio = max(in_resolution.x / in_resolution.y, 1.0); - float y_ratio = max(in_resolution.y / in_resolution.x, 1.0); - - float angle = -(u_angle * PI); - vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio); - vec2 rotatedUV = vec2( - centeredUv.x * cos(angle) - centeredUv.y * sin(angle), - centeredUv.x * sin(angle) + centeredUv.y * cos(angle) - ); - - float phase = u_phase * TWO_PI; - float value = (1.0 + sin((rotatedUV.x * u_frequency - HALF_PI) + phase)) / 2.0; - value = value < u_threshold ? 1.0 : 0.0; - out_color = vec4( - mix(in_color.r, u_color.r, value * u_opacity), - mix(in_color.g, u_color.g, value * u_opacity), - mix(in_color.b, u_color.b, value * u_opacity), - in_color.a - ); -} diff --git a/packages/frontend/src/utility/image-effector/fxs/stripe.ts b/packages/frontend/src/utility/image-effector/fxs/stripe.ts index 46fb98db5e3..37766e185dc 100644 --- a/packages/frontend/src/utility/image-effector/fxs/stripe.ts +++ b/packages/frontend/src/utility/image-effector/fxs/stripe.ts @@ -6,10 +6,52 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; +const shader = `#version 300 es +precision mediump float; + +const float PI = 3.141592653589793; +const float TWO_PI = 6.283185307179586; +const float HALF_PI = 1.5707963267948966; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform float u_angle; +uniform float u_frequency; +uniform float u_phase; +uniform float u_threshold; +uniform vec3 u_color; +uniform float u_opacity; +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float x_ratio = max(in_resolution.x / in_resolution.y, 1.0); + float y_ratio = max(in_resolution.y / in_resolution.x, 1.0); + + float angle = -(u_angle * PI); + vec2 centeredUv = (in_uv - vec2(0.5, 0.5)) * vec2(x_ratio, y_ratio); + vec2 rotatedUV = vec2( + centeredUv.x * cos(angle) - centeredUv.y * sin(angle), + centeredUv.x * sin(angle) + centeredUv.y * cos(angle) + ); + + float phase = u_phase * TWO_PI; + float value = (1.0 + sin((rotatedUV.x * u_frequency - HALF_PI) + phase)) / 2.0; + value = value < u_threshold ? 1.0 : 0.0; + out_color = vec4( + mix(in_color.r, u_color.r, value * u_opacity), + mix(in_color.g, u_color.g, value * u_opacity), + mix(in_color.b, u_color.b, value * u_opacity), + in_color.a + ); +} +`; + export const FX_stripe = defineImageEffectorFx({ id: 'stripe' as const, name: i18n.ts._imageEffector._fxs.stripe, - shader: () => import('./stripe.glsl?raw').then(m => m.default), + shader, uniforms: ['angle', 'frequency', 'phase', 'threshold', 'color', 'opacity'] as const, params: { angle: { diff --git a/packages/frontend/src/utility/image-effector/fxs/threshold.glsl b/packages/frontend/src/utility/image-effector/fxs/threshold.glsl deleted file mode 100644 index f938b2d520b..00000000000 --- a/packages/frontend/src/utility/image-effector/fxs/threshold.glsl +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform float u_r; -uniform float u_g; -uniform float u_b; -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float r = in_color.r < u_r ? 0.0 : 1.0; - float g = in_color.g < u_g ? 0.0 : 1.0; - float b = in_color.b < u_b ? 0.0 : 1.0; - out_color = vec4(r, g, b, in_color.a); -} diff --git a/packages/frontend/src/utility/image-effector/fxs/threshold.ts b/packages/frontend/src/utility/image-effector/fxs/threshold.ts index fc6d73dcb09..f2b8b107fda 100644 --- a/packages/frontend/src/utility/image-effector/fxs/threshold.ts +++ b/packages/frontend/src/utility/image-effector/fxs/threshold.ts @@ -6,10 +6,30 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; +const shader = `#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform float u_r; +uniform float u_g; +uniform float u_b; +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float r = in_color.r < u_r ? 0.0 : 1.0; + float g = in_color.g < u_g ? 0.0 : 1.0; + float b = in_color.b < u_b ? 0.0 : 1.0; + out_color = vec4(r, g, b, in_color.a); +} +`; + export const FX_threshold = defineImageEffectorFx({ id: 'threshold' as const, name: i18n.ts._imageEffector._fxs.threshold, - shader: () => import('./threshold.glsl?raw').then(m => m.default), + shader, uniforms: ['r', 'g', 'b'] as const, params: { r: { diff --git a/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl b/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl deleted file mode 100644 index 1bcda303c53..00000000000 --- a/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl +++ /dev/null @@ -1,80 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -#version 300 es -precision mediump float; - -const float PI = 3.141592653589793; -const float TWO_PI = 6.283185307179586; -const float HALF_PI = 1.5707963267948966; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform sampler2D u_texture_watermark; -uniform vec2 u_resolution_watermark; -uniform float u_scale; -uniform float u_angle; -uniform float u_opacity; -uniform bool u_repeat; -uniform int u_alignX; // 0: left, 1: center, 2: right -uniform int u_alignY; // 0: top, 1: center, 2: bottom -uniform int u_fitMode; // 0: contain, 1: cover -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float in_x_ratio = max(in_resolution.x / in_resolution.y, 1.0); - float in_y_ratio = max(in_resolution.y / in_resolution.x, 1.0); - - bool contain = u_fitMode == 0; - - float x_ratio = u_resolution_watermark.x / in_resolution.x; - float y_ratio = u_resolution_watermark.y / in_resolution.y; - - float aspect_ratio = contain ? - (min(x_ratio, y_ratio) / max(x_ratio, y_ratio)) : - (max(x_ratio, y_ratio) / min(x_ratio, y_ratio)); - - float x_scale = contain ? - (x_ratio > y_ratio ? 1.0 * u_scale : aspect_ratio * u_scale) : - (x_ratio > y_ratio ? aspect_ratio * u_scale : 1.0 * u_scale); - - float y_scale = contain ? - (y_ratio > x_ratio ? 1.0 * u_scale : aspect_ratio * u_scale) : - (y_ratio > x_ratio ? aspect_ratio * u_scale : 1.0 * u_scale); - - float x_offset = u_alignX == 0 ? x_scale / 2.0 : u_alignX == 2 ? 1.0 - (x_scale / 2.0) : 0.5; - float y_offset = u_alignY == 0 ? y_scale / 2.0 : u_alignY == 2 ? 1.0 - (y_scale / 2.0) : 0.5; - - float angle = -(u_angle * PI); - vec2 center = vec2(x_offset, y_offset); - //vec2 centeredUv = (in_uv - center) * vec2(in_x_ratio, in_y_ratio); - vec2 centeredUv = (in_uv - center); - vec2 rotatedUV = vec2( - centeredUv.x * cos(angle) - centeredUv.y * sin(angle), - centeredUv.x * sin(angle) + centeredUv.y * cos(angle) - ) + center; - - // trim - if (!u_repeat) { - bool isInside = rotatedUV.x > x_offset - (x_scale / 2.0) && rotatedUV.x < x_offset + (x_scale / 2.0) && - rotatedUV.y > y_offset - (y_scale / 2.0) && rotatedUV.y < y_offset + (y_scale / 2.0); - if (!isInside) { - out_color = in_color; - return; - } - } - - vec4 watermark_color = texture(u_texture_watermark, vec2( - (rotatedUV.x - (x_offset - (x_scale / 2.0))) / x_scale, - (rotatedUV.y - (y_offset - (y_scale / 2.0))) / y_scale - )); - - out_color.r = mix(in_color.r, watermark_color.r, u_opacity * watermark_color.a); - out_color.g = mix(in_color.g, watermark_color.g, u_opacity * watermark_color.a); - out_color.b = mix(in_color.b, watermark_color.b, u_opacity * watermark_color.a); - out_color.a = in_color.a * (1.0 - u_opacity * watermark_color.a) + watermark_color.a * u_opacity; -} diff --git a/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.ts b/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.ts index d0c901110da..1c1c95b0c57 100644 --- a/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.ts +++ b/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.ts @@ -5,10 +5,87 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; +const shader = `#version 300 es +precision mediump float; + +const float PI = 3.141592653589793; +const float TWO_PI = 6.283185307179586; +const float HALF_PI = 1.5707963267948966; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform sampler2D u_texture_watermark; +uniform vec2 u_resolution_watermark; +uniform float u_scale; +uniform float u_angle; +uniform float u_opacity; +uniform bool u_repeat; +uniform int u_alignX; // 0: left, 1: center, 2: right +uniform int u_alignY; // 0: top, 1: center, 2: bottom +uniform int u_fitMode; // 0: contain, 1: cover +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float in_x_ratio = max(in_resolution.x / in_resolution.y, 1.0); + float in_y_ratio = max(in_resolution.y / in_resolution.x, 1.0); + + bool contain = u_fitMode == 0; + + float x_ratio = u_resolution_watermark.x / in_resolution.x; + float y_ratio = u_resolution_watermark.y / in_resolution.y; + + float aspect_ratio = contain ? + (min(x_ratio, y_ratio) / max(x_ratio, y_ratio)) : + (max(x_ratio, y_ratio) / min(x_ratio, y_ratio)); + + float x_scale = contain ? + (x_ratio > y_ratio ? 1.0 * u_scale : aspect_ratio * u_scale) : + (x_ratio > y_ratio ? aspect_ratio * u_scale : 1.0 * u_scale); + + float y_scale = contain ? + (y_ratio > x_ratio ? 1.0 * u_scale : aspect_ratio * u_scale) : + (y_ratio > x_ratio ? aspect_ratio * u_scale : 1.0 * u_scale); + + float x_offset = u_alignX == 0 ? x_scale / 2.0 : u_alignX == 2 ? 1.0 - (x_scale / 2.0) : 0.5; + float y_offset = u_alignY == 0 ? y_scale / 2.0 : u_alignY == 2 ? 1.0 - (y_scale / 2.0) : 0.5; + + float angle = -(u_angle * PI); + vec2 center = vec2(x_offset, y_offset); + //vec2 centeredUv = (in_uv - center) * vec2(in_x_ratio, in_y_ratio); + vec2 centeredUv = (in_uv - center); + vec2 rotatedUV = vec2( + centeredUv.x * cos(angle) - centeredUv.y * sin(angle), + centeredUv.x * sin(angle) + centeredUv.y * cos(angle) + ) + center; + + // trim + if (!u_repeat) { + bool isInside = rotatedUV.x > x_offset - (x_scale / 2.0) && rotatedUV.x < x_offset + (x_scale / 2.0) && + rotatedUV.y > y_offset - (y_scale / 2.0) && rotatedUV.y < y_offset + (y_scale / 2.0); + if (!isInside) { + out_color = in_color; + return; + } + } + + vec4 watermark_color = texture(u_texture_watermark, vec2( + (rotatedUV.x - (x_offset - (x_scale / 2.0))) / x_scale, + (rotatedUV.y - (y_offset - (y_scale / 2.0))) / y_scale + )); + + out_color.r = mix(in_color.r, watermark_color.r, u_opacity * watermark_color.a); + out_color.g = mix(in_color.g, watermark_color.g, u_opacity * watermark_color.a); + out_color.b = mix(in_color.b, watermark_color.b, u_opacity * watermark_color.a); + out_color.a = in_color.a * (1.0 - u_opacity * watermark_color.a) + watermark_color.a * u_opacity; +} +`; + export const FX_watermarkPlacement = defineImageEffectorFx({ id: 'watermarkPlacement' as const, name: '(internal)', - shader: () => import('./watermarkPlacement.glsl?raw').then(m => m.default), + shader, uniforms: ['texture_watermark', 'resolution_watermark', 'scale', 'angle', 'opacity', 'repeat', 'alignX', 'alignY', 'fitMode'] as const, params: { cover: { diff --git a/packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl b/packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl deleted file mode 100644 index a5faf92bf4d..00000000000 --- a/packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -#version 300 es -precision mediump float; - -in vec2 in_uv; -uniform sampler2D in_texture; -uniform vec2 in_resolution; -uniform vec2 u_pos; -uniform float u_frequency; -uniform bool u_thresholdEnabled; -uniform float u_threshold; -uniform float u_maskSize; -uniform bool u_black; -out vec4 out_color; - -void main() { - vec4 in_color = texture(in_texture, in_uv); - float angle = atan(-u_pos.y + (in_uv.y), -u_pos.x + (in_uv.x)); - float t = (1.0 + sin(angle * u_frequency)) / 2.0; - if (u_thresholdEnabled) t = t < u_threshold ? 1.0 : 0.0; - float d = distance(in_uv * vec2(2.0, 2.0), u_pos * vec2(2.0, 2.0)); - float mask = d < u_maskSize ? 0.0 : ((d - u_maskSize) * (1.0 + (u_maskSize * 2.0))); - out_color = vec4( - mix(in_color.r, u_black ? 0.0 : 1.0, t * mask), - mix(in_color.g, u_black ? 0.0 : 1.0, t * mask), - mix(in_color.b, u_black ? 0.0 : 1.0, t * mask), - in_color.a - ); -} diff --git a/packages/frontend/src/utility/image-effector/fxs/zoomLines.ts b/packages/frontend/src/utility/image-effector/fxs/zoomLines.ts index b52b947055d..2613362a716 100644 --- a/packages/frontend/src/utility/image-effector/fxs/zoomLines.ts +++ b/packages/frontend/src/utility/image-effector/fxs/zoomLines.ts @@ -6,10 +6,40 @@ import { defineImageEffectorFx } from '../ImageEffector.js'; import { i18n } from '@/i18n.js'; +const shader = `#version 300 es +precision mediump float; + +in vec2 in_uv; +uniform sampler2D in_texture; +uniform vec2 in_resolution; +uniform vec2 u_pos; +uniform float u_frequency; +uniform bool u_thresholdEnabled; +uniform float u_threshold; +uniform float u_maskSize; +uniform bool u_black; +out vec4 out_color; + +void main() { + vec4 in_color = texture(in_texture, in_uv); + float angle = atan(-u_pos.y + (in_uv.y), -u_pos.x + (in_uv.x)); + float t = (1.0 + sin(angle * u_frequency)) / 2.0; + if (u_thresholdEnabled) t = t < u_threshold ? 1.0 : 0.0; + float d = distance(in_uv * vec2(2.0, 2.0), u_pos * vec2(2.0, 2.0)); + float mask = d < u_maskSize ? 0.0 : ((d - u_maskSize) * (1.0 + (u_maskSize * 2.0))); + out_color = vec4( + mix(in_color.r, u_black ? 0.0 : 1.0, t * mask), + mix(in_color.g, u_black ? 0.0 : 1.0, t * mask), + mix(in_color.b, u_black ? 0.0 : 1.0, t * mask), + in_color.a + ); +} +`; + export const FX_zoomLines = defineImageEffectorFx({ id: 'zoomLines' as const, name: i18n.ts._imageEffector._fxs.zoomLines, - shader: () => import('./zoomLines.glsl?raw').then(m => m.default), + shader, uniforms: ['pos', 'frequency', 'thresholdEnabled', 'threshold', 'maskSize', 'black'] as const, params: { x: { diff --git a/packages/frontend/src/utility/watermark.ts b/packages/frontend/src/utility/watermark.ts index eb96244d37f..a70e14d95d1 100644 --- a/packages/frontend/src/utility/watermark.ts +++ b/packages/frontend/src/utility/watermark.ts @@ -163,11 +163,11 @@ export class WatermarkRenderer { public async setLayers(layers: WatermarkPreset['layers']) { this.layers = layers; await this.effector.setLayers(this.makeImageEffectorLayers()); - await this.render(); + this.render(); } - public async render(): Promise { - await this.effector.render(); + public render(): void { + this.effector.render(); } /* From 5d87c039fb6541b91a665a1c07c2cf5d427ea80b Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Wed, 4 Jun 2025 13:32:09 +0900 Subject: [PATCH 15/18] =?UTF-8?q?fix:=20=E3=82=A6=E3=82=A9=E3=83=BC?= =?UTF-8?q?=E3=82=BF=E3=83=BC=E3=83=9E=E3=83=BC=E3=82=AF=E3=81=AEFX?= =?UTF-8?q?=E5=AE=9A=E7=BE=A9=E3=82=92=E5=88=86=E3=81=91=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/utility/image-effector/ImageEffector.ts | 4 ++-- .../frontend/src/utility/image-effector/fxs.ts | 7 ------- packages/frontend/src/utility/watermark.ts | 14 ++++++++++++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/frontend/src/utility/image-effector/ImageEffector.ts b/packages/frontend/src/utility/image-effector/ImageEffector.ts index 319dada09a1..80e3ff65de7 100644 --- a/packages/frontend/src/utility/image-effector/ImageEffector.ts +++ b/packages/frontend/src/utility/image-effector/ImageEffector.ts @@ -230,7 +230,7 @@ export class ImageEffector { + Object.entries(fx.params as ImageEffectorFxParamDefs).map(([key, param]) => { return [key, layer.params[key] ?? param.default]; }), ), @@ -238,7 +238,7 @@ export class ImageEffector { + Object.entries(fx.params as ImageEffectorFxParamDefs).map(([k, v]) => { if (v.type !== 'texture') return [k, null]; const param = getValue(layer.params, k); if (param == null) return [k, null]; diff --git a/packages/frontend/src/utility/image-effector/fxs.ts b/packages/frontend/src/utility/image-effector/fxs.ts index f391314abf3..5887a68c43e 100644 --- a/packages/frontend/src/utility/image-effector/fxs.ts +++ b/packages/frontend/src/utility/image-effector/fxs.ts @@ -35,10 +35,3 @@ export const FXS = [ FX_polkadot, FX_checker, ] as const satisfies ImageEffectorFx[]; - -export const WATERMARK_FXS = [ - FX_watermarkPlacement, - FX_stripe, - FX_polkadot, - FX_checker, -] as const satisfies ImageEffectorFx[]; diff --git a/packages/frontend/src/utility/watermark.ts b/packages/frontend/src/utility/watermark.ts index a70e14d95d1..f0b38684f06 100644 --- a/packages/frontend/src/utility/watermark.ts +++ b/packages/frontend/src/utility/watermark.ts @@ -3,10 +3,20 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { WATERMARK_FXS } from './image-effector/fxs.js'; -import type { ImageEffectorLayer } from '@/utility/image-effector/ImageEffector.js'; +import { FX_watermarkPlacement } from '@/utility/image-effector/fxs/watermarkPlacement.js'; +import { FX_stripe } from '@/utility/image-effector/fxs/stripe.js'; +import { FX_polkadot } from '@/utility/image-effector/fxs/polkadot.js'; +import { FX_checker } from '@/utility/image-effector/fxs/checker.js'; +import type { ImageEffectorFx, ImageEffectorLayer } from '@/utility/image-effector/ImageEffector.js'; import { ImageEffector } from '@/utility/image-effector/ImageEffector.js'; +const WATERMARK_FXS = [ + FX_watermarkPlacement, + FX_stripe, + FX_polkadot, + FX_checker, +] as const satisfies ImageEffectorFx[]; + export type WatermarkPreset = { id: string; name: string; From 9d3289521af46096fe4b500b61d08f0f2f828249 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 4 Jun 2025 16:21:47 +0900 Subject: [PATCH 16/18] Update packages/frontend/src/components/MkWatermarkEditorDialog.vue --- packages/frontend/src/components/MkWatermarkEditorDialog.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkWatermarkEditorDialog.vue b/packages/frontend/src/components/MkWatermarkEditorDialog.vue index db231f90d75..2d5ec2ed6f2 100644 --- a/packages/frontend/src/components/MkWatermarkEditorDialog.vue +++ b/packages/frontend/src/components/MkWatermarkEditorDialog.vue @@ -124,7 +124,7 @@ function createStripeLayer(): WatermarkPreset['layers'][number] { angle: 0.5, frequency: 10, threshold: 0.1, - color: [0, 0, 0], + color: [1, 1, 1], opacity: 0.75, }; } From e31d163bb8d3e3f4caba09d968e24fd330ce5506 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 4 Jun 2025 16:21:52 +0900 Subject: [PATCH 17/18] Update packages/frontend/src/components/MkWatermarkEditorDialog.vue --- packages/frontend/src/components/MkWatermarkEditorDialog.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkWatermarkEditorDialog.vue b/packages/frontend/src/components/MkWatermarkEditorDialog.vue index 2d5ec2ed6f2..67f14f1018c 100644 --- a/packages/frontend/src/components/MkWatermarkEditorDialog.vue +++ b/packages/frontend/src/components/MkWatermarkEditorDialog.vue @@ -140,7 +140,7 @@ function createPolkadotLayer(): WatermarkPreset['layers'][number] { majorOpacity: 0.75, minorOpacity: 0.5, minorDivisions: 4, - color: [0, 0, 0], + color: [1, 1, 1], opacity: 0.75, }; } From d11aad0619255b6151189c6dc881ce916de6d62d Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 4 Jun 2025 16:21:58 +0900 Subject: [PATCH 18/18] Update packages/frontend/src/components/MkWatermarkEditorDialog.vue --- packages/frontend/src/components/MkWatermarkEditorDialog.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkWatermarkEditorDialog.vue b/packages/frontend/src/components/MkWatermarkEditorDialog.vue index 67f14f1018c..206298b194b 100644 --- a/packages/frontend/src/components/MkWatermarkEditorDialog.vue +++ b/packages/frontend/src/components/MkWatermarkEditorDialog.vue @@ -151,7 +151,7 @@ function createCheckerLayer(): WatermarkPreset['layers'][number] { type: 'checker', angle: 0.5, scale: 3, - color: [0, 0, 0], + color: [1, 1, 1], opacity: 0.75, }; }