I already have some idea how to do this, but it is all theory. I have no real knowledge how to assign a palette to a graphic in a memory - I haven't done a non 32-bit image before either. So if anyone has a simple example code / tutorial to go with, I'll be grateful My search results this far have given far too complicated codes atm, but I continue searching once I'm awake again.
Here are two tools i've made for my quake modifications (which uses 8-bit palette).
In palette.zip there is a program for editing the palette.
In convert.zip there is a program that converts 8/16/24/32 bit images to 8 bit using the palette. I've made a dll file in C that searches for closest matching color from the palette, and because I'm not that good at C I didn't make the program load the palette file, I've added the palette to the code instead. You'll have to make it load it yourself.
Originally posted by cyborg Here are two tools i've made for my quake modifications (which uses 8-bit palette).
In palette.zip there is a program for editing the palette.
In convert.zip there is a program that converts 8/16/24/32 bit images to 8 bit using the palette. I've made a dll file in C that searches for closest matching color from the palette, and because I'm not that good at C I didn't make the program load the palette file, I've added the palette to the code instead. You'll have to make it load it yourself.
I don't need to convert images at all, as I have to read 8-bit images to memory and then view them with the correct palette. I might have found a code that works for me, but I can't test it until I can get as far as reading the data properly - sure is complicated not to be able to debug well, but I've always found a way
The colors in a 8-bit image are from 0 to 255 so the palette should have the Red, Green and Blue values for each 256 colors.
Just load the palette into an array like this:
VB Code:
Private Type ColorUDT
Red As Byte
Green As Byte
Blue As Byte
End Type
Dim Palette(255) As ColorUDT
Then to get the color from the palette you just do something like this:
Palette(ColorFrom8BitImage).Red
Palette(ColorFrom8BitImage).Green
Palette(ColorFrom8BitImage).Blue
Btw...Check the function that loads LMP files in the Bmp2Lmp program i attached. It loads 8-bit images and displays them on the screen using a palette.
I know how to do it the slow way - I want to do it the fast Windows native way. Should be possible.
- I have byte array of the image
- I want to storage it in a form I can display instantly from the memory
- I want to be able to view it in a PictureBox or any other object that supports Picture
There is code there, but these aren't too clear on what they do. And there are tons of API calls. At the moment I have ended up creating a class module - the only thing missing is the _working_ code. I haven't seen anything that is exactly what I need so I'm trying to figure out how to do it from the codes that handle the memory storaged images. What really lacks with the examples I have found are the comments: they are like "'Create the picture" - not describing how it does the new picture and what the input values mean.
This is my current class module, at the moment untested. You are free to point out errors you might see. I'm pretty sure this won't work, but I keep up a small drop of hope.
VB Code:
Option Explicit
Private Const DIB_RGB_COLORS As Long = 0
'bitmap information
Private Type BITMAP
bmType As Long
bmWidth As Long
bmHeight As Long
bmWidthBytes As Long
bmPlanes As Integer
bmBitsPixel As Integer
bmBits As Long
End Type
Private Type BMP_GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(7) As Byte
End Type
Private Type BMP_PICTURE
Size As Long
Type As Long
hBmp As Long
hPal As Long
Reserved As Long
End Type
'images in memory
Private Declare Function CreateBitmap Lib "gdi32" (ByVal nWidth As Long, ByVal nHeight As Long, ByVal nPlanes As Long, ByVal nBitCount As Long, lpBits As Any) As Long
Private Declare Function CreateCompatibleBitmap Lib "gdi32" (ByVal hDC As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hDC As Long, ByVal hObject As Long) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hDC As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As Long
Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal hDC As Long) As Long
Private Declare Function SetDIBits_8 Lib "gdi32" Alias "SetDIBits" (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpbi As BITMAPINFO_8, ByVal wUsage As Long) As Long
Private Declare Function CreatePalette Lib "gdi32" (lpLogPalette As LOGPALETTE) As Long
Private Declare Function RealizePalette Lib "gdi32" (ByVal hDC As Long) As Long
Private Declare Function SelectPalette Lib "gdi32" (ByVal hDC As Long, ByVal hPalette As Long, ByVal bForceBackground As Long) As Long
Private Declare Function OleCreatePictureIndirect Lib "olepro32.dll" (PicDesc As BMP_PICTURE, RefIID As BMP_GUID, ByVal fPictureOwnsHandle As Long, IPic As IPicture) As Long
Private InUseScreen As Boolean, InUseImage As Boolean
Private ScreenDC As Long, PicDC As Long, DestDC As Long
Private PicBmp As Long, PicPrevBmp As Long, PicPal As Long, PicPrevPal As Long
Private Width As Long, Height As Long
'initial step: get screen DC as default DC
Private Sub Class_Initialize()
Init GetDC(0)
End Sub
'last step: free memory
Private Sub Class_Terminate()
If InUseImage Then ClearImage
'free Dc
Call ReleaseDC(0, ScreenDC)
InUseScreen = False
End Sub
Public Sub ClearImage()
Dim PrevBmp As Long
'free image
If InUseImage Then
PrevBmp = SelectObject(PicDC, PicPrevBmp)
Call DeleteObject(PicBmp)
Call DeleteDC(PicDC)
InUseImage = False
End If
End Sub
'alternative step: change DC
Public Sub Init(hDC As Long)
'do a proper clearing before filling up with new information (if required)
If InUseScreen Then Class_Terminate
'set default DC
ScreenDC = hDC
PicDC = CreateCompatibleDC(ScreenDC)
'mark we have filled DC
InUseScreen = True
End Sub
'step 3: view the image
Property Get Picture() As IPictureDisp
Dim Pic As BMP_PICTURE, IPic As IPicture, IID_IDispatch As BMP_GUID
'fill GUID info (whatever it is...)
With IID_IDispatch
.Data1 = &H20400
.Data4(0) = &HC0
.Data4(7) = &H46
End With
'fill picture info
With Pic
.Size = Len(Pic) ' Length of structure
.Type = vbPicTypeBitmap ' Type of Picture (bitmap)
I finally found this great code that resolves my problem:
VB Code:
Option Explicit
Private Const BI_RGB = 0&
Private Const CBM_INIT = &H4
Private Const DIB_RGB_COLORS = 0
Private Const SRCCOPY = &HCC0020
Private Type BITMAPINFOHEADER
biSize As Long
biWidth As Long
biHeight As Long
biPlanes As Integer
biBitCount As Integer
biCompression As Long
biSizeImage As Long
biXPelsPerMeter As Long
biYPelsPerMeter As Long
biClrUsed As Long
biClrImportant As Long
End Type
Private Type RGBQUAD
rgbBlue As Byte
rgbGreen As Byte
rgbRed As Byte
rgbReserved As Byte
End Type
Private Type BITMAPINFO_256
bmiHeader As BITMAPINFOHEADER
bmiColors(0 To 255) As RGBQUAD
End Type
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private 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
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private 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
Dim Pixels() As Byte ' Pixel data.
Dim bm_info As BITMAPINFO_256 ' DIB bitmap info.
Dim hDIB As Long ' Bitmap handle.
Dim wid As Integer ' Size of the bitmap.
Dim hgt As Integer
' Create the DIB.
Private Sub CreateDIB()
Dim screen_hdc As Long
With bm_info.bmiHeader
.biSize = Len(bm_info.bmiHeader)
.biWidth = wid ' Width in pixels.
.biHeight = hgt ' Height in pixels.
.biPlanes = 1 ' 1 color plane.
.biBitCount = 8 ' 8 bits per pixel.
.biCompression = BI_RGB ' No compression.
.biSizeImage = 0 ' Unneeded with no compression.
.biXPelsPerMeter = 0 ' Unneeded.
.biYPelsPerMeter = 0 ' Unneeded.
.biClrUsed = 256 ' # colors in color table that are used by the image. 0 means all.
.biClrImportant = 256 ' # important colors. 0 means all.
End With
' Get the screen's device context.
screen_hdc = GetDC(0)
' Create the DIB.
hDIB = CreateDIBitmap(screen_hdc, _
bm_info.bmiHeader, CBM_INIT, Pixels(0, 0), _
bm_info, DIB_RGB_COLORS)
End Sub
' Draw the DIB onto the form.
Private Sub DrawDIB()
Dim compat_dc As Long
' Create a compatible device context.
compat_dc = CreateCompatibleDC(hdc)
' Select the DIB into the compatible DC.
SelectObject compat_dc, hDIB
' Copy the compatible DC's image onto the form.
StretchBlt Picture1.hdc, 0, 0, _
Picture1.ScaleWidth, Picture1.ScaleHeight, _
compat_dc, 0, 0, wid, hgt, _
SRCCOPY
' Destroy the compatible DC.
DeleteDC compat_dc
End Sub
' Initialize 256 shades of blue.
Private Sub SetColorTable()
Dim i As Integer
For i = 0 To 255
bm_info.bmiColors(i).rgbRed = 0
bm_info.bmiColors(i).rgbGreen = 0
bm_info.bmiColors(i).rgbBlue = i
bm_info.bmiColors(i).rgbReserved = 0
Next i
End Sub
' Create a drawing.
Private Sub SetPixels()
Dim X As Integer
Dim Y As Integer
wid = 100
hgt = 256
ReDim Pixels(0 To wid - 1, 0 To hgt - 1)
For Y = 0 To hgt - 1
For X = 0 To wid - 1
If Y Mod 20 = 19 Or X Mod 20 = 19 Then
Pixels(X, Y) = Y
Else
Pixels(X, Y) = 255 - Y
End If
Next X
Next Y
End Sub
Private Sub Form_Load()
SetColorTable
SetPixels
CreateDIB
End Sub
Private Sub Form_Resize()
Picture1.Move 0, 0, ScaleWidth, ScaleHeight
Picture1.Refresh
End Sub
Private Sub Picture1_Paint()
DrawDIB
End Sub
Simple and clear code and does exatly what I want. Well, not exactly (it doesn't provide Picture handling), but close enough to be usable