A TARGA Viewer in Borland Delphi

After examining the TARGA graphics file format, Gunter builds a TARGA viewer using Borland's Delphi development environment.


January 01, 1996
URL:http://www.drdobbs.com/tools/a-targa-viewer-in-borland-delphi/184409812

Figure 2

Figure 3

Figure 3

Figure 2

Figure 3

JAN96: A TARGA Viewer in Borland Delphi

A TARGA Viewer in Borland Delphi

Supporting graphics formats not native to the Windows environment

Gunter Born

Gunter is a computer consultant and the author of more than 35 books, including The File Formats Handbook (International Thomson Publishing, 1995). He can be reached at [email protected].


With the release of Windows 95 and the announcement of a 32-bit version of Borland's Delphi, I've begun moving my Turbo Pascal DOS code--including the TARGA viewer I present here--over to the Windows environment. The TARGA format, developed by TrueVision to store color-map and true-color images, supports a number of variants for different graphics modes. Delphi's ability to quickly create Windows apps--coupled with the fact that my DOS source code was easily portable--made Delphi a natural choice. In this article, I'll describe the internals of the TARGA file format and the process I went through to convert the viewer code to Delphi.

TARGA Files

All data in TARGA files are stored in Little-endian format (least-significant byte first). A TARGA file consists of a header, followed by two optional data areas (ID field and color map) and the image data; see Figure 1. In TARGA 2.0, the image data may be followed by an optional appendix. The header is a fixed area 18 bytes in length. While the header and the imagedata area are mandatory, other components are either vendor specific or depend upon the type of TARGA file. The 18-byte TARGA header contains all the information necessary to decode and evaluate the image file; see Table 1. The first byte in the header defines the length of the optional Image Identification field, which begins at offset 12H. Some manufacturers store configuration-specific data in this field, which may be between 0 and 255 bytes long. If the first header byte is 0, there is no image-identification field and the optional color map follows at offset 12H; see Figure 2. If a vendor needs more than 255 bytes, the TARGA 2.0 format allows data to be stored after the image area.

The offset from the beginning of the file to the first palette entry is calculated by length image identification field+12H. The number of entries in the color map and the entry size are stored in the header at offsets 05H and 07H. If an entry contains 32 bits, the first three bytes define the color information for blue, green, and red, and the fourth byte is used as an attribute. For 16-bit palette entries, the following bitwise coding applies (A=attribute, R=red, G=green, and B=blue): A RRRRR GGGGG BBBBB.

TARGA files may contain images with or without a color map (palette). If the second byte in the header is set to 1, a color map is stored after the header. A 0 value indicates that the image data contains all necessary color information. In addition, the TARGA format can store images of different types, including monochrome, RGB, compressed, and uncompressed. Offset 03H contains the TARGA image type, coded as shown in Table 1. Here, I describe the file types 1, 2, 3, 9, 10, and 11. At offset 03H, there are five bytes containing information about the optional color map. If a color map exists, the data are appended after the Image Identification field. A color map may contain up to 256 entries.

A bit of trickery is used to define the colors in the file. The integer value at offset 03H is used as an index into the color map. For example, a value of 5 defines the fifth entry in the color map as the first valid item. If the value is 0, all entries in the color map should be used. The integer at offset 05H indicates how many entries in the color map are valid. This integer is set to 100H (256) entries. A color map may contain 16, 24, or 32 bits per entry. The size of a palette entry in bits is defined in the byte at offset 07H.

The coordinates of the image origin are defined in two words beginning at offset 08H; see Table 1. The next two words define the image's width and height in pixels. The number of colors for each pixel is stored in a byte at offset 10H. TARGA files may use 1, 8, 16, 24, or 32 bits for each pixel. Those with 32 bits per pixel use the highest byte as an attribute (alpha or transparency information). The number of attribute bits used is defined in the image-descriptor flag, which is he last byte in the header and defines how the image should be interpreted; see Table 2. Bits 4 and 5 in the image-descriptor flag define the screen origin, which may be any of the four corners of the screen. Most applications set the origin to the upper- or lower-left corner. The Screen Origin must be set to 0 for TrueVision images. Type 1 images should set the Image Descriptor Flag to 0. The value for the attribute (bits 0 through 3) should be set to 0 or 1 for 16-bit TARGA files, 0 for 24-bit TARGA files (since they have no attributes), and 8 for 32-bit TARGA files.

The Image-Data Area

The image-data area follows the color map. Because the Image Identification field and the color map are optional, the first image data start at offset 12H+length image identification field + length color map. The image area contains width*height pixels with a color depth (monochrome or 256, 32,767, or 16 million colors). The pixel data may be stored compressed or uncompressed.

The monochrome image (types 3 and 11) uses two colors (black and white), so the color map is obvious. All image data are stored contiguously in the data area. Type 3 uses no compression for the image data, while type 11 defines a run length encoding (RLE) compression scheme; see Figure 3. A 16x16 image is defined by 256 pixels. With one bit per pixel, the data area needs only 32 bytes.

With type 1 uncompressed color-map images, n bits per pixel are stored. Each entry acts as an index into the color map of the graphics card. The color map contains 256 entries of 16, 24, or 32 bits, defining 256 colors. If not all colors are used, the entries in the color map are set to 0 (black).

The TARGA format recognizes various compression schemes. The most popular, RLE, is used for the image type 9. The image data (eight bits per pixel) are packed in the record structure in Figure 3. Each record contains a header, followed by one or more data bytes. If the most significant bit in the header is set to 1, an RLE record is used. This record type defines a pattern of n identical data bytes, where n is defined by the remaining 7 bits of the header. To calculate n, use the 7 remaining bits and add 1. The result is a value between 1 and 128. The next byte should be repeated n times in the output buffer. For example, the hexadecimal sequence 82 02 will be expanded to 02 02 02 (82H results in n=3).

The data of an expanded RLE record may extend into the following image line. If the image-data bytes cannot be compressed, they are stored in a raw-data record that contains a header byte with the most significant bit set to 0; see Figure 3. The remaining seven bits of the header byte contain a counter defining the number of bytes--1 following in the record. These data bytes should be copied to the output buffer. For example, the code sequence 85 0F--02 03 00 0F--83 33 should be expanded to 0F 0F 0F 0F 0F 0F--03 00 0F--33 33 33 33.

The "--" character marks the records in the RLE and expanded sequence. The same compression scheme is used for monochrome images (type 11). The pseudocode sequence in Example 1 shows the RLE decoding. The header of a record is always a byte. The pixel size depends on the image type (1, 2, 3, or 4 bytes).

Implementing a TARGA Viewer in Delphi

Delphi supports the display of bitmap images including BMP, ICO, and WMF files through the image control. To display an image in this control, you simply call the LoadFromFile method, which automatically handles the details of loading and displaying images within the image control. Thus, as Figure 4 illustrates, creating a BMP viewer in Delphi requires just a few lines of code. Unfortunately, the image control does not support graphics file formats not native to Windows, such as TIFF, PCX, and TARGA.

The Delphi documentation indicates that you can define your own objects to extend the LoadFromFile function. Unfortunately, this task is nontrivial, and no examples demonstrate the process. After some head scratching, I decided to create a bitmap structure and read the TARGA data into it. I first tried creating a TBitmap object and adding my code. The TBitmap object allows you to manipulate images in the canvas area and encapsulates the Windows HBitmap and HPalette structures necessary to fill in the data from the TARGA file. Unfortunately, the result was extremely slow code; in some cases, it took more than a minute to display a 200x200-pixel image.

To get around this problem I used the original Windows bitmap structures, which resulted in a lot of hand coding without any Delphi support. My solution was to port my Turbo Pascal DOS code to a unit which reads the TARGA file and stores the converted data in a temporary BMP file. I was then able to use the Delphi functions to display the file. The TGAtoBMP unit in Listing One contains no object-oriented code and also may be used in older versions of Borland Pascal. The conversion routine may be called as status:=ConvertTGABMP(Infile, Outfile). The two string parameters are filenames. Infile defines the name and location of the TARGA graphics file, and Outfile defines the path and name of the resulting BMP-file. Upon successful conversion, the function returns status=0 and the BMP-file will be available in the location defined in Outfile. Listing Two demonstrates how to use the function and is based on the reduced ImageView example from the Delphi package, with a few lines added for the TARGA support. The complete code and resource files for the TARGA viewer are available electronically; see "Availability," page 3.

References

Born, Gunter. The File Formats Handbook. London, U.K.: International Thomson Publishing, 1995.

Figure 1: Structure of a TARGA file.

Figure 2: TARGA file as a hex dump.

Figure 3: RLE record format.

Figure 4: Displaying a BMP file under Delphi.

var Image 1: TImage;
 ....
Image1.Picture.LoadFromFile (Filename);
ViewForm.Image1.Picture:= Image1.Picture;

Table 1: Structure of a TARGA header.

Offset  Bytes  Remarks

00H       1    Length of image ID field (0-255 bytes, 0 = no ID field)
01H       1    Color-map type (0 = no color map, 1 = color map in file)
02H       1    TARGA-image type
                0 = No image data in file
                1 = Color-map image, uncompressed
                2 = RGB image (24 bit), uncompressed
                3 = Monochrome image, uncompressed
                9 = Color-map image, RLE compression
               10 = RGB image (24 bit), RLE compression
               11 = Monochrome image, RLE compression
               32 = Color-map image, Huffmann, Delta, and RLE compression
               33 = Color-map image, Huffmann, Delta, and RLE compression (4-pass quadtree)
03H       2    Color-map origin (Integer)
05H       2    Color-map length (Integer)
07H       1    Color-map entry size (16, 24, 32)
08H       2    x-coordinate origin
0AH       2    y-coordinate origin
0CH       2    Image width in pixels
0EH       2    Image height in pixels
10H       1    Bits per pixel (1, 8, 16, 24, 32)
11H       1    Image-descriptor flag
12H       n    Image-identification field (optional)
..H       n    Color map (optional)

Table 2: Coding an image-descriptor flag.

Bit     Remarks

0-3     Attribute = bits per pixel
4-5     Screen origin
        00 = Lower-left corner
        01 = Lower-right corner
        10 = Upper-left corner
        11 = Upper-right corner
6-7     Interleave
        00 = No interleave
        01 = Interleave odd/even
        10 = Interleave quad
        11 = Reserved

Example 1: RLE decoding.

get header byte
n := (Byte and 3FH) + 1
IF (Byte and 80H) > 0 THEN
  get next pixel in RLE record
  output pixel n times
ELSE
  FOR k := 1 TO n
    get raw pixel
    output pixel
  END FOR k
END IF

Listing One

unit TGAToBMP;
{
  Warranty and Copyright Disclaimer:
  TGA to BMP conversion routine, implementation for Borland
  Delphi by: (c) Guenter Born - Version 17-July-1995
  The TARGA and BMP specification may be found in:
  The File Formats Handbook - by Gunter Born, 1300 pages,
  published by International Thomson Publishing,
  ISBN 1-85032-117-5
  This code comes unsupported AS IS without any warranty.
  The code was written as an example for my article in the
  Dr. Dobb's Journal of Software Tools.
  Users are given the right to use/modify and distribute this
  source code as long as this disclaimer are included and
  credits are given.
}
interface
function ConvertTGABMP (Infile, Outfile: string): Byte;
{
  Infile : Input TARGA File
  Outfile: Output BMP File
  Return:  0 conversion successful
           1 can't open input file
           2 can't create output file
           3 TARGA type not implemented (Header check)
           4 Data processing error
}
implementation
uses WinTypes, WinProcs, Classes, Graphics, Forms, Controls,
  FileCtrl, StdCtrls, ExtCtrls, Buttons, Spin;
 const
   MAX_WIDTH = 8000;                  { max. ImageWidth in Byte }
   MAX_BLOCK = 4096;                  { Input Buffer size       }
 type
   block_array = array [0..MAX_BLOCK] of byte;
   line_array = array [0..MAX_WIDTH] of byte;
   name = String [255];
   TGA_header = record
    ID_Size: Byte;   { Length ID-field }
    Pal_flag: Byte;  { Flag indicates a palette }
    Typ : Byte;      { Image Type Mono, Color   }
    Pal_index: Word; { Index into Palette       }
    Pal_size: Word;  { No. of palette entries   }
    Pal_entry_size: Byte; { Size of a pal. entry }
    leftx: Word;     { Coordinate X0 }
    lefty: Word;     { Coordinate Y0 }
    ImageWidth: Word; { Image width   }
    ImageHeight: Word; { Image height  }
    Bits_per_pixel:Byte; { Bits per Pixel }
    Image_descr:Byte; { Image descriptor byte }
   end;
var
   RawData: block_array;              { Input buffer raw data  }
   NextByte: integer;                 { Index in raw buffer    }
   Data: byte;                        { current ras data byte  }
   Header: TGA_header;                { TGA File Header        }
   IMGline: line_array;               { buffer Output data     }
   Index: integer;                    { IMGline Index          }
   TGABytes_per_Line : word;          { Byte per line TGA      }
   BMPBytes_per_Line : word;          { Byte per line BMP      }
   Bits_per_pixel: byte;
Function OPEN (Var handle : file; Filename: name) : boolean;
{--------------------------------------------------------}
{  Open File for Input Function                          }
{--------------------------------------------------------}
begin
  AssignFile (handle,Filename);
  {$I-}                                {* Errorcheck off     *}
  Reset(handle,1);                     {* open file          *}
  {$I+}                                {* Errorcheck on      *}
  Open := IOResult = 0;
end;
Function OPENNew (Var handle : file; Filename: name) : boolean;
{--------------------------------------------------------}
{  Open File for Output Function                         }
{--------------------------------------------------------}
begin
  Assign(handle,Filename);
  {$I-}                                {* Errorcheck off     *}
  Rewrite(handle,1);                   {* open file          *}
  {$I+}                                {* Errorcheck on      *}
  OpenNew := IOResult = 0
end;
function ProcessHeader (Var FIn,FOut: File): Boolean;
{--------------------------------------------------------}
{ Read TGA Header data and create a BMP Header           }
{--------------------------------------------------------}
 const
     Red =  0;                         { constants for Palette   }
     Green = 1;
     Blue = 2;
     Attr = 3;
 var
     Ofs:       LongInt;
     I, count:  Integer;
     BmHeader : TBitmapInfoHeader; { BMP-Header             }
     BitFile:   TBitmapFileHeader; { BMP File Header        }
     BMP_pal:   TRGBQuad;          { Palette BMP            }
     TGApal_array : array [Red .. Attr] of Byte; { buffer palette}
begin
 {$I-}
 BlockRead (FIn, Header, SizeOf(Header)); { get TGA Header  }
 {$I+}
 IF IOResult <> 0 Then
  begin
   ProcessHeader := false;
   exit;
  end;
 IF NOT (Header.Typ IN [1, 2, 3, 9, 10, 11]) Then
  begin  {  sorry TARGA types 32, 33 not implemented yet  }
   ProcessHeader := false;
   exit;
  end;
 IF NOT(Header.Bits_per_pixel IN [1, 8, 24]) Then
  begin { TARGA types with 16/32 Bit/pixel not implemented yet  }
   ProcessHeader := false;
   exit;
  end;
{
  calculate the number of Bytes per line (for n color planes)
}
 CASE Header.Bits_per_pixel OF
  1: TGABytes_per_line := Header.ImageWidth div 8;
  8: TGABytes_per_line := Header.ImageWidth;
 24: TGABytes_per_line := Header.ImageWidth * 3;
 end;
 BMPBytes_per_line := TGABytes_per_line;
 count := BMPBytes_per_line Mod 4;    { adjust length to 32 Bit }
 IF count <> 0 THEN
   INC (BMPBytes_per_line,(4-count));
{
  construct the BitmapInfoHeader
}
  BmHeader.biSize := Sizeof(TBitmapInfoHeader);
  BmHeader.biWidth := Header.ImageWidth;
  BmHeader.biHeight := Header.ImageHeight;
  BmHeader.biPlanes := 1;           { set always to 1         }
  BmHeader.biBitCount := Header.Bits_per_Pixel;
  BmHeader.biCompression := BI_RGB; { no compression }
  BmHeader.biSizeImage := 0;        { valid, no compress. used }
  BmHeader.biXPelsPerMeter :=0;     { not used yet             }
  BmHeader.biYPelsPerMeter :=0;     { ditto                    }
  BmHeader.biClrUsed := 0;          { all colors are used      }
  BmHeader.biClrImportant := 0;     { all colors important     }
{
  construct the BitmapFileHeader
}
  BitFile.bfType := $4D42;          { Signature 'BM'           }
  BitFile.bfReserved1 := 0;         { not used                 }
  BitFile.bfReserved2 := 0;         { dito                     }
  BitFile.bfOffBits := (256 * SizeOf(TRGBQuad))+ { Offset to Data }
                       sizeof(TBitmapFileHeader)+
                       sizeof(TBitmapInfoHeader);
  BitFile.bfSize := (256 * SizeOf(TRGBQuad)) +   { File size      }
                       sizeof(TBitmapFileHeader) +
                       sizeof(TBitmapInfoHeader) +
                      (Header.ImageHeight*BMPBytes_per_Line);
  {$I-}
  BlockWrite (FOut, BitFile, SizeOf(BitFile)); { write BMP-File Header }
  {$I+}
  IF IOResult <> 0 Then
   begin
    ProcessHeader := false;
    exit;
   end;
  {$I-}
  BlockWrite (FOut, BmHeader, SizeOf(BmHeader)); { write BitmapInfoHeader }
  {$I+}
  IF IOResult <> 0 Then
   begin
    ProcessHeader := false;
    exit;
   end;
{ *** process the color palette if available  *** }
 IF (Header.Pal_flag <> 0) THEN
  begin
   Ofs := SizeOf(Header) + Header.ID_Size;   { Offset to palette     }
   SEEK (FIn, Ofs);                          { set to Palette        }
   count := Header.Pal_entry_size div 8;     { Byte per Pal entry    }
   FOR i := 1 to Header.Pal_size do          { process all entries   }
    begin
   {$I-}
     BlockRead (FIn, TGAPal_array[0],count); { get one plaette entry }
   {$I-}
     IF IOResult <> 0 Then
      begin                                  { something wrong       }
       ProcessHeader := false;
       exit;
      end;
   { Write the BGR palete information to this file}
     IF count > 2 Then
      begin
       BMP_pal.rgbBlue := TGAPal_array[Red];
       BMP_pal.rgbGreen := TGAPal_array[Green];
       BMP_pal.rgbRed := TGAPal_array[Blue];
      end
     ELSE  { 16 Bit Palette Entry -> create 3 Byte Attribute  }
      begin{ Entry is ARRRRRGGGGGBBBBB coded                  }
       BMP_pal.rgbBlue := (TGAPal_array[1] SHR 2) AND $1F; { Red   }
       BMP_pal.rgbGreen := (TGAPal_array[0] SHR 5)+        { Green }
                         + (TGAPal_array[1]  AND $03) SHL 3;
       BMP_pal.rgbRed := TGAPal_array[0] AND $1F;          { Blue  }
      end;
           { in 32 Bit Palette entry, clear attribute byte always !! }
     BMP_pal.rgbReserved := 0;               { 4th byte in Palette   }
   {$I-}
     BlockWrite (FOut, BMP_pal,SizeOf(TRGBQuad)); { write Palette      }
   {$I+}
     IF IOResult <> 0 Then
      begin
       ProcessHeader := false;
       exit;
      end;
    end; { FOR }
 end; { Process Palette }
{ *** calculate Offset TGA Image Data *** }
  Ofs := SizeOf(Header)+
         Header.ID_Size;
  IF Header.Pal_flag <> 0 THEN
   Ofs := Ofs + Header.Pal_size*count;   { add Pal size to Offset   }
  SEEK (FIn, Ofs);                       { set to 1st Image Byte    }
end;  { ReadHeader }
procedure ReadByte (Var FIn : File);
{--------------------------------------------------------}
{ get a byte from the buffer, if buffer empty, fill      }
{--------------------------------------------------------}
var
 NumBlocksRead: integer;
begin
 if NextByte = MAX_BLOCK then   { buffer empty ?            }
  begin
   {$I-}                        { Yes, read next block      }
   BlockRead (FIn, RawData, MAX_BLOCK, NumBlocksRead);
   {$I+}
   IF IOResult <> 0 THEN
    begin
     Close (FIn);
     exit;
    end;
   NextByte := 0;                { reset buffer pointer     }
  end;
 data := RawData [NextByte];     { return next byte         }
 inc (NextByte);                 { pointer to next entry    }
end;  { ReadByte }
Function put_line (Var FOut: File; count: Integer): Boolean;
{----------------------------------------------------------}
{ write a uncompressed line into the BMP file              }
{----------------------------------------------------------}
Var X : Integer;
 begin
 {$I-}                        { Write the buffer        }
  BlockWrite(FOut, IMGLine[0], count);
 {$I+}
  IF IOResult <> 0 THEN
   put_line := false
  ELSE
   put_line := true;
end;  { Put_line }
function ProcessData (Var FIn, Fout : File): Boolean;
{--------------------------------------------------------}
{ read the TGA-data step by step, decode the data and    }
{ write 1, 8 and 24 Bit per Pixel to the BMP file        }
{--------------------------------------------------------}
var
   count: word;                        { repeat variable    }
   i,j,k: integer;
   pixel: array [0..2] of Byte;        { 24 Bit Data buffer }
begin
 NextByte := MAX_BLOCK;                { clear input buffer!}
{
  Attention: this implementation defines the image lines
  from top to bottom. TGA may have an invers order for the image lines.
}
 FOR j := 1 TO Header.ImageHeight do     { all lines           }
  begin
   index := 0;                           { Reset output ptr    }
{------------------------------------------------------}
{  TGA decoding starts here                            }
{------------------------------------------------------}
   WHILE (index < TGABytes_per_line) Do   { all bytes in line   }
    begin
{  *** RLE compression for 1 and 8 Bit per Pixel *** }
     IF Header.typ IN [9, 11] Then
      begin
       ReadByte (FIn);                    { get 1st Recordbyte  }
       count := (data AND $7F) + 1;       { get count value     }
       IF (data AND $80) > 0 THEN
        begin                             { RLE-Record          }
         ReadByte (Fin);                  { get pixel value     }
         FillChar (IMGLine[index],count,data); { expand         }
         INC (index, count);              { index ++n           }
        end
       ELSE                               { RAW-Record          }
        FOR k := 1 TO count do
         begin
          ReadByte (FIn);                 { get pixel data      }
          ImgLine[index] := data;         { copy to output buf  }
          INC (index, 1);                 { index ++            }
         end;
      end;  { RLE 1,8 Bit...}
{*** RLE compression for 24 Bit/Pixel, 16/32 Bit not supported *** }
     IF Header.typ IN [10] Then
      begin
       ReadByte (FIn);                    { get 1st Recordbyte  }
       count := (data AND $7F) + 1;       { get count value     }
       IF (data AND $80) > 0 THEN
        begin { RLE-Record -> 24 Bit per Pixel, process 3 Byte  }
         For i := 0 To 2 Do               { get 3 Byte          }
           begin
            ReadByte (Fin);               { get value           }
            pixel[i] := data;             { store value         }
           end;
          For i := 1 To count Do          { expand n pixel      }
           begin
            MOVE (pixel[0],IMGLine[index],3);
            INC (index,3);                { index ++3           }
           end;
        end
       ELSE                               { RAW-Record          }
        FOR k := 1 TO count*3 Do          { 3 Byte per Pixel    }
         begin
          ReadByte (Fin);                 { get value           }
          IMGLine[index] := data;         { store value         }
          INC (index, 1);                 { index ++1           }
         end;
      end; { 24 Bit RLE  }
     IF Header.typ IN [1, 2, 3] Then      { no Compression      }
      begin
       ReadByte (FIn);                    { get TGA-Pixel       }
       IMGLine[index] := data;            { copy to output buf  }
       INC (index,1);                     { index ++            }
      end;
    end; { While }
 IF BMPBytes_per_line<>TGABytes_per_line THEN
  FillChar (IMGLine[index],                { clear last n bytes }
           BMPBytes_per_line-TGABytes_per_line,0);
 IF Not put_line (FOut,BMPBytes_per_Line) Then { Write line     }
  begin
   ProcessData := false;
   exit;
  end;
 end; { FOR j .... }
end;  { ProcessData }
function ConvertTGABMP (Infile, Outfile: string): Byte;
{-------------------------------------------}
{ This is the root of the TGA BMP converter }
{-------------------------------------------}
Var
  FromF : File;
  ToF : File;
  status : byte;
begin
 status := 0;
 IF NOT Open (FromF, InFile) Then        { Open Input file     }
  status := 1                            { Error during open   }
 ELSE
  IF NOT OpenNew (ToF, OutFile) Then     { Open Output file    }
   status := 2                           { Error during open   }
  ELSE
   IF NOT ProcessHeader(FromF, ToF) THEN { process TGA Header  }
    status := 3                          { Error in Header     }
   ELSE
   IF NOT ProcessData (FromF, ToF) THEN  { process TGA Data    }
    status := 4;
 close (FromF);
 close (ToF);
 ConvertTGABMP := status;              { success status     }
end; { ConvertTGA }
end.

Listing Two

unit ImageWin;
{
  This is the unit to display BMP, ICO, WMF and TGA graphics.
  The code was taken from the Borland Delphi example IMAGEVIEW and was 
  changed by Guenter Born. Note: this unit needs the TGAToBMP conversion unit.
}
interface
uses WinTypes, WinProcs, Classes, Graphics, Forms, Controls,
  FileCtrl, StdCtrls, ExtCtrls, Buttons, Spin, TGAToBmp;
type
    TImageForm = class(TForm)
    DirectoryListBox1: TDirectoryListBox;
    DriveComboBox1: TDriveComboBox;
    PathLabel: TLabel;
    FileEdit: TEdit;
    Panel1: TPanel;
    FileListBox1: TFileListBox;
    Label1: TLabel;
    ViewBtn: TBitBtn;
    Bevel1: TBevel;
    FilterComboBox1: TFilterComboBox;
    StretchCheck: TCheckBox;
    Image1: TImage;
    procedure FileListBox1Click(Sender: TObject);
    procedure ViewBtnClick(Sender: TObject);
    procedure StretchCheckClick(Sender: TObject);
    procedure FileEditKeyPress(Sender: TObject; var Key: Char);
   end;
   name = string [255];
var
   ImageForm: TImageForm;
implementation
uses ViewWin, SysUtils;
{$R *.DFM}
procedure TImageForm.FileListBox1Click(Sender: TObject);
{ call if FileListBox is checked by a user }
var
  FileExt: string[4];
  FileName: string [255];
  TMPFileName: String [255];
  status : byte;
begin
  FileExt := UpperCase(ExtractFileExt(FileListBox1.Filename));
  if (FileExt = '.BMP') or (FileExt = '.ICO') or (FileExt = '.WMF') then
   begin
    Image1.Picture.LoadFromFile(FileListBox1.Filename);
    Label1.Caption := ExtractFilename(FileListBox1.Filename);
    if (FileExt = '.BMP') then
     begin
      { show image height and width in window }
      Label1.Caption := Label1.Caption +
        Format(' (%d x %d)', [Image1.Picture.Height, Image1.Picture.Width]);
      ViewForm.Image1.Picture := Image1.Picture; { show picture as icon }
     end;
    if FileExt = '.ICO' then Icon := Image1.Picture.Icon;
    if FileExt = '.WMF' then
      ViewForm.Image1.Picture.Metafile := Image1.Picture.Metafile;
   end
  else
{  Here comes the extension for the TARGA format. Note: to avoid all this 
   dirty BitBld stuff I read the TARGA file, convert it and store it as
   a BMP-File. This file is easy to load and display with delphi.}
   if FileExt = '.TGA' then
   begin
    FileName := FileListBox1.Filename; { Get Input Filename  }
    TMPFileName := 'TMP.BMP';          { Set Output Filename }
    status := ConvertTGABMP(FileName,TMPFileName); { Conversion TGA->BMP }
    IF status = 0 Then                 { conversion was succesful }
     begin
      Image1.Picture.LoadFromFile(TMPFileName); { Load BMP File }
      { show image height and width in window }
      Label1.Caption := ExtractFilename(FileListBox1.Filename);
      Label1.Caption := Label1.Caption +
        Format(' (%d x %d)', [Image1.Picture.Height,
               Image1.Picture.Width]);
      ViewForm.Image1.Picture := Image1.Picture;
     end
    ELSE
     begin                            { display conversion error }
                                      { show image height and width in window }
      Label1.Caption := ExtractFilename(FileListBox1.Filename);
      Label1.Caption := Label1.Caption +
        Format(' Error: (%d )', [status]);
end;
   end; { TARGA Branch }
end;
procedure TImageForm.ViewBtnClick(Sender: TObject);
begin
  ViewForm.HorzScrollBar.Range := Image1.Picture.Width;
  ViewForm.VertScrollBar.Range := Image1.Picture.Height;
  ViewForm.Caption := Label1.Caption;
  ViewForm.Show;
end;
procedure TImageForm.StretchCheckClick(Sender: TObject);
begin
  Image1.Stretch := StretchCheck.Checked;
end;
procedure TImageForm.FileEditKeyPress(Sender: TObject; var Key: Char);
begin
  if Key = #13 then
  begin
    FileListBox1.ApplyFilePath(FileEdit.Text);
    Key := #0;
  end;
end;
end.

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.