PNG格式图片常见转换方法

前言

最近碰到一个需要将图片由原始的PNG转化为JPG的需求,由于PNG图片本身质量等原因,导致转化为JPG之后,存在失真的问题,后来一个同事分享了下述的HighQualityPNGToJPG方法解决PNG转JPG失真的问题。

1、准备

复制代码
using System.Drawing;

using System.Net;

using System.Drawing.Imaging;



/// <summary>

/// 常见图片格式枚举

/// </summary>

public enum ImageFormatenmu

{

    jpg,

    gif,

    bmp,

    png

}
复制代码

2、给透明PNG图片添加白色底图

复制代码
/// <summary>

/// 透明PNG图片添加白色底图

/// </summary>

/// <param name="pngFilePath">Png文件路径</param>

/// <param name="savePngFilePath">新Png文件保存路径</param>

/// <returns></returns>

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保存图片

复制代码
/// <summary>

/// 根据图片url保存图片

/// </summary>

/// <param name="url">url地址</param>

/// <param name="savePath">保存本地路径【含文件名,注意扩展名要和url对应文件本身一样,否则可能出错】</param>

public static void GetImageByURL(String url, String savePath)

{

    WebClient webClient = new WebClient();

    webClient.DownloadFile(url, savePath);

}
复制代码

4、普通PNG格式转换

复制代码
/// <summary>

/// 普通PNG格式转换

/// </summary>

/// <param name="pngFilePath">png文件路径</param>

/// <param name="saveFilePath">保存文件路径</param>

/// <param name="imageFromat">转化格式</param>

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一般操作方法,可设置图片质量

复制代码
/// <summary>

/// PNG转JPG一般操作方法,可设置图片质量

/// </summary>

/// <param name="pngFilePath">png文件路径</param>

/// <param name="saveFilePath">jpg文件路径</param>

/// <param name="percentage">图片质量>0</param>

public 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);

}



/// <summary>

/// 获取图片编码信息

/// </summary>

/// <param name="mimeType">图片格式MIME类型</param>

/// <returns></returns>

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过程中图像失真的问题

复制代码
/// <summary>

/// 高保真PNG转JPG,解决部分PNG转JPG过程中图像失真的问题

/// 例如:本人将一张透明的PNG转JPG后,JEP图片失真

/// </summary>

/// <param name="pngFilePath">png文件路径</param>

/// <param name="jpgFilePath">jpg文件路径</param>

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转换情况如下:

transparent

图表 1 透明底图PNG

changeNewJpg

图表 2透明底图PNG转化后的JPG图片【较严重失真】

非透明底图PNG转换情况如下:

noTransparent

图表 3非透明底图PNG

changeJpg

图表 4 非透明底图PNG转JPG【较严重失真】

HighQualityPNGToJPG分别转化透明及非透明低图的PNG,结果如下:

highqualityJpgFromTrasparent

图表 5 非透明底图的PNG格式转化后的JPG

highqualityJpgFromNoTrasparent

图表 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、完整示例代码

点击这里下载

你可能感兴趣的:(png)