nomid2 commited on
Commit
f8dcb5d
·
verified ·
1 Parent(s): 5d5f4dc

Upload 2 files

Browse files
Files changed (1) hide show
  1. src/lib/imageSlicer.js +112 -41
src/lib/imageSlicer.js CHANGED
@@ -50,54 +50,94 @@ class ImageSlicer {
50
  calculateLongImageSliceGrid(width, height, aspectRatio) {
51
  console.log(`[${new Date().toISOString()}] 📏 长图裁切分析: ${width}x${height}, 比例=${aspectRatio.toFixed(2)}`)
52
 
53
- // 对于长图,优先沿长边方向裁切,保持更大的重叠区域
54
  const isVerticalLong = height > width
55
 
56
  if (isVerticalLong) {
57
  // 垂直长图:沿高度方向裁切
58
- const enhancedOverlap = Math.min(this.overlapPixels * 2, this.maxSize * 0.1)
59
  const sliceHeight = this.maxSize
60
- const stepY = Math.max(1, sliceHeight - enhancedOverlap)
61
 
62
- // 重新计算行数,确保覆盖整个图片
63
- const rows = Math.ceil((height - enhancedOverlap) / stepY)
64
- const cols = 1 // 垂直长图通常不需要水平裁切
 
65
 
66
- console.log(`[${new Date().toISOString()}] 📏 垂直长图策略: ${rows}行x${cols}列, 重叠=${enhancedOverlap}px`)
67
- console.log(`[${new Date().toISOString()}] 📏 切片尺寸: ${width}x${sliceHeight}, 步长=${stepY}`)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
  return {
70
  rows,
71
- cols,
72
  sliceWidth: width,
73
  sliceHeight,
74
  stepX: width,
75
- stepY,
76
- totalSlices: rows * cols,
77
- overlapPixels: enhancedOverlap
 
78
  }
79
  } else {
80
  // 水平长图:沿宽度方向裁切
81
- const enhancedOverlap = Math.min(this.overlapPixels * 2, this.maxSize * 0.1)
82
  const sliceWidth = this.maxSize
83
- const stepX = Math.max(1, sliceWidth - enhancedOverlap)
84
 
85
- // 重新计算列数,确保覆盖整个图片
86
- const cols = Math.ceil((width - enhancedOverlap) / stepX)
87
- const rows = 1 // 水平长图通常不需要垂直裁切
 
 
 
 
 
 
 
 
 
 
88
 
89
- console.log(`[${new Date().toISOString()}] 📏 水平长图策略: ${rows}行x${cols}列, 重叠=${enhancedOverlap}px`)
90
- console.log(`[${new Date().toISOString()}] 📏 切片尺寸: ${sliceWidth}x${height}, 步长=${stepX}`)
 
 
 
 
 
 
 
 
 
 
91
 
92
  return {
93
- rows,
94
  cols,
95
  sliceWidth,
96
  sliceHeight: height,
97
- stepX,
98
  stepY: height,
99
- totalSlices: rows * cols,
100
- overlapPixels: enhancedOverlap
 
101
  }
102
  }
103
  }
@@ -178,12 +218,32 @@ class ImageSlicer {
178
  // 生成所有切片
179
  for (let row = 0; row < grid.rows; row++) {
180
  for (let col = 0; col < grid.cols; col++) {
181
- const x = col * grid.stepX
182
- const y = row * grid.stepY
183
-
184
- // 确保不超出图片边界
185
- const actualWidth = Math.min(grid.sliceWidth, metadata.width - x)
186
- const actualHeight = Math.min(grid.sliceHeight, metadata.height - y)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
 
188
  // 验证裁切参数
189
  if (x < 0 || y < 0 || actualWidth <= 0 || actualHeight <= 0 ||
@@ -192,24 +252,35 @@ class ImageSlicer {
192
  console.error(`[${new Date().toISOString()}] 图片尺寸: ${metadata.width}x${metadata.height}`)
193
  console.error(`[${new Date().toISOString()}] 裁切位置: (${x}, ${y})`)
194
  console.error(`[${new Date().toISOString()}] 裁切尺寸: ${actualWidth}x${actualHeight}`)
 
195
  continue // 跳过这个无效的切片
196
  }
197
 
198
  console.log(`[${new Date().toISOString()}] 🔪 生成切片 ${row * grid.cols + col + 1}/${grid.totalSlices}: ${actualWidth}x${actualHeight} at (${x},${y})`)
 
199
 
200
  // 裁切图片并转换为JPEG格式(更好的兼容性)
201
- const sliceBuffer = await image
202
- .extract({
203
- left: x,
204
- top: y,
205
- width: actualWidth,
206
- height: actualHeight
207
- })
208
- .jpeg({
209
- quality: 90, // 高质量JPEG
210
- progressive: false
211
- })
212
- .toBuffer()
 
 
 
 
 
 
 
 
 
213
 
214
  const sliceIndex = row * grid.cols + col
215
  const sliceName = this.generateSliceName(originalName, sliceIndex, grid.totalSlices)
 
50
  calculateLongImageSliceGrid(width, height, aspectRatio) {
51
  console.log(`[${new Date().toISOString()}] 📏 长图裁切分析: ${width}x${height}, 比例=${aspectRatio.toFixed(2)}`)
52
 
53
+ // 对于长图,使用更保守的策略,确保不会出现边界错误
54
  const isVerticalLong = height > width
55
 
56
  if (isVerticalLong) {
57
  // 垂直长图:沿高度方向裁切
58
+ const enhancedOverlap = Math.min(this.overlapPixels * 2, 200) // 限制最大重叠
59
  const sliceHeight = this.maxSize
 
60
 
61
+ // 计算需要多少片才能覆盖整个图片
62
+ let rows = 1
63
+ let currentY = 0
64
+ const positions = []
65
 
66
+ while (currentY < height) {
67
+ const remainingHeight = height - currentY
68
+ const actualSliceHeight = Math.min(sliceHeight, remainingHeight)
69
+
70
+ positions.push({
71
+ y: currentY,
72
+ height: actualSliceHeight
73
+ })
74
+
75
+ // 如果这是最后一片,就结束
76
+ if (currentY + actualSliceHeight >= height) {
77
+ break
78
+ }
79
+
80
+ // 计算下一片的起始位置
81
+ currentY += actualSliceHeight - enhancedOverlap
82
+ rows++
83
+ }
84
+
85
+ console.log(`[${new Date().toISOString()}] 📏 垂直长图策略: ${rows}行x1列, 重叠=${enhancedOverlap}px`)
86
+ console.log(`[${new Date().toISOString()}] 📏 切片位置:`, positions.map(p => `y=${p.y}, h=${p.height}`).join(', '))
87
 
88
  return {
89
  rows,
90
+ cols: 1,
91
  sliceWidth: width,
92
  sliceHeight,
93
  stepX: width,
94
+ stepY: sliceHeight - enhancedOverlap,
95
+ totalSlices: rows,
96
+ overlapPixels: enhancedOverlap,
97
+ positions // 添加精确的位置信息
98
  }
99
  } else {
100
  // 水平长图:沿宽度方向裁切
101
+ const enhancedOverlap = Math.min(this.overlapPixels * 2, 200) // 限制最大重叠
102
  const sliceWidth = this.maxSize
 
103
 
104
+ // 计算需要多少片才能覆盖整个图片
105
+ let cols = 1
106
+ let currentX = 0
107
+ const positions = []
108
+
109
+ while (currentX < width) {
110
+ const remainingWidth = width - currentX
111
+ const actualSliceWidth = Math.min(sliceWidth, remainingWidth)
112
+
113
+ positions.push({
114
+ x: currentX,
115
+ width: actualSliceWidth
116
+ })
117
 
118
+ // 如果这是最后一片,就结束
119
+ if (currentX + actualSliceWidth >= width) {
120
+ break
121
+ }
122
+
123
+ // 计算下一片的起始位置
124
+ currentX += actualSliceWidth - enhancedOverlap
125
+ cols++
126
+ }
127
+
128
+ console.log(`[${new Date().toISOString()}] 📏 水平长图策略: 1行x${cols}列, 重叠=${enhancedOverlap}px`)
129
+ console.log(`[${new Date().toISOString()}] 📏 切片位置:`, positions.map(p => `x=${p.x}, w=${p.width}`).join(', '))
130
 
131
  return {
132
+ rows: 1,
133
  cols,
134
  sliceWidth,
135
  sliceHeight: height,
136
+ stepX: sliceWidth - enhancedOverlap,
137
  stepY: height,
138
+ totalSlices: cols,
139
+ overlapPixels: enhancedOverlap,
140
+ positions // 添加精确的位置信息
141
  }
142
  }
143
  }
 
218
  // 生成所有切片
219
  for (let row = 0; row < grid.rows; row++) {
220
  for (let col = 0; col < grid.cols; col++) {
221
+ let x, y, actualWidth, actualHeight
222
+
223
+ // 如果有精确的位置信息,使用它
224
+ if (grid.positions) {
225
+ if (grid.rows > 1) {
226
+ // 垂直长图
227
+ const pos = grid.positions[row]
228
+ x = 0
229
+ y = pos.y
230
+ actualWidth = grid.sliceWidth
231
+ actualHeight = pos.height
232
+ } else {
233
+ // 水平长图
234
+ const pos = grid.positions[col]
235
+ x = pos.x
236
+ y = 0
237
+ actualWidth = pos.width
238
+ actualHeight = grid.sliceHeight
239
+ }
240
+ } else {
241
+ // 使用传统的计算方式
242
+ x = col * grid.stepX
243
+ y = row * grid.stepY
244
+ actualWidth = Math.min(grid.sliceWidth, metadata.width - x)
245
+ actualHeight = Math.min(grid.sliceHeight, metadata.height - y)
246
+ }
247
 
248
  // 验证裁切参数
249
  if (x < 0 || y < 0 || actualWidth <= 0 || actualHeight <= 0 ||
 
252
  console.error(`[${new Date().toISOString()}] 图片尺寸: ${metadata.width}x${metadata.height}`)
253
  console.error(`[${new Date().toISOString()}] 裁切位置: (${x}, ${y})`)
254
  console.error(`[${new Date().toISOString()}] 裁切尺寸: ${actualWidth}x${actualHeight}`)
255
+ console.error(`[${new Date().toISOString()}] 边界检查: x+w=${x + actualWidth} <= ${metadata.width}, y+h=${y + actualHeight} <= ${metadata.height}`)
256
  continue // 跳过这个无效的切片
257
  }
258
 
259
  console.log(`[${new Date().toISOString()}] 🔪 生成切片 ${row * grid.cols + col + 1}/${grid.totalSlices}: ${actualWidth}x${actualHeight} at (${x},${y})`)
260
+ console.log(`[${new Date().toISOString()}] 🔍 边界验证: 图片${metadata.width}x${metadata.height}, 裁切区域(${x},${y},${actualWidth},${actualHeight})`)
261
 
262
  // 裁切图片并转换为JPEG格式(更好的兼容性)
263
+ let sliceBuffer
264
+ try {
265
+ sliceBuffer = await image
266
+ .extract({
267
+ left: x,
268
+ top: y,
269
+ width: actualWidth,
270
+ height: actualHeight
271
+ })
272
+ .jpeg({
273
+ quality: 90, // 高质量JPEG
274
+ progressive: false
275
+ })
276
+ .toBuffer()
277
+ } catch (extractError) {
278
+ console.error(`[${new Date().toISOString()}] ❌ Sharp裁切失败:`)
279
+ console.error(`[${new Date().toISOString()}] 错误: ${extractError.message}`)
280
+ console.error(`[${new Date().toISOString()}] 参数: left=${x}, top=${y}, width=${actualWidth}, height=${actualHeight}`)
281
+ console.error(`[${new Date().toISOString()}] 图片: ${metadata.width}x${metadata.height}`)
282
+ throw extractError
283
+ }
284
 
285
  const sliceIndex = row * grid.cols + col
286
  const sliceName = this.generateSliceName(originalName, sliceIndex, grid.totalSlices)