简体   繁体   中英

Trying to change image DPI without changing file size

I have the following code for changing the DPI of an image:

public void changeDPI(string imagePathSource,string imagePathDestination,float DPIx,float DPIy)
        {
            Bitmap bitmap = new Bitmap(imagePathSource);
            Bitmap newBitmap = new Bitmap(bitmap);
            newBitmap.SetResolution(DPIx,DPIy);
            newBitmap.Save(imagePathDestination);
        }

However, this ends up changing the memory size of the file. An example test image started at 267 KB, and the newBitmap version of the file ended up as 1.51 MB. How can I change the DPI without changing the file size?

我认为您必须指明输出文件的格式,以保存为像 JPEG 这样的压缩图像格式。

newBitmap.Save(imagePathDestination, System.Drawing.Imaging.ImageFormat.Jpeg);

Why are you making a new bitmap out of it? That converts the image to 32bpp ARGB, and loses the connection to the original loaded data.

The original loaded image's file format is available in the RawFormat property. So just set the original bitmap's resolution to your new one, and save it to the new path using bitmap.RawFormat :

public void changeDPI(String imagePathSource, String imagePathDestination, Single dpiX, Single dpiY)
{
    using (Bitmap bitmap = new Bitmap(imagePathSource))
    {
        bitmap.SetResolution(dpiX, dpiY);
        bitmap.Save(imagePathDestination, bitmap.RawFormat);
    }
}

I believe that this way, it won't even recompress the actual image content, meaning you have no further quality degrading due to reapplying the jpeg compression.

Also, do make sure you always either call Dispose() on image objects, or use them in a using block. They are objects backed by unmanaged sources (GDI+ objects), so you have to be careful or they'll pollute your program's memory, and keep locks on the files you opened.

On the note of locked files, if you give the same path for both imagePathSource and imagePathDestination you'll get an error about exactly that. To get around this, read the bytes from the image in advance, and use a MemoryStream to load the image:

public void changeDPI(String imagePathSource, String imagePathDestination, Single dpiX, Single dpiY)
{
    Byte[] fileData = File.ReadAllbytes(imagePathSource);
    using (MemoryStream ms = new MemoryStream(fileData))
    using (Bitmap loadedImage = new Bitmap(ms))
    {
        bitmap.SetResolution(dpiX, dpiY);
        bitmap.Save(imagePathDestination, bitmap.RawFormat);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM