程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> LockBits使用筆記,lockbits筆記

LockBits使用筆記,lockbits筆記

編輯:C#入門知識

LockBits使用筆記,lockbits筆記


昨天想基於一張圖片做個手機鎖屏來著,原圖如下:
1 unsafe class BitmapWrapper 2 { 3 private readonly Bitmap bmp; 4 private readonly BitmapData bmpData; 5 6 private readonly byte* scan0; 7 private readonly int byteCount; 8 9 public BitmapWrapper(Bitmap bitmap) 10 { 11 bmp = bitmap; 12 bmpData = bmp.LockBits( 13 new Rectangle(0, 0, bmp.Width, bmp.Height), 14 ImageLockMode.ReadWrite, 15 bmp.PixelFormat); 16 17 scan0 = (byte*) bmpData.Scan0; 18 // byteCount = bmpData.Stride / bmpData.Width; 19 byteCount = bmpData.PixelFormat.ToString().IndexOf("32") > 0 ? 4 : 3; 20 } 21 public Bitmap UnWrapper() 22 { 23 bmp.UnlockBits(bmpData); 24 return bmp; 25 } 26 public void SetPixel(Point point, Color color) 27 { 28 int offset = (point.X - 1) * byteCount + (point.Y - 1) * bmpData.Stride; 29 scan0[offset] = color.B; 30 scan0[offset + 1] = color.G; 31 scan0[offset + 2] = color.R; 32 if (byteCount == 4) 33 scan0[offset + 3] = color.A; 34 } 35 public Color GetPixel(Point point) 36 { 37 int offset = (point.X - 1) * byteCount + (point.Y - 1) * bmpData.Stride; 38 Color color = Color.FromArgb( 39 scan0[offset + 2], 40 scan0[offset + 1], 41 scan0[offset] 42 ); 43 if (byteCount == 4) 44 color = Color.FromArgb(scan0[offset + 3], color); 45 return color; 46 } 47 }



注意代碼裡頭有一句注掉了,那裡是我出現第一個問題的地方。。。
本來是想計算每一像素占的字節數,那就拿每行的字節數除每一行的像素數咯,於是就錯了。。。
MSDN查BitmapData.Stride可以看到備注裡面的一句話:

跨距是單行像素(一個掃描行)的寬度,捨入為一個 4 字節的邊界。

所以跨距其實應該是等於這樣的:Stride = byteCount * Width + ((byteCount * Width) % 4) == 0 ? 0 : (4 - (byteCount * Width) % 4)
於是不知道該怎麼反解byteCount,所以用了19行的那個方法,暫時忽略其他情況吧。。。


第二個問題是發生在存取RGB三個byte值的時候。
因為每個像素的RGB三個值是從高位到低位放置的,所以SetPixel裡面應該是這樣:

scan0[offset] = color.B;
scan0[offset + 1] = color.G;
scan0[offset + 2] = color.R;

而不是這樣:

scan0[offset] = color.R;
scan0[offset + 1] = color.G;
scan0[offset + 2] = color.B;



第三個問題發生在保存圖片的時候。。。本來是這麼寫的:

bmp.Save("Juven.bmp");

打開圖片再用油漆桶,發現還是和原來差不多,底色裡面仍然參雜了高度接近純白的灰色斑點。
因為Save不管你文件擴展名是什麼的啊!通通默認Jpeg啊!一壓縮就前功盡棄了!所以應該改成這樣:

bmp.Save(@"Juven.bmp", ImageFormat.Bmp);

這樣就對了,油漆桶後的效果如下(上傳前轉回jpg了,所以這張圖的底色其實還是不純的):
1 Bitmap bmp = new Bitmap(src); 2 BitmapWrapper wrapper = new BitmapWrapper(bmp); 3 4 byte r, g, b; 5 for (int y = 1; y <= bmp.Height; y++) 6 { 7 for (int x = 1; x <= bmp.Width; x++) 8 { 9 Point point = new Point(x, y); 10 Color cr = wrapper.GetPixel(point); 11 if (cr.R + cr.G + cr.B >= 30) 12 { 13 if (x < 200) 14 { 15 r = 34; 16 g = 177; 17 b = 76; 18 } 19 else if (x > 395) 20 { 21 r = 237; 22 g = 28; 23 b = 36; 24 } 25 else 26 r = g = b = 255; 27 wrapper.SetPixel(point, Color.FromArgb(r, g, b)); 28 } 29 else break; 30 } 31 32 for (int x = bmp.Width; x > 0; x--) 33 { 34 Point point = new Point(x, y); 35 Color cr = wrapper.GetPixel(point); 36 if (cr.R + cr.G + cr.B >= 30) 37 { 38 if (x < 200) 39 { 40 r = 34; 41 g = 177; 42 b = 76; 43 } 44 else if (x > 400) 45 { 46 r = 237; 47 g = 28; 48 b = 36; 49 } 50 else 51 r = g = b = 255; 52 wrapper.SetPixel(point, Color.FromArgb(r, g, b)); 53 } 54 else break; 55 } 56 }
57 wrapper.UnWrapper(); 58 bmp.Save(target);

成品圖如下:




最後想說的是,巴薩梅球王求輕虐十個以內啊!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved