1 /* Convert an YUY2 image to a PAM image
2 *
3 * See
4 * http://msdn.microsoft.com/en-us/library/aa904813%28VS.80%29.aspx#yuvformats_2
5 * and http://www.digitalpreservation.gov/formats/fdd/fdd000364.shtml for
6 * details.
7 *
8 * By Michael Haardt 2014.
9 *
10 * Contributed to the public domain by its author.
11 *
12 * Recoded in Netpbm style by Bryan Henderson
13 */
14
15 #include <stdio.h>
16 #include <string.h>
17
18 #include "pm_c_util.h"
19 #include "mallocvar.h"
20 #include "pm.h"
21 #include "pam.h"
22 #include "shhopt.h"
23
24
25
26 struct CmdlineInfo {
27 const char * inputFileName;
28 unsigned int width;
29 unsigned int height;
30 };
31
32
33
34 static void
parseCommandLine(int argc,const char ** argv,struct CmdlineInfo * const cmdlineP)35 parseCommandLine(int argc, const char ** argv,
36 struct CmdlineInfo * const cmdlineP) {
37 /* --------------------------------------------------------------------------
38 Parse program command line described in Unix standard form by argc
39 and argv. Return the information in the options as *cmdlineP.
40
41 If command line is internally inconsistent (invalid options, etc.),
42 issue error message to stderr and abort program.
43
44 Note that the strings we return are stored in the storage that
45 was passed to us as the argv array. We also trash *argv.
46 --------------------------------------------------------------------------*/
47 optEntry * option_def;
48 /* Instructions to pm_optParseOptions3 on how to parse our options. */
49 optStruct3 opt;
50
51 unsigned int widthSpec, heightSpec;
52 unsigned int option_def_index;
53
54 MALLOCARRAY_NOFAIL(option_def, 100);
55
56 option_def_index = 0; /* incremented by OPTENT3 */
57 OPTENT3(0, "width", OPT_UINT,
58 &cmdlineP->width, &widthSpec, 0);
59 OPTENT3(0, "height", OPT_UINT,
60 &cmdlineP->height, &heightSpec, 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 (!widthSpec)
70 pm_error("You must specify the image width with -width");
71 if (cmdlineP->width == 0)
72 pm_error("-width cannot be zero");
73
74 if (cmdlineP->width % 2 != 0)
75 pm_error("-width %u is odd, but YUY2 images must have an even width.",
76 cmdlineP->width);
77
78 if (!heightSpec)
79 pm_error("You must specify the image height with -height");
80 if (cmdlineP->height == 0)
81 pm_error("-height cannot be zero");
82
83 if (argc-1 < 1)
84 cmdlineP->inputFileName = "-";
85 else {
86 cmdlineP->inputFileName = argv[1];
87
88 if (argc-1 > 1)
89 pm_error("Too many arguments (%u). The only non-option argument "
90 "is the input file name.", argc-1);
91 }
92 }
93
94
95
96 typedef struct {
97 int y0;
98 int y1;
99 int u;
100 int v;
101 } Yuy2Pixel;
102
103
104
105 static Yuy2Pixel
readPixel(FILE * const ifP)106 readPixel(FILE * const ifP) {
107 /*----------------------------------------------------------------------------
108 Read one pixel from the YUY2 input. YUY2 represents a pixel in 4 bytes.
109 -----------------------------------------------------------------------------*/
110 Yuy2Pixel retval;
111 unsigned char c;
112
113 pm_readcharu(ifP, &c); retval.y0 = c - 16;
114 pm_readcharu(ifP, &c); retval.u = c - 128;
115 pm_readcharu(ifP, &c); retval.y1 = c - 16;
116 pm_readcharu(ifP, &c); retval.v = c - 128;
117
118 return retval;
119 }
120
121
122
123 typedef struct {
124 int a1;
125 int a2;
126 int a3;
127 int a4;
128 } UvCoeff;
129
130 typedef struct {
131 int a0a;
132 int a0b;
133 UvCoeff uv;
134 } Coeff;
135
136
137
138 static Coeff
coeffFromYuy2(Yuy2Pixel const yuy2)139 coeffFromYuy2(Yuy2Pixel const yuy2) {
140
141 Coeff retval;
142
143 retval.a0a = 298 * yuy2.y0;
144 retval.a0b = 298 * yuy2.y1;
145 retval.uv.a1 = 409 * yuy2.v;
146 retval.uv.a2 = 100 * yuy2.u;
147 retval.uv.a3 = 208 * yuy2.v;
148 retval.uv.a4 = 516 * yuy2.u;
149
150 return retval;
151 }
152
153
154
155 typedef struct {
156 int r;
157 int g;
158 int b;
159 } Rgb;
160
161
162
163 static Rgb
rgbFromCoeff(int const a0,UvCoeff const uv)164 rgbFromCoeff(int const a0,
165 UvCoeff const uv) {
166
167 Rgb retval;
168
169 retval.r = (a0 + uv.a1 + 128) >> 8;
170 retval.g = (a0 - uv.a2 - uv.a3 + 128) >> 8;
171 retval.b = (a0 + uv.a4 + 128) >> 8;
172
173 return retval;
174 }
175
176
177
178 static Rgb
rgbFromCoeff0(Coeff const coeff)179 rgbFromCoeff0(Coeff const coeff) {
180
181 return rgbFromCoeff(coeff.a0a, coeff.uv);
182 }
183
184
185
186 static Rgb
rgbFromCoeff1(Coeff const coeff)187 rgbFromCoeff1(Coeff const coeff) {
188
189 return rgbFromCoeff(coeff.a0b, coeff.uv);
190 }
191
192
193
194 static void
rgbToTuple(Rgb const rgb,tuple const out)195 rgbToTuple(Rgb const rgb,
196 tuple const out) {
197
198 out[PAM_RED_PLANE] = MIN(255, MAX(0, rgb.r));
199 out[PAM_GRN_PLANE] = MIN(255, MAX(0, rgb.g));
200 out[PAM_BLU_PLANE] = MIN(255, MAX(0, rgb.b));
201 }
202
203
204
205 static void
yuy2topam(const char * const fileName,unsigned int const width,unsigned int const height)206 yuy2topam(const char * const fileName,
207 unsigned int const width,
208 unsigned int const height) {
209
210 FILE * ifP;
211 struct pam outpam;
212 tuple * tuplerow;
213 unsigned int row;
214
215 outpam.size = sizeof(struct pam);
216 outpam.len = PAM_STRUCT_SIZE(allocation_depth);
217 outpam.file = stdout;
218 outpam.format = PAM_FORMAT;
219 outpam.plainformat = 0;
220 outpam.width = width;
221 outpam.height = height;
222 outpam.depth = 3;
223 outpam.maxval = 255;
224 outpam.bytes_per_sample = 1;
225 strcpy(outpam.tuple_type, PAM_PPM_TUPLETYPE);
226 outpam.allocation_depth = 3;
227
228 ifP = pm_openr(fileName);
229
230 pnm_writepaminit(&outpam);
231
232 tuplerow = pnm_allocpamrow(&outpam);
233
234 for (row = 0; row < outpam.height; ++row) {
235 unsigned int col;
236
237 for (col = 0; col < outpam.width; col += 2) {
238 Yuy2Pixel const yuy2 = readPixel(ifP);
239
240 Coeff const coeff = coeffFromYuy2(yuy2);
241
242 rgbToTuple(rgbFromCoeff0(coeff), tuplerow[col]);
243 rgbToTuple(rgbFromCoeff1(coeff), tuplerow[col+1]);
244 }
245 pnm_writepamrow(&outpam, tuplerow);
246 }
247 pnm_freepamrow(tuplerow);
248
249 pm_closer(ifP);
250 }
251
252
253
254 int
main(int argc,const char * argv[])255 main(int argc, const char *argv[]) {
256
257 struct CmdlineInfo cmdline;
258
259 pm_proginit(&argc, argv);
260
261 parseCommandLine(argc, argv, &cmdline);
262
263 yuy2topam(cmdline.inputFileName, cmdline.width, cmdline.height);
264
265 return 0;
266 }
267