wip
This commit is contained in:
parent
368b98bbfd
commit
7bff6cccb7
|
@ -12105,6 +12105,10 @@ export interface Locale extends ILocale {
|
||||||
* 点グリッド
|
* 点グリッド
|
||||||
*/
|
*/
|
||||||
"dottedGrid": string;
|
"dottedGrid": string;
|
||||||
|
/**
|
||||||
|
* チェッカー
|
||||||
|
*/
|
||||||
|
"checker": string;
|
||||||
};
|
};
|
||||||
"_imageEffector": {
|
"_imageEffector": {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3241,6 +3241,7 @@ _watermarkEditor:
|
||||||
stripeFrequency: "ラインの数"
|
stripeFrequency: "ラインの数"
|
||||||
angle: "角度"
|
angle: "角度"
|
||||||
dottedGrid: "点グリッド"
|
dottedGrid: "点グリッド"
|
||||||
|
checker: "チェッカー"
|
||||||
|
|
||||||
_imageEffector:
|
_imageEffector:
|
||||||
title: "エフェクト"
|
title: "エフェクト"
|
||||||
|
|
|
@ -54,6 +54,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #label>{{ i18n.ts._watermarkEditor.repeat }}</template>
|
<template #label>{{ i18n.ts._watermarkEditor.repeat }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else-if="layer.type === 'image'">
|
<template v-else-if="layer.type === 'image'">
|
||||||
<MkButton inline rounded primary @click="chooseFile">{{ i18n.ts.selectFile }}</MkButton>
|
<MkButton inline rounded primary @click="chooseFile">{{ i18n.ts.selectFile }}</MkButton>
|
||||||
|
|
||||||
|
@ -105,6 +106,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #label>{{ i18n.ts._watermarkEditor.cover }}</template>
|
<template #label>{{ i18n.ts._watermarkEditor.cover }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else-if="layer.type === 'stripe'">
|
<template v-else-if="layer.type === 'stripe'">
|
||||||
<MkRange
|
<MkRange
|
||||||
v-model="layer.frequency"
|
v-model="layer.frequency"
|
||||||
|
@ -147,12 +149,109 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #label>{{ i18n.ts._watermarkEditor.opacity }}</template>
|
<template #label>{{ i18n.ts._watermarkEditor.opacity }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template v-else-if="layer.type === 'dottedGrid'">
|
||||||
|
<MkRange
|
||||||
|
v-model="layer.angle"
|
||||||
|
:min="-1"
|
||||||
|
:max="1"
|
||||||
|
:step="0.01"
|
||||||
|
continuousUpdate
|
||||||
|
>
|
||||||
|
<template #label>{{ i18n.ts._watermarkEditor.angle }}</template>
|
||||||
|
</MkRange>
|
||||||
|
|
||||||
|
<MkRange
|
||||||
|
v-model="layer.scale"
|
||||||
|
:min="0"
|
||||||
|
:max="10"
|
||||||
|
:step="0.01"
|
||||||
|
continuousUpdate
|
||||||
|
>
|
||||||
|
<template #label>{{ i18n.ts._watermarkEditor.scale }}</template>
|
||||||
|
</MkRange>
|
||||||
|
|
||||||
|
<MkRange
|
||||||
|
v-model="layer.minorRadius"
|
||||||
|
:min="0"
|
||||||
|
:max="1"
|
||||||
|
:step="0.01"
|
||||||
|
:textConverter="(v) => (v * 100).toFixed(1) + '%'"
|
||||||
|
continuousUpdate
|
||||||
|
>
|
||||||
|
<template #label>{{ i18n.ts._watermarkEditor.gridMinorRadius }}</template>
|
||||||
|
</MkRange>
|
||||||
|
|
||||||
|
<MkRange
|
||||||
|
v-model="layer.minorDivisions"
|
||||||
|
:min="0"
|
||||||
|
:max="16"
|
||||||
|
:step="1"
|
||||||
|
continuousUpdate
|
||||||
|
>
|
||||||
|
<template #label>{{ i18n.ts._watermarkEditor.gridMinorDivisions }}</template>
|
||||||
|
</MkRange>
|
||||||
|
|
||||||
|
<MkRange
|
||||||
|
v-model="layer.majorOpacity"
|
||||||
|
:min="0"
|
||||||
|
:max="1"
|
||||||
|
:step="0.01"
|
||||||
|
:textConverter="(v) => (v * 100).toFixed(1) + '%'"
|
||||||
|
continuousUpdate
|
||||||
|
>
|
||||||
|
<template #label>{{ i18n.ts._watermarkEditor.gridMajorOpacity }}</template>
|
||||||
|
</MkRange>
|
||||||
|
|
||||||
|
<MkRange
|
||||||
|
v-model="layer.minorOpacity"
|
||||||
|
:min="0"
|
||||||
|
:max="1"
|
||||||
|
:step="0.01"
|
||||||
|
:textConverter="(v) => (v * 100).toFixed(1) + '%'"
|
||||||
|
continuousUpdate
|
||||||
|
>
|
||||||
|
<template #label>{{ i18n.ts._watermarkEditor.gridMinorOpacity }}</template>
|
||||||
|
</MkRange>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else-if="layer.type === 'checker'">
|
||||||
|
<MkRange
|
||||||
|
v-model="layer.angle"
|
||||||
|
:min="-1"
|
||||||
|
:max="1"
|
||||||
|
:step="0.01"
|
||||||
|
continuousUpdate
|
||||||
|
>
|
||||||
|
<template #label>{{ i18n.ts._watermarkEditor.angle }}</template>
|
||||||
|
</MkRange>
|
||||||
|
|
||||||
|
<MkRange
|
||||||
|
v-model="layer.scale"
|
||||||
|
:min="0"
|
||||||
|
:max="10"
|
||||||
|
:step="0.01"
|
||||||
|
continuousUpdate
|
||||||
|
>
|
||||||
|
<template #label>{{ i18n.ts._watermarkEditor.scale }}</template>
|
||||||
|
</MkRange>
|
||||||
|
|
||||||
|
<MkRange
|
||||||
|
v-model="layer.opacity"
|
||||||
|
:min="0"
|
||||||
|
:max="1"
|
||||||
|
:step="0.01"
|
||||||
|
:textConverter="(v) => (v * 100).toFixed(1) + '%'"
|
||||||
|
continuousUpdate
|
||||||
|
>
|
||||||
|
<template #label>{{ i18n.ts._watermarkEditor.opacity }}</template>
|
||||||
|
</MkRange>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, useTemplateRef, watch, onMounted, onUnmounted } from 'vue';
|
import { ref, useTemplateRef, watch, onMounted, onUnmounted } from 'vue';
|
||||||
import type { ImageEffectorLayer } from '@/utility/image-effector/ImageEffector.js';
|
|
||||||
import type { WatermarkPreset } from '@/utility/watermark.js';
|
import type { WatermarkPreset } from '@/utility/watermark.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
|
|
|
@ -47,6 +47,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div v-if="layer.type === 'text'">{{ i18n.ts._watermarkEditor.text }}</div>
|
<div v-if="layer.type === 'text'">{{ i18n.ts._watermarkEditor.text }}</div>
|
||||||
<div v-if="layer.type === 'image'">{{ i18n.ts._watermarkEditor.image }}</div>
|
<div v-if="layer.type === 'image'">{{ i18n.ts._watermarkEditor.image }}</div>
|
||||||
<div v-if="layer.type === 'stripe'">{{ i18n.ts._watermarkEditor.stripe }}</div>
|
<div v-if="layer.type === 'stripe'">{{ i18n.ts._watermarkEditor.stripe }}</div>
|
||||||
|
<div v-if="layer.type === 'dottedGrid'">{{ i18n.ts._watermarkEditor.dottedGrid }}</div>
|
||||||
|
<div v-if="layer.type === 'checker'">{{ i18n.ts._watermarkEditor.checker }}</div>
|
||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="_buttons">
|
<div class="_buttons">
|
||||||
|
@ -127,6 +129,33 @@ function createStripeLayer(): WatermarkPreset['layers'][number] {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createDottedGridLayer(): WatermarkPreset['layers'][number] {
|
||||||
|
return {
|
||||||
|
id: genId(),
|
||||||
|
type: 'dottedGrid',
|
||||||
|
angle: 0.5,
|
||||||
|
scale: 3,
|
||||||
|
majorRadius: 0.1,
|
||||||
|
minorRadius: 0.25,
|
||||||
|
majorOpacity: 0.75,
|
||||||
|
minorOpacity: 0.5,
|
||||||
|
minorDivisions: 4,
|
||||||
|
black: false,
|
||||||
|
opacity: 0.75,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createCheckerLayer(): WatermarkPreset['layers'][number] {
|
||||||
|
return {
|
||||||
|
id: genId(),
|
||||||
|
type: 'checker',
|
||||||
|
angle: 0.5,
|
||||||
|
scale: 3,
|
||||||
|
black: false,
|
||||||
|
opacity: 0.75,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
preset?: WatermarkPreset | null;
|
preset?: WatermarkPreset | null;
|
||||||
image?: File | null;
|
image?: File | null;
|
||||||
|
@ -301,6 +330,16 @@ function addLayer(ev: MouseEvent) {
|
||||||
action: () => {
|
action: () => {
|
||||||
preset.layers.push(createStripeLayer());
|
preset.layers.push(createStripeLayer());
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
text: i18n.ts._watermarkEditor.dottedGrid,
|
||||||
|
action: () => {
|
||||||
|
preset.layers.push(createDottedGridLayer());
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
text: i18n.ts._watermarkEditor.checker,
|
||||||
|
action: () => {
|
||||||
|
preset.layers.push(createCheckerLayer());
|
||||||
|
},
|
||||||
}], ev.currentTarget ?? ev.target);
|
}], ev.currentTarget ?? ev.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
import { FX_watermarkPlacement } from './image-effector/fxs/watermarkPlacement.js';
|
import { FX_watermarkPlacement } from './image-effector/fxs/watermarkPlacement.js';
|
||||||
import { FX_stripe } from './image-effector/fxs/stripe.js';
|
import { FX_stripe } from './image-effector/fxs/stripe.js';
|
||||||
|
import { FX_dottedGrid } from './image-effector/fxs/dottedGrid.js';
|
||||||
|
import { FX_checker } from './image-effector/fxs/checker.js';
|
||||||
import type { ImageEffectorLayer } from '@/utility/image-effector/ImageEffector.js';
|
import type { ImageEffectorLayer } from '@/utility/image-effector/ImageEffector.js';
|
||||||
import { ImageEffector } from '@/utility/image-effector/ImageEffector.js';
|
import { ImageEffector } from '@/utility/image-effector/ImageEffector.js';
|
||||||
|
|
||||||
|
@ -39,6 +41,25 @@ export type WatermarkPreset = {
|
||||||
threshold: number;
|
threshold: number;
|
||||||
black: boolean;
|
black: boolean;
|
||||||
opacity: number;
|
opacity: number;
|
||||||
|
} | {
|
||||||
|
id: string;
|
||||||
|
type: 'dottedGrid';
|
||||||
|
angle: number;
|
||||||
|
scale: number;
|
||||||
|
majorRadius: number;
|
||||||
|
majorOpacity: number;
|
||||||
|
minorDivisions: number;
|
||||||
|
minorRadius: number;
|
||||||
|
minorOpacity: number;
|
||||||
|
black: boolean;
|
||||||
|
opacity: number;
|
||||||
|
} | {
|
||||||
|
id: string;
|
||||||
|
type: 'checker';
|
||||||
|
angle: number;
|
||||||
|
scale: number;
|
||||||
|
black: boolean;
|
||||||
|
opacity: number;
|
||||||
})[];
|
})[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,7 +78,7 @@ export class WatermarkRenderer {
|
||||||
renderWidth: options.renderWidth,
|
renderWidth: options.renderWidth,
|
||||||
renderHeight: options.renderHeight,
|
renderHeight: options.renderHeight,
|
||||||
image: options.image,
|
image: options.image,
|
||||||
fxs: [FX_watermarkPlacement, FX_stripe],
|
fxs: [FX_watermarkPlacement, FX_stripe, FX_dottedGrid, FX_checker],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +130,33 @@ export class WatermarkRenderer {
|
||||||
opacity: layer.opacity,
|
opacity: layer.opacity,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
} else if (layer.type === 'dottedGrid') {
|
||||||
|
return {
|
||||||
|
fxId: 'dottedGrid',
|
||||||
|
id: layer.id,
|
||||||
|
params: {
|
||||||
|
angle: layer.angle,
|
||||||
|
scale: layer.scale,
|
||||||
|
majorRadius: layer.majorRadius,
|
||||||
|
majorOpacity: layer.majorOpacity,
|
||||||
|
minorDivisions: layer.minorDivisions,
|
||||||
|
minorRadius: layer.minorRadius,
|
||||||
|
minorOpacity: layer.minorOpacity,
|
||||||
|
black: layer.black,
|
||||||
|
opacity: layer.opacity,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} else if (layer.type === 'checker') {
|
||||||
|
return {
|
||||||
|
fxId: 'checker',
|
||||||
|
id: layer.id,
|
||||||
|
params: {
|
||||||
|
angle: layer.angle,
|
||||||
|
scale: layer.scale,
|
||||||
|
black: layer.black,
|
||||||
|
opacity: layer.opacity,
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue