Delphi版ZXing DLL的高性能bitmap跨边界封送方案咨询
内存流方案性能评估
- 你预估的封送开销确实存在:将TBitmap写入内存流需要做全量像素数据拷贝,每秒3次的调用频率下如果是1080P分辨率,单次拷贝大概是几毫秒级别,虽然不至于完全不可用,但属于无意义的性能浪费。
- 额外开销还包括内存流的内存分配、释放成本,如果使用压缩流格式开销还会进一步升高。
Windows平台最优跨DLL Bitmap传递方案
直接传递原生GDI位图句柄+位图参数是性能最高的实现,全程不需要做全量像素数据拷贝,封送开销几乎为0,实现逻辑如下:
- 主程序侧仅需要向DLL传递三个参数:
HBITMAP位图句柄、位图宽度、位图高度 - 如果DLL用Delphi开发,可以直接将传入的HBITMAP绑定到DLL本地的TBitmap对象,仅需一行代码
LocalBmp.Handle := 传入的HBITMAP,没有任何像素拷贝操作 - 如果DLL用其他语言开发,直接调用Windows API
GetObject读取位图头信息,再调用GetBitmapBits读取像素数据即可
优化后代码示例
主程序侧调用代码
// 提前声明DLL导出函数,用stdcall调用约定保证跨模块兼容 function ScanBitmap(hBmp: HBITMAP; bmpWidth, bmpHeight: Integer): PChar; stdcall; external 'YourZXingDll.dll'; procedure TForm1.BarCodeTimerTimer(Sender: TObject); var scanRes: PChar; begin // 直接传HBITMAP和尺寸参数,无全量数据拷贝 scanRes := ScanBitmap(_bmp.Handle, _bmp.Width, _bmp.Height); if scanRes <> nil then begin // 处理返回的条码结果 // 注意按约定释放返回的字符串内存 StrDispose(scanRes); end; end;
DLL侧实现代码
// DLL侧导出函数实现 function ScanBitmap(hBmp: HBITMAP; bmpWidth, bmpHeight: Integer): PChar; stdcall; var dllBmp: TBitmap; readResult: TZXingReadResult; // 自定义的ZXing扫描结果类 begin Result := nil; dllBmp := TBitmap.Create; try // 直接绑定句柄,无像素拷贝 dllBmp.Handle := hBmp; readResult := _scanManager.Scan(dllBmp); if readResult <> nil then begin // 按约定分配返回字符串内存,由主程序负责释放 Result := StrAlloc(Length(readResult.Text) + 1); StrPCopy(Result, readResult.Text); FreeAndNil(readResult); end; finally // 仅释放TBitmap对象,不会释放传入的HBITMAP,资源所有权归属主程序 dllBmp.Free; end; end;
注意事项
- 提前约定好HBITMAP的所有权:DLL侧不要调用
DeleteObject释放传入的HBITMAP,资源完全由主程序管理 - 如果需要兼容不同像素格式的位图,可以额外传递像素位深参数,或者DLL侧直接读取位图头信息判断即可
- 该方案性能开销几乎可忽略,哪怕是每秒几十次的调用频率也完全可以承载,比内存流方案性能高至少一个数量级
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

