matrix1233 0 Posted December 22, 2020 (edited) Hi, Am using Lazarus(FPC) and am trying to execute the Demo29 (work perfectly on delphi). the problem when i open Image and i Execute (Use Device Context Unchecked) the program go to the end and Image1.Picture.Graphic.LoadFromStream(_stream); raise an exception Wrong Image Format if (Image1.Picture.Graphic = nil) or Image1.Picture.Graphic.Empty then raise Exception.Create('You must first select an image'); PythonEngine1.ExecStrings(Memo1.Lines); _im := MainModule.ProcessImage(ImageToPyBytes(Image1.Picture.Graphic)); if not chkUseDC.Checked then begin // We have to call PyString_AsStringAndSize because the image may contain zeros with GetPythonEngine do begin pargs := MakePyTuple([ExtractPythonObjectFrom(_im)]); try presult := PyEval_CallObjectWithKeywords( ExtractPythonObjectFrom(MainModule.ImageToBytes), pargs, nil); try if (P = nil) or (PyBytes_AsStringAndSize(presult, P, Len) < 0) then begin ShowMessage('This does not work and needs fixing'); Abort; end; finally Py_XDECREF(pResult); end; finally Py_DECREF(pargs); end; end; _stream := TMemoryStream.Create(); try _stream.Write(P^, Len); _stream.Position := 0; Image1.Picture.Graphic.LoadFromStream(_stream); finally _stream.Free; end; end else begin Image1.Picture.Bitmap.SetSize(Image1.Width, Image1.Height); _dib := Import('PIL.ImageWin').Dib(_im); Image1.Picture.Bitmap.SetSize(Image1.Height, Image1.Width); _dib.expose(NativeInt(Image1.Picture.Bitmap.Canvas.Handle)); end; How can i correct that ? Thanks . Edited December 22, 2020 by matrix1233 Share this post Link to post
Fr0sT.Brutal 900 Posted December 22, 2020 Just save the _stream to disc and see what it contains Share this post Link to post
matrix1233 0 Posted December 22, 2020 Hi the file is saved and his size is 197k and the content is "þîþîþîþîþî.." (from the begin to end) Share this post Link to post
Fr0sT.Brutal 900 Posted December 22, 2020 So you receive garbage. You'll have to debug that stage Share this post Link to post
Virgo 18 Posted December 22, 2020 Looking original code in unit1.pas from git: value of P is undefined there, because it is never initialized. What happens, if you add p := nil; at the beginning of Button2Click? Share this post Link to post
matrix1233 0 Posted December 22, 2020 if p := nil then i have the msg 'This does not work and needs fixing' if (Image1.Picture.Graphic = nil) or Image1.Picture.Graphic.Empty then raise Exception.Create('You must first select an image'); PythonEngine1.ExecStrings(Memo1.Lines); _im := MainModule.ProcessImage(ImageToPyBytes(Image1.Picture.Graphic)); if not chkUseDC.Checked then begin P := nil; // We have to call PyString_AsStringAndSize because the image may contain zeros with GetPythonEngine do begin pargs := MakePyTuple([ExtractPythonObjectFrom(_im)]); try presult := PyEval_CallObjectWithKeywords( ExtractPythonObjectFrom(MainModule.ImageToBytes), pargs, nil); try if (P = nil) or (PyBytes_AsStringAndSize(presult, P, Len) < 0) then begin ShowMessage('This does not work and needs fixing'); Abort; end; finally Py_XDECREF(pResult); end; finally Py_DECREF(pargs); end; end; _stream := TMemoryStream.Create(); try _stream.Write(P^, Len); _stream.Position := 0; _stream.SaveToFile('test.jpeg'); // Image1.Picture.Graphic.LoadFromStream(_stream); finally _stream.Free; end; end else begin Image1.Picture.Bitmap.SetSize(Image1.Width, Image1.Height); _dib := Import('PIL.ImageWin').Dib(_im); Image1.Picture.Bitmap.SetSize(Image1.Height, Image1.Width); _dib.expose(NativeInt(Image1.Picture.Bitmap.Canvas.Handle)); end; Share this post Link to post
matrix1233 0 Posted December 22, 2020 i think that the problem is on MainModule.ImageToBytes because on Delphi when i try to display it to a memo (Memo3.Lines.Add(MainModule.ImageToBytes); ) i have <function ImageToBytes at 0x00000000068DDCA0> but when i try the same code on Lazarus i have nothing . any idea how can i resolve on lazarus ? Share this post Link to post
Virgo 18 Posted December 22, 2020 Right, there was or, so p value was red herring. Although (p=nil) check is invalid anyway, because value of p is undefined there. Share this post Link to post
matrix1233 0 Posted December 22, 2020 (edited) the problem is not P, i think that is just MainModule.ImageToBytes like i explained above .. any idea ? Edited December 22, 2020 by matrix1233 Share this post Link to post
Virgo 18 Posted December 23, 2020 After reading Python documentation I do not understand, how it can work in Delphi. Move _stream := TMemoryStream.Create(); try _stream.Write(P^, Len); _stream.Position := 0; Image1.Picture.Graphic.LoadFromStream(_stream); finally _stream.Free; end; before finally Py_XDECREF(pResult); end; P will be reference to internal buffer in pResult and Py_XDECREF(pResult); frees that memory. 1 Share this post Link to post
Virgo 18 Posted December 23, 2020 But also, from if (P = nil) or (PyBytes_AsStringAndSize(presult, P, Len) < 0) then begin "(p = nil) or" should be removed, because P is uninitialized, which only means, that it causes error, when P happens coincidentally initialize to nil. Share this post Link to post
matrix1233 0 Posted December 23, 2020 yes i see! .. between Delphi and Lazarus the result of execution are different for example this code below With Delphi work perfectly and with lazarus it doesn't work and it say that ( 'This does not work and needs fixing' ) generated by the test on PyBytes_AsStringAndSize. Any idea for this example why it's different ? var _im : Variant; _dib : Variant; i:integer; pargs: PPyObject; pResult :PPyObject; P : PAnsiChar; _stream:TmemoryStream; Len : NativeInt; SPython:TstringList; begin SPython:=TstringList.Create; SPython.Add('from io import BytesIO'); SPython.Add('from PIL import ImageGrab'); SPython.Add('def screenshot():'); SPython.Add(' im = ImageGrab.grab()'); SPython.Add(' stream = BytesIO()'); SPython.Add(' im.save(stream, "BMP")'); SPython.Add(' return stream.getvalue()'); SPython.Add('screenshot()'); PythonEngine1.ExecStrings(SPython); with GetPythonEngine do begin try pResult := ExtractPythonObjectFrom(MainModule.screenshot()); if (PyBytes_AsStringAndSize(pResult, P, Len) < 0) then begin ShowMessage('This does not work and needs fixing'); Abort; end; finally _stream := TMemoryStream.Create(); try _stream.Write(P^, Len); _stream.Position := 0; Memo2.Lines.add(_stream.Size.ToString); Image1.Picture.LoadFromStream(_stream); application.ProcessMessages; finally _stream.Free; end; end; end; Share this post Link to post
pyscripter 689 Posted December 23, 2020 (edited) The fpc support for custom variants is incomplete. See the fpc section at SupportedPlatforms · pyscripter/python4delphi Wiki (github.com). Does it work if you store MainModule.screenshot() to a variable and then call ExtractPythonObjectFrom like in the previous example? Edited December 23, 2020 by pyscripter Share this post Link to post
matrix1233 0 Posted December 23, 2020 Hi, i stored MainModule.screenshot() to a variable _im like you asked and it doesn't work (See the first code below) but when i change the line where pResult are affected with presult := PyEval_CallObjectWithKeywords(ExtractPythonObjectFrom(MainModule.screenshot()), nil, nil), it work on lazarus . (See the second code below) . i think that ExtractPythonObjectFrom are only needed to do the job and adding PyEval_CallObjectWithKeywords is not needed in this case but lazarus have some bugs .. we can perhaps correct this ? var _im : Variant; _dib : Variant; i:integer; pargs: PPyObject; pResult :PPyObject; P : PAnsiChar; _stream:TmemoryStream; Len : NativeInt; SPython:TstringList; begin SPython:=TstringList.Create; SPython.Add('from io import BytesIO'); SPython.Add('from PIL import ImageGrab'); SPython.Add('def screenshot():'); SPython.Add(' im = ImageGrab.grab()'); SPython.Add(' stream = BytesIO()'); SPython.Add(' im.save(stream, "BMP")'); SPython.Add(' return stream.getvalue()'); SPython.Add('screenshot()'); PythonEngine1.ExecStrings(SPython); _im:=MainModule.screenshot(); with GetPythonEngine do begin try pResult := ExtractPythonObjectFrom(_im); if (PyBytes_AsStringAndSize(pResult, P, Len) < 0) then begin ShowMessage('This does not work and needs fixing'); Abort; end; finally _stream := TMemoryStream.Create(); try _stream.Write(P^, Len); _stream.Position := 0; Memo2.Lines.add(_stream.Size.ToString); Image1.Picture.LoadFromStream(_stream); application.ProcessMessages; finally _stream.Free; end; end; end; var _im : Variant; _dib : Variant; i:integer; pargs: PPyObject; pResult :PPyObject; P : PAnsiChar; _stream:TmemoryStream; Len : NativeInt; SPython:TstringList; begin SPython:=TstringList.Create; SPython.Add('from io import BytesIO'); SPython.Add('from PIL import ImageGrab'); SPython.Add('def screenshot():'); SPython.Add(' im = ImageGrab.grab()'); SPython.Add(' stream = BytesIO()'); SPython.Add(' im.save(stream, "BMP")'); SPython.Add(' return stream.getvalue()'); SPython.Add('screenshot()'); PythonEngine1.ExecStrings(SPython); with GetPythonEngine do begin try presult := PyEval_CallObjectWithKeywords(ExtractPythonObjectFrom(MainModule.screenshot()), nil, nil); if (PyBytes_AsStringAndSize(pResult, P, Len) < 0) then begin ShowMessage('This does not work and needs fixing'); Abort; end; finally _stream := TMemoryStream.Create(); try _stream.Write(P^, Len); _stream.Position := 0; Memo2.Lines.add(_stream.Size.ToString); Image1.Picture.LoadFromStream(_stream); application.ProcessMessages; finally _stream.Free; end; end; end; Share this post Link to post