前言
最近碰到一个需要将图片由原始的PNG转化为JPG的需求,由于PNG图片本身质量等原因,导致转化为JPG之后,存在失真的问题,后来一个同事分享了下述的HighQualityPNGToJPG方法解决PNG转JPG失真的问题。
1、准备
using System.Drawing;using System.Net;using System.Drawing.Imaging;////// 常见图片格式枚举/// public enum ImageFormatenmu{ jpg, gif, bmp, png}
2、给透明PNG图片添加白色底图
////// 透明PNG图片添加白色底图/// /// Png文件路径/// 新Png文件保存路径///public static void AddBlankBaseMap(string pngFilePath, string savePngFilePath){ Bitmap bitmap = new Bitmap(pngFilePath); int w = bitmap.Width; int h = bitmap.Height; Bitmap dstBitmap = new Bitmap(bitmap.Width, bitmap.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); System.Drawing.Imaging.BitmapData srcData = bitmap.LockBits(new Rectangle(0, 0, w, h), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); System.Drawing.Imaging.BitmapData dstData = dstBitmap.LockBits(new Rectangle(0, 0, w, h), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); //不安全代码,编译时需将项目生成操作中添加【允许不安全代码】 unsafe { byte* pIn = (byte*)srcData.Scan0.ToPointer(); byte* pOut = (byte*)dstData.Scan0.ToPointer(); byte* p; int stride = srcData.Stride; int r, g, b, a; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { p = pIn; b = pIn[0]; g = pIn[1]; r = pIn[2]; a = pIn[3]; if (a == 0) { pOut[1] = (byte)255; pOut[2] = (byte)255; pOut[3] = (byte)255; pOut[0] = (byte)255; } else { pOut[1] = (byte)g; pOut[2] = (byte)r; pOut[3] = (byte)a; pOut[0] = (byte)b; } pIn += 4; pOut += 4; } pIn += srcData.Stride - w * 4; pOut += srcData.Stride - w * 4; } bitmap.UnlockBits(srcData); dstBitmap.UnlockBits(dstData); //也可以再这里讲dstBitmap转化为其他类型,如转gif:bitmap.Save(saveFilePath, ImageFormat.Gif) dstBitmap.Save(savePngFilePath); }}
3、根据图片url保存图片
////// 根据图片url保存图片/// /// url地址/// 保存本地路径【含文件名,注意扩展名要和url对应文件本身一样,否则可能出错】public static void GetImageByURL(String url, String savePath){ WebClient webClient = new WebClient(); webClient.DownloadFile(url, savePath);}
4、普通PNG格式转换
////// 普通PNG格式转换/// /// png文件路径/// 保存文件路径/// 转化格式public static void GeneralPngChange(String pngFilePath,String saveFilePath,ImageFormatenmu imageFromat){ Bitmap bitmap = new Bitmap(pngFilePath); switch (imageFromat) { case ImageFormatenmu.bmp: { bitmap.Save(saveFilePath, ImageFormat.Bmp); }; break; case ImageFormatenmu.gif: { bitmap.Save(saveFilePath, ImageFormat.Gif); }; break; case ImageFormatenmu.jpg: { bitmap.Save(saveFilePath, ImageFormat.Jpeg); }; break; }}
5、PNG转JPG一般操作方法,可设置图片质量
////// PNG转JPG一般操作方法,可设置图片质量/// /// png文件路径/// jpg文件路径/// 图片质量>0public static void GeneralPngToJpg(String pngFilePath, String saveFilePath, long percentage){ Bitmap bmp1 = new Bitmap(pngFilePath); ImageCodecInfo jgpEncoder = GetEncoder(ImageFormat.Jpeg); System.Drawing.Imaging.Encoder myEncoder =System.Drawing.Imaging.Encoder.Quality; EncoderParameters myEncoderParameters = new EncoderParameters(1); EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, percentage); myEncoderParameters.Param[0] = myEncoderParameter; bmp1.Save(saveFilePath, jgpEncoder, myEncoderParameters);}////// 获取图片编码信息/// /// 图片格式MIME类型///private static ImageCodecInfo GetEncoder(ImageFormat format){ ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders(); foreach (ImageCodecInfo codec in codecs) { if (codec.FormatID == format.Guid) { return codec; } } return null;}
6、高保真PNG转JPG,解决部分PNG转JPG过程中图像失真的问题
////// 高保真PNG转JPG,解决部分PNG转JPG过程中图像失真的问题/// 例如:本人将一张透明的PNG转JPG后,JEP图片失真/// /// png文件路径/// jpg文件路径public static void HighQualityPNGToJPG(String pngFilePath, String jpgFilePath){ Image pngImg = Image.FromFile(pngFilePath); var width = pngImg.Width; var height = pngImg.Height; Image bitmap = new System.Drawing.Bitmap(width, height); Graphics g = System.Drawing.Graphics.FromImage(bitmap); //设置高质量插值法 g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.Clear(Color.White); //在指定位置并且按指定大小绘制原图片的指定部分 g.DrawImage(pngImg, new Rectangle(0, 0, width, height), new Rectangle(0, 0, width, height), GraphicsUnit.Pixel); bitmap.Save(jpgFilePath, System.Drawing.Imaging.ImageFormat.Jpeg); bitmap.Dispose(); g.Dispose();}}
我遇到将一个透明的PNG或一个质量较低的PNG用上述方法转JPG出现失真的问题。
例如:
使用GeneralPngToJpg方法将png图转jpg,透明底图PNG转换情况如下:
图表 1 透明底图PNG
图表 2透明底图PNG转化后的JPG图片【较严重失真】
非透明底图PNG转换情况如下:
图表 3非透明底图PNG
图表 4 非透明底图PNG转JPG【较严重失真】
HighQualityPNGToJPG分别转化透明及非透明低图的PNG,结果如下:
图表 5 非透明底图的PNG格式转化后的JPG
图表 6 透明底图的PNG格式转化后的JPG
7、测试代码
String imageDirectory = string.Format("{0}image/",AppDomain.CurrentDomain.BaseDirectory);//透明PNG图片添加白色底图String transparentPng = Path.Combine(imageDirectory, "transparent.png");String noTransparentPng = Path.Combine(imageDirectory, "noTransparent.png");PngHelp.AddBlankBaseMap(transparentPng, noTransparentPng);//根据图片url保存图片String urlPng=Path.Combine(imageDirectory, "url.png");PngHelp.GetImageByURL("http://image.bitauto.com/dealer/brandgroup/m/389.png", urlPng);//PNG转JPG一般操作方法【存在失真的情况,原因决定于原始PNG图片的质量】String changeJpg=Path.Combine(imageDirectory, "changeJpg.jpg");PngHelp.GeneralPngChange(noTransparentPng, changeJpg,ImageFormatenmu.jpg);String changeBmp = Path.Combine(imageDirectory, "changeBmp.bmp");PngHelp.GeneralPngChange(noTransparentPng, changeBmp, ImageFormatenmu.bmp);String changeGif = Path.Combine(imageDirectory, "changeGif.gif");PngHelp.GeneralPngChange(noTransparentPng, changeBmp, ImageFormatenmu.gif); //【透明图失真更多】String changeNewJpg = Path.Combine(imageDirectory, "changeNewJpg.jpg");PngHelp.GeneralPngChange(transparentPng, changeNewJpg, ImageFormatenmu.jpg);//PNG转JPG一般操作方法,可设置图片质量String changeJpg0=Path.Combine(imageDirectory, "changeJpg0.jpg");PngHelp.GeneralPngToJpg(noTransparentPng, changeJpg0,0L);String changeJpg50 = Path.Combine(imageDirectory, "changeJpg50.jpg");PngHelp.GeneralPngToJpg(noTransparentPng, changeJpg50, 50L);String changeJpg100 = Path.Combine(imageDirectory, "changeJpg100.jpg");PngHelp.GeneralPngToJpg(noTransparentPng, changeJpg100, 50L);//高保真PNG转JPG,解决部分PNG转JPG过程中图像失真的问题String highqualityJpgFromTrasparent = Path.Combine(imageDirectory, "highqualityJpgFromTrasparent.jpg");String highqualityJpgFromNoTrasparent = Path.Combine(imageDirectory, "highqualityJpgFromNoTrasparent.jpg");PngHelp.HighQualityPNGToJPG(transparentPng, highqualityJpgFromTrasparent);PngHelp.HighQualityPNGToJPG(noTransparentPng, highqualityJpgFromNoTrasparent);
8、完整示例代码
版权说明
作者:
欢迎转载,请注明版权及来源。