=====Loading a PNG or TIFF image=====
//by Richard Russell, October 2008, revised November 2010 and January 2012//\\ \\ The article [[/Loading%20a%20GIF%20or%20JPEG%20image|Loading a GIF or JPEG image]] lists a replacement for the **LoadImage** API which works for JPEG, GIF, ICO, EMF and WMF images as well as for BMP images. However two common still-image formats not supported by that function are **PNG** and **TIFF**.\\ \\ The two functions listed below each load PNG and TIFF images in addition to the others (since there's a large variety of different TIFF formats it may load only the more common variants). They require **GDI+** to be installed on the target PC.\\ \\
==== Method 1 ====
\\ This version is the simpler of the two, but can't cope with very large images and, when scaling is required, the quality is not as good as it might be:
DEF FNloadimagegdip(file$, RETURN cx%, RETURN cy%, par%)
LOCAL tSI{}, bmp{}, ix%, iy%, hbm%, bmp%, hcopy%, gdip%, text%, res%, lGDIP%
DIM text% LOCAL 513
SYS "MultiByteToWideChar", 0, 0, file$, -1, text%, 256
SYS "LoadLibrary", "GDIPLUS.DLL" TO gdip%
IF gdip% = 0 ERROR 100, "Couldn't load GDIPLUS.DLL"
SYS "GetProcAddress", gdip%, "GdiplusStartup" TO `GdiplusStartup`
SYS "GetProcAddress", gdip%, "GdipCreateBitmapFromFile" TO `GdipCreateBitmapFromFile`
SYS "GetProcAddress", gdip%, "GdipCreateHBITMAPFromBitmap" TO `GdipCreateHBITMAPFromBitmap`
SYS "GetProcAddress", gdip%, "GdipDisposeImage" TO `GdipDisposeImage`
SYS "GetProcAddress", gdip%, "GdiplusShutdown" TO `GdiplusShutdown`
DIM tSI{GdiplusVersion%, DebugEventCallback%, \
\ SuppressBackgroundThread%, SuppressExternalCodecs%}
tSI.GdiplusVersion% = 1
SYS `GdiplusStartup`, ^lGDIP%, tSI{}, 0
SYS `GdipCreateBitmapFromFile`, text%, ^bmp% TO res%
IF res% THEN
SYS `GdiplusShutdown`, lGDIP%
SYS "FreeLibrary", gdip%
=0
ENDIF
SYS `GdipCreateHBITMAPFromBitmap`, bmp%, ^hbm% TO res%
IF res% THEN
SYS `GdipDisposeImage`, bmp%
SYS `GdiplusShutdown`, lGDIP%
SYS "FreeLibrary", gdip%
=0
ENDIF
DIM bmp{bmType%,bmWidth%,bmHeight%,bmWidthBytes%,bmPlanes{l&,h&}, \
\ bmBitsPixel{l&,h&}, bmBits%}
SYS "GetObject", hbm%, DIM(bmp{}), bmp{}
ix% = bmp.bmWidth%
iy% = bmp.bmHeight%
IF cx%=0 cx% = ix%
IF cy%=0 cy% = iy%
IF par% THEN
IF cx%/cy%>ix%/iy% cx% = cy%*ix%/iy% ELSE cy% = cx%*iy%/ix%
ENDIF
SYS "CopyImage", hbm%, 0, cx%, cy%, 0 TO hcopy%
SYS "DeleteObject", hbm%
SYS `GdipDisposeImage`, bmp%
SYS `GdiplusShutdown`, lGDIP%
SYS "FreeLibrary", gdip%
= hcopy%
==== Method 2 ====
\\ This version is a little more complicated, but can cope with very large images (potentially greater than 10000 x 10000 pixels) and scales the image, when required, with a higher quality:
DEF FNloadimagegdip2(file$, RETURN cx%, RETURN cy%, par%)
LOCAL tSI{}, bmi{}, text%, gdip%, image%, ix%, iy%, lGDIP%
LOCAL hdc%, hdib%, old%, gfx%, bits%
DIM text% LOCAL 513
SYS "MultiByteToWideChar", 0, 0, file$, -1, text%, 256
SYS "LoadLibrary", "GDIPLUS.DLL" TO gdip%
IF gdip% = 0 ERROR 100, "Couldn't load GDIPLUS.DLL"
SYS "GetProcAddress", gdip%, "GdiplusStartup" TO `GdiplusStartup`
SYS "GetProcAddress", gdip%, "GdipLoadImageFromFile" TO `GdipLoadImageFromFile`
SYS "GetProcAddress", gdip%, "GdipDrawImageRectRectI" TO `GdipDrawImageRectRectI`
SYS "GetProcAddress", gdip%, "GdipGetImageHeight" TO `GdipGetImageHeight`
SYS "GetProcAddress", gdip%, "GdipGetImageWidth" TO `GdipGetImageWidth`
SYS "GetProcAddress", gdip%, "GdipCreateFromHDC" TO `GdipCreateFromHDC`
SYS "GetProcAddress", gdip%, "GdipSetSmoothingMode" TO `GdipSetSmoothingMode`
SYS "GetProcAddress", gdip%, "GdipDeleteGraphics" TO `GdipDeleteGraphics`
SYS "GetProcAddress", gdip%, "GdipDisposeImage" TO `GdipDisposeImage`
SYS "GetProcAddress", gdip%, "GdiplusShutdown" TO `GdiplusShutdown`
DIM tSI{GdiplusVersion%, DebugEventCallback%, \
\ SuppressBackgroundThread%, SuppressExternalCodecs%}
DIM bmi{biSize%, biWidth%, biHeight%, biPlanes{l&,h&}, biBitCount{l&,h&}, \
\ biCompression%, biSizeImage%, biXPelsPerMeter%, biYPelsPerMeter%, \
\ biClrUsed%, biClrImportant%}
tSI.GdiplusVersion% = 1
SYS `GdiplusStartup`, ^lGDIP%, tSI{}, 0
SYS `GdipLoadImageFromFile`, text%, ^image%
IF image% = 0 THEN
SYS `GdiplusShutdown`, lGDIP%
SYS "FreeLibrary", gdip%
=0
ENDIF
SYS `GdipGetImageWidth`, image%, ^ix%
SYS `GdipGetImageHeight`, image%, ^iy%
IF cx% = 0 THEN cx% = ix%
IF cy% = 0 THEN cy% = iy%
IF par% THEN
IF cx%/cy%>ix%/iy% cx% = cy%*ix%/iy% ELSE cy% = cx%*iy%/ix%
ENDIF
bmi.biSize% = DIM(bmi{})
bmi.biWidth% = cx%
bmi.biHeight% = -cy%
bmi.biPlanes.l& = 1
bmi.biBitCount.l& = 24
SYS "CreateCompatibleDC", 0 TO hdc%
IF hdc% = 0 ERROR 92, "CreateCompatibleDC failed"
SYS "CreateDIBSection", hdc%, bmi{}, 0, ^bits%, 0, 0 TO hdib%
IF hdib%=0 ERROR 91, "CreateDIBSection failed"
SYS "SelectObject", hdc%, hdib% TO old%
SYS "PatBlt", hdc%, 0, 0, cx%, cy%, &FF0062 : REM WHITENESS
SYS `GdipCreateFromHDC`, hdc%, ^gfx%
IF gfx%=0 ERROR 90, "GdipCreateFromHDC failed"
SYS `GdipSetSmoothingMode`, gfx%, 2
SYS `GdipDrawImageRectRectI`,gfx%,image%,0,0,cx%,cy%,0,0,ix%,iy%,2,0,0,0
SYS "SelectObject", hdc%, old%
SYS "DeleteDC", hdc%
SYS `GdipDeleteGraphics`, gfx%
SYS `GdipDisposeImage`, image%
SYS `GdiplusShutdown`, lGDIP%
SYS "FreeLibrary", gdip%
= hdib%
==== How to use ====
\\ The parameters to the functions are the filename of the image, the required width and height (in pixels) and a flag to indicate whether you want the **aspect ratio** to be preserved or not. The returned value is a **handle** to the image, or zero if the image cannot be found or opened.\\ \\ If the required width and/or height values are supplied as zero then the actual width and/or height of the original image are used. Thus if a non-zero value is supplied for the width and zero is supplied for the height, the image will be scaled horizontally (if required) but not vertically; however if the **preserve aspect ratio** flag is set to TRUE, the then image //will// be scaled vertically to preserve the correct shape.\\ \\ The actual dimensions of the (possibly scaled) image are returned in the second and third parameters, therefore they must be supplied as **variables** rather than as **constants**. Thus if you don't want to scale the image call the function as follows
cx% = 0
cy% = 0
himage% = FNloadimagegdip2(filename$, cx%, cy%, FALSE)
Alternatively if you are not interested in knowing the actual dimensions you can modify the function definition by removing the **RETURN** qualifiers:
DEF FNloadimagegdip2(file$, cx%, cy%, par%)
With this modification you can supply constant values (e.g. 0) as parameters.\\ \\ When you have completely finished with the image you should delete the handle as follows:
SYS "DeleteObject", himage%
To use the **FNloadimagegdip** function to display an image in a **static control** see this [[/Displaying%20a%20JPEG%20or%20GIF%20in%20a%20picture%20box|article]].\\ \\ To access the data of the image it is better to use **Method 2** (in which the bitmap is stored in a **DIB Section**). The local variable **bits%** points to the bitmap data, so that could either be changed to a global or returned from the function as another RETURN parameter. The data is in 'top-down' format as RGB triplets, although a different format could be used by modifying the contents of the **bmi{}** structure.