TES Chapter 2: DAGGERFALL - IMAGE FILE FORMATS IMG, CIF, PAL, COL, and Texture File Formats by Dave Humphrey - 4 November 2000 dave@uesp.net This file was initially distributed with DAGPIC, a DOS program which uses the file format descriptions found below. This file may be distributed at will. The latest version can always be found at www.uesp.net/dagger/ CONTENTS ================================================= IMG File Format Special IMG Files CIF File Format Special CIF Files Weapon CIF Files Weapon CIF Group Header Weapon CIF RLE Image Data TEXTURE File Format General File Layout Texture Header Image Header Offset List Image Header SubImage Format SubImage Row Data Format RLE Image Format RLE Compressed Data Format RLE SubImage Format Special Texture Files PAL File Format COL File Format Appendix A - Special Texture Files IMG FILE FORMAT ================================================= The format of the IMG files found in Daggerfall's ARENA2 directory are quite simple to determine. The basic format, as follows, is 12 bytes of header information followed by the image data. The format completely describes the 259 IMG files found in the game. [Bytes 0-1] short XOffset [Bytes 2-3] short YOffset; Unknown what exactly these two values are, but probably the image offsets for displaying purposes. [Bytes 4-5] short Width; [Bytes 6-7] short Height; [Bytes 8-9] short Unknown; Might indicate compressed data or not. 0x0000 = Uncompressed image data??? 0x0002 = Compressed image data??? [Bytes 10-11] short ImageSize; Total number of bytes taken up by the image data. Note that this is the size of the image data in the file, which may be compressed (or, sometimes ImageSize is not Width*Height). [Bytes 12...] unsigned char ImageData[ImageSize]; A linear bitmap form (one pixel right after another). You will still need the correct palette to properly display the image (there are several in the ARENA2 directory). Special IMG Files -------------------------------------------- FMAP0I00.IMG FMAP0I01.IMG FMAP0I16.IMG These 12 byte files contain nothing but a NULL header (0x00's). 720 Byte Files 9x80 image with no header. 990 Byte Files 45x22 image with no header. 1720 Byte Files 43x40 image with no header. 2140 Byte Files 107x20 image with no header. 2916 Byte Files 36x81 image with no header. 3200 Byte Files 40x80 image with no header. 3938 Byte Files 179x22 image with no header. 4280 Byte Files 107x40 image with no header. 4508 Byte Files 322x14 image with no header. 20480 Byte Files 320x64 image with no header. 26496 Byte Files 184x144 image with no header. 64000 Byte Files 320x200 image with no header. 64768 Byte Files 320x200 image with no header and 768 bytes of palette data at the end of the file (256 RGB entries, 0-63 values). 68800 Byte Files 320x215 image with no header. 112128 Byte Files 512x219 image with no header. CIF FILE FORMAT ================================================= CIF files initially look just like the IMG files, except a closer examination reveals that they are much larger than they needed to be. This lead to the finding that most CIF files simply contain several IMG files, one after the other, illustrated as follows: Image #1 Header Image #1 Data Image #2 Header Image #2 Data ...etc... The only apparent method determining how many images a CIF file contains is to read all the images (or at least all the image headers, skipping the image data). Once no (or few) bytes are left after an image, the file is complete. The number of images in a CIF file may be fixed as is evident with playing around with the FACE*.CIF files (adding another face after the default 10 has no effect in the game). Using the format detailed below, all CIF files in the ARENA2 directory can be successfully exported to PCX files. Special CIF Files -------------------------------------------- FACES.CIF The file FACES.CIF contains the NPC portraits seen in the conversation window. There is no header information in the file, just 61 64x64 images placed one after another. WEAPON CIF Files -------------------------------------------- Unfortunately, once again, there are exceptions to the general CIF format, the WEAP*.CIF files. These images images for the weapons seen when you equip and attack from the main display. The first image in a weapon CIF is usually the normal weapon seen when you aren't attacking but have the weapon armed. This first image is the usual IMG format. Note that the file WEAPON09.CIF has the bow and hand-to-hand weapons which do not have this first image as they aren't visible unless you are attacking. The basic overall format is as follows: Image #1 Header (except for WEAPON09.CIF) Regular IMG Header Image #1 Data (except for WEAPON09.CIF) Regular IMG Data Group #1 Header RLE Image #1 Data RLE Image #2 Data ... Group #2 Header ... etc... Weapon CIF Group Header -------------------------------------------- The header is similar to the IMG image header but is longer, 76 bytes and has a few fields switched around. [Bytes 0-1] short Width; [Bytes 2-3] short Height; Note that the offset and size fields are switched around from the IMG format. [Bytes 4-5] short XOffset; [Bytes 6-7] short YOffset; Assuming from the IMG format [Bytes 8-9] short Unknown; The value 0x0015 which appears only in WEAPON09.CIF (unconfirmed). Otherwise unknown (possibly 0). [Bytes 10-11] short ImageSize; [Bytes 12-75] short ImageOffsetList[32]; These values are the offset from the start of the header to the beginning of the RLE compressed image data for each of the images in the group. Note that the last offset in the list gives the offset to the start of the next group header. Weapon CIF RLE Image Data -------------------------------------------- The weapon CIF image data for the group images (not the first image) is compressed in a form of RLE bytes (RLE means Run-Length-Encoded). The basic algorithim for decoding this data is as follows: while BytesRead < Width*Height Data = read 1 byte from file if (Data > 127) then PixelData = read 1 byte from file Copy PixelData to image (Data-127) times BytesRead += (Data-127) else Read in (Data+1) bytes from file Copy (Data+1) bytes to image BytesRead += (Data+1) end if end while As an example, take the raw hexadecimal byte string C7 00 01 77 71 81 70 00 75 D9 00 1. C7, decode as (C7-7F) = 48 x 00 2. 01, read in (01+01) bytes = 77 71 3. 81, decode as (81-7F) = 2 x 70 4. 00, read in (00+01) bytes = 75 5. D9, decode as (D9-7F) = 5A x 00 Summary: Total of A7 pixels decoded (167) TEXTURE FILE FORMATS ================================================= Texture files are all files in the ARENA2 game directory that match TEXTURE.??? where ??? is a number ranging from 000 to 511 (there are some numbers missing as there are 472 files total). The description which follows has been tested extensively and appears to describe the overall format accurately enough to be able to export all the images to PCX files successfully, all 10,956 of them. Note that there are 4 special texture files which are not described by the format and contain no images (see Appendix A). General File Layout -------------------------------------------- Texture Header (26 Bytes) Image Header Offset List ...Image Headers... ...Image Data... ... The overall texture format is slightly more complicated than the usual DF image format. The texture header and offset list are always the same, although the latter is variable length. The Image Headers and Data occur throughout the file with relatively little apparent order. What it appears to be is that the image data is always stored in images 256 bytes wide. Thus, if you had 4 images 64 pixels wide and 100 high, these would be stored in one big image 256x100 in size. Thus, reading the image data is not a simple matter as you have to read 1 column, skip 256 bytes, read the next column, etc... Fortunately, the offset to the first byte of image data is given in the image header. Image headers are grouped together so image data does not usually follow the header. To simplify, the basic input routine for the image data would be as follows: Read Header and Offset List For Each Image Jump to Image Header Offset in File Read Image Header Jump to Start of Image Data For Each Row in Image Read Image Row Jump Forward 256-ImageWidth Bytes Next Next Note that not all textures follow this convention, but most do. Texture Header -------------------------------------------- The header always starts off the texture file and is always 26 bytes in length. [Bytes 0-1] short NumImages; The number of images contained in the texture file. This value ranges from 1 to 128 in texture files. [Bytes 2-25] char TextureName[24]; Contain a string describing the texture file. Assumably it includes the terminating NULL character. Image Header Offset List -------------------------------------------- The offset list follows the texture header in the file and contains one 20 byte record for each image in the texture. [Bytes 0-1] short Type1; [Bytes 2-5] long HeaderOffset; Contains the offset to the of the image header from the origin of the texture file. [Bytes 6-7] short Type2; [Bytes 8-11] long Unknown1; Ranges from 0 to 4 but is usually zero (90% of all images). [Bytes 12-15] long NullValue1; [Bytes 16-19] long NullValue2; Always zero (confirmed). Image Header -------------------------------------------- Each image header is pointed to by the HeaderOffset in the offset list at the beginning of the file. It contains 28 bytes of information. [Bytes 0-1] short XOffset; [Bytes 2-3] short YOffset; Unconfirmed what these values really are, but could be some sort of offset used to position the texture when drawn. [Bytes 4-5] short Width; [Bytes 6-7] short Height; Size, in pixels, of the image. [Bytes 8-9] short Unknown1; 0x0108 = Image has subimages which are RLE compressed data. 0x1108 = Image has RLE type compressed data with a row offset section before the single image data. [Bytes 10-13] long ImageSize; Total size of the image including this 28 byte header. [Bytes 14-17] long ImageOffset; Offset to the first byte of the image data from the start of this header. [Bytes 18-19] short Unknown2; 0x0000 = Image has subimages in special compressed format. 0x00C0 = Usual value, regular single image. NonZero = Regular single image. Unknown what the differences in the values indicate. [Bytes 20-21] short NumSubImages; This value indicates the number of subimages in the image data. Usually this value is 1 indicating the usual image format, but some image records contain several subimages and have a special format (see below). [Bytes 22-25] long Unknown3; [Bytes 26-27] short Unknown4; SubImage Format -------------------------------------------- If the number of subimages is greater than 1, it indicates that the image is composed of a number of seperate images and has a slightly different format. The offset pointed to by the ImageOffset in the image header is to a list of long offsets to the seperate image data. Unlike the usual images data which is combined into one big 256 pixel wide image, subimage data is linear, although it is still seperated into rows. The subimage data format is as follows: Subimage Offset List - long Offsets[NumSubImages]; The offset is relative to the start of the offset list. Subimage #1 Data short ImageWidth; short ImageHeight; SubImage Row #1 Data Row data is slightly compressed in a format which is described further below. SubImage Row #2 Data ...etc... Subimage #2 Data ... ...etc... SubImage Row Data Format -------------------------------------------- The row data of each subimage is slightly compressed in a form of RLE encoding where only the 00 pixels are compressed (that is the pixels that are not displayed in the texture to provide transparency). For each row the basic algorithim to read and decode the bytes is as follows: While Not Finished Row NumZeroBytes = get character from file Add NumZeroBytes to Image Row NumImageBytes = get character from file Read NumImageBytes from file to Image Row End While As an example, take the encoded byte string 30 00 18 01 EF 17 00 17 02 EF EF 17 00 for an image that is 0x30 pixels wide. The rows decode as follows: Row 1: Made entirely of zeros (0x30 bytes of zero, 00 pixel bytes) Row 2: Starts with 0x18 bytes of zero 0x01 bytes of pixel data (0xEF) Ends with 0x17 bytes of zero (0x18 + 0x01 + 0x17 = 0x30) Row 3: Starts with 0x17 bytes of zero 0x02 bytes of pixel data (0xEF 0xEF) Ends with 0x17 bytes of zero (0x17 + 0x02 + 0x17 = 0x30) RLE Image Format -------------------------------------------- Some single images have compressed data which seems to be indicated by the value 0x1108 in the Unknown1 parameter of the image header (unconfirmed but pretty sure at the moment). The format of the image data pointed to by the DataOffset in the image header is as follows: RowOffsets[ImageHeight] (8 bytes each) Contains 8 byte records for each of the rows in the image. The record data is: short RowOffset; Offset from the start of the image header to the start of the compressed row data. short Encoded; 0x0000 Indicates an uncompressed row 0x8000 Indicates a RLE type compressed row. These are the only values it ever takes. RowData[ImageHeight] (variable length) Contains compressed row data in a form of RLE bytes. The format is as follows: short RowSize; Length of the row in pixels (not bytes of compressed data). RLE Compressed Data See the RLE Compressed Data section below. RLE Compressed Data Format -------------------------------------------- The RLE compressed image data is basically composed of 3 byte triplets, that is you can read 3 bytes of data at a time to determine what to do. The basic format is: signed short ByteCount; If this value is positive, it indicates the number of raw uncompressed pixel bytes which follow. Thus, the byte string '03 00 7F 7D 7E' merely uncompresses as 3 pixels with values '7F 7D 7E'. If this value is negative it indicates that the next pixel byte is to be repeated (-ByteCount) times. Thus, the byte string 'F9 FF 7D' uncompresses as '7D 7D 7D 7D 7D 7D 7D' unsigned char RLEData; Start of the pixel data. If ByteCount is negative, the next byte after this will be the next 3 bytes of RLE data (or the next row if this is the last pixel in the current row). If ByteCount is positive there may be more pixel data which follows this byte. RLE SubImage Format -------------------------------------------- So we have special formats for subimages, for single RLE encoded images, so obviously we must confuse things further with a RLE subimage format. This format occurs in images that have multiple subimages and also have the RLE encoding flag set with the Unknown1 variable in the image header. Although unconfirmed, a value of Unknown1 = 0x0108 indicates a RLE subimage format. As the name implies, it combines the subimage and RLE single image formats. There is no subimage offset table but the RLE row offset table contains offsets to all the rows of the subimages, one after the other, as shown below. Subimage #1, Row #1 Offset Subimage #1, Row #2 Offset ... Subimage #1, Row #Height Offset Subimage #2, Row #1 Offset ... Subimage #2, Row #Height Offset ...etc... Thus, the subimages can be extracted by combining consecutive (from the RLE offset table) ImageHeight rows of image data. Note that consecutive rows in the RLE offset table may not nessecarily be consecutive rows of data in the file. Special Texture Files -------------------------------------------- There are a few texture files which do not exactly fit the above format: TEXTURE.000 TEXTURE.001 These two texture files each contain 128 (0x80) images but with no image header or data, just the texture header and offset list. The high byte of the offset list Type1 parameter holds the palette color index of the color to use for the texture (assumably). The texture is used for any objects colored with a solid color and not a bitmap. The file can be identifed by an image offset of 0. TEXTURE.215 TEXTURE.217 Each of these textures contain one image but with only the texture header and offset list, no image header or data. Most likely these files are not used. PAL FILE FORMAT ================================================= The PAL palette files were trivial to intepret since the size of the files were all 768 bytes (768 = 256 * 3). A PAL file simply contains the Red, Green, and Blue components of each colour in that order for each of the 256 colours in the palette. Like regular VGA palettes, colour components values range from 0-63 (0x00 to 0x3F). COL FILE FORMATS ================================================= The COL palette files are similar to PAL files although they are 8 bytes larger. COL files appear to contain an 8 byte header which can simply be ignored at the moment. Appendix A - Special Texture Files ================================================= There are a four special texture files which should be noted to not follow the format given in this document. Texture.000 Color file (no images), colors 0x00 to 0x7f Texture.001 Color file (no images), colors 0x80 to 0xFF Texture.215 Empty except for the file header and offset list. Texture.217 Empty except for the file header and offset list.