【问题标题】:Delphi 2010 - Decode Base64 encoded image from XML docDelphi 2010 - 从 XML 文档解码 Base64 编码图像
【发布时间】:2010-04-15 11:19:46
【问题描述】:

我正在尝试从我的应用程序中的 XML 文档中解码 base64 编码的 EMF 图像并将其呈现在屏幕上,但是它似乎从未出现过。

如果我将 XML 文档中的数据复制/粘贴到 Notepad++ 中并使用Base64 Decode 选项并将文件另存为.emf,它会在 mspaint 中正常打开。所以我认为问题在于我如何解码它。

我尝试了这些文章中描述的以下解码方法:

How to encode / decode Base 64 string
http://www.swissdelphicenter.ch/torry/showcode.php?id=1223

我也尝试了TIdDecoderMIME 类,但无济于事。

有谁知道从 XML 解码 base64 编码字符串的最可靠方法?

示例

procedure TXmlSerializer.SaveImageFromString(const AValue: string);
var
  StrStream: TStringStream;
  Decoder: TIdDecoderMIME;
begin
  // AValue is base64 encoded string from XML doc
  Decoder := TIdDecoderMIME.Create(nil);
  try
    StrStream := TStringStream.Create(Decoder.DecodeString(AValue));
    try
      StrStream.SaveToFile('MyPath\Image.emf');
    finally
      StrStream.Free;
    end;
  finally
    Decoder.Free;
  end;
end;

为什么上述方法不起作用,但将原始数据复制到 Notepad++ 并解码并保存为.emf 有效?

【问题讨论】:

  • 你能给我们看一些代码吗?你用的是什么版本的德尔福?你用的是什么版本的 Indy?
  • @Fox:我已经标记了问题 Delphi 2010,并且它也在问题标题中.... indy 的版本将是我想象的 Delphi 2010 附带的任何版本。
  • 您是否在解码前检查了 AValue 的值以确保它包含整个 base64 编码值?
  • @Marcus 从我在手表上看到的,是的,看起来不错
  • @Marcus,确实,我一定看过 Delphi 2010 的标签和标题。

标签: delphi xml-serialization delphi-2010 base64


【解决方案1】:

您正在使用字符串来存储二进制数据; Delphi 2010 的 unicode-ness 可能是这里的“责备”。

尝试使用支持解码为流的base64解码器,直接解码为TFileStream;我使用JclMime(Jedi 的 JCL 的一部分),但如果没有适用于流而不是字符串的 Indy MIME 方法,我会感到惊讶。

由于JclMime 仅支持流到流解码,我在从 XML 有效负载中解码 base64 数据时使用以下包装器:

procedure MimeDecode(const inputString: string; const outputStream: Tstream);
var
  ss: TStringStream;
begin
  ss := TStringStream.Create(inputString);
  try
    JclMime.MimeDecodeStream(ss, outputStream);
  finally
    ss.free;
  end;
end;

【讨论】:

  • 在 Jame 的原始代码中,可以使用 TIdDecoderMIME 解码为 TStream。这就是 TIdDecoder 原生操作的内容。使用 TIdDecoder.DecodeBegin() 和 TIdDecoder.Decode() 方法代替 TIdDecoder.DecodeString() 方法(这是一个将内部解码的 TStream 转换为字符串的包装器)。
  • 我正在使用 JclMime 并将其写入文件并且它显示完美,不太明白为什么它不能正确显示......然后我意识到我没有重置位置!
【解决方案2】:

TIdDecoderMIME 工作得很好。尝试和测试。看看 Indy 提供的代码示例就知道了。

OmniXML 还具有 OmniXMLUtils.pas 单元,其中包含用于 XML 的各种实用程序功能。 在里面你可以找到独立的 Base64 编码/解码功能。您可以复制粘贴它们或按原样使用它们。

否则使用 TIdDecoderMIME 发布代码。一定是你的代码有错误。

编辑:

您必须注意将字符串以单字节顺序写入流。 Base64 适用于字节(ASCII 字符),如果您使用 2 字节 unicode 字符串提供它,它将无法正常工作。如果您将 Base64 编码序列作为字符串并将其按原样写入流中,则会出现错误,因为此类流的长度将是原始长度的两倍。

您可以使用 TStringStream 或使用 AnsiStrings 来完成任务。只要你坚持编码/解码就可以正常工作。

您也可以使用我的SimpleStorage,它会为您完成所有工作。从 XML 中读取图像非常简单:

  Jpeg := TJPEGImage.Create;
  try
    Jpeg.LoadFromStream(SrcStorage.Get('Image').Filter('gzip').AsBinary.Stream);
  finally
    Jpeg.Free;
  end;

是不是很简单(在这个过程中它也被解压了)。 :)

【讨论】:

  • 我已经发布了一个我在做什么的例子。基本上是尝试获取原始图像数据并将其保存为图像。
  • @Runner,看起来不错,但我不想介绍任何其他 3rd 方组件。
  • 明白。我只是发布它以供参考,以防有人发现它有用。无论如何检查我的建议。错误可能在那个区域。
【解决方案3】:

确保您只解码属性值而不是整个 XML。

在您的代码中,请务必在读取之前将流的位置设置为 0。

StrStream.Seek(0, soFromBeginning);

我不熟悉 TStringStream 的 SaveToFile() 方法。你确定吗?

此外,由于 Delphi 2010 支持 unicode 字符串,您可能希望在处理二进制数据时使用 AnsiStrings。将多字节字符类型与单字节数据混合时要小心。

【讨论】:

  • @Marcus,不要认为这对于这个特定的例子实际上很重要。反正在我把它写到文件之前就这样做了,但并没有什么不同。
  • nit:应该是 StrStream.Seek(0, soFromBeginning); :)
猜你喜欢
  • 2010-12-18
  • 1970-01-01
  • 2015-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-17
  • 2011-01-31
  • 1970-01-01
相关资源
最近更新 更多