Hi all !
Can i include jpeg file instead bitmap file , because .bmp very big. My app about 20k but my .bmp have 100k it make my app so huge, if i use .jpg it about 35k.
Posted on 2004-01-13 02:32:48 by neverending
Yes, you can, but then you should be able to load a jpeg as resource and use it
Posted on 2004-01-13 02:38:03 by greenant
Another option is to stick with BMP in resource, and simply compress the resulting exe using an executable packer like UPX.
Remember that even if you do use jpg, that jpg will be decompressed to a bmp regardless, and will still consume a bmp's worth of system resources at runtime.
Posted on 2004-01-13 04:19:27 by Homer
Using an exe compressor means your entire executable gets compressed, though... which is sorta bad because of the way paging works. Same old discussion.

You can include a JPG or PNG (depending on what content the image has) as a binary resource, and use Thomas' PNGLib or find some JPG source (there's some old stuff around by promethee) to load it at runtime.

Sure, you'll be adding code to decompress the file format, and you'll have both the compressed image + decompressed bitmap in memory... the advantage, however, is that pages from your executable can still be shared if you run multiple instances, et cetera.


PNG or JPG should also be able to give you better compression rate than just brute-force UPXing your executable, since these formats were specifically created for image data - especially JPG on 'photo' style data will yield much better ratios than stupid UPXing.
Posted on 2004-01-13 08:54:49 by f0dder
The masm32.lib library also comes with some functions to handle jpg and gif files using no extra libraries. I think the function name you're looking for is BitmapFromResouce, if I recall correctly.
Posted on 2004-01-13 10:15:36 by QvasiModo
Hi neverending,

You use RadASM so select Resource from the Project menu. Click the Add button to add a new resource and in the type drop down you will find a type Image this can be used for JPG or GIF images. In order to translate this to a bitmap handle use the MASM32 library functions by Ernie to convert the image.
[b][i]From the MASM32 library[/i][/b]


invoke BitmapFromResource, hModule, lpName
mov hBitmap,eax

hModule is the instance handle returned from GetModuleHandle
lpName is the ID that you gave the image when you added it to the resources
Posted on 2004-01-13 11:25:12 by donkey

Using an exe compressor means your entire executable gets compressed, though... which is sorta bad because of the way paging works. Same old discussion.

You can include a JPG or PNG (depending on what content the image has) as a binary resource, and use Thomas' PNGLib or find some JPG source (there's some old stuff around by promethee) to load it at runtime.

Sure, you'll be adding code to decompress the file format, and you'll have both the compressed image + decompressed bitmap in memory... the advantage, however, is that pages from your executable can still be shared if you run multiple instances, et cetera.

So it seems like you are saying that dealing with JPG is a pain in the arse.
Are you saying that MS is putting limits on what Win 32 apps can display?.



PNG or JPG should also be able to give you better compression rate than just brute-force UPXing your executable, since these formats were specifically created for image data - especially JPG on 'photo' style data will yield much better ratios than stupid UPXing.
Posted on 2004-02-22 22:41:21 by skywalker

So it seems like you are saying that dealing with JPG is a pain in the arse.
Are you saying that MS is putting limits on what Win 32 apps can display?.

Not really, they just don't support every display format on earth natively... There *IS* GIF and JPEG support via OleLoadPicture, though, this just requires a bit more code than a simple LoadBitmap.

And using UPX is still bad :)
Posted on 2004-02-23 00:45:30 by f0dder
Loading jpgs from resources is fairly straight forward. This is the routine I use (GoAsm) :

.data

IPicture STRUCT
; IUnknown methods
QueryInterface DD
AddRef DD
Release DD
; IPicture methods
get_Handle DD
get_hPal DD
get_Type DD
get_Width DD
get_Height DD
Render DD
set_hPal DD

get_CurDC DD
SelectPicture DD
get_KeepOriginalFormat DD
put_KeepOriginalFormat DD
PictureChanged DD
SaveAsFile DD
get_Attributes DD
IPicture ENDS

#define HIMETRIC_INCH 2540

IID_IPicture GUID <07BF80980H, 0BF32H, 0101AH, 08BH, 0BBH, 000H, \
0AAH, 000H, 030H, 00CH, 0ABH>

.code
LoadPicture FRAME hModule,IDPicture
uses edi
LOCAL pPicture :D
LOCAL hDC :D
LOCAL hTempDC :D
LOCAL OldObj :D
LOCAL hReturnBmp :D
LOCAL OLE_YSIZE_HIMETRIC :D
LOCAL OLE_XSIZE_HIMETRIC :D
LOCAL dwWidth :D
LOCAL dwHeight :D
LOCAL ptTop :POINT
LOCAL ptBtm :POINT

LOCAL pGlobal :D
LOCAL pStream :D
LOCAL hFindRes :D
LOCAL ResSize :D
LOCAL hResData :D
LOCAL pResData :D

; Load the picture from the resource file
invoke FindResource,[hModule],[IDPicture],2110 ;RT_IMAGE
mov [hFindRes],eax
invoke SizeofResource,[hModule],[hFindRes]
mov [ResSize],eax
or eax,eax
jnz >
dec eax
ret
:
invoke LoadResource,[hModule],[hFindRes]
mov [hResData],eax
invoke LockResource,[hResData]
mov [pResData],eax

invoke GlobalAlloc,GMEM_FIXED,[ResSize]
mov [pGlobal],eax

invoke memcopy,[pResData],[pGlobal],[ResSize]

invoke CreateStreamOnHGlobal, [pGlobal], TRUE, ADDR pStream
invoke OleLoadPicture, [pStream], NULL, TRUE, ADDR IID_IPicture, ADDR pPicture

test eax,eax
jz >
; no interface
invoke GlobalFree,[pGlobal]
xor eax,eax
dec eax
ret
:

mov edi, [pPicture]

push OFFSET OLE_YSIZE_HIMETRIC
push edi
mov eax, [edi]
call [eax+IPicture.get_Height]

push OFFSET OLE_XSIZE_HIMETRIC
push edi
mov eax, [edi]
call [eax+IPicture.get_Width]

invoke GetDC,NULL
mov [hDC],eax
invoke CreateCompatibleDC,[hDC]
mov [hTempDC],eax

invoke GetDeviceCaps, [hDC], LOGPIXELSY
invoke MulDiv, [OLE_YSIZE_HIMETRIC], eax, HIMETRIC_INCH
mov [dwHeight], eax
invoke GetDeviceCaps, [hDC], LOGPIXELSX
invoke MulDiv, [OLE_XSIZE_HIMETRIC], eax, HIMETRIC_INCH
mov [dwWidth], eax
invoke CreateIndependantBitmap,[hDC],[dwWidth],[dwHeight]
mov [hReturnBmp],eax
invoke ReleaseDC,NULL,[hDC]
invoke SelectObject,[hTempDC],[hReturnBmp]
mov [OldObj],eax

xor ecx,ecx
push ecx
push [OLE_YSIZE_HIMETRIC]
push [OLE_XSIZE_HIMETRIC]
push ecx
push ecx
push [dwHeight]
push [dwWidth]
push ecx
push ecx
push [hTempDC]
push edi
mov eax, [edi]
call [eax+IPicture.Render]

; release the stream
mov eax, [pStream]
push eax
mov eax, [eax]
call [eax+IPicture.Release]

push edi
mov eax, [edi]
call [eax+IPicture.Release]

; Flip the bitmap
xor ecx,ecx
mov eax,[dwWidth]
mov D[ptBtm.x],eax
mov D[ptTop.x],ecx
mov eax,[dwHeight]
dec eax
dec eax
mov D[ptTop.y],eax
inc eax
neg eax
mov D[ptBtm.y],eax
invoke StretchBlt, [hTempDC], ecx, ecx, [dwWidth], [dwHeight],\
[hTempDC], [ptTop.x], [ptTop.y], [ptBtm.x],[ ptBtm.y], SRCCOPY


invoke SelectObject,[hTempDC],[OldObj]
invoke DeleteDC,[hTempDC]
invoke GlobalFree,[pGlobal]
mov eax,[hReturnBmp]
ret

endf

CreateIndependantBitmap FRAME hDC,SizeX,SizeY
LOCAL bmi :BITMAPINFO

mov D[bmi.bmiHeader.biSize],SIZEOF BITMAPINFOHEADER
mov eax,[SizeX]
mov D[bmi.bmiHeader.biWidth],eax
mov eax,[SizeY]
mov D[bmi.bmiHeader.biHeight],eax
mov W[bmi.bmiHeader.biPlanes],1
mov W[bmi.bmiHeader.biBitCount],32
mov D[bmi.bmiHeader.biCompression],BI_RGB
xor ecx,ecx
invoke CreateDIBSection,[hDC],ADDR bmi,DIB_RGB_COLORS,ecx,ecx,ecx

push eax
invoke GdiFlush
pop eax
ret

endf
Posted on 2004-02-23 00:53:55 by donkey
donkey: An idea: instead of converting himetric inches to pixels by yourself, isn't it better to let GDI do that for you? The DC can be set up to use himetric inches. I tried that some time ago and it worked, if you're interested I can post the sources. :)
Posted on 2004-02-23 12:45:06 by QvasiModo
Donkey,

Nice work.

I have a question for you: can you advise me some references / tutorials about using OLE library functions (ole32.dll and oleaut32.dll ) with Masm or C/C++ ?
Posted on 2004-02-23 12:55:15 by Vortex
Hi QvasiModo,

Actually I was thinking that I could just call the IPicture::get_handle method and use GetObject to do everything. Using CopyBitmap I could make a local GDI handle and do it that way but it isn't much code and I use it so rarely that I have never really put in the effort to improve it. I may take the time one day. Actually I think that's how I did it in TBPaint for some image types but there were errors in the returned values or something, can't remember right now, I have to revisit the problem. In general though I do not like the IPicture interface or OleLoadPicture as it makes a botch of the color tables, I am currently looking at some alternative JPG libs.


Hi Vortex,

I generally hack my way through each interface on an "as needed" basis but I think Mad Wizard has a few tutorials on it, the COM section here is loaded with great examples. Virtually no-one posts there much anymore so any questions are answered very quickly. For myself I have not really seen any tutorials, I just keep plugging at them until they work.

You should also check out Ernie's COM folder in the MASM32 distribution.
Posted on 2004-02-23 13:04:02 by donkey

Hi QvasiModo,

Actually I was thinking that I could just call the IPicture::get_handle method and use GetObject to do everything. Using CopyBitmap I could make a local GDI handle and do it that way but it isn't much code and I use it so rarely that I have never really put in the effort to improve it. I may take the time one day. Actually I think that's how I did it in TBPaint for some image types but there were errors in the returned values or something, can't remember right now, I have to revisit the problem. In general though I do not like the IPicture interface or OleLoadPicture as it makes a botch of the color tables, I am currently looking at some alternative JPG libs.

I vaguely remember that get_Handle didn't work for all image types, but I have to check the docs.
Anyway, I also don't like to use IPicture either, but in the end it's much better than copying the image to a bitmap. Particularly for transparent GIF pictures, you have to make them opaque (at least I never figured out how to keep the transparency, or at least get the transparent color to build a region from it).

I once thought of writing a wrapper, but I thought that it wouldn't be too different from Ernie's lib, or calling the COM interfaces directly... there's not much in between.
Posted on 2004-02-23 13:24:39 by QvasiModo
Yeah, for JPGs it seems fine though...

LoadPictureRes FRAME hModule,IDPicture

uses edi
LOCAL pPicture :D
LOCAL pGlobal :D
LOCAL pStream :D
LOCAL hFindRes :D
LOCAL ResSize :D
LOCAL hResData :D
LOCAL pResData :D
LOCAL hOleBmp :D

; Load the picture from the resource file
invoke FindResource,[hModule],[IDPicture],2110 ;RT_IMAGE
mov [hFindRes],eax
invoke SizeofResource,[hModule],[hFindRes]
mov [ResSize],eax
or eax,eax
jnz >
dec eax
ret
:
invoke LoadResource,[hModule],[hFindRes]
mov [hResData],eax
invoke LockResource,[hResData]
mov [pResData],eax

invoke GlobalAlloc,GMEM_FIXED,[ResSize]
mov [pGlobal],eax

invoke memcopy,[pResData],[pGlobal],[ResSize]

invoke CreateStreamOnHGlobal, [pGlobal], TRUE, ADDR pStream
invoke OleLoadPicture, [pStream], NULL, TRUE, ADDR IID_IPicture, ADDR pPicture

test eax,eax
jz >
; no interface
invoke GlobalFree,[pGlobal]
ret
:

mov edi, [pPicture]

push OFFSET hOleBmp
push edi
mov eax, [edi]
call [eax+IPicture.get_Handle]

invoke CopyImage,[hOleBmp], IMAGE_BITMAP, 0, 0, LR_COPYDELETEORG
push eax

; release the stream
mov eax, [pStream]
push eax
mov eax, [eax]
call [eax+IPicture.Release]

push edi
mov eax, [edi]
call [eax+IPicture.Release]

invoke GlobalFree,[pGlobal]
pop eax
ret
ENDF


Just hacked it out and it returns a pretty good handle. A quick check only showed less than 1% change in the color table (variation in the RGBQUADs from the original) so it is fairly good. From the look of the table I would probably want to sort it before I used the bitmap as it does not seem to be in any good order but that can be expected from straight GDI functions.
Posted on 2004-02-23 13:29:22 by donkey
Great, I'll add it to my snippets folder. :alright:
I'll test it with GIFs and metafiles when I get the time. (Or should I say if I get the time? :grin: ).
Posted on 2004-02-23 13:51:32 by QvasiModo
Hi QvasiModo,

Looked into the GIF format a little and this should return the transparency color :

ReadGifHeader FRAME pFileName

LOCAL hFile :D
LOCAL cbRead :D
LOCAL format[8] :B
LOCAL header[8] :B

LOCAL Width :D
LOCAL Height :D
LOCAL flag :D
LOCAL iBkgnd :D
LOCAL AspectRatio :D

LOCAL ColorDepth :D
LOCAL nColors :D

LOCAL ColorTable[256] :D

LOCAL ExtensionBlock[4] :D
LOCAL TranspColor :D

invoke CreateFile,[pFileName],GENERIC_READ,NULL,NULL,\
OPEN_EXISTING,NULL,NULL
mov [hFile],eax

; File format :
invoke ReadFile,[hFile],OFFSET format,6,OFFSET cbRead,NULL

invoke ReadFile,[hFile],OFFSET header,7,OFFSET cbRead,NULL

movzx eax,W[header]
mov [Width],eax
movzx eax,W[header+2]
mov [Height],eax
movzx eax,B[header+4]
mov [flag],eax

movzx eax,B[header+5]
mov [iBkgnd],eax
movzx eax,B[header+6]
mov [AspectRatio],eax

mov eax,[flag]
and eax,7
mov [ColorDepth],eax
mov ecx,eax
mov eax,2
shl eax,cl

mov [nColors],eax

mov ecx,eax
shl eax,2
sub eax,ecx
invoke ReadFile,[hFile],OFFSET ColorTable,eax,OFFSET cbRead,NULL

mov D[TranspColor],-1
E1:
; Scan the extension blocks for the transparency color (249)
invoke ReadFile,[hFile],OFFSET ExtensionBlock,2,OFFSET cbRead,NULL
movzx eax,B[ExtensionBlock]
cmp eax,021h
jne >>E2
movzx eax,B[ExtensionBlock+1]
cmp eax,0F9h
jne <E1
invoke ReadFile,[hFile],OFFSET ExtensionBlock,8,OFFSET cbRead,NULL
movzx eax,B[ExtensionBlock+4]
mov ecx,eax
shl eax,2
sub eax,ecx
mov eax,[ColorTable+eax]
and eax,0FFFFFFh
mov [TranspColor],eax

E2:
invoke CloseHandle,[hFile]
mov eax,[TranspColor]
RET
ENDF
Posted on 2004-02-23 19:54:26 by donkey
Been toying with your snippets for a while... this is the result.
Two issues:

1. Since we're using the get_Handle method to get the bitmap (and then copying it), shouldn't we copy the pallete as well?

2. Your function will get the RGB values of the transparent GIF, and AFAIK we should use the pallete entry instead. We might have a repeated color in the pallete, one transparent and the other opaque. That would mess up the transparency. Should be easy to fix as long as the IPicture object does not alter the image's original pallete values.

BTW, my sample prog isn't even loading the picture... don't know why. :confused:

EDIT: Attachment updated. It's still not working as I want it to - but this is taking me time from other projects. Maybe I'll finish it later, maybe someone else will? :)
Posted on 2004-03-01 18:41:44 by QvasiModo
I also did this. :)
It's quick and dirty, and I didn't test it yet.
; LoadPictureRes

; Loads a picture from a resource into a GDI bitmap, using the IPicture interface.
; Original GoASM code by Donkey
; Conversion to MASM by QvasiModo

.code
align DWORD
LoadPictureRes PROC USES edi hModule:DWORD,IDPicture:DWORD
LOCAL pPicture :DWORD
LOCAL pGlobal :DWORD
LOCAL pStream :DWORD
LOCAL hFindRes :DWORD
LOCAL ResSize :DWORD
LOCAL hResData :DWORD
LOCAL pResData :DWORD
LOCAL hOleBmp :DWORD

; Load the picture from the resource file
invoke FindResource, hModule, IDPicture, 2110 ;RT_IMAGE
mov hFindRes, eax
invoke SizeofResource, hModule, hFindRes
test eax, eax
.if zero?
dec eax
ret
.endif
mov ResSize, eax
invoke LoadResource, hModule, hFindRes
mov hResData, eax
invoke LockResource, hResData
mov pResData, eax

invoke GlobalAlloc, GMEM_FIXED, ResSize
mov pGlobal, eax

invoke memcopy,pResData,pGlobal,ResSize

invoke CreateStreamOnHGlobal, pGlobal, TRUE, ADDR pStream
invoke OleLoadPicture, pStream, NULL, TRUE, ADDR IID_IPicture, ADDR pPicture

test eax, eax
.if ! zero?
; no interface
invoke GlobalFree, pGlobal
ret
.endif

mov edi, pPicture

push OFFSET hOleBmp
push edi
mov eax, [edi]
call [eax].IPicture.get_Handle

invoke CopyImage,hOleBmp, IMAGE_BITMAP, 0, 0, LR_COPYDELETEORG
push eax

; release the stream
mov eax, pStream
push eax
mov eax, [eax]
call [eax].IPicture.Release

push edi
mov eax, [edi]
call [eax].IPicture.Release

invoke GlobalFree,pGlobal
pop eax
ret

LoadPictureRes ENDP
Posted on 2004-03-01 18:47:08 by QvasiModo
Just to be pedantic - is it okay to use GMEM_FIXED for the GlobalAlloc call? CreateStreamOnHGlobal wants a HGLOBAL as the first parameter, but using GMEM_FIXED returns a pointer, not a HGLOBAL.

Fortunately win32 works a lot different than old 16bit pmode, so a HGLOBAL seems to be more or less a memory pointer, but... there is some difference between allocating with GMEM_FIXED and getting a "true pointer", and not using GMEM_FIXED and getting a (pseudo?) handle.

I haven't experienced any crashes or such on my own win2k, but I guess there might be a tiny risk of some internal structure corruption (though that might only happen, if at all, when treating the return value of GlobalAlloc without GMEM_FIXED flag as a pointer).

Don't know how bad it is in practice, but at least it seems "logically wrong" to use GMEM_FIXED for the memory?
Posted on 2004-03-02 03:40:17 by f0dder
You have a point, I overlooked the fact that a I needed a handle, not a pointer. I'll try that, thanks! :)
Posted on 2004-03-02 13:29:35 by QvasiModo