home *** CD-ROM | disk | FTP | other *** search
- /* Spottopgm: Convert a SPOT satellite image to Portable Greymap format.
- *
- * Usage: spottopgm [-1|2|3] [Firstcol Firstline Lastcol Lastline] inputfile
- *
- * Author: Warren Toomey, 1992.
- */
-
- #include <stdio.h>
- #include "pgm.h"
-
- /* You may have to redefine these for your compiler.
- */
- typedef unsigned int uint32_t;
- typedef unsigned short uint16_t;
- typedef unsigned char uint8_t;
-
- /* Define one of the following as appropriate
- * to your architecture.
- */
- #undef BIG_ENDIAN
- #define LITTLE_ENDIAN
-
- /* prototypes */
- #ifdef LITTLE_ENDIAN
- uint16_t ntohs ARGS((uint16_t x));
- uint32_t ntohl ARGS((uint32_t x));
- #endif
- int get_image ARGS((uint32_t length));
- int get_imghdr ARGS((int length));
- int usage ARGS((void));
- /* Global variables */
-
- FILE *spotfile; /* The input file */
- uint8_t linebuf[12000]; /* The line buffer */
-
- uint32_t Firstline = 0, /* The rectangle the user wants */
- Lastline = 3000, /* cut out of the image */
- Firstcol = 0,
- Lastcol = 0;
- uint32_t Diff = 0; /* Firstcol - Lastcol */
- uint8_t *Bufptr; /* Pointer into the input image */
- int Color = 1; /* Either 1, 2 or 3 */
- int Colbool = 0; /* 1 if colour */
-
-
- /* Architecture-dependent functions */
-
- #ifdef BIG_ENDIAN
- # define ntohs(x) (x) /* Convert big endian to little endian */
- # define ntohl(x) (x) /* for both 16- and 32- bit values */
- #endif
-
- #ifdef LITTLE_ENDIAN
- uint16_t
- ntohs(x)
- uint16_t x;
- {
- uint16_t y;
- char *a, *b;
-
- a = (char *) &x; b = (char *) &y;
- b[0] = a[1]; b[1] = a[0];
- return y;
- }
-
- uint32_t
- ntohl(x)
- uint32_t x;
- {
- uint32_t y;
- char *a, *b;
-
- a = (char *) &x; b = (char *) &y;
- b[0] = a[3]; b[3] = a[0];
- b[1] = a[2]; b[2] = a[1];
- return y;
- }
- #endif
-
-
- /* Get_image extracts the pixel data from one line
- * (i.e one record) in the SPOT input file. A SPOT image
- * record has a header, data and trailer. The data lengths
- * are fixed at 3960, 5400, 8640 or 10980 bytes.
- *
- * When we arrive here we have read in 12 bytes of the record.
- * We then read in the rest of the record. We find the trailer
- * and from that determine the number of pixels on the line.
- *
- * If the image is really color i.e interleaved 3 colors, we
- * convert a line if its spectral sequence is the same as the one
- * requested by the user (i.e 1, 2 or 3). I could create a ppm file
- * but I couldn't be bothered with the rearranging of the data.
- */
- int
- get_image(length)
- uint32_t length;
- {
- int cnt;
- struct Linehdr /* Each line begins with the 12 bytes */
- { /* we have already, plus these 20 bytes */
- uint32_t linenum; /* The line number of the record */
- uint16_t recseq; /* The record sequence number */
- uint16_t spectseq; /* The spectral number of the line */
- uint32_t linetime; /* Time it was recorded (in ms). */
- uint32_t leftpixmar; /* The pixel number of the 1st pixel */
- uint32_t rightpixmar; /* The pixel number of the last pixel */
- } linehdr;
- struct Lineend
- { /* And after the fixed size */
- uint8_t lossflg; /* data, we have this */
- uint8_t oorflag;
- uint8_t reserved1[22];
- uint32_t numpixels; /* Number of pixels on the line */
- } *lineend;
-
- /* Get the details of this line */
- cnt = fread(&linehdr, sizeof(linehdr), 1, spotfile);
- if (cnt == 0) exit(1);
- /* Convert to little-endian */
- #ifdef LITTLE_ENDIAN
- linehdr.linenum = ntohl(linehdr.linenum);
- linehdr.spectseq = ntohs(linehdr.spectseq);
- # ifdef DEBUG
- linehdr.leftpixmar = ntohl(linehdr.leftpixmar);
- linehdr.rightpixmar = ntohl(linehdr.rightpixmar);
- linehdr.recseq = ntohs(linehdr.recseq);
- linehdr.linetime = ntohl(linehdr.linetime);
- # endif
- #endif
-
- /* Now read in the line data */
- cnt = length - 20;
- cnt = fread(linebuf, 1, cnt, spotfile);
-
- if (!Diff)
- { switch (length) /* Try and find the trailer */
- {
- case 3948: lineend = (struct Lineend *) &linebuf[3860]; break;
- case 5388: lineend = (struct Lineend *) &linebuf[5300]; break;
- case 8628: lineend = (struct Lineend *) &linebuf[8540]; break;
- case 10968: lineend = (struct Lineend *) &linebuf[10880]; break;
- default: fprintf(stderr, "Bad image line record size\n"); exit(1);
- }
-
- #ifdef LITTLE_ENDIAN
- /* Work out the number of pixels */
- lineend->numpixels = ntohl(lineend->numpixels);
- #endif
-
- /* Determine the picture size */
- Bufptr = &linebuf[Firstcol];
- if (Lastcol == 0 || Lastcol > lineend->numpixels)
- Lastcol = lineend->numpixels;
- Diff = Lastcol - Firstcol;
- /* Print out the header */
- printf("P5\n%d %d\n255\n", Diff, Lastline - Firstline);
- /* Inform about the image size */
- if (Colbool) fprintf(stderr, "Color image, ");
- fprintf(stderr, "%d pixels wide\n", lineend->numpixels);
- }
-
- /* Output the line */
- if (linehdr.linenum >= Firstline && linehdr.linenum <= Lastline
- && linehdr.spectseq == Color)
- fwrite(Bufptr, 1, Diff, stdout);
- if (linehdr.linenum > Lastline) exit(0);
-
- #ifdef DEBUG
- fprintf(stderr,
- "Line %4d, %3d, %3d, time %4d, l/r pixmar %4d %4d len %d pixnum %d\n",
- linehdr.linenum, linehdr.recseq, linehdr.spectseq, linehdr.linetime,
- linehdr.leftpixmar, linehdr.rightpixmar, length, lineend->numpixels);
- #endif
- /* And return the amount to seek - should be 0 */
- return (length - 20 - cnt);
- }
-
- /* The image header tells us if the image is in monochrome or color, and
- * if the latter, if the input colors are interleaved. If interleaved
- * color, lines are interleaved R, G, B, R, G, B etc. Technically, some
- * interleaving of infra-red, visible and ultra-violet.
- *
- * In the description field below,
- * element 0 == P --> monochrome
- * element 0 == X --> color
- * element 9 == S --> sequential (i.e only one color here)
- * element 9 == I --> interleaved (1 or more colors)
- */
- int
- get_imghdr(length)
- int length;
- {
- int cnt;
- struct Imghdr
- {
- uint32_t linewidth;
- uint8_t dummy1[36];
- char description[16]; /* Type of image */
- } header;
-
- cnt = fread(&header, sizeof(header), 1, spotfile);
- if (cnt == 0) exit(1);
-
- /* Determine mono or colour */
- if (header.description[0] == 'X' && header.description[9] == 'S')
- Colbool = 1;
- else Colbool = 0;
-
- #ifdef DEBUG
- fprintf(stderr, "Dummy str is >%s<\n", header.dummy1);
- fprintf(stderr, "Imghdr str is >%s<, col %d\n", header.description, Colbool);
- #endif
- /* Return the amount to fseek */
- return (length - sizeof(header));
- }
-
- usage()
- {
- fprintf(stderr,
- "Usage: spottopgm [-1|2|3] [Firstcol Firstline Lastcol Lastline] input_file\n");
- exit(1);
- }
-
- int
- main(argc, argv)
- int argc;
- char *argv[];
-
- {
- struct Record /* A SPOT image is broken up into */
- { /* records with the following fields */
- uint32_t record; /* The record number (1, 2, 3...) */
- uint8_t sub1; /* Record sub type 1 */
- uint8_t type; /* The record type */
- uint8_t sub2; /* Record sub type 2 */
- uint8_t sub3; /* Record sub type 3 */
- uint32_t length; /* Record length in bytes */
- } arecord;
- int cnt;
-
- pgm_init( &argc, argv );
-
- if (sizeof(uint32_t)!=4 || sizeof(uint16_t)!=2 || sizeof(uint8_t)!=1)
- { fprintf(stderr, "Typedefs in spottopgm wrong size -- recompile!\n");
- exit(1);
- }
-
- switch (argc)
- {
- case 7:
- Color= -(atoi(argv[1])); /* Get the color to extract */
- argv++;
- case 6:
- Firstcol = atoi(argv[1]); /* Get the rectangle to extract */
- Firstline = atoi(argv[2]);
- Lastcol = atoi(argv[3]);
- Lastline = atoi(argv[4]);
- argv += 4;
- goto openfile; /* Yuk, a goto! */
- case 3:
- Color= -(atoi(argv[1])); /* Get the color to extract */
- argv++;
- case 2:
- openfile:
- spotfile = fopen(argv[1], "r"); /* Open the input file */
- if (spotfile == NULL) { perror("fopen"); exit(1); }
- break;
- default:
- usage();
- }
-
- while (1) /* Get a record */
- { cnt = fread(&arecord, sizeof(arecord), 1, spotfile);
- if (cnt == 0) break;
- #ifdef LITTLE_ENDIAN
- arecord.length = ntohl(arecord.length);
- # ifdef DEBUG
- arecord.record = ntohl(arecord.record);
- # endif
- #endif
-
-
- arecord.length -= 12; /* Subtract header size as well */
- if (arecord.type == 0355 && arecord.sub1 == 0355)
- arecord.length = get_image(arecord.length);
- else if (arecord.type == 0300 && arecord.sub1 == 077)
- arecord.length = get_imghdr(arecord.length);
- #ifdef DEBUG
- else
- fprintf(stderr, "Rcrd %3d, type %03o, stype %03o %03o %03o, length %d\n",
- arecord.record, arecord.type, arecord.sub1, arecord.sub2,
- (int) arecord.sub3 & 0xff, arecord.length);
- #endif
- /* Seek to next record */
- fseek(spotfile, arecord.length, 1);
- }
- }
-