前言

最近碰到一个需要将图片由原始的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转换情况如下:

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

点击这里下载

版权说明

作者:ChowYy

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

 
 

PNG格式图片常见转换方法的更多相关文章

  1. Linux下常见音频格式之间的转换方法

    Linux下常见音频格式之间的转换方法[转] 下面简单介绍下Linux环境常见音频格式之间的转换方法: MP3 相关工具: lameOGG 相关工具: vorbis-toolsAPE 相关工具: ma ...

  2. QT_SVG格式图片浏览器_源代码下载_详细注释

    源代码链接: http://pan.baidu.com/s/1pKA5Vcv 密码: ib2x 注:SVG格式图片特点: 1. 文件小 2. 图像中文字独立于图像, 可以编辑,可搜索. 3.没有字体限 ...

  3. 如何在latex 中插入EPS格式图片

    如何在latex 中插入EPS格式图片 第一步:生成.eps格式的图片 1.利用visio画图,另存为pdf格式的图片 利用Adobe Acrobat裁边,使图片大小合适 另存为.eps格式,如下图所 ...

  4. 关于.9.png格式图片的制作与使用

    .9.png图片其实就是png格式图片,不过它比普通的png图片外围多了1px(像素)的边框,另外就是使用这种格式的图片可以实现背景自适应大小且不失真的效果. 制作使用步骤: 1.制作属于你自己的pn ...

  5. jpg/png格式图片转eps格式的方法总结

    jpg/png格式图片转eps格式的方法总结 转自http://blog.sina.com.cn/s/blog_5410e7b50101lme2.html 用latex写论文的筒子应该遇到这样的问题: ...

  6. oracle 报“无效数字”异常和“ORA-01830: 日期格式图片在转换整个输入字符串之前结束”

    1.问题1 执行下列SQL: sql = "select count(1) as totle from vhl_model_data a where a.OBTAIN_CREATE_TIME ...

  7. Android 9 patch 图片 (.9.png 格式图片) 的特点和制作(转)

    本文围绕 .9.png 格式图片讨论以下两个话题: 1. 该格式图片的特点 2. 制作方式 一 .9.png 格式的文件的特点 与传统的png 格式图片相比, 9.png 格式图片在图片四周有一圈一个 ...

  8. 前端获取Base64字符串格式图片Ajax到后端处理

    前端获取到的Base64字符串格式图片一般都是经过处理的图片,例如:裁剪过后的,这里假设data为获取到的Base64字符串格式图片 Base64格式图片的格式为 “data:image/png;ba ...

  9. png格式图片转为svg格式图片

    png格式图片转为svg格式图片 (2012-08-30 16:24:00) 转载▼ 标签: 杂谈 分类: linux 在ubuntu下将png格式的图片转换成svg格式步骤如下:1.安装 inksc ...

随机推荐

  1. if中的-n -z linux_Shell

    ==========1 混淆的-n  -z================= -n 表示这个变量或者字符串是否不为空.-z 表示这个变量或者字符串为空 上面这两句话中最重要的点是不通的 -n 关注的是 ...

  2. RedHat 简易配置 VNC Server 与VNC View详细说明

    首先下载Linux版本的VNC文件. 下载地址:http://www.realvnc.com/download/vnc/ 如:VNC-5.0.2-Linux-x86-RPM.tar.gz(其实解压出来 ...

  3. Windows Phone Bing lock screen doesn't change解决方法

    之前一直用的Lumia 925,Bing lock screen每天都会更换.这几天换了Lumia 930,同步了账号相关的设置,发现Bing lock screen不再每天更换.尝试重启.使用cel ...

  4. 【转】.Net+MySQL组合开发 乱码篇

    所用工具MySQL5.022VS2005 Team SuiteMySQL Connector Net 5.0.3EMS SQL Manage 2005 For MySQL使用过MySQL的朋友都知道有 ...

  5. 基于spring-cloud的微服务(2) eureka服务提供方的注册和消费方的消费

    启动Eureka注册中心之后,服务提供方就可以注册到Eureka上去(作为一个Eureka的客户端) 我们使用IDEA提供的spring initializer来新建一个springcloud项目 填 ...

  6. 使用COSBench工具对ceph s3接口进行压力测试

    一.COSBench安装 COSBench是Intel团队基于java开发,对云存储的测试工具,全称是Cloud object Storage Bench 吐槽下,貌似这套工具是intel上海团队开发 ...

  7. border-image使用过程中遇到的几个问题

    这次年货,为了增添气氛,很多地方都用了边框,由于边框高度的不固定,给构建着实带了不小的麻烦. 通常我们处理边框的方法,无非以下两种方案: 1.切整张图片,做背景. 2.切上中下,进行拼接处理. 但是遇 ...

  8. 涨知识,涨知识 :ThinkPHP框架下Where条件查询Mysql数据库某字段是否为空

    代码虐我千百遍,我对代码如初恋~ 问题: 查询某字段app_date数据是否为NULL,正常我们实现的办法是: $map['app_data'] = array('eq','null'); $data ...

  9. vue---阻止默认表单提交的三种方法

    vue在做表单提交的时候,需要用到一些自定义的验证规则,这个时候就需要阻止表单默认的提交方式. 方法一:直接阻止 <form id="form" @submit=" ...

  10. Spark2 生存分析Survival regression

    在spark.ml中,实现了加速失效时间(AFT)模型,这是一个用于检查数据的参数生存回归模型. 它描述了生存时间对数的模型,因此它通常被称为生存分析的对数线性模型. 不同于为相同目的设计的比例风险模 ...