demos: c_simple: blittest: Add check.
[gfxprim.git] / libs / loaders / GP_PGM.c
blob4a2321da10763955c48f151a025ef307c978be8c
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 Jiri "BlueBear" Dluhos *
20 * <jiri.bluebear.dluhos@gmail.com> *
21 * *
22 * Copyright (C) 2009-2012 Cyril Hrubis <metan@ucw.cz> *
23 * *
24 *****************************************************************************/
28 PGM portable graymap loader/saver.
30 Format:
32 a magick number value of 'P' and '2'
33 whitespace (blanks, TABs, CRs, LFs).
34 ascii width
35 whitespace
36 ascii height
37 whitespace
38 maximal gray value (interval is 0 ... max)
39 width * height ascii gray values
41 lines starting with '#' are comments to the end of line
45 #include <stdio.h>
46 #include <stdint.h>
47 #include <inttypes.h>
48 #include <errno.h>
49 #include <string.h>
50 #include <ctype.h>
52 #include <GP_Debug.h>
54 #include "GP_PXMCommon.h"
55 #include "GP_PGM.h"
57 static void try_read_comments(FILE *f)
59 char c1, c2;
61 while (isspace(c1 = fgetc(f)));
63 ungetc(c1, f);
65 while ((c1 = fgetc(f)) == '#') {
66 do {
67 c2 = fgetc(f);
68 } while (c2 != '\n' && c2 != EOF);
71 ungetc(c1, f);
74 GP_Context *GP_LoadPGM(const char *src_path, GP_ProgressCallback *callback)
76 FILE *f;
77 GP_Context *ret;
78 uint32_t w, h, gray;
79 GP_PixelType type;
80 char h1, h2;
81 int err = EIO;
83 f = fopen(src_path, "r");
85 if (f == NULL) {
86 err = errno;
87 GP_DEBUG(1, "Failed to open file '%s': %s",
88 src_path, strerror(errno));
89 goto err0;
92 h1 = fgetc(f);
93 h2 = fgetc(f);
95 if (feof(f)) {
96 err = EIO;
97 goto err1;
100 if (h1 != 'P' || h2 != '2') {
101 GP_DEBUG(1, "Invalid PGM header '%c%c' (0x%2x 0x%2x)",
102 isprint(h1) ? h1 : ' ', isprint(h2) ? h2 : ' ',
103 h1, h2);
104 err = EINVAL;
105 goto err1;
108 try_read_comments(f);
110 if (fscanf(f, "%"PRIu32, &w) < 1) {
111 err = errno;
112 GP_DEBUG(1, "Failed to read PGM header width");
113 goto err1;
116 try_read_comments(f);
118 if (fscanf(f, "%"PRIu32, &h) < 1) {
119 err = errno;
120 GP_DEBUG(1, "Failed to read PGM header height");
121 goto err1;
124 try_read_comments(f);
126 if (fscanf(f, "%"PRIu32, &gray) < 1) {
127 err = errno;
128 GP_DEBUG(1, "Failed to read PGM header gray");
129 goto err1;
132 switch (gray) {
133 case 1:
134 type = GP_PIXEL_G1;
135 break;
136 case 3:
137 type = GP_PIXEL_G2;
138 break;
139 case 15:
140 type = GP_PIXEL_G4;
141 break;
142 case 255:
143 type = GP_PIXEL_G8;
144 break;
145 default:
146 GP_DEBUG(1, "Invalid number of grays %u", gray);
147 err = EINVAL;
148 goto err1;
151 ret = GP_ContextAlloc(w, h, type);
153 if (ret == NULL) {
154 err = ENOMEM;
155 goto err1;
158 //TODO: errno here
159 switch (gray) {
160 case 1:
161 if (GP_PXMLoad1bpp(f, ret))
162 goto err2;
163 break;
164 case 3:
165 if (GP_PXMLoad2bpp(f, ret))
166 goto err2;
167 break;
168 case 15:
169 if (GP_PXMLoad4bpp(f, ret))
170 goto err2;
171 break;
172 case 255:
173 if (GP_PXMLoad8bpp(f, ret))
174 goto err2;
175 break;
178 fclose(f);
179 return ret;
180 err2:
181 GP_ContextFree(ret);
182 err1:
183 fclose(f);
184 err0:
185 errno = err;
186 return NULL;
189 int GP_SavePGM(const GP_Context *src, const char *res_path,
190 GP_ProgressCallback *callback)
192 FILE *f;
193 uint32_t gray;
194 int err = EIO;
196 switch (src->pixel_type) {
197 case GP_PIXEL_G1:
198 gray = 1;
199 break;
200 case GP_PIXEL_G2:
201 gray = 3;
202 break;
203 case GP_PIXEL_G4:
204 gray = 15;
205 break;
206 case GP_PIXEL_G8:
207 gray = 255;
208 break;
209 default:
210 GP_DEBUG(1, "Invalid pixel type '%s'",
211 GP_PixelTypeName(src->pixel_type));
212 errno = EINVAL;
213 return 1;
216 f = fopen(res_path, "w");
218 if (f == NULL) {
219 err = errno;
220 GP_DEBUG(1, "Failed to open file '%s': %s",
221 res_path, strerror(errno));
222 goto err0;
225 if (fprintf(f, "P2\n%u %u\n%u\n# Generated by gfxprim\n",
226 (unsigned int) src->w, (unsigned int) src->h, gray) < 3)
227 goto err1;
229 //TODO: errno
230 switch (gray) {
231 case 1:
232 if (GP_PXMSave1bpp(f, src))
233 goto err1;
234 break;
235 case 3:
236 if (GP_PXMSave2bpp(f, src))
237 goto err1;
238 break;
239 //TODO
240 case 255:
241 if (GP_PXMSave8bpp(f, src))
242 goto err1;
243 break;
244 default:
245 err = ENOSYS;
246 goto err1;
249 if (fclose(f)) {
250 err = errno;
251 GP_DEBUG(1, "Failed to close file '%s': %s",
252 res_path, strerror(errno));
253 goto err0;
256 return 0;
257 err1:
258 fclose(f);
259 err0:
260 errno = err;
261 return 1;