开发者

Sometimes, scaling down a bitmap generates a bigger file. Why?

I'm trying to write a method to reduce the size of any image 50% each time is called but I've f开发者_运维问答ound a problem. Sometimes, I end up with a bigger filesize while the image is really just half of what it was. I'm taking care of DPI and PixelFormat. What else am I missing?

Thank you for your time.

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;
}

Sometimes, scaling down a bitmap generates a bigger file. Why?

Sometimes, scaling down a bitmap generates a bigger file. Why?

Edit: Here's the missing code:

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

Edit 2: Based on your comments, this is the solution I've found:

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;
}


You are most probably saving the jpeg image with a low compression ratio (high quality).


Recompressing a JPEG image is something you ought to avoid. But the real problem here is the InterpolationMode, a high quality one produces a lot of subtly shaded pixels, making it harder to compress the image. Using InterpolationMode.NearestNeighbor should avoid that, but at the cost of getting a lower quality image.


The problem isn't situated in the code you posted, but where you save the JPEG. What compression ratio are you using?


I would say that you are saving it as a high quality jpeg (less compression == more space)


Seeming as your bitmaps are actually saved as jpegs, and knowing how c# likes to do things for you, it is probably saving with a default compression level that is fairly low. The original jpeg must have a decent compression level on it. Even if it was the same compression level, the way the jpeg format works may mean that you have found a fluke image that dose bloat at a lower resolution.

A bit map though is an exact size, if it is ten pixels wide and ten high, it is 100 pixels, in say 16 bit (2 byte) colour that's 200 bytes, plus a bit of header.

lower the resolution to 5 by 5, you have 50 bytes plus a bit of header, should be the same amount of header though.


It seems like the original is the output from a digital camera. I think the camera producers use proprietary super optimized compression algoritms, while a common library may have a less effective implementation. (And of course you're probably not using the same compression level as the camera.)

In addition the camera uses the raw data (possibly doing some "magic" preprocessing on it first) from its sensors as input. While when you re-compress it, the input has compression and rescaling artifacts in it which may cause the compression to be less effective.

Actually i think if you compress an image several times with the same jpg algoritm at the same level, it could grow in size because the artifacts from the previous compressions adds "details" that is harder to compress (and it becomes uglier too).

(The camera compression algoritm may also be optimized for the fact that the input is always a photo, while a general purpose algoritm may do some less effective stuff to work reasonably well both for photos and line art mixed images containing both photo and generated graphical elements.)


Try this code to save the JPEG you have. It will allow you setting the compression quality. Experiment and see if it helps your size problem:

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;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜