1 /*
2  * Convert a SRF (Garmin vehicle) to a PAM image
3  *
4  * Copyright (C) 2011 by Mike Frysinger <vapier@gentoo.org>
5  *
6  * Permission to use, copy, modify, and distribute this software and its
7  * documentation for any purpose and without fee is hereby granted, provided
8  * that the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation.  This software is provided "as is" without express or
11  * implied warranty.
12  */
13 
14 #include <assert.h>
15 #include <stdio.h>
16 
17 #include "pm_c_util.h"
18 #include "shhopt.h"
19 #include "mallocvar.h"
20 #include "nstring.h"
21 #include "pam.h"
22 #include "srf.h"
23 
24 struct cmdlineInfo {
25   /* All the information the user supplied in the command line,
26      in a form easy for the program to use.
27   */
28   const char *  inputFileName;  /* '-' if stdin */
29   unsigned int  verbose;
30 };
31 
32 static bool verbose;
33 
34 
35 
36 static void
parseCommandLine(int argc,const char ** argv,struct cmdlineInfo * const cmdlineP)37 parseCommandLine(int argc, const char ** argv,
38                  struct cmdlineInfo * const cmdlineP) {
39 /*----------------------------------------------------------------------------
40    parse program command line described in Unix standard form by argc
41    and argv.  Return the information in the options as *cmdlineP.
42 
43    If command line is internally inconsistent (invalid options, etc.),
44    issue error message to stderr and abort program.
45 
46    Note that the strings we return are stored in the storage that
47    was passed to us as the argv array.  We also trash *argv.
48 -----------------------------------------------------------------------------*/
49     optEntry *option_def;
50     /* Instructions to pm_optParseOptions3 on how to parse our options.
51      */
52     optStruct3 opt;
53 
54     unsigned int option_def_index;
55 
56     MALLOCARRAY_NOFAIL(option_def, 100);
57 
58     option_def_index = 0;   /* incremented by OPTENT3 */
59     OPTENT3(0, "verbose",          OPT_FLAG,      NULL,
60             &cmdlineP->verbose,    0);
61 
62     opt.opt_table = option_def;
63     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
64     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
65 
66     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
67     /* Uses and sets argc, argv, and some of *cmdlineP and others. */
68 
69     if (argc-1 < 1)
70         cmdlineP->inputFileName = "-";
71     else if (argc-1 == 1)
72         cmdlineP->inputFileName = argv[1];
73     else
74         pm_error("Program takes at most one argument:  input file name");
75 }
76 
77 
78 
79 static unsigned int
srfRed(uint16_t const pixel)80 srfRed(uint16_t const pixel) {
81     return ((pixel >> 11) & 0x1f) << 3;
82 }
83 
84 
85 static unsigned int
srfGrn(uint16_t const pixel)86 srfGrn(uint16_t const pixel) {
87     return ((pixel >>  6) & 0x1f) << 3;
88 }
89 
90 
91 static unsigned int
srfBlu(uint16_t const pixel)92 srfBlu(uint16_t const pixel) {
93     return ((pixel >>  0) & 0x1f) << 3;
94 }
95 
96 
97 static uint8_t
srfAlpha(uint8_t const d)98 srfAlpha(uint8_t const d) {
99 
100     uint8_t retval;
101 
102     if (d == SRF_ALPHA_OPAQUE)
103         retval = 0xff;
104     else
105         retval = (128 - d) << 1;
106 
107     return retval;
108 }
109 
110 
111 
112 static void
writeRaster(struct pam * const pamP,struct srf_img * const imgP)113 writeRaster(struct pam *     const pamP,
114             struct srf_img * const imgP) {
115 
116     tuple *  tuplerow;
117     unsigned int row;
118 
119     assert(imgP->header.width <= pamP->width);
120 
121     tuplerow = pnm_allocpamrow(pamP);
122 
123     for (row = 0; row < imgP->header.height; ++row) {
124         unsigned int const rowStart = row * imgP->header.width;
125 
126         unsigned int col;
127 
128         for (col = 0; col < imgP->header.width; ++col) {
129             uint16_t const data  = imgP->data.data[rowStart + col];
130             uint16_t const alpha = imgP->alpha.data[rowStart + col];
131 
132             assert(col < pamP->width);
133 
134             tuplerow[col][PAM_RED_PLANE] = srfRed(data);
135             tuplerow[col][PAM_GRN_PLANE] = srfGrn(data);
136             tuplerow[col][PAM_BLU_PLANE] = srfBlu(data);
137             tuplerow[col][PAM_TRN_PLANE] = srfAlpha(alpha);
138         }
139 
140         for (; col < pamP->width; ++col) {
141             tuplerow[col][PAM_RED_PLANE] = 0;
142             tuplerow[col][PAM_GRN_PLANE] = 0;
143             tuplerow[col][PAM_BLU_PLANE] = 0;
144             tuplerow[col][PAM_TRN_PLANE] = 0;
145         }
146 
147         pnm_writepamrow(pamP, tuplerow);
148     }
149     pnm_freepamrow(tuplerow);
150 }
151 
152 
153 
154 static void
convertOneImage(struct srf_img * const imgP,FILE * const ofP)155 convertOneImage(struct srf_img * const imgP,
156                 FILE *           const ofP) {
157 
158     const char * comment = "Produced by srftopam";  /* constant */
159 
160     struct pam   outPam;
161 
162     outPam.size             = sizeof(struct pam);
163     outPam.len              = PAM_STRUCT_SIZE(comment_p);
164     outPam.file             = ofP;
165     outPam.format           = PAM_FORMAT;
166     outPam.plainformat      = 0;
167     outPam.width            = imgP->header.width;
168     outPam.height           = imgP->header.height;
169     outPam.depth            = 4;
170     outPam.maxval           = 255;
171     outPam.bytes_per_sample = 1;
172     sprintf(outPam.tuple_type, "RGB_ALPHA");
173     outPam.allocation_depth = 4;
174     outPam.comment_p        = &comment;
175 
176     pnm_writepaminit(&outPam);
177 
178     writeRaster(&outPam, imgP);
179 }
180 
181 
182 
183 static void
srftopam(struct cmdlineInfo const cmdline,FILE * const ifP,FILE * const ofP)184 srftopam(struct cmdlineInfo const cmdline,
185          FILE *             const ifP,
186          FILE *             const ofP) {
187 
188     unsigned int imgSeq;
189     struct srf   srf;
190 
191     srf_read(ifP, verbose, &srf);
192 
193     for (imgSeq = 0; imgSeq < srf.header.img_cnt; ++imgSeq) {
194         if (verbose)
195             pm_message("Converting Image %u", imgSeq);
196         convertOneImage(&srf.imgs[imgSeq], ofP);
197     }
198 
199     srf_term(&srf);
200 }
201 
202 
203 
204 int
main(int argc,const char * argv[])205 main(int argc, const char * argv[]) {
206 
207     struct cmdlineInfo cmdline;
208     FILE *             ifP;
209 
210     pm_proginit(&argc, argv);
211 
212     parseCommandLine(argc, argv, &cmdline);
213 
214     verbose = cmdline.verbose;
215 
216     ifP = pm_openr(cmdline.inputFileName);
217 
218     srftopam(cmdline, ifP, stdout);
219 
220     pm_closer(ifP);
221 
222     return 0;
223 }
224 
225 
226 
227