水印能够本身本身制做,也能够用代码写。 数组
我这里主要写如何添加到照片上面。app
UWP和WP8.1添加的方法同样。代码是通用的。dom
UWP和WP8.1没有像WPF和WINFROM中darw这样简便的API能够来用,可是能够提取字节,只好先肯定要添加的位置在直接输出字节中了。原本想把思路写在代码后面的。仍是写在前面吧。spa
具体的思路就是像在一个图形中【原图】求出阴影面积【水印】这样方法。3d
下图 宽800 高400code
黑图 高200 宽100orm
就像这样的图。blog
大图看做图片,小图看做水印。图片
图片的像素是四个字节组成的【普通来讲】对吧,也就是长宽的字节数分别是,800*4,400*4,这就是长宽的字节数。可是要算全面的总字节数则是 800*400*4=1280 000it
这一点多少有些区别。分开算是必须 请不要混了。水印图一样计算。
顺便说一下,字计数是一个一个铺开排列,一行正好是3200个,也就是800*4,总共有1600行,也就是400*4.,可是说3200*1600是总字节那就不对了。
简单来讲就是求每一行中水印的宽的所占原图的字节的数量,以后与水印的每一行所占的行数的字节相加。这里面相加的是字节的下标。而是不字节数所表示的数。
也就是求水印占原图的所有的字节的下标。以后将水印的字节按照刚才求得的下标依次输入到原图的字节中就能够了。
左上角来讲,水印的左上角占原图的左上角的字节下标就是0,水印的右上角占原图的字节下标就是400.正好就是水印的图的第一行的字节数。 由于是长方形也就是依次向下加就能够了。
难一点的就是左下角和右上角。 我这人也不会说仍是具体看代码把。
主要用到的是的API:
WriteableBitmap
BitmapDecoder
这两个,第一个方法用来重画照片。第二个方法用来提取照片的二维数组。
其次,咱们要了解照片的像素的。
下面是咱们看成水印的照片的
像素数据:
这个照片的像素是200*200*4是总结数据。 200*4是长宽的数据(长宽相等)。也就是像素*4等于字节数据。 像素相乘*4是总数据。 200*4*200*4这样子是错误的。
下面是咱们要看成原图的照片。
照片的数据:
总数据:580*410*4. 宽:580*4,高:410*4
OK,咱们先提取保存在程序中的照片,而且提取像素数据,以及字节数组
//打开原图 StorageFile imageFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///PB.png", UriKind.Absolute)); IRandomAccessStream accStream = await imageFile.OpenAsync(FileAccessMode.Read); //打开水印图 StorageFile Mfile=await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///s.jpg", UriKind.Absolute)); //转换流 IRandomAccessStream MiStream= await Mfile.OpenAsync(FileAccessMode.Read); //使用解码器 BitmapDecoder bd = await BitmapDecoder.CreateAsync(accStream); BitmapDecoder bd_Mi = await BitmapDecoder.CreateAsync(MiStream); //是否旋转或者缩小 BitmapTransform bt = new BitmapTransform(); ///获取数据 var imageData = await bd.GetPixelDataAsync(BitmapPixelFormat.Bgra8, bd.BitmapAlphaMode, bt, ExifOrientationMode.IgnoreExifOrientation, ColorManagementMode.DoNotColorManage); //获取二维数组 byte[] buffer = imageData.DetachPixelData(); //获取数据 var miData = await bd_Mi.GetPixelDataAsync(); //水印的字节数组 byte[] Mi_buffer = miData.DetachPixelData();
咱们先暂且不水印图作任何处理,200*200的叠在原图上面。主要表现如何叠在原图的操做。
咱们暂时把水印贴在左上角,右上角等地方。 咱们先看肯定左上角的代码
须要的数据,如下全部的角落都要用到的
//原图的高 int Pxh =(int) bd.PixelHeight; //原图的宽 int Pxw = (int)bd.PixelWidth; //原图的高的像素的第一层数据 int Pxh_Byte_H = Pxh * 4; //原图的宽的像素的第一层数据 int Pxw_Byte_W = Pxw * 4; // 水印的高 int Npxh = (int)bd_Mi.PixelHeight; // 水印的宽 int Npxw = (int)bd_Mi.PixelWidth; // 水印的高的像素的第一层数据 int Npxh_Byte_H = Npxh * 4; // 水印的宽的像素的第一层数据 int Npxw_Byte_W = Npxw * 4; //水印的总字节数 int Npx_Byte = Npxh * Npxw * 4; // 水印的像素总数据 int[] Npx_Byte_all = new int[Npx_Byte]; //水印的高的像素总数据 int[] Npx_Byte_all_H = new int[Npxh_Byte_H]; //循环小于水印宽度的数据的计数器 int Times = 0; //记录总数据的循环计数器 int ALL_Times = 0;
肯定左上角的代码:
{ //获取水印的高的像素的子节点在原图的高的像素的所在的点 for (int i = 0; i < Npx_Byte_all_H.Length; i++) { Npx_Byte_all_H[i] = (i * Pxw_Byte_W); } //获取到水印的高的像素的子节点在原图的高的像素的所在的点以后 //就像计算面积同样,计算水印的全部的点在原图上的点 for (int n = 0; n < Npx_Byte_all_H.Length; n++) { int nub = Npx_Byte_all_H[n]; Times = 0; //向前推动 //计算每个点 while (Times < Npxw_Byte_W) { if (ALL_Times < Npx_Byte_all.Length) { Npx_Byte_all[ALL_Times] = nub + Times; } Times++; ALL_Times++; } } //输出到原图上Npx_Byte_all中保存的是水印在原图上所对应的坐标点。 for (int m = 0; m < Npx_Byte_all.Length; m++) { if (m < Npx_Byte_all.Length - 1) { buffer[Npx_Byte_all[m]] = Mi_buffer[m]; } } }
肯定好位置后,咱们就要重绘图片。
//新建一个原图的WriteableBitmap。长宽和原图同样 WriteableBitmap writBitMap = new WriteableBitmap((int)bd.PixelWidth, (int)bd.PixelHeight); //利用 writBitMap.PixelBuffer.AsStream()的这个方法向其写入流 using (Stream stream = writBitMap.PixelBuffer.AsStream()) { await stream.WriteAsync(buffer, 0, buffer.Length); } //请求重绘图片 writBitMap.Invalidate(); //输出奥照片上 _iMAGE.Source = writBitMap;
结果就是
嗯...非常不和谐啊... 图片大小问题咱们稍后再说,主要说的添加水印不是?
OK,让咱们看看右上角的代码
//获取水印的高的像素的子节点在原图上的子节点 for (int i = 0; i < Npx_Byte_all_H.Length; i++) { Npx_Byte_all_H[i] = (i * Pxw_Byte_W); } //获取水印的高的像素的子节点在原图上的子节点以后,就是计算左上角同样计算,不过这一次是稍稍不一样 for (int n = 0; n < Npx_Byte_all_H.Length; n++) { //获取坐标点 int nub = Npx_Byte_all_H[n]; Times = 0; while (Times < Npxw_Byte_W) { if (ALL_Times < Npx_Byte_all.Length && nub > 0) { //肯定一行中最小的坐标点,而后加法到水印的宽。 int minNub = nub - Npxw_Byte_W; Npx_Byte_all[ALL_Times] = minNub + Times; } Times++; ALL_Times++; }
for (int m = 0; m < Npx_Byte_all.Length; m++) { if (m < Npx_Byte_all.Length) { buffer[Npx_Byte_all[m]] = Mi_buffer[m]; } }
效果如图
左下角的代码
//// 水印的最上的左上角的点的坐标 int L_Npxh = (Pxh - Npxh) * Pxw * 4; for (int i = 0; i < Npx_Byte_all_H.Length; i++) { Npx_Byte_all_H[i] = L_Npxh + (i * Pxw_Byte_W); } for (int n = 0; n < Npx_Byte_all_H.Length; n++) { int nub = Npx_Byte_all_H[n]; Times = 0; while (Times < Npxw_Byte_W) { if (ALL_Times < Npx_Byte_all.Length) { // int maxNub = nub - Pxw_Byte_W; Npx_Byte_all[ALL_Times] = nub + Times; } ALL_Times++; Times++; } } for (int m = 0; m < Npx_Byte_all.Length; m++) { if (m < Npx_Byte_all.Length) { buffer[Npx_Byte_all[m]] = Mi_buffer[m]; } }
效果图
右下角的代码
//水印的左上角在原图上的点 int R_Npxh = (Pxh - Npxh) * Pxw * 4; for(int i=0;i<Npx_Byte_all_H.Length;i++) { Npx_Byte_all_H[i] = R_Npxh + (i * Pxw_Byte_W); } for(int n=0;n<Npx_Byte_all_H.Length;n++) { int nub = Npx_Byte_all_H[n]; Times = 0; while (Times < Npxw_Byte_W) { if(ALL_Times<Npx_Byte_all.Length) { int minNub = nub +Pxw_Byte_W- Npxw_Byte_W; Npx_Byte_all[ALL_Times] = minNub + Times; } ALL_Times++; Times++; } } //输出到原图的字节数组中 for (int m = 0; m < Npx_Byte_all.Length; m++) { if (m < Npx_Byte_all.Length) { buffer[Npx_Byte_all[m]] = Mi_buffer[m]; } }
效果图
OK,到这里四个角的水印嵌入基本Ok了。