shineworld 73 Posted April 11, 2022 Hi all, I'm using DelphiVCL + PyScripter to develop a Python windows application.I've created and "pyd" extension module in which perform some critical time operations or add support functions missing in DelphiVCL. - In python script I create an Image - now I would like to send a bytes array to cnc_vision_ext module (made with Delphi): import delphivcl import cnc_vision_ext as ext .... my_Image = delphivcl.Image(Form1) ext.update_image_from_bytes(my_image, 1024, 768, 3) Now in the wrapper CncVisionUpdateImageFromBytesArray_Wrapper I need to extract the TImage instance contained in PPyObject of args. I was not able to find the right way.... { generic functions wrappers } function CncVisionUpdateImageFromBytesArray_Wrapper(pself, args: PPyObject): PPyObject; cdecl; var Image: TImage; Width: Integer; Height: Integer; Channels: Integer; Bytes: TByteArray; ImagePyObj: PPyObject; begin with GetPythonEngine do begin if PyArg_ParseTuple(args, 'Oiii:update_image_from_bytes', @ImagePyObj, @Width, @Height, @Channels) <> 0 then begin // ??? HOW TO GET BACK wrapped TImage from Image() object created with my_image = delphivcl.Image(owner) ??? Image := TImage((PythonToDelphi(ImagePyObj) as TPyDelphiObject).DelphiObject); Result := PyUnicodeFromString ( Format('%s %d %d %d', [Image.Name, Width, Height, Channels]) ); end else Result := nil; end; end; { TPyExtensionManager } procedure TPyExtensionManager.WrapperInitializationEvent(Sender: TObject); begin FWrapper.RegisterDelphiWrapper(TPyCncVisionVideoCapturePxc_Wrapper); FWrapper.RegisterFunction ( PAnsiChar('update_image_from_bytes'), CncVisionUpdateImageFromBytesArray_Wrapper, PAnsiChar('update delphivcl Image object from bytes array with width, height & channels') ); FWrapper.RegisterFunction ( PAnsiChar('get_usb_camera_device_list'), CncVisionGetUSBCameraDeviceList_Wrapper, PAnsiChar('get list of available usb camera devices') ); end; Thanks in advance for the suggestions.... Best Regards Silverio Share this post Link to post
shineworld 73 Posted April 11, 2022 Seems this works but is hard to say OK, at moment, for me: { A B C +-------------------++------------------------------------------------------+ | PyObject header || TPyObject class | +----------+--------++-----------------+------------+----------+------------+ |ob_refcnt |ob_type ||hidden Class Ptr |PythonType |IsSubType |PythonAlloc | |integer |pointer ||pointer |TPythonType |Boolean |Boolean | |4 bytes |4 bytes ||4 bytes |4 bytes |1 byte |1 byte | +----------+--------++-----------------+------------+----------+------------+ ^ ^ | | ptr returned ptr returned by Adjust by GetSelf - a Python object must start at A. - a Delphi class class must start at B - TPyObject.InstanceSize will return C-B - Sizeof(TPyObject) will return C-B - The total memory allocated for a TPyObject instance will be C-A, even if its InstanceSize is C-B. - When turning a Python object pointer into a Delphi instance pointer, PythonToDelphi will offset the pointer from A to B. - When turning a Delphi instance into a Python object pointer, GetSelf will offset Self from B to A. - Properties ob_refcnt and ob_type will call GetSelf to access their data. } function CncVisionUpdateImageFromBytesArray_Wrapper(pself, args: PPyObject): PPyObject; cdecl; var Image: TImage; Width: Integer; Height: Integer; Channels: Integer; Bytes: TByteArray; ImagePyObj: PPyObject; begin with GetPythonEngine do begin if PyArg_ParseTuple(args, 'Oiii:update_image_from_bytes', @ImagePyObj, @Width, @Height, @Channels) <> 0 then begin Image := TPyDelphiImage(TPyObject(PAnsiChar(ImagePyObj)+Sizeof(PyObject))).DelphiObject; Result := PyUnicodeFromString ( Format('%s %d %d %d', [Image.Name, Width, Height, Channels]) ); end else Result := nil; end; end; Share this post Link to post