File: jpeg2hdf.c

package info (click to toggle)
libhdf4 4.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 29,892 kB
  • sloc: ansic: 128,688; sh: 14,969; fortran: 12,444; java: 5,864; xml: 1,305; makefile: 900; yacc: 678; pascal: 418; perl: 360; javascript: 203; lex: 163; csh: 41
file content (396 lines) | stat: -rw-r--r-- 12,352 bytes parent folder | download | duplicates (3)
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
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * Copyright by the Board of Trustees of the University of Illinois.         *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF.  The full HDF copyright notice, including       *
 * terms governing use, modification, and redistribution, is contained in    *
 * the COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF/releases/.  *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "hdf_priv.h"

/* Size of the file buffer to copy through */
#define MAX_FILE_BUF 16384

typedef enum { /* JPEG marker codes */
               M_SOF0 = 0xc0,
               M_SOF1 = 0xc1,
               M_SOF2 = 0xc2,
               M_SOF3 = 0xc3,

               M_SOF5 = 0xc5,
               M_SOF6 = 0xc6,
               M_SOF7 = 0xc7,

               M_JPG   = 0xc8,
               M_SOF9  = 0xc9,
               M_SOF10 = 0xca,
               M_SOF11 = 0xcb,

               M_SOF13 = 0xcd,
               M_SOF14 = 0xce,
               M_SOF15 = 0xcf,

               M_DHT = 0xc4,

               M_DAC = 0xcc,

               M_RST0 = 0xd0,
               M_RST1 = 0xd1,
               M_RST2 = 0xd2,
               M_RST3 = 0xd3,
               M_RST4 = 0xd4,
               M_RST5 = 0xd5,
               M_RST6 = 0xd6,
               M_RST7 = 0xd7,

               M_SOI = 0xd8,
               M_EOI = 0xd9,
               M_SOS = 0xda,
               M_DQT = 0xdb,
               M_DNL = 0xdc,
               M_DRI = 0xdd,
               M_DHP = 0xde,
               M_EXP = 0xdf,

               M_APP0  = 0xe0,
               M_APP15 = 0xef,

               M_JPG0  = 0xf0,
               M_JPG13 = 0xfd,
               M_COM   = 0xfe,

               M_TEM = 0x01,

               M_ERROR = 0x100
} JPEG_MARKER;

static int32 num_bytes;              /* number of bytes until the SOS code. */
static int32 image_width    = 0;     /* width of the JPEG image in pixels */
static int32 image_height   = 0;     /* height of the JPEG image in pixels */
static intn  num_components = 0;     /* number of components in the JPEG image */
static uint8 file_buf[MAX_FILE_BUF]; /* size of the buffer to copy through */

/*
 * Routines to parse JPEG markers & save away the useful info.
 */

static intn
jgetc(FILE *f)
/* Get a 2-byte unsigned integer (e.g., a marker parameter length field) */
{
    intn a;

    a = fgetc(f);
    if (a != EOF)
        num_bytes++;
    return (a);
}

static int32
get_2bytes(FILE *f)
/* Get a 2-byte unsigned integer (e.g., a marker parameter length field) */
{
    int32 a;

    a = jgetc(f);
    return (a << 8) + jgetc(f);
}

static void
get_sof(FILE *f)
/* Process a SOFn marker */
{
    short ci;

    (void)get_2bytes(f);

    jgetc(f); /* data_precision */
    image_height   = get_2bytes(f);
    image_width    = get_2bytes(f);
    num_components = jgetc(f);

    for (ci = 0; ci < num_components; ci++) {
        jgetc(f);
        jgetc(f);
        jgetc(f);
    }
}

static void
skip_variable(FILE *f)
/* Skip over an unknown or uninteresting variable-length marker */
{
    int32 length;

    length = get_2bytes(f);

    for (length -= 2; length > 0; length--)
        (void)jgetc(f);
}

static intn
next_marker(FILE *f)
/* Find the next JPEG marker */
/* Note that the output might not be a valid marker code, */
/* but it will never be 0 or FF */
{
    intn c, nbytes;

    nbytes = 0;
    do {
        do { /* skip any non-FF bytes */
            nbytes++;
            c = jgetc(f);
        } while (c != 0xFF);
        do { /* skip any duplicate FFs */
            nbytes++;
            c = jgetc(f);
        } while (c == 0xFF);
    } while (c == 0); /* repeat if it was a stuffed FF/00 */

    return c;
}

static JPEG_MARKER
process_tables(FILE *f)
/* Scan and process JPEG markers that can appear in any order */
/* Return when an SOI, EOI, SOFn, or SOS is found */
{
    int c;

    while (TRUE) {
        c = next_marker(f);

        switch (c) {
            case M_EOI:
                return ((JPEG_MARKER)c);

            case M_SOF0:
            case M_SOF1:
            case M_SOF9:
                get_sof(f);
                return ((JPEG_MARKER)c);

            case M_RST0: /* these are all parameterless */
            case M_RST1:
            case M_RST2:
            case M_RST3:
            case M_RST4:
            case M_RST5:
            case M_RST6:
            case M_RST7:
            case M_TEM:
                break;

            default: /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn */
                skip_variable(f);
                break;
        }
    }
}

/*
 * Initialize and read the file header (everything through the SOF marker).
 */

static int32
read_file_header(FILE *f)
{
    int c;

    num_bytes = 0; /* reset the number of bytes into the file we are */

    /* Demand an SOI marker at the start of the file --- otherwise it's
     * probably not a JPEG file at all.  If the user interface wants to support
     * nonstandard headers in front of the SOI, it must skip over them itself
     * before calling jpeg_decompress().
     */
    if (jgetc(f) != 0xFF || jgetc(f) != M_SOI)
        return (0);

    /* Process markers until SOF */
    c = (int)process_tables(f);

    switch (c) {
        case M_SOF0: /* ok, now we know the correct number of bytes to grab */
        case M_SOF1:
        case M_SOF9:
            return (num_bytes);

        default:
            return (0);
    }
}

/*-----------------------------------------------------------------------------
 * Name:    DFJPEGaddrig
 * Purpose: Write RIG struct for the new JPEG image out to HDF file
 * Inputs:  file_id: HDF file pointer
 *          ref: ref to write RIG with
 * Returns: 0 on success, -1 on failure with DFerror set
 * Users:   hopefully only routines in this utility
 * Invokes: DFdistart, DFdiadd, DFdiend, DFputelement
 * Remarks: another really, really, nasty hack brought to you by QAK in the
 *          interest of not decompressing the JPEG image before stuffing it
 *          into the HDF file...
 *---------------------------------------------------------------------------*/

static intn
DFJPEGaddrig(int32 file_id, uint16 ref, uint16 ctag)
{
    uint8  ntstring[4];
    int32  GroupID;
    uint8 *p;

    ntstring[0] = DFNT_VERSION; /* version */
    ntstring[1] = DFNT_UCHAR;   /* type */
    ntstring[2] = 8;            /* width: RIG data is 8-bit chars */
    ntstring[3] = DFNTC_BYTE;   /* class: data are numeric values */
    if (Hputelement(file_id, DFTAG_NT, ref, (uint8 *)ntstring, (int32)4) == FAIL)
        return FAIL;

    p = file_buf;
    INT32ENCODE(p, image_width);  /* width */
    INT32ENCODE(p, image_height); /* height */
    UINT16ENCODE(p, DFTAG_NT);    /* number type */
    UINT16ENCODE(p, ref);
    INT16ENCODE(p, num_components); /* number of components */
    INT16ENCODE(p, 0);              /* interlace scheme */
    UINT16ENCODE(p, ctag);          /* compression type */
    UINT16ENCODE(p, ref);
    if (Hputelement(file_id, DFTAG_ID, ref, file_buf, (int32)(p - file_buf)) == FAIL)
        return FAIL;

    /* prepare to start writing rig */
    /* ### NOTE: the parameter to this call may go away */
    if ((GroupID = DFdisetup(10)) == FAIL)
        return FAIL; /* max 10 tag/refs in set */
    /* add tag/ref to RIG - image description, image and lookup table */
    if (DFdiput(GroupID, DFTAG_ID, ref) == FAIL)
        return FAIL;

    if (DFdiput(GroupID, DFTAG_CI, ref) == FAIL)
        return FAIL;

    /* write out RIG */
    return (DFdiwrite(file_id, GroupID, DFTAG_RIG, ref));
}

static void
usage(void)
{
    printf("USAGE: jpeg2hdf <input JPEG file> <output HDF file>\n");
    printf("    <input JPEG file> : JPEG file containing input image \n");
    printf("    <output HDF file> : HDF file to store the image\n");
    exit(1);
} /* end usage() */

int
main(int argc, char *argv[])
{
    int32  off_image; /* offset of the JPEG image in the JFIF file */
    int32  file_len;  /* total length of the JPEG file */
    FILE  *jfif_file; /* file handle of the JFIF image */
    int32  file_id;   /* HDF file ID of the file to write */
    uint16 wtag;      /* tag number to use for the image */
    uint16 wref;      /* reference number to use for the image */
    uint16 ctag;      /* tag for the compression to do */
    int32  aid;       /* access ID for the JPEG image to stuff */

    if (argc != 3)
        usage();

    if (argv[1][0] == '-' || argv[1][0] == '/') /* check command line */
        usage();

    jfif_file = fopen(argv[1], "rb");
    if (jfif_file == NULL) {
        printf("Error opening JPEG file: %s\n", argv[1]);
        exit(1);
    } /* end if */

    off_image = read_file_header(jfif_file);
    if (off_image == 0 || image_width <= 0 || image_height <= 0 || num_components <= 0) {
        printf("Error reading JPEG file: %s, could not find a JFIF header\n", argv[1]);
        exit(1);
    } /* end if */

    if (!fseek(jfif_file, 0, SEEK_END)) {
        file_len = (int32)ftell(jfif_file);
        fseek(jfif_file, 0, SEEK_SET); /* go back to beginning of JFIF file */
    }                                  /* end if */
    else {
        printf("Error, cannot fseek in %s(?!)\n", argv[1]);
        exit(1);
    } /* end else */

    if ((file_id = Hopen(argv[2], DFACC_RDWR, 0)) != FAIL) {
        wref = Hnewref(file_id);
        if (!wref) {
            printf("Error getting a reference number for HDF file: %s\n", argv[2]);
            Hclose(file_id);
            exit(1);
        }                /* end if */
        wtag = DFTAG_CI; /* yes, this is a compressed image */
        if (num_components == 1)
            ctag = DFTAG_GREYJPEG5;
        else if (num_components == 3)
            ctag = DFTAG_JPEG5;
        else {
            printf("Error, cannot support JPEG file containing %d components\n", num_components);
            Hclose(file_id);
            exit(1);
        } /* end else */
        if ((aid = Hstartwrite(file_id, ctag, wref, 0)) == FAIL) {
            printf("Error writing JPEG header to HDF file: %s\n", argv[2]);
            exit(1);
        } /* end if */
        Hendaccess(aid);
        if ((aid = Hstartwrite(file_id, wtag, wref, file_len)) == FAIL) {
            printf("Error from Hstartwrite() for JPEG image data\n");
            exit(1);
        } /* end if */
        while (file_len > MAX_FILE_BUF) {
            if (fread(file_buf, sizeof(uint8), MAX_FILE_BUF, jfif_file) != MAX_FILE_BUF) {
                printf("Error reading JFIF image data from %s\n", argv[1]);
                exit(1);
            } /* end if */
            if (Hwrite(aid, MAX_FILE_BUF, file_buf) != (int32)(MAX_FILE_BUF)) {
                printf("Error writing JPEG image data to HDF file\n");
                exit(1);
            } /* end if */
            file_len -= MAX_FILE_BUF;
        } /* end while */
        if (file_len > 0) {
            if (fread(file_buf, sizeof(uint8), (size_t)file_len, jfif_file) != (size_t)file_len) {
                printf("Error reading JFIF image data from %s\n", argv[1]);
                exit(1);
            } /* end if */
            if (Hwrite(aid, file_len, file_buf) != (int32)(file_len)) {
                printf("Error writing last of JPEG image data to HDF file\n");
                exit(1);
            }            /* end if */
        }                /* end if */
        Hendaccess(aid); /* done with JPEG data, create RIG */
        if (DFJPEGaddrig(file_id, wref, ctag) == FAIL) {
            printf("Error writing JPEG RIG information\n");
            exit(1);
        } /* end if */
        Hclose(file_id);
    } /* end if */
    else {
        printf("Error opening HDF file: %s\b", argv[2]);
        exit(1);
    } /* end else */

    return (0);
} /* end jpeg2hdf */