GDI +错误将24bpp JPG转换为8bpp索引格式(PNG或GIF)

时间:2016-01-21 15:39:04

标签: c# .net image bitmap

我需要一个通用函数来将图像转换为目标格式。 (在这种情况下,Format8bppIndexed)目标是能够处理合理范围的常规.NET支持的图像。我们有许多客户拥有数百TB的不同类型的图像,我打算用这些代码遍历它们。

以下是我尝试转换的图片,它会抛出错误: Single page JPG example

我意识到这段代码有多个内部尝试捕获,但我想说明问题。

在下面的每个尝试中,我都有评论显示我收到的异常和错误。

public static Bitmap ConvertToFormat(this Bitmap Source, PixelFormat TargetFormat)
{
    try
    {
        //This throws OutOfMemoryException: "Out of memory."
        return Source.Clone(new Rectangle(0, 0, Source.Width, Source.Height), TargetFormat);
    }
    catch (OutOfMemoryException)
    {
        try
        {
            MemoryStream ResultStream = new MemoryStream();

            // This throws ExternalException: "A generic error occurred in GDI+"
            Source.Save(ResultStream, ImageFormat.Gif);

            ResultStream.Position = 0;
            return new Bitmap(ResultStream);
        }
        catch (ExternalException)
        {
            // this is just an attempt to break the process down further to try and find the cause:

            ImageCodecInfo myImageCodecInfo = GetCodecInfo(ImageFormat.Gif);
            EncoderParameters myEncoderParameters = new EncoderParameters(2);
            myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Compression, (long)EncoderValue.CompressionLZW); ;
            myEncoderParameters.Param[1] = new EncoderParameter(Encoder.Quality, 0L);

            MemoryStream ResultStream = new MemoryStream();

            // This throws ExternalException: "A generic error occurred in GDI+"
            Source.Save(ResultStream, myImageCodecInfo, myEncoderParameters);

            ResultStream.Position = 0;
            return new Bitmap(ResultStream);
        }
    }
}

private static ImageCodecInfo GetCodecInfo(ImageFormat TargetFormat)
{
    return ImageCodecInfo.GetImageEncoders().ToList().Find(
        delegate (ImageCodecInfo codec) 
            { return codec.FormatID == TargetFormat.Guid; });
}

我知道源图像很好,因为我可以使用LockBits()读取像素。我正在考虑使用循环来逐像素地创建一个新图像,但我更喜欢使用更直接的克隆选项,因为它会自动处理调色板创建,颜色匹配和抖动。

更新
我发现导致问题的代码,但我不确定为什么。 我不希望文件被锁定,所以我使用下面的代码将图像加载到内存中然后解锁文件。显然这会导致问题,但只有在调用Clone()方法时才会出现问题。当我使用与LockBits()相同的图像时,它允许我通过内存指针访问每个像素,并且它在PictureBox中显示得很好。有谁知道为什么这个方法导致.Clone()错误,以及如何将Image文件加载到内存中然后立即释放文件?

using (Stream s = File.OpenRead(SourceFileName))
{
    return (Bitmap)Bitmap.FromStream(s);
}

0 个答案:

没有答案