Results 1 to 5 of 5

Thread: Bitmap problems [resolved by self!]

  1. #1

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Bitmap problems [resolved by self!]

    This seems weird... I have bitmaps storaged in memory and most of them display correctly, but all ones with odd width and also some others (it is quite random) display incorrectly. Attached is a file that shows what kind of results I get.

    Is there a reason for this? I give the bytes correctly. Here is the code I use to storage the graphics to memory:

    VB Code:
    1. 'IN A CLASS MODULE
    2. Option Explicit
    3.  
    4. Private BMP_INFO As BITMAPINFO_256, BMP_DATA() As Byte
    5. Private hDIB As Long, hWidth As Integer, hHeight As Integer
    6. Public Sub Create(ByVal NewWidth As Integer, ByVal NewHeight As Integer, ByRef Pixels() As Byte, ByRef Palette() As Byte)
    7.     Dim Screen_hDC As Long, A As Integer, B As Long
    8.  
    9.     'set width and height
    10.     hWidth = NewWidth
    11.     hHeight = NewHeight
    12.  
    13.     B = UBound(Pixels)
    14.  
    15.     'resize graphics array
    16.     ReDim BMP_DATA(B)
    17.  
    18.     'copy graphics data
    19.     RtlMoveMemory ByVal VarPtr(BMP_DATA(0)), ByVal VarPtr(Pixels(0)), B + 1
    20.  
    21.     'copy palette data
    22.     RtlMoveMemory ByVal VarPtr(BMP_INFO.bmiColors(0)), ByVal VarPtr(Palette(0)), UBound(Palette) + 1
    23.  
    24.     'set DIB header
    25.     With BMP_INFO.bmiHeader
    26.         .biSize = Len(BMP_INFO.bmiHeader)
    27.         .biWidth = hWidth       ' width in pixels
    28.         .biHeight = hHeight     ' height in pixels
    29.         .biPlanes = 1           ' 1 color plane
    30.         .biBitCount = 8         ' 8 bits per pixel
    31.         .biCompression = BI_RGB ' no compression
    32.         .biSizeImage = 0        ' unrequired with no compression
    33.         .biXPelsPerMeter = 0    ' unrequired
    34.         .biYPelsPerMeter = 0    ' unrequired
    35.         .biClrUsed = 256        ' number colors in color table that are used by the image (0 means all)
    36.         .biClrImportant = 256   ' number important colors (0 means all)
    37.     End With
    38.  
    39.     'get the screen's device context
    40.     Screen_hDC = GetDC(0)
    41.  
    42.     'create the DIB
    43.     hDIB = CreateDIBitmap(Screen_hDC, BMP_INFO.bmiHeader, CBM_INIT, BMP_DATA(0), BMP_INFO, DIB_RGB_COLORS)
    44.    
    45.     'free up memory
    46.     ReleaseDC 0, Screen_hDC
    47. End Sub
    48. Public Sub Draw(ByRef Form_hDC As Long, ByRef Target_hDC As Long, ByVal TargetWidth As Integer, ByVal TargetHeight As Integer)
    49.     Dim Compat_DC As Long
    50.  
    51.     'create a compatible device context
    52.     Compat_DC = CreateCompatibleDC(Form_hDC)
    53.  
    54.     'select the DIB into the compatible DC
    55.     SelectObject Compat_DC, hDIB
    56.  
    57.     'copy the compatible DC's image to the target
    58.     StretchBlt Target_hDC, 0, 0, TargetWidth, TargetHeight, Compat_DC, 0, hHeight - 1, hWidth, -hHeight, vbSrcCopy
    59.  
    60.     'destroy the compatible DC
    61.     DeleteDC Compat_DC
    62. End Sub

    VB Code:
    1. 'IN A MODULE
    2. Option Explicit
    3.  
    4. Public Const BI_RGB = 0&
    5. Public Const CBM_INIT = &H4
    6. Public Const DIB_RGB_COLORS = 0
    7.  
    8. Public Type BITMAPINFOHEADER
    9.     biSize As Long
    10.     biWidth As Long
    11.     biHeight As Long
    12.     biPlanes As Integer
    13.     biBitCount As Integer
    14.     biCompression As Long
    15.     biSizeImage As Long
    16.     biXPelsPerMeter As Long
    17.     biYPelsPerMeter As Long
    18.     biClrUsed As Long
    19.     biClrImportant As Long
    20. End Type
    21.  
    22. Public Type RGBQUAD
    23.     rgbBlue As Byte
    24.     rgbGreen As Byte
    25.     rgbRed As Byte
    26.     rgbReserved As Byte
    27. End Type
    28.  
    29. Public Type BITMAPINFO_256
    30.     bmiHeader As BITMAPINFOHEADER
    31.     bmiColors(0 To 255) As RGBQUAD
    32. End Type
    33.  
    34. Public Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hDC As Long) As Long
    35. Public Declare Function CreateDIBitmap Lib "gdi32" (ByVal hDC As Long, lpInfoHeader As BITMAPINFOHEADER, ByVal dwUsage As Long, lpInitBits As Any, lpInitInfo As BITMAPINFO_256, ByVal wUsage As Long) As Long
    36. Public Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As Long
    37. Public Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
    38. Public Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
    39. Public Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal hDC As Long) As Long
    40. Public Declare Function SelectObject Lib "gdi32" (ByVal hDC As Long, ByVal hObject As Long) As Long
    41. Public Declare Function StretchBlt Lib "gdi32" (ByVal hDC As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal dwRop As Long) As Long


    Hope someone can answer the question. I can't see anything wrong with the code, since it is a modification of a code made by someone else.



    Finally! Figured it! Just had to make so that each data row is dividable by four. Code to make this clearer in case somebody happens to have the same problem some day:

    VB Code:
    1. Public Sub Create(ByVal NewWidth As Integer, ByVal NewHeight As Integer, ByRef Pixels() As Byte, ByRef Palette() As Byte)
    2.     Dim Screen_hDC As Long, A As Integer, B As Long, C As Integer
    3.  
    4.     'set width and height
    5.     hWidth = NewWidth
    6.     hHeight = NewHeight
    7.  
    8.     B = IIf(hWidth Mod 4, (hWidth + 4 - hWidth Mod 4) * hHeight - 1, UBound(Pixels))
    9.  
    10.     'resize graphics array
    11.     ReDim BMP_DATA(B)
    12.  
    13.     If hWidth Mod 4 Then
    14.         C = hWidth + 4 - hWidth Mod 4
    15.         For A = 0 To hHeight - 1
    16.             RtlMoveMemory ByVal VarPtr(BMP_DATA(A * C)), ByVal VarPtr(Pixels(A * hWidth)), hWidth
    17.         Next A
    18.     Else
    19.         'copy graphics data
    20.         RtlMoveMemory ByVal VarPtr(BMP_DATA(0)), ByVal VarPtr(Pixels(0)), B + 1
    21.     End If
    22. '... rest match with the code above
    Attached Images Attached Images  
    Last edited by Merri; May 22nd, 2004 at 06:43 PM.

  2. #2
    Fanatic Member
    Join Date
    Jan 2003
    Posts
    1,004
    Can something like this be done with rows not divisible by four? If so, how?
    "Can't" and "shouldn't" are two totally separate things.

    All questions should be answered. All answers should be true. That is why I post.

  3. #3

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654
    You mean, the row must be divisible by a bigger number? Easy: just change all the occurances of four in the code above. Or did you mean something else?

  4. #4
    Fanatic Member
    Join Date
    Jan 2003
    Posts
    1,004
    Finally! Figured it! Just had to make so that each data row is dividable by four.
    Why did you need to do this?
    "Can't" and "shouldn't" are two totally separate things.

    All questions should be answered. All answers should be true. That is why I post.

  5. #5

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654
    Windows appears to be storing images so that the width is dividible by four. I don't know if it is some kind of optimization.

    Image data looks like this:
    Code:
    Width 31:
    ACTUAL IMAGE ROW [extra byte]
    ACTUAL IMAGE ROW [extra byte]
    ...
    
    
    Width 29:
    ACTUAL IMAGE ROW [3 extra bytes]
    ACTUAL IMAGE ROW [3 extra bytes]
    ...
    
    Width 32:
    ACTUAL IMAGE ROW
    ACTUAL IMAGE ROW
    ...
    Nevertheless, that's what the images look like in the memory.

    Edit After some thinking, I guess the image system is optimized for Long values and 32-bit images. So even if you use 8-bit images, it still handles all images with long values, thus all image widths must be dividible by four when using 8-bit images. With 4-bits you have to do the same thing, I believe, so you have to include up to seven extra pixels in the end.


    Code:
    R = Red, G = Green, B = Blue, A = Alpha, P = Pixel, e = extra
    [ = byte begins, ] = byte ends
    
    32-bit (2 pixels row, 8/8 bytes):
    [R][G][B][A][R][G][B][A]
    
    24-bit (2 pixels row, 6/8 bytes):
    [R][G][B][R][G][B][e][e]
    
    16-bit (3 pixels row, 6/8 bytes):
    [RG][GB][RG][GB][RG][GB][e][e]
    
    - 16-bit is 5 bits for red, 6 for green and 5 for blue
    
    8-bit (7 pixels row, 7/8 bytes):
    [P][P][P][P][P][P][P][e]
    
    4-bit (15 pixels row, 7.5/8 bytes):
    [PP][PP][PP][PP][PP][PP][PP][Pe]
    I hope this clears this thing up
    Last edited by Merri; May 29th, 2004 at 03:03 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width