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:
'IN A CLASS MODULE
Option Explicit
Private BMP_INFO As BITMAPINFO_256, BMP_DATA() As Byte
Private hDIB As Long, hWidth As Integer, hHeight As Integer
Public Sub Create(ByVal NewWidth As Integer, ByVal NewHeight As Integer, ByRef Pixels() As Byte, ByRef Palette() As Byte)
Dim Screen_hDC As Long, A As Integer, B As Long
'set width and height
hWidth = NewWidth
hHeight = NewHeight
B = UBound(Pixels)
'resize graphics array
ReDim BMP_DATA(B)
'copy graphics data
RtlMoveMemory ByVal VarPtr(BMP_DATA(0)), ByVal VarPtr(Pixels(0)), B + 1
Public Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hDC As Long) As Long
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
Public Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As Long
Public Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Public Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
Public Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal hDC As Long) As Long
Public Declare Function SelectObject Lib "gdi32" (ByVal hDC As Long, ByVal hObject As Long) As Long
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:
Public Sub Create(ByVal NewWidth As Integer, ByVal NewHeight As Integer, ByRef Pixels() As Byte, ByRef Palette() As Byte)
Dim Screen_hDC As Long, A As Integer, B As Long, C As Integer
'set width and height
hWidth = NewWidth
hHeight = NewHeight
B = IIf(hWidth Mod 4, (hWidth + 4 - hWidth Mod 4) * hHeight - 1, UBound(Pixels))
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?
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]