九宫格图片
如上图所示正常情况下九宫格绘制会遵循下面的规则:
a. 保持4个角部分不变形
c. 双向拉伸中间部分(即九宫格的中间部分,横向,纵向同时拉伸,PS:拉伸比例不一定相同)
那问题来了,如果我们手上有一张图片(上图 九宫格效果),怎么把它剪裁成九宫格原图,甚至是比原图还小的图片。
由上面的原则,理论上只要保证四个角不变形就弄,边界可以尽可能的切小(PS:前提图片内没有花纹或渐变色等图案)。
用PS是可以实现,不过比较麻烦,切掉四个角再拼接起来。
秉承不会偷懒的程序员不是好的程序员这个原则,做了这个小工具。
界面
以下是用Windows窗体制作的界面
中间两个大窗口是PictureBox,用来显示,原图和剪裁完后的效果图。
功能描述
- 打开,选择要剪裁的图片
- 剪裁,根据下面四个参数剪裁图片
- 保存,保存效果图到文件中
过程
新建工程
Visual Studio中新建一个Windows窗体,基于C#。
打开按钮
打开的功能其实很简单,用new一个OpenFileDialog选择张图片,得到这张图片的绝对路径就行了。
OpenFileDialog fileDialog = new OpenFileDialog(); fileDialog.Multiselect = true; fileDialog.Title = "请选择文件"; fileDialog.Filter = "图片(*.png)|*.png"; if (fileDialog.ShowDialog() == DialogResult.OK) { imagePath = fileDialog.FileName; Image image = Image.FromFile(imagePath); TargetPicture.Image = image; InfoLabel.Text = "size: " + image.Width + "*" + image.Height + " path:" + imagePath; }
剪裁图片
要图片进行剪裁,我们首先需要知道几个参数。
也有是我TextBox中的四个值(left,right,top,bottom)。
用一个结构体来保存四个参数
struct BorderConfig { public int left; public int right; public int top; public int bottom; public void Reset() { left = 0; right = 0; top = 0; bottom = 0; } } BorderConfig borderConfig;
知道了这四个参数就可以知道1、3、7、9的大小,把这四块从原图中切出来。
将这四块的信息存入一个数组中,其中每一块的包含了开始点(x, y)长宽(width, height)。
struct CaptureConfig { public int x; public int y; public int width; public int height; public CaptureConfig(int x, int y, int width, int height) { this.x = x; this.y = y; this.width = width; this.height = height; } }
CaptureConfig[] configs = { new CaptureConfig(0, 0, left, top), new CaptureConfig(fromImage.Width - right, 0, right, top), new CaptureConfig(0, fromImage.Height - bottom, left, bottom), new CaptureConfig(fromImage.Width - right, fromImage.Height - bottom, right, bottom) };
/// <summary> /// 剪裁图片 /// </summary> /// <param name="picPath">要剪裁图片完整路径</param> /// <param name="x">剪裁起点x坐标</param> /// <param name="y">剪裁起点y坐标</param> /// <param name="width">剪裁宽度</param> /// <param name="height">剪裁高度</param> /// <returns></returns> Bitmap CaptureImage(String picPath, int x, int y, int width, int height) { if (width <= 0 || height <= 0) return null; //定义截取矩形 Rectangle cropArea = new Rectangle(x, y, width, height); //定义Bitmap对象, 加载图片 Bitmap srcMap = new Bitmap(picPath); //判断超出的位置否 if ((srcMap.Width < x + width) || srcMap.Height < y + height) { MessageBox.Show("裁剪尺寸超出原有尺寸!"); srcMap.Dispose(); return null; } //进行裁剪 Bitmap capMap = srcMap.Clone(cropArea, srcMap.PixelFormat); //释放对象 srcMap.Dispose(); return capMap; }
CaptureImage中,通过图片的路径加载图片,再通过每个块的剪裁数据,用Bitmap.Clone保存这块距形数据到新的Bitmap中
这些有取到了四块剪裁完的Bitmap。
合并图片
取到四个边角后,我们要做的就是把这个四角的合并成一张完整图片输入。
具体的方法就是用Graphics新建一个作图区域,把四个角的画上去。
//创建新图位图 Bitmap bitmap = new Bitmap(width, height); //创建作图区域 Graphics graphic = Graphics.FromImage(bitmap); //清除整个绘图面并以透明背景色填充 graphic.Clear(Color.Transparent); //截取原图相应区域写入作图区 foreach (CaptureConfig config in configs) { Bitmap capMap = CaptureImage(imagePath, config.x, config.y, config.width, config.height); if (capMap != null) { graphic.DrawImage(capMap, config.x == 0 ? 0 : left, config.y == 0 ? 0 : top, config.width, config.height); capMap.Dispose(); } }
绘制预览剪裁边
//定义Bitmap对象, 加载图片 Bitmap bitMap = new Bitmap(imagePath); Pen pen = new Pen(Color.Green, 1); Graphics g = Graphics.FromImage(bitMap); g.DrawLine(pen, new Point(borderConfig.left, 0), new Point(borderConfig.left, bitMap.Height)); g.DrawLine(pen, new Point(bitMap.Width - borderConfig.right, 0), new Point(bitMap.Width - borderConfig.right, bitMap.Height)); g.DrawLine(pen, new Point(0, borderConfig.top), new Point(bitMap.Width, borderConfig.top)); g.DrawLine(pen, new Point(0, bitMap.Height - borderConfig.bottom), new Point(bitMap.Width, bitMap.Height - borderConfig.bottom)); TargetPicture.Image = bitMap; TargetPicture.Refresh();
最终效果图