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