无法使用 GDI+ 保存 TIF 文件

Posted

技术标签:

【中文标题】无法使用 GDI+ 保存 TIF 文件【英文标题】:Cannot save TIF file using GDI+ 【发布时间】:2019-11-09 21:24:06 【问题描述】:

我有一个选择和加载 JPG 文件的 vb.net 应用程序

 LoadedImage = Image.FromFile(InputImageName)

然后尝试使用 GDI+ 将文件另存为 TIF

 LoadedImage.Save(TIF_ImageName, ImageFormat.Tiff)

没有语法错误,但保存失败

System.InvalidCastException was unhandled
Message=Conversion from string "System.Runtime.InteropServices.E" to type 'Integer' is not valid.

我尝试过使用位图而不是图像,没有乐趣 图像很大(9000x11000 像素) 这是encoderparams 的问题吗?也许没有默认值?可用的样本是用于双色调图像的。

最后,我将使用位置数据生成新的 TIF 标签,因此这是开发中的一个临时步骤。

【问题讨论】:

【参考方案1】:

尝试使用ImageCodecInfo 类,它提供了控制用于对图像格式进行编码的编解码器参数的方法。

在 GDI+ 中,您可以指定数量非常有限的参数。在实践中,只有Compression 方法和Quality 级别决定了压缩级别(0-100,其中0 是最大压缩)。

这些参数组装在EncoderParameters 对象的EncoderParameter 数组中 - 用于指定Encoder 主题 - 在将它们传递给接受 Image.Save() 重载之前>ImageCodecInfoEncoderParameters 作为参数。

示例方法调用: 将源图像保存为 TIFF 格式,使用相同的 DPI 设置,压缩级别设置为 50%。图片保存为24bpp RGB格式。根据需要进行修改。 压缩类型为LZW

Dim jpgImage As Image = Image.FromFile("ImageFile.jpg"), True)
SaveTiffImage(jpgImage, jpgImage.VerticalResolution, 50L, "DestinationFile.tif")
jpgImage.Dispose()

编解码器初始化方法

Imports System.Drawing
Imports System.Drawing.Imaging
Imports ImageCodec = System.Drawing.Imaging.Encoder

Private Sub SaveTiffImage(image As Image, resolution As Single, compressionLevel As Long, fileName As String)
    resolution = Math.Max(72, Math.Min(2400, resolution))
    compressionLevel = Math.Max(0, Math.Min(100, compressionLevel))

    Using bitmap = New Bitmap(image.Width, image.Height, PixelFormat.Format24bppRgb)
        bitmap.SetResolution(resolution, resolution)
        Using g = Graphics.FromImage(bitmap)
            g.DrawImage(image, New Rectangle(Point.Empty, image.Size),
                               New Rectangle(Point.Empty, image.Size), GraphicsUnit.Pixel)
            Dim codec = ImageCodecInfo.GetImageEncoders().
                        FirstOrDefault(Function(enc) enc.FormatID = ImageFormat.Tiff.Guid)
            Dim qualityParam =
                New EncoderParameter(ImageCodec.Quality, compressionLevel)
            Dim compressionParam =
                New EncoderParameter(ImageCodec.Compression, EncoderValue.CompressionLZW)
            Using codecParms = New EncoderParameters(2)
                codecParms.Param(0) = qualityParam
                codecParms.Param(1) = compressionParam
                bitmap.Save(fileName, codec, codecParms)
            End Using
        End Using
    End Using
End Sub

C# 版本

using System.Drawing;
using System.Drawing.Imaging;
using ImageCodec = System.Drawing.Imaging.Encoder;

private void SaveTiffImage(Image image, float resolution, long compressionLevel, string fileName)

    resolution = Math.Max(72, Math.Min(2400, resolution));
    compressionLevel = Math.Max(0, Math.Min(100, compressionLevel));

    using (var bitmap = new Bitmap(image.Width, image.Height, PixelFormat.Format24bppRgb))
    
        bitmap.SetResolution(resolution, resolution);
        using (var g = Graphics.FromImage(bitmap))
        
            g.DrawImage(image, new Rectangle(Point.Empty, image.Size), 
                               new Rectangle(Point.Empty, image.Size), GraphicsUnit.Pixel);
            var imageCodec = ImageCodecInfo.GetImageEncoders()
                                .FirstOrDefault(enc => enc.FormatID == ImageFormat.Tiff.Guid);
            if (imageCodec == null)
                throw new NotSupportedException("TIFF Conversion not suppoted", 
                      new NullReferenceException("TIFF Codec reference missing"));
            var qualityParam = 
                new EncoderParameter(ImageCodec.Quality, compressionLevel);
            var compressionParam = 
                new EncoderParameter(ImageCodec.Compression, (long)EncoderValue.CompressionLZW);
            using (var codecParms = new EncoderParameters(2))
            
                codecParms.Param[0] = qualityParam;
                codecParms.Param[1] = compressionParam;
                bitmap.Save(fileName, imageCodec, codecParms);
            
        
    

【讨论】:

您好,谢谢!需要进行一些更改才能消除错误 - 修改了 2 行 Dim qualityParam = New EncoderParameter(Encoder.Quality, compressionLevel) Dim compressionParam = New EncoderParameter(Encoder.Compression, EncoderValue.CompressionLZW) 为什么这个:Imports ImageCodec = System.Drawing.Imaging.Encoder 会产生错误?这是一个标准的Imports 修改,以避免与使用相同名称的其他命名空间/类发生冲突。在这种情况下,Text.Encoder 命名空间。您使用的是什么版本的 Visual Studio? 嗨 Jimi - 这可能是问题吗?这里有 3 个变化。 . . Imports ImageCodec = System.Drawing.Imaging.Encoder - VS 说不需要,但是引用 ImageCodec 的 2 行被修改为使用 encoder.Quality 和 Encoder.Compression (Dim qualityParam = New EncoderParameter(encoder.Quality, compressionLevel) Dim compressionParam = New EncoderParameter(encoder.Compression, EncoderValue.CompressionLZW)) Visual Studio 说什么并不重要。该 Import 是必需的,您可以保持原样。 ImageCodecSystem.Drawing.Imaging.Encoder,最好保留原样,因为您可能还需要对 System.Text 的引用(它也有一个 Encoder 类),并且此设置避免了在导入两个命名空间时出现的冲突。我仍然不知道您是否能够转换图像。 嗨,谢谢 - 问题是 VS2015 - 我切换到 VS2019(有点小悲伤)并将代码改回你的建议,瞧 - 得到了我的第一个 TIF!下一个任务是将位置数据添加为标签,以便 ArcMap 可以加载文件并使用 WGS84 正确显示它

以上是关于无法使用 GDI+ 保存 TIF 文件的主要内容,如果未能解决你的问题,请参考以下文章

怎样用matlab保存剪切的tif图像?

Imagemagick无法从tif转换为jpg

在 GDI+ 或 WPF 中保存透明 GIF

致命错误LNK1104:无法打开文件'gdi32.lib'

windows gdi截屏使用libjpeg保存jpg文件

无法从 Win32 C++ GDI+ 中的函数返回图形对象