某天参加微软编程马拉松,我们做的是Jigsaw拼图小游戏,有一个功能是让玩家选择图片,然后应用将其剪裁成3*3的小块进行拼图游戏。剪裁的效果用Image.Clip实现不了,
<Image.Clip >
<RectangleGeometry Rect="x1 y1 width height"/>`
</Image.Clip>
Image.Clip中:
<RectangleGeometry Rect=”x1 y1 width height”/>
参数x1 y1代表以当前控件左上顶点为坐标原点,显示区域左上顶点的坐标,width height则是显示区域的宽和高。所以用:
<RectangleGeometry Rect=”233 233 233 233″/>
从大图中截取中间部分便会出现:
未达到效果
显然没有达到效果,于是就采用对图片像素点的处理达到截图效果
涉及要点:
WriteableBitmap可写的位图
StorageFile 文件
IRandomAccessStream 可随机访问输入和输出流
在WriteableBitmap中图像的每个像素点是采用RGBA色彩模式(不知道是不是这样叫的)储存的,是通过对红(R)、绿(G)、蓝(B)三个颜色分量和Alpha的色彩空间(用来控制透明度)的变化以及它们相互之间的叠加来得到各式各样的颜色的。一个像素点占四个字节,四个字节依次代表蓝、绿、红、透明度。每个分量0~255范围内的强度值,对于透明度0代表全透明,255代表不透明。
具体操作见代码:
const int BigImgWidth = 699, BigImgLenth = 699;
const int SmallImgWidth = 233, SmallLenth = 233;
//定义可写的位图,参数为宽和长
WriteableBitmap bigbitmap = new WriteableBitmap(BigImgWideth, BigImgLenth);
WriteableBitmap smallbitmap = new WriteableBitmap(SmallImgWidth, SmallImgLenth);
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/123.jpg"));//定义文件并打开123.jpg
IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);//定义文件流
await bigbitmap.SetSourceAsync(fileStream);//给大图赋值
Stream str = bigbitmap.PixelBuffer.AsStream();
//将大图转化为流,这是将大图转化为byte[]数组的中间步骤
byte[] bigpixels = new byte[str.Length]; //将stream转成byte[]
str.Read(bigpixels, 0, bigpixels.Length);
byte[] smallpixels = new byte[4 * smallbitmap.PixelWidth * smallbitmap.PixelHeight]; //定义小图的位数组的大小,4 * 宽 *长,单位是像素(Pixel)
const int startx = 233, starty = 233; //截图区域左上角点的坐标(按理说应该把截图写成函数,把startx,starty,以及小图的长宽以实参的形式传进来的)
for (int y = 0; y < smallbitmap.PixelHeight; y++)
for (int x = 0; x < smallbitmap.PixelWidth; x++)
{
//核心代码就下面两句,将sindex和index为小图和大图转化成位数组(一维数组)的下标
int sindex = 4 * (y * smallbitmap.PixelWidth + x);
int index = 4 * ((starty + y) * bigbitmap.PixelWidth + x + startx);
smallpixels[sindex + 0] = bigpixels[index + 0];
//复制蓝色分量的值
smallpixels[sindex + 1] = bigpixels[index + 1];
//复制绿色分量的值
smallpixels[sindex + 2] = bigpixels[index + 2];//复制红色分量
smallpixels[sindex + 3] = bigpixels[index + 3];//复制透明度分量
}
Stream pixelStream = smallbitmap.PixelBuffer.AsStream();
await pixelStream.WriteAsync(smallpixels, 0, smallpixels.Length);
smallbitmap.Invalidate();//重新绘制整个位图
img2.Source = smallbitmap;//将控件img2的源设为smallbitmap
}
可以看到实现了想截哪块就截哪块的功能了。