1 /*
2 I recently had a visit from my mom who owns a Sony Mavica camera.
3 This camera produces standard MPEG and JPEG files, but it also
4 creates 64x48 pixel thumbnails for preview/index on its own tiny
5 LCD screen. These files are named with an extension that is
6 ".411".
7
8 Sony appears not to want to document the ".411" file format, but it
9 is clear from various web pages that it is a variant of the
10 CCIR.601 standard YUV encoding used in MPEG. The name indicates
11 that the file content consists of chunks of 6 bytes: 4 bytes of
12 image Y values, followed by 1 bytes of U and one byte of V values
13 that apply to the previous 4 Y pixel values.
14
15 There appear to be some commercial 411 file readers on the net, and
16 there is the Java-based Javica program, but I prefer Open Source
17 command-line utilities. So, I grabbed a copy of netpbm-9.11 from
18 SourceForge and hacked the eyuvtoppm.c file so that it looks like
19 this. While this may not be exactly the right thing to do, it
20 produces results which are close enough for me.
21
22 There are all sorts of user-interface gotchas possible in here that
23 I'm not going to bother changing -- especially not without actual
24 documentation from Sony about what they intend to do with ".411"
25 files in the future. I place my modifications into the public
26 domain, but I ask that my name & e-mail be mentioned in the
27 commentary of any derived version.
28
29 Steve Allen <sla@alumni.caltech.edu>, 2001-03-01
30
31 Bryan Henderson reworked the program to use the Netpbm libraries to
32 create the PPM output and follow some other Netpbm conventions.
33 2001-03-03. Bryan's contribution is public domain.
34 */
35 /*
36 * Copyright (c) 1995 The Regents of the University of California.
37 * All rights reserved.
38 *
39 * Permission to use, copy, modify, and distribute this software and its
40 * documentation for any purpose, without fee, and without written agreement is
41 * hereby granted, provided that the above copyright notice and the following
42 * two paragraphs appear in all copies of this software.
43 *
44 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
45 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
46 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
47 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 *
49 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
50 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
51 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
52 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
53 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */
54
55 /*==============*
56 * HEADER FILES *
57 *==============*/
58 #include <stdio.h>
59
60 #include "pm_c_util.h"
61 #include "mallocvar.h"
62 #include "shhopt.h"
63 #include "ppm.h"
64
65 typedef unsigned char uint8;
66
67 #define CHOP(x) ((x < 0) ? 0 : ((x > 255) ? 255 : x))
68
69 struct CmdlineInfo {
70 /* All the information the user supplied in the command line,
71 in a form easy for the program to use.
72 */
73 const char * inputFileName;
74 int width;
75 int height;
76 };
77
78
79
80 static void
parseCommandLine(int argc,const char ** argv,struct CmdlineInfo * cmdlineP)81 parseCommandLine(int argc, const char ** argv,
82 struct CmdlineInfo *cmdlineP) {
83 /*----------------------------------------------------------------------------
84 Note that the file spec array we return is stored in the storage that
85 was passed to us as the argv array.
86 -----------------------------------------------------------------------------*/
87
88 optEntry * option_def;
89 /* Instructions to OptParseOptions2 on how to parse our options.
90 */
91 optStruct3 opt;
92
93 unsigned int option_def_index;
94
95 MALLOCARRAY_NOFAIL(option_def, 100);
96
97 option_def_index = 0; /* incremented by OPTENT3 */
98 OPTENT3(0, "width", OPT_INT, &cmdlineP->width, NULL, 0);
99 OPTENT3(0, "height", OPT_INT, &cmdlineP->height, NULL, 0);
100
101 /* Set the defaults */
102 cmdlineP->width = 64;
103 cmdlineP->height = 48;
104
105 opt.opt_table = option_def;
106 opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */
107 opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */
108
109 pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
110 /* Uses and sets argc, argv, and some of *cmdlineP and others. */
111
112 if (cmdlineP->width <= 0)
113 pm_error("-width must be positive.");
114 if (cmdlineP->width %4 != 0)
115 pm_error("-width must be a multiple of 4.");
116 if (cmdlineP->height <= 0)
117 pm_error("-height must be positive.");
118
119 if (argc > 2)
120 pm_error("There is at most 1 argument: the input file spec. "
121 "You supplied %d", argc-1);
122 else {
123 if (argc > 1)
124 cmdlineP->inputFileName = argv[1];
125 else
126 cmdlineP->inputFileName = "-";
127 }
128 free(option_def);
129 }
130
131
132
133 static void
ReadYUV(FILE * const ifP,uint8 * const inbuff)134 ReadYUV(FILE * const ifP,
135 uint8 * const inbuff) {
136
137 size_t bytesRead;
138
139 bytesRead = fread(inbuff, 1, 6, ifP);
140
141 if (bytesRead != 6 ) {
142 if (feof(ifP))
143 pm_error("Premature end of input.");
144 else
145 pm_error("Error reading input.");
146 }
147 }
148
149
150
151 static void
YUVtoPPM(FILE * const ifP,int const width,int const height,pixel * const pixrow)152 YUVtoPPM(FILE * const ifP,
153 int const width,
154 int const height,
155 pixel * const pixrow ) {
156
157 unsigned int col;
158
159 for (col = 0; col < width; ++col) {
160
161 uint8 inbuff[6];
162
163 uint8 * const origY = &inbuff[0];
164 uint8 * const origCb = &inbuff[4];
165 uint8 * const origCr = &inbuff[5];
166 int y, u, v;
167 int32_t tempR, tempG, tempB;
168 pixval r, g, b;
169
170 if (col % 4 == 0) {
171 ReadYUV(ifP, inbuff);
172 u = origCb[0] - 128;
173 v = origCr[0] - 128;
174 }
175
176 y = origY[col % 4] - 16;
177
178 tempR = 104635 * v + y * 76310;
179 tempG = -25690 * u + -53294 * v + y * 76310;
180 tempB = 132278 * u + y * 76310;
181
182 r = CHOP((int)(tempR >> 16));
183 g = CHOP((int)(tempG >> 16));
184 b = CHOP((int)(tempB >> 16));
185
186 PPM_ASSIGN(pixrow[col], r, g, b);
187 }
188 }
189
190
191
192 int
main(int argc,const char ** argv)193 main(int argc, const char **argv) {
194
195 pixval const maxval = 255;
196 struct CmdlineInfo cmdline;
197 FILE * ifP;
198 pixel * pixrow;
199 unsigned int row;
200
201 pm_proginit(&argc, argv);
202
203 parseCommandLine(argc, argv, &cmdline);
204
205 pixrow = ppm_allocrow(cmdline.width);
206
207 pm_message("Reading (%ux%u): '%s'", cmdline.width, cmdline.height,
208 cmdline.inputFileName);
209
210 ifP = pm_openr(cmdline.inputFileName);
211
212 ppm_writeppminit(stdout, cmdline.width, cmdline.height, maxval, 0);
213
214 for (row = 0; row < cmdline.height; ++row) {
215 YUVtoPPM(ifP, cmdline.width, cmdline.height, pixrow);
216 ppm_writeppmrow(stdout, pixrow, cmdline.width, maxval, 0);
217 }
218
219 if (fgetc(ifP) != EOF)
220 pm_message("Extraneous data at end of image.");
221
222 pm_close(ifP);
223 ppm_freerow(pixrow);
224
225 return 0;
226 }
227
228 /*
229 By default a .411 file is width=64, height=48, 4608 bytes.
230 There is no header.
231 */
232