about summary refs log tree commit diff
path: root/converter/pgm/spottopgm.c
blob: 26801cb20e6c8f7ed966a5803b71c13ce0d085d4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/* Spottopgm: Convert a SPOT satellite image to PGM format.
 *
 * Usage: spottopgm [-1|2|3] [Firstcol Firstline Lastcol Lastline] inputfile
 *
 * Author: Warren Toomey, 1992.
 */

#include <stdio.h>
#include "pgm.h"

/* Global variables */

static FILE *spotfile;          /* The input file */
static char linebuf[12000];        /* The line buffer */

static long Firstline = 0,     /* The rectangle the user wants */
    Lastline = 3000,   /* cut out of the image */
    Firstcol = 0,
    Lastcol = 0;
static long Diff = 0;          /* Firstcol - Lastcol */
static char *Bufptr;           /* Pointer into the input image */
static int Color = 1;          /* Either 1, 2 or 3 */
static int Colbool = 0;        /* 1 if color */


/* 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.
 */
static int
get_image(long length)
{
    int cnt;
    struct Linehdr        /* Each line begins with the 12 bytes */
    {             /* we have already, plus these 20 bytes */
        long linenum;       /* The line number of the record */
        short recseq;       /* The record sequence number */
        short spectseq;     /* The spectral number of the line */
        long linetime;      /* Time it was recorded (in ms). */
        long leftpixmar;        /* The pixel number of the 1st pixel */
        long rightpixmar;       /* The pixel number of the last pixel */
    } linehdr;
    long numpixels;       /* Number of pixels on the line */

    /* Get the details of this line */
    if (pm_readbiglong (spotfile, &linehdr.linenum) == -1
        || pm_readbigshort (spotfile, &linehdr.recseq) == -1
        || pm_readbigshort (spotfile, &linehdr.spectseq) == -1
        || pm_readbiglong (spotfile, &linehdr.linetime) == -1
        || pm_readbiglong (spotfile, &linehdr.leftpixmar) == -1
        || pm_readbiglong (spotfile, &linehdr.rightpixmar) == -1)
        pm_error ("EOF / read error reading line header");

    /* Now read in the line data */
    cnt = length - 20 - 88;
    cnt = fread(linebuf, 1, cnt, spotfile);

    if (!Diff)
    {
        cnt += 28;
        if (fseek (spotfile, 24, 1) == EOF)
            pm_error ("seek error");
        if (pm_readbiglong (spotfile, &numpixels) == -1)
            pm_error ("EOF / read error reading line ender");

        /* Determine the picture size */
        Bufptr = &linebuf[Firstcol];
        if (Lastcol == 0 || Lastcol > numpixels)
            Lastcol = numpixels;
        Diff = Lastcol - Firstcol;
        /* Print out the header */
        printf("P5\n%ld %ld\n255\n", Diff, Lastline - Firstline);
        /* Inform about the image size */
        if (Colbool) fprintf(stderr, "Color image, ");
        fprintf(stderr, "%ld pixels wide\n", 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, numpixels);
#endif
    /* And return the amount to seek */
    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)
 */
static int
get_imghdr(int length)
{
    struct Imghdr
    {
        long linewidth;
        char dummy1[36];
        char description[16];   /* Type of image */
    } header;

    if (pm_readbiglong (spotfile, &header.linewidth) == -1)
        pm_error ("EOF / read error reading header");
#ifdef DEBUG
    if (fread (header.dummy1, 1, 36, spotfile) != 36)
        pm_error ("EOF / read error reading header");
#else
    if (fseek (spotfile, 36, 1) == EOF)
        pm_error ("seek error");
#endif
    if (fread (header.description, 1, 16, spotfile) != 16)
        pm_error ("EOF / read error reading header");

    /* Determine mono or color */
    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 - 56);
}



static void
usage()
{
    fprintf(stderr,
            "Usage: spottopgm [-1|2|3] [Firstcol Firstline Lastcol Lastline] "
            "input_file\n");
    exit(1);
}



int
main(int argc, char *argv[])
{
    struct Record             /* A SPOT image is broken up into */
    {                 /* records with the following fields */
        long record;            /* The record number (1, 2, 3...) */
        unsigned char sub1;         /* Record sub type 1 */
        unsigned char type;         /* The record type */
        unsigned char sub2;         /* Record sub type 2 */
        unsigned char sub3;         /* Record sub type 3 */
        long length;            /* Record length in bytes */
    } arecord;

    pgm_init( &argc, argv );

    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], "rb");  /* Open the input file */
    if (spotfile == NULL) { perror("fopen"); exit(1); }
    break;
    default:
        usage();
    }

    while (1)             /* Get a record */
    {
        if (pm_readbiglong (spotfile, &arecord.record) == -1)
            break;
        arecord.sub1 = fgetc (spotfile);
        arecord.type = fgetc (spotfile);
        arecord.sub2 = fgetc (spotfile);
        arecord.sub3 = fgetc (spotfile);
        if (pm_readbiglong (spotfile, &arecord.length) == -1)
            pm_error ("EOF / read error reading a record");

        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);
    }
    exit (0);
}