需要引用 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();
}
}