@@ -19,8 +19,10 @@ const mockData = {
19
19
} ,
20
20
{
21
21
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 : '图片大小'
24
26
} ,
25
27
{
26
28
groupOpenID : '' ,
@@ -44,20 +46,6 @@ const mockData = {
44
46
path : 'https://res.wx.qq.com/wxdoc/dist/assets/img/demo.ef5c5bef.jpg' ,
45
47
size : '图片大小'
46
48
} ,
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
- } ,
61
49
{
62
50
groupOpenID : '' ,
63
51
type : 'text/message' ,
@@ -99,7 +87,9 @@ const mockData = {
99
87
100
88
Page ( {
101
89
data : {
102
- materials : [ ]
90
+ materials : [ ] ,
91
+ canvasWidth : 0 ,
92
+ canvasHeight : 0
103
93
} ,
104
94
105
95
onUnload ( ) {
@@ -109,6 +99,7 @@ Page({
109
99
} ,
110
100
111
101
onLoad ( ) {
102
+ this . _forwardMaterials = [ ]
112
103
this . getMaterials ( )
113
104
// this.formatMaterials(mockData.materials)
114
105
@@ -136,6 +127,9 @@ Page({
136
127
} ,
137
128
138
129
formatMaterials ( forwardMaterials = [ ] ) {
130
+ this . _forwardMaterials = forwardMaterials
131
+ this . triggerMergedImage ( )
132
+
139
133
const materials = [ ]
140
134
for ( let item of forwardMaterials ) {
141
135
let recordType = ''
@@ -158,4 +152,136 @@ Page({
158
152
} )
159
153
} ,
160
154
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