线程中WICImage与Bitmap数据转换
最近项目开发, 要用到线程中对图像进行缩放和二值化处理
为了省事, 图像缩放用的WICImage.ImagingFactory接口, 二值化用的是bitmap.PixelFormat := pf1bit后直接bitmap.Canvas.Draw(0, 0, wicimage)(这么做是因为bitmap在处理透明通道时会强制变为黑色, 而项目需要为白色, 所以只能draw)
运行时发现, 经常性的出现图像数据丢失, 经过排查发现数据丢失都是出现在wicimage向bitmap做数据转换时出现的
跟踪源码, 发现wicimage中的数据处理全部使用32位RGBA格式, 与外部进行图像对象交换时, 都要先吧数据存放到一个bitmap中, 再转换为其他格式
但是, 由于TBitmap不是线程安全的, 在线程中进行绘画操作要先canvas.lock才行, 而wicimage没有相关处理, 所以, 问题出现了
解决方案是, 自己吧wicimage中, 转换为中间bitmap的方法复制出来成为独立函数, 直接吧数据输出到目的bitmap, 省略draw那一步
这样就可以自己在外面随意控制bitmap的lock了
其实还有更好的办法是, 直接吧wicimage数据输出为1bit的位图, 但是我没搞定, 只要不是1bit的都可以, 唯独1bit的总是失败, 所以还是使用默认的32bit外面再使用bitmap的PixelFormat做转换了
代码如下:
function WICBitmap2Bitmap(AWICBitmap: IWICBitmap; ABMP: TBitmap): Boolean; var nLWicBitmap: IWICBitmapSource; nStride: Cardinal; nBuffer: array of Byte; nBitmapInfo: TBitmapInfo; nWidth, nHeight: UInt32; begin Result := False; if AWICBitmap = nil then Exit; if ABMP = nil then Exit; AWICBitmap.GetSize(nWidth, nHeight); nStride := nWidth * 4; SetLength(nBuffer, nStride * nHeight); WICConvertBitmapSource(GUID_WICPixelFormat32bppBGRA, AWICBitmap, nLWicBitmap); nLWicBitmap.CopyPixels(nil, nStride, Length(nBuffer), @nBuffer[0]); FillChar(nBitmapInfo, sizeof(nBitmapInfo), 0); with nBitmapInfo.bmiHeader do begin biSize := SizeOf(nBitmapInfo); biWidth := nWidth; biHeight := -nHeight; biPlanes := 1; biBitCount := 32; end; with ABMP do begin PixelFormat := pf32bit; SetSize(nWidth, nHeight); {DC par not used (ABMP.Canvas.Handle) since Usage = DIB_RGB_COLORS} SetDIBits(0, Handle, 0, nHeight, @nBuffer[0], nBitmapInfo, DIB_RGB_COLORS); AlphaFormat := afDefined; end; Result := True; end; function Bitmap2WICBitmap(ABMP: TBitmap; var AWICBitmap: IWicBitmap): Boolean; var nPixelFormat: TGUID; nBitmapInfo: TBitmapInfo; nBuffer: array of byte; nWidth, nHeight: Int32; begin Result := False; if ABMP.AlphaFormat = afDefined then nPixelFormat := GUID_WICPixelFormat32bppBGRA else nPixelFormat := GUID_WICPixelFormat32bppBGR; ABMP.PixelFormat := pf32bit; nWidth := ABMP.Width; nHeight := ABMP.Height; SetLength(nBuffer, nWidth * 4 * nHeight); FillChar(nBitmapInfo, sizeof(nBitmapInfo), 0); with nBitmapInfo.bmiHeader do begin biSize := SizeOf(nBitmapInfo); biWidth := nWidth; biHeight := -nHeight; biPlanes := 1; biBitCount := 32; end; // Forces evaluation of Bitmap.Handle before Bitmap.Canvas.Handle GetDIBits(ABMP.Canvas.Handle, ABMP.Handle, 0, nHeight, @nBuffer[0], nBitmapInfo, DIB_RGB_COLORS); TWICImage.ImagingFactory.CreateBitmapFromMemory(nWidth, nHeight, nPixelFormat, nWidth * 4, Length(nBuffer), @nBuffer[0], AWICBitmap); end;
--------------------------------------------------------------------------------------------------
作者:黑暗煎饼果子
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
--------------------------------------------------------------------------------------------------