本人业余时间开发了一个图片切割工具,非常好用,也很灵活!
特别对大型图片切割,更能体现出该软件的优势!
功能说明
可以设定切割的高度和宽度。切割线可以上下拖动,可以增加一个切割区域,可设定某个区域不参与切割。
主要技术点分析
切割区域确定
每个切割区域是一个长方形。用一个结构标识该属性。
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; //第几个rect11 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.direct36 && this.rectIndex == another.rectIndex37 && 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 }
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 else135 {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 else280 {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 else524 {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 else562 {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 else576 {577 lastRect = rect;578 haveLast = true;579 }580 }581 else { Debug.Assert(false); }582 }583 else584 {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 }
图像快速切割
图像切割其实就是在一个内存中重新绘制,再将内存中的数据保存到文件。切割代码如下:
。。。