使用GDI+将24 bpp转换为4 bpp
使用GDI+将24 bpp转换为4 bpp
我的程序目前将4 bpp(每像素位数)的TIFF作为位图输入,将其转换为图形,添加一些文本字符串,然后再将其保存为TIFF文件。默认情况下,输出的Bitmap.Save() TIFF文件似乎是24 bpp(无论输入是什么),并且比原始TIFF文件大得多。
是否可以保持与输入相同的4 bpp调色板编码的输出,如果不可以,如何将我的位图像素格式从24 bpp转换为4 bpp-indexed?
我在Bob Powell: Locking Bits 上看到了将24 bpp转换为1 bpp的示例,但是无法弄清楚如何将其应用于4 bpp。
问题:将24 bpp转换为4 bpp的问题出现的原因是需要将一个原始的24 bpp位图转换为4 bpp位图,以减少内存占用和提高处理速度。
解决方法:使用GDI+的功能将24 bpp位图转换为4 bpp位图。具体步骤如下:
1. 将原始位图转换为GDI hbitmap。
2. 创建一个GDI单色hbitmap。
3. 使用GDI的"BitBlt"函数将原始hbitmap复制到单色位图中。
4. 将单色hbitmap转换为位图。
具体实现代码如下:
Public Class BitmapEncoder Public Shared Function ConvertBitmapToSpecified(ByVal b As System.Drawing.Bitmap, ByVal bpp As Integer) As System.Drawing.Bitmap '根据目标bpp的值进行判断和处理 Select Case bpp Case 1 Case 4 Case 8 Case Else Throw New ArgumentException("bpp must be 1, 4 or 8") End Select '将原始位图转换为GDI hbitmap Dim w As Integer = b.Width, h As Integer = b.Height Dim hbm As IntPtr = b.GetHbitmap() '创建单色位图的BITMAPINFO结构 Dim bmi As New BITMAPINFO() bmi.biSize = 40 bmi.biWidth = w bmi.biHeight = h bmi.biPlanes = 1 bmi.biBitCount = CShort(bpp) bmi.biCompression = BI_RGB bmi.biSizeImage = CUInt((((w + 7) And &HFFFFFFF8) * h / 8)) bmi.biXPelsPerMeter = 1000000 bmi.biYPelsPerMeter = 1000000 Dim ncols As UInteger = CUInt(1) << bpp bmi.biClrUsed = ncols bmi.biClrImportant = ncols bmi.cols = New UInteger(255) {} '创建单色位图的hbitmap Dim bits0 As IntPtr Dim hbm0 As IntPtr = CreateDIBSection(IntPtr.Zero, bmi, DIB_RGB_COLORS, bits0, IntPtr.Zero, 0) '使用GDI的BitBlt函数将原始hbitmap复制到单色位图中 Dim sdc As IntPtr = GetDC(IntPtr.Zero) Dim hdc As IntPtr = CreateCompatibleDC(sdc) SelectObject(hdc, hbm) Dim hdc0 As IntPtr = CreateCompatibleDC(sdc) SelectObject(hdc0, hbm0) BitBlt(hdc0, 0, 0, w, h, hdc, 0, 0, SRCCOPY) '将单色hbitmap转换为位图 Dim b0 As System.Drawing.Bitmap = System.Drawing.Bitmap.FromHbitmap(hbm0) '清理资源 DeleteDC(hdc) DeleteDC(hdc0) ReleaseDC(IntPtr.Zero, sdc) DeleteObject(hbm) DeleteObject(hbm0) Return b0 End Function '其他函数和结构体定义 '... End Class
使用方法:
'加载原始图像
Using B As New Bitmap("c:\test.tiff")
'对图像进行处理
'...
'将图像转换为4bpp
Using I = BitmapEncoder.ConvertBitmapToSpecified(B, 4)
'保存到磁盘
I.Save("c:\test2.tiff")
End Using
End Using
需要注意的是,这里保存的是PNG格式的图像,而不是TIF格式的。无论如何,这正是我所需要的解决方案。