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

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

功能说明

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

主要技术点分析

切割区域确定

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

 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. (小数化分数)小数化分数2 -- HDU --1717

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=1717 举例: 0.24333333…………=(243-24)/900=73/3000.9545454…… ...

  2. _variant_t与其他数据类型的转换

    转自:http://kuaixingdong.blog.hexun.com/29627840_d.html 我们先看看COM所支持的一些类型的基本类: (微软提供,在comdef.h中定义) 在COM ...

  3. 一个CTO谈自己的技术架构体系

    理解算法背后的世界观 我比较擅长的领域可能是数据和架构两个方面吧. 大数据方面就是数据挖掘.数据分析等领域,我现在带着极光推送整个的数据团队,需要把握数据团队的技术方向,还需要做很多算法方面的研究. ...

  4. 结对编程-四则运算生成器(java实现)

     结对伙伴:陈振华  项目要求 1.题目:实现一个自动生成小学四则运算题目的命令行程序. 2.需求: 1. 使用 -n 参数控制生成题目的个数 2. 使用 -r 参数控制题目中数值(自然数.真分数和真 ...

  5. Java-网络编程之-Internet地址

    在网络编程中,比较重要的部分,就是关于Internet地址的知识理解 连接到Internet的设备我们成为节点(node),而计算机节点我们称为主机(host),要记住每个node或者host,至少一 ...

  6. 如何在Windows应用商店中提交您的Windows 8.1 应用更新

    翘首以盼的Windows 8.1 不负众望的与大家见面了,与此同时也带来了全新的应用商店,小伙伴儿们要赶紧升级系统啦! 今天给大家介绍下如何提交一个Windows 8.1 的应用,其实微软针对这次系统 ...

  7. Thread in depth 2:Asynchronization and Task

    When we want to do a work asynchronously, creating a new thread is a good way. .NET provides two oth ...

  8. Spring Boot 应用系列 3 -- Spring Boot 2 整合MyBatis和Druid,多数据源

    本文演示多数据源(MySQL+SQL Server)的配置,并且我引入了分页插件pagehelper. 1. 项目结构 (1)db.properties存储数据源和连接池配置. (2)两个数据源的ma ...

  9. MVC4 项目开发日志(1)

    最近一直在定义一个功能全面,层次结构分明的框架.一边学习一边应用.

  10. 设计模式之单件模式(Singleton Pattern)

    一.单件模式是什么? 单件模式也被称为单例模式,它的作用说白了就是为了确保“该类的实例只有一个” 单件模式经常被用来管理资源敏感的对象,比如:数据库连接对象.注册表对象.线程池对象等等,这种对象如果同 ...