1 /* ----------------------------------------------------------------------
2 *
3 * Convert a Netpbm file to the GNU Octave image format
4 * by Scott Pakin <scott+pbm@pakin.org>
5 *
6 * ----------------------------------------------------------------------
7 *
8 * Copyright information is at end of file.
9 * ----------------------------------------------------------------------
10 */
11
12 #include <assert.h>
13 #include <stdio.h>
14
15 #include "pm_c_util.h"
16 #include "mallocvar.h"
17 #include "nstring.h"
18 #include "pam.h"
19 #include "pammap.h"
20
21 typedef struct {
22 double comp[3];
23 /* comp[0] is red; comp[1] is green; comp[2] is blue */
24 } octaveColor;
25
26 typedef struct {
27 struct pam pam;
28 unsigned int nColors;
29 tuplehash hash;
30 unsigned int paletteAlloc;
31 /* 'palette' array has this many slots allocated. Only the first
32 'nColors' are meaningful.
33 */
34 octaveColor * palette;
35 double normalizer;
36 /* 1/maxval */
37 } cmap;
38
39
40
41 static void
initCmap(cmap * const cmapP,sample const maxval)42 initCmap(cmap * const cmapP,
43 sample const maxval) {
44
45 cmapP->pam.size = sizeof(cmapP->pam.size);
46 cmapP->pam.len = PAM_STRUCT_SIZE(tuple_type);
47 cmapP->pam.depth = 3;
48 cmapP->pam.maxval = maxval;
49 cmapP->pam.bytes_per_sample = pnm_bytespersample(maxval);
50
51 cmapP->normalizer = 1.0/maxval;
52 cmapP->nColors = 0;
53 cmapP->paletteAlloc = 0;
54 cmapP->palette = NULL;
55 cmapP->hash = pnm_createtuplehash();
56 }
57
58
59
60 static void
termCmap(cmap * const cmapP)61 termCmap(cmap * const cmapP) {
62 pnm_destroytuplehash(cmapP->hash);
63
64 free(cmapP->palette);
65 }
66
67
68
69 static void
findOrAddColor(tuple const color,cmap * const cmapP,unsigned int * const colorIndexP)70 findOrAddColor(tuple const color,
71 cmap * const cmapP,
72 unsigned int * const colorIndexP) {
73 /*----------------------------------------------------------------------------
74 Return as *colorIndexP the colormap index of color 'color' in
75 colormap *cmapP. If the color isn't in the map, give it a new
76 colormap index, put it in the colormap, and return that.
77 -----------------------------------------------------------------------------*/
78 int found;
79 int colorIndex;
80
81 pnm_lookuptuple(&cmapP->pam, cmapP->hash, color, &found, &colorIndex);
82
83 if (!found) {
84 int fits;
85 unsigned int plane;
86
87 colorIndex = cmapP->nColors++;
88
89 if (cmapP->nColors > cmapP->paletteAlloc) {
90 cmapP->paletteAlloc *= 2;
91 REALLOCARRAY(cmapP->palette, cmapP->nColors);
92 }
93 for (plane = 0; plane < 3; ++plane)
94 cmapP->palette[colorIndex].comp[plane] =
95 color[plane] * cmapP->normalizer;
96
97 pnm_addtotuplehash(&cmapP->pam, cmapP->hash, color, colorIndex, &fits);
98
99 if (!fits)
100 pm_error("Out of memory constructing color map, on %uth color",
101 cmapP->nColors);
102 }
103 *colorIndexP = colorIndex;
104 }
105
106
107
108 static void
outputColormap(FILE * const ofP,cmap const cmap)109 outputColormap(FILE * const ofP,
110 cmap const cmap) {
111 /*----------------------------------------------------------------------------
112 Output the colormap as a GNU Octave matrix.
113 -----------------------------------------------------------------------------*/
114 unsigned int colorIndex;
115
116 fprintf(ofP, "# name: map\n");
117 fprintf(ofP, "# type: matrix\n");
118 fprintf(ofP, "# rows: %u\n", cmap.nColors);
119 fprintf(ofP, "# columns: 3\n");
120
121 for (colorIndex = 0; colorIndex < cmap.nColors; ++colorIndex) {
122 unsigned int plane;
123
124 assert(cmap.pam.depth == 3);
125
126 for (plane = 0; plane < 3; ++plane)
127 fprintf(ofP, " %.10f", cmap.palette[colorIndex].comp[plane]);
128
129 fprintf(ofP, "\n");
130 }
131 }
132
133
134
135 static void
convertToOctave(FILE * const ifP,FILE * const ofP)136 convertToOctave(FILE * const ifP,
137 FILE * const ofP) {
138
139 struct pam inpam;
140 tuple * inRow;
141 unsigned int row;
142 cmap cmap;
143
144 pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(allocation_depth));
145
146 pnm_setminallocationdepth(&inpam, 3);
147
148 /* Output the image as a GNU Octave matrix. For each row of the
149 * input file we immediately output indexes into the colormap then,
150 * when we're finished, we output the colormap as a second
151 * matrix. */
152 fprintf(ofP, "# name: img\n");
153 fprintf(ofP, "# type: matrix\n");
154 fprintf(ofP, "# rows: %u\n", inpam.height);
155 fprintf(ofP, "# columns: %u\n", inpam.width);
156
157 initCmap(&cmap, inpam.maxval);
158
159 inRow = pnm_allocpamrow(&inpam);
160 for (row = 0; row < inpam.height; ++row) {
161 unsigned int col;
162 pnm_readpamrow(&inpam, inRow);
163
164 pnm_makerowrgb(&inpam, inRow);
165
166 for (col = 0; col < inpam.width; ++col) {
167 unsigned int colorIndex;
168 findOrAddColor(inRow[col], &cmap, &colorIndex);
169 fprintf(ofP, " %u", colorIndex + 1);
170 }
171 fprintf(ofP, "\n");
172 }
173 pm_message("%u colors in palette", cmap.nColors);
174
175 pnm_freepamrow(inRow);
176 outputColormap(ofP, cmap);
177
178 termCmap(&cmap);
179 }
180
181
182
183 int
main(int argc,char * argv[])184 main(int argc, char *argv[]) {
185
186 FILE * ifP;
187 const char * inputName;
188
189 pnm_init(&argc, argv);
190
191 inputName = argc-1 > 0 ? argv[1] : "-";
192
193 ifP = pm_openr(inputName);
194
195 if (streq(inputName, "-"))
196 fprintf(stdout, "# Created by pamtooctave\n");
197 else
198 fprintf(stdout, "# Created from '%s' by pamtooctave\n", inputName);
199
200 convertToOctave(ifP, stdout);
201
202 pm_close(ifP);
203
204 return 0;
205 }
206
207
208
209 /*
210 * Copyright (C) 2007 Scott Pakin <scott+pbm@pakin.org>
211 *
212 * All rights reserved.
213 *
214 * Redistribution and use in source and binary forms, with or without
215 * modification, are permitted provided that the following conditions
216 * are met:
217 *
218 * 1. Redistributions of source code must retain the above copyright
219 * notice, this list of conditions and the following disclaimer.
220 * 2. Redistributions in binary form must reproduce the above
221 * copyright notice, this list of conditions and the following
222 * disclaimer in the documentation and/or other materials provided
223 * with the distribution.
224 * 3. The name of the author may not be used to endorse or promote
225 * products derived from this software without specific prior written
226 * permission.
227 *
228 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
229 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
230 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
232 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
233 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
234 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
235 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
236 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
237 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
238 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
239 *
240 * ----------------------------------------------------------------------
241 */
242