Question

I'm trying to send a picture of a DataSnap server to the client via Stream, more trying to open the stream on the client I get the error "range check error" I get this image of a url and need to send to the client via stream or otherwise.

    //SERVER
function TServerMethods1.DownloadImage(xUrlImg : String; out resp : String) : TStream;
var
  HTTP : TIdHttp;
  Stream : TStream;
  Image : TImage;
  stemp : String;
begin
 try
    HTTP := TIdHttp.Create(nil);
    try
      Stream := TMemoryStream.Create;
      try
        HTTP.ReadTimeout := 10000;
        HTTP.ConnectTimeout := 10000;
        HTTP.Get(xUrlImg, Stream);
        Stream.Position := 0;

        Image := TImage.Create(nil);
        Image.BitMap := TBitMap.Create(0, 0);
        Image.BitMap.LoadFromStream(Stream);
        sTEmp := DateTimeToStr(now).Replace('/', '').Replace(':', '') + '.jpg';
        Image.Bitmap.SaveToFile('C:\SISTEMAS\MOBILE\' + stemp);
        //Image.Free;

        Result := TMemoryStream.Create;
        Image.Bitmap.SaveToStream(Result);
        Result.Seek( 0, TSeekOrigin.soBeginning );
        Result.Position := 0;
        Image.Free;
        //Result.CopyFrom(Stream, 0);
        Stream.Free;
      finally
        //img := Stream;
        resp := '';
        //Stream.Free
      end
    finally
      HTTP.Free
    end;
 Except
   ON E: Exception do
     begin
       resp := 'ERRO: ' + E.Message;
     end;
 end;
end;

//client

    function TFPrin.SalvaImg(URL, xNomeImg : String) : Boolean;
var
  Stream : TStream;
  Image : TImage;
  pathImage,
  sTemp : String;
begin
 try
  Stream := TMemoryStream.Create;
  Stream := ClientModule1.ServerMethods1Client.DownloadImage(URL, sTemp);
  Stream.Position := 0;
  if Trim(sTemp) <> '' then
     begin
      //Stream.Free;
      ShowMessage('Erro: ' + sTemp);
      Exit;
     end;

  pathImage := GetDirPlat + xNomeImg;
  Image := TImage.Create(nil);
  //Image.BitMap := TBitMap.Create(0, 0);
  Image.BitMap.LoadFromStream(Stream);  **//ERROR - RANGE CHECK ERROR**
  Image.Bitmap.SaveToFile(pathImage);
  Image.Free;
  //Stream.Free

 Except
  On E: Exception do
    begin
       ShowMessage('Erro gerar imagem: ' + e.Message);
    end;
 end;
end;
Was it helpful?

Solution 2

Try something more like this:

//Server
function TServerMethods1.DownloadImage(xUrlImg : String; out resp : String) : TStream;
var
  HTTP : TIdHttp;
  Stream : TStream;
  Bmp : TBitmap;
  Fmt: TFormatSettings;
begin
  Result := nil;
  try
    Stream := TMemoryStream.Create;
    try
      HTTP := TIdHttp.Create(nil);
      try
        HTTP.ReadTimeout := 10000;
        HTTP.ConnectTimeout := 10000;
        HTTP.Get(xUrlImg, Stream);
      finally
        HTTP.Free;
      end;

      Bmp := TBitmap.Create(0, 0);
      try
        Stream.Position := 0;
        Bmp.LoadFromStream(Stream);

        Fmt := TFormatSettings.Create;
        Fmt.DateSeparator := #0;
        Fmt.TimeSeparator := #0;
        Bmp.SaveToFile('C:\SISTEMAS\MOBILE\' + DateTimeToStr(Now, Fmt) + '.jpg');

        Stream.Clear;
        Bmp.SaveToStream(Stream);
        Stream.Position := 0;
      finally
        Bmp.Free;
      end
    except
      Stream.Free;
      raise;
    end;
    Result := Stream;
  except
    on E: Exception do
    begin
      resp := 'ERRO: ' + E.Message;
    end;
  end;
end;

//client
function TFPrin.SalvaImg(URL, xNomeImg : String) : Boolean;
var
  Stream : TStream;
  Bmp : TBitmap;
  sTemp : String;
begin
  try
    Stream := ClientModule1.ServerMethods1Client.DownloadImage(URL, sTemp);
    if Stream = nil then
    begin
      ShowMessage('Erro: ' + sTemp);
      Exit;
    end;
    try
      Bmp := TBitmap.Create(0, 0);
      try
        Bmp.LoadFromStream(Stream);
        Bmp.SaveToFile(GetDirPlat + xNomeImg);
      finally
        Bmp.Free;
      end;
    finally
      Stream.Free;
    end;
  except
    on E: Exception do
    begin
      ShowMessage('Erro gerar imagem: ' + e.Message);
    end;
  end;
end;

OTHER TIPS

Your code has many flaws:

  • It is messy and full of comments for a start. That alone makes it hard for you to see what is going on.
  • You are leaking memory. At least one memory stream and likely more. Use full FastMM debug to track down and resolve these leaks if a static analysis won't find them.
  • You are using TImage incorrectly. That's a GUI control. Use TBitmap directly if you need to work with a bitmap.
  • But you don't need to work with a bitmap. All you trying to do is send a file from one machine to another.

Remove all the TBitmap and TImage code. Instead transmit the file between the machines by loading and saving the stream directly to disk. And then using the Indy components to transmit the stream. A TFileStream is what you need.

Once you've done this your code will be much simpler. If you still have an error you can investigate that in the context of code that is close to what you really need.

Your range check error appears to be in the code that you should remove, the code that works with bitmaps. That's why I've not addressed the error directly. Because that code should be removed anyway.

So, as an example, the call to TIdHttp.Get could well be written like this:

var
  FileStream: TFileStream;
....
FileStream := TFileStream.Create(FileName, fmCreate);
try
  HTTP.Get(xUrlImg, FileStream);
finally
  FileStream.Free;
end;

And now you have saved the file. Extend this to transferring to a memory stream result variable like so:

Result := TMemoryStream.Create;
try
  FileStream := TFileStream.Create(FileName, fmCreate);
  try
    HTTP.Get(xUrlImg, FileStream);
    FileStream.Position := 0;
    Result.CopyFrom(FileStream, FileStream.Size);
  finally
    FileStream.Free;
  end;
except
  Result.Free;
  raise;
end;

Or if you would rather read into the memory stream, and then copy to file that would go like this:

Result := TMemoryStream.Create;
try
  HTTP.Get(xUrlImg, Result);
  FileStream := TFileStream.Create(FileName, fmCreate);
  try
    Result.Position := 0;
    FileStream.CopyFrom(Result, Result.Size);
  finally
    FileStream.Free;
  end;
except
  Result.Free;
  raise;
end;

Your client code would look like this:

function TFPrin.SalvaImg(URL, xNomeImg: string): Boolean;
var
  Stream: TStream;
begin
  Stream := ClientModule1.ServerMethods1Client.DownloadImage(URL, sTemp);
  try
    Stream.Position := 0;
    FileStream := TFileStream.Create(GetDirPlat + xNomeImg, fmCreate);
    try
      FileStream.CopyFrom(Stream, Stream.Size);
    finally
      FileStream.Free;
    end;
  finally
    Stream.Free;
  end;
end;

The type of database field used to store the data will depend on the approach used. You can use the following solution if you would like to save something like a bitmap image into a database field of type "LargeText". If using a field of data type "BLOB" on the database table, some data will be lost in the saving process when using a memory stream, so I would recommend using a "LargeText" database field type for BLOB objects such as bitmaps.

//***** Table script example for storing bitmap images *****
CREATE TABLE `images` (
  `ImageID` int(11) NOT NULL AUTO_INCREMENT,
  `Image` longtext,
  PRIMARY KEY (`ImageID`)
);

//***** SET BITMAP IMAGE TO DATABASE FIELD FOR SAVING *****

//Load the bitmap image.
var bImage := TBitmap;
bImage := Image1.Picture.Bitmap;

//Prepare the memory stream.
var msImage := TMemoryStream.Create;
bImage.SaveToStream(msImage);

//Reset the memory stream before loading into field.
msImage.Position := 0;

//Load memory stream into query field for SQL execution.
Query1.ParamByName('pImage').LoadFromStream(msImage, ftMemo);
Query.Execute;

---------------------------------------------------------------------

//***** LOAD BITMAP IMAGE FROM DATABASE FIELD ******

//Extract data from query field into memory stream.
var msImage := TMemoryStream.Create;
(Query1.FieldByName('Image') as TMemoField).SaveToStream(msImage);

//Reset the memory stream.
msImage.Position := 0;

//Read data from memory stream into image.
var bImage := TBitmap;
bImage.LoadFromStream(msImage);

//Load extracted image to image component.
Image1.Picture.Bitmap := bImage;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top