![]() |
![]() |
![]() |
![]() |
Creating ImagesObviously there are lots of ways to make a digital image that don't require writing your own program. But if you're visualizing 2D data, or converting terrain elevations into displacement or bump maps, or you need to create a gradient that follows an unusual path through RGB space, writing a program can be easier than trying to trick off-the-shelf software into creating the image. This article introduces a set of three qbasic programs that create images in the TGA format originated by Truevision, Inc.. These programs write uncompressed 8-bit grayscale, 8-bit indexed color, and 24-bit images that can be loaded directly into most graphics software. A BASIC Program that Creates a TGA Image The original TGA format is remarkably simple, an 18-byte header (in Windows little-endian byte order) followed by pixel bytes, along with a palette for indexed color images. The pixel data can be compressed using run-length encoding, but it doesn't have to be. The following qbasic program creates a small TGA image containing a rainbow gradient. qbasic keywords appear in red, comments in green. ' tga.bas ' Ernie Wright 24 Aug 97 qbasic allows you to implicitly declare variable types according to the first letter of every variable's name. This is an idea borrowed from FORTRAN, and we'll use it here to tell qbasic that by default we want 16-bit integers. We could also choose to explicitly declare each variable, or use type suffix characters (%, &, !, #, $) in variable names to specify their types. DEFINT A-Z TGA files begin with an 18-byte header that describes the pixel information in the file. qbasic supports user-defined record types, which we'll use here to define both the header and a 24-bit RGB color specifier. TYPE TGAHDR idlen AS STRING * 1 'size of image id field cmaptype AS STRING * 1 'palette type imtype AS STRING * 1 'image type cmapstart AS INTEGER 'lowest color index cmaplen AS INTEGER 'number of palette entries cmapdepth AS STRING * 1 'bit depth of palette RGB xorigin AS INTEGER 'image origin x yorigin AS INTEGER 'image origin y imwidth AS INTEGER 'image width in pixels imheight AS INTEGER 'image height in pixels pixdepth AS STRING * 1 'bits per pixel imdescrip AS STRING * 1 'image descriptor END TYPE TYPE TGARGB blue AS STRING * 1 green AS STRING * 1 red AS STRING * 1 END TYPE qbasic also supports subroutines. This is a forward declaration for a routine that converts between real-valued HSV and byte-valued RGB color spaces. |
DECLARE SUB hsv2rgb (h AS SINGLE, s AS SINGLE, v AS SINGLE, c AS TGARGB) |
DIM hdr AS TGAHDR DIM c AS TGARGB DIM byte AS STRING * 1 w = 256 h = 24 filename$ = "index.tga" Up to this point, the programs for writing grayscale, indexed color, and 24-bit TGA files are the same. Now we have to fill in the TGA header with information that describes the image, so the three programs naturally must now diverge. We'll follow the indexed color example, since it's a bit more complicated than the other two. The qbasic CHR$ function is used to convert an integer to a single-byte value. The &H prefix denotes that the digits are hexadecimal (base 16). hdr.imwidth = w 'image width hdr.imheight = h 'image height hdr.imdescrip = CHR$(&H20) 'origin is upper left hdr.cmaptype = CHR$(1) 'has palette hdr.imtype = CHR$(1) 'indexed color hdr.cmaplen = 256 '256 palette entries hdr.cmapdepth = CHR$(24) '24-bit palette hdr.pixdepth = CHR$(8) '8 bits per pixel This line opens an output file in binary mode. qbasic uses the PUT statement to write to binary files, rather than PRINT. OPEN filename$ FOR BINARY ACCESS WRITE AS 1 All TGA files begin with the 18-byte header. In grayscale and 24-bit TGAs, the header is ordinarily followed immediately by pixel values. Indexed color TGAs add a palette, the format and size of which is described in the cmaplen and cmaptype fields of the header. Here we create a rainbow palette with 256 entries. PUT #1, , hdr FOR i = 0 TO 255 CALL hsv2rgb(359! * i / 255!, 1!, 1!, c) PUT #1, , c NEXT All that's left to do is to write the pixel data. For indexed color images, each pixel is represented by a 1-byte palette index. In grayscale images, the pixel data is a byte containing the gray level. 24-bit color images use a TGARGB record for each pixel. FOR j = 0 TO 23 FOR i = 0 TO 255 byte = CHR$(i) PUT #1, , byte NEXT NEXT We're done. CLOSE 1 |