需要引用 System.Drawing.dll
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
//预乘Alpha public static void PremultiplyAlpha(string filePath) { if (!File.Exists(filePath) || !filePath.EndsWith(".png")) return; FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); byte[] bytes = new byte[fs.Length]; fs.Read(bytes, 0, bytes.Length); fs.Close(); Stream stream = null; try { stream = new MemoryStream(bytes); stream.Seek(0, SeekOrigin.Begin); Bitmap bmp = new Bitmap(stream); for (int y = 0; y < bmp.Height; y++) { for (int x = 0; x < bmp.Width; x++) { Color c = bmp.GetPixel(x, y); //公式 float alpha = (float)c.A / 255f; int A = c.A; int R = (int)(c.R * alpha); int G = (int)(c.G * alpha); int B = (int)(c.B * alpha); c = Color.FromArgb(A, R, G, B); bmp.SetPixel(x, y, c); } } bmp.Save(filePath); bmp.Dispose(); bmp = null; } catch(ArgumentException ex) { //stream不是图片或为空时引发此异常 Console.WriteLine("\r\n{0};{1}", ex.Message, filePath); } finally { stream.Close(); stream = null; bytes = null; GC.Collect(); } } //快速-预乘Alpha,采用内存拷贝 public static void FastPremultiplyAlpha(string filePath) { if (!File.Exists(filePath) || !filePath.EndsWith(".png")) return; FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); byte[] bytes = new byte[fs.Length]; fs.Read(bytes, 0, bytes.Length); fs.Close(); Stream stream = null; try { stream = new MemoryStream(bytes); stream.Seek(0, SeekOrigin.Begin); Bitmap bmp = new Bitmap(stream); Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat); //图片第1个像素的内存地址 IntPtr ptr = bmpData.Scan0; //两种计算方式 int byteSize = bmp.Width * bmp.Height * 4; //int byteSize = Math.Abs(bmpData.Stride) * bmp.Height; byte[] rgbaValues = new byte[byteSize]; //内存拷贝, 颜色分量排列顺序要根据 PixelFormat 判断 Marshal.Copy(ptr, rgbaValues, 0, byteSize); for (int i=0; i<rgbaValues.Length; i+=4) { //公式 RGBA float a = (float)rgbaValues[i+3] / 255f; rgbaValues[i] = (byte)(rgbaValues[i] * a); rgbaValues[i+1] = (byte)(rgbaValues[i+1] * a); rgbaValues[i+2] = (byte)(rgbaValues[i+2] * a); } Marshal.Copy(rgbaValues, 0, ptr, byteSize); bmp.UnlockBits(bmpData); bmp.Save(filePath); bmp.Dispose(); bmp = null; bmpData = null; rgbaValues = null; } catch (ArgumentException ex) { //stream不是图片或为空时引发此异常 Console.WriteLine("\r\n{0};{1}", ex.Message, filePath); } finally { stream.Close(); stream = null; bytes = null; GC.Collect(); } } //超快速-预乘Alpha,采用指针直接修改内存数据 public static void FastestPremultiplyAlpha(string filePath) { if (!File.Exists(filePath) || !filePath.EndsWith(".png")) return; FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); byte[] bytes = new byte[fs.Length]; fs.Read(bytes, 0, bytes.Length); fs.Close(); Stream stream = null; try { stream = new MemoryStream(bytes); stream.Seek(0, SeekOrigin.Begin); Bitmap bmp = new Bitmap(stream); Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); //以读写方式销定位图 BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat); //需要勾选上 [属性]->[生成]->允许不安全代码 unsafe { //图片第1个像素的内存地址 byte* ptr = (byte*)bmpData.Scan0; for (int i=0; i<bmpData.Height; i++) { for (int j=0; j<bmpData.Width; j++) { float a = ptr[3] / 255f; ptr[2] = (byte)(ptr[2] * a); ptr[1] = (byte)(ptr[1] * a); ptr[0] = (byte)(ptr[0] * a); ptr += 4; } //跳过空白内存块 ptr += bmpData.Stride - bmpData.Width * 4; } } //解锁位图 bmp.UnlockBits(bmpData); bmp.Save(filePath); bmp.Dispose(); bmp = null; bmpData = null; } catch (ArgumentException ex) { //stream不是图片或为空时引发此异常 Console.WriteLine("\r\n{0};{1}", ex.Message, filePath); } finally { stream.Close(); stream = null; bytes = null; GC.Collect(); } }