1+ import { app } from "../../scripts/app.js" ;
2+
3+
4+ function inspectNode ( node ) {
5+ console . log ( '节点信息:' , {
6+ id : node . id ,
7+ type : node . type ,
8+ title : node . title ,
9+ size : node . size
10+ } ) ;
11+ }
12+
13+ // 节点类型与图片类型的映射
14+ const NODE_TYPE_MAPPING = {
15+ 'PreviewImage' : { type : 'temp' , path : 'temp' } ,
16+ 'SaveImage' : { type : 'output' , path : 'output' } ,
17+ 'LoadImage' : { type : 'input' , path : 'input' }
18+ } ;
19+
20+ // 监听来自iframe的消息
21+ window . addEventListener ( 'message' , async function ( event ) {
22+
23+ if ( event . data && event . data . type === 'APPLY_IMAGE_TO_NODE' ) {
24+ const { nodeId, base64Data } = event . data . data ;
25+
26+ console . log ( '收到应用图片到节点请求:' , nodeId ) ;
27+
28+ if ( ! nodeId || ! base64Data ) {
29+ console . error ( '应用图片到节点失败: 缺少必要的参数' ) ;
30+ return ;
31+ }
32+
33+ try {
34+ // 找到目标节点
35+ const targetNode = app . graph . getNodeById ( parseInt ( nodeId ) ) ;
36+ if ( ! targetNode ) {
37+ console . error ( '应用图片到节点失败: 找不到指定ID的节点' , nodeId ) ;
38+ return ;
39+ }
40+
41+ // 保存原始节点大小
42+ const originalSize = targetNode . size ? [ ...targetNode . size ] : null ;
43+
44+ // 记录节点基本信息
45+ inspectNode ( targetNode ) ;
46+
47+ // 确定节点类型和对应的图片类型
48+ const nodeType = targetNode . type || targetNode . comfyClass ;
49+ const mapping = NODE_TYPE_MAPPING [ nodeType ] || { type : 'temp' , path : 'temp' } ;
50+ const imageType = mapping . type ;
51+
52+ console . log ( `节点类型: ${ nodeType } , 使用图片类型: ${ imageType } ` ) ;
53+
54+ // 提取base64
55+ const cleanBase64Data = base64Data . includes ( 'base64,' )
56+ ? base64Data . split ( 'base64,' ) [ 1 ]
57+ : base64Data ;
58+
59+ // 创建一个临时图片文件名
60+ const timestamp = new Date ( ) . getTime ( ) ;
61+ const randomStr = Math . random ( ) . toString ( 36 ) . substring ( 2 , 10 ) ;
62+ const filename = `bizyair_${ imageType } _${ timestamp } _${ randomStr } .png` ;
63+
64+ // 从base64创建Blob对象
65+ const byteCharacters = atob ( cleanBase64Data ) ;
66+ const byteArrays = [ ] ;
67+
68+ for ( let offset = 0 ; offset < byteCharacters . length ; offset += 512 ) {
69+ const slice = byteCharacters . slice ( offset , offset + 512 ) ;
70+
71+ const byteNumbers = new Array ( slice . length ) ;
72+ for ( let i = 0 ; i < slice . length ; i ++ ) {
73+ byteNumbers [ i ] = slice . charCodeAt ( i ) ;
74+ }
75+
76+ const byteArray = new Uint8Array ( byteNumbers ) ;
77+ byteArrays . push ( byteArray ) ;
78+ }
79+
80+ const blob = new Blob ( byteArrays , { type : 'image/png' } ) ;
81+
82+ // 创建FormData对象
83+ const formData = new FormData ( ) ;
84+ formData . append ( 'image' , blob , filename ) ;
85+ formData . append ( 'type' , imageType ) ;
86+ formData . append ( 'filename' , filename ) ;
87+
88+ // 发送请求
89+ const response = await fetch ( '/upload/image' , {
90+ method : 'POST' ,
91+ body : formData
92+ } ) ;
93+
94+ if ( ! response . ok ) {
95+ throw new Error ( `保存图片失败: ${ response . status } ${ response . statusText } ` ) ;
96+ }
97+
98+ const data = await response . json ( ) ;
99+ console . log ( '保存图片成功:' , data ) ;
100+
101+ // 使用服务器返回的文件名
102+ const serverFilename = data . name || filename ;
103+ const serverType = data . type || imageType ;
104+
105+ // 创建图片对象
106+ const imageObj = {
107+ filename : serverFilename ,
108+ type : serverType ,
109+ subfolder : data . subfolder || ''
110+ } ;
111+
112+ // 只有LoadImage类型的节点需要更新节点内容
113+ if ( nodeType === 'LoadImage' ) {
114+ console . log ( '处理LoadImage节点,将更新节点内容...' ) ;
115+ // 更新节点的图片数据
116+ if ( ! targetNode . images ) {
117+ targetNode . images = [ ] ;
118+ }
119+ targetNode . images [ 0 ] = imageObj ;
120+
121+ if ( targetNode . widgets ) {
122+ // 更新filename widget
123+ const imageWidget = targetNode . widgets . find ( w =>
124+ w . name === 'image' || w . name === 'filename' ) ;
125+ if ( imageWidget ) {
126+ imageWidget . value = serverFilename ;
127+ if ( typeof imageWidget . callback === "function" ) {
128+ imageWidget . callback ( serverFilename ) ;
129+ }
130+ }
131+
132+ // 确保type widget设置为input
133+ const typeWidget = targetNode . widgets . find ( w => w . name === 'type' ) ;
134+ if ( typeWidget ) {
135+ typeWidget . value = 'input' ;
136+ if ( typeof typeWidget . callback === "function" ) {
137+ typeWidget . callback ( 'input' ) ;
138+ }
139+ }
140+ }
141+
142+ // 标记重绘但不改变大小
143+ targetNode . setDirtyCanvas ( true , true ) ;
144+
145+ // 恢复原始大小
146+ if ( originalSize ) {
147+ targetNode . size = originalSize ;
148+ }
149+
150+ // 通知重绘
151+ app . canvas && app . canvas . draw ( true , true ) ;
152+
153+ console . log ( `图片已成功应用到LoadImage节点 ${ targetNode . title } (ID: ${ targetNode . id } )` ) ;
154+ } else {
155+ // 对于其他类型节点,保存图片
156+ if ( nodeType === 'SaveImage' ) {
157+ console . log ( `图片已成功保存到output目录: ${ serverFilename } ` ) ;
158+ alert ( `图片已保存到output目录: ${ serverFilename } ` ) ;
159+ } else if ( nodeType === 'PreviewImage' ) {
160+ console . log ( `图片已成功保存到temp目录: ${ serverFilename } ` ) ;
161+ alert ( `图片已保存到temp目录: ${ serverFilename } ` ) ;
162+ } else {
163+ console . log ( `图片已成功保存到${ imageType } 目录: ${ serverFilename } ` ) ;
164+ alert ( `图片已保存到${ imageType } 目录: ${ serverFilename } ` ) ;
165+ }
166+ }
167+ } catch ( error ) {
168+ console . error ( '应用图片到节点时发生异常:' , error ) ;
169+ alert ( '处理图片请求失败: ' + error . message ) ;
170+ }
171+ }
172+ } ) ;
173+
174+ console . log ( '已设置消息监听器,可接收iframe发送的图片更新请求' ) ;
175+
176+ export { app } ;
0 commit comments