预乘Alpha

作者:追风剑情 发布于:2022-2-17 17:25 分类:C#

需要引用 System.Drawing.dll
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;


  1. //预乘Alpha
  2. public static void PremultiplyAlpha(string filePath)
  3. {
  4. if (!File.Exists(filePath) || !filePath.EndsWith(".png"))
  5. return;
  6.  
  7. FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
  8. byte[] bytes = new byte[fs.Length];
  9. fs.Read(bytes, 0, bytes.Length);
  10. fs.Close();
  11.  
  12. Stream stream = null;
  13. try
  14. {
  15. stream = new MemoryStream(bytes);
  16. stream.Seek(0, SeekOrigin.Begin);
  17. Bitmap bmp = new Bitmap(stream);
  18.  
  19. for (int y = 0; y < bmp.Height; y++)
  20. {
  21. for (int x = 0; x < bmp.Width; x++)
  22. {
  23. Color c = bmp.GetPixel(x, y);
  24. //公式
  25. float alpha = (float)c.A / 255f;
  26. int A = c.A;
  27. int R = (int)(c.R * alpha);
  28. int G = (int)(c.G * alpha);
  29. int B = (int)(c.B * alpha);
  30.  
  31. c = Color.FromArgb(A, R, G, B);
  32. bmp.SetPixel(x, y, c);
  33. }
  34. }
  35. bmp.Save(filePath);
  36. bmp.Dispose();
  37. bmp = null;
  38. }
  39. catch(ArgumentException ex)
  40. {
  41. //stream不是图片或为空时引发此异常
  42. Console.WriteLine("\r\n{0};{1}", ex.Message, filePath);
  43. }
  44. finally
  45. {
  46. stream.Close();
  47. stream = null;
  48. bytes = null;
  49. GC.Collect();
  50. }
  51. }
  52.  
  53. //快速-预乘Alpha,采用内存拷贝
  54. public static void FastPremultiplyAlpha(string filePath)
  55. {
  56. if (!File.Exists(filePath) || !filePath.EndsWith(".png"))
  57. return;
  58.  
  59. FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
  60. byte[] bytes = new byte[fs.Length];
  61. fs.Read(bytes, 0, bytes.Length);
  62. fs.Close();
  63.  
  64. Stream stream = null;
  65. try
  66. {
  67. stream = new MemoryStream(bytes);
  68. stream.Seek(0, SeekOrigin.Begin);
  69. Bitmap bmp = new Bitmap(stream);
  70. Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
  71. BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);
  72. //图片第1个像素的内存地址
  73. IntPtr ptr = bmpData.Scan0;
  74. //两种计算方式
  75. int byteSize = bmp.Width * bmp.Height * 4;
  76. //int byteSize = Math.Abs(bmpData.Stride) * bmp.Height;
  77. byte[] rgbaValues = new byte[byteSize];
  78. //内存拷贝, 颜色分量排列顺序要根据 PixelFormat 判断
  79. Marshal.Copy(ptr, rgbaValues, 0, byteSize);
  80. for (int i=0; i<rgbaValues.Length; i+=4)
  81. {
  82. //公式 RGBA
  83. float a = (float)rgbaValues[i+3] / 255f;
  84. rgbaValues[i] = (byte)(rgbaValues[i] * a);
  85. rgbaValues[i+1] = (byte)(rgbaValues[i+1] * a);
  86. rgbaValues[i+2] = (byte)(rgbaValues[i+2] * a);
  87. }
  88. Marshal.Copy(rgbaValues, 0, ptr, byteSize);
  89. bmp.UnlockBits(bmpData);
  90.  
  91. bmp.Save(filePath);
  92. bmp.Dispose();
  93. bmp = null;
  94. bmpData = null;
  95. rgbaValues = null;
  96. }
  97. catch (ArgumentException ex)
  98. {
  99. //stream不是图片或为空时引发此异常
  100. Console.WriteLine("\r\n{0};{1}", ex.Message, filePath);
  101. }
  102. finally
  103. {
  104. stream.Close();
  105. stream = null;
  106. bytes = null;
  107. GC.Collect();
  108. }
  109. }
  110.  
  111. //超快速-预乘Alpha,采用指针直接修改内存数据
  112. public static void FastestPremultiplyAlpha(string filePath)
  113. {
  114. if (!File.Exists(filePath) || !filePath.EndsWith(".png"))
  115. return;
  116.  
  117. FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
  118. byte[] bytes = new byte[fs.Length];
  119. fs.Read(bytes, 0, bytes.Length);
  120. fs.Close();
  121.  
  122. Stream stream = null;
  123. try
  124. {
  125. stream = new MemoryStream(bytes);
  126. stream.Seek(0, SeekOrigin.Begin);
  127. Bitmap bmp = new Bitmap(stream);
  128. Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
  129. //以读写方式销定位图
  130. BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);
  131. //需要勾选上 [属性]->[生成]->允许不安全代码
  132. unsafe
  133. {
  134. //图片第1个像素的内存地址
  135. byte* ptr = (byte*)bmpData.Scan0;
  136. for (int i=0; i<bmpData.Height; i++)
  137. {
  138. for (int j=0; j<bmpData.Width; j++)
  139. {
  140. float a = ptr[3] / 255f;
  141. ptr[2] = (byte)(ptr[2] * a);
  142. ptr[1] = (byte)(ptr[1] * a);
  143. ptr[0] = (byte)(ptr[0] * a);
  144. ptr += 4;
  145. }
  146. //跳过空白内存块
  147. ptr += bmpData.Stride - bmpData.Width * 4;
  148. }
  149. }
  150. //解锁位图
  151. bmp.UnlockBits(bmpData);
  152.  
  153. bmp.Save(filePath);
  154. bmp.Dispose();
  155. bmp = null;
  156. bmpData = null;
  157. }
  158. catch (ArgumentException ex)
  159. {
  160. //stream不是图片或为空时引发此异常
  161. Console.WriteLine("\r\n{0};{1}", ex.Message, filePath);
  162. }
  163. finally
  164. {
  165. stream.Close();
  166. stream = null;
  167. bytes = null;
  168. GC.Collect();
  169. }
  170. }


标签: C#

Powered by emlog  蜀ICP备18021003号-1   sitemap

川公网安备 51019002001593号