C# - 如何更改 PNG 质量或颜色深度

发布于 2024-08-24 06:28:13 字数 2376 浏览 2 评论 0原文

我应该编写一个程序,从用户那里获取一些 PNG 图像,进行一些简单的编辑(例如旋转)并将它们保存在 JAR 文件中,以便它可以使用图像作为资源。问题是,当我打开一个 80kb 图像,然后用 C# 保存它时,我会得到一个具有相同质量但占用 130kb 空间的图像。因为它必须放入 J2ME jar 文件中,所以我确实需要较小的大小,至少是原始大小。我尝试了下面的代码,但后来发现它只适用于 Jpeg 图像。

ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
                int j = 0;
                for (j = 0; j < codecs.Length; j++)
                {
                    if (codecs[j].MimeType == "image/png") break;
                }
                EncoderParameter ratio = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 10L);
                EncoderParameters CodecParams = new EncoderParameters(1);
                CodecParams.Param[0] = ratio;

                Image im;
                im = pictureBox1.Image;
                im.Save(address , codecs[j], CodecParams);

这是将图像加载到图片框的位置:

private void pictureBox1_DoubleClick(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                string address = openFileDialog1.FileName;
                address.Replace("\\", "\\\\");
                Image im = Image.FromFile(address);
                pictureBox1.Image = im;
            }
        }

这是在不进行任何编辑的情况下将图像保存回来的位置:

private void generateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {

                ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
                int j = 0;
                for (j = 0; j < codecs.Length; j++)
                {
                    if (codecs[j].MimeType == "image/png") break;
                }
                EncoderParameter ratio = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 10L);
                EncoderParameters CodecParams = new EncoderParameters(1);
                CodecParams.Param[0] = ratio;

                string address = folderBrowserDialog1.SelectedPath;
                address = address + "\\";
                address.Replace("\\", "\\\\");

                Image im;
                im = pictureBox1.Image;               
                im.Save(address + imageFileNames[1], codecs[j], CodecParams);

注意:imageFileNames[] 只是一个字符串数组,其中包含图像必须保存到的一些文件名。

任何想法将不胜感激并提前致谢。

I am supposed to write a program that gets some PNG images from the user, does some simple edits like rotation and saves them inside a JAR file so that it can use the images as resources. The problem is when I open, say an 80kb image and then save it with C#, I get an image with the same quality but for 130kb space. And because it has to go inside a J2ME jar file I really need lower sizes, at least the original size. I tried the code below but later found out that it only works for Jpeg images.

ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
                int j = 0;
                for (j = 0; j < codecs.Length; j++)
                {
                    if (codecs[j].MimeType == "image/png") break;
                }
                EncoderParameter ratio = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 10L);
                EncoderParameters CodecParams = new EncoderParameters(1);
                CodecParams.Param[0] = ratio;

                Image im;
                im = pictureBox1.Image;
                im.Save(address , codecs[j], CodecParams);

This is where the image is loaded to a picture box:

private void pictureBox1_DoubleClick(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                string address = openFileDialog1.FileName;
                address.Replace("\\", "\\\\");
                Image im = Image.FromFile(address);
                pictureBox1.Image = im;
            }
        }

And this is where it's being saved back with no edits:

private void generateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {

                ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
                int j = 0;
                for (j = 0; j < codecs.Length; j++)
                {
                    if (codecs[j].MimeType == "image/png") break;
                }
                EncoderParameter ratio = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 10L);
                EncoderParameters CodecParams = new EncoderParameters(1);
                CodecParams.Param[0] = ratio;

                string address = folderBrowserDialog1.SelectedPath;
                address = address + "\\";
                address.Replace("\\", "\\\\");

                Image im;
                im = pictureBox1.Image;               
                im.Save(address + imageFileNames[1], codecs[j], CodecParams);

Note: imageFileNames[] is just a string array that has some of the the file names to which the images must be saved with.

Any ideas will be appreciated and thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

や三分注定 2024-08-31 06:28:13

很抱歉提出一个老问题,但我今天正在解决同样的问题,并在 MSDN 上找到了此页面: “列出所有编码器的参数和值”。我希望在那里参考它可能会有用。

本文包含一个示例程序,该程序输出现有 GDI+ 图像编码器支持的 EncoderParameter,而 PNG 编码器根据它不支持任何参数。

我不确定人们是否可以认为这是理所当然的,或者在 gdiplus.dll 的未来版本中,PNG 编码器可能会获得更多支持,因此应该在运行时检查编码器的功能。

无论如何,对源图像应用一些显式变换似乎是更有效的方法;不过我还没有探索过。

Sorry for bringing up an old question, but I were solving the same problem today and found this page on MSDN: "Listing Parameters and Values for All Encoders". I hope it might be useful to refer to it there.

The article contains a sample program which outputs EncoderParameters supported by stock GDI+ image encoders, and PNG encoder supports no parameters according to it.

I'm not sure thought if one can take this for granted, or in some future version of gdiplus.dll the PNG encoder might grow more support, and so one is supposed to check the encoder's capabilities at runtime.

In any case applying some explicit transformation on a source image appears to be more fruitful approach; I did not explore it yet though.

第七度阳光i 2024-08-31 06:28:13

我拍摄了 4 个不同的 PNG,大小从 2KB 到 2.6MB 不等。使用您的代码,我加载它们并将它们保存出来。我不会通过旋转或翻转来修改图像。重新保存时,所有 4 个 PNG 的大小完全相同。

此外,我还获取了 2.6MB PNG,在 Photoshop 中打开它并保存了两份副本,一份是隔行扫描的(减少到 2.06MB),一份是非隔行扫描的(减少到 1.7MB)。他们通过您的代码并保存了它们。两者的最终大小都恢复到原来的 2.6MB。

所以,我的猜测是,原始图像是用一个软件(如 Photoshop)创建的,并且该软件具有优化的压缩算法,用于 .NET 不采用的 PNG 规范。

我已经搞乱了压缩的 EncoderParameter,但它似乎没有影响。

I have taken 4 different PNGs, ranging in sizes from 2KB to 2.6MB. Using your code, I load them up and save them out. I do not modify the image by rotating or flipping. All 4 PNGs, when re-saved, have exactly the same size.

In addition, I have taken the 2.6MB PNG, opened it in Photoshop and saved two copies of it, one interlaced (reduced to 2.06MB), one non-interlaced (reduced to 1.7MB.) I then took each of those, ran them through your code and saved them. The resulting sizes of both were back to the original 2.6MB.

So, my guess is that the original images were created with a piece of software (like photoshop) and that piece of software has an optimized compression algorithm it is using for the PNG spec that .NET does not employ.

I've messed around with the EncoderParameter for Compression, but it seems to have no impact.

甜中书 2024-08-31 06:28:13

它们要么使用不同的压缩方法保存,要么使用相同的压缩方法但级别不同。例如,LZW 有 10 个级别(0 表示快速/无压缩,9 表示慢速/最大压缩)。我会告诉你如何在编写图像时设置它,但我在试图弄清楚这一点时发现了这个线程,哈哈。

They're either saved using a different compression methods, or it's the same compression method but at different levels. LZW, for example, has 10 levels (0 for fast/no compression, to 9 for slow/max compression). I'd tell you how to set that when writing the image, but I found this thread while trying to figure that out lol.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文