水印能夠本身本身製做,也能夠用代碼寫。 數組
我這裏主要寫如何添加到照片上面。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了。