@@ -4,69 +4,48 @@ import { PathString } from "@/utils/pathString";
44import { RecentFileManager } from "../dataFileService/RecentFileManager" ;
55import { Section } from "@/core/stage/stageObject/entity/Section" ;
66import { sleep } from "@/utils/sleep" ;
7+ import { Rectangle } from "@graphif/shapes" ;
78
89/**
910 * 从一个文件中生成截图
1011 */
1112export namespace GenerateScreenshot {
1213 /**
13- * 根据文件名和Section框名生成截图
14- * @param fileName 文件名
15- * @param sectionName Section框名
14+ * 创建临时Canvas并渲染Project
15+ * @param project 项目实例
16+ * @param targetRect 目标矩形区域
1617 * @returns 截图的Blob对象
1718 */
18- export async function generateSection ( fileName : string , sectionName : string ) : Promise < Blob | undefined > {
19- try {
20- // 1. 根据文件名查找并加载prg文件
21- const recentFiles = await RecentFileManager . getRecentFiles ( ) ;
22- const file = recentFiles . find ( ( file ) => PathString . getFileNameFromPath ( file . uri . fsPath ) === fileName ) ;
23- if ( ! file ) {
24- return undefined ;
25- }
26- const fileUri = file . uri ;
27- const project = new Project ( fileUri ) ;
28- loadAllServicesBeforeInit ( project ) ;
29- await project . init ( ) ;
30- // 5. 查找指定名称的Section
31- const targetSection = project . stage . find ( ( obj ) => obj instanceof Section && obj . text === sectionName ) ;
19+ async function renderProjectToBlob ( project : Project , targetRect : Rectangle ) : Promise < Blob > {
20+ // 计算缩放比例,确保最终截图宽高不超过1920
21+ const maxDimension = 1920 ;
22+ let scaleFactor = 1 ;
23+ if ( targetRect . width > maxDimension || targetRect . height > maxDimension ) {
24+ const widthRatio = maxDimension / targetRect . width ;
25+ const heightRatio = maxDimension / targetRect . height ;
26+ scaleFactor = Math . min ( widthRatio , heightRatio ) ;
27+ }
28+ project . camera . currentScale = scaleFactor ;
29+ project . camera . targetScale = scaleFactor ;
3230
33- if ( ! targetSection ) {
34- console . error ( `Section框 【${ sectionName } 】 没有发现 in file ${ fileName } ` ) ;
35- return undefined ;
36- }
31+ // 创建临时Canvas
32+ const tempCanvas = document . createElement ( "canvas" ) ;
33+ const deviceScale = window . devicePixelRatio ;
34+ const canvasWidth = Math . min ( targetRect . width * scaleFactor + 2 , maxDimension + 2 ) ;
35+ const canvasHeight = Math . min ( targetRect . height * scaleFactor + 2 , maxDimension + 2 ) ;
36+ tempCanvas . width = canvasWidth * deviceScale ;
37+ tempCanvas . height = canvasHeight * deviceScale ;
38+ tempCanvas . style . width = `${ canvasWidth } px` ;
39+ tempCanvas . style . height = `${ canvasHeight } px` ;
40+ const tempCtx = tempCanvas . getContext ( "2d" ) ! ;
41+ tempCtx . scale ( deviceScale , deviceScale ) ;
3742
38- // 6. 调整相机位置到Section
39- const sectionRect = targetSection . collisionBox . getRectangle ( ) ;
40- project . camera . location = sectionRect . center ;
43+ // 保存原Canvas和渲染器尺寸
44+ const originalCanvas = project . canvas . element ;
45+ const originalRendererWidth = project . renderer . w ;
46+ const originalRendererHeight = project . renderer . h ;
4147
42- // 7. 计算缩放比例,确保最终截图宽高不超过1920
43- const maxDimension = 1920 ;
44- let scaleFactor = 1 ;
45- if ( sectionRect . width > maxDimension || sectionRect . height > maxDimension ) {
46- const widthRatio = maxDimension / sectionRect . width ;
47- const heightRatio = maxDimension / sectionRect . height ;
48- scaleFactor = Math . min ( widthRatio , heightRatio ) ;
49- }
50- project . camera . currentScale = scaleFactor ;
51- project . camera . targetScale = scaleFactor ;
52-
53- // 8. 创建临时Canvas
54- const tempCanvas = document . createElement ( "canvas" ) ;
55- const deviceScale = window . devicePixelRatio ;
56- const canvasWidth = Math . min ( sectionRect . width * scaleFactor + 2 , maxDimension + 2 ) ;
57- const canvasHeight = Math . min ( sectionRect . height * scaleFactor + 2 , maxDimension + 2 ) ;
58- tempCanvas . width = canvasWidth * deviceScale ;
59- tempCanvas . height = canvasHeight * deviceScale ;
60- tempCanvas . style . width = `${ canvasWidth } px` ;
61- tempCanvas . style . height = `${ canvasHeight } px` ;
62- const tempCtx = tempCanvas . getContext ( "2d" ) ! ;
63- tempCtx . scale ( deviceScale , deviceScale ) ;
64-
65- // 8. 渲染Project到临时Canvas
66- // 保存原Canvas和渲染器尺寸
67- const originalCanvas = project . canvas . element ;
68- const originalRendererWidth = project . renderer . w ;
69- const originalRendererHeight = project . renderer . h ;
48+ try {
7049 // 设置临时Canvas
7150 project . canvas . element = tempCanvas ;
7251 project . canvas . ctx = tempCtx ;
@@ -79,7 +58,7 @@ export namespace GenerateScreenshot {
7958 await sleep ( 1000 ) ; // 1s
8059 project . pause ( ) ;
8160
82- // 9. 将Canvas内容转换为Blob
61+ // 将Canvas内容转换为Blob
8362 const blob = await new Promise < Blob > ( ( resolve ) => {
8463 tempCanvas . toBlob ( ( blob ) => {
8564 if ( blob ) {
@@ -90,22 +69,95 @@ export namespace GenerateScreenshot {
9069 } , "image/png" ) ;
9170 } ) ;
9271
72+ return blob ;
73+ } finally {
9374 // 恢复原Canvas
9475 project . canvas . element = originalCanvas ;
9576 project . canvas . ctx = originalCanvas . getContext ( "2d" ) ! ;
9677 // 恢复渲染器尺寸
9778 project . renderer . w = originalRendererWidth ;
9879 project . renderer . h = originalRendererHeight ;
9980
100- // 10. 清理临时资源
81+ // 清理临时资源
10182 tempCanvas . remove ( ) ;
83+ }
84+ }
10285
103- project . dispose ( ) ;
86+ /**
87+ * 根据文件名和Section框名生成截图
88+ * @param fileName 文件名
89+ * @param sectionName Section框名
90+ * @returns 截图的Blob对象
91+ */
92+ export async function generateSection ( fileName : string , sectionName : string ) : Promise < Blob | undefined > {
93+ try {
94+ // 加载项目
95+ const recentFiles = await RecentFileManager . getRecentFiles ( ) ;
96+ const file = recentFiles . find ( ( file ) => PathString . getFileNameFromPath ( file . uri . fsPath ) === fileName ) ;
97+ if ( ! file ) {
98+ return undefined ;
99+ }
104100
101+ const project = new Project ( file . uri ) ;
102+ loadAllServicesBeforeInit ( project ) ;
103+ await project . init ( ) ;
104+
105+ // 查找指定名称的Section
106+ const targetSection = project . stage . find ( ( obj ) => obj instanceof Section && obj . text === sectionName ) ;
107+ if ( ! targetSection ) {
108+ console . error ( `Section框 【${ sectionName } 】 没有发现 in file ${ fileName } ` ) ;
109+ return undefined ;
110+ }
111+
112+ // 调整相机位置到Section
113+ const sectionRect = targetSection . collisionBox . getRectangle ( ) ;
114+ project . camera . location = sectionRect . center ;
115+
116+ // 渲染并获取截图
117+ const blob = await renderProjectToBlob ( project , sectionRect ) ;
118+
119+ project . dispose ( ) ;
105120 return blob ;
106121 } catch ( error ) {
107122 console . error ( "根据Section生成截图失败" , error ) ;
108123 return undefined ;
109124 }
110125 }
126+
127+ /**
128+ * 生成整个文件内容的广视野截图
129+ * @param fileName 文件名
130+ * @returns 截图的Blob对象
131+ */
132+ export async function generateFullView ( fileName : string ) : Promise < Blob | undefined > {
133+ try {
134+ // 加载项目
135+ const recentFiles = await RecentFileManager . getRecentFiles ( ) ;
136+ const file = recentFiles . find ( ( file ) => PathString . getFileNameFromPath ( file . uri . fsPath ) === fileName ) ;
137+ if ( ! file ) {
138+ return undefined ;
139+ }
140+
141+ const project = new Project ( file . uri ) ;
142+ loadAllServicesBeforeInit ( project ) ;
143+ await project . init ( ) ;
144+
145+ // 使用相机的reset方法重置视野,以适应所有内容
146+ project . camera . reset ( ) ;
147+
148+ // 获取整个舞台的边界矩形
149+ const stageSize = project . stageManager . getSize ( ) ;
150+ const stageCenter = project . stageManager . getCenter ( ) ;
151+ const fullRect = new Rectangle ( stageCenter . subtract ( stageSize . divide ( 2 ) ) , stageSize ) ;
152+
153+ // 渲染并获取截图
154+ const blob = await renderProjectToBlob ( project , fullRect ) ;
155+
156+ project . dispose ( ) ;
157+ return blob ;
158+ } catch ( error ) {
159+ console . error ( "生成广视野截图失败" , error ) ;
160+ return undefined ;
161+ }
162+ }
111163}
0 commit comments