Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / synfig-core / tags / synfig_0_61_05 / synfig-core / src / modules / mod_libavcodec / libavformat / pnm.c
1 /*
2  * PNM image format
3  * Copyright (c) 2002, 2003 Fabrice Bellard.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 #include "avformat.h"
20
21 static inline int pnm_space(int c)  
22 {
23     return (c == ' ' || c == '\n' || c == '\r' || c == '\t');
24 }
25
26 static void pnm_get(ByteIOContext *f, char *str, int buf_size) 
27 {
28     char *s;
29     int c;
30     
31     /* skip spaces and comments */
32     for(;;) {
33         c = url_fgetc(f);
34         if (c == '#')  {
35             do  {
36                 c = url_fgetc(f);
37             } while (c != '\n' && c != URL_EOF);
38         } else if (!pnm_space(c)) {
39             break;
40         }
41     }
42     
43     s = str;
44     while (c != URL_EOF && !pnm_space(c)) {
45         if ((s - str)  < buf_size - 1)
46             *s++ = c;
47         c = url_fgetc(f);
48     }
49     *s = '\0';
50 }
51
52 static int pnm_read1(ByteIOContext *f, 
53                      int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque,
54                      int allow_yuv)
55 {
56     int i, n, linesize, h;
57     char buf1[32];
58     unsigned char *ptr;
59     AVImageInfo info1, *info = &info1;
60     int ret;
61
62     pnm_get(f, buf1, sizeof(buf1));
63     if (!strcmp(buf1, "P4")) {
64         info->pix_fmt = PIX_FMT_MONOWHITE;
65     } else if (!strcmp(buf1, "P5")) {
66         if (allow_yuv) 
67             info->pix_fmt = PIX_FMT_YUV420P;
68         else
69             info->pix_fmt = PIX_FMT_GRAY8;
70     } else if (!strcmp(buf1, "P6")) {
71         info->pix_fmt = PIX_FMT_RGB24;
72     } else {
73         return AVERROR_INVALIDDATA;
74     }
75     pnm_get(f, buf1, sizeof(buf1));
76     info->width = atoi(buf1);
77     if (info->width <= 0)
78         return AVERROR_INVALIDDATA;
79     pnm_get(f, buf1, sizeof(buf1));
80     info->height = atoi(buf1);
81     if (info->height <= 0)
82         return AVERROR_INVALIDDATA;
83     if (info->pix_fmt != PIX_FMT_MONOWHITE) {
84         pnm_get(f, buf1, sizeof(buf1));
85     }
86
87     /* more check if YUV420 */
88     if (info->pix_fmt == PIX_FMT_YUV420P) {
89         if ((info->width & 1) != 0)
90             return AVERROR_INVALIDDATA;
91         h = (info->height * 2);
92         if ((h % 3) != 0)
93             return AVERROR_INVALIDDATA;
94         h /= 3;
95         info->height = h;
96     }
97     
98     ret = alloc_cb(opaque, info);
99     if (ret)
100         return ret;
101     
102     switch(info->pix_fmt) {
103     default:
104         return AVERROR_INVALIDDATA;
105     case PIX_FMT_RGB24:
106         n = info->width * 3;
107         goto do_read;
108     case PIX_FMT_GRAY8:
109         n = info->width;
110         goto do_read;
111     case PIX_FMT_MONOWHITE:
112         n = (info->width + 7) >> 3;
113     do_read:
114         ptr = info->pict.data[0];
115         linesize = info->pict.linesize[0];
116         for(i = 0; i < info->height; i++) {
117             get_buffer(f, ptr, n);
118             ptr += linesize;
119         }
120         break;
121     case PIX_FMT_YUV420P:
122         {
123             unsigned char *ptr1, *ptr2;
124
125             n = info->width;
126             ptr = info->pict.data[0];
127             linesize = info->pict.linesize[0];
128             for(i = 0; i < info->height; i++) {
129                 get_buffer(f, ptr, n);
130                 ptr += linesize;
131             }
132             ptr1 = info->pict.data[1];
133             ptr2 = info->pict.data[2];
134             n >>= 1;
135             h = info->height >> 1;
136             for(i = 0; i < h; i++) {
137                 get_buffer(f, ptr1, n);
138                 get_buffer(f, ptr2, n);
139                 ptr1 += info->pict.linesize[1];
140                 ptr2 += info->pict.linesize[2];
141             }
142         }
143         break;
144     }
145     return 0;
146 }
147
148 static int pnm_read(ByteIOContext *f, 
149                     int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque)
150 {
151     return pnm_read1(f, alloc_cb, opaque, 0);
152 }
153
154 static int pgmyuv_read(ByteIOContext *f, 
155                        int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque)
156 {
157     return pnm_read1(f, alloc_cb, opaque, 1);
158 }
159
160 static int pnm_write(ByteIOContext *pb, AVImageInfo *info)
161 {
162     int i, h, h1, c, n, linesize;
163     char buf[100];
164     uint8_t *ptr, *ptr1, *ptr2;
165
166     h = info->height;
167     h1 = h;
168     switch(info->pix_fmt) {
169     case PIX_FMT_MONOWHITE:
170         c = '4';
171         n = (info->width + 7) >> 3;
172         break;
173     case PIX_FMT_GRAY8:
174         c = '5';
175         n = info->width;
176         break;
177     case PIX_FMT_RGB24:
178         c = '6';
179         n = info->width * 3;
180         break;
181     case PIX_FMT_YUV420P:
182         c = '5';
183         n = info->width;
184         h1 = (h * 3) / 2;
185         break;
186     default:
187         return AVERROR_INVALIDDATA;
188     }
189     snprintf(buf, sizeof(buf), 
190              "P%c\n%d %d\n",
191              c, info->width, h1);
192     put_buffer(pb, buf, strlen(buf));
193     if (info->pix_fmt != PIX_FMT_MONOWHITE) {
194         snprintf(buf, sizeof(buf), 
195                  "%d\n", 255);
196         put_buffer(pb, buf, strlen(buf));
197     }
198     
199     ptr = info->pict.data[0];
200     linesize = info->pict.linesize[0];
201     for(i=0;i<h;i++) {
202         put_buffer(pb, ptr, n);
203         ptr += linesize;
204     }
205     
206     if (info->pix_fmt == PIX_FMT_YUV420P) {
207         h >>= 1;
208         n >>= 1;
209         ptr1 = info->pict.data[1];
210         ptr2 = info->pict.data[2];
211         for(i=0;i<h;i++) {
212             put_buffer(pb, ptr1, n);
213             put_buffer(pb, ptr2, n);
214                 ptr1 += info->pict.linesize[1];
215                 ptr2 += info->pict.linesize[2];
216         }
217     }
218     put_flush_packet(pb);
219     return 0;
220 }
221
222 static int pam_read(ByteIOContext *f, 
223                     int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque)
224 {
225     int i, n, linesize, h, w, depth, maxval;
226     char buf1[32], tuple_type[32];
227     unsigned char *ptr;
228     AVImageInfo info1, *info = &info1;
229     int ret;
230
231     pnm_get(f, buf1, sizeof(buf1));
232     if (strcmp(buf1, "P7") != 0)
233         return AVERROR_INVALIDDATA;
234     w = -1;
235     h = -1;
236     maxval = -1;
237     depth = -1;
238     tuple_type[0] = '\0';
239     for(;;) {
240         pnm_get(f, buf1, sizeof(buf1));
241         if (!strcmp(buf1, "WIDTH")) {
242             pnm_get(f, buf1, sizeof(buf1));
243             w = strtol(buf1, NULL, 10);
244         } else if (!strcmp(buf1, "HEIGHT")) {
245             pnm_get(f, buf1, sizeof(buf1));
246             h = strtol(buf1, NULL, 10);
247         } else if (!strcmp(buf1, "DEPTH")) {
248             pnm_get(f, buf1, sizeof(buf1));
249             depth = strtol(buf1, NULL, 10);
250         } else if (!strcmp(buf1, "MAXVAL")) {
251             pnm_get(f, buf1, sizeof(buf1));
252             maxval = strtol(buf1, NULL, 10);
253         } else if (!strcmp(buf1, "TUPLETYPE")) {
254             pnm_get(f, buf1, sizeof(buf1));
255             pstrcpy(tuple_type, sizeof(tuple_type), buf1);
256         } else if (!strcmp(buf1, "ENDHDR")) {
257             break;
258         } else {
259             return AVERROR_INVALIDDATA;
260         }
261     }
262     /* check that all tags are present */
263     if (w <= 0 || h <= 0 || maxval <= 0 || depth <= 0 || tuple_type[0] == '\0')
264         return AVERROR_INVALIDDATA;
265     info->width = w;
266     info->height = h;
267     if (depth == 1) {
268         if (maxval == 1)
269             info->pix_fmt = PIX_FMT_MONOWHITE;
270         else 
271             info->pix_fmt = PIX_FMT_GRAY8;
272     } else if (depth == 3) {
273         info->pix_fmt = PIX_FMT_RGB24;
274     } else if (depth == 4) {
275         info->pix_fmt = PIX_FMT_RGBA32;
276     } else {
277         return AVERROR_INVALIDDATA;
278     }
279     ret = alloc_cb(opaque, info);
280     if (ret)
281         return ret;
282     
283     switch(info->pix_fmt) {
284     default:
285         return AVERROR_INVALIDDATA;
286     case PIX_FMT_RGB24:
287         n = info->width * 3;
288         goto do_read;
289     case PIX_FMT_GRAY8:
290         n = info->width;
291         goto do_read;
292     case PIX_FMT_MONOWHITE:
293         n = (info->width + 7) >> 3;
294     do_read:
295         ptr = info->pict.data[0];
296         linesize = info->pict.linesize[0];
297         for(i = 0; i < info->height; i++) {
298             get_buffer(f, ptr, n);
299             ptr += linesize;
300         }
301         break;
302     case PIX_FMT_RGBA32:
303         ptr = info->pict.data[0];
304         linesize = info->pict.linesize[0];
305         for(i = 0; i < info->height; i++) {
306             int j, r, g, b, a;
307
308             for(j = 0;j < w; j++) {
309                 r = get_byte(f);
310                 g = get_byte(f);
311                 b = get_byte(f);
312                 a = get_byte(f);
313                 ((uint32_t *)ptr)[j] = (a << 24) | (r << 16) | (g << 8) | b;
314             }
315             ptr += linesize;
316         }
317         break;
318     }
319     return 0;
320 }
321
322 static int pam_write(ByteIOContext *pb, AVImageInfo *info)
323 {
324     int i, h, w, n, linesize, depth, maxval;
325     const char *tuple_type;
326     char buf[100];
327     uint8_t *ptr;
328
329     h = info->height;
330     w = info->width;
331     switch(info->pix_fmt) {
332     case PIX_FMT_MONOWHITE:
333         n = (info->width + 7) >> 3;
334         depth = 1;
335         maxval = 1;
336         tuple_type = "BLACKANDWHITE";
337         break;
338     case PIX_FMT_GRAY8:
339         n = info->width;
340         depth = 1;
341         maxval = 255;
342         tuple_type = "GRAYSCALE";
343         break;
344     case PIX_FMT_RGB24:
345         n = info->width * 3;
346         depth = 3;
347         maxval = 255;
348         tuple_type = "RGB";
349         break;
350     case PIX_FMT_RGBA32:
351         n = info->width * 4;
352         depth = 4;
353         maxval = 255;
354         tuple_type = "RGB_ALPHA";
355         break;
356     default:
357         return AVERROR_INVALIDDATA;
358     }
359     snprintf(buf, sizeof(buf), 
360              "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLETYPE %s\nENDHDR\n",
361              w, h, depth, maxval, tuple_type);
362     put_buffer(pb, buf, strlen(buf));
363     
364     ptr = info->pict.data[0];
365     linesize = info->pict.linesize[0];
366     
367     if (info->pix_fmt == PIX_FMT_RGBA32) {
368         int j;
369         unsigned int v;
370
371         for(i=0;i<h;i++) {
372             for(j=0;j<w;j++) {
373                 v = ((uint32_t *)ptr)[j];
374                 put_byte(pb, (v >> 16) & 0xff);
375                 put_byte(pb, (v >> 8) & 0xff);
376                 put_byte(pb, (v) & 0xff);
377                 put_byte(pb, (v >> 24) & 0xff);
378             }
379             ptr += linesize;
380         }
381     } else {
382         for(i=0;i<h;i++) {
383             put_buffer(pb, ptr, n);
384             ptr += linesize;
385         }
386     }
387     put_flush_packet(pb);
388     return 0;
389 }
390
391 static int pnm_probe(AVProbeData *pd)
392 {
393     const char *p = pd->buf;
394     if (pd->buf_size >= 8 &&
395         p[0] == 'P' &&
396         p[1] >= '4' && p[1] <= '6' &&
397         p[2] == '\n')
398         return AVPROBE_SCORE_MAX - 1; /* to permit pgmyuv probe */
399     else
400         return 0;
401 }
402
403 static int pgmyuv_probe(AVProbeData *pd)
404 {
405     if (match_ext(pd->filename, "pgmyuv"))
406         return AVPROBE_SCORE_MAX;
407     else
408         return 0;
409 }
410
411 static int pam_probe(AVProbeData *pd)
412 {
413     const char *p = pd->buf;
414     if (pd->buf_size >= 8 &&
415         p[0] == 'P' &&
416         p[1] == '7' &&
417         p[2] == '\n')
418         return AVPROBE_SCORE_MAX;
419     else
420         return 0;
421 }
422
423 AVImageFormat pnm_image_format = {
424     "pnm",
425     NULL,
426     pnm_probe,
427     pnm_read,
428     0,
429     NULL,
430 };
431
432 AVImageFormat pbm_image_format = {
433     "pbm",
434     "pbm",
435     NULL,
436     NULL,
437     (1 << PIX_FMT_MONOWHITE),
438     pnm_write,
439 };
440
441 AVImageFormat pgm_image_format = {
442     "pgm",
443     "pgm",
444     NULL,
445     NULL,
446     (1 << PIX_FMT_GRAY8),
447     pnm_write,
448 };
449
450 AVImageFormat ppm_image_format = {
451     "ppm",
452     "ppm",
453     NULL,
454     NULL,
455     (1 << PIX_FMT_RGB24),
456     pnm_write,
457 };
458
459 AVImageFormat pam_image_format = {
460     "pam",
461     "pam",
462     pam_probe,
463     pam_read,
464     (1 << PIX_FMT_MONOWHITE) | (1 << PIX_FMT_GRAY8) | (1 << PIX_FMT_RGB24) | 
465     (1 << PIX_FMT_RGBA32),
466     pam_write,
467 };
468
469 AVImageFormat pgmyuv_image_format = {
470     "pgmyuv",
471     "pgmyuv",
472     pgmyuv_probe,
473     pgmyuv_read,
474     (1 << PIX_FMT_YUV420P),
475     pnm_write,
476 };