zoukankan      html  css  js  c++  java
  • 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、完整示例代码

    点击这里下载

    版权说明

    作者:ChowYy

    欢迎转载,请注明版权及来源。

     
     
  • 相关阅读:
    ES 分组排序java实现
    java多线程中的死锁、活锁、饥饿、无锁都是什么鬼?
    Java 虚拟机对锁优化所做的努力
    Docker 核心概念、安装、端口映射及常用操作命令,详细到令人发指。
    20条最最常用的Linux命令讲解
    Linux查看系统配置常用命令
    全面认识Docker和基本指令
    25个深度学习开源数据集
    Docker 简单运用
    一小时学会C# 6
  • 原文地址:https://www.cnblogs.com/waw/p/5956630.html
Copyright © 2011-2022 走看看