【问题标题】:Transferring Images from .NET to Delphi将图像从 .NET 传输到 Delphi
【发布时间】:2012-08-08 07:28:00
【问题描述】:

我想知道是否有人可以提供建议。我编写了一个 .NET 4 WCF 服务,该服务旨在为扫描的文档提供服务,并且正在努力让 Delphi 7 使用者工作。

在 .NET 方面,我使用以下代码将图像转换为位图,然后转换为字节数组:

        using (Bitmap img = new Bitmap(fileName))
        {
            ImageConverter converter = new ImageConverter();
            _bytes = (byte[])converter.ConvertTo(img, typeof(byte[]));
        }

在消费者方面,我想将 ByteArray 读入 TImage.Picture,这就是计划失败的地方。带有

的“LoadFromStream”行上的以下代码错误

带有消息“位图图像无效”的 EInvalidGraphic

procedure TBarcodeImageForm.FetchFile;
var
  bytes : TByteDynArray;
  info  : TDocInfo;
  Stream : TMemoryStream;
  bmp : TBitMap;
begin
  info := TDocInfo(FDocList.Items[lbFIles.ItemIndex]);
  bytes := FDocButton.FetchDocument(info.FilePath).Data;
  stream := TMemoryStream.Create();
  try
    Stream.Write(bytes[0], Length(Bytes));
    Stream.Position := 0;
    bmp := TBitMap.Create;
    bmp.LoadFromStream(stream);
  finally
    Stream.Free;
  end; 
end;

通过使用 TFileStream 代替上面的内存流,我已经证明数据是有效的——也就是说,我可以在 MSPaint 中加载结果。我不得不承认我被困在下一步:Delphi 7 是否过于过时而无法处理现代位图?服务器端的文件与 tiffs 和 jpgs 相关吗?接下来我该怎么办?

感谢您的任何建议。

更新-------

我更改了代码,以便传递 JPG,结果非常相似。这次我在尝试加载图像客户端时收到 JPEG 错误 #53。如果我使用 TFileStream 并保存到磁盘,则生成的文件在 Windows 图片查看器中看起来不错,但仍不会加载到 TImage 组件中。

客户端现在看起来像这样

  stream := TFileStream.Create('c:\temp.jpg', fmCreate);
  try
    Stream.Write(bytes[0], Length(Bytes));
    Stream.Position := 0;
  finally
    Stream.Free;
  end;

  try
    imgDocument.Picture.LoadFromFile('c:\temp.jpg');
  except end;

服务器端(这次发布整个数据合约以防万一)

    [DataContract]
public class ImageData
{
    private byte[] _bytes;

    [DataMember]
    public byte[] Data
    {
        get { return _bytes; }
        set { _bytes = value; }
    }

    public ImageData(string fileName)
    {
        using (MemoryStream memStream = new MemoryStream())
        {
            using (Image img = Image.FromFile(fileName))
            {
                img.Save(memStream, ImageFormat.Jpeg);
            }
            _bytes = new Byte[memStream.Length];
            int i = 0;
            while (i < memStream.Length)
                i += memStream.Read(_bytes, i, 128000);
        }
    }
}

更新 ---------------------------------------------- -------------------

来自 Winforms 消费者的服务成功测试使用了以下代码。

if (docList != null)
{
    using (MemoryStream memStream = 
        new MemoryStream(client.FetchDocument(docList.Items[0].FilePath).Data))
    {
        System.Drawing.Image img = Image.FromStream(memStream); 
        pictureBox1.Image = img; 
    }
}   

【问题讨论】:

  • 发布问题的实际情况总是有帮助的。如果基于代码,则显示您所拥有的。如果基于设计,请告诉我们您的想法。
  • 很抱歉,我还没准备好就提出了这个问题
  • 这可能与您正在序列化位图(JPEG 或 TIFF)以外的内容有关。 Delphi 的TBitmap 需要一个有效的位图头。您可以尝试使用TJPegImage.LoadFromStream 并测试获取 JPEG;如果这样可以解决问题,您可能还可以找到 D7 的 TIFF 组件;您必须从数组中读取前几个字节以确定您正在接收哪种类型的图像并创建适当的图形来处理它。
  • 我不一定要使用 TBitMap,我只是假设它是最低公分母。实际扫描的文档可能有多种格式。我将尝试使用 jpeg,看看它们是否更可靠。关于为什么 MSPaint 可以读取输出但 TBitMap 不能的任何想法?
  • @Hugh - 可能。尽管您正在测试的查看器可能会容忍无效文件。使用您知道 D7 的 TImage 能够显示的图像程序(使用相同的格式,即 A8R8G8B8 等)重新保存其中一个文件,然后您可以通过区分标题来确定文件的问题。

标签: .net wcf delphi


【解决方案1】:

我的印象是,您让 WCF 负责在服务器和客户端之间编组和序列化数据的过程(两者都是由工具为您自动生成的?)而且您实际上并没有太多控制“在线”格式,现在您想在 Delphi 7 中编写一个可以读取此格式的客户端。

我会警告您,您将面临一场艰苦的斗争,但如果您的 WCF 使用 SOAP 消息,那么您就有机会在 Delphi 中编写一个使用 WCF 服务的 SOAP 客户端消息。

至于图像本身,我不知道它们是如何序列化的。但是一旦你发现它应该很容易。假设 WCF 不是简单地序列化 System.Drawing.Bitmap 而是在磁盘上传输 Bitmap 文件的原始字节,那么您就一切就绪:只需将 WCF 消息的字节转储到磁盘或内存缓冲区并打开使用 TBitmap。

【讨论】:

  • 我非常小心地指定了数据协定 - 'fetchFile' 方法返回一个字节数组。我的所有其他方法都可以很好地工作。在 Delphi 方面,我依靠 wsdlImp 创建界面,但我很确定接收到的数据是预期的——正如我在帖子中所说——如果我将接收到的流保存到文件中,它是一个非常好的图形。
  • 您的第三段几乎总结了我的问题 - 它应该是直截了当的,但它不起作用。是的,我正在使用 SOAP。
  • 问题不在于 Delphi 中的位图支持,而是 WCF 到 Delphi-SOAP-RTL 阻抗不匹配。 Delphi 的 SOAP RTL 不能无缝处理所有可能的 WCF API 签名(您称它们为数据契约)。我多么希望它可以。
  • @Warren - 我已经设法解决了 WCF 到 Delphi 的问题。我发现通过在数据契约中非常明确,加上从 Embarcadero 安装 Soap 补丁,WSDLImp 可以毫无问题地创建一个好的接口。我可以看到,如果服务不在我的控制之下,那将是另一回事。
【解决方案2】:

对不起,大家 - 这原来是一个红鲱鱼。问题是我提供的图像首先是无效的。只需快速致电第三方供应商即可。

从好的方面来说,这意味着我提供的代码示例基本上是合理的。

【讨论】:

    【解决方案3】:

    除非您可以使用位图图像,否则您可能想尝试通过 TJPegImage(在 JPeg 单元之外)从流中读取图像。我正在做类似于您正在尝试的事情,但是我通过 AtoZed 的“CrossTalk”产品直接从 .Net 4 包装器中获取图像字节。

    所以首先我必须将跨越边界的.Net MemoryStream 对象转换为Delphi 字节数组。然后我将其加载到 Delphi TMemoryStream 中,并将其带入 TJpegImage。

    (我最初遇到了与您相同的问题,直到我决定 LoadfromFile 显然是根据文件名定制加载方式。基于此,我明确地为 JPegs、Tiffs 等创建了正确的图像变体。而不是尝试将其作为通用 TImage 加载。)

    当返回的图像是 Jpeg 时,这适用于 Delphi7:

      dJpegImage: TJpegImage;
      imageMemoryStream: MemoryStream;
      pictureBoxImageOutput: TImage;
      lengthImageByteArray: Integer;   // already set before this fragment based on the .Net Image info
      imageDelphiByteArray: array of byte;
      ...
      ...
      imageStream := TMemoryStream.Create();
      imageStream.WriteBuffer(imageDelphiByteArray[0], lengthImageByteArray);
      imageStream.Position := 0;
      dJpegImage := TJPEGImage.Create;
      dJpegImage.LoadFromStream(imageStream);
      pictureBoxImageOutput.Picture.Graphic := dJpegImage;
    

    【讨论】:

    • 谢谢你——这就是客户端现在的样子——显然最好不要打磁盘客户端。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-24
    • 2011-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多