Hugh Jones
Hugh Jones

Reputation: 2694

Transferring Images from .NET to Delphi

I wonder if anyone can advise. I have written a .NET 4 WCF service which is intended to serve scanned documents and am struggling to get a Delphi 7 consumer to work.

On the .NET side I am converting Images to Bitmaps and then to Arrays of Byte using the following code :

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

On the Consumer side I want to read the ByteArray into a TImage.Picture and this is where the plan has foundered. The following code errors on the 'LoadFromStream' line with

EInvalidGraphic with message 'Bitmap image is not valid'

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;

By using a TFileStream in place of the memory stream above I have demonstrated that the data are valid - that is I can load the result in MSPaint. I have to admit I am stuck for the next step : Is Delphi 7 too outdated to handle modern bitmaps ? Is the fact that the files on the server side are tiffs and jpgs relevant? What should I do next ?

Any advice gratefully received.

UPDATE -------------------

I altered the code so that a JPG was being passed across and the results are very similar. This time I get JPEG Error #53 when I try and Load the image client-side. If I use a TFileStream and save to disk the resultant file looks fine with Windows Picture Viewer, but still will not load into the TImage Component.

Client Side now looks like this

  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;

Server-side (publishing the whole data contract this time in case)

    [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);
        }
    }
}

UPDATE -----------------------------------------------------------------

A successful test of the service from a Winforms consumer used the following code.

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; 
    }
}   

Upvotes: 1

Views: 1177

Answers (3)

Bob Riddle
Bob Riddle

Reputation: 339

Unless you are OK with staying with a Bitmap image, you might want to try reading the image from stream via TJPegImage (out of the JPeg unit). I'm doing something similar to what you're attempting, but am getting the image bytes direct from a .Net 4 wrapper around a .Net imaging library via AtoZed's "CrossTalk" product.

So first I'm having to convert a .Net MemoryStream object passed across the boundary to a Delphi array of byte. I then load it into a Delphi TMemoryStream and bring it into the TJpegImage.

(I initially had the same problem that you did until I decided that the LoadfromFile was apparently tailoring how the load was done based on the filename. Based on that, I explicitly created the proper image variant for JPegs, Tiffs, etc. instead of trying to load it as a generic TImage.)

This works for me with Delphi7 when the image being returned was a Jpeg:

  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;

Upvotes: 1

Hugh Jones
Hugh Jones

Reputation: 2694

Sorry, everyone - this turned out to be a red-herring. The issue was that the images I was serving were not valid in the first place. A quick 'phone call to a third-party vendor was all that was necessary.

On the plus-side, it means the code samples I provided are basically sound.

Upvotes: 1

Dai
Dai

Reputation: 155558

I get the impression that you're getting WCF to take care of the process of marshalling and serialising data between the server and the clients (both auto-generated for you by tools?) and that you don't really have much control over the "on-the-wire" format, and now you want to write a client in Delphi 7 that can read this.

I'll warn you that you're in for an uphill struggle, but if your WCF is using SOAP messages then you've got a chance as you should be able to write a SOAP client in Delphi that consumes your WCF service's messages.

As for the images themselves, I don't know how they're serialized. But once you find out it should be easy. Assuming that WCF is not simply serializing a System.Drawing.Bitmap and is instead transferring the raw bytes of a Bitmap file on-disk then you're all set: just dump the WCF message's bytes to disk or an in-memory buffer and open them with TBitmap.

Upvotes: 1

Related Questions