mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
feat: masks, properties refactor, shaders, storage migrations, and more
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import type { EditorCore } from "@/core";
|
||||
import type { RootNode } from "@/services/renderer/nodes/root-node";
|
||||
import type { ExportOptions, ExportResult } from "@/types/export";
|
||||
import type { ExportOptions, ExportResult } from "@/lib/export";
|
||||
import { CanvasRenderer } from "@/services/renderer/canvas-renderer";
|
||||
import { SceneExporter } from "@/services/renderer/scene-exporter";
|
||||
import { buildScene } from "@/services/renderer/scene-builder";
|
||||
@@ -8,6 +8,10 @@ import { createTimelineAudioBuffer } from "@/lib/media/audio";
|
||||
import { formatTimeCode, getLastFrameTime } from "@/lib/time";
|
||||
import { downloadBlob } from "@/utils/browser";
|
||||
|
||||
type SnapshotResult =
|
||||
| { success: true; blob: Blob; filename: string }
|
||||
| { success: false; error: string };
|
||||
|
||||
export class RendererManager {
|
||||
private renderTree: RootNode | null = null;
|
||||
private listeners = new Set<() => void>();
|
||||
@@ -24,6 +28,45 @@ export class RendererManager {
|
||||
}
|
||||
|
||||
async saveSnapshot(): Promise<{ success: boolean; error?: string }> {
|
||||
const snapshot = await this.createSnapshot();
|
||||
if (!snapshot.success) {
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
downloadBlob({ blob: snapshot.blob, filename: snapshot.filename });
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
async copySnapshot(): Promise<{ success: boolean; error?: string }> {
|
||||
if (typeof ClipboardItem === "undefined" || !navigator.clipboard?.write) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Clipboard image copy is not supported in this browser",
|
||||
};
|
||||
}
|
||||
|
||||
const snapshot = await this.createSnapshot();
|
||||
if (!snapshot.success) {
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
try {
|
||||
await navigator.clipboard.write([
|
||||
new ClipboardItem({
|
||||
[snapshot.blob.type || "image/png"]: snapshot.blob,
|
||||
}),
|
||||
]);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error("Copy snapshot failed:", error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private async createSnapshot(): Promise<SnapshotResult> {
|
||||
try {
|
||||
const renderTree = this.getRenderTree();
|
||||
const activeProject = this.editor.project.getActive();
|
||||
@@ -70,15 +113,14 @@ export class RendererManager {
|
||||
timeInSeconds: renderTime,
|
||||
fps,
|
||||
}).replace(/:/g, "-");
|
||||
const safeName = activeProject.metadata.name
|
||||
.replace(/[<>:"/\\|?*]/g, "-")
|
||||
.trim() || "snapshot";
|
||||
const safeName =
|
||||
activeProject.metadata.name.replace(/[<>:"/\\|?*]/g, "-").trim() ||
|
||||
"snapshot";
|
||||
const filename = `${safeName}-${timecode}.png`;
|
||||
|
||||
downloadBlob({ blob, filename });
|
||||
return { success: true };
|
||||
return { success: true, blob, filename };
|
||||
} catch (error) {
|
||||
console.error("Save snapshot failed:", error);
|
||||
console.error("Snapshot capture failed:", error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
@@ -193,6 +235,8 @@ export class RendererManager {
|
||||
}
|
||||
|
||||
private notify(): void {
|
||||
this.listeners.forEach((fn) => fn());
|
||||
this.listeners.forEach((fn) => {
|
||||
fn();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user