Article View: alt.graphics.pixutils
Article #719[Source] SPOT image to PGM converter
From: Warren Toomey
Date: Mon, 13 Jul 1992 00:36
Date: Mon, 13 Jul 1992 00:36
348 lines
11759 bytes
11759 bytes
Here is the source for a SPOT satellite image to Portable Greymap
converter. This is the first release, and I've only had a limited
number of images to work with (i.e 1), so I expect it may not be
faultless. Thanks to those people who gave me information about
SPOT.
Warren Toomey wkt@csadfa.cs.adfa.oz.au
echo x - spot2pgm.1
sed '/^X/s///' > spot2pgm.1 << '/'
X.TH spot2pgm 1L
X.SH NAME
Xspot2pgm \- convert SPOT satellite images to Portable Greymap format
X.SH SYNTAX
Xspot2pgm [\-1|2|3] [Firstcol Firstline Lastcol Lastline] inputfile
X.SH OPTIONS
X.TP 8
X.B \-1|2|3
XExtract the given colour from the SPOT image. The colours are infra-red,
Xvisible light and ultra-violet, although I don't know which corresponds
Xto which number. If the image is in colour, this will be announced on
Xstandard error. The default colour is 1.
X.TP
X.B Firstcol Firstline Lastcol Lastline
XExtract the specified rectangle from the SPOT image. Most SPOT images are
X3000 lines long and 3000 or more columns wide. Unfortunately the SPOT format
Xonly gives the width and not the length. The width is printed on standard
Xerror. The default rectangle is the width of the input image by 3000 lines.
X.SH DESCRIPTION
X.I Spot2pgm
Xconverts the named
X.B inputfile
Xinto Portable Greymap format, defaulting to the first color and the whole
XSPOT image unless specified by the options.
X.SH INSTALLATION
XYou
X.B must
Xedit the source program and either define BIG\_ENDIAN or LITTLE\_ENDIAN,
Xand fix the typedefs for uint32\_t, uint16\_t and uint8\_t appropriately.
X.SH BUGS
XCurrently
X.I spot2pgm
Xdoesn't determine the length of the input file; this would involve two
Xpasses over the input file. It defaults to 3000 lines instead.
X.PP
X.I Spot2pgm
Xcould extract a three-color image (ppm), but I didn't feel like making the
Xprogram more complicated than it is now. Besides, there is no one-to-one
Xcorrespondence between red, green, blue and infra-red, visible and
Xultra-violet.
X.PP
XI've only had a limited number of SPOT images to play with, and therefore
Xwouldn't guarantee that this will work on any other images.
X.SH AUTHOR
XWarren Toomey wkt@csadfa.cs.adfa.oz.au
X.SH SEE ALSO
XThe rest of the Pbmplus suite.
/
echo x - spot2pgm.c
sed '/^X/s///' > spot2pgm.c << '/'
X/* Spot2pgm: Convert a SPOT satellite image to Portable Greymap format.
X *
X * Usage: spot2pgm [-1|2|3] [Firstcol Firstline Lastcol Lastline] inputfile
X *
X * Author: Warren Toomey, 1992.
X */
X
X#include <stdio.h>
X
X/* You may have to redefine these for your compiler.
X */
Xtypedef unsigned int uint32_t;
Xtypedef unsigned short uint16_t;
Xtypedef unsigned char uint8_t;
X
X/* Define one of the following as appropriate
X * to your architecture.
X */
X#undef BIG_ENDIAN
X#define LITTLE_ENDIAN
X
X/* Global variables */
X
XFILE *spotfile; /* The input file */
Xuint8_t linebuf[12000]; /* The line buffer */
X
Xuint32_t Firstline = 0, /* The rectangle the user wants */
X Lastline = 3000, /* cut out of the image */
X Firstcol = 0,
X Lastcol = 0;
Xuint32_t Diff = 0; /* Firstcol - Lastcol */
Xuint8_t *Bufptr; /* Pointer into the input image */
Xint Color = 1; /* Either 1, 2 or 3 */
Xint Colbool = 0; /* 1 if colour */
X
X
X/* Architecture-dependent functions */
X
X#ifdef BIG_ENDIAN
X# define ntohs(x) (x) /* Convert big endian to little endian */
X# define ntohl(x) (x) /* for both 16- and 32- bit values */
X#endif
X
X#ifdef LITTLE_ENDIAN
Xuint16_t
Xntohs(x)
X uint16_t x;
X{
X uint16_t y;
X char *a, *b;
X
X a = (char *) &x; b = (char *) &y;
X b[0] = a[1]; b[1] = a[0];
X return y;
X}
X
Xuint32_t
Xntohl(x)
X uint32_t x;
X{
X uint32_t y;
X char *a, *b;
X
X a = (char *) &x; b = (char *) &y;
X b[0] = a[3]; b[3] = a[0];
X b[1] = a[2]; b[2] = a[1];
X return y;
X}
X#endif
X
X
X/* Get_image extracts the pixel data from one line
X * (i.e one record) in the SPOT input file. A SPOT image
X * record has a header, data and trailer. The data lengths
X * are fixed at 3960, 5400, 8640 or 10980 bytes.
X *
X * When we arrive here we have read in 12 bytes of the record.
X * We then read in the rest of the record. We find the trailer
X * and from that determine the number of pixels on the line.
X *
X * If the image is really color i.e interleaved 3 colors, we
X * convert a line if its spectral sequence is the same as the one
X * requested by the user (i.e 1, 2 or 3). I could create a ppm file
X * but I couldn't be bothered with the rearranging of the data.
X */
Xint
Xget_image(length)
X uint32_t length;
X{
X int cnt;
X struct Linehdr /* Each line begins with the 12 bytes */
X { /* we have already, plus these 20 bytes */
X uint32_t linenum; /* The line number of the record */
X uint16_t recseq; /* The record sequence number */
X uint16_t spectseq; /* The spectral number of the line */
X uint32_t linetime; /* Time it was recorded (in ms). */
X uint32_t leftpixmar; /* The pixel number of the 1st pixel */
X uint32_t rightpixmar; /* The pixel number of the last pixel */
X } linehdr;
X struct Lineend
X { /* And after the fixed size */
X uint8_t lossflg; /* data, we have this */
X uint8_t oorflag;
X uint8_t reserved1[22];
X uint32_t numpixels; /* Number of pixels on the line */
X } *lineend;
X
X /* Get the details of this line */
X cnt = fread(&linehdr, sizeof(linehdr), 1, spotfile);
X if (cnt == 0) exit(1);
X /* Convert to little-endian */
X#ifdef LITTLE_ENDIAN
X linehdr.linenum = ntohl(linehdr.linenum);
X linehdr.spectseq = ntohs(linehdr.spectseq);
X# ifdef DEBUG
X linehdr.leftpixmar = ntohl(linehdr.leftpixmar);
X linehdr.rightpixmar = ntohl(linehdr.rightpixmar);
X linehdr.recseq = ntohs(linehdr.recseq);
X linehdr.linetime = ntohl(linehdr.linetime);
X# endif
X#endif
X
X /* Now read in the line data */
X cnt = length - 20;
X cnt = fread(linebuf, 1, cnt, spotfile);
X
X if (!Diff)
X { switch (length) /* Try and find the trailer */
X {
X case 3948: lineend = (struct Lineend *) &linebuf[3860]; break;
X case 5388: lineend = (struct Lineend *) &linebuf[5300]; break;
X case 8628: lineend = (struct Lineend *) &linebuf[8540]; break;
X case 10968: lineend = (struct Lineend *) &linebuf[10880]; break;
X default: fprintf(stderr, "Bad image line record size\n"); exit(1);
X }
X
X#ifdef LITTLE_ENDIAN
X /* Work out the number of pixels */
X lineend->numpixels = ntohl(lineend->numpixels);
X#endif
X
X /* Determine the picture size */
X Bufptr = &linebuf[Firstcol];
X if (Lastcol == 0 || Lastcol > lineend->numpixels)
X Lastcol = lineend->numpixels;
X Diff = Lastcol - Firstcol;
X /* Print out the header */
X printf("P5\n%d %d\n255\n", Diff, Lastline - Firstline);
X /* Inform about the image size */
X if (Colbool) fprintf(stderr, "Color image, ");
X fprintf(stderr, "%d pixels wide\n", lineend->numpixels);
X }
X
X /* Output the line */
X if (linehdr.linenum >= Firstline && linehdr.linenum <= Lastline
X && linehdr.spectseq == Color)
X fwrite(Bufptr, 1, Diff, stdout);
X if (linehdr.linenum > Lastline) exit(0);
X
X#ifdef DEBUG
X fprintf(stderr,
X "Line %4d, %3d, %3d, time %4d, l/r pixmar %4d %4d len %d pixnum %d\n",
X linehdr.linenum, linehdr.recseq, linehdr.spectseq, linehdr.linetime,
X linehdr.leftpixmar, linehdr.rightpixmar, length, lineend->numpixels);
X#endif
X /* And return the amount to seek - should be 0 */
X return (length - 20 - cnt);
X}
X
X/* The image header tells us if the image is in monochrome or color, and
X * if the latter, if the input colors are interleaved. If interleaved
X * color, lines are interleaved R, G, B, R, G, B etc. Technically, some
X * interleaving of infra-red, visible and ultra-violet.
X *
X * In the description field below,
X * element 0 == P --> monochrome
X * element 0 == X --> color
X * element 9 == S --> sequential (i.e only one color here)
X * element 9 == I --> interleaved (1 or more colors)
X */
Xint
Xget_imghdr(length)
X int length;
X{
X int cnt;
X struct Imghdr
X {
X uint32_t linewidth;
X uint8_t dummy1[36];
X char description[16]; /* Type of image */
X } header;
X
X cnt = fread(&header, sizeof(header), 1, spotfile);
X if (cnt == 0) exit(1);
X
X /* Determine mono or colour */
X if (header.description[0] == 'X' && header.description[9] == 'S')
X Colbool = 1;
X else Colbool = 0;
X
X#ifdef DEBUG
X fprintf(stderr, "Dummy str is >%s<\n", header.dummy1);
X fprintf(stderr, "Imghdr str is >%s<, col %d\n", header.description, Colbool);
X#endif
X /* Return the amount to fseek */
X return (length - sizeof(header));
X}
X
Xusage()
X{
X fprintf(stderr,
X"Usage: spot2pgm [-1|2|3] [Firstcol Firstline Lastcol Lastline] input_file\n");
X exit(1);
X}
X
Xmain(argc, argv)
X int argc;
X char *argv[];
X
X{
X struct Record /* A SPOT image is broken up into */
X { /* records with the following fields */
X uint32_t record; /* The record number (1, 2, 3...) */
X uint8_t sub1; /* Record sub type 1 */
X uint8_t type; /* The record type */
X uint8_t sub2; /* Record sub type 2 */
X uint8_t sub3; /* Record sub type 3 */
X uint32_t length; /* Record length in bytes */
X } arecord;
X int cnt;
X
X if (sizeof(uint32_t)!=4 || sizeof(uint16_t)!=2 || sizeof(uint8_t)!=1)
X { fprintf(stderr, "Typedefs in spot2pgm wrong size -- recompile!\n");
X exit(1);
X }
X
X switch (argc)
X {
X case 7:
X Color= -(atoi(argv[1])); /* Get the color to extract */
X argv++;
X case 6:
X Firstcol = atoi(argv[1]); /* Get the rectangle to extract */
X Firstline = atoi(argv[2]);
X Lastcol = atoi(argv[3]);
X Lastline = atoi(argv[4]);
X argv += 4;
X goto openfile; /* Yuk, a goto! */
X case 3:
X Color= -(atoi(argv[1])); /* Get the color to extract */
X argv++;
X case 2:
Xopenfile:
X spotfile = fopen(argv[1], "r"); /* Open the input file */
X if (spotfile == NULL) { perror("fopen"); exit(1); }
X break;
X default:
X usage();
X }
X
X while (1) /* Get a record */
X { cnt = fread(&arecord, sizeof(arecord), 1, spotfile);
X if (cnt == 0) break;
X#ifdef LITTLE_ENDIAN
X arecord.length = ntohl(arecord.length);
X# ifdef DEBUG
X arecord.record = ntohl(arecord.record);
X# endif
X#endif
X
X
X arecord.length -= 12; /* Subtract header size as well */
X if (arecord.type == 0355 && arecord.sub1 == 0355)
X arecord.length = get_image(arecord.length);
X else if (arecord.type == 0300 && arecord.sub1 == 077)
X arecord.length = get_imghdr(arecord.length);
X#ifdef DEBUG
X else
X fprintf(stderr, "Rcrd %3d, type %03o, stype %03o %03o %03o, length %d\n",
X arecord.record, arecord.type, arecord.sub1, arecord.sub2,
(int) arecord.sub3 & 0xff, arecord.length);
X#endif
X /* Seek to next record */
X fseek(spotfile, arecord.length, 1);
X }
X}
/
Technical Details
Message-ID:
<1992Jul13.003617.18659@sserve.cc.adfa.oz.au>Path:
arc1-ca.pugleaf.net!wupost!spool.mu.edu!mips!mips!munnari.oz.au!manuel!sserve!csadfa.cs.adfa.oz.au!wktShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!wupost!spool.mu.edu!mips!mips!munnari.oz.au!manuel!sserve!csadfa.cs.adfa.oz.au!wkt From: wkt@csadfa.cs.adfa.oz.au (Warren Toomey) Newsgroups: alt.graphics.pixutils,alt.sources,sci.astro Subject: [Source] SPOT image to PGM converter Keywords: SPOT pgm converter source Message-ID: <1992Jul13.003617.18659@sserve.cc.adfa.oz.au> Date: 13 Jul 92 00:36:17 GMT Article-I.D.: sserve.1992Jul13.003617.18659 Sender: news@sserve.cc.adfa.oz.au Organization: Australian Defence Force Academy, Canberra, Australia Lines: 348