No announcement yet.

Colors on DIB bitmaps

  • Filter
  • Time
  • Show
Clear All
new posts

  • Colors on DIB bitmaps

    I work with DIB bitmaps to do numeric simulations. DIBs are 8 bit. I fill the bitmap with colors which represent different materials, then I need to be absolutely certain what color API calls use when drawing on DIBs.
    I use the PALETTEINDEX macro to declare the color I want, but if the color table of the DIB contains two identical colors, API uses the first occurrence of the two, no the one i want. If I create a pen with PALETTEINDEX, I can verify with GetObject that the color index loaded is that I want. But after drawing on the DIB in a memory context, the color loaded may be different.

    The obvious way to solve the problem is to be sure all colors are different in the color table. Is it true? How big the difference must be? Is it sufficient 1 bit on either R, G or B)?

    Rgds, Aldo

  • #2
    I'm not very clear on how exactly you are verifying the colors actually used in the DIB, but if the drawn color is different from the specified pen color, then the problem has to be related to the color palette being used.

    Are you creating a custom palette for the Window you are displaying the image, or are you reading the DIB memory directly?

    Since this is the second time you've posted, you may wish to consider posting some code so folks can see exactly what you are doing, since this tends to provide the greatest oportunity for peer-help...

    PowerBASIC Support
    mailto:[email protected][email protected]</A>
    mailto:[email protected]


    • #3

      my program calls the following API:

      1) CreateDIBsection to create my bitmap, 8 bit, filling the palette I need to use. For instance, I fill the palette with both the DOS colors and the Windows colors. Black and White will be declared twice. White will be present on entries 15 (DOS) and 35 (Windows).
      2) CreateCompatibleDc( %null ) to get a device context
      3) SelectObject to load the DIB on the DC
      4) CreatePen loading the color (with the PALETTEINDEX macro); let's say the loaded index is 35
      5) SelectObject to load the pen on the DC
      5) GetObject to verify the pen structure: the color loaded is &H01000023 (23 HEX = 35)
      6) Draw on the DC
      7) Get the color loaded on the DIB. This is accessing memory, via the data pointer retrieved form the CreateDIBsection call.

      The color loaded on the DIB bitmap is 15, not 35. Well, if I loaded the White on index 35 as RGB( 255, 255, 254 ), which will be different from White on index 15 ( 255, 255, 255 ), the color retrieved on step 7 was 35.

      The behavior described has nothing to do with the screen; at the moment of step 7 the bitmap is not displayed. The behavior is the same if I change the screen properties (8/16/24 bit per pixel).

      The only reason I can imagine is API verify the palette contents before using an index, but I can't find this information on all my microsoft sources.

      [This message has been edited by Aldo Cavini (edited March 19, 2001).]
      Rgds, Aldo


      • #4
        MSDN GetSystemPaletteUse
        By default, the system palette contains 20 static colors that are not changed when an application realizes its logical palette.

        PS. I beleive that GetDeviceCaps(hDC, %NumColors) in 256-colors mode returns no. of static colors.

        [This message has been edited by Semen Matusovski (edited March 19, 2001).]


        • #5

          What I've written is about DIB bitmaps drawing-in. Now I describe how I show the DIB bitmaps on the screen:

          1) CreatePalette to create a logical palette (this is done only a first time, as a response to a %WM_CREATE message ).
          2) SelectPalette( memoryDC, hPalette, %false ) and
          3) RealizePalette( memoryDc ) - the memoryDc is that has the DIB bitmap loaded

          4) If screen is 256 colors, the main window receives %WM_QUERYNEWPALETTE. The program calls:
          5) windowDc = GetWindowDc( hWnd )
          6) SelectPalette windowDC, hPalette, %false
          7) UnrealizeObject hPalette
          8) RealizePalette windowDC
          9) ReleaseDc hWnd, windowDC

          10) On %WM_PAINT messages, GetDeviceCaps( windowDc, %RASTERCAPS ) and see the %RC_PALETTE flag. It it is set, then
          11) SelectPalette( windowDC, hPalette, %true )
          12) RealizePalette( windowDC )

          15) BitBlt...

          All this stuff works perfectly. I added some instructions to respond to a %WM_PALETTECHANGED message, and the program follows the screen properties changes. The colors are always exact (almost correct, if the application is not foreground and the screen is 256 colors).
          Note: colours are wrong if you omit points 2 and 3. If you include them, API works correctly in translating my bitmap colors to the screen (bitblt). Then I think it is not a problem of system palette. Still I don't understand the reason API changes the palette indexes when drawing. I have this problem not only on Whites, but also on colors that are neither DOS nor Windows.

          Rgds, Aldo


          • #6
            Aldo --
            What about using SetTextColor hDc, &H02000000 + RGB(...) ?
            (02 means that Windows will search in palette)

            [This message has been edited by Semen Matusovski (edited March 19, 2001).]


            • #7
              Semen --

              I don't understand why it is so difficult to draw into a DIB bitmap with the color index I want. My problem is I want both to put data directly in memory, AND use API calls for all that difficult stuff (arcs, floods, etc). Most important, I want to read directly the data, being certain about the colors I found.

              I don't understand why I have to create a palette for a memory context (I already have a color table inside of the bitmap header!). Of course API needs to convert the memory color table to the screen color table; but this problem shouldn't be involved when I am drawing on a memory context.

              May be all my API calls are wrong (they seem to work...). I'd like to know the correct way to do what i need to.

              Rgds, Aldo


              • #8
                Aldo -
                I prefer to work with 32-bit sections. It's much easy (but waste of memory).
                If I don't make a mistake, during BitBlt memoryDC -> ScreenDC Windows (st least, Win2000) automatic uses palette colors only.

                Compare %g = 0 and %g = 1 in true-color video regime (the same).
                Than the same in 256 colors (not the same).

                   %g = 0
                   #Compile Exe
                   #Register None
                   #Dim All
                   #Include "WIN32API.INC"
                    CallBack Function DlgProc
                      Dim i As Long, j As Long, jj As Long, k As Long, kk As Long
                      Select Case CbMsg
                         Case %WM_INITDIALOG
                            Dim hBrush As Static Long
                            hBrush = CreateSolidBrush(Rgb(255, 192, 128))
                         Case %WM_DESTROY
                            DeleteObject hBrush
                         Case %WM_CTLCOLORDLG
                           If %g Then Function = hBrush
                         Case %WM_ERASEBKGND
                           If %g Then Else Function = 1: Exit Function
                         Case %WM_PAINT
                            If %g Then Exit Function
                            Dim bmi As BITMAPINFO, bm As BITMAP, ps As PAINTSTRUCT, rc As Rect
                            Dim hMemDC As Long, hMemBmp As Long, pBits As Long Ptr, Coef As Double
                            InValidateRect CbHndl, ByVal 0, 0
                            GetClientRect CbHndl, rc
                            BeginPaint CbHndl, ps
                            hMemDC  = CreateCompatibleDC(ps.hDC)
                            bmi.bmiHeader.biSize = SizeOf(bmi.bmiHeader)
                            bmi.bmiHeader.biWidth = rc.nRight
                            bmi.bmiHeader.biHeight = rc.nBottom
                            bmi.bmiHeader.biPlanes = 1
                            bmi.bmiHeader.biBitCount = 32
                            bmi.bmiHeader.biCompression = %BI_RGB
                            hMemBmp = CreateDIBSection(hMemDC, bmi, %DIB_RGB_COLORS, 0, 0, 0)
                            GlobalLock hMemBmp: SelectObject hMemDC, hMemBmp
                            GetObject hMemBmp, SizeOf(bm), bm
                            pBits = bm.bmBits
                            Dim Clr1 As Long
                            For j = rc.nBottom - 1 To 0 Step - 1
                               Clr1 = Rgb(128, 192, 255)
                               For k = 0 To rc.nRight - 1
                                  @pBits = Clr1
                                  pBits = pBits + 4
                            BitBlt ps.hDC, 0, 0, rc.nRight, rc.nBottom, hMemDC, 0, 0, %SRCCOPY
                            EndPaint CbHndl, ps
                            DeleteDC hMemDC: DeleteObject hMemBmp
                            Function = 0: Exit Function
                      End Select
                   End Function
                   Function PbMain
                      Local hDlg As Long
                      Dialog New 0, "Progress Bar",,, 200, 80, %WS_SYSMENU To hDlg
                      Dialog Show Modal hDlg Call DlgProc
                   End Function
                E-MAIL: [email protected]


                • #9
                  What you are describing sounds familiar. I did some work with palettes and
                  DIBs a while back and I found the following book quite helpful. I think it
                  explains the problems you are seeing. It used to be on MSDN. Chapter 3
                  discusses the RGB, PALETTEINDEX AND PALETTERGB macros and why you do not
                  always get the color you specify.

                  Animation Techniques in Win32
                  by Nigel Thompson
                  With a Foreword by Charles Petzold
                  PUBLISHED BY
                  Microsoft Press
                  ISBN 1-55615-669-3

                  Dominic Mitchell
                  Dominic Mitchell
                  Phoenix Visual Designer


                  • #10
                    Originally posted by Semen Matusovski:
                    What about using SetTextColor hDc, &H02000000 + RGB(...) ?
                    (02 means that Windows will search in palette)
                    My problem is not to confuse two identical colors in the palette... This way API will use always the first entry in the palette that matches the required color.


                    Semen --

                    I tried your code. When you use 8 bit resolution screen, the difference depends on the way API matches the colors. DIB colors are matched to the closest color in the system palette; brushes are dithered.
                    I added the following rows to your code:
                    CASE %WM_INITDIALOG
                      STATIC lpl      AS LOGPALETTE PTR
                      STATIC hpalette AS LONG
                        lPl = LocalAlloc( %LMEM_FIXED OR %LMEM_ZEROINIT, SIZEOF( @lPl ) + 255 * 4 )
                        @lpl.palVersion = &h300
                        @lpl.PalNumEntries = 1
                        @lpl.PalPalEntry( 0 ).peRed   = 255
                        @lpl.PalPalEntry( 0 ).peGreen = 192
                        @lpl.PalPalEntry( 0 ).peBlue  = 128
                        @lpl.PalPalEntry( 0 ).peFlags = %PC_NOCOLLAPSE
                        hPalette = createpalette( @lpl )
                    CASE %WM_DESTROY
                        deleteobject hPalette
                        localfree lPl
                    CASE %WM_PAINT
                        selectpalette ps.hDC, hPalette, %false
                        realizepalette ps.hDC
                    Now the color is correctly displayed. With %g = 0 you will see the EXACT color; with %g = 1 you will see a DITHERED color.


                    Dominic --
                    Thanks for your advice.


                    [This message has been edited by Aldo Cavini (edited March 20, 2001).]
                    Rgds, Aldo


                    • #11
                      Guys --
                      It's not comfortable to think about colors during drawing.
                      But when drawing is finished, appears a wish to build a palette.
                      Do you have subs to create a pallete from 24/32-bits DIB section ?

                      I imagine that it's possible to sort RGB and to select the most important.
                      Or there are better ways ?

                      E-MAIL: [email protected]


                      • #12
                        You will in many cases get good results (apperance/speed) by just creating a good allround common palette, and let Windows do the mapping when blitting.

                        Best Regards
                        Peter Scheutz

                        Best Regards
                        Peter Scheutz


                        • #13
                          Semen --

                          It depends on what you have to do with bitmaps. If you need the best color resolution, it's obvious you can't work on a 8 bit per pixel screen - if the screen resolution is at least 15 bit per pixel, you have not to wonder about palettes.

                          If you need a few colors, you can reduce bitmaps from 32/24 bit to 16. It is simple to access data (via integers instead of longs), and you have at least 5 bit resolution for each R G and B. If you use 15 bit colors inside your bitmap, you can create a 32768 elements array and make a statistic.
                          DIM BitCount( 0:32767 ) as long
                          dim bitmapdataptr as integer ptr
                          bitmapdataptr = ...
                          for i = 0 to ...
                            incr BiCount( @bitmapdataptr[ i ] )
                          next i
                          Each element of the array will contain the number of pixel that have its index color.

                          Well, when I need less than 236 colors, I use 8 bit bitmaps. I have to fill the color table inside the bitmap header, to create a palette, communicate it to ALL the device contexts and respond to messages like %WM_PALETTEQUERY, %WM_PALETTECHANGED, %WM_DISPLAYCHANGE... It is not esasy, but it works in every situation.


                          Semen, Peter --

                          At the moment I have no problems in viewing colors/bitmaps. My original question was: how can I be sure the indexes API will use on drawing into 8 bit bitmaps?


                          [This message has been edited by Aldo Cavini (edited March 20, 2001).]
                          Rgds, Aldo


                          • #14
                            Actually I want to use true colors with gradient effects and so on.
                            Easiest sample: "3d" text (similar I posted two days ago in "BeginPaint vs GetDC").

                            Typically users work in high resolution. But I should accept that 10-15% of customers can have old PCes/notebooks.

                            Universal palette - of course, not bad, but what to do with gradient effects ?

                            Aldo, sure, that you will receive much more replies, if you will post small "run-able" fragment.

                            E-MAIL: [email protected]


                            • #15
                              Semen --

                              As I stated on my first message, I need 8 bit bitmaps to get data for making numeric simulations; I don't need gradient effects.

                              I just did the following:
                              I created the pen declaring a normal RGB color, without using the PALETTEINDEX macro - the program worked well;
                              Then I deleted the SelectPalette and RealizePalette calls to the memory device contexts (only that have bitmaps selected) - the program still worked well!

                              I think palette loaded into a memory device context is only needed if I use the PALETTEINDEX macro. In other words, API needs the palette to get the color associated to an index, and then looks for the nearest color in the color table of the bitmap. Of course API stops the search when it finds an exact match... then API uses ALWAYS the first match of the color (no matter if I use palette/PALETTEINDEX or not).

                              I'd like to know if you (and may be other guys) agree with my analisys. This can be an explanation why all the colors need to be different inside a color table.


                              [This message has been edited by Aldo Cavini (edited March 20, 2001).]
                              Rgds, Aldo


                              • #16
                                Originally posted by Semen Matusovski:
                                Universal palette - of course, not bad, but what to do with gradient effects ?
                                Use the smallest possible part of the palette for the base colors you know you are going to use.

                                Then, if you can limit yourself to one gradiant "tone", then use 100-200 colors for that gradient.
                                Or 2x100 colors for two gradients?

                                Another approch is to take a screenshot (in truecolor mode! ) of a typical picture and use something like Photoshop to create a good 236 color (leaving room for Windows static colors) palette.
                                You can also take more than one screenshot, paste them to the same Photoshop picture, and then reduce.

                                Best Regards
                                Peter Scheutz


                                [This message has been edited by Peter Scheutz (edited March 20, 2001).]
                                Best Regards
                                Peter Scheutz


                                • #17
                                  Aldo --
                                  I didn't test, but your results looks enough reallistic.

                                  Assume, that guy #1 wrote a subroutine "SetPixel", which accepts exact RGB only as parameter.
                                  What does guy #2, which writes a subroutine "LineTo" ?
                                  He, at first, call a subroutine, which translate PaletteRgb/PaletteIndex to simple RGB.

                                  Double conversion is enough often. I look on my analog LCD monitor and think --
                                  digital signal - analog output - conversion to digital image again.

                                  I don't think that it's possible to use rules, which you encounted (not documented).
                                  In my opinion, to avoid problems, when drawing is finished, it's better to process bm.bmBits and to set desired values "manually" (simple XLAT).

                                  E-MAIL: [email protected]