wip
This commit is contained in:
parent
ec79b3ae37
commit
244f5a2793
|
|
@ -5658,6 +5658,14 @@ export interface Locale extends ILocale {
|
|||
* 二次元コード
|
||||
*/
|
||||
"withQrCode": string;
|
||||
/**
|
||||
* 背景色
|
||||
*/
|
||||
"backgroundColor": string;
|
||||
/**
|
||||
* 文字色
|
||||
*/
|
||||
"textColor": string;
|
||||
};
|
||||
"_compression": {
|
||||
"_quality": {
|
||||
|
|
|
|||
|
|
@ -1411,6 +1411,8 @@ _imageFrameEditor:
|
|||
captionSub: "キャプション(小)"
|
||||
availableVariables: "利用可能な変数"
|
||||
withQrCode: "二次元コード"
|
||||
backgroundColor: "背景色"
|
||||
textColor: "文字色"
|
||||
|
||||
_compression:
|
||||
_quality:
|
||||
|
|
|
|||
|
|
@ -35,6 +35,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template #label>{{ i18n.ts._imageFrameEditor.borderThickness }}</template>
|
||||
</MkRange>
|
||||
|
||||
<MkInput :modelValue="getHex(frame.bgColor)" type="color" @update:modelValue="v => { const c = getRgb(v); if (c != null) frame.bgColor = c; }">
|
||||
<template #label>{{ i18n.ts._imageFrameEditor.backgroundColor }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkInput :modelValue="getHex(frame.fgColor)" type="color" @update:modelValue="v => { const c = getRgb(v); if (c != null) frame.fgColor = c; }">
|
||||
<template #label>{{ i18n.ts._imageFrameEditor.textColor }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkFolder :defaultOpen="true">
|
||||
<template #label>{{ i18n.ts._imageFrameEditor.header }}</template>
|
||||
|
||||
|
|
@ -180,7 +188,7 @@ const frame = reactive<ImageFrameParams>(deepClone(props.frame) ?? {
|
|||
centered: false,
|
||||
withQrCode: true,
|
||||
},
|
||||
bgColor: [255, 255, 255],
|
||||
bgColor: [1, 1, 1],
|
||||
fgColor: [0, 0, 0],
|
||||
});
|
||||
|
||||
|
|
@ -321,6 +329,24 @@ async function save() {
|
|||
|
||||
emit('ok', preset);
|
||||
}
|
||||
|
||||
function getHex(c: [number, number, number]) {
|
||||
return `#${c.map(x => (x * 255).toString(16).padStart(2, '0')).join('')}`;
|
||||
}
|
||||
|
||||
function getRgb(hex: string | number): [number, number, number] | null {
|
||||
if (
|
||||
typeof hex === 'number' ||
|
||||
typeof hex !== 'string' ||
|
||||
!/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(hex)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const m = hex.slice(1).match(/[0-9a-fA-F]{2}/g);
|
||||
if (m == null) return [0, 0, 0];
|
||||
return m.map(x => parseInt(x, 16) / 255) as [number, number, number];
|
||||
}
|
||||
</script>
|
||||
|
||||
<style module>
|
||||
|
|
|
|||
|
|
@ -18,14 +18,19 @@ uniform float u_paddingTop;
|
|||
uniform float u_paddingBottom;
|
||||
uniform float u_paddingLeft;
|
||||
uniform float u_paddingRight;
|
||||
uniform vec3 u_bg;
|
||||
out vec4 out_color;
|
||||
|
||||
float remap(float value, float inputMin, float inputMax, float outputMin, float outputMax) {
|
||||
return outputMin + (outputMax - outputMin) * ((value - inputMin) / (inputMax - inputMin));
|
||||
}
|
||||
|
||||
vec3 blendAlpha(vec3 bg, vec4 fg) {
|
||||
return fg.a * fg.rgb + (1.0 - fg.a) * bg;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 bg = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
vec4 bg = vec4(u_bg, 1.0);
|
||||
|
||||
vec4 image_color = texture(u_image, vec2(
|
||||
remap(in_uv.x, u_paddingLeft, 1.0 - u_paddingRight, 0.0, 1.0),
|
||||
|
|
@ -43,9 +48,9 @@ void main() {
|
|||
)) : bg;
|
||||
|
||||
if (in_uv.y < u_paddingTop) {
|
||||
out_color = topLabel_color;
|
||||
out_color = vec4(blendAlpha(bg.rgb, topLabel_color), 1.0);
|
||||
} else if (in_uv.y > (1.0 - u_paddingBottom)) {
|
||||
out_color = bottomLabel_color;
|
||||
out_color = vec4(blendAlpha(bg.rgb, bottomLabel_color), 1.0);
|
||||
} else {
|
||||
if (in_uv.y > u_paddingTop && in_uv.x > u_paddingLeft && in_uv.x < (1.0 - u_paddingRight)) {
|
||||
out_color = image_color;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export const FX_frame = defineImageEffectorFx({
|
|||
id: 'frame',
|
||||
name: '(internal)',
|
||||
shader,
|
||||
uniforms: ['image', 'topLabel', 'bottomLabel', 'topLabelEnabled', 'bottomLabelEnabled', 'paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight'] as const,
|
||||
uniforms: ['image', 'topLabel', 'bottomLabel', 'topLabelEnabled', 'bottomLabelEnabled', 'paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight', 'bg'] as const,
|
||||
params: {
|
||||
image: {
|
||||
type: 'textureRef',
|
||||
|
|
@ -56,6 +56,10 @@ export const FX_frame = defineImageEffectorFx({
|
|||
max: 1,
|
||||
min: 0,
|
||||
},
|
||||
bg: {
|
||||
type: 'color',
|
||||
default: [1, 1, 1],
|
||||
},
|
||||
},
|
||||
main: ({ gl, u, params, textures }) => {
|
||||
const image = textures.image;
|
||||
|
|
@ -71,6 +75,7 @@ export const FX_frame = defineImageEffectorFx({
|
|||
gl.uniform1f(u.paddingBottom, params.paddingBottom);
|
||||
gl.uniform1f(u.paddingLeft, params.paddingLeft);
|
||||
gl.uniform1f(u.paddingRight, params.paddingRight);
|
||||
gl.uniform3f(u.bg, params.bg[0], params.bg[1], params.bg[2]);
|
||||
|
||||
if (params.topLabelEnabled) {
|
||||
const topLabel = textures.topLabel;
|
||||
|
|
|
|||
|
|
@ -112,9 +112,6 @@ export class ImageFrameRenderer {
|
|||
const qrSize = scaleBase * 0.1;
|
||||
const qrMarginRight = Math.max((labelCanvasCtx.canvas.height - qrSize) / 2, paddingRight);
|
||||
|
||||
labelCanvasCtx.fillStyle = '#ffffff';
|
||||
labelCanvasCtx.fillRect(0, 0, labelCanvasCtx.canvas.width, labelCanvasCtx.canvas.height);
|
||||
|
||||
labelCanvasCtx.fillStyle = '#000000';
|
||||
labelCanvasCtx.font = `bold ${fontSize}px sans-serif`;
|
||||
labelCanvasCtx.textBaseline = 'middle';
|
||||
|
|
@ -241,6 +238,7 @@ export class ImageFrameRenderer {
|
|||
paddingRight: paddingRight / renderWidth,
|
||||
paddingTop: paddingTop / renderHeight,
|
||||
paddingBottom: paddingBottom / renderHeight,
|
||||
bg: params.bgColor,
|
||||
},
|
||||
}]);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue