Reputation: 155
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;
Upvotes: 0
Views: 14648
Reputation: 21
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;
Upvotes: 0
Reputation: 596256
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;
Upvotes: 1
Reputation: 612964
Your code has many flaws:
TImage
incorrectly. That's a GUI control. Use TBitmap
directly if you need to work with a bitmap. 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;
Upvotes: 2