1 /* libppm2.c - ppm utility library part 2
2 **
3 ** Copyright (C) 1989 by Jef Poskanzer.
4 **
5 ** Permission to use, copy, modify, and distribute this software and its
6 ** documentation for any purpose and without fee is hereby granted, provided
7 ** that the above copyright notice appear in all copies and that both that
8 ** copyright notice and this permission notice appear in supporting
9 ** documentation. This software is provided "as is" without express or
10 ** implied warranty.
11 */
12
13 #include <string.h>
14 #include <errno.h>
15
16
17 #include "netpbm/pm_c_util.h"
18 #include "netpbm/mallocvar.h"
19 #include "ppm.h"
20
21 void
ppm_writeppminit(FILE * const fileP,int const cols,int const rows,pixval const maxval,int const forceplain)22 ppm_writeppminit(FILE* const fileP,
23 int const cols,
24 int const rows,
25 pixval const maxval,
26 int const forceplain) {
27
28 bool const plainFormat = forceplain || pm_plain_output;
29
30 if (maxval > PPM_OVERALLMAXVAL && !plainFormat)
31 pm_error("too-large maxval passed to ppm_writeppminit(): %d."
32 "Maximum allowed by the PPM format is %d.",
33 maxval, PPM_OVERALLMAXVAL);
34
35 fprintf(fileP, "%c%c\n%d %d\n%d\n",
36 PPM_MAGIC1,
37 plainFormat || maxval >= 1<<16 ? PPM_MAGIC2 : RPPM_MAGIC2,
38 cols, rows, maxval );
39 }
40
41
42
43 static void
putus(unsigned short const n,FILE * const fileP)44 putus(unsigned short const n,
45 FILE * const fileP) {
46
47 if (n >= 10)
48 putus(n / 10, fileP);
49 putc('0' + n % 10, fileP);
50 }
51
52
53
54 static void
format1bpsRow(const pixel * const pixelrow,unsigned int const cols,unsigned char * const rowBuffer)55 format1bpsRow(const pixel * const pixelrow,
56 unsigned int const cols,
57 unsigned char * const rowBuffer) {
58
59 /* single byte samples. */
60
61 unsigned int col;
62 unsigned int bufferCursor;
63
64 bufferCursor = 0;
65
66 for (col = 0; col < cols; ++col) {
67 rowBuffer[bufferCursor++] = PPM_GETR(pixelrow[col]);
68 rowBuffer[bufferCursor++] = PPM_GETG(pixelrow[col]);
69 rowBuffer[bufferCursor++] = PPM_GETB(pixelrow[col]);
70 }
71 }
72
73
74
75
76 static void
format2bpsRow(const pixel * const pixelrow,unsigned int const cols,unsigned char * const rowBuffer)77 format2bpsRow(const pixel * const pixelrow,
78 unsigned int const cols,
79 unsigned char * const rowBuffer) {
80
81 /* two byte samples. */
82
83 unsigned int col;
84 unsigned int bufferCursor;
85
86 bufferCursor = 0;
87
88 for (col = 0; col < cols; ++col) {
89 pixval const r = PPM_GETR(pixelrow[col]);
90 pixval const g = PPM_GETG(pixelrow[col]);
91 pixval const b = PPM_GETB(pixelrow[col]);
92
93 rowBuffer[bufferCursor++] = r >> 8;
94 rowBuffer[bufferCursor++] = (unsigned char)r;
95 rowBuffer[bufferCursor++] = g >> 8;
96 rowBuffer[bufferCursor++] = (unsigned char)g;
97 rowBuffer[bufferCursor++] = b >> 8;
98 rowBuffer[bufferCursor++] = (unsigned char)b;
99 }
100 }
101
102
103
104 static void
ppm_writeppmrowraw(FILE * const fileP,const pixel * const pixelrow,unsigned int const cols,pixval const maxval)105 ppm_writeppmrowraw(FILE * const fileP,
106 const pixel * const pixelrow,
107 unsigned int const cols,
108 pixval const maxval ) {
109
110 unsigned int const bytesPerSample = maxval < 256 ? 1 : 2;
111 unsigned int const bytesPerRow = cols * 3 * bytesPerSample;
112
113 unsigned char * rowBuffer;
114 ssize_t rc;
115
116 MALLOCARRAY(rowBuffer, bytesPerRow);
117
118 if (rowBuffer == NULL)
119 pm_error("Unable to allocate memory for row buffer "
120 "for %u columns", cols);
121
122 if (maxval < 256)
123 format1bpsRow(pixelrow, cols, rowBuffer);
124 else
125 format2bpsRow(pixelrow, cols, rowBuffer);
126
127 rc = fwrite(rowBuffer, 1, bytesPerRow, fileP);
128
129 if (rc < 0)
130 pm_error("Error writing row. fwrite() errno=%d (%s)",
131 errno, strerror(errno));
132 else {
133 size_t const bytesWritten = rc;
134
135 if (bytesWritten != bytesPerRow)
136 pm_error("Error writing row. Short write of %u bytes "
137 "instead of %u", (unsigned)bytesWritten, bytesPerRow);
138 }
139 free(rowBuffer);
140 }
141
142
143
144
145 static void
ppm_writeppmrowplain(FILE * const fileP,const pixel * const pixelrow,unsigned int const cols,pixval const maxval)146 ppm_writeppmrowplain(FILE * const fileP,
147 const pixel * const pixelrow,
148 unsigned int const cols,
149 pixval const maxval) {
150
151 unsigned int col;
152 unsigned int charcount;
153
154 charcount = 0;
155
156 for (col = 0; col < cols; ++col) {
157 if (charcount >= 65) {
158 putc('\n', fileP);
159 charcount = 0;
160 } else if (charcount > 0) {
161 putc(' ', fileP);
162 putc(' ', fileP);
163 charcount += 2;
164 }
165 putus(PPM_GETR(pixelrow[col]), fileP);
166 putc(' ', fileP);
167 putus(PPM_GETG(pixelrow[col]), fileP);
168 putc(' ', fileP);
169 putus(PPM_GETB(pixelrow[col]), fileP);
170 charcount += 11;
171 }
172 if (charcount > 0)
173 putc('\n', fileP);
174 }
175
176
177
178 void
ppm_writeppmrow(FILE * const fileP,const pixel * const pixelrow,int const cols,pixval const maxval,int const forceplain)179 ppm_writeppmrow(FILE * const fileP,
180 const pixel * const pixelrow,
181 int const cols,
182 pixval const maxval,
183 int const forceplain) {
184
185 if (forceplain || pm_plain_output || maxval >= 1<<16)
186 ppm_writeppmrowplain(fileP, pixelrow, cols, maxval);
187 else
188 ppm_writeppmrowraw(fileP, pixelrow, cols, maxval);
189 }
190
191
192
193 void
ppm_writeppm(FILE * const file,pixel ** const pixels,int const cols,int const rows,pixval const maxval,int const forceplain)194 ppm_writeppm(FILE * const file,
195 pixel** const pixels,
196 int const cols,
197 int const rows,
198 pixval const maxval,
199 int const forceplain) {
200 int row;
201
202 ppm_writeppminit(file, cols, rows, maxval, forceplain);
203
204 for (row = 0; row < rows; ++row)
205 ppm_writeppmrow(file, pixels[row], cols, maxval, forceplain);
206 }
207