1 /*****************************************************************
2  * gmerlin - a general purpose multimedia framework and applications
3  *
4  * Copyright (c) 2001 - 2011 Members of the Gmerlin project
5  * gmerlin-general@lists.sourceforge.net
6  * http://gmerlin.sourceforge.net
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program 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
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  * *****************************************************************/
21 
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <inttypes.h>
27 #include <errno.h>
28 
29 #include <config.h>
30 #include <gmerlin/translation.h>
31 #include <gmerlin/plugin.h>
32 #include <gmerlin/pluginfuncs.h>
33 #include <gmerlin/utils.h>
34 
35 #include <gmerlin/log.h>
36 #define LOG_DOMAIN "iw_pnm"
37 
38 #define BINARY_RGB    6
39 #define ASCII_RGB     3
40 
41 #define BINARY_GRAY   5
42 #define ASCII_GRAY    2
43 
44 typedef struct
45   {
46   FILE *output;
47   char *comment;
48   uint32_t Width;
49   uint32_t Height;
50   gavl_video_format_t format;
51   int binary;
52   bg_iw_callbacks_t * cb;
53   int is_gray;
54   } pnm_t;
55 
create_pnm()56 static void * create_pnm()
57   {
58   pnm_t * ret;
59   ret = calloc(1, sizeof(*ret));
60   return ret;
61   }
62 
destroy_pnm(void * priv)63 static void destroy_pnm(void* priv)
64   {
65   pnm_t * pnm = priv;
66   if(pnm->comment)
67     free(pnm->comment);
68   free(pnm);
69   }
70 
set_callbacks_pnm(void * data,bg_iw_callbacks_t * cb)71 static void set_callbacks_pnm(void * data, bg_iw_callbacks_t * cb)
72   {
73   pnm_t * e = data;
74   e->cb = cb;
75   }
76 
write_header_pnm(void * priv,const char * filename,gavl_video_format_t * format,const gavl_metadata_t * m)77 static int write_header_pnm(void * priv, const char * filename,
78                             gavl_video_format_t * format,
79                             const gavl_metadata_t * m)
80   {
81   int sig = 0;
82   const char * ext;
83   char * real_filename;
84   pnm_t * p = priv;
85 
86   p->Width =  format->image_width;
87   p->Height =  format->image_height;
88 
89   if(gavl_pixelformat_is_gray(format->pixelformat))
90     {
91     format->pixelformat = GAVL_GRAY_8;
92     p->is_gray = 1;
93     ext = "pgm";
94     }
95   else
96     {
97     format->pixelformat = GAVL_RGB_24;
98     p->is_gray = 0;
99     ext = "ppm";
100     }
101 
102   real_filename = bg_filename_ensure_extension(filename, ext);
103 
104   if(!bg_iw_cb_create_output_file(p->cb, real_filename))
105     {
106     free(real_filename);
107     return 0;
108     }
109 
110   p->output = fopen(real_filename,"wb");
111   free(real_filename);
112 
113   if(!p->output)
114     {
115     bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Cannot open %s: %s",
116            real_filename, strerror(errno));
117     return 0;
118     }
119 
120 
121   if(p->binary)
122     {
123     if(p->is_gray)
124       sig = BINARY_GRAY;
125     else
126       sig = BINARY_RGB;
127     }
128   else
129     {
130     if(p->is_gray)
131       sig = ASCII_GRAY;
132     else
133       sig = ASCII_RGB;
134     }
135 
136   /* Write the header lines */
137   fprintf(p->output,"P%d\n# %s\n%d %d\n255\n", sig, p->comment, p->Width, p->Height);
138   return 1;
139   }
140 
write_image_pnm(void * priv,gavl_video_frame_t * frame)141 static int write_image_pnm(void *priv, gavl_video_frame_t *frame)
142   {
143   int i, j;
144   pnm_t *p = priv;
145   uint8_t * frame_ptr;
146 
147   int bytes_per_pixel;
148   if(p->is_gray)
149     bytes_per_pixel = 1;
150   else
151     bytes_per_pixel = 3;
152 
153   /* write image data binary */
154   if(p->binary)
155     {
156     frame_ptr = frame->planes[0];
157 
158     for (i = 0; i < p->Height; i++)
159       {
160       fwrite(frame_ptr, bytes_per_pixel, p->Width, p->output);
161       frame_ptr += frame->strides[0];
162       }
163     }
164   /* write image data ascii */
165   else
166     {
167     uint8_t * frame_ptr_start;
168     frame_ptr_start = frame->planes[0];
169     for (i = 0; i < p->Height; i++)
170       {
171       frame_ptr = frame_ptr_start ;
172 
173       for(j = 0; j < p->Width * bytes_per_pixel; j++)
174         {
175         fprintf(p->output," %d", *frame_ptr);
176         frame_ptr++;
177         }
178       fprintf(p->output,"\n");
179       frame_ptr_start += frame->strides[0];
180       }
181     }
182 
183   fclose(p->output);
184   return 1;
185   }
186 
187 
188 /* Configuration stuff */
189 
190 static const bg_parameter_info_t parameters[] =
191   {
192     {
193       .name =        "format",
194       .long_name =   TRS("Format"),
195       .type =        BG_PARAMETER_STRINGLIST,
196       .multi_names = (char const *[]){ "binary", "ascii", NULL },
197       .multi_labels =  (char const *[]){ TRS("Binary"), TRS("ASCII"), NULL },
198 
199       .val_default = { .val_str = "binary" },
200     },
201     {
202       .name =        "comment",
203       .long_name =   TRS("Comment"),
204       .type =        BG_PARAMETER_STRING,
205 
206       .val_default = { .val_str = "Created with gmerlin" },
207       .help_string = TRS("Comment which will be written in front of every file")
208     },
209    { /* End of parameters */ }
210   };
211 
get_parameters_pnm(void * p)212 static const bg_parameter_info_t * get_parameters_pnm(void * p)
213   {
214   return parameters;
215   }
216 
set_parameter_pnm(void * p,const char * name,const bg_parameter_value_t * val)217 static void set_parameter_pnm(void * p, const char * name,
218                               const bg_parameter_value_t * val)
219   {
220   pnm_t * pnm;
221   pnm = p;
222 
223   if(!name)
224     return;
225 
226   else if(!strcmp(name, "format"))
227     {
228     if(!strcmp(val->val_str, "binary"))
229       pnm->binary = 1;
230     else if(!strcmp(val->val_str, "ascii"))
231       pnm->binary = 0;
232     }
233   else if(!strcmp(name, "comment"))
234     pnm->comment = bg_strdup(pnm->comment, val->val_str);
235   }
236 
237 const bg_image_writer_plugin_t the_plugin =
238   {
239     .common =
240     {
241       BG_LOCALE,
242       .name =           "iw_pnm",
243       .long_name =      TRS("PPM/PGM writer"),
244       .description =    TRS("Writer for PPM/PGM images"),
245       .type =           BG_PLUGIN_IMAGE_WRITER,
246       .flags =          BG_PLUGIN_FILE,
247       .priority =       5,
248       .create =         create_pnm,
249       .destroy =        destroy_pnm,
250       .get_parameters = get_parameters_pnm,
251       .set_parameter =  set_parameter_pnm
252     },
253     .extensions = "ppm pgm",
254     .set_callbacks = set_callbacks_pnm,
255     .write_header =  write_header_pnm,
256     .write_image =   write_image_pnm,
257   };
258 
259 /* Include this into all plugin modules exactly once
260    to let the plugin loader obtain the API version */
261 BG_GET_PLUGIN_API_VERSION;
262 
263