Loading+a+GIF+or+JPEG+image

//by Richard Russell, September 2008//

The main Help documentation describes how to [|display a GIF or JPEG image] on the main output window, but you may wish to perform other operations on an image such as accessing its data or displaying it in a static control. In such cases you are likely to need a **handle** to the image.

The function below operates in a similar way to **SYS "LoadImage"** except that it works with JPEG, GIF, BMP, ICO, EMF or WMF images. You can alternatively use the function **FNloadimagegdip2** listed at Loading a PNG or TIFF image because that will load GIF and JPEG images too, and gives better results when the image is very large or needs to be scaled.

code format="bb4w" DEF FNloadimage(file$, RETURN cx%, RETURN cy%, par%) LOCAL iid{}, bmp{}, ix%, iy%, hbm%, hcopy%, pic%, ole%, olpp%, text% DIM iid{a%,b%,c%,d%}, text% LOCAL 513 iid.a% = &7BF80980 : REM. 128-bit iid iid.b% = &101ABF32 iid.c% = &AA00BB8B iid.d% = &AB0C3000 SYS "MultiByteToWideChar", 0, 0, file$, -1, text%, 256 SYS "LoadLibrary", "OLEAUT32.DLL" TO ole% SYS "GetProcAddress", ole%, "OleLoadPicturePath" TO olpp% IF olpp%=0 THEN = 0 SYS olpp%, text%, 0, 0, 0, iid{}, ^pic% : REM. OleLoadPicturePath IF pic%=0 THEN = 0 SYS !(!pic%+12), pic%, ^hbm% : REM. IPicture::get_Handle IF hbm%=0 THEN = 0 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 !(!pic%+8), pic% : REM. IPicture::Release = hcopy% code The parameters to the function are the filename (or URL) 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. Note that a filename must contain the drive name (e.g. **C:**) to distinguish it from an internet URL. 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

code format="bb4w" cx% = 0 cy% = 0 himage% = FNloadimage(filename$, cx%, cy%, FALSE) code Alternatively if you are not interested in knowing the actual dimensions you can modify the function definition by removing the **RETURN** qualifiers:

code format="bb4w" DEF FNloadimage(file$, cx%, cy%, par%) code 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:

code format="bb4w" SYS "DeleteObject", himage% code To use the **FNloadimage** function to display an image in a **static control** see this article.

To access the data of the image you can use the **SYS "GetDIBits"** API as follows:

code format="bb4w" cx% = 0 cy% = 0 himage% = FNloadimage(filename$, cx%, cy%, FALSE)

DIM bmih{biSize%, biWidth%, biHeight%, biPlanes{l&,h&}, \ \ biBitCount{l&,h&}, biCompression%, biSizeImage%, \ \ biXPelsPerMeter%, biYPelsPerMeter%, biClrUsed%, \ \ biClrImportant%}

bmih.biSize% = DIM(bmih{}) bmih.biWidth% = cx% bmih.biHeight% = -cy% bmih.biPlanes.l& = 1 bmih.biBitCount.l& = 24 bmih.biCompression% = 0 bmih.biSizeImage% = ((cx%*(bmih.biBitCount.l& DIV 8) + 3) AND -4) * cy%

DIM imagedata% bmih.biSizeImage%-1

SYS "GetDIBits", @memhdc%, himage%, 0, cy%, imagedata%, bmih{}, 0 TO num% SYS "DeleteObject", himage% IF num% <> cy% ERROR 100, "GetDIBits failed" code This provides the image data in 'top-down' format as RGB triplets stored at **imagedata%**; if you require a different data format modify the members of the **bmih** structure accordingly. Note that each line of image data is always padded (if necessary) to a multiple of four bytes.

If the image data may be too large to be stored on the heap (possibly with **HIMEM** increased) then you can instead allocate the memory using the Windows API:

code format="bb4w" SYS "GlobalAlloc", &40, bmih.biSizeImage% TO imagedata% IF imagedata% = 0 ERROR 100, "Insufficient memory" code but in this case don't forget to free the memory later.