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