add tono watermark

This commit is contained in:
2026-03-30 21:54:35 -07:00
parent 8a70b0af05
commit c6b3be51c3
2 changed files with 26 additions and 2 deletions

View File

@@ -10,7 +10,6 @@ from backend.node_registry import register_node
from backend.execution_context import emit_warning
from backend.data_types import DataField, LineData, MeshModel, datafield_to_uint8, image_to_uint8
@register_node(display_name="Save")
class Save:
@classmethod

View File

@@ -14,6 +14,7 @@ import { pickNativeDirectorySelection, pickNativeFileSelection } from './nativeP
import { toBlob } from 'html-to-image';
import { embedWorkflow, extractWorkflow } from './pngMetadata';
import { captureViewportBlob as captureWorkflowViewportBlob } from './workflowCapture';
import tonoIconUrl from '../../resources/icon_1024.png';
import { hydrateWorkflowState } from './workflowHydration';
import { serializeWorkflowState } from './workflowSerialization';
import { sortNodesForParentOrder } from './nodeHierarchy.js';
@@ -1985,6 +1986,29 @@ function Flow() {
});
}, [loadDefaultWorkflow]);
const stampLogoOnBlob = useCallback(async (blob) => {
const [img, logo] = await Promise.all([blob, tonoIconUrl].map((src) => new Promise((resolve, reject) => {
const el = new Image();
el.onload = () => resolve(el);
el.onerror = reject;
el.src = typeof src === 'string' ? src : URL.createObjectURL(src);
})));
const canvas = document.createElement('canvas');
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
const margin = 16;
const size = Math.min(128, Math.floor(img.naturalWidth / 6), Math.floor(img.naturalHeight / 6));
if (size >= 16) {
ctx.drawImage(logo, img.naturalWidth - size - margin, img.naturalHeight - size - margin, size, size);
}
return new Promise((resolve) => canvas.toBlob(resolve, 'image/png'));
}, []);
const getWorkflowBlob = useCallback(async () => {
const viewportEl = document.querySelector('.react-flow__viewport');
if (!viewportEl) throw new Error('Flow element not found');
@@ -2013,8 +2037,9 @@ function Flow() {
});
if (!blob) throw new Error('Capture returned empty');
const stampedBlob = await stampLogoOnBlob(blob);
const workflow = serializeWorkflowState(allNodes, reactFlow.getEdges());
return embedWorkflow(blob, workflow);
return embedWorkflow(stampedBlob, workflow);
}, [reactFlow]);
const saveWorkflow = useCallback(async () => {