wrlib: Improved NETPBM support
[wmaker-crm.git] / wrlib / load_ppm.c
blob8d1ab72b88c1ae793bae5ab95bdecc33c57d27e5
1 /* ppm.c - load PPM image from file
3 * Raster graphics library
5 * Copyright (c) 1997-2003 Alfredo K. Kojima
6 * Copyright (c) 2014 Window Maker Team
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
21 * MA 02110-1301, USA.
24 #include <config.h>
26 #include <X11/Xlib.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <limits.h>
32 #include "wraster.h"
33 #include "imgformat.h"
36 * fileio.c - routines to read elements based on Netpbm
38 * Copyright (C) 1988 by Jef Poskanzer.
40 * Permission to use, copy, modify, and distribute this software and its
41 * documentation for any purpose and without fee is hereby granted, provided
42 * that the above copyright notice appear in all copies and that both that
43 * copyright notice and this permission notice appear in supporting
44 * documentation. This software is provided "as is" without express or
45 * implied warranty.
48 char pm_getc(FILE * const fileP)
50 int ich;
51 char ch;
53 ich = getc(fileP);
54 if (ich == EOF)
55 fprintf(stderr, "EOF / read error reading a byte\n");
56 ch = (char)ich;
58 if (ch == '#') {
59 do {
60 ich = getc(fileP);
61 if (ich == EOF)
62 fprintf(stderr, "EOF / read error reading a byte\n");
63 ch = (char)ich;
64 } while (ch != '\n' && ch != '\r');
66 return ch;
69 unsigned char pm_getrawbyte(FILE * const file)
71 int iby;
73 iby = getc(file);
74 if (iby == EOF)
75 fprintf(stderr, "EOF / read error reading a one-byte sample\n");
76 return (unsigned char)iby;
79 int pm_getuint(FILE * const ifP)
81 char ch;
82 unsigned int i;
84 do {
85 ch = pm_getc(ifP);
86 } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
88 if (ch < '0' || ch > '9')
89 fprintf(stderr, "junk in file where an unsigned integer should be\n");
91 i = 0;
92 do {
93 unsigned int const digitVal = ch - '0';
95 if (i > INT_MAX / 10) {
96 fprintf(stderr, "ASCII decimal integer in file is too large to be processed\n");
97 return -1;
100 i *= 10;
102 if (i > INT_MAX - digitVal) {
103 fprintf(stderr, "ASCII decimal integer in file is too large to be processed\n");
104 return -1;
107 i += digitVal;
109 ch = pm_getc(ifP);
110 } while (ch >= '0' && ch <= '9');
112 return i;
114 /* end of fileio.c re-used code */
115 /******************************************************************************************/
117 /* PGM: support for portable graymap ascii and binary encoding */
118 static RImage *load_graymap(FILE * file, int w, int h, int max, int raw)
120 RImage *image;
121 unsigned char *ptr;
122 int x, y;
124 if (raw != '2' && raw != '5') {
125 RErrorCode = RERR_BADFORMAT;
126 return NULL;
129 image = RCreateImage(w, h, 0);
130 if (!image) {
131 RErrorCode = RERR_NOMEMORY;
132 return NULL;
135 if (max < 256) {
136 ptr = image->data;
137 if (raw == '2') {
138 int val;
140 for (y = 0; y < h; y++) {
141 for (x = 0; x < w; x++) {
142 val = pm_getuint(file);
144 if (val > max || val < 0) {
145 RErrorCode = RERR_BADIMAGEFILE;
146 RReleaseImage(image);
147 return NULL;
150 val = val * 255 / max;
151 *(ptr++) = val;
152 *(ptr++) = val;
153 *(ptr++) = val;
156 } else {
157 if (raw == '5') {
158 char *buf;
160 buf = malloc(w + 1);
161 if (!buf) {
162 RErrorCode = RERR_NOMEMORY;
163 RReleaseImage(image);
164 return NULL;
166 for (y = 0; y < h; y++) {
167 if (!fread(buf, w, 1, file)) {
168 free(buf);
169 RErrorCode = RERR_BADIMAGEFILE;
170 RReleaseImage(image);
171 return NULL;
174 for (x = 0; x < w; x++) {
175 *(ptr++) = buf[x];
176 *(ptr++) = buf[x];
177 *(ptr++) = buf[x];
180 free(buf);
184 return image;
187 /* PPM: support for portable pixmap ascii and binary encoding */
188 static RImage *load_pixmap(FILE * file, int w, int h, int max, int raw)
190 RImage *image;
191 int i;
192 unsigned char *ptr;
194 if (raw != '3' && raw != '6') {
195 RErrorCode = RERR_BADFORMAT;
196 return NULL;
199 image = RCreateImage(w, h, 0);
200 if (!image) {
201 RErrorCode = RERR_NOMEMORY;
202 return NULL;
205 ptr = image->data;
206 if (max < 256) {
207 if (raw == '3') {
208 int x, y, val;
210 for (y = 0; y < h; y++) {
211 for (x = 0; x < w; x++) {
212 for (i = 0; i < 3; i++) {
213 val = pm_getuint(file);
215 if (val > max || val < 0) {
216 RErrorCode = RERR_BADIMAGEFILE;
217 RReleaseImage(image);
218 return NULL;
221 val = val * 255 / max;
222 *(ptr++) = val;
226 } else if (raw == '6') {
227 char buf[3];
229 i = 0;
230 while (i < w * h) {
231 if (fread(buf, 1, 3, file) != 3) {
232 RErrorCode = RERR_BADIMAGEFILE;
233 RReleaseImage(image);
234 return NULL;
237 *(ptr++) = buf[0];
238 *(ptr++) = buf[1];
239 *(ptr++) = buf[2];
240 i++;
244 return image;
247 /* PBM: support for portable bitmap ascii and binary encoding */
248 static RImage *load_bitmap(FILE * file, int w, int h, int max, int raw)
250 RImage *image;
251 int val;
252 unsigned char *ptr;
254 if (raw != '1' && raw != '4') {
255 RErrorCode = RERR_BADFORMAT;
256 return NULL;
259 image = RCreateImage(w, h, 0);
260 if (!image) {
261 RErrorCode = RERR_NOMEMORY;
262 return NULL;
265 ptr = image->data;
266 if (raw == '1') {
267 int i = 0;
269 while (i < w * h) {
270 val = pm_getuint(file);
272 if (val > max || val < 0) {
273 RErrorCode = RERR_BADIMAGEFILE;
274 RReleaseImage(image);
275 return NULL;
278 val = (val == 0) ? 255 : 0;
279 *(ptr++) = val;
280 *(ptr++) = val;
281 *(ptr++) = val;
282 i++;
284 } else {
285 if (raw == '4') {
286 unsigned char buf;
287 int bitshift;
288 int x, y;
290 for (y = 0; y < h; y++) {
291 bitshift = -1;
292 for (x = 0; x < w; x++) {
293 if (bitshift == -1) {
294 buf = pm_getrawbyte(file);
295 bitshift = 7;
297 val = (buf >> bitshift) & 1;
298 val = (val == 0) ? 255 : 0;
299 --bitshift;
300 *(ptr++) = val;
301 *(ptr++) = val;
302 *(ptr++) = val;
307 return image;
310 RImage *RLoadPPM(const char *file_name)
312 FILE *file;
313 RImage *image = NULL;
314 char buffer[256];
315 int w, h, m;
316 int type;
318 file = fopen(file_name, "rb");
319 if (!file) {
320 RErrorCode = RERR_OPEN;
321 return NULL;
324 /* get signature */
325 if (!fgets(buffer, 255, file)) {
326 RErrorCode = RERR_BADIMAGEFILE;
327 fclose(file);
328 return NULL;
331 /* accept bitmaps, pixmaps or graymaps */
332 if (buffer[0] != 'P' || (buffer[1] < '1' || buffer[1] > '6')) {
333 RErrorCode = RERR_BADFORMAT;
334 fclose(file);
335 return NULL;
338 type = buffer[1];
340 /* skip comments */
341 while (1) {
342 if (!fgets(buffer, 255, file)) {
343 RErrorCode = RERR_BADIMAGEFILE;
344 fclose(file);
345 return NULL;
348 if (buffer[0] != '#')
349 break;
352 /* get size */
353 if (sscanf(buffer, "%i %i", &w, &h) != 2 || w < 1 || h < 1) {
354 /* Short file */
355 RErrorCode = RERR_BADIMAGEFILE;
356 fclose(file);
357 return NULL;
360 if (type != '1' && type != '4') {
361 if (!fgets(buffer, 255, file)) {
362 RErrorCode = RERR_BADIMAGEFILE;
363 fclose(file);
364 return NULL;
366 /* get max value */
367 if (sscanf(buffer, "%i", &m) != 1 || m < 1) {
368 /* Short file */
369 RErrorCode = RERR_BADIMAGEFILE;
370 fclose(file);
371 return NULL;
373 } else {
374 m = 1;
377 if (type == '1' || type == '4') {
378 /* Portable Bit Map: P1 is for 'plain' (ascii, rare), P4 for 'regular' (binary) */
379 image = load_bitmap(file, w, h, m, type);
380 } else if (type == '2' || type == '5') {
381 /* Portable Gray Map: P2 is for 'plain' (ascii, rare), P5 for 'regular' (binary) */
382 image = load_graymap(file, w, h, m, type);
383 } else if (type == '3' || type == '6') {
384 /* Portable Pix Map: P3 is for 'plain' (ascii, rare), P6 for 'regular' (binary) */
385 image = load_pixmap(file, w, h, m, type);
388 fclose(file);
389 return image;