从文件或者字节数组中读取和复制Bitmap图像的安全方法

大部分时候,我们使用下面代码来读取和复制bitmap文件

Bitmap bmp = new Bitmap(fullpath);
Bitmap bmpLoad = (Bitmap)bmp.Clone();
Bmp.dispose(); //释放,避免锁定文件

但是,clone会克隆文件流路径,这可能会带来问题。

 

**********************************************************

如果使用new Bitmap(bmp ),构造函数会使用屏幕dpi和32位PixelFormat来创建Bitmap,分辨率变成默认的96,图像深度会变成32。我们也不能使用memorystream来复制bitmap,因为图像需要在内存中保持数据流不被释放,这会带来内存管理的麻烦。

可以这样写
static Bitmap LoadImage(Stream stream)
{
    Bitmap retval = null;

    using (Bitmap b = new Bitmap(stream))
    {
        retval = new Bitmap(b.Width, b.Height, b.PixelFormat);   //丢失分辨率,需要额外传参。
        using (Graphics g = Graphics.FromImage(retval))
        {
            g.DrawImage(b, Point.Empty);
            g.Flush();
        }
    }

    return retval;
}

**********************************************************

比较安全的方法是使用LockBits+Marshal.Copy从内存中进行复制,这样可以确保深度不变。然后使用SetResolution设置分辨率。代码很长。
参见https://stackoverflow.com/questions/4803935/free-file-locked-by-new-bitmapfilepath/7972963#7972963

 

也可以试试下面的方法,使用ImageConverter类

**********************************************************

Using System.Drawing;
private static readonly ImageConverter _imageConverter = new ImageConverter();

图像到字节数组:

/// <summary>
/// Method to "convert" an Image object into a byte array, formatted in PNG file format, which
/// provides lossless compression. This can be used together with the GetImageFromByteArray()
/// method to provide a kind of serialization / deserialization.
/// </summary>
/// <param name="theImage">Image object, must be convertable to PNG format</param>
/// <returns>byte array image of a PNG file containing the image</returns>
public static byte[] CopyImageToByteArray(Image theImage)
{
    using (MemoryStream memoryStream = new MemoryStream())
    {
        theImage.Save(memoryStream, ImageFormat.Png);   //更换成自己的格式,如果用RawFormat可能会出问题。

        return memoryStream.ToArray();
    }
}


字节数组到图像:

/// <summary>
/// Method that uses the ImageConverter object in .Net Framework to convert a byte array,
/// presumably containing a JPEG or PNG file image, into a Bitmap object, which can also be
/// used as an Image object.
/// </summary>
/// <param name="byteArray">byte array containing JPEG or PNG file image or similar</param>
/// <returns>Bitmap object if it works, else exception is thrown</returns>
public static Bitmap GetImageFromByteArray(byte[] byteArray)
{
    Bitmap bm = (Bitmap)_imageConverter.ConvertFrom(byteArray);

    if (bm != null && (bm.HorizontalResolution != (int)bm.HorizontalResolution ||
    bm.VerticalResolution != (int)bm.VerticalResolution))
    {
        // Correct a strange glitch that has been observed in the test program when converting
        // from a PNG file image created by CopyImageToByteArray() - the dpi value "drifts"
        // slightly away from the nominal integer value
        bm.SetResolution((int)(bm.HorizontalResolution + 0.5f),  (int)(bm.VerticalResolution + 0.5f));
    }

    return bm;
}

使用示例:

Bitmap newBitmap = GetImageFromByteArray(File.ReadAllBytes(fileName));
这避免了与希望其源流保持打开的位图相关的问题,以及导致源文件保持锁定的一些建议的解决方法。

 

posted @ 2022-04-20 10:01  Charltsing  阅读(539)  评论(0编辑  收藏  举报