24 bpp的转换为4BPP与GDI +在VB.NET [英] Converting 24BPP to 4BPP with GDI+ in VB.NET

查看:413
本文介绍了24 bpp的转换为4BPP与GDI +在VB.NET的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我VB.NET方案目前需要4BPP TIFF作为位图,将其转换为一个图形,增加了一些文本串,然后再次将其保存作为一个TIFF文件。缺省输出Bitmap.Save()TIFF文件似乎是24 bpp的(不考虑输入)和比原始TIFF大很多。

My VB.NET program currently takes a 4BPP TIFF as an Bitmap, converts it to a Graphic, adds some text strings and then saves it out again as a TIFF file. The output Bitmap.Save() TIFF file by default seems to be 24BPP (regardless of the input) and is a lot larger than the original TIFF.

是否有可能保持相同4BPP调色板编码的输入输出,如果没有,我怎么能转换24 bpp的我的位图的PixelFormat到4BPP索引。

Is it possible to keep the same 4BPP palette encoding as the input for the output and if not, how can I convert my Bitmap PixelFormat from 24BPP to 4BPP Indexed.

我已经看到了在 HTTP转换24 BPP 1 BPP一个例子://www.bobpowell。净/ onebit.htm 使用BitmapData.Lockbits(),但无法弄清楚如何做到这一点的4BPP。

I've seen an example for converting 24 BPP to 1 BPP at http://www.bobpowell.net/onebit.htm using BitmapData.Lockbits() but cannot figure out how to do it for 4BPP.

非常感谢
克里斯

Many thanks Chris

推荐答案

下面是我贴<一类修改后的版本href=\"http://stackoverflow.com/questions/2501104/outofmemoryexception-with-image-clone-only-on-windows-2003/2502605#2502605\">here.它采用4bpp逻辑从什么是在原来的源站点的评论。

Here's a modified version of the class I posted here. It uses 4bpp logic from what was in the comments in the original source site.

Public Class BitmapEncoder
    ''' <summary>
    ''' Copies a bitmap into a 1bpp/4bpp/8bpp bitmap of the same dimensions, fast
    ''' </summary>
    ''' <param name="b">original bitmap</param>
    ''' <param name="bpp">1 or 8, target bpp</param>
    ''' <returns>a 1bpp copy of the bitmap</returns>
    Public Shared Function ConvertBitmapToSpecified(ByVal b As System.Drawing.Bitmap, ByVal bpp As Integer) As System.Drawing.Bitmap
        Select Case bpp
            Case 1
            Case 4
            Case 8
            Case Else
                Throw New ArgumentException("bpp must be 1, 4 or 8")
        End Select


        ' Plan: built into Windows GDI is the ability to convert
        ' bitmaps from one format to another. Most of the time, this
        ' job is actually done by the graphics hardware accelerator card
        ' and so is extremely fast. The rest of the time, the job is done by
        ' very fast native code.
        ' We will call into this GDI functionality from C#. Our plan:
        ' (1) Convert our Bitmap into a GDI hbitmap (ie. copy unmanaged->managed)
        ' (2) Create a GDI monochrome hbitmap
        ' (3) Use GDI "BitBlt" function to copy from hbitmap into monochrome (as above)
        ' (4) Convert the monochrone hbitmap into a Bitmap (ie. copy unmanaged->managed)

        Dim w As Integer = b.Width, h As Integer = b.Height
        Dim hbm As IntPtr = b.GetHbitmap()
        ' this is step (1)
        '
        ' Step (2): create the monochrome bitmap.
        ' "BITMAPINFO" is an interop-struct which we define below.
        ' In GDI terms, it's a BITMAPHEADERINFO followed by an array of two RGBQUADs
        Dim bmi As New BITMAPINFO()
        bmi.biSize = 40
        ' the size of the BITMAPHEADERINFO struct
        bmi.biWidth = w
        bmi.biHeight = h
        bmi.biPlanes = 1
        ' "planes" are confusing. We always use just 1. Read MSDN for more info.
        bmi.biBitCount = CShort(bpp)
        ' ie. 1bpp or 8bpp
        bmi.biCompression = BI_RGB
        ' ie. the pixels in our RGBQUAD table are stored as RGBs, not palette indexes
        bmi.biSizeImage = CUInt((((w + 7) And &HFFFFFFF8) * h / 8))
        bmi.biXPelsPerMeter = 1000000
        ' not really important
        bmi.biYPelsPerMeter = 1000000
        ' not really important
        ' Now for the colour table.
        Dim ncols As UInteger = CUInt(1) << bpp
        ' 2 colours for 1bpp; 256 colours for 8bpp
        bmi.biClrUsed = ncols
        bmi.biClrImportant = ncols
        bmi.cols = New UInteger(255) {}
        ' The structure always has fixed size 256, even if we end up using fewer colours
        If bpp = 1 Then
            bmi.cols(0) = MAKERGB(0, 0, 0)
            bmi.cols(1) = MAKERGB(255, 255, 255)
        ElseIf bpp = 4 Then
            bmi.biClrUsed = 16
            bmi.biClrImportant = 16
            Dim colv1 As Integer() = New Integer(15) {8, 24, 38, 56, 72, 88, 104, 120, 136, 152, 168, 184, 210, 216, 232, 248}

            For i As Integer = 0 To 15
                bmi.cols(i) = MAKERGB(colv1(i), colv1(i), colv1(i))
            Next
        ElseIf bpp = 8 Then
            For i As Integer = 0 To ncols - 1
                bmi.cols(i) = MAKERGB(i, i, i)
            Next
        End If
        ' For 8bpp we've created an palette with just greyscale colours.
        ' You can set up any palette you want here. Here are some possibilities:
        ' greyscale: for (int i=0; i<256; i++) bmi.cols[i]=MAKERGB(i,i,i);
        ' rainbow: bmi.biClrUsed=216; bmi.biClrImportant=216; int[] colv=new int[6]{0,51,102,153,204,255};
        '          for (int i=0; i<216; i++) bmi.cols[i]=MAKERGB(colv[i/36],colv[(i/6)%6],colv[i%6]);
        ' optimal: a difficult topic: http://en.wikipedia.org/wiki/Color_quantization
        ' 
        ' Now create the indexed bitmap "hbm0"
        Dim bits0 As IntPtr
        ' not used for our purposes. It returns a pointer to the raw bits that make up the bitmap.
        Dim hbm0 As IntPtr = CreateDIBSection(IntPtr.Zero, bmi, DIB_RGB_COLORS, bits0, IntPtr.Zero, 0)
        '
        ' Step (3): use GDI's BitBlt function to copy from original hbitmap into monocrhome bitmap
        ' GDI programming is kind of confusing... nb. The GDI equivalent of "Graphics" is called a "DC".
        Dim sdc As IntPtr = GetDC(IntPtr.Zero)
        ' First we obtain the DC for the screen
        ' Next, create a DC for the original hbitmap
        Dim hdc As IntPtr = CreateCompatibleDC(sdc)
        SelectObject(hdc, hbm)
        ' and create a DC for the monochrome hbitmap
        Dim hdc0 As IntPtr = CreateCompatibleDC(sdc)
        SelectObject(hdc0, hbm0)
        ' Now we can do the BitBlt:
        BitBlt(hdc0, 0, 0, w, h, hdc, _
         0, 0, SRCCOPY)
        ' Step (4): convert this monochrome hbitmap back into a Bitmap:
        Dim b0 As System.Drawing.Bitmap = System.Drawing.Bitmap.FromHbitmap(hbm0)
        '
        ' Finally some cleanup.
        DeleteDC(hdc)
        DeleteDC(hdc0)
        ReleaseDC(IntPtr.Zero, sdc)
        DeleteObject(hbm)
        DeleteObject(hbm0)
        '
        Return b0
    End Function


    Private Shared SRCCOPY As Integer = &HCC0020
    Private Shared BI_RGB As UInteger = 0
    Private Shared DIB_RGB_COLORS As UInteger = 0
    <System.Runtime.InteropServices.DllImport("gdi32.dll")> _
    Private Shared Function DeleteObject(ByVal hObject As IntPtr) As Boolean
    End Function

    <System.Runtime.InteropServices.DllImport("user32.dll")> _
    Private Shared Function GetDC(ByVal hwnd As IntPtr) As IntPtr
    End Function

    <System.Runtime.InteropServices.DllImport("gdi32.dll")> _
    Private Shared Function CreateCompatibleDC(ByVal hdc As IntPtr) As IntPtr
    End Function

    <System.Runtime.InteropServices.DllImport("user32.dll")> _
    Private Shared Function ReleaseDC(ByVal hwnd As IntPtr, ByVal hdc As IntPtr) As Integer
    End Function

    <System.Runtime.InteropServices.DllImport("gdi32.dll")> _
    Private Shared Function DeleteDC(ByVal hdc As IntPtr) As Integer
    End Function

    <System.Runtime.InteropServices.DllImport("gdi32.dll")> _
    Private Shared Function SelectObject(ByVal hdc As IntPtr, ByVal hgdiobj As IntPtr) As IntPtr
    End Function

    <System.Runtime.InteropServices.DllImport("gdi32.dll")> _
    Private Shared Function BitBlt(ByVal hdcDst As IntPtr, ByVal xDst As Integer, ByVal yDst As Integer, ByVal w As Integer, ByVal h As Integer, ByVal hdcSrc As IntPtr, _
     ByVal xSrc As Integer, ByVal ySrc As Integer, ByVal rop As Integer) As Integer
    End Function


    <System.Runtime.InteropServices.DllImport("gdi32.dll")> _
    Private Shared Function CreateDIBSection(ByVal hdc As IntPtr, ByRef bmi As BITMAPINFO, ByVal Usage As UInteger, ByRef bits As IntPtr, ByVal hSection As IntPtr, ByVal dwOffset As UInteger) As IntPtr
    End Function

    <System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)> _
    Private Structure BITMAPINFO
        Public biSize As UInteger
        Public biWidth As Integer, biHeight As Integer
        Public biPlanes As Short, biBitCount As Short
        Public biCompression As UInteger, biSizeImage As UInteger
        Public biXPelsPerMeter As Integer, biYPelsPerMeter As Integer
        Public biClrUsed As UInteger, biClrImportant As UInteger
        <System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=256)> _
        Public cols As UInteger()
    End Structure

    Private Shared Function MAKERGB(ByVal r As Integer, ByVal g As Integer, ByVal b As Integer) As UInteger
        Return CUInt((b And 255)) Or CUInt(((r And 255) << 8)) Or CUInt(((g And 255) << 16))
    End Function
    Private Sub New()

    End Sub

End Class

要使用它:

    'Load your image
    Using B As New Bitmap("c:\test.tiff")
        'Do a bunch of stuff to it
        '...'

        'Convert it to 4BPP
        Using I = BitmapEncoder.ConvertBitmapToSpecified(B, 4)
            'Save to disk
            I.Save("c:\test2.tiff")
        End Using
    End Using

这篇关于24 bpp的转换为4BPP与GDI +在VB.NET的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆