r999: maintainers added to README_en.
[cinelerra_cv/mob.git] / cinelerra / filepng.C
blob3b29db2d69cf085edd0b7af4970cfaef9fa4b157
1 #include "asset.h"
2 #include "edit.h"
3 #include "file.h"
4 #include "filepng.h"
5 #include "interlacemodes.h"
6 #include "language.h"
7 #include "mwindow.inc"
8 #include "quicktime.h"
9 #include "vframe.h"
10 #include "videodevice.inc"
11 #include "mainerror.h"
13 #include <png.h>
15 FilePNG::FilePNG(Asset *asset, File *file)
16  : FileList(asset, file, "PNGLIST", ".png", FILE_PNG, FILE_PNG_LIST)
20 FilePNG::~FilePNG()
26 int FilePNG::check_sig(Asset *asset)
28         FILE *stream = fopen(asset->path, "rb");
30         if(stream)
31         {
33 //printf("FilePNG::check_sig 1\n");
34                 char test[16];
35                 fread(test, 16, 1, stream);
36                 fclose(stream);
38                 if(png_check_sig((unsigned char*)test, 8))
39                 {
40 //printf("FilePNG::check_sig 1\n");
41                         return 1;
42                 }
43                 else
44                 if(test[0] == 'P' && test[1] == 'N' && test[2] == 'G' && 
45                         test[3] == 'L' && test[4] == 'I' && test[5] == 'S' && test[6] == 'T')
46                 {
47 //printf("FilePNG::check_sig 1\n");
48                         return 1;
49                 }
50         }
51         return 0;
56 void FilePNG::get_parameters(BC_WindowBase *parent_window, 
57         Asset *asset, 
58         BC_WindowBase* &format_window,
59         int audio_options,
60         int video_options)
62         if(video_options)
63         {
64                 PNGConfigVideo *window = new PNGConfigVideo(parent_window, asset);
65                 format_window = window;
66                 window->create_objects();
67                 window->run_window();
68                 delete window;
69         }
75 int FilePNG::can_copy_from(Edit *edit, int64_t position)
77         if(edit->asset->format == FILE_MOV)
78         {
79                 if(match4(edit->asset->vcodec, QUICKTIME_PNG)) return 1;
80         }
81         else
82         if(edit->asset->format == FILE_PNG || 
83                 edit->asset->format == FILE_PNG_LIST)
84                 return 1;
86         return 0;
90 int FilePNG::colormodel_supported(int colormodel)
92         if (((colormodel == BC_RGBA8888) && (native_cmodel == BC_RGBA16161616))
93             || ((colormodel == BC_RGB161616) && (native_cmodel == BC_RGBA16161616))
94             || (colormodel == BC_RGB888))
95         {
96             return colormodel;
97         }
98         else if ((colormodel == BC_RGB161616) && (native_cmodel == BC_RGBA8888))
99         {
100             return BC_RGB888;
101         }
102         else
103         {
104             return native_cmodel;
105         }
109 int FilePNG::get_best_colormodel(Asset *asset, int driver)
111         if(asset->png_use_alpha)
112                 return BC_RGBA8888;
113         else
114                 return BC_RGB888;
120 int FilePNG::read_frame_header(char *path)
122         int result = 0;
123         int color_type;
124         int color_depth;
125         int num_trans = 0;
126         
127         FILE *stream;
129         if(!(stream = fopen(path, "rb")))
130         {
131                 eprintf("Error while opening \"%s\" for reading. \n%m\n", asset->path);
132                 return 1;
133         }
135         png_structp png_ptr;
136         png_infop info_ptr;
137         png_infop end_info = 0; 
138         png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
139         info_ptr = png_create_info_struct(png_ptr);
140         png_init_io(png_ptr, stream);
143         png_read_info(png_ptr, info_ptr);
145         asset->width = png_get_image_width(png_ptr, info_ptr);
146         asset->height = png_get_image_height(png_ptr, info_ptr);
147         
148         asset->interlace_mode = BC_ILACE_MODE_NOTINTERLACED;
150         color_type = png_get_color_type(png_ptr, info_ptr);
151         color_depth = png_get_bit_depth(png_ptr,info_ptr);
152         
153         png_get_tRNS(png_ptr, info_ptr, NULL, &num_trans, NULL);
154         
155         if (color_depth == 16)
156         {
157             if (color_type & PNG_COLOR_MASK_ALPHA)
158             {
159                 native_cmodel = BC_RGBA16161616;
160             }
161             else
162             {
163                 native_cmodel = BC_RGB161616;
164             }
165         }
166         else 
167         if ((color_type & PNG_COLOR_MASK_ALPHA)
168             || (num_trans > 0))
169         {
170             native_cmodel = BC_RGBA8888;
171         }
172         else
173         {
174             native_cmodel = BC_RGB888;
175         }
178         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
179         fclose(stream);
180         
181         
182         
183         return result;
189 static void read_function(png_structp png_ptr, 
190         png_bytep data, 
191         png_uint_32 length)
193         VFrame *input = (VFrame*)png_get_io_ptr(png_ptr);
195         memcpy(data, input->get_data() + input->get_compressed_size(), length);
196         input->set_compressed_size(input->get_compressed_size() + length);
199 static void write_function(png_structp png_ptr, png_bytep data, png_uint_32 length)
201         VFrame *output = (VFrame*)png_get_io_ptr(png_ptr);
203         if(output->get_compressed_allocated() < output->get_compressed_size() + length)
204                 output->allocate_compressed_data((output->get_compressed_allocated() + length) * 2);
205         memcpy(output->get_data() + output->get_compressed_size(), data, length);
206         output->set_compressed_size(output->get_compressed_size() + length);
209 static void flush_function(png_structp png_ptr)
211         ;
216 int FilePNG::write_frame(VFrame *frame, VFrame *data, FrameWriterUnit *unit)
218         PNGUnit *png_unit = (PNGUnit*)unit;
219         int result = 0;
220         png_structp png_ptr;
221         png_infop info_ptr;
222         png_infop end_info = 0; 
223         VFrame *output_frame;
224         data->set_compressed_size(0);
226 //printf("FilePNG::write_frame 1\n");
227         png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
228         info_ptr = png_create_info_struct(png_ptr);
229         png_set_write_fn(png_ptr,
230                data, 
231                            (png_rw_ptr)write_function,
232                (png_flush_ptr)flush_function);
233         png_set_compression_level(png_ptr, 9);
235         png_set_IHDR(png_ptr, 
236                 info_ptr, 
237                 asset->width, 
238                 asset->height,
239         8, 
240                 asset->png_use_alpha ? 
241                   PNG_COLOR_TYPE_RGB_ALPHA : 
242                   PNG_COLOR_TYPE_RGB, 
243                 PNG_INTERLACE_NONE, 
244                 PNG_COMPRESSION_TYPE_DEFAULT, 
245                 PNG_FILTER_TYPE_DEFAULT);
246         png_write_info(png_ptr, info_ptr);
248 //printf("FilePNG::write_frame 1\n");
249         native_cmodel = asset->png_use_alpha ? BC_RGBA8888 : BC_RGB888;
250         if(frame->get_color_model() != native_cmodel)
251         {
252                 if(!png_unit->temp_frame) png_unit->temp_frame = new VFrame(0, 
253                         asset->width, 
254                         asset->height, 
255                         native_cmodel);
257                 cmodel_transfer(png_unit->temp_frame->get_rows(), /* Leave NULL if non existent */
258                         frame->get_rows(),
259                         png_unit->temp_frame->get_y(), /* Leave NULL if non existent */
260                         png_unit->temp_frame->get_u(),
261                         png_unit->temp_frame->get_v(),
262                         frame->get_y(), /* Leave NULL if non existent */
263                         frame->get_u(),
264                         frame->get_v(),
265                         0,        /* Dimensions to capture from input frame */
266                         0, 
267                         asset->width, 
268                         asset->height,
269                         0,       /* Dimensions to project on output frame */
270                         0, 
271                         asset->width, 
272                         asset->height,
273                         frame->get_color_model(), 
274                         png_unit->temp_frame->get_color_model(),
275                         0,         /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
276                         asset->width,       /* For planar use the luma rowspan */
277                         asset->height);
278                 
279                 output_frame = png_unit->temp_frame;
280         }
281         else
282                 output_frame = frame;
285 //printf("FilePNG::write_frame 2\n");
286         png_write_image(png_ptr, output_frame->get_rows());
287         png_write_end(png_ptr, info_ptr);
288         png_destroy_write_struct(&png_ptr, &info_ptr);
289 //printf("FilePNG::write_frame 3 %d\n", data->get_compressed_size());
291         return result;
294 int FilePNG::read_frame(VFrame *output, VFrame *input)
296         png_structp png_ptr;
297         png_infop info_ptr;
298         png_infop end_info = 0; 
299         int result = 0;
300         int color_type;
301         int color_depth;
302         int colormodel;
303         int size = input->get_compressed_size();
304         input->set_compressed_size(0);
305         
306         
307         //printf("FilePNG::read_frame 1 %d %d\n", native_cmodel, output->get_color_model());
308         png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
309         info_ptr = png_create_info_struct(png_ptr);
310         png_set_read_fn(png_ptr, input, (png_rw_ptr)read_function);
311         png_read_info(png_ptr, info_ptr);
313         int png_color_type = png_get_color_type(png_ptr, info_ptr);
314         if (png_color_type == PNG_COLOR_TYPE_GRAY ||
315                 png_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
316         {
317                 png_set_gray_to_rgb(png_ptr);
318         }
320         colormodel = output->get_color_model();
321         color_type = png_get_color_type(png_ptr, info_ptr);
322         color_depth = png_get_bit_depth(png_ptr,info_ptr);
323         
324         if (((native_cmodel == BC_RGBA16161616)||(native_cmodel == BC_RGB161616))
325             && ((colormodel == BC_RGBA8888)||(colormodel == BC_RGB888)))
326         {
327             png_set_strip_16(png_ptr);
328         }
330         /* If we're dropping the alpha channel, use the background color of the image
331            otherwise, use black */
332         if (((native_cmodel == BC_RGBA16161616)||(native_cmodel == BC_RGBA8888))
333             && ((colormodel == BC_RGB161616)||(colormodel == BC_RGB888)))
334         {
335             png_color_16 my_background;
336             png_color_16p image_background;
337             
338             memset(&my_background,0,sizeof(png_color_16));
339             
340             if (png_get_bKGD(png_ptr, info_ptr, &image_background))
341             {
342                 png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
343             }
344             else
345             {
346                 png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
347             }
348         }
349         
350         /* Little endian */
351         if ((color_depth == 16)
352             &&((colormodel == BC_RGBA16161616)||(colormodel == BC_RGB161616)))
353         {
354             png_set_swap(png_ptr);
355         }
356         
357         if (!(color_type & PNG_COLOR_MASK_COLOR))
358         {
359             png_set_gray_to_rgb(png_ptr);
360         }
361         
362         if (color_type & PNG_COLOR_MASK_PALETTE)
363         {
364             png_set_palette_to_rgb(png_ptr);
365         }
366         
367         if (color_depth <= 8)
368         {
369             png_set_expand(png_ptr);
370         }
372 /* read the image */
373         png_read_image(png_ptr, output->get_rows());
374 //printf("FilePNG::read_frame 3\n");
375         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
377         input->set_compressed_size(size);
379 //printf("FilePNG::read_frame 4\n");
380         return result;
383 FrameWriterUnit* FilePNG::new_writer_unit(FrameWriter *writer)
385         return new PNGUnit(this, writer);
399 PNGUnit::PNGUnit(FilePNG *file, FrameWriter *writer)
400  : FrameWriterUnit(writer)
402         this->file = file;
403         temp_frame = 0;
405 PNGUnit::~PNGUnit()
407         if(temp_frame) delete temp_frame;
418 PNGConfigVideo::PNGConfigVideo(BC_WindowBase *parent_window, Asset *asset)
419  : BC_Window(PROGRAM_NAME ": Video Compression",
420         parent_window->get_abs_cursor_x(1),
421         parent_window->get_abs_cursor_y(1),
422         200,
423         100)
425         this->parent_window = parent_window;
426         this->asset = asset;
429 PNGConfigVideo::~PNGConfigVideo()
433 int PNGConfigVideo::create_objects()
435         int x = 10, y = 10;
436         add_subwindow(new PNGUseAlpha(this, x, y));
437         add_subwindow(new BC_OKButton(this));
438         return 0;
441 int PNGConfigVideo::close_event()
443         set_done(0);
444         return 1;
448 PNGUseAlpha::PNGUseAlpha(PNGConfigVideo *gui, int x, int y)
449  : BC_CheckBox(x, y, gui->asset->png_use_alpha, _("Use alpha"))
451         this->gui = gui;
454 int PNGUseAlpha::handle_event()
456         gui->asset->png_use_alpha = get_value();
457         return 1;