summaryrefslogtreecommitdiff
path: root/packages/frontend/src/utility/image-effector
diff options
context:
space:
mode:
authorsyuilo <4439005+syuilo@users.noreply.github.com>2025-11-06 20:25:17 +0900
committerGitHub <noreply@github.com>2025-11-06 20:25:17 +0900
commit4ba18690d7abd7eea086bb59e6cbcc8ead9e121a (patch)
tree7d25ec47d8711d945b08e3903642f2e982f40048 /packages/frontend/src/utility/image-effector
parentfix(frontend): improve startViewTransition handling (diff)
downloadmisskey-4ba18690d7abd7eea086bb59e6cbcc8ead9e121a.tar.gz
misskey-4ba18690d7abd7eea086bb59e6cbcc8ead9e121a.tar.bz2
misskey-4ba18690d7abd7eea086bb59e6cbcc8ead9e121a.zip
feat(frontend): EXIFフレーム機能 (#16725)
* wip * wip * Update ImageEffector.ts * Update image-label-renderer.ts * Update image-label-renderer.ts * wip * Update image-label-renderer.ts * wip * wip * wip * wip * wip * wip * wip * Update use-uploader.ts * Update watermark.ts * wip * wu * wip * Update image-frame-renderer.ts * wip * wip * Update image-frame-renderer.ts * Create ImageCompositor.ts * Update ImageCompositor.ts * wip * wip * Update ImageEffector.ts * wip * Update use-uploader.ts * wip * wip * wip * wip * Update fxs.ts * wip * wip * wip * Update CHANGELOG.md * wip * wip * Update MkImageEffectorDialog.vue * Update MkImageEffectorDialog.vue * Update MkImageFrameEditorDialog.vue * Update use-uploader.ts * improve error handling * Update use-uploader.ts * 🎨 * wip * wip * lazy load * lazy load * wip * wip * wip
Diffstat (limited to 'packages/frontend/src/utility/image-effector')
-rw-r--r--packages/frontend/src/utility/image-effector/ImageEffector.ts482
-rw-r--r--packages/frontend/src/utility/image-effector/fxs.ts82
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/blockNoise.glsl43
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/blockNoise.ts86
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/blur.glsl78
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/blur.ts83
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/checker.glsl43
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/checker.ts54
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl49
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/chromaticAberration.ts34
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/colorAdjust.glsl82
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/colorAdjust.ts69
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl29
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/colorClamp.ts43
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.ts79
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/distort.glsl30
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/distort.ts58
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/fill.glsl50
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/fill.ts89
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/grayscale.glsl22
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/grayscale.ts19
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/invert.glsl23
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/invert.ts37
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/mirror.glsl26
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/mirror.ts41
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/pixelate.glsl68
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/pixelate.ts83
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/polkadot.glsl75
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/polkadot.ts92
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/stripe.glsl45
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/stripe.ts66
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/tearing.glsl33
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/tearing.ts75
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/threshold.glsl23
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/threshold.ts46
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl147
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.ts94
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl48
-rw-r--r--packages/frontend/src/utility/image-effector/fxs/zoomLines.ts77
39 files changed, 80 insertions, 2623 deletions
diff --git a/packages/frontend/src/utility/image-effector/ImageEffector.ts b/packages/frontend/src/utility/image-effector/ImageEffector.ts
index 26c74bfae5..b4295c4637 100644
--- a/packages/frontend/src/utility/image-effector/ImageEffector.ts
+++ b/packages/frontend/src/utility/image-effector/ImageEffector.ts
@@ -3,18 +3,12 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import QRCodeStyling from 'qr-code-styling';
-import { url, host } from '@@/js/config.js';
-import { getProxiedImageUrl } from '../media-proxy.js';
-import { initShaderProgram } from '../webgl.js';
-import { ensureSignin } from '@/i.js';
+import { FXS } from './fxs.js';
+import type { ImageCompositorFunction, ImageCompositorLayer } from '@/lib/ImageCompositor.js';
+import { ImageCompositor } from '@/lib/ImageCompositor.js';
export type ImageEffectorRGB = [r: number, g: number, b: number];
-type ParamTypeToPrimitive = {
- [K in ImageEffectorFxParamDef['type']]: (ImageEffectorFxParamDef & { type: K })['default'];
-};
-
interface CommonParamDef {
type: string;
label?: string;
@@ -60,479 +54,77 @@ interface SeedParamDef extends CommonParamDef {
default: number;
};
-interface TextureParamDef extends CommonParamDef {
- type: 'texture';
- default: {
- type: 'text'; text: string | null;
- } | {
- type: 'url'; url: string | null;
- } | {
- type: 'qr'; data: string | null;
- } | null;
-};
-
interface ColorParamDef extends CommonParamDef {
type: 'color';
default: ImageEffectorRGB;
};
-type ImageEffectorFxParamDef = NumberParamDef | NumberEnumParamDef | BooleanParamDef | AlignParamDef | SeedParamDef | TextureParamDef | ColorParamDef;
+type ImageEffectorFxParamDef = NumberParamDef | NumberEnumParamDef | BooleanParamDef | AlignParamDef | SeedParamDef | ColorParamDef;
export type ImageEffectorFxParamDefs = Record<string, ImageEffectorFxParamDef>;
-export type GetParamType<T extends ImageEffectorFxParamDef> =
- T extends NumberEnumParamDef
- ? T['enum'][number]['value']
- : ParamTypeToPrimitive[T['type']];
-
-export type ParamsRecordTypeToDefRecord<PS extends ImageEffectorFxParamDefs> = {
- [K in keyof PS]: GetParamType<PS[K]>;
-};
-
-export function defineImageEffectorFx<ID extends string, PS extends ImageEffectorFxParamDefs, US extends string[]>(fx: ImageEffectorFx<ID, PS, US>) {
- return fx;
-}
+export type ImageEffectorLayer = {
+ [K in keyof typeof FXS]: {
+ id: string;
+ fxId: K;
+ params: Parameters<(typeof FXS)[K]['fn']['main']>[0]['params'];
+ };
+}[keyof typeof FXS];
-export type ImageEffectorFx<ID extends string = string, PS extends ImageEffectorFxParamDefs = ImageEffectorFxParamDefs, US extends string[] = string[]> = {
- id: ID;
+export type ImageEffectorUiDefinition<Fn extends ImageCompositorFunction<any> = ImageCompositorFunction> = {
name: string;
- shader: string;
- uniforms: US;
- params: PS,
- main: (ctx: {
- gl: WebGL2RenderingContext;
- program: WebGLProgram;
- params: ParamsRecordTypeToDefRecord<PS>;
- u: Record<US[number], WebGLUniformLocation>;
- width: number;
- height: number;
- textures: Record<string, {
- texture: WebGLTexture;
- width: number;
- height: number;
- } | null>;
- }) => void;
-};
-
-export type ImageEffectorLayer = {
- id: string;
- fxId: string;
- params: Record<string, any>;
+ params: Fn extends ImageCompositorFunction<infer P> ? {
+ [K in keyof P]: ImageEffectorFxParamDef;
+ } : never;
};
-function getValue<T extends keyof ParamTypeToPrimitive>(params: Record<string, any>, k: string): ParamTypeToPrimitive[T] {
- return params[k];
-}
+type ImageEffectorImageCompositor = ImageCompositor<{
+ [K in keyof typeof FXS]: typeof FXS[K]['fn'];
+}>;
-export class ImageEffector<IEX extends ReadonlyArray<ImageEffectorFx<any, any, any>>> {
- private gl: WebGL2RenderingContext;
+export class ImageEffector {
private canvas: HTMLCanvasElement | null = null;
- private renderWidth: number;
- private renderHeight: number;
- private originalImage: ImageData | ImageBitmap | HTMLImageElement | HTMLCanvasElement;
- private layers: ImageEffectorLayer[] = [];
- private originalImageTexture: WebGLTexture;
- private shaderCache: Map<string, WebGLProgram> = new Map();
- private perLayerResultTextures: Map<string, WebGLTexture> = new Map();
- private perLayerResultFrameBuffers: Map<string, WebGLFramebuffer> = new Map();
- private nopProgram: WebGLProgram;
- private fxs: [...IEX];
- private paramTextures: Map<string, { texture: WebGLTexture; width: number; height: number; }> = new Map();
+ private compositor: ImageEffectorImageCompositor;
constructor(options: {
canvas: HTMLCanvasElement;
renderWidth: number;
renderHeight: number;
- image: ImageData | ImageBitmap | HTMLImageElement | HTMLCanvasElement;
- fxs: [...IEX];
+ image: ImageData | ImageBitmap | HTMLImageElement | HTMLCanvasElement | null;
}) {
this.canvas = options.canvas;
- this.renderWidth = options.renderWidth;
- this.renderHeight = options.renderHeight;
- this.originalImage = options.image;
- this.fxs = options.fxs;
-
- this.canvas.width = this.renderWidth;
- this.canvas.height = this.renderHeight;
-
- const gl = this.canvas.getContext('webgl2', {
- preserveDrawingBuffer: false,
- alpha: true,
- premultipliedAlpha: false,
- });
-
- if (gl == null) {
- throw new Error('Failed to initialize WebGL2 context');
- }
-
- this.gl = gl;
-
- gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
-
- const VERTICES = new Float32Array([-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1]);
- const vertexBuffer = gl.createBuffer();
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
- gl.bufferData(gl.ARRAY_BUFFER, VERTICES, gl.STATIC_DRAW);
-
- this.originalImageTexture = createTexture(gl);
- gl.activeTexture(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_2D, this.originalImageTexture);
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.originalImage.width, this.originalImage.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.originalImage);
- gl.bindTexture(gl.TEXTURE_2D, null);
-
- this.nopProgram = initShaderProgram(this.gl, `#version 300 es
- in vec2 position;
- out vec2 in_uv;
-
- void main() {
- in_uv = (position + 1.0) / 2.0;
- gl_Position = vec4(position * vec2(1.0, -1.0), 0.0, 1.0);
- }
- `, `#version 300 es
- precision mediump float;
- in vec2 in_uv;
- uniform sampler2D u_texture;
- out vec4 out_color;
-
- void main() {
- out_color = texture(u_texture, in_uv);
- }
- `);
-
- // レジスタ番号はシェーダープログラムに属しているわけではなく、独立の存在なので、とりあえず nopProgram を使って設定する(その後は効果が持続する)
- // ref. https://qiita.com/emadurandal/items/5966c8374f03d4de3266
- const positionLocation = gl.getAttribLocation(this.nopProgram, 'position');
- gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
- gl.enableVertexAttribArray(positionLocation);
- }
-
- private renderLayer(layer: ImageEffectorLayer, preTexture: WebGLTexture, invert = false) {
- 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);
- const shaderProgram = cachedShader ?? initShaderProgram(this.gl, `#version 300 es
- in vec2 position;
- uniform bool u_invert;
- out vec2 in_uv;
-
- void main() {
- in_uv = (position + 1.0) / 2.0;
- gl_Position = u_invert ? vec4(position * vec2(1.0, -1.0), 0.0, 1.0) : vec4(position, 0.0, 1.0);
- }
- `, fx.shader);
- if (cachedShader == null) {
- this.shaderCache.set(fx.id, shaderProgram);
- }
-
- gl.useProgram(shaderProgram);
-
- const in_resolution = gl.getUniformLocation(shaderProgram, 'in_resolution');
- gl.uniform2fv(in_resolution, [this.renderWidth, this.renderHeight]);
-
- const u_invert = gl.getUniformLocation(shaderProgram, 'u_invert');
- gl.uniform1i(u_invert, invert ? 1 : 0);
-
- gl.activeTexture(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_2D, preTexture);
- const in_texture = gl.getUniformLocation(shaderProgram, 'in_texture');
- gl.uniform1i(in_texture, 0);
-
- fx.main({
- gl: gl,
- program: shaderProgram,
- params: Object.fromEntries(
- Object.entries(fx.params as ImageEffectorFxParamDefs).map(([key, param]) => {
- return [key, layer.params[key] ?? param.default];
- }),
- ),
- u: Object.fromEntries(fx.uniforms.map(u => [u, gl.getUniformLocation(shaderProgram, 'u_' + u)!])),
- width: this.renderWidth,
- height: this.renderHeight,
- textures: Object.fromEntries(
- Object.entries(fx.params as ImageEffectorFxParamDefs).map(([k, v]) => {
- if (v.type !== 'texture') return [k, null];
- const param = getValue<typeof v.type>(layer.params, k);
- if (param == null) return [k, null];
- const texture = this.paramTextures.get(this.getTextureKeyForParam(param)) ?? null;
- return [k, texture];
- })),
+ this.compositor = new ImageCompositor({
+ canvas: this.canvas,
+ renderWidth: options.renderWidth,
+ renderHeight: options.renderHeight,
+ image: options.image,
+ functions: Object.fromEntries(Object.entries(FXS).map(([fxId, fx]) => [fxId, fx.fn])),
});
-
- gl.drawArrays(gl.TRIANGLES, 0, 6);
- }
-
- public render() {
- const gl = this.gl;
-
- // 入力をそのまま出力
- if (this.layers.length === 0) {
- gl.activeTexture(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_2D, this.originalImageTexture);
-
- gl.useProgram(this.nopProgram);
- gl.uniform1i(gl.getUniformLocation(this.nopProgram, 'u_texture')!, 0);
-
- gl.drawArrays(gl.TRIANGLES, 0, 6);
- return;
- }
-
- let preTexture = this.originalImageTexture;
-
- for (const layer of this.layers) {
- const isLast = layer === this.layers.at(-1);
-
- const cachedResultTexture = this.perLayerResultTextures.get(layer.id);
- const resultTexture = cachedResultTexture ?? createTexture(gl);
- if (cachedResultTexture == null) {
- this.perLayerResultTextures.set(layer.id, resultTexture);
- }
- gl.bindTexture(gl.TEXTURE_2D, resultTexture);
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.renderWidth, this.renderHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
- gl.bindTexture(gl.TEXTURE_2D, null);
-
- if (isLast) {
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
- } else {
- const cachedResultFrameBuffer = this.perLayerResultFrameBuffers.get(layer.id);
- const resultFrameBuffer = cachedResultFrameBuffer ?? gl.createFramebuffer()!;
- if (cachedResultFrameBuffer == null) {
- this.perLayerResultFrameBuffers.set(layer.id, resultFrameBuffer);
- }
- gl.bindFramebuffer(gl.FRAMEBUFFER, resultFrameBuffer);
- gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, resultTexture, 0);
- }
-
- this.renderLayer(layer, preTexture, isLast);
-
- preTexture = resultTexture;
- }
}
- public async setLayers(layers: ImageEffectorLayer[]) {
- this.layers = layers;
-
- const unused = new Set(this.paramTextures.keys());
+ public async render(layers: ImageEffectorLayer[]) {
+ const compositorLayers: Parameters<ImageCompositor<any>['render']>[0] = [];
for (const layer of layers) {
- const fx = this.fxs.find(fx => fx.id === layer.fxId);
- if (fx == null) continue;
-
- for (const k of Object.keys(layer.params)) {
- const paramDef = fx.params[k];
- if (paramDef == null) continue;
- if (paramDef.type !== 'texture') continue;
- const v = getValue<typeof paramDef.type>(layer.params, k);
- if (v == null) continue;
-
- const textureKey = this.getTextureKeyForParam(v);
- unused.delete(textureKey);
- if (this.paramTextures.has(textureKey)) continue;
-
- 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) :
- v.type === 'qr' ? await createTextureFromQr(this.gl, { data: v.data }) :
- null;
- if (texture == null) continue;
-
- this.paramTextures.set(textureKey, texture);
- }
+ compositorLayers.push({
+ id: layer.id,
+ functionId: layer.fxId,
+ params: layer.params,
+ });
}
- for (const k of unused) {
- if (_DEV_) console.log(`Dispose unused texture <${k}>...`);
- this.gl.deleteTexture(this.paramTextures.get(k)!.texture);
- this.paramTextures.delete(k);
- }
-
- this.render();
+ this.compositor.render(compositorLayers as Parameters<ImageEffectorImageCompositor['render']>[0]);
}
public changeResolution(width: number, height: number) {
- this.renderWidth = width;
- this.renderHeight = height;
- if (this.canvas) {
- this.canvas.width = this.renderWidth;
- this.canvas.height = this.renderHeight;
- }
- this.gl.viewport(0, 0, this.renderWidth, this.renderHeight);
- }
-
- private getTextureKeyForParam(v: ParamTypeToPrimitive['texture']) {
- if (v == null) return '';
- return (
- v.type === 'text' ? `text:${v.text}` :
- v.type === 'url' ? `url:${v.url}` :
- v.type === 'qr' ? `qr:${v.data}` :
- ''
- );
+ this.compositor.changeResolution(width, height);
}
/*
* disposeCanvas = true だとloseContextを呼ぶため、コンストラクタで渡されたcanvasも再利用不可になるので注意
*/
public destroy(disposeCanvas = true) {
- this.gl.deleteProgram(this.nopProgram);
-
- for (const shader of this.shaderCache.values()) {
- this.gl.deleteProgram(shader);
- }
- this.shaderCache.clear();
-
- for (const texture of this.perLayerResultTextures.values()) {
- this.gl.deleteTexture(texture);
- }
- this.perLayerResultTextures.clear();
-
- for (const framebuffer of this.perLayerResultFrameBuffers.values()) {
- this.gl.deleteFramebuffer(framebuffer);
- }
- this.perLayerResultFrameBuffers.clear();
-
- for (const texture of this.paramTextures.values()) {
- this.gl.deleteTexture(texture.texture);
- }
- this.paramTextures.clear();
-
- this.gl.deleteTexture(this.originalImageTexture);
-
- if (disposeCanvas) {
- const loseContextExt = this.gl.getExtension('WEBGL_lose_context');
- if (loseContextExt) loseContextExt.loseContext();
- }
+ this.compositor.destroy(disposeCanvas);
}
}
-
-function createTexture(gl: WebGL2RenderingContext): WebGLTexture {
- const texture = gl.createTexture();
- gl.bindTexture(gl.TEXTURE_2D, texture);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
- gl.bindTexture(gl.TEXTURE_2D, null);
- return texture;
-}
-
-async function createTextureFromUrl(gl: WebGL2RenderingContext, imageUrl: string | null): Promise<{ texture: WebGLTexture, width: number, height: number } | null> {
- if (imageUrl == null || imageUrl.trim() === '') return null;
-
- const image = await new Promise<HTMLImageElement>((resolve, reject) => {
- const img = new Image();
- img.onload = () => resolve(img);
- img.onerror = reject;
- img.src = getProxiedImageUrl(imageUrl); // CORS対策
- }).catch(() => null);
-
- if (image == null) return null;
-
- const texture = createTexture(gl);
- gl.activeTexture(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_2D, texture);
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, image.width, image.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, image);
- gl.bindTexture(gl.TEXTURE_2D, null);
-
- return {
- texture,
- width: image.width,
- height: image.height,
- };
-}
-
-async function createTextureFromText(gl: WebGL2RenderingContext, text: string | null, resolution = 2048): Promise<{ texture: WebGLTexture, width: number, height: number } | null> {
- if (text == null || text.trim() === '') return null;
-
- const ctx = window.document.createElement('canvas').getContext('2d')!;
- ctx.canvas.width = resolution;
- ctx.canvas.height = resolution / 4;
- const fontSize = resolution / 32;
- const margin = fontSize / 2;
- ctx.shadowColor = '#000000';
- ctx.shadowBlur = fontSize / 4;
-
- //ctx.fillStyle = '#00ff00';
- //ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
-
- ctx.fillStyle = '#ffffff';
- ctx.font = `bold ${fontSize}px sans-serif`;
- ctx.textBaseline = 'middle';
-
- ctx.fillText(text, margin, ctx.canvas.height / 2);
-
- const textMetrics = ctx.measureText(text);
- const cropWidth = (Math.ceil(textMetrics.actualBoundingBoxRight + textMetrics.actualBoundingBoxLeft) + margin + margin);
- const cropHeight = (Math.ceil(textMetrics.actualBoundingBoxAscent + textMetrics.actualBoundingBoxDescent) + margin + margin);
- const data = ctx.getImageData(0, (ctx.canvas.height / 2) - (cropHeight / 2), ctx.canvas.width, ctx.canvas.height);
-
- const texture = createTexture(gl);
- gl.activeTexture(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_2D, texture);
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, cropWidth, cropHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
- gl.bindTexture(gl.TEXTURE_2D, null);
-
- const info = {
- texture: texture,
- width: cropWidth,
- height: cropHeight,
- };
-
- ctx.canvas.remove();
-
- return info;
-}
-
-async function createTextureFromQr(gl: WebGL2RenderingContext, options: { data: string | null }, resolution = 512): Promise<{ texture: WebGLTexture, width: number, height: number } | null> {
- const $i = ensureSignin();
-
- const qrCodeInstance = new QRCodeStyling({
- width: resolution,
- height: resolution,
- margin: 42,
- type: 'canvas',
- data: options.data == null || options.data === '' ? `${url}/users/${$i.id}` : options.data,
- image: $i.avatarUrl,
- qrOptions: {
- typeNumber: 0,
- mode: 'Byte',
- errorCorrectionLevel: 'H',
- },
- imageOptions: {
- hideBackgroundDots: true,
- imageSize: 0.3,
- margin: 16,
- crossOrigin: 'anonymous',
- },
- dotsOptions: {
- type: 'dots',
- },
- cornersDotOptions: {
- type: 'dot',
- },
- cornersSquareOptions: {
- type: 'extra-rounded',
- },
- });
-
- const blob = await qrCodeInstance.getRawData('png') as Blob | null;
- if (blob == null) return null;
-
- const image = await window.createImageBitmap(blob);
-
- const texture = createTexture(gl);
- gl.activeTexture(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_2D, texture);
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, resolution, resolution, 0, gl.RGBA, gl.UNSIGNED_BYTE, image);
- gl.bindTexture(gl.TEXTURE_2D, null);
-
- return {
- texture,
- width: resolution,
- height: resolution,
- };
-}
diff --git a/packages/frontend/src/utility/image-effector/fxs.ts b/packages/frontend/src/utility/image-effector/fxs.ts
index 2b20cc1f99..1fd0ad6ed7 100644
--- a/packages/frontend/src/utility/image-effector/fxs.ts
+++ b/packages/frontend/src/utility/image-effector/fxs.ts
@@ -3,43 +3,47 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import { FX_checker } from './fxs/checker.js';
-import { FX_chromaticAberration } from './fxs/chromaticAberration.js';
-import { FX_colorAdjust } from './fxs/colorAdjust.js';
-import { FX_colorClamp } from './fxs/colorClamp.js';
-import { FX_colorClampAdvanced } from './fxs/colorClampAdvanced.js';
-import { FX_distort } from './fxs/distort.js';
-import { FX_polkadot } from './fxs/polkadot.js';
-import { FX_tearing } from './fxs/tearing.js';
-import { FX_grayscale } from './fxs/grayscale.js';
-import { FX_invert } from './fxs/invert.js';
-import { FX_mirror } from './fxs/mirror.js';
-import { FX_stripe } from './fxs/stripe.js';
-import { FX_threshold } from './fxs/threshold.js';
-import { FX_zoomLines } from './fxs/zoomLines.js';
-import { FX_blockNoise } from './fxs/blockNoise.js';
-import { FX_fill } from './fxs/fill.js';
-import { FX_blur } from './fxs/blur.js';
-import { FX_pixelate } from './fxs/pixelate.js';
-import type { ImageEffectorFx } from './ImageEffector.js';
+import * as checker from '../image-compositor-functions/checker.js';
+import * as chromaticAberration from '../image-compositor-functions/chromaticAberration.js';
+import * as colorAdjust from '../image-compositor-functions/colorAdjust.js';
+import * as colorClamp from '../image-compositor-functions/colorClamp.js';
+import * as colorClampAdvanced from '../image-compositor-functions/colorClampAdvanced.js';
+import * as distort from '../image-compositor-functions/distort.js';
+import * as polkadot from '../image-compositor-functions/polkadot.js';
+import * as tearing from '../image-compositor-functions/tearing.js';
+import * as grayscale from '../image-compositor-functions/grayscale.js';
+import * as invert from '../image-compositor-functions/invert.js';
+import * as mirror from '../image-compositor-functions/mirror.js';
+import * as stripe from '../image-compositor-functions/stripe.js';
+import * as threshold from '../image-compositor-functions/threshold.js';
+import * as zoomLines from '../image-compositor-functions/zoomLines.js';
+import * as blockNoise from '../image-compositor-functions/blockNoise.js';
+import * as fill from '../image-compositor-functions/fill.js';
+import * as blur from '../image-compositor-functions/blur.js';
+import * as pixelate from '../image-compositor-functions/pixelate.js';
+import type { ImageCompositorFunction } from '@/lib/ImageCompositor.js';
+import type { ImageEffectorUiDefinition } from './ImageEffector.js';
-export const FXS = [
- FX_mirror,
- FX_invert,
- FX_grayscale,
- FX_colorAdjust,
- FX_colorClamp,
- FX_colorClampAdvanced,
- FX_distort,
- FX_threshold,
- FX_zoomLines,
- FX_stripe,
- FX_polkadot,
- FX_checker,
- FX_chromaticAberration,
- FX_tearing,
- FX_blockNoise,
- FX_fill,
- FX_blur,
- FX_pixelate,
-] as const satisfies ImageEffectorFx<string, any>[];
+export const FXS = {
+ checker,
+ chromaticAberration,
+ colorAdjust,
+ colorClamp,
+ colorClampAdvanced,
+ distort,
+ polkadot,
+ tearing,
+ grayscale,
+ invert,
+ mirror,
+ stripe,
+ threshold,
+ zoomLines,
+ blockNoise,
+ fill,
+ blur,
+ pixelate,
+} as const satisfies Record<string, {
+ readonly fn: ImageCompositorFunction<any>;
+ readonly uiDefinition: ImageEffectorUiDefinition<any>;
+}>;
diff --git a/packages/frontend/src/utility/image-effector/fxs/blockNoise.glsl b/packages/frontend/src/utility/image-effector/fxs/blockNoise.glsl
deleted file mode 100644
index 84c4ecbed4..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/blockNoise.glsl
+++ /dev/null
@@ -1,43 +0,0 @@
-#version 300 es
-precision mediump float;
-
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-in vec2 in_uv;
-uniform sampler2D in_texture;
-uniform vec2 in_resolution;
-uniform int u_amount;
-uniform float u_shiftStrengths[128];
-uniform vec2 u_shiftOrigins[128];
-uniform vec2 u_shiftSizes[128];
-uniform float u_channelShift;
-out vec4 out_color;
-
-void main() {
- // TODO: ピクセル毎に計算する必要はないのでuniformにする
- float aspect_ratio = min(in_resolution.x, in_resolution.y) / max(in_resolution.x, in_resolution.y);
- float aspect_ratio_x = in_resolution.x > in_resolution.y ? 1.0 : aspect_ratio;
- float aspect_ratio_y = in_resolution.x < in_resolution.y ? 1.0 : aspect_ratio;
-
- float v = 0.0;
-
- for (int i = 0; i < u_amount; i++) {
- if (
- in_uv.x * aspect_ratio_x > ((u_shiftOrigins[i].x * aspect_ratio_x) - u_shiftSizes[i].x) &&
- in_uv.x * aspect_ratio_x < ((u_shiftOrigins[i].x * aspect_ratio_x) + u_shiftSizes[i].x) &&
- in_uv.y * aspect_ratio_y > ((u_shiftOrigins[i].y * aspect_ratio_y) - u_shiftSizes[i].y) &&
- in_uv.y * aspect_ratio_y < ((u_shiftOrigins[i].y * aspect_ratio_y) + u_shiftSizes[i].y)
- ) {
- 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/blockNoise.ts b/packages/frontend/src/utility/image-effector/fxs/blockNoise.ts
deleted file mode 100644
index 355ab4536c..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/blockNoise.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import seedrandom from 'seedrandom';
-import shader from './blockNoise.glsl';
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import { i18n } from '@/i18n.js';
-
-export const FX_blockNoise = defineImageEffectorFx({
- id: 'blockNoise',
- name: i18n.ts._imageEffector._fxs.glitch + ': ' + i18n.ts._imageEffector._fxs.blockNoise,
- shader,
- uniforms: ['amount', 'channelShift'] as const,
- params: {
- amount: {
- label: i18n.ts._imageEffector._fxProps.amount,
- type: 'number',
- default: 50,
- min: 1,
- max: 100,
- step: 1,
- },
- strength: {
- label: i18n.ts._imageEffector._fxProps.strength,
- type: 'number',
- default: 0.05,
- min: -1,
- max: 1,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- width: {
- label: i18n.ts.width,
- type: 'number',
- default: 0.05,
- min: 0.01,
- max: 1,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- height: {
- label: i18n.ts.height,
- type: 'number',
- default: 0.01,
- min: 0.01,
- max: 1,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- channelShift: {
- label: i18n.ts._imageEffector._fxProps.glitchChannelShift,
- type: 'number',
- default: 0,
- min: 0,
- max: 10,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- seed: {
- label: i18n.ts._imageEffector._fxProps.seed,
- type: 'seed',
- default: 100,
- },
- },
- main: ({ gl, program, u, params }) => {
- gl.uniform1i(u.amount, params.amount);
- gl.uniform1f(u.channelShift, params.channelShift);
-
- const margin = 0;
-
- const rnd = seedrandom(params.seed.toString());
-
- for (let i = 0; i < params.amount; i++) {
- const o = gl.getUniformLocation(program, `u_shiftOrigins[${i.toString()}]`);
- gl.uniform2f(o, (rnd() * (1 + (margin * 2))) - margin, (rnd() * (1 + (margin * 2))) - margin);
-
- const s = gl.getUniformLocation(program, `u_shiftStrengths[${i.toString()}]`);
- gl.uniform1f(s, (1 - (rnd() * 2)) * params.strength);
-
- const sizes = gl.getUniformLocation(program, `u_shiftSizes[${i.toString()}]`);
- gl.uniform2f(sizes, params.width, params.height);
- }
- },
-});
diff --git a/packages/frontend/src/utility/image-effector/fxs/blur.glsl b/packages/frontend/src/utility/image-effector/fxs/blur.glsl
deleted file mode 100644
index e591267887..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/blur.glsl
+++ /dev/null
@@ -1,78 +0,0 @@
-#version 300 es
-precision mediump float;
-
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-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 vec2 u_offset;
-uniform vec2 u_scale;
-uniform bool u_ellipse;
-uniform float u_angle;
-uniform float u_radius;
-uniform int u_samples;
-out vec4 out_color;
-
-void main() {
- float angle = -(u_angle * PI);
- vec2 centeredUv = in_uv - vec2(0.5, 0.5) - u_offset;
- vec2 rotatedUV = vec2(
- centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
- centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
- ) + u_offset;
-
- bool isInside = false;
- if (u_ellipse) {
- vec2 norm = (rotatedUV - u_offset) / u_scale;
- isInside = dot(norm, norm) <= 1.0;
- } else {
- isInside = rotatedUV.x > u_offset.x - u_scale.x && rotatedUV.x < u_offset.x + u_scale.x && rotatedUV.y > u_offset.y - u_scale.y && rotatedUV.y < u_offset.y + u_scale.y;
- }
-
- if (!isInside) {
- out_color = texture(in_texture, in_uv);
- return;
- }
-
- vec4 result = vec4(0.0);
- float totalSamples = 0.0;
-
- // Make blur radius resolution-independent by using a percentage of image size
- // This ensures consistent visual blur regardless of image resolution
- float referenceSize = min(in_resolution.x, in_resolution.y);
- float normalizedRadius = u_radius / 100.0; // Convert radius to percentage (0-15 -> 0-0.15)
- vec2 blurOffset = vec2(normalizedRadius) / in_resolution * referenceSize;
-
- // Calculate how many samples to take in each direction
- // This determines the grid density, not the blur extent
- int sampleRadius = int(sqrt(float(u_samples)) / 2.0);
-
- // Sample in a grid pattern within the specified radius
- for (int x = -sampleRadius; x <= sampleRadius; x++) {
- for (int y = -sampleRadius; y <= sampleRadius; y++) {
- // Normalize the grid position to [-1, 1] range
- float normalizedX = float(x) / float(sampleRadius);
- float normalizedY = float(y) / float(sampleRadius);
-
- // Scale by radius to get the actual sampling offset
- vec2 offset = vec2(normalizedX, normalizedY) * blurOffset;
- vec2 sampleUV = in_uv + offset;
-
- // Only sample if within texture bounds
- if (sampleUV.x >= 0.0 && sampleUV.x <= 1.0 && sampleUV.y >= 0.0 && sampleUV.y <= 1.0) {
- result += texture(in_texture, sampleUV);
- totalSamples += 1.0;
- }
- }
- }
-
- out_color = totalSamples > 0.0 ? result / totalSamples : texture(in_texture, in_uv);
-}
diff --git a/packages/frontend/src/utility/image-effector/fxs/blur.ts b/packages/frontend/src/utility/image-effector/fxs/blur.ts
deleted file mode 100644
index 40f51fa646..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/blur.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import shader from './blur.glsl';
-import { i18n } from '@/i18n.js';
-
-export const FX_blur = defineImageEffectorFx({
- id: 'blur',
- name: i18n.ts._imageEffector._fxs.blur,
- shader,
- uniforms: ['offset', 'scale', 'ellipse', 'angle', 'radius', 'samples'] as const,
- params: {
- offsetX: {
- label: i18n.ts._imageEffector._fxProps.offset + ' X',
- type: 'number',
- default: 0.0,
- min: -1.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- offsetY: {
- label: i18n.ts._imageEffector._fxProps.offset + ' Y',
- type: 'number',
- default: 0.0,
- min: -1.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- scaleX: {
- label: i18n.ts._imageEffector._fxProps.scale + ' W',
- type: 'number',
- default: 0.5,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- scaleY: {
- label: i18n.ts._imageEffector._fxProps.scale + ' H',
- type: 'number',
- default: 0.5,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- ellipse: {
- label: i18n.ts._imageEffector._fxProps.circle,
- type: 'boolean',
- default: false,
- },
- angle: {
- label: i18n.ts._imageEffector._fxProps.angle,
- type: 'number',
- default: 0,
- min: -1.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 90) + '°',
- },
- radius: {
- label: i18n.ts._imageEffector._fxProps.strength,
- type: 'number',
- default: 3.0,
- min: 0.0,
- max: 10.0,
- step: 0.5,
- },
- },
- main: ({ gl, u, params }) => {
- gl.uniform2f(u.offset, params.offsetX / 2, params.offsetY / 2);
- gl.uniform2f(u.scale, params.scaleX / 2, params.scaleY / 2);
- gl.uniform1i(u.ellipse, params.ellipse ? 1 : 0);
- gl.uniform1f(u.angle, params.angle / 2);
- gl.uniform1f(u.radius, params.radius);
- gl.uniform1i(u.samples, 256);
- },
-});
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 09d11c15d2..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/checker.glsl
+++ /dev/null
@@ -1,43 +0,0 @@
-#version 300 es
-precision mediump float;
-
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-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
deleted file mode 100644
index 7d1938eeb7..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/checker.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import shader from './checker.glsl';
-import { i18n } from '@/i18n.js';
-
-export const FX_checker = defineImageEffectorFx({
- id: 'checker',
- name: i18n.ts._imageEffector._fxs.checker,
- shader,
- uniforms: ['angle', 'scale', 'color', 'opacity'] as const,
- params: {
- angle: {
- label: i18n.ts._imageEffector._fxProps.angle,
- type: 'number',
- default: 0,
- min: -1.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 90) + '°',
- },
- scale: {
- label: i18n.ts._imageEffector._fxProps.scale,
- type: 'number',
- default: 3.0,
- min: 1.0,
- max: 10.0,
- step: 0.1,
- },
- color: {
- label: i18n.ts._imageEffector._fxProps.color,
- type: 'color',
- default: [1, 1, 1],
- },
- opacity: {
- label: i18n.ts._imageEffector._fxProps.opacity,
- type: 'number',
- default: 0.5,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- },
- main: ({ gl, u, params }) => {
- gl.uniform1f(u.angle, params.angle / 2);
- gl.uniform1f(u.scale, params.scale * params.scale);
- gl.uniform3f(u.color, params.color[0], params.color[1], params.color[2]);
- gl.uniform1f(u.opacity, params.opacity);
- },
-});
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 60bb4f5318..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl
+++ /dev/null
@@ -1,49 +0,0 @@
-#version 300 es
-precision mediump float;
-
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-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
deleted file mode 100644
index ed4d134251..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/chromaticAberration.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import shader from './chromaticAberration.glsl';
-import { i18n } from '@/i18n.js';
-
-export const FX_chromaticAberration = defineImageEffectorFx({
- id: 'chromaticAberration',
- name: i18n.ts._imageEffector._fxs.chromaticAberration,
- shader,
- uniforms: ['amount', 'start', 'normalize'] as const,
- params: {
- normalize: {
- label: i18n.ts._imageEffector._fxProps.normalize,
- type: 'boolean',
- default: false,
- },
- amount: {
- label: i18n.ts._imageEffector._fxProps.amount,
- type: 'number',
- default: 0.1,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- },
- },
- main: ({ gl, u, params }) => {
- gl.uniform1f(u.amount, params.amount);
- gl.uniform1i(u.normalize, params.normalize ? 1 : 0);
- },
-});
diff --git a/packages/frontend/src/utility/image-effector/fxs/colorAdjust.glsl b/packages/frontend/src/utility/image-effector/fxs/colorAdjust.glsl
deleted file mode 100644
index 2d0c87ce95..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/colorAdjust.glsl
+++ /dev/null
@@ -1,82 +0,0 @@
-#version 300 es
-precision mediump float;
-
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-in vec2 in_uv;
-uniform sampler2D in_texture;
-uniform vec2 in_resolution;
-uniform float u_brightness;
-uniform float u_contrast;
-uniform float u_hue;
-uniform float u_lightness;
-uniform float u_saturation;
-out vec4 out_color;
-
-// RGB to HSL
-vec3 rgb2hsl(vec3 c) {
- float maxc = max(max(c.r, c.g), c.b);
- float minc = min(min(c.r, c.g), c.b);
- float l = (maxc + minc) * 0.5;
- float s = 0.0;
- float h = 0.0;
- if (maxc != minc) {
- float d = maxc - minc;
- s = l > 0.5 ? d / (2.0 - maxc - minc) : d / (maxc + minc);
- if (maxc == c.r) {
- h = (c.g - c.b) / d + (c.g < c.b ? 6.0 : 0.0);
- } else if (maxc == c.g) {
- h = (c.b - c.r) / d + 2.0;
- } else {
- h = (c.r - c.g) / d + 4.0;
- }
- h /= 6.0;
- }
- return vec3(h, s, l);
-}
-
-// HSL to RGB
-float hue2rgb(float p, float q, float t) {
- if (t < 0.0) t += 1.0;
- if (t > 1.0) t -= 1.0;
- if (t < 1.0/6.0) return p + (q - p) * 6.0 * t;
- if (t < 1.0/2.0) return q;
- if (t < 2.0/3.0) return p + (q - p) * (2.0/3.0 - t) * 6.0;
- return p;
-}
-
-vec3 hsl2rgb(vec3 hsl) {
- float r, g, b;
- float h = hsl.x;
- float s = hsl.y;
- float l = hsl.z;
- if (s == 0.0) {
- r = g = b = l;
- } else {
- float q = l < 0.5 ? l * (1.0 + s) : l + s - l * s;
- float p = 2.0 * l - q;
- r = hue2rgb(p, q, h + 1.0/3.0);
- g = hue2rgb(p, q, h);
- b = hue2rgb(p, q, h - 1.0/3.0);
- }
- return vec3(r, g, b);
-}
-
-void main() {
- vec4 in_color = texture(in_texture, in_uv);
- vec3 color = in_color.rgb;
-
- color = color * u_brightness;
- color += vec3(u_lightness);
- color = (color - 0.5) * u_contrast + 0.5;
-
- vec3 hsl = rgb2hsl(color);
- hsl.x = mod(hsl.x + u_hue, 1.0);
- hsl.y = clamp(hsl.y * u_saturation, 0.0, 1.0);
-
- color = hsl2rgb(hsl);
- out_color = vec4(color, in_color.a);
-}
diff --git a/packages/frontend/src/utility/image-effector/fxs/colorAdjust.ts b/packages/frontend/src/utility/image-effector/fxs/colorAdjust.ts
deleted file mode 100644
index 989ca79a2c..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/colorAdjust.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import shader from './colorAdjust.glsl';
-import { i18n } from '@/i18n.js';
-
-export const FX_colorAdjust = defineImageEffectorFx({
- id: 'colorAdjust',
- name: i18n.ts._imageEffector._fxs.colorAdjust,
- shader,
- uniforms: ['lightness', 'contrast', 'hue', 'brightness', 'saturation'] as const,
- params: {
- lightness: {
- label: i18n.ts._imageEffector._fxProps.lightness,
- type: 'number',
- default: 0,
- min: -1,
- max: 1,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- contrast: {
- label: i18n.ts._imageEffector._fxProps.contrast,
- type: 'number',
- default: 1,
- min: 0,
- max: 4,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- hue: {
- label: i18n.ts._imageEffector._fxProps.hue,
- type: 'number',
- default: 0,
- min: -1,
- max: 1,
- step: 0.01,
- toViewValue: v => Math.round(v * 180) + '°',
- },
- brightness: {
- label: i18n.ts._imageEffector._fxProps.brightness,
- type: 'number',
- default: 1,
- min: 0,
- max: 4,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- saturation: {
- label: i18n.ts._imageEffector._fxProps.saturation,
- type: 'number',
- default: 1,
- min: 0,
- max: 4,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- },
- main: ({ gl, u, params }) => {
- gl.uniform1f(u.brightness, params.brightness);
- gl.uniform1f(u.contrast, params.contrast);
- gl.uniform1f(u.hue, params.hue / 2);
- gl.uniform1f(u.lightness, params.lightness);
- gl.uniform1f(u.saturation, params.saturation);
- },
-});
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 bf37f5ab43..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl
+++ /dev/null
@@ -1,29 +0,0 @@
-#version 300 es
-precision mediump float;
-
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-// colorClamp, colorClampAdvanced共通
-// colorClampではmax, minがすべて同じ値となる
-
-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/colorClamp.ts b/packages/frontend/src/utility/image-effector/fxs/colorClamp.ts
deleted file mode 100644
index f3513011fa..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/colorClamp.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import shader from './colorClamp.glsl';
-import { i18n } from '@/i18n.js';
-
-export const FX_colorClamp = defineImageEffectorFx({
- id: 'colorClamp',
- name: i18n.ts._imageEffector._fxs.colorClamp,
- shader,
- uniforms: ['rMax', 'rMin', 'gMax', 'gMin', 'bMax', 'bMin'] as const,
- params: {
- max: {
- label: i18n.ts._imageEffector._fxProps.max,
- type: 'number',
- default: 1.0,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- min: {
- label: i18n.ts._imageEffector._fxProps.min,
- type: 'number',
- default: -1.0,
- min: -1.0,
- max: 0.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- },
- main: ({ gl, u, params }) => {
- gl.uniform1f(u.rMax, params.max);
- gl.uniform1f(u.rMin, 1.0 + params.min);
- gl.uniform1f(u.gMax, params.max);
- gl.uniform1f(u.gMin, 1.0 + params.min);
- gl.uniform1f(u.bMax, params.max);
- gl.uniform1f(u.bMin, 1.0 + params.min);
- },
-});
diff --git a/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.ts b/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.ts
deleted file mode 100644
index 397e16c1ba..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import shader from './colorClamp.glsl';
-import { i18n } from '@/i18n.js';
-
-export const FX_colorClampAdvanced = defineImageEffectorFx({
- id: 'colorClampAdvanced',
- name: i18n.ts._imageEffector._fxs.colorClampAdvanced,
- shader,
- uniforms: ['rMax', 'rMin', 'gMax', 'gMin', 'bMax', 'bMin'] as const,
- params: {
- rMax: {
- label: `${i18n.ts._imageEffector._fxProps.max} (${i18n.ts._imageEffector._fxProps.redComponent})`,
- type: 'number',
- default: 1.0,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- rMin: {
- label: `${i18n.ts._imageEffector._fxProps.min} (${i18n.ts._imageEffector._fxProps.redComponent})`,
- type: 'number',
- default: -1.0,
- min: -1.0,
- max: 0.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- gMax: {
- label: `${i18n.ts._imageEffector._fxProps.max} (${i18n.ts._imageEffector._fxProps.greenComponent})`,
- type: 'number',
- default: 1.0,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- gMin: {
- label: `${i18n.ts._imageEffector._fxProps.min} (${i18n.ts._imageEffector._fxProps.greenComponent})`,
- type: 'number',
- default: -1.0,
- min: -1.0,
- max: 0.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- bMax: {
- label: `${i18n.ts._imageEffector._fxProps.max} (${i18n.ts._imageEffector._fxProps.blueComponent})`,
- type: 'number',
- default: 1.0,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- bMin: {
- label: `${i18n.ts._imageEffector._fxProps.min} (${i18n.ts._imageEffector._fxProps.blueComponent})`,
- type: 'number',
- default: -1.0,
- min: -1.0,
- max: 0.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- },
- main: ({ gl, u, params }) => {
- gl.uniform1f(u.rMax, params.rMax);
- gl.uniform1f(u.rMin, 1.0 + params.rMin);
- gl.uniform1f(u.gMax, params.gMax);
- gl.uniform1f(u.gMin, 1.0 + params.gMin);
- gl.uniform1f(u.bMax, params.bMax);
- gl.uniform1f(u.bMin, 1.0 + params.bMin);
- },
-});
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 7e0d1e3252..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/distort.glsl
+++ /dev/null
@@ -1,30 +0,0 @@
-#version 300 es
-precision mediump float;
-
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-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_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((HALF_PI + (u_phase * PI) - (u_frequency / 2.0)) + in_uv.y * u_frequency) * u_strength :
- sin((HALF_PI + (u_phase * PI) - (u_frequency / 2.0)) + 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
deleted file mode 100644
index 3ea93a0266..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/distort.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import shader from './distort.glsl';
-import { i18n } from '@/i18n.js';
-
-export const FX_distort = defineImageEffectorFx({
- id: 'distort',
- name: i18n.ts._imageEffector._fxs.distort,
- shader,
- uniforms: ['phase', 'frequency', 'strength', 'direction'] as const,
- params: {
- direction: {
- label: i18n.ts._imageEffector._fxProps.direction,
- type: 'number:enum',
- enum: [
- { value: 0 as const, label: i18n.ts.horizontal },
- { value: 1 as const, label: i18n.ts.vertical },
- ],
- default: 1,
- },
- phase: {
- label: i18n.ts._imageEffector._fxProps.phase,
- type: 'number',
- default: 0.0,
- min: -1.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- frequency: {
- label: i18n.ts._imageEffector._fxProps.frequency,
- type: 'number',
- default: 30,
- min: 0,
- max: 100,
- step: 0.1,
- },
- strength: {
- label: i18n.ts._imageEffector._fxProps.strength,
- type: 'number',
- default: 0.05,
- min: 0,
- max: 1,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- },
- main: ({ gl, u, params }) => {
- gl.uniform1f(u.phase, params.phase);
- gl.uniform1f(u.frequency, params.frequency);
- gl.uniform1f(u.strength, params.strength);
- gl.uniform1i(u.direction, params.direction);
- },
-});
diff --git a/packages/frontend/src/utility/image-effector/fxs/fill.glsl b/packages/frontend/src/utility/image-effector/fxs/fill.glsl
deleted file mode 100644
index f04dc5545a..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/fill.glsl
+++ /dev/null
@@ -1,50 +0,0 @@
-#version 300 es
-precision mediump float;
-
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-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 vec2 u_offset;
-uniform vec2 u_scale;
-uniform bool u_ellipse;
-uniform float u_angle;
-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) - u_offset;
- vec2 rotatedUV = vec2(
- centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
- centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
- ) + u_offset;
-
- bool isInside = false;
- if (u_ellipse) {
- vec2 norm = (rotatedUV - u_offset) / u_scale;
- isInside = dot(norm, norm) <= 1.0;
- } else {
- isInside = rotatedUV.x > u_offset.x - u_scale.x && rotatedUV.x < u_offset.x + u_scale.x && rotatedUV.y > u_offset.y - u_scale.y && rotatedUV.y < u_offset.y + u_scale.y;
- }
-
- out_color = isInside ? vec4(
- mix(in_color.r, u_color.r, u_opacity),
- mix(in_color.g, u_color.g, u_opacity),
- mix(in_color.b, u_color.b, u_opacity),
- in_color.a
- ) : in_color;
-}
diff --git a/packages/frontend/src/utility/image-effector/fxs/fill.ts b/packages/frontend/src/utility/image-effector/fxs/fill.ts
deleted file mode 100644
index 772cd76cf7..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/fill.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import shader from './fill.glsl';
-import { i18n } from '@/i18n.js';
-
-export const FX_fill = defineImageEffectorFx({
- id: 'fill',
- name: i18n.ts._imageEffector._fxs.fill,
- shader,
- uniforms: ['offset', 'scale', 'ellipse', 'angle', 'color', 'opacity'] as const,
- params: {
- offsetX: {
- label: i18n.ts._imageEffector._fxProps.offset + ' X',
- type: 'number',
- default: 0.0,
- min: -1.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- offsetY: {
- label: i18n.ts._imageEffector._fxProps.offset + ' Y',
- type: 'number',
- default: 0.0,
- min: -1.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- scaleX: {
- label: i18n.ts._imageEffector._fxProps.scale + ' W',
- type: 'number',
- default: 0.5,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- scaleY: {
- label: i18n.ts._imageEffector._fxProps.scale + ' H',
- type: 'number',
- default: 0.5,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- ellipse: {
- label: i18n.ts._imageEffector._fxProps.circle,
- type: 'boolean',
- default: false,
- },
- angle: {
- label: i18n.ts._imageEffector._fxProps.angle,
- type: 'number',
- default: 0,
- min: -1.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 90) + '°',
- },
- color: {
- label: i18n.ts._imageEffector._fxProps.color,
- type: 'color',
- default: [1, 1, 1],
- },
- opacity: {
- label: i18n.ts._imageEffector._fxProps.opacity,
- type: 'number',
- default: 1.0,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- },
- main: ({ gl, u, params }) => {
- gl.uniform2f(u.offset, params.offsetX / 2, params.offsetY / 2);
- gl.uniform2f(u.scale, params.scaleX / 2, params.scaleY / 2);
- gl.uniform1i(u.ellipse, params.ellipse ? 1 : 0);
- gl.uniform1f(u.angle, params.angle / 2);
- gl.uniform3f(u.color, params.color[0], params.color[1], params.color[2]);
- gl.uniform1f(u.opacity, params.opacity);
- },
-});
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 54ca719976..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/grayscale.glsl
+++ /dev/null
@@ -1,22 +0,0 @@
-#version 300 es
-precision mediump float;
-
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-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
deleted file mode 100644
index 055e8b4618..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/grayscale.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import shader from './grayscale.glsl';
-import { i18n } from '@/i18n.js';
-
-export const FX_grayscale = defineImageEffectorFx({
- id: 'grayscale',
- name: i18n.ts._imageEffector._fxs.grayscale,
- shader,
- uniforms: [] as const,
- params: {
- },
- main: ({ gl, 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 a2d1574f5b..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/invert.glsl
+++ /dev/null
@@ -1,23 +0,0 @@
-#version 300 es
-precision mediump float;
-
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-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
deleted file mode 100644
index 9417047931..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/invert.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import shader from './invert.glsl';
-import { i18n } from '@/i18n.js';
-
-export const FX_invert = defineImageEffectorFx({
- id: 'invert',
- name: i18n.ts._imageEffector._fxs.invert,
- shader,
- uniforms: ['r', 'g', 'b'] as const,
- params: {
- r: {
- label: i18n.ts._imageEffector._fxProps.redComponent,
- type: 'boolean',
- default: true,
- },
- g: {
- label: i18n.ts._imageEffector._fxProps.greenComponent,
- type: 'boolean',
- default: true,
- },
- b: {
- label: i18n.ts._imageEffector._fxProps.blueComponent,
- type: 'boolean',
- default: true,
- },
- },
- main: ({ gl, u, params }) => {
- gl.uniform1i(u.r, params.r ? 1 : 0);
- gl.uniform1i(u.g, params.g ? 1 : 0);
- gl.uniform1i(u.b, params.b ? 1 : 0);
- },
-});
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 b27934e9ef..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/mirror.glsl
+++ /dev/null
@@ -1,26 +0,0 @@
-#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
deleted file mode 100644
index 6515454ead..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/mirror.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import shader from './mirror.glsl';
-import { i18n } from '@/i18n.js';
-
-export const FX_mirror = defineImageEffectorFx({
- id: 'mirror',
- name: i18n.ts._imageEffector._fxs.mirror,
- shader,
- uniforms: ['h', 'v'] as const,
- params: {
- h: {
- label: i18n.ts.horizontal,
- type: 'number:enum',
- enum: [
- { value: -1 as const, icon: 'ti ti-arrow-bar-right' },
- { value: 0 as const, icon: 'ti ti-minus-vertical' },
- { value: 1 as const, icon: 'ti ti-arrow-bar-left' }
- ],
- default: -1,
- },
- v: {
- label: i18n.ts.vertical,
- type: 'number:enum',
- enum: [
- { value: -1 as const, icon: 'ti ti-arrow-bar-down' },
- { value: 0 as const, icon: 'ti ti-minus' },
- { value: 1 as const, icon: 'ti ti-arrow-bar-up' }
- ],
- default: 0,
- },
- },
- main: ({ gl, u, params }) => {
- gl.uniform1i(u.h, params.h);
- gl.uniform1i(u.v, params.v);
- },
-});
diff --git a/packages/frontend/src/utility/image-effector/fxs/pixelate.glsl b/packages/frontend/src/utility/image-effector/fxs/pixelate.glsl
deleted file mode 100644
index 4de3f27397..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/pixelate.glsl
+++ /dev/null
@@ -1,68 +0,0 @@
-#version 300 es
-precision mediump float;
-
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-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 vec2 u_offset;
-uniform vec2 u_scale;
-uniform bool u_ellipse;
-uniform float u_angle;
-uniform int u_samples;
-uniform float u_strength;
-out vec4 out_color;
-
-// TODO: pixelateの中心を画像中心ではなく範囲の中心にする
-// TODO: 画像のアスペクト比に関わらず各画素は正方形にする
-
-void main() {
- if (u_strength <= 0.0) {
- out_color = texture(in_texture, in_uv);
- return;
- }
-
- float angle = -(u_angle * PI);
- vec2 centeredUv = in_uv - vec2(0.5, 0.5) - u_offset;
- vec2 rotatedUV = vec2(
- centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
- centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
- ) + u_offset;
-
- bool isInside = false;
- if (u_ellipse) {
- vec2 norm = (rotatedUV - u_offset) / u_scale;
- isInside = dot(norm, norm) <= 1.0;
- } else {
- isInside = rotatedUV.x > u_offset.x - u_scale.x && rotatedUV.x < u_offset.x + u_scale.x && rotatedUV.y > u_offset.y - u_scale.y && rotatedUV.y < u_offset.y + u_scale.y;
- }
-
- if (!isInside) {
- out_color = texture(in_texture, in_uv);
- return;
- }
-
- float dx = u_strength / 1.0;
- float dy = u_strength / 1.0;
- vec2 new_uv = vec2(
- (dx * (floor((in_uv.x - 0.5 - (dx / 2.0)) / dx) + 0.5)),
- (dy * (floor((in_uv.y - 0.5 - (dy / 2.0)) / dy) + 0.5))
- ) + vec2(0.5 + (dx / 2.0), 0.5 + (dy / 2.0));
-
- vec4 result = vec4(0.0);
- float totalSamples = 0.0;
-
- // TODO: より多くのサンプリング
- result += texture(in_texture, new_uv);
- totalSamples += 1.0;
-
- out_color = totalSamples > 0.0 ? result / totalSamples : texture(in_texture, in_uv);
-}
diff --git a/packages/frontend/src/utility/image-effector/fxs/pixelate.ts b/packages/frontend/src/utility/image-effector/fxs/pixelate.ts
deleted file mode 100644
index e3eef49b23..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/pixelate.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import shader from './pixelate.glsl';
-import { i18n } from '@/i18n.js';
-
-export const FX_pixelate = defineImageEffectorFx({
- id: 'pixelate',
- name: i18n.ts._imageEffector._fxs.pixelate,
- shader,
- uniforms: ['offset', 'scale', 'ellipse', 'angle', 'strength', 'samples'] as const,
- params: {
- offsetX: {
- label: i18n.ts._imageEffector._fxProps.offset + ' X',
- type: 'number',
- default: 0.0,
- min: -1.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- offsetY: {
- label: i18n.ts._imageEffector._fxProps.offset + ' Y',
- type: 'number',
- default: 0.0,
- min: -1.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- scaleX: {
- label: i18n.ts._imageEffector._fxProps.scale + ' W',
- type: 'number',
- default: 0.5,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- scaleY: {
- label: i18n.ts._imageEffector._fxProps.scale + ' H',
- type: 'number',
- default: 0.5,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- ellipse: {
- label: i18n.ts._imageEffector._fxProps.circle,
- type: 'boolean',
- default: false,
- },
- angle: {
- label: i18n.ts._imageEffector._fxProps.angle,
- type: 'number',
- default: 0,
- min: -1.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 90) + '°',
- },
- strength: {
- label: i18n.ts._imageEffector._fxProps.strength,
- type: 'number',
- default: 0.2,
- min: 0.0,
- max: 0.5,
- step: 0.01,
- },
- },
- main: ({ gl, u, params }) => {
- gl.uniform2f(u.offset, params.offsetX / 2, params.offsetY / 2);
- gl.uniform2f(u.scale, params.scaleX / 2, params.scaleY / 2);
- gl.uniform1i(u.ellipse, params.ellipse ? 1 : 0);
- gl.uniform1f(u.angle, params.angle / 2);
- gl.uniform1f(u.strength, params.strength * params.strength);
- gl.uniform1i(u.samples, 256);
- },
-});
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 39ecad34b5..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/polkadot.glsl
+++ /dev/null
@@ -1,75 +0,0 @@
-#version 300 es
-precision mediump float;
-
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-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
deleted file mode 100644
index 521e08cc7b..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/polkadot.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import shader from './polkadot.glsl';
-import { i18n } from '@/i18n.js';
-
-// Primarily used for watermark
-export const FX_polkadot = defineImageEffectorFx({
- id: 'polkadot',
- name: i18n.ts._imageEffector._fxs.polkadot,
- shader,
- uniforms: ['angle', 'scale', 'major_radius', 'major_opacity', 'minor_divisions', 'minor_radius', 'minor_opacity', 'color'] as const,
- params: {
- angle: {
- label: i18n.ts._imageEffector._fxProps.angle,
- type: 'number',
- default: 0,
- min: -1.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 90) + '°',
- },
- scale: {
- label: i18n.ts._imageEffector._fxProps.scale,
- type: 'number',
- default: 3.0,
- min: 1.0,
- max: 10.0,
- step: 0.1,
- },
- majorRadius: {
- label: i18n.ts._watermarkEditor.polkadotMainDotRadius,
- type: 'number',
- default: 0.1,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- },
- majorOpacity: {
- label: i18n.ts._watermarkEditor.polkadotMainDotOpacity,
- type: 'number',
- default: 0.75,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- minorDivisions: {
- label: i18n.ts._watermarkEditor.polkadotSubDotDivisions,
- type: 'number',
- default: 4,
- min: 0,
- max: 16,
- step: 1,
- },
- minorRadius: {
- label: i18n.ts._watermarkEditor.polkadotSubDotRadius,
- type: 'number',
- default: 0.25,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- },
- minorOpacity: {
- label: i18n.ts._watermarkEditor.polkadotSubDotOpacity,
- type: 'number',
- default: 0.5,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- color: {
- label: i18n.ts._imageEffector._fxProps.color,
- type: 'color',
- default: [1, 1, 1],
- },
- },
- main: ({ gl, u, params }) => {
- gl.uniform1f(u.angle, params.angle / 2);
- gl.uniform1f(u.scale, params.scale * params.scale);
- gl.uniform1f(u.major_radius, params.majorRadius);
- gl.uniform1f(u.major_opacity, params.majorOpacity);
- gl.uniform1f(u.minor_divisions, params.minorDivisions);
- gl.uniform1f(u.minor_radius, params.minorRadius);
- gl.uniform3f(u.color, params.color[0], params.color[1], params.color[2]);
- gl.uniform1f(u.minor_opacity, params.minorOpacity);
- },
-});
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 bb18d8fcb8..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/stripe.glsl
+++ /dev/null
@@ -1,45 +0,0 @@
-#version 300 es
-precision mediump float;
-
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-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
deleted file mode 100644
index 3a6ecf970c..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/stripe.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import shader from './stripe.glsl';
-import { i18n } from '@/i18n.js';
-
-// Primarily used for watermark
-export const FX_stripe = defineImageEffectorFx({
- id: 'stripe',
- name: i18n.ts._imageEffector._fxs.stripe,
- shader,
- uniforms: ['angle', 'frequency', 'phase', 'threshold', 'color', 'opacity'] as const,
- params: {
- angle: {
- label: i18n.ts._imageEffector._fxProps.angle,
- type: 'number',
- default: 0.5,
- min: -1.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 90) + '°',
- },
- frequency: {
- label: i18n.ts._watermarkEditor.stripeFrequency,
- type: 'number',
- default: 10.0,
- min: 1.0,
- max: 30.0,
- step: 0.1,
- },
- threshold: {
- label: i18n.ts._watermarkEditor.stripeWidth,
- type: 'number',
- default: 0.1,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- color: {
- label: i18n.ts._imageEffector._fxProps.color,
- type: 'color',
- default: [1, 1, 1],
- },
- opacity: {
- label: i18n.ts._imageEffector._fxProps.opacity,
- type: 'number',
- default: 0.5,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- },
- main: ({ gl, u, params }) => {
- gl.uniform1f(u.angle, params.angle / 2);
- gl.uniform1f(u.frequency, params.frequency * params.frequency);
- gl.uniform1f(u.phase, 0.0);
- gl.uniform1f(u.threshold, params.threshold);
- gl.uniform3f(u.color, params.color[0], params.color[1], params.color[2]);
- gl.uniform1f(u.opacity, params.opacity);
- },
-});
diff --git a/packages/frontend/src/utility/image-effector/fxs/tearing.glsl b/packages/frontend/src/utility/image-effector/fxs/tearing.glsl
deleted file mode 100644
index 3fb2fc2cad..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/tearing.glsl
+++ /dev/null
@@ -1,33 +0,0 @@
-#version 300 es
-precision mediump float;
-
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-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/tearing.ts b/packages/frontend/src/utility/image-effector/fxs/tearing.ts
deleted file mode 100644
index 453b16bb19..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/tearing.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import seedrandom from 'seedrandom';
-import shader from './tearing.glsl';
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import { i18n } from '@/i18n.js';
-
-export const FX_tearing = defineImageEffectorFx({
- id: 'tearing',
- name: i18n.ts._imageEffector._fxs.glitch + ': ' + i18n.ts._imageEffector._fxs.tearing,
- shader,
- uniforms: ['amount', 'channelShift'] as const,
- params: {
- amount: {
- label: i18n.ts._imageEffector._fxProps.amount,
- type: 'number',
- default: 3,
- min: 1,
- max: 100,
- step: 1,
- },
- strength: {
- label: i18n.ts._imageEffector._fxProps.strength,
- type: 'number',
- default: 0.05,
- min: -1,
- max: 1,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- size: {
- label: i18n.ts._imageEffector._fxProps.size,
- type: 'number',
- default: 0.2,
- min: 0,
- max: 1,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- channelShift: {
- label: i18n.ts._imageEffector._fxProps.glitchChannelShift,
- type: 'number',
- default: 0.5,
- min: 0,
- max: 10,
- step: 0.01,
- toViewValue: v => Math.round(v * 100) + '%',
- },
- seed: {
- label: i18n.ts._imageEffector._fxProps.seed,
- type: 'seed',
- default: 100,
- },
- },
- main: ({ gl, program, u, params }) => {
- gl.uniform1i(u.amount, params.amount);
- gl.uniform1f(u.channelShift, params.channelShift);
-
- const rnd = seedrandom(params.seed.toString());
-
- for (let i = 0; i < params.amount; i++) {
- const o = gl.getUniformLocation(program, `u_shiftOrigins[${i.toString()}]`);
- gl.uniform1f(o, rnd());
-
- const s = gl.getUniformLocation(program, `u_shiftStrengths[${i.toString()}]`);
- gl.uniform1f(s, (1 - (rnd() * 2)) * params.strength);
-
- const h = gl.getUniformLocation(program, `u_shiftHeights[${i.toString()}]`);
- gl.uniform1f(h, rnd() * params.size);
- }
- },
-});
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 5ca8c46c39..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/threshold.glsl
+++ /dev/null
@@ -1,23 +0,0 @@
-#version 300 es
-precision mediump float;
-
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-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
deleted file mode 100644
index d0bb8305ae..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/threshold.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import shader from './threshold.glsl';
-import { i18n } from '@/i18n.js';
-
-export const FX_threshold = defineImageEffectorFx({
- id: 'threshold',
- name: i18n.ts._imageEffector._fxs.threshold,
- shader,
- uniforms: ['r', 'g', 'b'] as const,
- params: {
- r: {
- label: i18n.ts._imageEffector._fxProps.redComponent,
- type: 'number',
- default: 0.5,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- },
- g: {
- label: i18n.ts._imageEffector._fxProps.greenComponent,
- type: 'number',
- default: 0.5,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- },
- b: {
- label: i18n.ts._imageEffector._fxProps.blueComponent,
- type: 'number',
- default: 0.5,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- },
- },
- main: ({ gl, u, params }) => {
- gl.uniform1f(u.r, params.r);
- gl.uniform1f(u.g, params.g);
- gl.uniform1f(u.b, params.b);
- },
-});
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 d6a1ef1820..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl
+++ /dev/null
@@ -1,147 +0,0 @@
-#version 300 es
-precision mediump float;
-
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-const float PI = 3.141592653589793;
-
-in vec2 in_uv; // 0..1
-uniform sampler2D in_texture; // 背景
-uniform vec2 in_resolution; // 出力解像度(px)
-
-uniform sampler2D u_watermark; // ウォーターマーク
-uniform vec2 u_wmResolution; // ウォーターマーク元解像度(px)
-
-uniform float u_opacity; // 0..1
-uniform float u_scale; // watermarkのスケール
-uniform float u_angle; // -1..1 (PI倍)
-uniform bool u_cover; // cover基準 or fit基準
-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 float u_margin; // 余白(比率)
-uniform float u_repeatMargin; // 敷き詰め時の余白(比率)
-uniform bool u_noBBoxExpansion; // 回転時のBounding Box拡張を抑止
-uniform bool u_wmEnabled; // watermark有効
-
-out vec4 out_color;
-
-mat2 rot(float a) {
- float c = cos(a), s = sin(a);
- return mat2(c, -s, s, c);
-}
-
-// cover/fitとscaleから、最終的なサイズ(px)を計算
-vec2 computeWmSize(vec2 outSize, vec2 wmSize, bool cover, float scale) {
- float wmAspect = wmSize.x / wmSize.y;
- float outAspect = outSize.x / outSize.y;
- vec2 size;
- if (cover) {
- if (wmAspect >= outAspect) {
- size.y = outSize.y * scale;
- size.x = size.y * wmAspect;
- } else {
- size.x = outSize.x * scale;
- size.y = size.x / wmAspect;
- }
- } else {
- if (wmAspect >= outAspect) {
- size.x = outSize.x * scale;
- size.y = size.x / wmAspect;
- } else {
- size.y = outSize.y * scale;
- size.x = size.y * wmAspect;
- }
- }
- return size;
-}
-
-void main() {
- vec2 outSize = in_resolution;
- vec2 p = in_uv * outSize; // 出力のピクセル座標
- vec4 base = texture(in_texture, in_uv);
-
- if (!u_wmEnabled) {
- out_color = base;
- return;
- }
-
- float theta = u_angle * PI; // ラジアン
- vec2 wmSize = computeWmSize(outSize, u_wmResolution, u_cover, u_scale);
- vec2 margin = u_repeat ? wmSize * u_repeatMargin : outSize * u_margin;
-
- // アライメントに基づく回転中心を計算
- float rotateX = 0.0;
- float rotateY = 0.0;
- if (abs(theta) > 1e-6 && !u_noBBoxExpansion) {
- rotateX = abs(abs(wmSize.x * cos(theta)) + abs(wmSize.y * sin(theta)) - wmSize.x) * 0.5;
- rotateY = abs(abs(wmSize.x * sin(theta)) + abs(wmSize.y * cos(theta)) - wmSize.y) * 0.5;
- }
-
- float x;
- if (u_alignX == 1) {
- x = (outSize.x - wmSize.x) * 0.5;
- } else if (u_alignX == 0) {
- x = rotateX + margin.x;
- } else {
- x = outSize.x - wmSize.x - margin.x - rotateX;
- }
-
- float y;
- if (u_alignY == 1) {
- y = (outSize.y - wmSize.y) * 0.5;
- } else if (u_alignY == 0) {
- y = rotateY + margin.y;
- } else {
- y = outSize.y - wmSize.y - margin.y - rotateY;
- }
-
- vec2 rectMin = vec2(x, y);
- vec2 rectMax = rectMin + wmSize;
- vec2 rectCenter = (rectMin + rectMax) * 0.5;
-
- vec4 wmCol = vec4(0.0);
-
- if (u_repeat) {
- // アライメントに基づく中心で回転
- vec2 q = rectCenter + rot(theta) * (p - rectCenter);
-
- // タイルグリッドの原点をrectMin(アライメント位置)に設定
- vec2 gridOrigin = rectMin - margin;
- vec2 qFromOrigin = q - gridOrigin;
-
- // タイルサイズ(ウォーターマーク + マージン)で正規化
- vec2 tile = wmSize + margin * 2.0;
- vec2 tileUv = qFromOrigin / tile;
-
- // タイル内のローカル座標(0..1)を取得
- vec2 localUv = fract(tileUv);
-
- // ローカル座標をピクセル単位に変換
- vec2 localPos = localUv * tile;
-
- // マージン領域内かチェック
- bool inMargin = any(lessThan(localPos, margin)) || any(greaterThanEqual(localPos, margin + wmSize));
-
- if (!inMargin) {
- // ウォーターマーク領域内: UV座標を計算
- vec2 uvWm = (localPos - margin) / wmSize;
- wmCol = texture(u_watermark, uvWm);
- }
- // マージン領域の場合は透明(wmCol = vec4(0.0))のまま
- } else {
- // アライメントと回転に従い一枚だけ描画
- vec2 q = rectCenter + rot(theta) * (p - rectCenter);
- bool inside = all(greaterThanEqual(q, rectMin)) && all(lessThan(q, rectMax));
- if (inside) {
- vec2 uvWm = (q - rectMin) / wmSize;
- wmCol = texture(u_watermark, uvWm);
- }
- }
-
- float a = clamp(wmCol.a * u_opacity, 0.0, 1.0);
- out_color = mix(base, vec4(wmCol.rgb, 1.0), a);
-}
diff --git a/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.ts b/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.ts
deleted file mode 100644
index bb51ed796b..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import shader from './watermarkPlacement.glsl';
-
-export const FX_watermarkPlacement = defineImageEffectorFx({
- id: 'watermarkPlacement',
- name: '(internal)',
- shader,
- uniforms: ['opacity', 'scale', 'angle', 'cover', 'repeat', 'alignX', 'alignY', 'margin', 'repeatMargin', 'noBBoxExpansion', 'wmResolution', 'wmEnabled', 'watermark'] as const,
- params: {
- cover: {
- type: 'boolean',
- default: false,
- },
- repeat: {
- type: 'boolean',
- default: false,
- },
- scale: {
- type: 'number',
- default: 0.3,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- },
- angle: {
- type: 'number',
- default: 0,
- min: -1.0,
- max: 1.0,
- step: 0.01,
- },
- align: {
- type: 'align',
- default: { x: 'right', y: 'bottom', margin: 0 },
- },
- opacity: {
- type: 'number',
- default: 0.75,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- },
- noBoundingBoxExpansion: {
- type: 'boolean',
- default: false,
- },
- watermark: {
- type: 'texture',
- default: null,
- },
- },
- main: ({ gl, u, params, textures }) => {
- // 基本パラメータ
- gl.uniform1f(u.opacity, params.opacity ?? 1.0);
- gl.uniform1f(u.scale, params.scale ?? 0.3);
- gl.uniform1f(u.angle, params.angle ?? 0.0);
- gl.uniform1i(u.cover, params.cover ? 1 : 0);
- gl.uniform1i(u.repeat, params.repeat ? 1 : 0);
- const ax = params.align?.x === 'left' ? 0 : params.align?.x === 'center' ? 1 : 2;
- const ay = params.align?.y === 'top' ? 0 : params.align?.y === 'center' ? 1 : 2;
- gl.uniform1i(u.alignX, ax);
- gl.uniform1i(u.alignY, ay);
- gl.uniform1f(u.margin, (params.align?.margin ?? 0));
- gl.uniform1f(u.repeatMargin, (params.align?.margin ?? 0));
- gl.uniform1i(u.noBBoxExpansion, params.noBoundingBoxExpansion ? 1 : 0);
-
- // ウォーターマークテクスチャ
- const wm = textures.watermark;
- if (wm) {
- gl.activeTexture(gl.TEXTURE1);
- gl.bindTexture(gl.TEXTURE_2D, wm.texture);
-
- // リピートモードに応じてWRAP属性を設定
- if (params.repeat) {
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
- } else {
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
- }
-
- gl.uniform1i(u.watermark, 1);
- gl.uniform2f(u.wmResolution, wm.width, wm.height);
- gl.uniform1i(u.wmEnabled, 1);
- } else {
- gl.uniform1i(u.wmEnabled, 0);
- }
- },
-});
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 a0f11fcb5b..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl
+++ /dev/null
@@ -1,48 +0,0 @@
-#version 300 es
-precision mediump float;
-
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-// エイリアスを解決してくれないので、プロジェクトルートからの絶対パスにする必要がある
-#include /src/shaders/snoise;
-
-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);
- vec2 centeredUv = (in_uv - vec2(0.5, 0.5));
- vec2 uv = centeredUv;
-
- float seed = 1.0;
- float time = 0.0;
-
- vec2 noiseUV = (uv - u_pos) / distance((uv - u_pos), vec2(0.0));
- float noiseX = (noiseUV.x + seed) * u_frequency;
- float noiseY = (noiseUV.y + seed) * u_frequency;
- float noise = (1.0 + snoise(vec3(noiseX, noiseY, time))) / 2.0;
-
- float t = noise;
- if (u_thresholdEnabled) t = t < u_threshold ? 1.0 : 0.0;
-
- // TODO: マスクの形自体も揺らぎを与える
- float d = distance(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
deleted file mode 100644
index 8c0956d24e..0000000000
--- a/packages/frontend/src/utility/image-effector/fxs/zoomLines.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { defineImageEffectorFx } from '../ImageEffector.js';
-import shader from './zoomLines.glsl';
-import { i18n } from '@/i18n.js';
-
-export const FX_zoomLines = defineImageEffectorFx({
- id: 'zoomLines',
- name: i18n.ts._imageEffector._fxs.zoomLines,
- shader,
- uniforms: ['pos', 'frequency', 'thresholdEnabled', 'threshold', 'maskSize', 'black'] as const,
- params: {
- x: {
- label: i18n.ts._imageEffector._fxProps.centerX,
- type: 'number',
- default: 0.0,
- min: -1.0,
- max: 1.0,
- step: 0.01,
- },
- y: {
- label: i18n.ts._imageEffector._fxProps.centerY,
- type: 'number',
- default: 0.0,
- min: -1.0,
- max: 1.0,
- step: 0.01,
- },
- frequency: {
- label: i18n.ts._imageEffector._fxProps.frequency,
- type: 'number',
- default: 5.0,
- min: 0.0,
- max: 15.0,
- step: 0.1,
- },
- smoothing: {
- label: i18n.ts._imageEffector._fxProps.zoomLinesSmoothing,
- caption: i18n.ts._imageEffector._fxProps.zoomLinesSmoothingDescription,
- type: 'boolean',
- default: false,
- },
- threshold: {
- label: i18n.ts._imageEffector._fxProps.zoomLinesThreshold,
- type: 'number',
- default: 0.5,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- },
- maskSize: {
- label: i18n.ts._imageEffector._fxProps.zoomLinesMaskSize,
- type: 'number',
- default: 0.5,
- min: 0.0,
- max: 1.0,
- step: 0.01,
- },
- black: {
- label: i18n.ts._imageEffector._fxProps.zoomLinesBlack,
- type: 'boolean',
- default: false,
- },
- },
- main: ({ gl, u, params }) => {
- gl.uniform2f(u.pos, params.x / 2, params.y / 2);
- gl.uniform1f(u.frequency, params.frequency * params.frequency);
- // thresholdの調整が有効な間はsmoothingが利用できない
- gl.uniform1i(u.thresholdEnabled, params.smoothing ? 0 : 1);
- gl.uniform1f(u.threshold, params.threshold);
- gl.uniform1f(u.maskSize, params.maskSize);
- gl.uniform1i(u.black, params.black ? 1 : 0);
- },
-});