filters: Add generated Nearest Neighbour filter.
[gfxprim.git] / libs / loaders / GP_PNM.c
blob261b75f8471f6d1eb255d2f44a90cc22e20a5493
1 /*****************************************************************************
2 * This file is part of gfxprim library. *
3 * *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
8 * *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
18 * *
19 * Copyright (C) 2009-2010 Cyril Hrubis <metan@ucw.cz> *
20 * *
21 *****************************************************************************/
23 #include <stdint.h>
24 #include <inttypes.h>
26 #include <ctype.h>
27 #include <errno.h>
28 #include <string.h>
30 #include <GP_Debug.h>
32 #include "GP_PNM.h"
36 PNM portable bitmap header
37 --------------------------
39 Format:
41 a magick number value of 'P' and one of
42 '1' - PBM 2bpp gray ASCII
43 '2' - PGM gray ASCII
44 '3' - PPM rgb888 ASCII
45 '4' - PBM 2bpp gray BINARY
46 '5' - PGM gray BINARY
47 '6' - PPM rgb888 BINARY
48 whitespace (blanks, TABs, CRs, LFs).
49 ascii width
50 whitespace
51 ascii height
52 whitespace
53 maximal value (interval is 0 ... max) (not applicable for PBM)
54 width * height ascii or binary values
56 lines starting with '#' are comments to the end of line
60 static void try_read_comments(FILE *f)
62 char c1, c2;
64 while (isspace(c1 = fgetc(f)));
66 ungetc(c1, f);
68 while ((c1 = fgetc(f)) == '#') {
69 do {
70 c2 = fgetc(f);
71 } while (c2 != '\n' && c2 != EOF);
74 ungetc(c1, f);
78 static char *pnm_names[] = {
79 "ASCII encoded PBM",
80 "ASCII encoded PGM",
81 "ASCII encoded PPM",
82 "BINARY encoded PBM",
83 "BINARY encoded PGM",
84 "BINARY encoded PPM",
87 FILE *GP_ReadPNM(const char *src_path, char *fmt,
88 uint32_t *w, uint32_t *h, uint32_t *depth)
90 FILE *f = fopen(src_path, "r");
91 int ch;
93 if (f == NULL) {
94 GP_DEBUG(1, "Failed to open file '%s': %s",
95 src_path, strerror(errno));
96 return NULL;
99 ch = fgetc(f);
101 if (ch != 'P') {
102 GP_DEBUG(1, "Invalid PNM header start '%c' (0x%2x) expecting 'P'",
103 isprint(ch) ? ch : ' ', ch);
104 goto err1;
107 ch = fgetc(f);
109 switch (ch) {
110 case '4':
111 case '1':
112 *depth = 1;
113 break;
114 case '2':
115 case '3':
116 case '5':
117 case '6':
118 break;
119 default:
120 GP_DEBUG(1, "Invalid PNM format 'P%c' (0x%2x)",
121 isprint(ch) ? ch : ' ', ch);
122 goto err1;
125 *fmt = ch;
127 try_read_comments(f);
129 if (fscanf(f, "%"PRIu32"\n", w) < 1) {
130 GP_DEBUG(1, "Failed to read PNM header width");
131 goto err1;
134 try_read_comments(f);
136 if (fscanf(f, "%"PRIu32"\n", h) < 1) {
137 GP_DEBUG(1, "Failed to read PNM header height");
138 goto err1;
141 GP_DEBUG(2, "Have %s size %"PRIu32"x%"PRIu32,
142 pnm_names[*fmt - '1'], *w, *h);
144 if (*fmt == '1' || *fmt == '3')
145 return f;
147 try_read_comments(f);
149 if (fscanf(f, "%"PRIu32"\n", depth) < 1) {
150 GP_DEBUG(1, "Failed to read PNM header depth");
151 goto err1;
154 return f;
155 err1:
156 fclose(f);
157 return NULL;
160 #define GFXPRIM_SIGNATURE "# Generated by gfxprim http://gfxprim.ucw.cz\n"
162 FILE *GP_WritePNM(const char *dst_path, char fmt,
163 uint32_t w, uint32_t h, uint32_t depth)
165 FILE *f = fopen(dst_path, "w");
166 int ret;
168 ret = fprintf(f, "P%c\n"GFXPRIM_SIGNATURE
169 "%"PRIu32" %"PRIu32"\n%"PRIu32"\n",
170 fmt, w, h, depth);
172 if (ret < 0) {
173 GP_DEBUG(1, "Failed to write PNM header '%s' : %s",
174 dst_path, strerror(errno));
175 fclose(f);
176 return NULL;
179 return f;