本人业余时间开发了一个图片切割工具,非常好用,也很灵活!
特别对大型图片切割,更能体现出该软件的优势!
开发工具为winform
可以设定切割的高度和宽度。切割线可以上下拖动,可以增加一个切割区域,可设定某个区域不参与切割。
每个切割区域是一个长方形。用一个结构标识该属性。
1 class SpliteMoveIndex
2 {
3 public enum EN_DIR
4 {
5 NON,
6 HORIZONTAL,
7 VERTICAL
8 };
9 public EN_DIR direct = EN_DIR.NON;//0 无;1 水平;2垂直
10 public int rectIndex; //第几个rect
11 public int lineIndex; //第几个线 1:上或左;2 下或右
12 public int mouseX;
13 public int mouseY;
14
15
16 public static SpliteMoveIndex CreateNon(int x, int y)
17 {
18 SpliteMoveIndex _nonIndex = new SpliteMoveIndex();
19 _nonIndex.direct = EN_DIR.NON;
20 _nonIndex.SetMouse(x, y);
21 return _nonIndex;
22 }
23
24 public SpliteMoveIndex()
25 {
26
27 }
28 public SpliteMoveIndex(int x, int y)
29 {
30 SetMouse(x, y);
31 }
32
33 public bool IsSameLine(SpliteMoveIndex another)
34 {
35 return this.direct == another.direct
36 && this.rectIndex == another.rectIndex
37 && this.lineIndex == another.lineIndex;
38 }
39
40 public bool IsIn()
41 {
42 return direct != EN_DIR.NON;
43 }
44 public bool IsHorIn()
45 {
46 return direct == EN_DIR.HORIZONTAL;
47 }
48 public bool IsVertIn()
49 {
50 return direct == EN_DIR.VERTICAL;
51 }
52
53 public void SetMouse(int x, int y)
54 {
55 mouseX = x;
56 mouseY = y;
57 }
58 }
View Code
SpliteRectGroup 负责组合这些长方形。当有鼠标移动时,动态调整这些长方形大小,再重画!
1 class SpliteRectGroup
2 {
3 List _listSplitRect = new List();
4 int _widthSrc;
5 int _heightSrc;
6
7 SpliteMoveIndex _lastMoveIndex = new SpliteMoveIndex();
8
9 public int _defaultHitSpace = 5;
10
11 int _moveAllFlagR = 10;
12 bool _isMoveAll = false;
13
14 //不参加切割的区域
15 List _listSplitRectNotUsed = new List();
16
17 public void SetRect(int widthSrc, int heightSrc, int startX, int startY,
18 int widthDest, int heightDest)
19 {
20 _widthSrc = widthSrc;
21 _heightSrc = heightSrc;
22 _listSplitRect.Clear();
23
24 GetSplitSize(_widthSrc, _heightSrc, startX, startY,
25 widthDest, heightDest, ref _listSplitRect);
26 }
27
28 public List GetRects()
29 {
30 return _listSplitRect;
31 }
32
33 public List GetRectsSplit()
34 {
35 List listShow = new List();
36
37 int i = 0;
38 foreach(Rectangle rect in _listSplitRect)
39 {
40 if(IsRectUsed(i))
41 {
42 listShow.Add(rect);
43 }
44 i++;
45 }
46 return listShow;
47 }
48
49
50 public int GetStartX()
51 {
52 if (_listSplitRect.Count == 0)
53 return 0;
54 Rectangle first = _listSplitRect.First();
55 return first.X;
56 }
57
58 public int GetSpliteWidth()
59 {
60 if (_listSplitRect.Count == 0)
61 return 0;
62 Rectangle first = _listSplitRect.First();
63 return first.Width;
64 }
65
66 public int GetSpliteTotalHeight()
67 {
68 if (_listSplitRect.Count == 0)
69 return 0;
70 int i = 0;
71 foreach (Rectangle r in _listSplitRect)
72 {
73 i += r.Height;
74 }
75 return i;
76 }
77
78 public void SetMoveAllFlag(bool flag)
79 {
80 _isMoveAll = flag;
81 }
82
83 public bool GetMoveAllFlag()
84 {
85 return _isMoveAll;
86 }
87
88 public int GetStartY()
89 {
90 if (_listSplitRect.Count == 0)
91 return 0;
92 Rectangle first = _listSplitRect.First();
93 return first.Y;
94 }
95 public void Draw(Graphics g)
96 {
97 SolidBrush brushRect = new SolidBrush(Color.FromArgb(200, 255, 0, 0));
98 Font strfont = new Font("Verdana", 20);
99 Brush strBrush = Brushes.Blue;
100 Brush strBrushBack = Brushes.White;
101
102 //起点圆
103 int x = GetStartX();
104 int y = GetStartY();
105 g.FillEllipse(brushRect, x - _moveAllFlagR, y - _moveAllFlagR, 2 * _moveAllFlagR, 2 * _moveAllFlagR);
106 brushRect.Dispose();
107 //起点信息
108 string startInfo = string.Format("({0}:{1})",x,y);
109 SizeF sizeF = g.MeasureString(startInfo, strfont);
110 Point ptStart = new Point((int)(x-sizeF.Width/2), (int)(y -sizeF.Height- _defaultHitSpace*2) );
111 g.FillRectangle(strBrushBack, new RectangleF(ptStart, sizeF));
112 g.DrawString(startInfo, strfont, strBrush, ptStart);
113
114
115 //画方框
116 Color backColor = Color.FromArgb(0, Color.PowderBlue);
117 HatchBrush hat1 = new HatchBrush(HatchStyle.OutlinedDiamond, Color.DarkBlue, backColor);
118 HatchBrush hat2 = new HatchBrush(HatchStyle.OutlinedDiamond, Color.Red, backColor);
119
120 //输出提示信息
121 Pen rectPen = Pens.Red;
122 int i = 0;
123 int showIndex = 0;
124 string info;
125 foreach (Rectangle rect in _listSplitRect)
126 {
127 i++;
128 bool used = IsRectUsed(rect);
129 if (used)
130 {
131 showIndex++;
132 info = string.Format("{0}-({1}:{2})", showIndex, rect.Width, rect.Height);
133 }
134 else
135 {
136 info = string.Format("({0}:{1})--不参与切割", rect.Width, rect.Height);
137 }
138
139 g.DrawRectangle(rectPen, rect);
140 if (!used)
141 {
142 g.FillRectangle(hat1, rect);
143 }
144
145 Point strStart = new Point(rect.X + 5, rect.Y + 5);
146 sizeF = g.MeasureString(info, strfont);
147 g.FillRectangle(strBrushBack, new RectangleF(strStart, sizeF));
148
149 g.DrawString(info, strfont, strBrush, strStart);
150 }
151 strfont.Dispose();
152 hat1.Dispose();
153 hat2.Dispose();
154 }
155 public bool StartPointMoveTo(int x, int y)
156 {
157 if (_listSplitRect.Count == 0)
158 return false;
159
160 Rectangle first = _listSplitRect.First();
161 int moveX = x - first.X;
162 int moveY = y - first.Y;
163
164 List listSplitRectNew = new List();
165 foreach (Rectangle r in _listSplitRect)
166 {
167 Rectangle tmp = r;
168 tmp.Offset(moveX, moveY);
169 listSplitRectNew.Add(tmp);
170 }
171
172 _listSplitRect.Clear();
173 _listSplitRect = listSplitRectNew;
174 return true;
175 }
176
177 public bool IsAllMove(int mouseX, int mouseY)
178 {
179 GraphicsPath myGraphicsPath = new GraphicsPath();
180 myGraphicsPath.Reset();
181 Region myRegion = new Region();
182
183 int x = GetStartX();
184 int y = GetStartY();
185 myGraphicsPath.AddEllipse(x - _moveAllFlagR, y - _moveAllFlagR, 2 * _moveAllFlagR, 2 * _moveAllFlagR);//points);
186 myRegion.MakeEmpty();
187 myRegion.Union(myGraphicsPath);
188 //返回判断点是否在多边形里
189 bool myPoint = myRegion.IsVisible(mouseX, mouseY);
190 return myPoint;
191 }
192
193 public void ResetMoveFlag()
194 {
195 _lastMoveIndex.direct = SpliteMoveIndex.EN_DIR.NON;
196 }
197
198 public bool SetMove(SpliteMoveIndex index)
199 {
200 //移动到区域外
201 if (!index.IsIn())
202 {
203 _lastMoveIndex = index;
204 return false;
205 }
206
207 //不是同一条线
208 if (!_lastMoveIndex.IsSameLine(index))
209 {
210 _lastMoveIndex = index;
211 return false;
212 }
213
214 //移动到新的区域
215 MoveRect(_lastMoveIndex, index);
216 _lastMoveIndex = index;
217 return true;
218 }
219
220 public bool IsInSplite()
221 {
222 if (_lastMoveIndex == null)
223 return false;
224 return _lastMoveIndex.IsIn();
225 }
226
227 void MoveRect(SpliteMoveIndex last, SpliteMoveIndex now)
228 {
229 if (last.IsHorIn())
230 {
231 MoveRectHor(last, now);
232 }
233 else if (last.IsVertIn())
234 {
235 MoveRectVert(last, now);
236 }
237 }
238
239 void MoveRectHor(SpliteMoveIndex last, SpliteMoveIndex now)
240 {
241 int moveY = now.mouseY - last.mouseY;
242 List listSplitRectNew = new List();
243 int i = 0;
244 int find = 0;
245 foreach (Rectangle r in _listSplitRect)
246 {
247 Rectangle tmp = r;
248 i++;
249 if (find == 2)
250 {
251 listSplitRectNew.Add(tmp);
252 continue;
253 }
254 if (find == 1)
255 {
256 tmp.Y += moveY;
257 tmp.Height -= moveY;
258 find = 2;
259 listSplitRectNew.Add(tmp);
260 continue;
261 }
262
263 if (i == last.rectIndex)
264 {
265 if (last.lineIndex == 1)
266 {
267 tmp.Y += moveY;
268 tmp.Height -= moveY;
269 find = 2;
270 listSplitRectNew.Add(tmp);
271 }
272 else if (last.lineIndex == 2)
273 {
274 tmp.Height += moveY;
275 find = 1;
276 listSplitRectNew.Add(tmp);
277 }
278 }
279 else
280 {
281 listSplitRectNew.Add(tmp);
282 }
283 }
284
285 _listSplitRect.Clear();
286 _listSplitRect = listSplitRectNew;
287 }
288
289
290 void MoveRectVert(SpliteMoveIndex last, SpliteMoveIndex now)
291 {
292 int moveX = now.mouseX - last.mouseX;
293 List listSplitRectNew = new List();
294 int i = 0;
295 foreach (Rectangle r in _listSplitRect)
296 {
297 Rectangle tmp = r;
298 i++;
299 if (last.lineIndex == 1)
300 {
301 tmp.X += moveX;
302 tmp.Width -= moveX;
303 listSplitRectNew.Add(tmp);
304 }
305 else if (last.lineIndex == 2)
306 {
307 tmp.Width += moveX;
308 listSplitRectNew.Add(tmp);
309 }
310 }
311
312 _listSplitRect.Clear();
313 _listSplitRect = listSplitRectNew;
314 }
315
316 SpliteMoveIndex GetHorizontal(int x, int y, int hitSpace)
317 {
318 int startX = GetStartX();
319 int width = GetSpliteWidth();
320 if (x < startX || x > (startX + width))
321 return SpliteMoveIndex.CreateNon(x, y);
322
323 int i = 0;
324 foreach (Rectangle rect in _listSplitRect)
325 {
326 i++;
327 int y1 = rect.Y;
328 //是否落在水平线 一定范围内
329 if (y >= y1 - hitSpace && y <= (y1 + hitSpace))
330 {
331 SpliteMoveIndex moveIndex = new SpliteMoveIndex(x, y);
332 moveIndex.direct = SpliteMoveIndex.EN_DIR.HORIZONTAL;
333 moveIndex.rectIndex = i;
334 moveIndex.lineIndex = 1;
335 return moveIndex;
336 }
337
338 int y2 = rect.Y + rect.Height;
339 if (y >= (y2 - hitSpace) && y <= (y2 + hitSpace))
340 {
341 SpliteMoveIndex moveIndex = new SpliteMoveIndex(x, y);
342 moveIndex.direct = SpliteMoveIndex.EN_DIR.HORIZONTAL;
343 moveIndex.rectIndex = i;
344 moveIndex.lineIndex = 2;
345 return moveIndex;
346 }
347 }
348
349 return SpliteMoveIndex.CreateNon(x, y);
350 }
351
352 SpliteMoveIndex GetVectical(int x, int y, int hitSpace)
353 {
354 int startY = GetStartY();
355 if (y < startY || y > (startY + _heightSrc))
356 return SpliteMoveIndex.CreateNon(x, y);
357
358 int i = 0;
359 foreach (Rectangle rect in _listSplitRect)
360 {
361 i++;
362 //是否落在垂直线 一定范围内
363 if (y >= rect.Y && y <= (rect.Y + rect.Height))
364 {
365 int x1 = rect.X;
366 if (x >= (x1 - hitSpace) && x <= (x1 + hitSpace))
367 {
368 SpliteMoveIndex moveIndex = new SpliteMoveIndex(x, y);
369 moveIndex.direct = SpliteMoveIndex.EN_DIR.VERTICAL;
370 moveIndex.rectIndex = i;
371 moveIndex.lineIndex = 1;
372 return moveIndex;
373 }
374
375 int x2 = rect.X + rect.Width;
376 if (x >= (x2 - hitSpace) && x <= (x2 + hitSpace))
377 {
378 SpliteMoveIndex moveIndex = new SpliteMoveIndex(x, y);
379 moveIndex.direct = SpliteMoveIndex.EN_DIR.VERTICAL;
380 moveIndex.rectIndex = i;
381 moveIndex.lineIndex = 2;
382 return moveIndex;
383 }
384 }
385 }
386
387 return SpliteMoveIndex.CreateNon(x, y);
388 }
389
390 public SpliteMoveIndex PointHit(int x, int y, int hitSpace)
391 {
392 //判断是否在水平线
393 SpliteMoveIndex hRect = GetHorizontal(x, y, hitSpace);
394 if (hRect.IsIn())
395 return hRect;
396
397 //判断是否在垂直线
398 SpliteMoveIndex vRect = GetVectical(x, y, hitSpace);
399 if (vRect.IsIn())
400 return vRect;
401
402 return SpliteMoveIndex.CreateNon(x, y);
403 }
404
405 public bool PointInRect(int x,int y)
406 {
407 int startX = GetStartX();
408 int width = GetSpliteWidth();
409 if (x < startX || x > (startX + width))
410 return false;
411
412 int startY = GetStartY();
413 int heght = GetSpliteTotalHeight();
414 if (y < startY || y > (startY + heght))
415 return false;
416 return true;
417 }
418
419 public void ClearNotUsedRect()
420 {
421 _listSplitRectNotUsed.Clear();
422 }
423
424 public bool GetRectIndex(int index,ref Rectangle outRect)
425 {
426 int i = 0;
427 foreach (Rectangle rect in _listSplitRect)
428 {
429 if (i == index)
430 {
431 outRect = rect;
432 return true;
433 }
434 i++;
435 }
436 return false;
437 }
438
439 public bool IsNotUsed(int x, int y)
440 {
441 Rectangle rect = new Rectangle();
442 foreach (int n in _listSplitRectNotUsed)
443 {
444 if (GetRectIndex(n, ref rect) && rect.Contains(x, y))
445 {
446 return true;
447 }
448 }
449 return false;
450 }
451
452 public bool IsRectUsed(Rectangle rect)
453 {
454 Rectangle rectNot = new Rectangle();
455 foreach (int n in _listSplitRectNotUsed)
456 {
457 if (GetRectIndex(n, ref rectNot) && rectNot == rect)
458 {
459 return false;
460 }
461 }
462 return true;
463 }
464
465 public bool IsRectUsed(int index)
466 {
467 foreach (int n in _listSplitRectNotUsed)
468 {
469 if (n == index)
470 return false;
471 }
472 return true;
473 }
474
475 //区块加入切割
476 public bool AddRectUsed(int x,int y)
477 {
478 int i = 0;
479 Rectangle rectNot = new Rectangle();
480 foreach (int n in _listSplitRectNotUsed)
481 {
482 if (GetRectIndex(n, ref rectNot) && rectNot.Contains(x,y))
483 {
484 _listSplitRectNotUsed.RemoveAt(i);
485 return true;
486 }
487 i++;
488 }
489 return false;
490 }
491
492 //区块不加入切割
493 public bool DelRectUsed(int x, int y)
494 {
495 int i = 0;
496 foreach (Rectangle rect in _listSplitRect)
497 {
498 if (rect.Contains(x, y))
499 {
500 _listSplitRectNotUsed.Add(i);
501 return true;
502 }
503 i++;
504 }
505 return false;
506 }
507
508 public bool AddHorLine(int x, int y)
509 {
510 List listSplitRectNew = new List();
511 foreach (Rectangle rect in _listSplitRect)
512 {
513 if (y > rect.Y && y < rect.Y + rect.Height)
514 {
515 Rectangle r1 = new Rectangle(rect.Location, rect.Size);
516 r1.Height = y - rect.Y;
517 listSplitRectNew.Add(r1);
518
519 r1.Y = y ;
520 r1.Height = (rect.Y + rect.Height - y);
521 listSplitRectNew.Add(r1);
522 }
523 else
524 {
525 listSplitRectNew.Add(rect);
526 }
527 }
528 _listSplitRect = listSplitRectNew;
529 return true;
530 }
531
532 //删除水平线
533 public bool DeleteHorSplite(SpliteMoveIndex index)
534 {
535 List listSplitRectNew = new List();
536 int i = 0;
537 bool del = false;
538 Rectangle lastRect = new Rectangle();
539 bool haveLast = false;
540
541 foreach (Rectangle rect in _listSplitRect)
542 {
543 i++;
544 if(haveLast)
545 {
546 haveLast = false;
547 lastRect.Height += rect.Height;
548 listSplitRectNew.Add(lastRect);
549 continue;
550 }
551
552 if(index.rectIndex == i)
553 {
554 del = true;
555 if (index.lineIndex == 1)
556 {
557 if(listSplitRectNew.Count == 0)
558 {
559 continue;
560 }
561 else
562 {
563 Rectangle r = listSplitRectNew.Last();
564 r.Height += rect.Height;
565 listSplitRectNew.RemoveAt(listSplitRectNew.Count-1);
566 listSplitRectNew.Add(r);
567 }
568 }
569 else if (index.lineIndex == 2)
570 {
571 if(i == _listSplitRect.Count)
572 {
573 continue;
574 }
575 else
576 {
577 lastRect = rect;
578 haveLast = true;
579 }
580 }
581 else { Debug.Assert(false); }
582 }
583 else
584 {
585 listSplitRectNew.Add(rect);
586 }
587 }
588
589 _listSplitRect = listSplitRectNew;
590 return del;
591 }
592
593 public static int GetSplitSize(int widthSrc, int heightSrc, int startX, int startY,
594 int widthDest, int heightDest, ref List listOut)
595 {
596 listOut = new List();
597
598 int width = Math.Min(widthSrc - startX, widthDest);
599
600 int i = 0;
601 bool stop = false;
602 while (!stop)
603 {
604 Rectangle rect = new Rectangle();
605
606 rect.X = startX;
607 rect.Y = startY + (i * heightDest);
608 rect.Width = width;
609 rect.Height = heightDest;
610 if (rect.Y + rect.Height >= heightSrc)
611 {
612 stop = true;
613 rect.Height = heightSrc - rect.Y;
614 }
615 listOut.Add(rect);
616 i++;
617 }
618 return 0;
619 }
620 }
View Code
图像切割其实就是在一个内存中重新绘制,再将内存中的数据保存到文件。切割代码如下:
1 public static bool SplitPic(Image initImage,
2 int startX, int startY, int width, int height, ref Image destImage,int destWidth = 0)
3 {
4 if (startX >= initImage.Width || startY >= initImage.Height)
5 return false;
6
7 //计算最大宽度 长度
8 int width2 = Math.Min(width, initImage.Width - startX);
9 int height2 = Math.Min(height, initImage.Height - startY);
10
11 int destHeight;
12 if (destWidth == 0)
13 {
14 destWidth = width2;
15 destHeight = height2;
16 }
17 else
18 {
19 destHeight = (height2 * destWidth) / width2;
20 }
21
22
23 width = width2;
24 height = height2;
25
26 //裁剪对象
27 System.Drawing.Image pickedImage = null;
28 System.Drawing.Graphics pickedG = null;
29
30 //定位
31 Rectangle fromR = new Rectangle(0, 0, 0, 0);//原图裁剪定位
32 Rectangle toR = new Rectangle(0, 0, 0, 0);//目标定位
33
34 //裁剪对象实例化
35 pickedImage = new System.Drawing.Bitmap(destWidth, destHeight);
36 pickedG = System.Drawing.Graphics.FromImage(pickedImage);
37
38 //裁剪源定位
39 fromR.X = startX;
40 fromR.Y = startY;
41 fromR.Width = width;
42 fromR.Height = height;
43
44 //裁剪目标定位
45 toR.X = 0;
46 toR.Y = 0;
47 toR.Width = destWidth;
48 toR.Height = destHeight;
49
50 //设置质量
51 pickedG.InterpolationMode = InterpolationMode.HighQualityBicubic;
52 pickedG.SmoothingMode = SmoothingMode.HighQuality;
53 //裁剪
54 pickedG.DrawImage(initImage, toR, fromR, System.Drawing.GraphicsUnit.Pixel);
55
56 destImage = pickedImage;
57 return true;
58 }