Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation on 11/22/24 in Posts

  1. Remy Lebeau

    Unable to save from TImage to file

    I don't see how that is possible given the bugs I mentioned in the code you showed. Also, I just now noticed another bug I didn't see earlier - your server code is not synchronizing the call to SaveImageToDisk(). OK, but the rest of the server code you showed is still buggy. First off, you should not be calling TIdTCPClient.Connect() in the main UI thread. In fact, modern Android versions do not allow any network operations on the main thread at all. Second, that client send code does not match the server read code you showed earlier! Your client is sending the JSON using IOHandler.WriteLn(), but your server is reading the JSON using IOHandler.ReadStream(). That will not work! You need to use IOHandler.ReadLn() on the server side, eg: procedure TMainForm.SendPicture; var Host, Msg: string; Port: Integer; begin {$IFDEF MSWINDOWS} FImageFilePath := TPath.Combine(TPath.GetDocumentsPath, EditImage.Text); {$ENDIF} {$IFDEF ANDROID} FImageFilePath := TPath.Combine(TPath.GetSharedDocumentsPath, SetupForm.EditImage.Text); {$ENDIF} if not FileExists(FImageFilePath) then begin ShowMessage('No such file at ' + FImageFilePath + '!'); Exit; end; Host := SetupForm.EditHost.Text.Trim; if Host.IsEmpty then begin ShowMessage('Wrong host value!'); Exit; end; if not TryStrToInt(SetupForm.EditPort.Text, Port) then begin ShowMessage('Wrong port value!'); Exit; end; Msg := Edit1.Text; TTask.Run( procedure var MemoryStream: TMemoryStream; JObj: TJSONObject; JsonStr: string; begin try JObj := TJSONObject.Create; try MemoryStream := TMemoryStream.Create; try MemoryStream.LoadFromFile(FImageFilePath); JObj.AddPair('image_encoded', TIdEncoderMIME.EncodeStream(MemoryStream)); finally MemoryStream.Free; end; JObj.AddPair('message', Msg); JsonStr := JObj.ToJSON; finally JObj.Free; end; if IdTCPClient1.Connected then IdTCPClient1.Disconnect; IdTCPClient1.Host := Host; IdTCPClient1.Port := Port; try IdTCPClient1.Connect; except TThread.Queue(nil, procedure begin ShowMessage('Connection error!'); end); Exit; end; try try IdTCPClient1.IOHandler.WriteLn(JSonStr); finally IdTCPClient1.Disconnect; end; except TThread.Queue(nil, procedure begin ShowMessage('Send error!'); end); Exit; end; TThread.Queue(nil, procedure begin ShowMessage('BASE64 Image and message successfully sent to server!'); end); except on E: Exception do begin TThread.Queue(nil, procedure begin ShowMessage('Error! ' + E.Message); end); end; end; end); end; procedure TMainForm.IdTCPServer1Execute(AContext: TIdContext); var JSON: TJSONObject; MemoryStream: TMemoryStream; JsonStr, Msg: String; begin AContext.Connection.IOHandler.MaxLineLength := MaxInt; JsonStr := AContext.Connection.IOHandler.ReadLn; MemoryStream := nil; try JSON := TJSONObject.ParseJSONValue(JsonStr) as TJSONObject; try MemoryStream := TMemoryStream.Create; TIdDecoderMIME.DecodeStream(JSON.GetValue('image_encoded').Value, MemoryStream); Msg := JSON.GetValue('message').Value; finally JSON.Free; end; MemoryStream.Position := 0; TThread.Synchronize(nil, procedure begin Edit2.Text := Msg; Image1.Bitmap.LoadFromStream(MemoryStream); end); finally MemoryStream.Free; end; TThread.Synchronize(nil, SaveImageToDisk); end; However, if there is any possibility that the JSON may have any embedded line breaks, then using IOHandler.WriteLn/ReadLn will not work, so you should use IOHandler.Write(TStream) with IOHandler.ReadStream/ReadString() instead, eg: procedure TMainForm.SendPicture; var Host, Msg: string; Port: Integer; begin {$IFDEF MSWINDOWS} FImageFilePath := TPath.Combine(TPath.GetDocumentsPath, EditImage.Text); {$ENDIF} {$IFDEF ANDROID} FImageFilePath := TPath.Combine(TPath.GetSharedDocumentsPath, SetupForm.EditImage.Text); {$ENDIF} if not FileExists(FImageFilePath) then begin ShowMessage('No such file at ' + FImageFilePath + '!'); Exit; end; Host := SetupForm.EditHost.Text.Trim; if Host.IsEmpty then begin ShowMessage('Wrong host value!'); Exit; end; if not TryStrToInt(SetupForm.EditPort.Text, Port) then begin ShowMessage('Wrong port value!'); Exit; end; Msg := Edit1.Text; TTask.Run( procedure var MemoryStream: TMemoryStream; StringStream: TStringStream; JObj: TJSONObject; begin try StringStream := nil; try JObj := TJSONObject.Create; try MemoryStream := TMemoryStream.Create; try MemoryStream.LoadFromFile(FImageFilePath); JObj.AddPair('image_encoded', TIdEncoderMIME.EncodeStream(MemoryStream)); finally MemoryStream.Free; end; JObj.AddPair('message', Msg); StringStream := TStringStream.Create(JObj.ToJSON, TEncoding.UTF8); finally JObj.Free; end; if IdTCPClient1.Connected then IdTCPClient1.Disconnect; IdTCPClient1.Host := Host; IdTCPClient1.Port := Port; try IdTCPClient1.Connect; except TThread.Queue(nil, procedure begin ShowMessage('Connection error!'); end); Exit; end; try try IdTCPClient1.IOHandler.LargeStream := False; IdTCPClient1.IOHandler.Write(StringStream, 0, True); finally IdTCPClient1.Disconnect; end; except TThread.Queue(nil, procedure begin ShowMessage('Send error!'); end); Exit; end; finally StringStream.Free; end; TThread.Queue(nil, procedure begin ShowMessage('BASE64 Image and message successfully sent to server!'); end); except on E: Exception do begin TThread.Queue(nil, procedure begin ShowMessage('Error! ' + E.Message); end); end; end; end); end; procedure TMainForm.IdTCPServer1Execute(AContext: TIdContext); var JSON: TJSONObject; MemoryStream: TMemoryStream; StringStream: TStringStream; // alternatively: // JSONStr: string; Msg: String; begin MemoryStream := nil; try StringStream := TStringStream.Create('', TEncoding.UTF8); try AContext.Connection.IOHandler.LargeStream := False; AContext.Connection.IOHandler.ReadStream(StringStream, -1, False); JSON := TJSONObject.ParseJSONValue(StringStream.DataString) as TJSONObject; finally StringStream.Free; end; // alternatively: // JSONStr := AContext.Connection.IOHandler.ReadString(AContext.Connection.IOHandler.ReadInt32); // JSON := TJSONObject.ParseJSONValue(JSONStr) as TJSONObject; try MemoryStream := TMemoryStream.Create; TIdDecoderMIME.DecodeStream(JSON.GetValue('image_encoded').Value, MemoryStream); Msg := JSON.GetValue('message').Value; finally Json.Free; end; MemoryStream.Position := 0; TThread.Synchronize(nil, procedure begin Edit2.Text := Msg; Image1.Bitmap.LoadFromStream(MemoryStream); end); finally MemoryStream.Free; end; TThread.Synchronize(nil, SaveImageToDisk); end;
  2. Here an example: program Crcr32Demo; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.ZLib; var Buf1 : AnsiString; Buf2 : String; Crc : UInt32; begin Buf1 := 'Hello World!'; Crc := System.ZLib.Crc32(0, PByte(Buf1), Length(Buf1) * Sizeof(Buf1[1])); WriteLn('AnsiString ID=', IntToHex(Crc, 8)); Buf2 := 'Hello World!'; Crc := System.ZLib.Crc32(0, PByte(Buf2), Length(Buf2) * Sizeof(Buf2[1])); WriteLn('UnicodeString ID=', IntToHex(Crc, 8)); ReadLn; end. The output is: AnsiString ID=1C291CA3 UnicodeString ID=E2106423 AnsiString and Unicode string doesn't produce the same result because character code are different (8 bit and 16 bit per character). and CRC32 work at the byte level.
×