繁体   English   中英

如何以原始格式保存图像?

[英]How to save an image in its original format?

如何使用原始编码保存图像?

似乎保存图像的唯一方法是使用BitmapEncoder,但我不知道如何从图像中获取正确的格式。

例:

Clipboard.GetImage()返回一个InteropBitmap,它似乎不包含任何有关原始格式的信息。

我也尝试使用Extension方法:

public static void Save(this BitmapImage image, System.IO.Stream stream)
{
    var decoder = BitmapDecoder.Create(image.StreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
    var encoder = BitmapEncoder.Create(decoder.CodecInfo.ContainerFormat);
    foreach (var frame in decoder.Frames)
    {
        encoder.Frames.Add(BitmapFrame.Create(frame));
    }
    encoder.Save(stream);
}

但问题是

  1. 例如,ImageSource并不总是BitmapImage(Clipboard.GetImage())
  2. 在某些情况下,image.StreamSource可以为null(似乎是通过相对Uri加载图像时)

有什么建议?

这里的基本问题是“如何获取任意ImageSource并了解它最初编码的格式?”

答案是你不能总是这样做,但是对于大多数实际目的,有一个可用的解决方法。 正如您上面的代码所示,一旦您学会了使用哪种格式,其余的就很容易了。

你不能总是找到原始格式的原因是它可能(有一些非常棘手的代码!)继承BitmapSource来创建一个新的ImageSource,从你喜欢的任何地方获取它的数据。 例如,我可以实现一个返回随机像素的PseudoRandomBitmapSource。 在这种情况下,“原始格式”可能是用于随机数生成器的种子。

如果您正在处理其中一个内置的ImageSource类,找到原始编码的方法取决于您使用的确切类:

  1. 对于BitmapImage,您可以使用StreamSource或UriSource,无论设置哪一个。 其中任何一个都可以传递给BitmapDecoder.Create重载。 您的示例代码显示了如何为StreamSource执行此操作。 UriSource完全相同,除了你需要新的Uri(BaseUri, UriSource)并将它传递给带有Uri的BitmapDecoder.Create重载。

  2. 对于ColorConvertedBitmap,CroppedBitmap,FormatConvertedBitmap和TransformedBitmap,可以使用公共“Source”属性来获取基础源,然后使用此算法递归检查其编码。

  3. 对于CachedBitmap,您只能通过内部字段访问源位图。 如果你有足够的权限,你可以使用反射访问,否则你运气不好。

  4. 对于RenderTargetBitmap,WritableBitmap,D3DImage和DrawingImage,没有原始编码,因为图像是从矢量格式或算法“动态”构造的。

  5. 对于BitmapFrame,使用Decoder属性获取解码器,然后使用CodecInfo.ContainerFormat。

  6. 对于InteropBitmap或UnmanagedBitmapWrapper,它非常复杂。 基本上你需要使用反射来读取内部的WicSourceHandle属性,然后调用DangerousGetHandle()来获得一个IntPtr,它实际上是一个非托管的IUnkown。 使用非托管代码,IWICBitmapDecoder的QueryInterface。 如果成功,您可以调用IWICBitmapDecoder.GetContainerFormat来获取格式Guid(这仍然是非托管代码)。 如果没有,则有关原始来源的所有信息都已丢失。

正如您所看到的,有很多情况下您无法获取源(例如,InteropBitmap用于完全解码的位图)或获取源需要特殊技术和权限(InteropBitmap的非托管代码或内部字段的反射) for CachedBitmap)。

因为通常很难获得原始格式,所以在将信息传递到代码中时,寻找保存此信息的方法是个好主意。 如果您控制图像的源,它可能像创建ImageSourceAndFormat类一样简单:

public class BitmapSourceAndFormat
{
  public ImageSource Source { get; set; }
  public Guid OriginalFormat { get; set; }
}

如果要将图像放在剪贴板上,这将特别有用。 除了正常地将图像添加到DataObject之外,还可以添加BitmapSourceAndFormat对象。 如果这样做,粘贴操作将接收包含这两种格式的DataObject。 然后,您的代码只需要首先检查BitmapSourceAndFormat对象。 如果发现它可以简单地访问它以获得原始格式。 如果不是,则必须采用上述方法。

最后一点:对于剪贴板粘贴,您可以检查可用的数据格式字符串。 一些有用的是:Bitmap,Dib,Tiff,Gif,Jpeg和FileName。 对于“Tiff”,“Gif”和“Jpeg”,您可以对所需格式进行硬编码。 对于“FileName”,您可以自己打开文件以获取要传递给BitmapDecoder的流。 对于没有任何其他内容的“Dib”或“Bitmap”,您知道原始格式已丢失。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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