@@ -19,8 +19,10 @@ const mockData = {
1919 } ,
2020 {
2121 groupOpenID : '' ,
22- type : 'text/message' ,
23- content : '阿尔山的秋天很美' ,
22+ type : 'image/png' ,
23+ name : '图片名称' ,
24+ path : 'https://gips2.baidu.com/it/u=1651586290,17201034&fm=3028&app=3028&f=JPEG&fmt=auto&q=100&size=f600_800' ,
25+ size : '图片大小'
2426 } ,
2527 {
2628 groupOpenID : '' ,
@@ -44,20 +46,6 @@ const mockData = {
4446 path : 'https://res.wx.qq.com/wxdoc/dist/assets/img/demo.ef5c5bef.jpg' ,
4547 size : '图片大小'
4648 } ,
47- {
48- groupOpenID : '' ,
49- type : 'image/png' ,
50- name : '图片名称' ,
51- path : '图片路径' ,
52- size : '图片大小'
53- } ,
54- {
55- groupOpenID : '' ,
56- type : 'image/png' ,
57- name : '图片名称' ,
58- path : '图片路径' ,
59- size : '图片大小'
60- } ,
6149 {
6250 groupOpenID : '' ,
6351 type : 'text/message' ,
@@ -99,7 +87,9 @@ const mockData = {
9987
10088Page ( {
10189 data : {
102- materials : [ ]
90+ materials : [ ] ,
91+ canvasWidth : 0 ,
92+ canvasHeight : 0
10393 } ,
10494
10595 onUnload ( ) {
@@ -109,6 +99,7 @@ Page({
10999 } ,
110100
111101 onLoad ( ) {
102+ this . _forwardMaterials = [ ]
112103 this . getMaterials ( )
113104 // this.formatMaterials(mockData.materials)
114105
@@ -136,6 +127,9 @@ Page({
136127 } ,
137128
138129 formatMaterials ( forwardMaterials = [ ] ) {
130+ this . _forwardMaterials = forwardMaterials
131+ this . triggerMergedImage ( )
132+
139133 const materials = [ ]
140134 for ( let item of forwardMaterials ) {
141135 let recordType = ''
@@ -158,4 +152,136 @@ Page({
158152 } )
159153 } ,
160154
161- } )
155+ async triggerMergedImage ( ) {
156+ try {
157+ const tempFilePaths = this . _forwardMaterials
158+ . filter ( item => item . type . startsWith ( 'image' ) )
159+ . map ( item => item . path )
160+ console . info ( 'tempFilePaths: ' , tempFilePaths )
161+ const shareImagePath = await this . mergeImages ( tempFilePaths )
162+ this . setData ( {
163+ shareImagePath,
164+ } )
165+ console . info ( 'shareImagePath: ' , shareImagePath )
166+
167+ } catch ( error ) {
168+ console . error ( 'mergeImages fail: ' , error )
169+ }
170+ } ,
171+
172+ shareMergedImage ( ) {
173+ if ( ! this . data . shareImagePath ) {
174+ wx . showToast ( {
175+ title : '拼图失败' ,
176+ icon : 'none'
177+ } )
178+ this . triggerMergedImage ( )
179+ return
180+ }
181+ wx . shareImageToGroup ( {
182+ imagePath : this . data . shareImagePath ,
183+ needShowEntrance : false ,
184+ complete ( res ) {
185+ console . info ( 'shareImageToGroup: ' , res )
186+ }
187+ } )
188+ } ,
189+
190+ async mergeImages ( tempFilePaths ) {
191+ try {
192+ // 获取 canvas 节点
193+ const { node : canvas , width : cw , height : ch } = await this . getCanvasNode ( ) ;
194+
195+ // 获取 2D 上下文
196+ const ctx = canvas . getContext ( '2d' ) ;
197+
198+ // 预加载所有图片
199+ const images = await this . loadAllImages ( canvas , tempFilePaths ) ;
200+
201+ // 绘制图片
202+ this . drawImages ( ctx , images , 400 ) ;
203+
204+ // 生成临时文件
205+ return await this . canvasToTempFile ( canvas ) ;
206+ } catch ( err ) {
207+ console . error ( '合并失败:' , err ) ;
208+ return null ;
209+ }
210+ } ,
211+
212+ // 获取 Canvas 节点(Promise 封装)
213+ getCanvasNode ( ) {
214+ return new Promise ( ( resolve , reject ) => {
215+ wx . createSelectorQuery ( )
216+ . select ( '#myCanvas' )
217+ . fields ( { node : true , size : true } )
218+ . exec ( res => {
219+ if ( res [ 0 ] ) resolve ( res [ 0 ] ) ;
220+ else reject ( new Error ( 'Canvas 节点获取失败' ) ) ;
221+ } ) ;
222+ } ) ;
223+ } ,
224+
225+ // 计算画布尺寸
226+ calculateLayout ( paths ) {
227+ const imgSize = 100 ;
228+ const spacing = 10 ;
229+ const perLine = 3 ;
230+
231+ const rows = Math . ceil ( paths . length / perLine ) ;
232+ return {
233+ canvasWidth : perLine * imgSize + ( perLine - 1 ) * spacing ,
234+ canvasHeight : rows * imgSize + ( rows - 1 ) * spacing
235+ } ;
236+ } ,
237+
238+ // 加载所有图片(Web Image 对象)
239+ loadAllImages ( canvas , paths ) {
240+ return Promise . all ( paths . map ( url => {
241+ return new Promise ( ( resolve , reject ) => {
242+ const image = canvas . createImage ( ) ;
243+ image . onload = ( ) => resolve ( image ) ;
244+ image . onerror = reject ;
245+ image . src = url ; // 支持本地路径和网络图片
246+ } ) ;
247+ } ) ) ;
248+ } ,
249+
250+ // 执行图片绘制
251+ drawImages ( ctx , images , canvasWidth ) {
252+ const imgSize = 100 ;
253+ const spacing = 10 ;
254+ const perLine = 3 ;
255+
256+ images . forEach ( ( image , index ) => {
257+ const row = Math . floor ( index / perLine ) ;
258+ const col = index % perLine ;
259+
260+ const x = col * ( imgSize + spacing ) ;
261+ const y = row * ( imgSize + spacing ) ;
262+
263+ // 绘制图像(支持缩放裁剪)
264+ ctx . drawImage (
265+ image ,
266+ 0 , 0 , image . width , image . height , // 源图裁剪区域
267+ x , y , imgSize , imgSize // 画布绘制区域
268+ ) ;
269+ } ) ;
270+ } ,
271+
272+ // Canvas 转临时文件
273+ canvasToTempFile ( canvas ) {
274+ return new Promise ( ( resolve , reject ) => {
275+ wx . canvasToTempFilePath ( {
276+ canvas : canvas ,
277+ fileType : 'png' ,
278+ width : 400 ,
279+ height : 500 ,
280+ quality : 1 ,
281+ success : res => resolve ( res . tempFilePath ) ,
282+ fail : reject
283+ } ) ;
284+ } ) ;
285+ }
286+
287+ } )
0 commit comments