wip
This commit is contained in:
parent
7bb9d3d0af
commit
a54b4f2fd9
|
|
@ -5618,6 +5618,14 @@ export interface Locale extends ILocale {
|
||||||
* 画像にフレームやメタデータを含んだラベルを追加して装飾できます。
|
* 画像にフレームやメタデータを含んだラベルを追加して装飾できます。
|
||||||
*/
|
*/
|
||||||
"tip": string;
|
"tip": string;
|
||||||
|
/**
|
||||||
|
* ヘッダー
|
||||||
|
*/
|
||||||
|
"header": string;
|
||||||
|
/**
|
||||||
|
* フッター
|
||||||
|
*/
|
||||||
|
"footer": string;
|
||||||
/**
|
/**
|
||||||
* フチの幅
|
* フチの幅
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1401,6 +1401,8 @@ frame: "フレーム"
|
||||||
_imageFrameEditor:
|
_imageFrameEditor:
|
||||||
title: "フレームの編集"
|
title: "フレームの編集"
|
||||||
tip: "画像にフレームやメタデータを含んだラベルを追加して装飾できます。"
|
tip: "画像にフレームやメタデータを含んだラベルを追加して装飾できます。"
|
||||||
|
header: "ヘッダー"
|
||||||
|
footer: "フッター"
|
||||||
borderThickness: "フチの幅"
|
borderThickness: "フチの幅"
|
||||||
labelThickness: "ラベルの幅"
|
labelThickness: "ラベルの幅"
|
||||||
labelScale: "ラベルのスケール"
|
labelScale: "ラベルのスケール"
|
||||||
|
|
|
||||||
|
|
@ -35,29 +35,65 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #label>{{ i18n.ts._imageFrameEditor.borderThickness }}</template>
|
<template #label>{{ i18n.ts._imageFrameEditor.borderThickness }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
|
|
||||||
<MkRange v-model="frame.labelThickness" :min="0.01" :max="0.5" :step="0.01" :continuousUpdate="true">
|
<MkFolder :defaultOpen="true">
|
||||||
<template #label>{{ i18n.ts._imageFrameEditor.labelThickness }}</template>
|
<template #label>{{ i18n.ts._imageFrameEditor.header }}</template>
|
||||||
</MkRange>
|
|
||||||
|
|
||||||
<MkRange v-model="frame.labelScale" :min="0.5" :max="2.0" :step="0.01" :continuousUpdate="true">
|
<div class="_gaps">
|
||||||
<template #label>{{ i18n.ts._imageFrameEditor.labelScale }}</template>
|
<MkRange v-model="frame.labelTop.padding" :min="0.01" :max="0.5" :step="0.01" :continuousUpdate="true">
|
||||||
</MkRange>
|
<template #label>{{ i18n.ts._imageFrameEditor.labelThickness }}</template>
|
||||||
|
</MkRange>
|
||||||
|
|
||||||
<MkSwitch v-model="frame.centered">
|
<MkRange v-model="frame.labelTop.scale" :min="0.5" :max="2.0" :step="0.01" :continuousUpdate="true">
|
||||||
<template #label>{{ i18n.ts._imageFrameEditor.centered }}</template>
|
<template #label>{{ i18n.ts._imageFrameEditor.labelScale }}</template>
|
||||||
</MkSwitch>
|
</MkRange>
|
||||||
|
|
||||||
<MkInput v-model="frame.title">
|
<MkSwitch v-model="frame.labelTop.centered">
|
||||||
<template #label>{{ i18n.ts._imageFrameEditor.captionMain }}</template>
|
<template #label>{{ i18n.ts._imageFrameEditor.centered }}</template>
|
||||||
</MkInput>
|
</MkSwitch>
|
||||||
|
|
||||||
<MkTextarea v-model="frame.text">
|
<MkInput v-model="frame.labelTop.textBig">
|
||||||
<template #label>{{ i18n.ts._imageFrameEditor.captionSub }}</template>
|
<template #label>{{ i18n.ts._imageFrameEditor.captionMain }}</template>
|
||||||
</MkTextarea>
|
</MkInput>
|
||||||
|
|
||||||
<MkSwitch v-model="frame.withQrCode">
|
<MkTextarea v-model="frame.labelTop.textSmall">
|
||||||
<template #label>{{ i18n.ts._imageFrameEditor.withQrCode }}</template>
|
<template #label>{{ i18n.ts._imageFrameEditor.captionSub }}</template>
|
||||||
</MkSwitch>
|
</MkTextarea>
|
||||||
|
|
||||||
|
<MkSwitch v-model="frame.labelTop.withQrCode">
|
||||||
|
<template #label>{{ i18n.ts._imageFrameEditor.withQrCode }}</template>
|
||||||
|
</MkSwitch>
|
||||||
|
</div>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
|
<MkFolder :defaultOpen="true">
|
||||||
|
<template #label>{{ i18n.ts._imageFrameEditor.footer }}</template>
|
||||||
|
|
||||||
|
<div class="_gaps">
|
||||||
|
<MkRange v-model="frame.labelBottom.padding" :min="0.01" :max="0.5" :step="0.01" :continuousUpdate="true">
|
||||||
|
<template #label>{{ i18n.ts._imageFrameEditor.labelThickness }}</template>
|
||||||
|
</MkRange>
|
||||||
|
|
||||||
|
<MkRange v-model="frame.labelBottom.scale" :min="0.5" :max="2.0" :step="0.01" :continuousUpdate="true">
|
||||||
|
<template #label>{{ i18n.ts._imageFrameEditor.labelScale }}</template>
|
||||||
|
</MkRange>
|
||||||
|
|
||||||
|
<MkSwitch v-model="frame.labelBottom.centered">
|
||||||
|
<template #label>{{ i18n.ts._imageFrameEditor.centered }}</template>
|
||||||
|
</MkSwitch>
|
||||||
|
|
||||||
|
<MkInput v-model="frame.labelBottom.textBig">
|
||||||
|
<template #label>{{ i18n.ts._imageFrameEditor.captionMain }}</template>
|
||||||
|
</MkInput>
|
||||||
|
|
||||||
|
<MkTextarea v-model="frame.labelBottom.textSmall">
|
||||||
|
<template #label>{{ i18n.ts._imageFrameEditor.captionSub }}</template>
|
||||||
|
</MkTextarea>
|
||||||
|
|
||||||
|
<MkSwitch v-model="frame.labelBottom.withQrCode">
|
||||||
|
<template #label>{{ i18n.ts._imageFrameEditor.withQrCode }}</template>
|
||||||
|
</MkSwitch>
|
||||||
|
</div>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<MkInfo>
|
<MkInfo>
|
||||||
<div>{{ i18n.ts._imageFrameEditor.availableVariables }}:</div>
|
<div>{{ i18n.ts._imageFrameEditor.availableVariables }}:</div>
|
||||||
|
|
@ -118,12 +154,22 @@ const props = defineProps<{
|
||||||
|
|
||||||
const frame = reactive<ImageFrameParams>(deepClone(props.frame) ?? {
|
const frame = reactive<ImageFrameParams>(deepClone(props.frame) ?? {
|
||||||
borderThickness: 0.05,
|
borderThickness: 0.05,
|
||||||
labelThickness: 0.2,
|
labelTop: {
|
||||||
labelScale: 1.0,
|
scale: 1.0,
|
||||||
title: '{year}/{0month}/{0day}',
|
padding: 0.2,
|
||||||
text: '{camera_mm}mm f/{camera_f} {camera_s}s ISO{camera_iso}',
|
textBig: '',
|
||||||
centered: false,
|
textSmall: '',
|
||||||
withQrCode: true,
|
centered: false,
|
||||||
|
withQrCode: false,
|
||||||
|
},
|
||||||
|
labelBottom: {
|
||||||
|
scale: 1.0,
|
||||||
|
padding: 0.2,
|
||||||
|
textBig: '{year}/{0month}/{0day}',
|
||||||
|
textSmall: '{camera_mm}mm f/{camera_f} {camera_s}s ISO{camera_iso}',
|
||||||
|
centered: false,
|
||||||
|
withQrCode: true,
|
||||||
|
},
|
||||||
bgColor: [255, 255, 255],
|
bgColor: [255, 255, 255],
|
||||||
fgColor: [0, 0, 0],
|
fgColor: [0, 0, 0],
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ in vec2 in_uv;
|
||||||
uniform sampler2D in_texture;
|
uniform sampler2D in_texture;
|
||||||
uniform vec2 in_resolution;
|
uniform vec2 in_resolution;
|
||||||
uniform sampler2D u_image;
|
uniform sampler2D u_image;
|
||||||
uniform sampler2D u_label;
|
uniform sampler2D u_topLabel;
|
||||||
|
uniform sampler2D u_bottomLabel;
|
||||||
uniform float u_paddingTop;
|
uniform float u_paddingTop;
|
||||||
uniform float u_paddingBottom;
|
uniform float u_paddingBottom;
|
||||||
uniform float u_paddingLeft;
|
uniform float u_paddingLeft;
|
||||||
|
|
@ -27,13 +28,20 @@ void main() {
|
||||||
remap(in_uv.y, u_paddingTop, 1.0 - u_paddingBottom, 0.0, 1.0)
|
remap(in_uv.y, u_paddingTop, 1.0 - u_paddingBottom, 0.0, 1.0)
|
||||||
));
|
));
|
||||||
|
|
||||||
vec4 label_color = texture(u_label, vec2(
|
vec4 topLabel_color = texture(u_topLabel, vec2(
|
||||||
|
in_uv.x,
|
||||||
|
remap(in_uv.y, 0.0, u_paddingTop, 0.0, 1.0)
|
||||||
|
));
|
||||||
|
|
||||||
|
vec4 bottomLabel_color = texture(u_bottomLabel, vec2(
|
||||||
in_uv.x,
|
in_uv.x,
|
||||||
remap(in_uv.y, 1.0 - u_paddingBottom, 1.0, 0.0, 1.0)
|
remap(in_uv.y, 1.0 - u_paddingBottom, 1.0, 0.0, 1.0)
|
||||||
));
|
));
|
||||||
|
|
||||||
if (in_uv.y > (1.0 - u_paddingBottom)) {
|
if (in_uv.y < u_paddingTop) {
|
||||||
out_color = label_color;
|
out_color = topLabel_color;
|
||||||
|
} else if (in_uv.y > (1.0 - u_paddingBottom)) {
|
||||||
|
out_color = bottomLabel_color;
|
||||||
} else {
|
} else {
|
||||||
if (in_uv.y > u_paddingTop && in_uv.x > u_paddingLeft && in_uv.x < (1.0 - u_paddingRight)) {
|
if (in_uv.y > u_paddingTop && in_uv.x > u_paddingLeft && in_uv.x < (1.0 - u_paddingRight)) {
|
||||||
out_color = image_color;
|
out_color = image_color;
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,17 @@ export const FX_frame = defineImageEffectorFx({
|
||||||
id: 'frame',
|
id: 'frame',
|
||||||
name: '(internal)',
|
name: '(internal)',
|
||||||
shader,
|
shader,
|
||||||
uniforms: ['image', 'label', 'paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight'] as const,
|
uniforms: ['image', 'topLabel', 'bottomLabel', 'paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight'] as const,
|
||||||
params: {
|
params: {
|
||||||
image: {
|
image: {
|
||||||
type: 'textureRef',
|
type: 'textureRef',
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
label: {
|
topLabel: {
|
||||||
|
type: 'textureRef',
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
bottomLabel: {
|
||||||
type: 'textureRef',
|
type: 'textureRef',
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
|
|
@ -47,6 +51,8 @@ export const FX_frame = defineImageEffectorFx({
|
||||||
},
|
},
|
||||||
main: ({ gl, u, params, textures }) => {
|
main: ({ gl, u, params, textures }) => {
|
||||||
const image = textures.image;
|
const image = textures.image;
|
||||||
|
if (image == null) return;
|
||||||
|
|
||||||
gl.activeTexture(gl.TEXTURE1);
|
gl.activeTexture(gl.TEXTURE1);
|
||||||
gl.bindTexture(gl.TEXTURE_2D, image.texture);
|
gl.bindTexture(gl.TEXTURE_2D, image.texture);
|
||||||
gl.uniform1i(u.image, 1);
|
gl.uniform1i(u.image, 1);
|
||||||
|
|
@ -56,11 +62,18 @@ export const FX_frame = defineImageEffectorFx({
|
||||||
gl.uniform1f(u.paddingLeft, params.paddingLeft);
|
gl.uniform1f(u.paddingLeft, params.paddingLeft);
|
||||||
gl.uniform1f(u.paddingRight, params.paddingRight);
|
gl.uniform1f(u.paddingRight, params.paddingRight);
|
||||||
|
|
||||||
const label = textures.label;
|
const topLabel = textures.topLabel;
|
||||||
if (label) {
|
if (topLabel) {
|
||||||
gl.activeTexture(gl.TEXTURE2);
|
gl.activeTexture(gl.TEXTURE2);
|
||||||
gl.bindTexture(gl.TEXTURE_2D, label.texture);
|
gl.bindTexture(gl.TEXTURE_2D, topLabel.texture);
|
||||||
gl.uniform1i(u.label, 2);
|
gl.uniform1i(u.topLabel, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bottomLabel = textures.bottomLabel;
|
||||||
|
if (bottomLabel) {
|
||||||
|
gl.activeTexture(gl.TEXTURE3);
|
||||||
|
gl.bindTexture(gl.TEXTURE_2D, bottomLabel.texture);
|
||||||
|
gl.uniform1i(u.bottomLabel, 3);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -11,20 +11,27 @@ import type { ImageEffectorFx, ImageEffectorLayer } from '@/utility/image-effect
|
||||||
import { ImageEffector } from '@/utility/image-effector/ImageEffector.js';
|
import { ImageEffector } from '@/utility/image-effector/ImageEffector.js';
|
||||||
import { ensureSignin } from '@/i.js';
|
import { ensureSignin } from '@/i.js';
|
||||||
|
|
||||||
|
const $i = ensureSignin();
|
||||||
|
|
||||||
const FXS = [
|
const FXS = [
|
||||||
FX_frame,
|
FX_frame,
|
||||||
] as const satisfies ImageEffectorFx<string, any>[];
|
] as const satisfies ImageEffectorFx<string, any>[];
|
||||||
|
|
||||||
// TODO: 上部にもラベルを配置できるようにする
|
// TODO: 上部にもラベルを配置できるようにする
|
||||||
|
|
||||||
export type ImageFrameParams = {
|
type LabelParams = {
|
||||||
borderThickness: number;
|
scale: number;
|
||||||
labelThickness: number;
|
padding: number;
|
||||||
labelScale: number;
|
textBig: string;
|
||||||
title: string;
|
textSmall: string;
|
||||||
text: string;
|
|
||||||
centered: boolean;
|
centered: boolean;
|
||||||
withQrCode: boolean;
|
withQrCode: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ImageFrameParams = {
|
||||||
|
borderThickness: number;
|
||||||
|
labelTop: LabelParams;
|
||||||
|
labelBottom: LabelParams;
|
||||||
bgColor: [r: number, g: number, b: number];
|
bgColor: [r: number, g: number, b: number];
|
||||||
fgColor: [r: number, g: number, b: number];
|
fgColor: [r: number, g: number, b: number];
|
||||||
borderRadius: number; // TODO
|
borderRadius: number; // TODO
|
||||||
|
|
@ -64,7 +71,7 @@ export class ImageFrameRenderer {
|
||||||
this.effector.registerTexture('image', this.image);
|
this.effector.registerTexture('image', this.image);
|
||||||
}
|
}
|
||||||
|
|
||||||
private interpolateText(text: string) {
|
private interpolateTemplateText(text: string) {
|
||||||
return text.replaceAll(/\{(\w+)\}/g, (_: string, key: string) => {
|
return text.replaceAll(/\{(\w+)\}/g, (_: string, key: string) => {
|
||||||
const meta_date = this.exif.DateTimeOriginal ? this.exif.DateTimeOriginal.description : '-';
|
const meta_date = this.exif.DateTimeOriginal ? this.exif.DateTimeOriginal.description : '-';
|
||||||
const date = meta_date.split(' ')[0].replaceAll(':', '/');
|
const date = meta_date.split(' ')[0].replaceAll(':', '/');
|
||||||
|
|
@ -92,33 +99,11 @@ export class ImageFrameRenderer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateAndRender(params: ImageFrameParams): Promise<void> {
|
private async renderLabel(renderWidth: number, renderHeight: number, paddingLeft: number, paddingRight: number, imageAreaH: number, params: LabelParams) {
|
||||||
let imageAreaW = this.image.width;
|
const scaleBase = imageAreaH * params.scale;
|
||||||
let imageAreaH = this.image.height;
|
|
||||||
|
|
||||||
if (this.renderAsPreview) {
|
|
||||||
const MAX_W = 1000;
|
|
||||||
const MAX_H = 1000;
|
|
||||||
|
|
||||||
if (imageAreaW > MAX_W || imageAreaH > MAX_H) {
|
|
||||||
const scale = Math.min(MAX_W / imageAreaW, MAX_H / imageAreaH);
|
|
||||||
imageAreaW = Math.floor(imageAreaW * scale);
|
|
||||||
imageAreaH = Math.floor(imageAreaH * scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const paddingTop = Math.floor(imageAreaH * params.borderThickness);
|
|
||||||
const paddingLeft = Math.floor(imageAreaH * params.borderThickness);
|
|
||||||
const paddingRight = Math.floor(imageAreaH * params.borderThickness);
|
|
||||||
const paddingBottom = Math.floor(imageAreaH * params.labelThickness);
|
|
||||||
const renderWidth = imageAreaW + paddingLeft + paddingRight;
|
|
||||||
const renderHeight = imageAreaH + paddingTop + paddingBottom;
|
|
||||||
|
|
||||||
const aspectRatio = renderWidth / renderHeight;
|
|
||||||
const labelCanvasCtx = window.document.createElement('canvas').getContext('2d')!;
|
const labelCanvasCtx = window.document.createElement('canvas').getContext('2d')!;
|
||||||
labelCanvasCtx.canvas.width = renderWidth;
|
labelCanvasCtx.canvas.width = renderWidth;
|
||||||
labelCanvasCtx.canvas.height = paddingBottom;
|
labelCanvasCtx.canvas.height = renderHeight;
|
||||||
const scaleBase = imageAreaH * params.labelScale;
|
|
||||||
const fontSize = scaleBase / 30;
|
const fontSize = scaleBase / 30;
|
||||||
const textsMarginLeft = Math.max(fontSize * 2, paddingLeft);
|
const textsMarginLeft = Math.max(fontSize * 2, paddingLeft);
|
||||||
const textsMarginRight = textsMarginLeft;
|
const textsMarginRight = textsMarginLeft;
|
||||||
|
|
@ -133,30 +118,28 @@ export class ImageFrameRenderer {
|
||||||
labelCanvasCtx.font = `bold ${fontSize}px sans-serif`;
|
labelCanvasCtx.font = `bold ${fontSize}px sans-serif`;
|
||||||
labelCanvasCtx.textBaseline = 'middle';
|
labelCanvasCtx.textBaseline = 'middle';
|
||||||
|
|
||||||
const titleY = params.text === '' ? (labelCanvasCtx.canvas.height / 2) : (labelCanvasCtx.canvas.height / 2) - (fontSize * 0.9);
|
const titleY = params.textSmall === '' ? (labelCanvasCtx.canvas.height / 2) : (labelCanvasCtx.canvas.height / 2) - (fontSize * 0.9);
|
||||||
if (params.centered) {
|
if (params.centered) {
|
||||||
labelCanvasCtx.textAlign = 'center';
|
labelCanvasCtx.textAlign = 'center';
|
||||||
labelCanvasCtx.fillText(this.interpolateText(params.title), labelCanvasCtx.canvas.width / 2, titleY, labelCanvasCtx.canvas.width - textsMarginLeft - textsMarginRight);
|
labelCanvasCtx.fillText(this.interpolateTemplateText(params.textBig), labelCanvasCtx.canvas.width / 2, titleY, labelCanvasCtx.canvas.width - textsMarginLeft - textsMarginRight);
|
||||||
} else {
|
} else {
|
||||||
labelCanvasCtx.textAlign = 'left';
|
labelCanvasCtx.textAlign = 'left';
|
||||||
labelCanvasCtx.fillText(this.interpolateText(params.title), textsMarginLeft, titleY, labelCanvasCtx.canvas.width - textsMarginLeft - (withQrCode ? (qrSize + qrMarginRight + (fontSize * 1)) : textsMarginRight));
|
labelCanvasCtx.fillText(this.interpolateTemplateText(params.textBig), textsMarginLeft, titleY, labelCanvasCtx.canvas.width - textsMarginLeft - (withQrCode ? (qrSize + qrMarginRight + (fontSize * 1)) : textsMarginRight));
|
||||||
}
|
}
|
||||||
|
|
||||||
labelCanvasCtx.fillStyle = '#00000088';
|
labelCanvasCtx.fillStyle = '#00000088';
|
||||||
labelCanvasCtx.font = `${fontSize * 0.85}px sans-serif`;
|
labelCanvasCtx.font = `${fontSize * 0.85}px sans-serif`;
|
||||||
labelCanvasCtx.textBaseline = 'middle';
|
labelCanvasCtx.textBaseline = 'middle';
|
||||||
|
|
||||||
const textY = params.title === '' ? (labelCanvasCtx.canvas.height / 2) : (labelCanvasCtx.canvas.height / 2) + (fontSize * 0.9);
|
const textY = params.textBig === '' ? (labelCanvasCtx.canvas.height / 2) : (labelCanvasCtx.canvas.height / 2) + (fontSize * 0.9);
|
||||||
if (params.centered) {
|
if (params.centered) {
|
||||||
labelCanvasCtx.textAlign = 'center';
|
labelCanvasCtx.textAlign = 'center';
|
||||||
labelCanvasCtx.fillText(this.interpolateText(params.text), labelCanvasCtx.canvas.width / 2, textY, labelCanvasCtx.canvas.width - textsMarginLeft - textsMarginRight);
|
labelCanvasCtx.fillText(this.interpolateTemplateText(params.textSmall), labelCanvasCtx.canvas.width / 2, textY, labelCanvasCtx.canvas.width - textsMarginLeft - textsMarginRight);
|
||||||
} else {
|
} else {
|
||||||
labelCanvasCtx.textAlign = 'left';
|
labelCanvasCtx.textAlign = 'left';
|
||||||
labelCanvasCtx.fillText(this.interpolateText(params.text), textsMarginLeft, textY, labelCanvasCtx.canvas.width - textsMarginLeft - (withQrCode ? (qrSize + qrMarginRight + (fontSize * 1)) : textsMarginRight));
|
labelCanvasCtx.fillText(this.interpolateTemplateText(params.textSmall), textsMarginLeft, textY, labelCanvasCtx.canvas.width - textsMarginLeft - (withQrCode ? (qrSize + qrMarginRight + (fontSize * 1)) : textsMarginRight));
|
||||||
}
|
}
|
||||||
|
|
||||||
const $i = ensureSignin();
|
|
||||||
|
|
||||||
if (withQrCode) {
|
if (withQrCode) {
|
||||||
try {
|
try {
|
||||||
const qrCodeInstance = new QRCodeStyling({
|
const qrCodeInstance = new QRCodeStyling({
|
||||||
|
|
@ -207,9 +190,38 @@ export class ImageFrameRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = labelCanvasCtx.getImageData(0, 0, labelCanvasCtx.canvas.width, labelCanvasCtx.canvas.height);
|
return labelCanvasCtx;
|
||||||
|
}
|
||||||
|
|
||||||
await this.effector.registerTexture('label', data);
|
public async updateAndRender(params: ImageFrameParams): Promise<void> {
|
||||||
|
let imageAreaW = this.image.width;
|
||||||
|
let imageAreaH = this.image.height;
|
||||||
|
|
||||||
|
if (this.renderAsPreview) {
|
||||||
|
const MAX_W = 1000;
|
||||||
|
const MAX_H = 1000;
|
||||||
|
|
||||||
|
if (imageAreaW > MAX_W || imageAreaH > MAX_H) {
|
||||||
|
const scale = Math.min(MAX_W / imageAreaW, MAX_H / imageAreaH);
|
||||||
|
imageAreaW = Math.floor(imageAreaW * scale);
|
||||||
|
imageAreaH = Math.floor(imageAreaH * scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const paddingLeft = Math.floor(imageAreaH * params.borderThickness);
|
||||||
|
const paddingRight = Math.floor(imageAreaH * params.borderThickness);
|
||||||
|
const paddingTop = Math.floor(imageAreaH * params.labelTop.padding);
|
||||||
|
const paddingBottom = Math.floor(imageAreaH * params.labelBottom.padding);
|
||||||
|
const renderWidth = imageAreaW + paddingLeft + paddingRight;
|
||||||
|
const renderHeight = imageAreaH + paddingTop + paddingBottom;
|
||||||
|
|
||||||
|
const topLabelCanvasCtx = await this.renderLabel(renderWidth, paddingBottom, paddingLeft, paddingRight, imageAreaH, params.labelTop);
|
||||||
|
const topLabelImage = topLabelCanvasCtx.getImageData(0, 0, topLabelCanvasCtx.canvas.width, topLabelCanvasCtx.canvas.height);
|
||||||
|
this.effector.registerTexture('topLabel', topLabelImage);
|
||||||
|
|
||||||
|
const bottomLabelCanvasCtx = await this.renderLabel(renderWidth, paddingBottom, paddingLeft, paddingRight, imageAreaH, params.labelBottom);
|
||||||
|
const bottomLabelImage = bottomLabelCanvasCtx.getImageData(0, 0, bottomLabelCanvasCtx.canvas.width, bottomLabelCanvasCtx.canvas.height);
|
||||||
|
this.effector.registerTexture('bottomLabel', bottomLabelImage);
|
||||||
|
|
||||||
this.effector.changeResolution(renderWidth, renderHeight);
|
this.effector.changeResolution(renderWidth, renderHeight);
|
||||||
|
|
||||||
|
|
@ -218,7 +230,8 @@ export class ImageFrameRenderer {
|
||||||
id: 'a',
|
id: 'a',
|
||||||
params: {
|
params: {
|
||||||
image: 'image',
|
image: 'image',
|
||||||
label: 'label',
|
topLabel: 'topLabel',
|
||||||
|
bottomLabel: 'bottomLabel',
|
||||||
paddingLeft: paddingLeft / renderWidth,
|
paddingLeft: paddingLeft / renderWidth,
|
||||||
paddingRight: paddingRight / renderWidth,
|
paddingRight: paddingRight / renderWidth,
|
||||||
paddingTop: paddingTop / renderHeight,
|
paddingTop: paddingTop / renderHeight,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue