AWARE [SYSTEMS] Imaging expertise for the Delphi developer
AWare Systems, Imaging expertise for the Delphi developer, Home TIFF and LibTiff Mailing List Archive

LibTiff Mailing List

TIFF and LibTiff Mailing List Archive
January 2004

Previous Thread
Next Thread

Previous by Thread
Next by Thread

Previous by Date
Next by Date

Contact

The TIFF Mailing List Homepage
This list is run by Frank Warmerdam
Archive maintained by AWare Systems



Valid HTML 4.01!



Thread

2004.01.16 17:32 "libtiff and CALS files...", by Bill Hess
2004.01.19 15:03 "Re: libtiff and CALS files...", by Bob Friesenhahn
2004.01.20 12:58 "Re: libtiff and CALS files...", by Bill Hess
2004.01.20 13:44 "libtiff and CALS files...", by Ross Finlayson
2004.01.19 19:15 "Re: libtiff and CALS files...", by Phillip Crews

2004.01.20 13:44 "libtiff and CALS files...", by Ross Finlayson

Hello,

CALS is a DOD, Department of Defense, standard for acquisition and life 
cycle support, it is said.  Anyways part of the CALS standards are CALS 
raster and document file formats.

CALS 1, or CALS raster or C1, .img, or perhaps .mil images, are as 
described, a fixed length header of maybe 2048 bytes, I forget, then a 
block of Group 4 facsimile encoded data.

CALS2 has two varieties, one form is a raster image, and the other uses 
an SGML profile of some form, perhaps similar to DSSSL, some form of 
ODAP.  Anyways the raster image is similar to the CALS Type 1 image, but 
different.  I think type 2 raster files might also be called TRIF files.

The CALS3 format is a raster format and is very similar to TIFF.  Also 
called NIFF, for Navy Image File Format, or NIRS/NIFF, it is almost 
identical in structure to a TIFF.  Where TIFF has the header ir 
signature of of "42", NIFF uses "N1".  All NIFF images, at least for the 
specifications I have read, are black and white images.  If the image is 
less than or equal to letter size, it is an untiled images, else it is a 
tiled image.

CALS4 is also known as EDMICs, and JEDMICS, EDMICS/JEDMICS, ImageCenter, 
tg4, or sometimes C4, or IMG files.  These are files with a fixed header 
and tiles of Group 4 compressed fax data to comprise basically 
engineering drawings.

I wrote a short synopsis how to read NIRS/NIFF images with libtiff, 
although I'm still looking for NIRS/NIFF images to test it.  If you have 
any NIRS/NIFF samples that you can share I'm interested in looking at 
them.  The way I read NIFF files using libtiff is to add support for 
reading the NIFF private fields and the NIFF header instead of the TIFF 
header.

Programs to convert CALS type 1 or 4 into TIFF could be similar to the 
fax2tiff program.

Hopefully if you actually have a NIFF file this might be useful.  If so, 
please e-mail to me sample NIFF files of small size, standard tiled and 
untiled, thank you.

Ross


Reading NIRS/NIFF files with libtiff and these patches.

NIFF, the "Navy Image File Format", also known as "CALS Raster Type 3", 
according to "Navy
Specification, Advanced Technical Information Support (ATIS), Raster 
Technical Manuals,
Preparation of" is an image file format for the storage of bilevel/black 
and white data
in tiled and untiled forms that is very similar to little-endian TIFF.

The difference between a NIFF and a valid
TIFF file is that the NIFF file has as its header "N1", 0x4e31 instead 
of 42, 0x0042.  As
the file is defined to use little-endian byte order the actual value of 
zero-based bytes 2
and 3 are hexadecimal 31 and 4e instead of 42 and 00.

NIFF defines several private TIFF tag definitions and as well overloads 
for its use a few
of the TIFF tags.  Here are some definitions for the NIFF tags and 
specified values:

#define NIFFTAG_SUBFILETYPE		254	/* Same tag as 
TIFFTAG_SUBFILETYPE, different interpretation */
#define NIFF_SUBFILE_SUPPORTIMAGE 	0x01
#define NIFF_SUBFILE_TILED		0x02
#define NIFFTAG_PELPATHLENGTH		256	/* Same as TIFFTAG_IMAGEWIDTH */
#define NIFFTAG_LINEPROGRESSIONLENGTH	257 	/* Same as TIFFTAG_IMAGELENGTH 
*/
#define NIFFTAG_BITSPERSAMPLE		258 	/* Same as TIFFTAG_BITSPERSAMPLE */
#define NIFFTAG_PHOTOMETRIC		262 	/* Same as TIFFTAG_PHOTOMETRIC */
#define NIFFTAG_DATAOFFSET		273	/* Either strip offset or tile 
offsets */
#define NIFFTAG_SAMPLESPERPIXEL		277 	/* Same as 
TIFFTAG_SAMPLESPERPIXEL */
#define NIFFTAG_DATABYTECOUNTS		279	/* Either strip byte counts or 
tile byte counts */
#define NIFFTAG_PELPATHRESOLUTION	282 	/* Same as TIFFTAG_XRESOLUTION */
#define NIFFTAG_LINEPROGRESOLUTION	283	/* Same as TIFFTAG_YRESOLUTION */
#define NIFFTAG_RESOLUTIONUNIT		296 	/* Same as 
TIFFTAG_RESOLUTIONUNIT */
#define NIFFTAG_COLUMNSPERPELPATH	322 	/* Same as TIFFTAG_TILEWIDTH */
#define NIFFTAG_ROWSPERLINEPATH		323 	/* Same as TIFFTAG_TILELENGTH */
#define NIFFTAG_ROTATION		33465	/* Private tag, 1 x uint16 */
#define NIFF_ROTATION_0			0
#define NIFF_ROTATION_90		1
#define NIFF_ROTATION_180		2
#define NIFF_ROTATION_270		3
#define NIFFTAG_NAVYCOMPRESSION		33466	/* Private tag, 1 x 
uint16 or tile count x uint16 */
#define NIFF_NAVYCOMPRESSION_UNCOMPRESSED 1
#define NIFF_NAVYCOMPRESSION_G4FAX 	4
#define NIFFTAG_TILEINDEX		33467	/* Private tag, tile count * uint16 */

If the image is less than the size of one 8 1/2" by 11" page, then it 
may be stored as a
single-strip image, otherwise it is stored as a tiled image, with tiles 
of dimensions
512 x 512.

The tile index field stores for each tile of the image, in order of the 
tiles stored in the
file as indicated by the tile offsets and tile byte counts, the tile's 
location in the sequence
of tiles of the image.  For example, for a 1024 x 2048 image, with two 
tiles in the x
dimension and four tiles in the y dimension, the tile with tile index 0 
is the upper left
tile, and the tile with tile index 7 is the lower right tile, and they 
may otherwise any
of the tiles stored physically in the image.

NIFF uses only CCITT Fax Group 4 compression, (Modifed Modified READ, 
MMR), and otherwise
stores uncompressed data.  The data is to be compressed with Group 4 
facsimile encoding
unless the compressed data would be larger than the uncompressed data, 
in which case it is
to be stored uncompressed.

The Navy Compression field contains either one entry or entry for each 
tile.  If it contains
only one entry then its value applies to each tile of the image, else 
for each tile its
compression method is indicated.  The specified allowable values are 1 
for uncompressed data
and 4 for Group 4 facsimile compressed data.

The NIFF rotation tag is used instead of the TIFF orientation tag, 
values represent
degrees counterclockwise rotation, 0, 1, 2, and 3 correspond to TIFF 
orientations 0, 6,
3, and 8.

In reading the NIFF contents, it is either a tiled or untiled image.  IF 
it is a tiled
image, bit 1 of the Navy Subfiletype uint16 field is set.  If it is an 
untiled image it
has exactly one strip, which could be considered a tile, the only 
difference between an
untiled image and a tiled image is that the single strip or tile of the 
untiled image may
have dimensions that are not 512 x 512.  The TIFFIsTiled()
function will return a positive value as the TIFFTAG_TILEWIDTH and 
TIFFTAG_TILELENGTH tags are set.  As well, bit 1 of the NIFF subfiletype 
will be set if
the image is tiled.  Otherwise the image is untiled and consists of a 
single strip image
that is compressed with Group 4 fax encoding unless the 
NIFFTAG_NAVYCOMPRESSION field has
the value NIFF_NAVYCOMPRESSION_UNCOMPRESSED.

It is necessary to read the contents of the tile index field, when the 
image is tiled, to
determine which tile in the image file represents a particular tile in 
the image.  One way
to do that is to store an array of structures with the tile index and 
the ttile_t libtiff
tile number type and sort it on the tile index, then when the tile at 
that index is to be read,
to read the tile from the file of the ttile_t.

Define a structure to contain the reference to the tile from the tile 
index.

typedef struct {
	uint16 tile_index;
	ttile_t tile_number;
	uint16 tile_uncompressed;
} tile;

Before reading the tiles, sort an array of (or rather pointer to) the 
tile indexes/indices.

tile* tiles;
uint16* tileindex;
uint16* tilecompression;

ttile_t tile_count = TIFFNumberOfTiles(tiff);

tiles = _TIFFmalloc(tile_count * sizeof(tile));

_TIFFmemset(tiles, 0x00, tile_count * sizeof(tile));

TIFFGetField(tiff, NIFFTAG_TILEINDEX, &tileindex);

for(i=0; i<tile_count; i++){
	tiles[i].tile_index = tileindex[i];
	tiles[i].tile_number = i;
}

if(TIFFGetField(tiff, NIFFTAG_NAVYCOMPRESSION, 
&tilecompression)==tile_count){
	for(i=0; i<tile_count;i++){
		if(tilecompression[i]==NIFF_NAVYCOMPRESSION_UNCOMPRESSED){
			tiles[i].tile_uncompressed=1;
		}
	}
} else if (TIFFGetField(tiff, NIFFTAG_NAVYCOMPRESSION, 
&tilecompression)==1){
	if(tilecompression[0]==NIFF_NAVYCOMPRESSION_UNCOMPRESSED){
		for(i=0; i<tile_count;i++){
			tiles[i].tile_uncompressed=1;
		}
	}
}

qsort(tiles, tile_count, sizeof(tile), qsort_cmp_tile_index);

The qsort_cmp_tile_index function compares the tile indexes.

int qsort_cmp_tile_index(const void* e1, const void* e2){
	return( ((tile*)e1)->tile_index - ((tile*)e2)->tileindex );
}

Then, you have the tile array.  When you go to read the tiles, for 
ttile_t
i from 0 to tile_count in order, instead of calling TIFFReadEncodedTile 
on
i, call it on tiles[i].tile_number.  If tiles[i].tile_uncompressed is 
equal
to 1, call TIFFReadRawTile instead of TIFFReadEncodedTile.

These patches here don't really handle writing NIFF files.  In writing 
NIFF files
it is necessary to determine for each tile whether or not "compression" 
would
increase the size of the data.  In Group 4 compression, data that is 
likely to be
increased in size by encoding is stippled with few long runs of black or 
white pixels.
Normally the method to determine if data would be increased in size by 
compression is
to compress it and compare the size to the uncompressed data, which 
shall be a 512 x 512
block for tiles of 512*512/8 bytes, or the complete image for the single 
strip image
representing less than or equal to a letter size piece of paper.  A way 
to do that
would be to generate a regular compressed tiled TIFF.  Then, go through 
the tiles and
compare their size against the size of the uncompressed tile to form the 
arrays of
short 16-bit integers representing for each tile whether it is to be 
stored compressed
or uncompressed.  Then, generate a NIFF file, with storing for each file 
either the
raw data of the image to be stored for the tile, if and only if the 
compressed size is
larger than the Group 4 fax compressed size, otherwise copying over the 
raw tile from
the fully compressed image.  The writing of the tiles to the output NIFF 
would be done
after setting the NIFFTAG_SUBFILETYPE, NIFFTAG_NAVYCOMPRESSION, 
NIFFTAG_TILEINDEX,
and other NIFF/TIFF fields besides NIFFTAG_DATAOFFSETS and 
NIFFTAG_DATABYTECOUNTS.