refboard: add native image copy and export renderer
This commit is contained in:
@@ -9,8 +9,12 @@
|
||||
import type { Viewport } from 'pixi-viewport';
|
||||
import type { Application } from 'pixi.js';
|
||||
import type { SceneManager, SceneItem } from './SceneManager';
|
||||
import { getItemWorldBounds } from './SceneManager';
|
||||
import { uploadImage } from '../api';
|
||||
import {
|
||||
renderCanvasSnapshot,
|
||||
renderNativeImageSelection,
|
||||
supportsNativeImageExport,
|
||||
} from './snapshotRenderer';
|
||||
|
||||
/**
|
||||
* Write selected items (or full viewport) to system clipboard as PNG.
|
||||
@@ -24,53 +28,16 @@ export async function writeCanvasToClipboard(
|
||||
if (!viewport) throw new Error('Viewport not available');
|
||||
if (!app) throw new Error('Renderer not available');
|
||||
|
||||
const directCanvas = app.canvas as unknown as HTMLCanvasElement | undefined;
|
||||
const sourceCanvas = directCanvas
|
||||
?? (app.renderer?.extract
|
||||
? (app.renderer.extract.canvas(viewport) as HTMLCanvasElement)
|
||||
: undefined);
|
||||
if (!sourceCanvas || sourceCanvas.width <= 0 || sourceCanvas.height <= 0) {
|
||||
throw new Error('Rendered canvas unavailable');
|
||||
}
|
||||
|
||||
let outputCanvas: HTMLCanvasElement;
|
||||
|
||||
if (items && items.length > 0) {
|
||||
// Compute world-space bounding box, then convert to visible screen-space crop.
|
||||
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
||||
for (const item of items) {
|
||||
const { x, y, w, h } = getItemWorldBounds(item);
|
||||
minX = Math.min(minX, x);
|
||||
minY = Math.min(minY, y);
|
||||
maxX = Math.max(maxX, x + w);
|
||||
maxY = Math.max(maxY, y + h);
|
||||
if (supportsNativeImageExport(items)) {
|
||||
outputCanvas = await renderNativeImageSelection(items, { background: null, paddingPx: 10 });
|
||||
} else {
|
||||
outputCanvas = renderCanvasSnapshot(app, viewport, items, { background: null, paddingPx: 12 });
|
||||
}
|
||||
|
||||
const screenTL = viewport.toScreen(minX, minY);
|
||||
const screenBR = viewport.toScreen(maxX, maxY);
|
||||
const rect = sourceCanvas.getBoundingClientRect();
|
||||
const scaleX = rect.width > 0 ? sourceCanvas.width / rect.width : 1;
|
||||
const scaleY = rect.height > 0 ? sourceCanvas.height / rect.height : 1;
|
||||
const pad = 12;
|
||||
const sx = Math.max(0, Math.floor(Math.min(screenTL.x, screenBR.x) * scaleX) - pad);
|
||||
const sy = Math.max(0, Math.floor(Math.min(screenTL.y, screenBR.y) * scaleY) - pad);
|
||||
const sw = Math.max(1, Math.min(sourceCanvas.width - sx, Math.ceil(Math.abs(screenBR.x - screenTL.x) * scaleX) + pad * 2));
|
||||
const sh = Math.max(1, Math.min(sourceCanvas.height - sy, Math.ceil(Math.abs(screenBR.y - screenTL.y) * scaleY) + pad * 2));
|
||||
|
||||
outputCanvas = document.createElement('canvas');
|
||||
outputCanvas.width = sw;
|
||||
outputCanvas.height = sh;
|
||||
const ctx2d = outputCanvas.getContext('2d')!;
|
||||
ctx2d.clearRect(0, 0, outputCanvas.width, outputCanvas.height);
|
||||
ctx2d.drawImage(sourceCanvas, sx, sy, sw, sh, 0, 0, sw, sh);
|
||||
} else {
|
||||
// Full current view copy.
|
||||
outputCanvas = document.createElement('canvas');
|
||||
outputCanvas.width = sourceCanvas.width;
|
||||
outputCanvas.height = sourceCanvas.height;
|
||||
const ctx2d = outputCanvas.getContext('2d')!;
|
||||
ctx2d.clearRect(0, 0, outputCanvas.width, outputCanvas.height);
|
||||
ctx2d.drawImage(sourceCanvas, 0, 0);
|
||||
outputCanvas = renderCanvasSnapshot(app, viewport, undefined, { background: null });
|
||||
}
|
||||
|
||||
const blob = await new Promise<Blob>((resolve, reject) => {
|
||||
|
||||
Reference in New Issue
Block a user