wip
This commit is contained in:
parent
33486ebdf2
commit
09eb631fdc
|
@ -96,7 +96,7 @@ import { isWebpSupported } from '@/utility/isWebpSupported.js';
|
|||
import { uploadFile, UploadAbortedError } from '@/utility/drive.js';
|
||||
import * as os from '@/os.js';
|
||||
import { ensureSignin } from '@/i.js';
|
||||
import { Watermarker } from '@/utility/watermarker.js';
|
||||
import { ImageEffector } from '@/utility/ImageEffector.js';
|
||||
|
||||
const $i = ensureSignin();
|
||||
|
||||
|
@ -152,7 +152,7 @@ const items = ref<{
|
|||
uploaded: Misskey.entities.DriveFile | null;
|
||||
uploadFailed: boolean;
|
||||
aborted: boolean;
|
||||
compressionLevel: 0 | 1 | 2 | 3;
|
||||
compressionLevel: number;
|
||||
compressedSize?: number | null;
|
||||
preprocessedFile?: Blob | null;
|
||||
file: File;
|
||||
|
@ -486,11 +486,11 @@ async function preprocess(item: (typeof items)['value'][number]): Promise<void>
|
|||
const preset = prefer.s.watermarkPresets.find(p => p.id === item.watermarkPresetId);
|
||||
if (needsWatermark && preset != null) {
|
||||
const canvas = window.document.createElement('canvas');
|
||||
const renderer = new Watermarker({
|
||||
const renderer = new ImageEffector({
|
||||
canvas: canvas,
|
||||
width: img.width,
|
||||
height: img.height,
|
||||
preset: preset,
|
||||
layers: preset.layers,
|
||||
originalImage: img,
|
||||
});
|
||||
|
||||
|
|
|
@ -87,9 +87,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<script setup lang="ts">
|
||||
import { ref, useTemplateRef, watch, onMounted, onUnmounted } from 'vue';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import type { WatermarkerLayer, WatermarkPreset } from '@/utility/watermarker.js';
|
||||
import type { ImageEffectorLayer } from '@/utility/ImageEffector.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { Watermarker } from '@/utility/watermarker.js';
|
||||
import { ImageEffector } from '@/utility/ImageEffector.js';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
|
@ -102,7 +102,7 @@ import { selectFile } from '@/utility/drive.js';
|
|||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
||||
const layer = defineModel<WatermarkerLayer>('layer', { required: true });
|
||||
const layer = defineModel<ImageEffectorLayer>('layer', { required: true });
|
||||
|
||||
const driveFile = ref();
|
||||
const driveFileError = ref(false);
|
||||
|
|
|
@ -45,9 +45,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<script setup lang="ts">
|
||||
import { ref, useTemplateRef, watch, onMounted, onUnmounted, reactive } from 'vue';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import type { WatermarkPreset } from '@/utility/watermarker.js';
|
||||
import type { WatermarkPreset } from '@/preferences/def.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { Watermarker } from '@/utility/watermarker.js';
|
||||
import { ImageEffector } from '@/utility/ImageEffector.js';
|
||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
@ -121,7 +121,7 @@ watch(type, () => {
|
|||
|
||||
watch(preset, async (newValue, oldValue) => {
|
||||
if (renderer != null) {
|
||||
renderer.updatePreset(preset);
|
||||
renderer.updateLayers(preset.layers);
|
||||
}
|
||||
}, { deep: true });
|
||||
|
||||
|
@ -148,25 +148,25 @@ watch(sampleImageType, async () => {
|
|||
}
|
||||
});
|
||||
|
||||
let renderer: Watermarker | null = null;
|
||||
let renderer: ImageEffector | null = null;
|
||||
|
||||
async function initRenderer() {
|
||||
if (canvasEl.value == null) return;
|
||||
|
||||
if (sampleImageType.value === '3_2') {
|
||||
renderer = new Watermarker({
|
||||
renderer = new ImageEffector({
|
||||
canvas: canvasEl.value,
|
||||
width: 1500,
|
||||
height: 1000,
|
||||
preset: preset,
|
||||
layers: preset.layers,
|
||||
originalImage: sampleImage_3_2,
|
||||
});
|
||||
} else if (sampleImageType.value === '2_3') {
|
||||
renderer = new Watermarker({
|
||||
renderer = new ImageEffector({
|
||||
canvas: canvasEl.value,
|
||||
width: 1000,
|
||||
height: 1500,
|
||||
preset: preset,
|
||||
layers: preset.layers,
|
||||
originalImage: sampleImage_2_3,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -22,13 +22,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, onMounted, onUnmounted, ref, useTemplateRef, watch } from 'vue';
|
||||
import type { WatermarkPreset } from '@/utility/watermarker.js';
|
||||
import type { WatermarkPreset } from '@/preferences/def.js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { deepClone } from '@/utility/clone.js';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import { Watermarker } from '@/utility/watermarker.js';
|
||||
import { ImageEffector } from '@/utility/ImageEffector.js';
|
||||
|
||||
const props = defineProps<{
|
||||
preset: WatermarkPreset;
|
||||
|
@ -64,18 +64,18 @@ const canvasEl = useTemplateRef('canvasEl');
|
|||
const sampleImage = new Image();
|
||||
sampleImage.src = '/client-assets/sample/3-2.jpg';
|
||||
|
||||
let renderer: Watermarker | null = null;
|
||||
let renderer: ImageEffector | null = null;
|
||||
|
||||
onMounted(() => {
|
||||
sampleImage.onload = async () => {
|
||||
watch(canvasEl, async () => {
|
||||
if (canvasEl.value == null) return;
|
||||
|
||||
renderer = new Watermarker({
|
||||
renderer = new ImageEffector({
|
||||
canvas: canvasEl.value,
|
||||
width: 1500,
|
||||
height: 1000,
|
||||
preset: props.preset,
|
||||
layers: props.preset.layers,
|
||||
originalImage: sampleImage,
|
||||
});
|
||||
|
||||
|
@ -95,7 +95,7 @@ onUnmounted(() => {
|
|||
|
||||
watch(() => props.preset, async () => {
|
||||
if (renderer != null) {
|
||||
renderer.updatePreset(props.preset);
|
||||
renderer.updateLayers(props.preset.layers);
|
||||
await renderer.bakeTextures();
|
||||
renderer.render();
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ import { computed, defineAsyncComponent, ref } from 'vue';
|
|||
import * as Misskey from 'misskey-js';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import XWatermarkItem from './drive.WatermarkItem.vue';
|
||||
import type { WatermarkPreset } from '@/utility/watermarker.js';
|
||||
import type { WatermarkPreset } from '@/preferences/def.js';
|
||||
import FormLink from '@/components/form/link.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
|
|
|
@ -11,7 +11,7 @@ import type { Plugin } from '@/plugin.js';
|
|||
import type { DeviceKind } from '@/utility/device-kind.js';
|
||||
import type { DeckProfile } from '@/deck.js';
|
||||
import type { PreferencesDefinition } from './manager.js';
|
||||
import type { WatermarkPreset } from '@/utility/watermarker.js';
|
||||
import type { ImageEffectorLayer } from '@/utility/ImageEffector.js';
|
||||
import { DEFAULT_DEVICE_KIND } from '@/utility/device-kind.js';
|
||||
|
||||
/** サウンド設定 */
|
||||
|
@ -30,6 +30,12 @@ export type SoundStore = {
|
|||
volume: number;
|
||||
};
|
||||
|
||||
export type WatermarkPreset = {
|
||||
id: string;
|
||||
name: string;
|
||||
layers: ImageEffectorLayer[];
|
||||
};
|
||||
|
||||
// NOTE: デフォルト値は他の設定の状態に依存してはならない(依存していた場合、ユーザーがその設定項目単体で「初期値にリセット」した場合不具合の原因になる)
|
||||
|
||||
export const PREF_DEF = {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
const IMAGE_ADD_SHADER = `#version 300 es
|
||||
const IMAGE_PLACEMENT_SHADER = `#version 300 es
|
||||
precision highp float;
|
||||
|
||||
in vec2 in_uv;
|
||||
|
@ -51,13 +51,7 @@ void main() {
|
|||
}
|
||||
`;
|
||||
|
||||
export type WatermarkPreset = {
|
||||
id: string;
|
||||
name: string;
|
||||
layers: WatermarkerLayer[];
|
||||
};
|
||||
|
||||
type WatermarkerTextLayer = {
|
||||
type ImageEffectorTextLayer = {
|
||||
id: string;
|
||||
type: 'text';
|
||||
text: string;
|
||||
|
@ -68,7 +62,7 @@ type WatermarkerTextLayer = {
|
|||
opacity: number;
|
||||
};
|
||||
|
||||
type WatermarkerImageLayer = {
|
||||
type ImageEffectorImageLayer = {
|
||||
id: string;
|
||||
type: 'image';
|
||||
imageUrl: string | null;
|
||||
|
@ -80,9 +74,9 @@ type WatermarkerImageLayer = {
|
|||
opacity: number;
|
||||
};
|
||||
|
||||
export type WatermarkerLayer = WatermarkerTextLayer | WatermarkerImageLayer;
|
||||
export type ImageEffectorLayer = ImageEffectorTextLayer | ImageEffectorImageLayer;
|
||||
|
||||
export class Watermarker {
|
||||
export class ImageEffector {
|
||||
private canvas: HTMLCanvasElement | null = null;
|
||||
private gl: WebGL2RenderingContext | null = null;
|
||||
private renderTextureProgram!: WebGLProgram;
|
||||
|
@ -90,7 +84,7 @@ export class Watermarker {
|
|||
private renderWidth!: number;
|
||||
private renderHeight!: number;
|
||||
private originalImage: ImageData | ImageBitmap | HTMLImageElement | HTMLCanvasElement;
|
||||
private preset: WatermarkPreset;
|
||||
private layers: ImageEffectorLayer[];
|
||||
private originalImageTexture: WebGLTexture;
|
||||
private resultTexture: WebGLTexture;
|
||||
private resultFrameBuffer: WebGLFramebuffer;
|
||||
|
@ -102,7 +96,7 @@ export class Watermarker {
|
|||
width: number;
|
||||
height: number;
|
||||
originalImage: ImageData | ImageBitmap | HTMLImageElement | HTMLCanvasElement;
|
||||
preset: WatermarkPreset;
|
||||
layers: ImageEffectorLayer[];
|
||||
}) {
|
||||
this.canvas = options.canvas;
|
||||
this.canvas.width = options.width;
|
||||
|
@ -110,7 +104,7 @@ export class Watermarker {
|
|||
this.renderWidth = options.width;
|
||||
this.renderHeight = options.height;
|
||||
this.originalImage = options.originalImage;
|
||||
this.preset = options.preset;
|
||||
this.layers = options.layers;
|
||||
this.texturesKey = this.calcTexturesKey();
|
||||
|
||||
this.gl = this.canvas.getContext('webgl2', {
|
||||
|
@ -180,7 +174,7 @@ export class Watermarker {
|
|||
}
|
||||
|
||||
private calcTexturesKey() {
|
||||
return this.preset.layers.map(layer => {
|
||||
return this.layers.map(layer => {
|
||||
if (layer.type === 'image') {
|
||||
return layer.imageId;
|
||||
} else if (layer.type === 'text') {
|
||||
|
@ -224,10 +218,11 @@ export class Watermarker {
|
|||
|
||||
this.disposeBakedTextures();
|
||||
|
||||
for (const layer of this.preset.layers) {
|
||||
for (const layer of this.layers) {
|
||||
if (layer.type === 'image') {
|
||||
const image = await new Promise<HTMLImageElement>((resolve, reject) => {
|
||||
const img = new Image();
|
||||
img.crossOrigin = 'use-credentials';
|
||||
img.onload = () => resolve(img);
|
||||
img.onerror = reject;
|
||||
img.src = layer.imageUrl;
|
||||
|
@ -332,7 +327,7 @@ export class Watermarker {
|
|||
return shaderProgram;
|
||||
}
|
||||
|
||||
private renderTextOrImageLayer(layer: WatermarkerTextLayer | WatermarkerImageLayer) {
|
||||
private renderTextOrImageLayer(layer: ImageEffectorTextLayer | ImageEffectorImageLayer) {
|
||||
const gl = this.gl;
|
||||
if (gl == null) {
|
||||
throw new Error('gl is not initialized');
|
||||
|
@ -351,7 +346,7 @@ export class Watermarker {
|
|||
in_uv = (position + 1.0) / 2.0;
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
}
|
||||
`, IMAGE_ADD_SHADER);
|
||||
`, IMAGE_PLACEMENT_SHADER);
|
||||
|
||||
gl.useProgram(shaderProgram);
|
||||
|
||||
|
@ -392,7 +387,7 @@ export class Watermarker {
|
|||
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||
}
|
||||
|
||||
private renderLayer(layer: WatermarkerLayer) {
|
||||
private renderLayer(layer: ImageEffectorLayer) {
|
||||
if (layer.type === 'image') {
|
||||
this.renderTextOrImageLayer(layer);
|
||||
} else if (layer.type === 'text') {
|
||||
|
@ -435,7 +430,7 @@ export class Watermarker {
|
|||
|
||||
// --------------------
|
||||
|
||||
for (const layer of this.preset.layers) {
|
||||
for (const layer of this.layers) {
|
||||
this.renderLayer(layer);
|
||||
}
|
||||
|
||||
|
@ -450,8 +445,8 @@ export class Watermarker {
|
|||
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||
}
|
||||
|
||||
public async updatePreset(preset: WatermarkPreset) {
|
||||
this.preset = preset;
|
||||
public async updateLayers(layers: ImageEffectorLayer[]) {
|
||||
this.layers = layers;
|
||||
|
||||
const newTexturesKey = this.calcTexturesKey();
|
||||
if (newTexturesKey !== this.texturesKey) {
|
Loading…
Reference in New Issue