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

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

功能说明

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

主要技术点分析

切割区域确定

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

 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开发) 附源码

    本人业余时间开发了一个图片切割工具,非常好用,也很灵活! 特别对大型图片切割,更能体现出该软件的优势! 开发工具为winform,源码下载地址:http://download.csdn.net/dow ...

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

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

  3. 一个web图片热点生成工具(winform开发) 附源码

    给图片加热点是web开发中经常用到的一个功能.这方面的工具也不少. 为了更好的满足自己的需求,写了一个winform程序. 可以方便的给图片加热点,更方便灵活! 源码下载 http://downloa ...

  4. 图片切割工具---产生多个div切割图片 采用for和一的二维阵列设置背景位置

    照片库 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGlhb21vZ2c=/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...

  5. 网络请求以及网络请求下载图片的工具类 android开发java工具类

    package cc.jiusan.www.utils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; ...

  6. Android中将一个图片切割成多个图片

    有种场景,我们想将一个图片切割成多个图片.比如我们在开发一个拼图的游戏,就首先要对图片进行切割. 以下是封装好的两个类,可以实现图片的切割.仅供参考和学习. 一个是ImagePiece类,此类保存了一 ...

  7. Android中将一个图片切割成多个图片[转]

    有种场景,我们想将一个图片切割成多个图片.比如我们在开发一个拼图的游戏,就首先要对图片进行切割. 以下是封装好的两个类,可以实现图片的切割.仅供参考和学习. 一个是ImagePiece类,此类保存了一 ...

  8. 转: ImageMagick 命令行的图片处理工具(客户端与服务器均可用)

    http://www.imagemagick.com.cn/ 关于ImageMagick ImageMagick (TM) 是一个免费的创建.编辑.合成图片的软件.它可以读取.转换.写入多种格式的图片 ...

  9. Java操作图片的工具类

    操作图片的工具类: import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Font; import java.a ...

随机推荐

  1. tar、7z(7zip)压缩/解压缩指令的使用

    本文介绍tar.7z指令的使用方法 tar指令 在Linux中,使用的最多的压缩/解压缩指令就是tar指令了. tar指令用来将多个文件/目录结构打包.在实际使用中,往往使用tar对压缩的支持,即同时 ...

  2. CodeForces - 589J —(DFS)

    Masha has recently bought a cleaner robot, it can clean a floor without anybody's assistance. Schema ...

  3. mongodb 两小时入门

    传统的计算机应用大多使用关系型数据库来存储数据,比如大家可能熟悉的MySql, Sqlite等等,它的特点是数据以表格(table)的形式储存起来的.数据库由一张张排列整齐的表格构成,就好像一个Exc ...

  4. 软件工程作业 - 实现WC功能(java)

    项目地址:https://github.com/yogurt1998/WordCount 要求 基本要求 -c 统计文件字符数(实现) -w 统计文件单词数(实现) -l 统计文件行数(实现) 扩展功 ...

  5. 将Heap RID转换成RID格式

    使用DBCC PAGE命令查看索引叶子层中的索引键(最后一个参数为3才会显示索引键对应的HEAP RID)时,可以使用下面的SQL将HEAP RID转换成 FileId:PageId:SlotNo的格 ...

  6. MySQLdb & pymsql

    python有两个模块可以连接和操作mysql数据库,分别是MySQLdb和pymysql,python3建议使用pymysql MySQLdb安装 pip install mysql-python ...

  7. Cookie操作-----Selenium快速入门(十一)

    什么是cookie?顾名思义,就是饼干,小甜饼.而根据读音则是“曲奇”的意思,相信不少的人都吃过.而在网络上,cookie是指浏览器在本地的一种少量数据的存储方式.例如,我们常见的,登陆的时候有个ch ...

  8. 服务端JSON内容中有富文本时

    问题背景 由于数据中存在复杂的富文本,包含各种引号和特殊字符,导致后端和前端通过JSON格式进行数据交互引发前端JSON解析出错. 解决方案 后端将富文本内容 ConvertToBase64Strin ...

  9. 基于Easyui框架的datagrid绑定数据,新增,修改,删除方法(四)

    @{ ViewBag.Title = "xxlist"; } <script type="text/javascript" language=" ...

  10. SSE sqrt还是比C math库的sqrtf快了不少

    #include <stdio.h> #include <xmmintrin.h> #define NOMINMAX #include <windows.h> #i ...