it is known that gdi+ does not bring full support to icon files. so, we can't make some simple conversions to create .ico files directly.
but there are some easy tricks that we can use to do that. the main step is to retrieve a icon handle from our bitmap, the "hicon".
the simplest aproach is to use the olecreatepictureindirect api to obtain a ole picture object reference. next step is to send this object to the savepicture() function to save it to disk.
but the problem of this technique is that the icons are generated at a lousy quality, 4bpp ( 4 bits per pixel ). this means that the se icons can have at most 2^4 = 16 colors, that brings really ugly and bad quality results.
below is the code:
requires vfp9 and gdiplusx to run.
please make sure that you have the latest version!
http://www.codeplex.com/vfpx/wiki/view.aspx?title=gdiplusx&referringtitle=home
* api declarations
declare short destroyicon in user32 integer hicon
declare long olecreatepictureindirect in oleaut32 ;
string @pictdesc , string @riid , long own , object @obj
* initialize gdiplusx
_screen.addproperty("system", newobject("xfcsystem", locfile("system.vcx")))
local lcpict, lciconfile
lcpict = getpict("bmp")
lciconfile = "c:\" + juststem(lcpict) + ".ico"
with _screen.system.drawing
local lhicon
local lobmp as xfcbitmap
lobmp = .bitmap.fromfile(lcpict)
lhicon = lobmp.gethicon()
endwith
if lhicon # 0
*!* typedef struct tagpictdesc
*!* {
*!* uint cbsizeofstruct;
*!* uint pictype;
*!* hicon hicon;
*!* } icon;
*!* struct
*!* {
*!* henhmetafile hemf;
*!* } emf;
*!* } ;
*!* } pictdesc;
#define pictype_icon 3
#define guid_icon2 0h0004020000000000c000000000000046 && "{00020400-0000-0000-c000-000000000046}"
#define guid_icon 0h8109f87b32bf1a108bbb00aa00300cab && "{7bf80981-bf32-101a-8bbb-00aa00300cab}"
local lcpictdesc, lqguid, loiconobj
lcpictdesc = bintoc(16,"4rs") + ; && size of structure
bintoc(pictype_icon, "4rs") + ; && type of image
bintoc(lhicon, "4rs") + ; && image handle
bintoc(0, "4rs")
lqguid = guid_icon
loiconobj = 0
*!* http://msdn2.microsoft.com/en-us/library/ms694511.aspx
*!* stdapi olecreatepictureindirect(
*!* pictdesc* ppictdesc, //pointer to the structure of parameters for picture
*!* refiid riid, //reference to the identifier of the interface
*!* bool fown, //whether the picture is to be destroyed
*!* if true, the picture object is to destroy its picture when the object is destroyed. if false, the caller is responsible for destroying the picture.
*!* void** ppvobj //address of output variable that receives the
*!* // interface pointer requested in riid
*!* );
* create the picture ole object
olecreatepictureindirect(@lcpictdesc, @lqguid, 1, @loiconobj)
if vartype(loiconobj) = 'o'
* save the picture using vfp native function 'savepicture()'
if savepicture(loiconobj, lciconfile)
messagebox('icon created successfully !', 64)
endif
else
messagebox('olecreatepictureindirect() error', 16)
endif
* free the memory handle allocated for the hicon
= destroyicon(lhicon)
endif
return
original picture .bmp | icon picture .ico (16 colors) |
you can try it by yourself without running this code: open mspaint, and load one of the four images on the left. then, select to save the image as a 16 color bitmap, and you'll obtain exactly the same result that olecreatepictureindirect generated. it will use only the color palette below to convert the image.
so, as the result isn't as good as desired, why did i post these codes here ?
that's because the original .net "system.drawing" library uses a similar aproach as the shown above to create icons, in the icon.save() method.
in the next post i'll show how we can convert our bitmaps to high quality icons, but using some good and old gdi ( not gdi+) techniques. the code wont be simple and short as the shown here, but the performance will be similar and the quality will be perfect !
I'm looking forward to trying that Cesar. By co-incidence, I was going to ask about that.
ReplyDeleteGDI is a fascinating subject.
Este articulo estra traducido al español en PortalFox en:
ReplyDelete-- Convertir BMP a ICONO - Parte 1 --
http://www.portalfox.com/article.php?sid=2480
Here's a challenge: How would you convert a bitmap to a metafile? Is it possible?
ReplyDeleteHi Tod,
Yep ! Gdi+ brings some functions to deal with metafiles, but I haven't tried them yet. Anyway, Bo Durban has already tried with success, you can check this here:
http://blog.moxiedata.com/PermaLink,guid,00a6d6f7-ca4b-4269-9e2d-1093559b3bbe.aspx
Regards
Cesar
Thats great! I'll get a chance to meet Bo next month in Atlanta for Fox Forward.
ReplyDelete