ICONIMAGE structure, useless? (and a small demo)
Posted: Mon Dec 29, 2014 6:44 am
Here is the structure PureBasic uses for ICONIMAGE:
The structure union is meaningless here as the static array members initialized to 0 already take up no memory and all have the same address. How would one go about using that if he wanted to fill the members in an allocated memory block and then write them out to a file? They all have the same address and when you write the icAND member it overwrites the icColors member, and they're both overwritten by the icXOR bytes. Unless I'm missing something fairly obvious, this structure is good for nothing. I tried to make a better one but I didn't have much luck. Using mine is no better than using a BITMAPINFOHEADER structure and then writing the other parts out after it. Can't do anything very elegant here so far. Any ideas? (btw, what follows can serve as a small tutorial for anyone who wants to make an application that converts images to Windows icons. Just remember that to include icons of varying sizes, the ICONHEADER structures are an array and the ICONIMAGE structures follow them, one for each header. Here I'm only putting one icon in the file:
Code: Select all
Structure ICONIMAGE
icHeader.BITMAPINFOHEADER
StructureUnion
icColors.RGBQUAD[0]
icXOR.b[0]
icAND.b[0]
EndStructureUnion
EndStructureCode: Select all
Structure ICONDIR
idReserved.w ; // Reserved (must be 0)
idType.w ; // Resource type (1 for icons)
idCount.w ; // How many images?
idEntries.ICONHEADER[0] ; // The entries for each image
EndStructure
Declare GetMask(image)
Structure ICONIMAGE_MSDN
icHeader.BITMAPINFOHEADER ; // DIB header
icColors.RGBQUAD[0] ; // Color table
Array icXOR.b(0) ; // DIB bits for XOR mask
Array icAND.b(0) ; // DIB bits for AND mask
EndStructure
ii.ICONIMAGE_MSDN
; Make an image to test with
CreateImage(0, 32,32,32,#PB_Image_Transparent)
StartDrawing(ImageOutput(0))
DrawingMode(#PB_2DDrawing_AllChannels)
Box(0,0,16,16,RGBA(255,0,0,255))
Box(16,16,16,16,RGBA(0,0,255,255))
StopDrawing()
; Make a mask for it (at 32bpp for now)
Mask = GetMask(0)
; Start by getting the icXOR bits for the icon's color image
hdcSrc = CreateCompatibleDC_(0)
*bmi.BITMAPINFO = AllocateMemory(SizeOf(BITMAPINFO)+SizeOf(RGBQUAD)*256)
With *bmi
\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
\bmiHeader\biWidth = 32
\bmiHeader\biHeight = 32
\bmiHeader\biPlanes = 1
\bmiHeader\biBitCount = 32
EndWith
GetDIBits_(hdcSrc, ImageID(0), 0, 32, #Null, *bmi, #DIB_RGB_COLORS)
sz_color = *bmi\bmiHeader\biSizeImage
ReDim ii\icXOR(sz_color)
GetDIBits_(hdcSrc, ImageID(0), 0, 32, @ii\icXOR(0), *bmi, #DIB_RGB_COLORS)
FreeMemory(*bmi)
; Then we have to get the 1bpp Mask bits
*bmiMask.BITMAPINFO = AllocateMemory(SizeOf(BITMAPINFO)+SizeOf(RGBQUAD)*256)
With *bmiMask
\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
\bmiHeader\biWidth = 32
\bmiHeader\biHeight = 32
\bmiHeader\biPlanes = 1
\bmiHeader\biBitCount = 1
EndWith
GetDIBits_(hdcSrc, ImageID(Mask), 0, 32, #Null, *bmiMask, #DIB_PAL_COLORS)
sz_mask_1bpp = *bmiMask\bmiHeader\biSizeImage
ReDim ii\icAND(sz_mask_1bpp)
GetDIBits_(hdcSrc, ImageID(Mask), 0, 32, @ii\icAND(0), *bmiMask, #DIB_PAL_COLORS)
FreeMemory(*bmiMask)
DeleteDC_(hdcSrc)
; All is ready, we can write this stuff out to a memory block
*file = AllocateMemory(SizeOf(ICONDIR) + SizeOf(ICONHEADER) + SizeOf(BITMAPINFOHEADER) + sz_color + sz_mask_1bpp)
*dir.ICONDIR = *file
With *dir
\idCount = 1
\idType = 1
EndWith
*ih.ICONHEADER = *file+SizeOf(ICONDIR)
With *ih
\bWidth = 32
\bHeight = 32
\wPlanes = 1
\wBitCount = 32
\dwBytesInRes = SizeOf(BITMAPINFOHEADER) + sz_color + sz_mask_1bpp
\dwBytesOffset = SizeOf(ICONDIR) + SizeOf(ICONHEADER)
EndWith
*iimage.ICONIMAGE = *file + *ih\dwBytesOffset
With *iimage\icHeader
\biSize = SizeOf(BITMAPINFOHEADER)
\biWidth = 32
\biHeight = 32 * 2
\biPlanes = 1
\biBitCount = 32
\biSizeImage = sz_color
EndWith
*color = *file + *ih\dwBytesOffset + SizeOf(BITMAPINFOHEADER)
*mask = *color + sz_color
CopyMemory(@ii\icXOR(0), *color, sz_color)
CopyMemory(@ii\icAND(0), *mask, sz_mask_1bpp)
; Now dump it to a file and see how we did
; If a window comes up with two transparent icons on a "purebasic yellow" background, we succeeded.
If CreateFile(0, "test.ico")
WriteData(0, *file, MemorySize(*file))
CloseFile(0)
EndIf
; Test it, did it make an icon?
ExtractIconEx_("test.ico", 0, @large.i, @small.i, 1)
OpenWindow(0,0,0,640,480,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
SetWindowColor(0, RGB(255,255,223))
ImageGadget(0,10,10,0,0,large)
ImageGadget(1,100,10,0,0,small)
Repeat:Until WaitWindowEvent()=#PB_Event_CloseWindow
;===============================================
; PROCEDURES
;===============================================
Procedure GetMask(image)
Dim maskcolors.b(ImageWidth(image)-1, ImageHeight(image)-1)
mask = CreateImage(#PB_Any, ImageWidth(image), ImageHeight(image), ImageDepth(image), #Black)
StartDrawing(ImageOutput(image))
DrawingMode(#PB_2DDrawing_AlphaChannel)
For j=0 To ImageHeight(image)-1
For i=0 To ImageWidth(image)-1
If Alpha(Point(i,j)) = 0
maskcolors(i,j) = 1
Else
maskcolors(i,j) = 0
EndIf
Next
Next
StopDrawing()
StartDrawing(ImageOutput(mask))
For j=0 To ImageHeight(mask)-1
For i=0 To ImageWidth(mask)-1
If maskcolors(i,j)
Plot(i, j, #White)
Else
Plot(i, j, #Black)
EndIf
Next
Next
StopDrawing()
ProcedureReturn mask
EndProcedure