Rexx/gd is a Rexx extension allowing you to quickly draw images complete with lines, arcs, text, multiple colors, cut and paste from other images, and flood fills, and write out the result as a PNG or JPEG file. This is particularly useful in World Wide Web applications, where PNG and JPEG are two of the formats accepted for inline images by most browsers. Rexx/gd does not create GIF files. Unisys holds a patent on the LZW compression algorithm, which is used in fully compressed GIF images.
Rexx/gd is not a paint program. If you are looking for a paint program, you are looking in the wrong place. If you are not a Rexx programmer, you are looking in the wrong place.
Rexx/gd does not provide for every possible desirable graphics operation. Rexx/gd is based on the freely available gd library.
What else do I need to use Rexx/gd?
Well, you obviously need a Rexx interpreter! Rexx/gd will work with any Rexx interpreter that supports the SAA API.
Rexx/gd is dependent on the requirements of the underlying gd library. As such Rexx/gd requires the following:
If you want to see the images you have created, then you will need a PNG and/or JPEG viewer. Most browsers will be able to view these files.
While this all looks daunting, the DOS, Win32 and OS/2 ports of Rexx/gd are statically linked with ports of all of the above packages, so you don't need anything else, other than Rexx/gd.
On Unix platforms, things are not as simple :-( You will need to install (possibly build) the above packages. Once you have done this, then the configure script that comes with Rexx/gd should find all of the required libraries. if not, you can always specify where you have installed the packages. Note that you will need development versions of the packages; ie. library files and header files!
Rexx/gd basics: using Rexx/gd in your program
To use Rexx/gd in your
program, load the library with RxFuncAdd as you would for any other Rexx extensions
and call GdLoadFuncs.
Here is a short example program. (For a more advanced example, see rexxgddemo.rexx, included in the distribution. rexxgddemo.rexx is NOT the same program; it demonstrates additional features!)
/* Load the Rexx/gd library functions */ Call RxFuncAdd 'GdLoadFuncs', 'rexxgd', 'GdLoadFuncs' Call GdLoadFuncs /* Allocate the image: 64 pixels across by 64 pixels tall */ im = gdImageCreate(64, 64) /* Allocate the color black (red, green and blue all minimum). Since this is the first color in a new image, it will be the background color. */ black = gdImageColorAllocate(im, 0, 0, 0) /* Allocate the color white (red, green and blue all maximum). */ white = gdImageColorAllocate(im, 255, 255, 255) /* Draw a line from the upper left to the lower right, using white color index. */ Call gdImageLine im, 0, 0, 63, 63, white /* Output the image to the disk file in PNG format. */ gdImagePng(im, 'test.png'); /* Output the same image in JPEG format, using the default JPEG quality setting. */ Call gdImageJpeg im, 'test.jpg', -1 /* Destroy the image in memory. */ Call gdImageDestroy imWhen executed, this program creates an image, allocates two colors (the first color allocated becomes the background color), draws a diagonal line (note that 0, 0 is the upper left corner), writes the image to PNG and JPEG files, and destroys the image.
The above example program should give you an idea of how the package works. Rexx/gd provides many additional functions, which are listed in the following reference chapters, complete with code snippets demonstrating each. There is also an alphabetical index.
im = gdImageCreate(64, 64) /* ... Use the image ... */ Call gdImageDestroy im
im = gdImageCreateFromJpeg("myjpeg.jpg") Say 'Image size:' gdImageGetWidth(im) 'x' gdImageGetHeight(im) Call gdImageDestroy im
im = gdImageCreateFromPng("mypng.png") Say 'Image size:' gdImageGetWidth(im) 'x' gdImageGetHeight(im) Call gdImageDestroy im
im = gdImageCreateFromGd("mygd.gd") Say 'Image size:' gdImageGetWidth(im) 'x' gdImageGetHeight(im) Call gdImageDestroy im
im = gdImageCreateFromGd2("mygd2.gd2") Say 'Image size:' gdImageGetWidth(im) 'x' gdImageGetHeight(im) Call gdImageDestroy im
EXAMPLE ???
im = gdImageCreateFromXbm("myxbm.xbm") Say 'Image size:' gdImageGetWidth(im) 'x' gdImageGetHeight(im) Call gdImageDestroy im
im = gdImageCreate(10, 10) /* ... Use the image ... */ /* Now destroy it */ Call gdImageDestroy im
If jpeg_quality is negative, the default IJG JPEG quality value (which should yield a good general quality / size tradeoff for most situations) is used. Otherwise, for practical purposes, quality should be a value in the range 0-95, higher quality values usually implying both higher quality and larger image sizes.
If you have set image interlacing using gdImageInterlace, this function will interpret that to mean you wish to output a progressive JPEG. Some programs (e.g., Web browsers) can display progressive JPEGs incrementally; this can be useful when browsing over a relatively slow communications link, for example. Progressive JPEGs can also be slightly smaller than sequential (non-progressive) JPEGs.
/* Create the image */ im = gdImageCreate(100, 100) /* Allocate background */ white = gdImageColorAllocate(im, 255, 255, 255) /* Allocate drawing color */ black = gdImageColorAllocate(im, 0, 0, 0) /* Draw rectangle */ gdImageRectangle(im, 0, 0, 99, 99, black) /* Write JPEG using default quality */ Call gdImageJpeg im, "rect.jpg", -1 /* Destroy image */ Call gdImageDestroy im
/* Create the image */ im = gdImageCreate(100, 100) /* Allocate background */ white = gdImageColorAllocate(im, 255, 255, 255) /* Allocate drawing color */ black = gdImageColorAllocate(im, 0, 0, 0) /* Draw rectangle */ gdImageRectangle(im, 0, 0, 99, 99, black) /* Write PNG file */ Call gdImagePng im, "rect.png" /* Destroy image */ Call gdImageDestroy im
WBMP file support is black and white only. The color index specified by the fg argument is the "foreground," and only pixels of this color will be set in the WBMP file. All other pixels will be considered "background."
/* Create the image */ im = gdImageCreate(100, 100) /* Allocate background */ white = gdImageColorAllocate(im, 255, 255, 255) /* Allocate drawing color */ black = gdImageColorAllocate(im, 0, 0, 0) /* Draw rectangle */ gdImageRectangle(im, 0, 0, 99, 99, black) /* Write PNG file */ Call gdImageWBMP im, "rect.wbmp", black /* Destroy image */ Call gdImageDestroy im
The gd image format is intended for fast reads and writes of images your program will need frequently to build other images. It is not a compressed format, and is not intended for general use.
/* Create the image */ im = gdImageCreate(100, 100) /* Allocate background */ white = gdImageColorAllocate(im, 255, 255, 255) /* Allocate drawing color */ black = gdImageColorAllocate(im, 0, 0, 0) /* Draw rectangle */ gdImageRectangle(im, 0, 0, 99, 99, black) /* Write PNG file */ Call gdImageGd im, "rect.gd", black /* Destroy image */ Call gdImageDestroy im
The gd2 image format is intended for fast reads and writes of parts of images. It is a compressed format, and well suited to retrieving smll sections of much larger images.
The file is stored as a series of compressed subimages, and the chunkSize determines the sub-image size - a value of zero causes the GD library to use the default.
It is also possible to store GD2 files in an uncompressed format, in which case the fmt should be GD2RAW. To store GD2 files in compressed format specify GD2COMPRESSED for fmt.
/* Create the image */ im = gdImageCreate(100, 100) /* Allocate background */ white = gdImageColorAllocate(im, 255, 255, 255) /* Allocate drawing color */ black = gdImageColorAllocate(im, 0, 0, 0) /* Draw rectangle */ gdImageRectangle(im, 0, 0, 99, 99, black) /* Write PNG file */ Call gdImageGd im, "rect.gd", 0, "GD2COMPRESSED" /* Destroy image */ Call gdImageDestroy im
im = gdImageCreate(100, 100) /* Background color (first allocated) */ black = gdImageColorAllocate(im, 0, 0, 0) /* Allocate the color white (red, green and blue all maximum). */ white = gdImageColorAllocate(im, 255, 255, 255) /* Set a pixel near the center. */ Call gdImageSetPixel im, 50, 50, white /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
im = gdImageCreate(100, 100) /* Background color (first allocated) */ black = gdImageColorAllocate(im, 0, 0, 0) /* Allocate the color white (red, green and blue all maximum). */ white = gdImageColorAllocate(im, 255, 255, 255) /* Draw a line from the upper left corner to the lower right corner. */ Call gdImageLine im, 0, 0, 99, 99, white /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
im = gdImageCreate(100, 100) /* Background color (first allocated) */ black = gdImageColorAllocate(im, 0, 0, 0) /* Allocate the color white (red, green and blue all maximum). */ white = gdImageColorAllocate(im, 255, 255, 255) /* Draw a triangle. */ x.0 = 3; x.1 = 50; x.2 = 99; x.3 = 0; y.0 = 3; y.1 = 0; y.2 = 99; y.3 = 99; Call gdImagePolygon im, 'x.', 'y.', white /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
im = gdImageCreate(100, 100) /* Background color (first allocated) */ black = gdImageColorAllocate(im, 0, 0, 0) /* Allocate the color white (red, green and blue all maximum). */ white = gdImageColorAllocate(im, 255, 255, 255) red = gdImageColorAllocate(im, 255, 0, 0) /* Draw a triangle. */ x.0 = 3; x.1 = 50; x.2 = 99; x.3 = 0; y.0 = 3; y.1 = 0; y.2 = 99; y.3 = 99; /* Paint it in white */ Call gdImageFilledPolygon im, 'x.', 'y.', white /* Outline it in red; must be done second */ Call gdImagePolygon im, 'x.', 'y.', red /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
im = gdImageCreate(100, 100) /* Background color (first allocated) */ black = gdImageColorAllocate(im, 0, 0, 0) /* Allocate the color white (red, green and blue all maximum). */ white = gdImageColorAllocate(im, 255, 255, 255) /* Draw a rectangle occupying the central area. */ Call gdImageRectangle im, 25, 25, 74, 74, white /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
im = gdImageCreate(100, 100) /* Background color (first allocated) */ black = gdImageColorAllocate(im, 0, 0, 0) /* Allocate the color white (red, green and blue all maximum). */ white = gdImageColorAllocate(im, 255, 255, 255) /* Draw a rectangle occupying the central area. */ Call gdImageRectangle im, 25, 25, 74, 74, white /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
im = gdImageCreate(100, 50) /* Background color (first allocated) */ black = gdImageColorAllocate(im, 0, 0, 0) /* Allocate the color white (red, green and blue all maximum). */ white = gdImageColorAllocate(im, 255, 255, 255) /* Inscribe an ellipse in the image. */ Call gdImageArc im, 50, 25, 98, 48, 0, 360, white /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
The fill color can be GDTILED, resulting in a tile fill using another image as the tile. However, the tile image cannot be transparent. If the image you wish to fill with has a transparent color index, call gdImageTransparent on the tile image and set the transparent color index to -1 to turn off its transparency.
Note that gdImageFill is recursive. It is not the most naive implementation possible, and the implementation is expected to improve, but there will always be degenerate cases in which the stack can become very deep. This can be a problem in MSDOS and MS Windows 3.1 environments. (Of course, in a Unix or Win32 environment with a proper stack, this is not a problem at all.)
im = gdImageCreate(100, 50) /* Background color (first allocated) */ black = gdImageColorAllocate(im, 0, 0, 0) /* Allocate the color white (red, green and blue all maximum). */ white = gdImageColorAllocate(im, 255, 255, 255) /* Allocate the color red. */ red = gdImageColorAllocate(im, 255, 0, 0) /* Inscribe an ellipse in the image. */ Call gdImageArc im, 50, 25, 98, 48, 0, 360, white /* Flood-fill the ellipse. Fill color is red, and will replace the black interior of the ellipse. */ Call gdImageFill im, 50, 50, red; /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
The border color cannot be a special color such as GDTILED; it must be a proper solid color. The fill color can be, however.
Note that gdImageFillToBorder is recursive. It is not the most naive implementation possible, and the implementation is expected to improve, but there will always be degenerate cases in which the stack can become very deep. This can be a problem in MSDOS and MS Windows 3.1 environments. (Of course, in a Unix or Win32 environment with a proper stack, this is not a problem at all.)
im = gdImageCreate(100, 50) /* Background color (first allocated) */ black = gdImageColorAllocate(im, 0, 0, 0) /* Allocate the color white (red, green and blue all maximum). */ white = gdImageColorAllocate(im, 255, 255, 255) /* Allocate the color red. */ red = gdImageColorAllocate(im, 255, 0, 0) /* Inscribe an ellipse in the image. */ Call gdImageArc im, 50, 25, 98, 48, 0, 360, white /* Flood-fill the ellipse. Fill color is red, border color is white (ellipse). */ Call gdImageFillToBorder im, 50, 50, white, red /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
gdImageSetBrush is used to specify the brush to be used in a particular image. You can set any image to be the brush. If the brush image does not have the same color map as the first image, any colors missing from the first image will be allocated. If not enough colors can be allocated, the closest colors already available will be used. This allows arbitrary PNGs to be used as brush images. It also means, however, that you should not set a brush unless you will actually use it; if you set a rapid succession of different brush images, you can quickly fill your color map, and the results will not be optimal.
You need not take any special action when you are finished with a brush. As for any other image, if you will not be using the brush image for any further purpose, you should call gdImageDestroy. You must not use the color GDBRUSHED if the current brush has been destroyed; you can of course set a new brush to replace it.
im = gdImageCreate(100, 100) /* Open the brush PNG. For best results, portions of the brush that should be transparent (ie, not part of the brush shape) should have the transparent color index. */ brush = gdImageCreateFromPng("star.png") /* Background color (first allocated) */ black = gdImageColorAllocate(im, 0, 0, 0) Call gdImageSetBrush im, brush /* Draw a line from the upper left corner to the lower right corner using the brush. */ Call gdImageLine im, 0, 0, 99, 99, "GDBRUSHED" /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im /* Destroy the brush image */ Call gdImageDestroy brush
gdImageSetTile is used to specify the tile to be used in a particular image. You can set any image to be the tile. If the tile image does not have the same color map as the first image, any colors missing from the first image will be allocated. If not enough colors can be allocated, the closest colors already available will be used. This allows arbitrary PNGs to be used as tile images. It also means, however, that you should not set a tile unless you will actually use it; if you set a rapid succession of different tile images, you can quickly fill your color map, and the results will not be optimal.
You need not take any special action when you are finished with a tile. As for any other image, if you will not be using the tile image for any further purpose, you should call gdImageDestroy. You must not use the color GDTILED if the current tile has been destroyed; you can of course set a new tile to replace it.
im = gdImageCreate(100, 100) /* Open the tile PNG. For best results, portions of the tile that should be transparent (ie, allowing the background to shine through) should have the transparent color index. */ tile = gdImageCreateFromPng("star.png") /* Background color (first allocated) */ black = gdImageColorAllocate(im, 0, 0, 0) Call gdImageSetTile im, tile /* Fill an area using the tile. */ Call gdImageFilledRectangle im, 25, 25, 75, 75, "GDTILED" /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im /* Destroy the tile image */ Call gdImageDestroy tile
To use gdImageSetStyle, create an array of colors to be repeated. You can assign the special color value; GDTRANSPARENT to indicate that the existing color should be left unchanged for that particular pixel (allowing a dashed line to be attractively drawn over an existing image).
Then, to draw a line using the style, use the normal gdImageLine function with the special color value; GDSTYLED.
You can also combine styles and brushes to draw the brush image at intervals instead of in a continuous stroke. When creating a style for use with a brush, the style values are interpreted differently: zero (0) indicates pixels at which the brush should not be drawn, while one (1) indicates pixels at which the brush should be drawn. To draw a styled, brushed line, you must use the special color value; GDSTYLEDBRUSHED. For an example of this feature in use, see rexxgddemo.rexx (provided in the distribution).
im = gdImageCreate(100, 100) /* Background color (first allocated) */ black = gdImageColorAllocate(im, 0, 0, 0) red = gdImageColorAllocate(im, 255, 0, 0) /* Set up dotted style. Leave every other pixel alone. */ styledotted.1 = red styledotted.2 = "GDTRANSPARENT" styledotted.0 = 2 /* Set up dashed style. Three on, three off. */ styledashed.1 = red styledashed.2 = red styledashed.3 = red styledashed.4 = "GDTRANSPARENT" styledashed.5 = "GDTRANSPARENT" styledashed.6 = "GDTRANSPARENT" styledashed.0 = 6 /* Set dotted style. Note that we have to specify how many pixels are in the style! */ Call gdImageSetStyle im, "STYLEDOTTED." /* Draw a line from the upper left corner to the lower right corner. */ Call gdImageLine im, 0, 0, 99, 99, "GDSTYLED" /* Now the dashed line. */ Call gdImageSetStyle(im, "STYLEDASHED." Call gdImageLine im, 0, 99, 0, 99, "GDSTYLED" /* ... Do something with the image, such as saving it to a file ... */ /* Destroy it */ Call gdImageDestroy im
im = gdImageCreateFromPng("mypng.png") c = gdImageGetPixel(im, gdImageGetWidth(im) % 2, gdImageGetHeight(im) % 2) Say "The value of the center pixel is" c Say "RGB values are" gdImageColorRed(im,c)","gdImageColorGreen(im,c)","gdImageColorBlue(im,c) Call gdImageDestroy im
If gdImageBoundsSafe(im, 50, 50) Then Say "50, 50 is within the image bounds" Else Say "50, 50 is outside the image bounds" Call gdImageDestroy im
Say "Large font is" gdFontGetHeight("GDFONTLARGE") "pixels high."
Say "Large font is" gdFontGetWidth("GDFONTLARGE") "pixels wide."
im = gdImageCreate(100, 100) /* Background color (first allocated) */ black = gdImageColorAllocate(im, 0, 0, 0) /* Allocate the color white (red, green and blue all maximum). */ white = gdImageColorAllocate(im, 255, 255, 255) /* Draw a character. */ Call gdImageChar im, "GDFONTLARGE", 0, 0, 'Q', white /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
im = gdImageCreate(100, 100) /* Background color (first allocated) */ black = gdImageColorAllocate(im, 0, 0, 0) /* Allocate the color white (red, green and blue all maximum). */ white = gdImageColorAllocate(im, 255, 255, 255) /* Draw a character upwards so it rests against the top of the image. */ Call gdImageCharUp(im, "GDFONTLARGE", 0, gdFontGetHeight("GDFONTLARGE"), 'Q', white /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
/* String to draw. */ string = "Hello." /* Font to use */ font = "GDFONTLARGE" im = gdImageCreate(100, 100) /* Background color (first allocated) */ black = gdImageColorAllocate(im, 0, 0, 0) /* Allocate the color white (red, green and blue all maximum). */ white = gdImageColorAllocate(im, 255, 255, 255) /* Draw a centered string. */ Call gdImageString(im, font, gdImageGetWidth(im) % 2 - ( Length(string) * gdFontGetWidth(font) % 2 ), gdImageGetHeight(im) % 2 - gdFontGetHeight(font) % 2, string, white) /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
This function provides a means of rendering fonts with more than 256 characters for those who have them. A more frequently used routine is gdImageString.
/* String to draw. */ string = "Hello." /* Font to use */ font = "GDFONTLARGE" im = gdImageCreate(100, 100) /* Background color (first allocated) */ black = gdImageColorAllocate(im, 0, 0, 0) /* Allocate the color white (red, green and blue all maximum). */ white = gdImageColorAllocate(im, 255, 255, 255) /* Draw a centered string. */ Call gdImageStringUp(im, font, gdImageGetWidth(im) % 2 - ( Length(string) * gdFontGetWidth(font) % 2 ), gdImageGetHeight(im) % 2 - gdFontGetHeight(font) % 2, string, white) /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
This function provides a means of rendering fonts with more than 256 characters for those who have them. A more frequently used routine is gdImageStringUp.
On return, gdImageStringTTF returns "" if successful, or an error string if unsuccessful. The brect array is filled on return from gdImageStringTTF with the 8 elements representing the 4 corner coordinates of the bounding rectangle:
brect.1 | lower left corner, X position |
brect.2 | lower left corner, Y position |
brect.3 | lower right corner, X position |
brect.4 | lower right corner, Y position |
brect.5 | upper right corner, X position |
brect.6 | upper right corner, Y position |
brect.7 | upper left corner, X position |
brect.8 | upper left corner, Y position |
The points are relative to the text regardless of the angle, so "upper left" means in the top left-hand corner seeing the text horizontally.
Use an empty argument for im to get the bounding rectangle without rendering. This is a relatively cheap operation if followed by a rendering of the same string, because of the caching of the partial rendering during bounding rectangle calculation.
The string is rendered in the color indicated. Use the negative of the desired color index to disable anti-aliasing.
The string may contain UTF-8 sequences like: "À"
string = "Hello." /* String to draw. */ size = 40 fontname = "/usr/local/share/ttf/Times.ttf" /* User supplied font */ /* obtain brect so that we can size the image */ err = gdImageStringTTF( ,"brect.",0,fontname,size,0,0,0,string) If err \= "" Then Do Say "Error with gdImageStringTTF():" err return 1 End /* create an image big enough for the string plus a little whitespace */ x = brect.3-brect.7 + 6 y = brect.4-brect.8 + 6 im = gdImageCreate(x,y) /* Background color (first allocated) */ white = gdImageColorResolve(im, 255, 255, 255) black = gdImageColorResolve(im, 0, 0, 0) /* render the string, offset origin to center string*/ /* note that we use top-left coordinate for adjustment * since gd origin is in top-left with y increasing downwards. */ x = 3 - brect.7 y = 3 - brect.8 err = gdImageStringTTF(im,"brect.",black,fontname,size,0,x,y,string) If err \= "" Then Do Say "Error with gdImageStringTTF():" err return 1 End /* Save image */ Call gdImagePng im, "mypng.png" /* Destroy it */ Call gdImageDestroy im
In the event that all gdMaxColors colors (256) have already been allocated, gdImageColorAllocate will return -1 to indicate failure. (This is not uncommon when working with existing PNG files that already use 256 colors.) Note that gdImageColorAllocate does not check for existing colors that match your request; see gdImageColorExact, gdImageColorClosest and gdImageColorClosestHWB for ways to locate existing colors that approximate the color desired in situations where a new color is not available. Also see gdImageColorResolve.
... inside a function ... im = gdImageCreate(100, 100) /* Background color (first allocated) */ black = gdImageColorAllocate(im, 0, 0, 0) /* Allocate the color red. */ red = gdImageColorAllocate(im, 255, 0, 0) /* Draw a dashed line from the upper left corner to the lower right corner. */ Call gdImageLine im, 0, 0, 99, 99, red /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
If no colors have yet been allocated in the image, gdImageColorClosest returns -1.
This function is most useful as a backup method for choosing a drawing color when an image already contains gdMaxColors (256) colors and no more can be allocated. (This is not uncommon when working with existing PNG files that already use many colors.) See gdImageColorExact for a method of locating exact matches only.
/* Let's suppose that photo.png is a scanned photograph with many colors. */ im = gdImageCreateFromPng("photo.png"); /* Try to allocate red directly */ red = gdImageColorAllocate(im, 255, 0, 0) /* If we fail to allocate red... */ If red = -1 Then Do /* Find the closest color instead. */ red = gdImageColorClosest(im, 255, 0, 0) End /* Draw a line from the upper left corner to the lower right corner */ Call gdImageLine im, 0, 0, 99, 99, red /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
If no colors have yet been allocated in the image, gdImageColorClosestHWB returns -1.
This function is most useful as a backup method for choosing a drawing color when an image already contains gdMaxColors (256) colors and no more can be allocated. (This is not uncommon when working with existing PNG files that already use many colors.) See gdImageColorExact for a method of locating exact matches only.
/* Let's suppose that photo.png is a scanned photograph with many colors. */ im = gdImageCreateFromPng("photo.png") /* Try to allocate red directly */ red = gdImageColorAllocate(im, 255, 0, 0) /* If we fail to allocate red... */ If red = -1 Then Do /* Find the closest color instead. */ red = gdImageColorClosestHWB(im, 255, 0, 0) End /* Draw a line from the upper left corner to the lower right corner */ Call gdImageLine im, 0, 0, 99, 99, red /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
im = gdImageCreateFromPng("photo.png") /* The image may already contain red; if it does, we'll save a slot in the color table by using that color. */ /* See if red already exists */ red = gdImageColorExact(im, 255, 0, 0) /* If red isn't already present... */ If red = -1 Then Do /* Second best: try to allocate it directly. */ red = gdImageColorAllocate(im, 255, 0, 0) /* Out of colors, so find the closest color instead. */ If red = -1 Then red = gdImageColorClosest(im, 255, 0, 0) End /* Draw a line from the upper left corner to the lower right corner */ Call gdImageLine im, 0, 0, 99, 99, red /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
im = gdImageCreateFromPng("photo.png") /* The image may already contain red; if it does, we'll save a slot in the color table by using that color. */ /* Get index of red, or color closest to red */ red = gdImageColorResolve(im, 255, 0, 0); /* Draw a line from the upper left corner to the lower right corner */ Call gdImageLine im, 0, 0, 99, 99, red /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
im = gdImageCreateFromPng("photo.png") /* Look for red in the color table. */ red = gdImageColorExact(im, 255, 0, 0) /* If red is present... */ If red != -1 Then Do /* Deallocate it. */ Call gdImageColorDeallocate im, red /* Allocate blue, reusing slot in table. Existing red pixels will change color. */ blue = gdImageColorAllocate(im, 0, 0, 255) End /* ... Do something with the image, such as saving it to a file... */ /* Destroy it */ Call gdImageDestroy im
The color index used should be an index allocated by gdImageColorAllocate, whether explicitly invoked by your code or implicitly invoked by loading an image. In order to ensure that your image has a reasonable appearance when viewed by users who do not have transparent background capabilities (or when you are writing a JPEG-format file, which does not support transparency), be sure to give reasonable RGB values to the color you allocate for use as a transparent color, even though it will be transparent on systems that support PNG transparency.
im = gdImageCreateFromPng("photo.png") /* Look for black in the color table and make it transparent. */ black = gdImageColorExact(im, 0, 0, 0) /* If black is present... */ If black != -1 Then Do /* Make it transparent */ Call gdImageColorTransparent im, black End /* Save the newly-transparent image back to the file */ Call gdImagePng im, "photo.png" /* Destroy it */ Call gdImageDestroy im
dstX and dstY arguments specify the point in the destination image to which the region will be copied. The srcX and srcY arguments specify the upper left corner of the region in the source image. The width and height arguments specify the width and height of the region.
When you copy a region from one location in an image to another location in the same image, gdImageCopy will perform as expected unless the regions overlap, in which case the result is unpredictable.
Important note on copying between images: since different images do not necessarily have the same color tables, pixels are not simply set to the same color index values to copy them. gdImageCopy will attempt to find an identical RGB value in the destination image for each pixel in the copied portion of the source image by invoking gdImageColorExact. If such a value is not found, gdImageCopy will attempt to allocate colors as needed using gdImageColorAllocate. If both of these methods fail, gdImageCopy will invoke gdImageColorClosest to find the color in the destination image which most closely approximates the color of the pixel being copied.
/* Load a small png to tile the larger one with */ im_in = gdImageCreateFromPng("small.png") /* Get size of im_in for later use */ in_x = gdImageGetWidth(im_in) in_y = gdImageGetHeight(im_in) /* Make the output image four times as large on both axes */ im_out = gdImageCreate(in_x * 4, in_y * 4) /* Now tile the larger image using the smaller one */ Do y = 0 To 3 Do x = 0 To 3 Call gdImageCopy im_out, im_in, x * in_x, y * in_y, 0, 0, in_x, in_y End End Call gdImagePng im_out, "tiled.png" Call gdImageDestroy im_in Call gdImageDestroy im_out
The dstX and dstY arguments specify the point in the destination image to which the region will be copied. The srcX and srcY arguments specify the upper left corner of the region in the source image. The dstW and dstH arguments specify the width and height of the destination region. The srcW and srcH arguments specify the width and height of the source region and can differ from the destination size, allowing a region to be scaled during the copying process.
When you copy a region from one location in an image to another location in the same image, gdImageCopy will perform as expected unless the regions overlap, in which case the result is unpredictable. If this presents a problem, create a scratch image in which to keep intermediate results.
Important note on copying between images: since images do not necessarily have the same color tables, pixels are not simply set to the same color index values to copy them. gdImageCopy will attempt to find an identical RGB value in the destination image for each pixel in the copied portion of the source image by invoking gdImageColorExact. If such a value is not found, gdImageCopy will attempt to allocate colors as needed using gdImageColorAllocate. If both of these methods fail, gdImageCopy will invoke gdImageColorClosest to find the color in the destination image which most closely approximates the color of the pixel being copied.
/* Load a small png to expand in the larger one */ im_in = gdImageCreateFromPng("small.png") /* Get size of im_in and out_im for later use */ in_x = gdImageGetWidth(im_in) in_y = gdImageGetHeight(im_in) out_x = gdImageGetWidth(im_out) out_y = gdImageGetHeight(im_out) /* Make the output image four times as large on both axes */ im_out = gdImageCreate(im_in->sx * 4, im_in->sy * 4); /* Now copy the smaller image, but four times larger */ Call gdImageCopyResized im_out, im_in, 0, 0, 0, 0, out_x, out_y, in_x, in_y Call gdImagePng im_out, "large.png" Call gdImageDestroy im_in Call gdImageDestroy im_out
If, however, pct is less than 100, then the two images are merged. With pct = 0, no action is taken.
This feature is most useful to 'highlight' sections of an image by merging a solid color with pct = 50:
Call gdImageCopyMerge im_out, im_in, 100, 200, 0, 0, 30, 50, 50
Call gdImageCopyMergeGray im_out, im_in, 100, 200, 0, 0, 30, 50, 50
cmpMask = gdImageCompare(im1, im2) If gdImageDifferent(cmpMask) Then Say "Images will display differently" If gdImageDifferentTransparent(cmpMask) Then Say "Images have different transparency indexes"
A nonzero value for the interlace argument turns on interlace; a zero value turns it off. Note that interlace has no effect on other functions, and has no meaning unless you save the image in PNG or JPEG format; the gd and xbm formats do not support interlace.
When a PNG is loaded with gdImageCreateFromPng or a JPEG is loaded with gdImageCreateFromJpeg, interlace will be set according to the setting in the PNG or JPEG file.
Note that many PNG and JPEG viewers and web browsers do not support interlace or the incremental display of progressive JPEGs. However, the interlaced PNG or progressive JPEG should still display; it will simply appear all at once, just as other images do.
/* Load the image */ im_in = gdImageCreateFromPng("test.png") /* Now turn on interlace */ Call gdImageInterlace im, 1 /* And open an output file */ /* Save the image -- could also use gdImageJpeg */ Call gdImagePng im, "test.png" Call gdImageDestroy im