本人业余时间开发了一个图片切割工具,非常好用,也很灵活!

特别对大型图片切割,更能体现出该软件的优势!

功能说明

可以设定切割的高度和宽度。切割线可以上下拖动,可以增加一个切割区域,可设定某个区域不参与切割。

主要技术点分析

切割区域确定

每个切割区域是一个长方形。用一个结构标识该属性。

 class SpliteMoveIndex
{
public enum EN_DIR
{
NON,
HORIZONTAL,
VERTICAL
};
public EN_DIR direct = EN_DIR.NON;//0 无;1 水平;2垂直
public int rectIndex; //第几个rect
public int lineIndex; //第几个线 1:上或左;2 下或右
public int mouseX;
public int mouseY; public static SpliteMoveIndex CreateNon(int x, int y)
{
SpliteMoveIndex _nonIndex = new SpliteMoveIndex();
_nonIndex.direct = EN_DIR.NON;
_nonIndex.SetMouse(x, y);
return _nonIndex;
} public SpliteMoveIndex()
{ }
public SpliteMoveIndex(int x, int y)
{
SetMouse(x, y);
} public bool IsSameLine(SpliteMoveIndex another)
{
return this.direct == another.direct
&& this.rectIndex == another.rectIndex
&& this.lineIndex == another.lineIndex;
} public bool IsIn()
{
return direct != EN_DIR.NON;
}
public bool IsHorIn()
{
return direct == EN_DIR.HORIZONTAL;
}
public bool IsVertIn()
{
return direct == EN_DIR.VERTICAL;
} public void SetMouse(int x, int y)
{
mouseX = x;
mouseY = y;
}
}

SpliteRectGroup 负责组合这些长方形。当有鼠标移动时,动态调整这些长方形大小,再重画!

  class SpliteRectGroup
{
List<Rectangle> _listSplitRect = new List<Rectangle>();
int _widthSrc;
int _heightSrc; SpliteMoveIndex _lastMoveIndex = new SpliteMoveIndex(); public int _defaultHitSpace = ; int _moveAllFlagR = ;
bool _isMoveAll = false; //不参加切割的区域
List<int> _listSplitRectNotUsed = new List<int>(); public void SetRect(int widthSrc, int heightSrc, int startX, int startY,
int widthDest, int heightDest)
{
_widthSrc = widthSrc;
_heightSrc = heightSrc;
_listSplitRect.Clear(); GetSplitSize(_widthSrc, _heightSrc, startX, startY,
widthDest, heightDest, ref _listSplitRect);
} public List<Rectangle> GetRects()
{
return _listSplitRect;
} public List<Rectangle> GetRectsSplit()
{
List<Rectangle> listShow = new List<Rectangle>(); int i = ;
foreach(Rectangle rect in _listSplitRect)
{
if(IsRectUsed(i))
{
listShow.Add(rect);
}
i++;
}
return listShow;
} public int GetStartX()
{
if (_listSplitRect.Count == )
return ;
Rectangle first = _listSplitRect.First();
return first.X;
} public int GetSpliteWidth()
{
if (_listSplitRect.Count == )
return ;
Rectangle first = _listSplitRect.First();
return first.Width;
} public int GetSpliteTotalHeight()
{
if (_listSplitRect.Count == )
return ;
int i = ;
foreach (Rectangle r in _listSplitRect)
{
i += r.Height;
}
return i;
} public void SetMoveAllFlag(bool flag)
{
_isMoveAll = flag;
} public bool GetMoveAllFlag()
{
return _isMoveAll;
} public int GetStartY()
{
if (_listSplitRect.Count == )
return ;
Rectangle first = _listSplitRect.First();
return first.Y;
}
public void Draw(Graphics g)
{
SolidBrush brushRect = new SolidBrush(Color.FromArgb(, , , ));
Font strfont = new Font("Verdana", );
Brush strBrush = Brushes.Blue;
Brush strBrushBack = Brushes.White; //起点圆
int x = GetStartX();
int y = GetStartY();
g.FillEllipse(brushRect, x - _moveAllFlagR, y - _moveAllFlagR, * _moveAllFlagR, * _moveAllFlagR);
brushRect.Dispose();
//起点信息
string startInfo = string.Format("({0}:{1})",x,y);
SizeF sizeF = g.MeasureString(startInfo, strfont);
Point ptStart = new Point((int)(x-sizeF.Width/), (int)(y -sizeF.Height- _defaultHitSpace*) );
g.FillRectangle(strBrushBack, new RectangleF(ptStart, sizeF));
g.DrawString(startInfo, strfont, strBrush, ptStart); //画方框
Color backColor = Color.FromArgb(, Color.PowderBlue);
HatchBrush hat1 = new HatchBrush(HatchStyle.OutlinedDiamond, Color.DarkBlue, backColor);
HatchBrush hat2 = new HatchBrush(HatchStyle.OutlinedDiamond, Color.Red, backColor); //输出提示信息
Pen rectPen = Pens.Red;
int i = ;
int showIndex = ;
string info;
foreach (Rectangle rect in _listSplitRect)
{
i++;
bool used = IsRectUsed(rect);
if (used)
{
showIndex++;
info = string.Format("{0}-({1}:{2})", showIndex, rect.Width, rect.Height);
}
else
{
info = string.Format("({0}:{1})--不参与切割", rect.Width, rect.Height);
} g.DrawRectangle(rectPen, rect);
if (!used)
{
g.FillRectangle(hat1, rect);
} Point strStart = new Point(rect.X + , rect.Y + );
sizeF = g.MeasureString(info, strfont);
g.FillRectangle(strBrushBack, new RectangleF(strStart, sizeF)); g.DrawString(info, strfont, strBrush, strStart);
}
strfont.Dispose();
hat1.Dispose();
hat2.Dispose();
}
public bool StartPointMoveTo(int x, int y)
{
if (_listSplitRect.Count == )
return false; Rectangle first = _listSplitRect.First();
int moveX = x - first.X;
int moveY = y - first.Y; List<Rectangle> listSplitRectNew = new List<Rectangle>();
foreach (Rectangle r in _listSplitRect)
{
Rectangle tmp = r;
tmp.Offset(moveX, moveY);
listSplitRectNew.Add(tmp);
} _listSplitRect.Clear();
_listSplitRect = listSplitRectNew;
return true;
} public bool IsAllMove(int mouseX, int mouseY)
{
GraphicsPath myGraphicsPath = new GraphicsPath();
myGraphicsPath.Reset();
Region myRegion = new Region(); int x = GetStartX();
int y = GetStartY();
myGraphicsPath.AddEllipse(x - _moveAllFlagR, y - _moveAllFlagR, * _moveAllFlagR, * _moveAllFlagR);//points);
myRegion.MakeEmpty();
myRegion.Union(myGraphicsPath);
//返回判断点是否在多边形里
bool myPoint = myRegion.IsVisible(mouseX, mouseY);
return myPoint;
} public void ResetMoveFlag()
{
_lastMoveIndex.direct = SpliteMoveIndex.EN_DIR.NON;
} public bool SetMove(SpliteMoveIndex index)
{
//移动到区域外
if (!index.IsIn())
{
_lastMoveIndex = index;
return false;
} //不是同一条线
if (!_lastMoveIndex.IsSameLine(index))
{
_lastMoveIndex = index;
return false;
} //移动到新的区域
MoveRect(_lastMoveIndex, index);
_lastMoveIndex = index;
return true;
} public bool IsInSplite()
{
if (_lastMoveIndex == null)
return false;
return _lastMoveIndex.IsIn();
} void MoveRect(SpliteMoveIndex last, SpliteMoveIndex now)
{
if (last.IsHorIn())
{
MoveRectHor(last, now);
}
else if (last.IsVertIn())
{
MoveRectVert(last, now);
}
} void MoveRectHor(SpliteMoveIndex last, SpliteMoveIndex now)
{
int moveY = now.mouseY - last.mouseY;
List<Rectangle> listSplitRectNew = new List<Rectangle>();
int i = ;
int find = ;
foreach (Rectangle r in _listSplitRect)
{
Rectangle tmp = r;
i++;
if (find == )
{
listSplitRectNew.Add(tmp);
continue;
}
if (find == )
{
tmp.Y += moveY;
tmp.Height -= moveY;
find = ;
listSplitRectNew.Add(tmp);
continue;
} if (i == last.rectIndex)
{
if (last.lineIndex == )
{
tmp.Y += moveY;
tmp.Height -= moveY;
find = ;
listSplitRectNew.Add(tmp);
}
else if (last.lineIndex == )
{
tmp.Height += moveY;
find = ;
listSplitRectNew.Add(tmp);
}
}
else
{
listSplitRectNew.Add(tmp);
}
} _listSplitRect.Clear();
_listSplitRect = listSplitRectNew;
} void MoveRectVert(SpliteMoveIndex last, SpliteMoveIndex now)
{
int moveX = now.mouseX - last.mouseX;
List<Rectangle> listSplitRectNew = new List<Rectangle>();
int i = ;
foreach (Rectangle r in _listSplitRect)
{
Rectangle tmp = r;
i++;
if (last.lineIndex == )
{
tmp.X += moveX;
tmp.Width -= moveX;
listSplitRectNew.Add(tmp);
}
else if (last.lineIndex == )
{
tmp.Width += moveX;
listSplitRectNew.Add(tmp);
}
} _listSplitRect.Clear();
_listSplitRect = listSplitRectNew;
} SpliteMoveIndex GetHorizontal(int x, int y, int hitSpace)
{
int startX = GetStartX();
int width = GetSpliteWidth();
if (x < startX || x > (startX + width))
return SpliteMoveIndex.CreateNon(x, y); int i = ;
foreach (Rectangle rect in _listSplitRect)
{
i++;
int y1 = rect.Y;
//是否落在水平线 一定范围内
if (y >= y1 - hitSpace && y <= (y1 + hitSpace))
{
SpliteMoveIndex moveIndex = new SpliteMoveIndex(x, y);
moveIndex.direct = SpliteMoveIndex.EN_DIR.HORIZONTAL;
moveIndex.rectIndex = i;
moveIndex.lineIndex = ;
return moveIndex;
} int y2 = rect.Y + rect.Height;
if (y >= (y2 - hitSpace) && y <= (y2 + hitSpace))
{
SpliteMoveIndex moveIndex = new SpliteMoveIndex(x, y);
moveIndex.direct = SpliteMoveIndex.EN_DIR.HORIZONTAL;
moveIndex.rectIndex = i;
moveIndex.lineIndex = ;
return moveIndex;
}
} return SpliteMoveIndex.CreateNon(x, y);
} SpliteMoveIndex GetVectical(int x, int y, int hitSpace)
{
int startY = GetStartY();
if (y < startY || y > (startY + _heightSrc))
return SpliteMoveIndex.CreateNon(x, y); int i = ;
foreach (Rectangle rect in _listSplitRect)
{
i++;
//是否落在垂直线 一定范围内
if (y >= rect.Y && y <= (rect.Y + rect.Height))
{
int x1 = rect.X;
if (x >= (x1 - hitSpace) && x <= (x1 + hitSpace))
{
SpliteMoveIndex moveIndex = new SpliteMoveIndex(x, y);
moveIndex.direct = SpliteMoveIndex.EN_DIR.VERTICAL;
moveIndex.rectIndex = i;
moveIndex.lineIndex = ;
return moveIndex;
} int x2 = rect.X + rect.Width;
if (x >= (x2 - hitSpace) && x <= (x2 + hitSpace))
{
SpliteMoveIndex moveIndex = new SpliteMoveIndex(x, y);
moveIndex.direct = SpliteMoveIndex.EN_DIR.VERTICAL;
moveIndex.rectIndex = i;
moveIndex.lineIndex = ;
return moveIndex;
}
}
} return SpliteMoveIndex.CreateNon(x, y);
} public SpliteMoveIndex PointHit(int x, int y, int hitSpace)
{
//判断是否在水平线
SpliteMoveIndex hRect = GetHorizontal(x, y, hitSpace);
if (hRect.IsIn())
return hRect; //判断是否在垂直线
SpliteMoveIndex vRect = GetVectical(x, y, hitSpace);
if (vRect.IsIn())
return vRect; return SpliteMoveIndex.CreateNon(x, y);
} public bool PointInRect(int x,int y)
{
int startX = GetStartX();
int width = GetSpliteWidth();
if (x < startX || x > (startX + width))
return false; int startY = GetStartY();
int heght = GetSpliteTotalHeight();
if (y < startY || y > (startY + heght))
return false;
return true;
} public void ClearNotUsedRect()
{
_listSplitRectNotUsed.Clear();
} public bool GetRectIndex(int index,ref Rectangle outRect)
{
int i = ;
foreach (Rectangle rect in _listSplitRect)
{
if (i == index)
{
outRect = rect;
return true;
}
i++;
}
return false;
} public bool IsNotUsed(int x, int y)
{
Rectangle rect = new Rectangle();
foreach (int n in _listSplitRectNotUsed)
{
if (GetRectIndex(n, ref rect) && rect.Contains(x, y))
{
return true;
}
}
return false;
} public bool IsRectUsed(Rectangle rect)
{
Rectangle rectNot = new Rectangle();
foreach (int n in _listSplitRectNotUsed)
{
if (GetRectIndex(n, ref rectNot) && rectNot == rect)
{
return false;
}
}
return true;
} public bool IsRectUsed(int index)
{
foreach (int n in _listSplitRectNotUsed)
{
if (n == index)
return false;
}
return true;
} //区块加入切割
public bool AddRectUsed(int x,int y)
{
int i = ;
Rectangle rectNot = new Rectangle();
foreach (int n in _listSplitRectNotUsed)
{
if (GetRectIndex(n, ref rectNot) && rectNot.Contains(x,y))
{
_listSplitRectNotUsed.RemoveAt(i);
return true;
}
i++;
}
return false;
} //区块不加入切割
public bool DelRectUsed(int x, int y)
{
int i = ;
foreach (Rectangle rect in _listSplitRect)
{
if (rect.Contains(x, y))
{
_listSplitRectNotUsed.Add(i);
return true;
}
i++;
}
return false;
} public bool AddHorLine(int x, int y)
{
List<Rectangle> listSplitRectNew = new List<Rectangle>();
foreach (Rectangle rect in _listSplitRect)
{
if (y > rect.Y && y < rect.Y + rect.Height)
{
Rectangle r1 = new Rectangle(rect.Location, rect.Size);
r1.Height = y - rect.Y;
listSplitRectNew.Add(r1); r1.Y = y ;
r1.Height = (rect.Y + rect.Height - y);
listSplitRectNew.Add(r1);
}
else
{
listSplitRectNew.Add(rect);
}
}
_listSplitRect = listSplitRectNew;
return true;
} //删除水平线
public bool DeleteHorSplite(SpliteMoveIndex index)
{
List<Rectangle> listSplitRectNew = new List<Rectangle>();
int i = ;
bool del = false;
Rectangle lastRect = new Rectangle();
bool haveLast = false; foreach (Rectangle rect in _listSplitRect)
{
i++;
if(haveLast)
{
haveLast = false;
lastRect.Height += rect.Height;
listSplitRectNew.Add(lastRect);
continue;
} if(index.rectIndex == i)
{
del = true;
if (index.lineIndex == )
{
if(listSplitRectNew.Count == )
{
continue;
}
else
{
Rectangle r = listSplitRectNew.Last();
r.Height += rect.Height;
listSplitRectNew.RemoveAt(listSplitRectNew.Count-);
listSplitRectNew.Add(r);
}
}
else if (index.lineIndex == )
{
if(i == _listSplitRect.Count)
{
continue;
}
else
{
lastRect = rect;
haveLast = true;
}
}
else { Debug.Assert(false); }
}
else
{
listSplitRectNew.Add(rect);
}
} _listSplitRect = listSplitRectNew;
return del;
} public static int GetSplitSize(int widthSrc, int heightSrc, int startX, int startY,
int widthDest, int heightDest, ref List<Rectangle> listOut)
{
listOut = new List<Rectangle>(); int width = Math.Min(widthSrc - startX, widthDest); int i = ;
bool stop = false;
while (!stop)
{
Rectangle rect = new Rectangle(); rect.X = startX;
rect.Y = startY + (i * heightDest);
rect.Width = width;
rect.Height = heightDest;
if (rect.Y + rect.Height >= heightSrc)
{
stop = true;
rect.Height = heightSrc - rect.Y;
}
listOut.Add(rect);
i++;
}
return ;
}
}

图像快速切割

图像切割其实就是在一个内存中重新绘制,再将内存中的数据保存到文件。切割代码如下:

 。。。

技术交流联系qq 13712486

一个非常好用的图片切割工具(c# winform开发) 附源码的更多相关文章

  1. 一个非常好用的图片切割工具(c# winform开发)

    本人业余时间开发了一个图片切割工具,非常好用,也很灵活! 特别对大型图片切割,更能体现出该软件的优势! 功能说明 可以设定切割的高度和宽度.切割线可以上下拖动,可以增加一个切割区域,可设定某个区域不参 ...

  2. 文件夹管理工具(MVC+zTree+layer)(附源码)

    写在前 之前写了一篇关于 文件夹与文件的操作的文章  操作文件方法简单总结(File,Directory,StreamReader,StreamWrite )  把常用的对于文件与文件夹的操作总结了一 ...

  3. ShoeBox一个超级好用的图片切割工具

    下载地址:http://renderhjs.net/shoebox/ ShoeBox是一个图片处理软件,体积很小. 我主要用第三个功能拆开图片.根据大图上的小图空白间隙来处理的. 导出后变成很多小图

  4. cesium 之地图贴地量算工具效果篇(附源码下载)

    前言 cesium 官网的api文档介绍地址cesium官网api,里面详细的介绍 cesium 各个类的介绍,还有就是在线例子:cesium 官网在线例子,这个也是学习 cesium 的好素材. 内 ...

  5. 动手写一个Remoting接口测试工具(附源码下载)

    基于.NET开发分布式系统,经常用到Remoting技术.在测试驱动开发流行的今天,如果针对分布式系统中的每个Remoting接口的每个方法都要写详细的测试脚本,无疑非常浪费时间.所以,我想写一个能自 ...

  6. 使用 CSS3 实现 3D 图片滑块效果【附源码下载】

    使用 CSS3 的3D变换特性,我们可以通过让元素在三维空间中变换来实现一些新奇的效果. 这篇文章分享的这款 jQuery 立体图片滑块插件,利用了 3D transforms(变换)属性来实现多种不 ...

  7. wpf 模拟3D效果(和手机浏览图片效果相似)(附源码)

    原文 wpf 模拟3D效果(和手机浏览图片效果相似)(附源码) pf的3D是一个很有意思的东西,类似于ps的效果,类似于电影动画的效果,因为动画的效果,(对于3D基础的摄像机,光源,之类不介绍,对于依 ...

  8. 【转】.NET(C#):浅谈程序集清单资源和RESX资源 关于单元测试的思考--Asp.Net Core单元测试最佳实践 封装自己的dapper lambda扩展-设计篇 编写自己的dapper lambda扩展-使用篇 正确理解CAP定理 Quartz.NET的使用(附源码) 整理自己的.net工具库 GC的前世与今生 Visual Studio Package 插件开发之自动生

    [转].NET(C#):浅谈程序集清单资源和RESX资源   目录 程序集清单资源 RESX资源文件 使用ResourceReader和ResourceSet解析二进制资源文件 使用ResourceM ...

  9. (SSM框架)实现小程序图片上传(配小程序源码)

    阅读本文约"2分钟" 又是一个开源小组件啦! 因为刚好做到这个小功能,所以就整理了一下,针对微信小程序的图片(文件)上传! 原业务是针对用户反馈的图片上传.(没错,本次还提供小程序 ...

随机推荐

  1. SpringMVC 基本概念

    DispatcherServlet:前端控制器,解释用户请求,通过HandlerMapping查找对应Handler处理请求,调用ViewResolve回填页面,DispatcherServlet在W ...

  2. 使用selenium webdriver+beautifulsoup+跳转frame,实现模拟点击网页下一页按钮,抓取网页数据

    记录一次快速实现的python爬虫,想要抓取中财网数据引擎的新三板板块下面所有股票的公司档案,网址为http://data.cfi.cn/data_ndkA0A1934A1935A1986A1995. ...

  3. HDU1005 Number Sequence (奇技淫巧模拟)

    A number sequence is defined as follows: f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mo ...

  4. poj 2566 Bound Found

    Bound Found Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4384   Accepted: 1377   Spe ...

  5. Tomcat请求头过大

    今天开发反应Tomcat的请求头过大 <Connector port="8280" protocol="HTTP/1.1" connectionTimeo ...

  6. Problem C: 线性表的基本操作

    Description 线性表是一类重要的且基础的数据结构.请定义MyList类,来模拟针对线性表的插入.删除等操作: 1. 数据成员int *elements:线性表元素. 2. 数据成员int l ...

  7. Python通过跳板机链接MySQL的一种方法

  8. Java多线程Lock

    JDK5以后为代码的同步提供了更加灵活的Lock+Condition模式,并且一个Lock可以绑定多个Condition对象 1.把原来的使用synchronized修饰或者封装的代码块用lock.l ...

  9. .NET MVC 二级域名路由的实现

    .NET MVC 5以下版本: http://www.cnblogs.com/luanwey/archive/2009/08/12/1544444.html http://blog.maartenba ...

  10. C语言实现二叉树的基本操作

    二叉树是一种非常重要的数据结构.本文总结了二叉树的常见操作:二叉树的构建,查找,删除,二叉树的遍历(包括前序遍历.中序遍历.后序遍历.层次遍历),二叉搜索树的构造等. 1. 二叉树的构建 二叉树的基本 ...