Date: Tue, 22 Apr 97 20:24:31 EDT
From: margie@pgt.com (Margie Mott)
To: david.bright@nist.gov
Subject: Re: PGT software questions

Hi David,

As promised, but very late - sorry! - this should give you what you need for particle locations. 

It's not a completely elegant job. Please let me know about any questions you have.

Regards,

Margie Mott

PGT
margie@pgt.com
___________________________________________________________ 

PGT Image File Format, not Including 24-bit True Color: ------------------------------------------------------- 

The format of PGT images is based on Sun raster files, with PGT-specific information appended.

If the file is a multi-image file, such as an X-ray map, the file format is similar, like this:

Sun raster image 1
PGT data for image 1
Sun raster image 2
PGT data for image 2
...

until end-of-file.

----------------------------------------------------------------------------------- 1. Sun Raster File Format:
---------------------------

The header file which describes this is /usr/include/rasterfile.h, on any non-Solaris 2 Sun.

Bytes 0-31	Header, defined as follows:

struct rasterfile {
int	ras_magic;	/* magic number */
int	ras_width;	/* width (pixels) of image */
int	ras_height;	/* height (pixels) of image */
int	ras_depth;	/* depth (1, 8, or 24 bits) of pixel */
int	ras_length;	/* length (bytes) of image */
int	ras_type;	/* type of file; see RT_* below */
int	ras_maptype;	/* type of colormap; see RMT_* below */
int	ras_maplength;	/* length (bytes) of following map */
/* color map follows for ras_maplength bytes, followed by image */ };

The following settings in the header should always be true: 

ras_magic	0x59a66a95
ras_type	0	/* RT_STANDARD. */
ras_maptype	1	/* RMT_EQUAL_RGB. */
ras_maplength 768	/* 256 bytes of read, 256 bytes of
* green, 256 bytes of blue. */

Here's how to account for ras_length:

ras_length	(ras_width * (bit_depth/8)), rounded up to make the
number of bytes in the line
a multiple of 4,

multiplied by ras_height, which is number of lines.
(The exception here is that 24-bit data is actually
stored as 32-bit data.)

Bytes 32-799	Color table.

256 bytes red
256 bytes green
256 bytes blue

Bytes 800-(800+ras_length)	Image data, with the data origin in the
upper left corner. Remember that lines
of image data are a multiple of 4 bytes.

----------------------------------------------------------------------------------- 2. PGT Appended Data:
----------------------

There are 2 parts to this.

The first is the display list, which is the information about all the items drawn on top of the PGT image, such as numeric marks, boxes, and text.

The second is the collection header, which contains the image label and distance calibration.

2a. PGT Display List:
---------------------

All the definitions for this are included in display_list.h, which I am appending.

Read the next 4-byte int, and see if it equals DLIST_MAGIC. 

If it does, the following int is the number of items in the display list.

Once you know the number of items, you can read them into an array of

struct display_list_node items[num_items]; 

We read these in a loop, one by one, and process them. 

You should look for the items which are of type "mark_t". For each of those, its location is stored in "struct pr_pos", which is simply:

struct pr_pos {
int x;
int y;
}

It's defined in one of the Sun header files, but if you have any difficulty, just add that somewhere.

2b. PGT Collection Header:
--------------------------

Read the next 4-byte int, and see if it equals COLLECTION_HEADER_MAGIC. 

If it does, use some reasonable approximation of the code I am appending here. When you are done reading the collection header, If you are not at end-of-file, there is another image to come, starting with the Sun rasterfile header. 

/* Read fixed length stuff from
* collection header first.*/

/* The following fields are read with separate
* freads rather than just doing one fread on a
* structure (as it used to do). This is because
* of an incompatibility between the Sun3 and the
* Sparc in the way fields of a structure are
* aligned on byte/word boundaries. */
fread (&version, sizeof (double), 1, fp); 

fread (&name_length, sizeof (int), 1, fp); 

fread (&units_length, sizeof (int), 1, fp); 

fread (&cal_filename_length, sizeof (int), 1, fp); 

fread (&im->mag, sizeof (double), 1, fp); 

fread (&im->units_per_pixel, sizeof (double), 1, fp); 

if (version == 1.0) {
im->collection_size = 512;
}
if (version >= 1.1) {

fread (&im->collection_size, sizeof (int), 1, fp); }
if (version >= 1.2) {

fread (&im->true_color_transform, sizeof (int), 1, fp); } else {
im->true_color_transform = PIC_GRAY;
}

/* Read variable length stuff. */

if (name_length > 0) {
fread (im->name, name_length, 1, fp);
im->name[name_length] = '\0';
}

if (units_length > 0) {
fread (im->units, units_length, 1, fp);
im->units[units_length] = '\0';
}

if (cal_filename_length > 0) {
fread (im->calibration_filename, cal_filename_length, 1, fp); im->calibration_filename[cal_filename_length] = '\0'; }

_______________________________________________________________________________________________ /* @(#) display_list.h 1.9 3/31/97 Copyright PGT */ 

#include <sys/types.h>
#ifdef XVIEW
#include <xview/xview.h>
#include <xview/font.h>
#include <xview/canvas.h>
#include <xview/cms.h>
#include <X11/Xlib.h>
#else
#include <suntool/sunview.h>
#include <suntool/canvas.h>
#endif
#include <pixrect/pixrect.h>
#include <pixrect/pixfont.h>

#define DLIST_MAGIC	0x59a66a96

typedef enum {
mark_t, text_t, box_t, line_t, pr_t, /* real types */ scale_bar_t,
no_type, draggable_type, any_type,	/* pseudo-types, for select */
} display_item_type;

/*
* would be nice to add a chain-coded, 3-bit per pixel (10-step/word) outline * representation to this---
*/

#define DISPLAY_ITEM_TYPES 6	/* not including pseudo-types */

struct display_list_node {

/* Public parts of structure */

display_item_type type;	/* controls which of following are
* used; set, don't change	*/
int col;	/* color	*/
struct pr_pos pos;	/* position in data space */
char *text;	/* a text label	*/
char *font_name;	/* use this for load/store */
Pixrect *pr;	/* a monochrome pixrect */
int zoom_pr_flag;	/* use mag on above ? */
int no_drag_flag;
struct pr_size size;	/* a box size	*/
int box_no;	/* all "no's" start at 1 */
int mark_no;	/* an indexed mark	*/

/* Private parts of structure */

int zoom_to;	/* number of image box zooms to */
struct display_list_node *end_a, *end_b;	/* id's of line endpts */
int text_len;	/* including NUL	*/
#ifdef XVIEW
Xv_Font font;	/* don't load and store this */
#else
Pixfont *font;	/* don't load and store this */
#endif
int font_name_len;	/* including NUL	*/

int quadrant;	/* line only */
int controls_zoom;	/* box only */
int controls_histogram_or_profile;

/* crammed into same flag so as
not to change structure, so we can
load old images */
Rectlist *rl;	/* display space obscured, in each
* view */
struct display_list_node *next, *prev, *self; struct display_list_node **overlaps; /* vector of all dlist items 
* overlapping this one */
int noverlaps;
struct display_list_node **zooms;	/* vector of all dlist items
* zoomed by this one */
int nzooms;
};
#define HIST 1
#define PROF 2

struct display_list {
struct display_list_node *list[DISPLAY_ITEM_TYPES]; int count[DISPLAY_ITEM_TYPES];
int hide[DISPLAY_ITEM_TYPES];
};

struct display_header {
Canvas canvas;
#ifdef XVIEW
Xv_Window pw;	/* Paint window for canvas. */
GC gc;
Window xid;	/* Canvas's XID. */
Visual *visual;	/* Paint window visual. */
Cms cms;
int	pw_depth;
char pw_name[10];
#endif
int w;	/* Width of display. */
int h;	/* Height of display. */
int this;	/* Which subwindow we are,
* counting from 1. */
int ancestor;	/* If we're a mag window,
* subwindow # of image at
* head of mag chain. */
Pixrect *data;	/* Parent's, if we're mag. */
struct display_list *dlist;	/* If we're a mag window,
* display list of parent. */
int *hide_mark_numbers;	/* TRUE if mark numbers are
* to be hidden. */
};

struct display_list_node *add_to_display_list (), *select_from_display_list (), *find_end (); 

#define FOR_TYPE(dlist,li,type) for(li= dlist->list[(int)type]; li; li=li->next) #define END_FOR_TYPE

#define FOR_ALL_TYPES(dlist,li)	\
{display_item_type __temptype; \
for(__temptype=(display_item_type)0; (int)__temptype<DISPLAY_ITEM_TYPES;\ 
__temptype=(display_item_type)((int)__temptype+1))\
FOR_TYPE(dlist,li,__temptype)
#define END_FOR_ALL_TYPES	}

#define FOR_TYPE_BACKWARDS(dlist,li,type) for(li= find_end(dlist->list[(int)type]); li; li=li->prev) #define END_FOR_TYPE_BACKWARDS

#define FOR_ALL_TYPES_BACKWARDS(dlist,li)	\
{display_item_type __temptype; \
for(__temptype=(display_item_type)0; (int)__temptype<DISPLAY_ITEM_TYPES;\ 
__temptype=(display_item_type)((int)__temptype+1))\
FOR_TYPE_BACKWARDS(dlist,li,__temptype)
#define END_FOR_ALL_TYPES_BACKWARDS	}

struct display_list_node **get_whole_dlist(), **get_dlist_items();