【问题标题】:Sometimes, scaling down a bitmap generates a bigger file. Why?有时,缩小位图会生成更大的文件。为什么?
【发布时间】:2010-03-24 13:10:35
【问题描述】:

我正在尝试编写一种方法,每次调用时将任何图像的大小减小 50%,但我发现了一个问题。有时,我最终会得到更大的文件大小,而图像实际上只是原来的一半。我正在处理 DPI 和 PixelFormat。我还缺少什么?

感谢您的宝贵时间。

public Bitmap ResizeBitmap(Bitmap origBitmap, int nWidth, int nHeight)
{
    Bitmap newBitmap = new Bitmap(nWidth, nHeight, origBitmap.PixelFormat);

    newBitmap.SetResolution(
       origBitmap.HorizontalResolution, 
       origBitmap.VerticalResolution);

    using (Graphics g = Graphics.FromImage((Image)newBitmap))
    {
        g.InterpolationMode = InterpolationMode.HighQualityBicubic;

        g.DrawImage(origBitmap, 0, 0, nWidth, nHeight);
    }

    return newBitmap;
}

编辑: 这是缺少的代码:

int width = (int)(bitmap.Width * 0.5f);
int height = (int)(bitmap.Height * 0.5f);
Bitmap resizedBitmap = ResizeBitmap(bitmap, width, height);
resizedBitmap.Save(newFilename);

编辑 2: 根据您的 cmets,这是我找到的解决方案:

private void saveAsJPEG(string savingPath, Bitmap bitmap, long quality)
{
    EncoderParameter parameter = new EncoderParameter(Encoder.Compression, quality);
    ImageCodecInfo encoder = getEncoder(ImageFormat.Jpeg);
    if (encoder != null)
    {
        EncoderParameters encoderParams = new EncoderParameters(1);
        encoderParams.Param[0] = parameter;
        bitmap.Save(savingPath, encoder, encoderParams);
    }
}

private ImageCodecInfo getEncoder(ImageFormat format)
{

    ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
    foreach (ImageCodecInfo codec in codecs)
        if (codec.FormatID == format.Guid)
            return codec;

    return null;
}

【问题讨论】:

  • 压缩?压缩位/像素不同。
  • 发布你的 C# JPEG 导出代码。我也猜这是一个压缩问题。
  • 哦,我刚刚添加了缺少的代码

标签: c# .net bitmap resize-image


【解决方案1】:

您很可能以低压缩比(高质量)保存 jpeg 图像。

【讨论】:

  • 好吧,我没有选择任何压缩比。有没有办法可以使用与原始图像相同的压缩比?谢谢。
  • @Matías - 据我所知,压缩比没有存储在标题中,因此一旦保存文件,信息就会丢失。
  • @Matiás:没有指定时使用的默认压缩值很高。我正在使用一种方法来迭代压缩级别值,直到输出大小合适(当用户在从应用程序导出 jpeg 时选择将输出大小限制为某个值时)。
【解决方案2】:

您应该避免重新压缩 JPEG 图像。但这里真正的问题是 InterpolationMode,一个高质量的会产生很多微妙的阴影像素,使得压缩图像变得更加困难。使用 InterpolationMode.NearestNeighbor 应该可以避免这种情况,但代价是获得较低质量的图像。

【讨论】:

  • 我试过了,文件大小还是比原图大。
  • @Matías:当你开始使用 PNG 时会发生什么,以避免第一次压缩产生的噪音?
  • 什么意思?我的源图像始终是 JPEG,抱歉我之前没有提到。
  • 我认为这个建议是倒退的。 JPEG 在平滑变化的输入上比在锯齿状的输入上压缩得更好。
  • @Mark:HQ 插值平滑。像素抖动频繁,相差 +/- 4 左右。
【解决方案3】:

问题不在于您发布的代码,而在于您保存 JPEG 的位置。您使用的压缩比是多少?

【讨论】:

    【解决方案4】:

    我会说您将其保存为高质量的 jpeg(压缩更少 == 更多空间)

    【讨论】:

      【解决方案5】:

      看起来您的位图实际上保存为 jpeg,并且知道 c# 喜欢为您做事,它可能会以相当低的默认压缩级别保存。原始 jpeg 必须具有不错的压缩级别。即使是相同的压缩级别,jpeg 格式的工作方式也可能意味着您发现了一个在较低分辨率下会膨胀的侥幸图像。

      位图虽然是精确尺寸,但如果它是 10 像素宽和 10 像素高,则它是 100 像素,例如 16 位(2 字节)颜色,即 200 字节,加上一点标题。

      将分辨率降低到 5 x 5,您有 50 个字节加上一些标头,但应该是相同数量的标头。

      【讨论】:

        【解决方案6】:

        看起来原件是数码相机的输出。我认为相机生产商使用专有的超级优化压缩算法,而通用库的实现可能不太有效。 (当然,您可能没有使用与相机相同的压缩级别。)

        此外,相机使用来自其传感器的原始数据(可能首先对其进行一些“魔术”预处理)作为输入。当您重新压缩它时,输入中有压缩和重新缩放伪影,这可能会导致压缩效果降低。

        实际上,我认为如果您在 same 级别使用 same jpg 算法多次压缩图像,它的大小可能会增加,因为先前压缩的伪影会增加更难压缩的“细节”(也变得更丑)。

        (相机压缩算法也可以针对输入总是一张照片这一事实进行优化,而通用算法可能会做一些不太有效的事情,以便对照片和 线条艺术包含照片和生成的图形元素的混合图像。)

        【讨论】:

        • JPEG 在线条艺术上永远无法正常工作,除非您将质量水平调到最高。你说得对,相机制造商可以优化他们的 JPEG 算法。当 Sigma 推出他们的 Foveon 传感器时,他们发现他们使用的算法与竞争对手相比失去了新传感器提供的一些细节,他们必须对其进行调整。
        • 当然它不适合线条艺术(为此使用 png 等!)。我实际上是在考虑具有许多不同类型图形的混合图像。 (我已经更新了我的答案)
        【解决方案7】:

        尝试使用此代码保存您拥有的 JPEG。它将允许您设置压缩质量。试验一下,看看它是否有助于解决您的尺寸问题:

        private void saveJpeg(string path, Bitmap img, long quality)
        {
            EncoderParameter parameter = new EncoderParameter(Encoder.Quality, quality);
            ImageCodecInfo encoder = this.getEncoderInfo("image/jpeg");
            if (encoder != null)
            {
                EncoderParameters encoderParams = new EncoderParameters(1);
                encoderParams.Param[0] = parameter;
                img.Save(path, encoder, encoderParams);
            }
        }
        
        private ImageCodecInfo getEncoderInfo(string mimeType)
        {
            ImageCodecInfo[] imageEncoders = ImageCodecInfo.GetImageEncoders();
            for (int i = 0; i < imageEncoders.Length; i++)
            {
                if (imageEncoders[i].MimeType == mimeType)
                {
                    return imageEncoders[i];
                }
            }
            return null;
        }
        

        【讨论】:

        • 对不起,我完全忘记了那个方法。现在它应该是完整的(即使我想现在为时已晚:))
        猜你喜欢
        • 1970-01-01
        • 2010-11-26
        • 1970-01-01
        • 1970-01-01
        • 2011-01-29
        • 2020-10-28
        • 1970-01-01
        • 2015-11-25
        • 2016-10-15
        相关资源
        最近更新 更多