6ccbf28819f51343957018d075574d54f45cbbbb
[goodguy/history.git] / cinelerra-5.1 / cinelerra / filepng.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "asset.h"
23 #include "edit.h"
24 #include "file.h"
25 #include "filepng.h"
26 #include "interlacemodes.h"
27 #include "language.h"
28 #include "mwindow.inc"
29 #include "vframe.h"
30 #include "videodevice.inc"
31 #include "mainerror.h"
32
33 #include <png.h>
34 #include <string.h>
35
36 FilePNG::FilePNG(Asset *asset, File *file)
37  : FileList(asset, file, "PNGLIST", ".png", FILE_PNG, FILE_PNG_LIST)
38 {
39 }
40
41 FilePNG::~FilePNG()
42 {
43 }
44
45
46
47 int FilePNG::check_sig(Asset *asset)
48 {
49         FILE *stream = fopen(asset->path, "rb");
50
51         if(stream)
52         {
53
54 //printf("FilePNG::check_sig 1\n");
55                 char test[16];
56                 (void)fread(test, 16, 1, stream);
57                 fclose(stream);
58
59 //              if(png_sig_cmp((unsigned char*)test, 0, 8))
60                 if(png_check_sig((unsigned char*)test, 8))
61                 {
62 //printf("FilePNG::check_sig 1\n");
63                         return 1;
64                 }
65                 else
66                 if(test[0] == 'P' && test[1] == 'N' && test[2] == 'G' &&
67                         test[3] == 'L' && test[4] == 'I' && test[5] == 'S' && test[6] == 'T')
68                 {
69 //printf("FilePNG::check_sig 1\n");
70                         return 1;
71                 }
72         }
73         return 0;
74 }
75
76
77
78 void FilePNG::get_parameters(BC_WindowBase *parent_window,
79         Asset *asset,
80         BC_WindowBase* &format_window,
81         int audio_options,
82         int video_options)
83 {
84         if(video_options)
85         {
86                 PNGConfigVideo *window = new PNGConfigVideo(parent_window, asset);
87                 format_window = window;
88                 window->create_objects();
89                 window->run_window();
90                 delete window;
91         }
92 }
93
94
95
96
97 int FilePNG::can_copy_from(Asset *asset, int64_t position)
98 {
99         if(asset->format == FILE_PNG ||
100                 asset->format == FILE_PNG_LIST)
101                 return 1;
102
103         return 0;
104 }
105
106
107 int FilePNG::colormodel_supported(int colormodel)
108 {
109         if (((colormodel == BC_RGBA8888) && (native_cmodel == BC_RGBA16161616))
110             || ((colormodel == BC_RGB161616) && (native_cmodel == BC_RGBA16161616))
111             || (colormodel == BC_RGB888))
112         {
113             return colormodel;
114         }
115         else if ((colormodel == BC_RGB161616) && (native_cmodel == BC_RGBA8888))
116         {
117             return BC_RGB888;
118         }
119         else
120         {
121             return native_cmodel;
122         }
123 }
124
125
126 int FilePNG::get_best_colormodel(Asset *asset, int driver)
127 {
128         if(asset->png_use_alpha)
129                 return BC_RGBA8888;
130         else
131                 return BC_RGB888;
132 }
133
134
135
136
137 int FilePNG::read_frame_header(char *path)
138 {
139         int result = 0;
140         int color_type;
141         int color_depth;
142         int num_trans = 0;
143
144         FILE *stream;
145
146         if(!(stream = fopen(path, "rb")))
147         {
148                 eprintf("Error while opening \"%s\" for reading. \n%m\n", asset->path);
149                 return 1;
150         }
151
152         png_structp png_ptr;
153         png_infop info_ptr;
154         png_infop end_info = 0;
155         png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
156         info_ptr = png_create_info_struct(png_ptr);
157         png_init_io(png_ptr, stream);
158
159
160         png_read_info(png_ptr, info_ptr);
161
162         asset->width = png_get_image_width(png_ptr, info_ptr);
163         asset->height = png_get_image_height(png_ptr, info_ptr);
164
165         asset->interlace_mode = BC_ILACE_MODE_NOTINTERLACED;
166
167         color_type = png_get_color_type(png_ptr, info_ptr);
168         color_depth = png_get_bit_depth(png_ptr,info_ptr);
169
170         png_get_tRNS(png_ptr, info_ptr, NULL, &num_trans, NULL);
171
172         if (color_depth == 16)
173         {
174             if (color_type & PNG_COLOR_MASK_ALPHA)
175             {
176                 native_cmodel = BC_RGBA16161616;
177             }
178             else
179             {
180                 native_cmodel = BC_RGB161616;
181             }
182         }
183         else
184         if ((color_type & PNG_COLOR_MASK_ALPHA)
185             || (num_trans > 0))
186         {
187             native_cmodel = BC_RGBA8888;
188         }
189         else
190         {
191             native_cmodel = BC_RGB888;
192         }
193
194         asset->png_use_alpha = BC_CModels::has_alpha(native_cmodel) ? 1 : 0;
195
196         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
197         fclose(stream);
198
199
200
201         return result;
202 }
203
204
205
206
207 static void read_function(png_structp png_ptr,
208         png_bytep data,
209         png_uint_32 length)
210 {
211         VFrame *input = (VFrame*)png_get_io_ptr(png_ptr);
212
213         memcpy(data, input->get_data() + input->get_compressed_size(), length);
214         input->set_compressed_size(input->get_compressed_size() + length);
215 }
216
217 static void write_function(png_structp png_ptr, png_bytep data, png_uint_32 length)
218 {
219         VFrame *output = (VFrame*)png_get_io_ptr(png_ptr);
220         long total_length = output->get_compressed_size() + length;
221         if(output->get_compressed_allocated() < total_length) {
222                 long new_length = 2 * (output->get_compressed_allocated() + length);
223                 output->allocate_compressed_data(new_length);
224         }
225         memcpy(output->get_data() + output->get_compressed_size(), data, length);
226         output->set_compressed_size(total_length);
227 }
228
229 static void flush_function(png_structp png_ptr)
230 {
231 }
232
233
234 int FilePNG::write_frame(VFrame *frame, VFrame *data, FrameWriterUnit *unit)
235 {
236         PNGUnit *png_unit = (PNGUnit*)unit;
237         png_structp png_ptr = 0;
238         png_infop info_ptr = 0;
239         VFrame *output_frame;
240         int result = 1;
241         data->set_compressed_size(0);
242 //printf("FilePNG::write_frame 1\n");
243         native_cmodel = asset->png_use_alpha ? BC_RGBA8888 : BC_RGB888;
244         if(frame->get_color_model() != native_cmodel)
245         {
246                 if(!png_unit->temp_frame) png_unit->temp_frame = new VFrame(0,
247                         -1, asset->width, asset->height, native_cmodel, -1);
248
249                 png_unit->temp_frame->transfer_from(frame);
250                 output_frame = png_unit->temp_frame;
251         }
252         else
253                 output_frame = frame;
254
255 //printf("FilePNG::write_frame 1\n");
256         png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
257         if( png_ptr && !setjmp(png_jmpbuf(png_ptr)) ) {
258                 info_ptr = png_create_info_struct(png_ptr);
259                 png_set_write_fn(png_ptr, data,
260                         (png_rw_ptr)write_function, (png_flush_ptr)flush_function);
261                 png_set_compression_level(png_ptr, 5);
262
263                 png_set_IHDR(png_ptr, info_ptr, asset->width, asset->height, 8,
264                         asset->png_use_alpha ?  PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
265                         PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
266                 png_write_info(png_ptr, info_ptr);
267                 png_write_image(png_ptr, output_frame->get_rows());
268                 png_write_end(png_ptr, info_ptr);
269                 png_destroy_write_struct(&png_ptr, &info_ptr);
270                 result = 0;
271         }
272         else {
273                 char error[256];  png_error(png_ptr, error);
274                 fprintf(stderr, "FilePNG::write_frame failed: %s\n", error);
275         }
276
277         png_destroy_write_struct(&png_ptr, &info_ptr);
278 //printf("FilePNG::write_frame 3 %d\n", data->get_compressed_size());
279         return result;
280 }
281
282 int FilePNG::read_frame(VFrame *output, VFrame *input)
283 {
284         png_structp png_ptr;
285         png_infop info_ptr;
286         png_infop end_info = 0;
287         int result = 0;
288         int color_type;
289         int color_depth;
290         int colormodel;
291         int size = input->get_compressed_size();
292         input->set_compressed_size(0);
293
294
295         //printf("FilePNG::read_frame 1 %d %d\n", native_cmodel, output->get_color_model());
296         png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
297         info_ptr = png_create_info_struct(png_ptr);
298         png_set_read_fn(png_ptr, input, (png_rw_ptr)read_function);
299         png_read_info(png_ptr, info_ptr);
300
301         int png_color_type = png_get_color_type(png_ptr, info_ptr);
302         if (png_color_type == PNG_COLOR_TYPE_GRAY ||
303                 png_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
304         {
305                 png_set_gray_to_rgb(png_ptr);
306         }
307
308         colormodel = output->get_color_model();
309         color_type = png_get_color_type(png_ptr, info_ptr);
310         color_depth = png_get_bit_depth(png_ptr,info_ptr);
311
312         if (((native_cmodel == BC_RGBA16161616)||(native_cmodel == BC_RGB161616))
313             && ((colormodel == BC_RGBA8888)||(colormodel == BC_RGB888)))
314         {
315             png_set_strip_16(png_ptr);
316         }
317
318         /* If we're dropping the alpha channel, use the background color of the image
319            otherwise, use black */
320         if (((native_cmodel == BC_RGBA16161616)||(native_cmodel == BC_RGBA8888))
321             && ((colormodel == BC_RGB161616)||(colormodel == BC_RGB888)))
322         {
323             png_color_16 my_background;
324             png_color_16p image_background;
325
326             memset(&my_background,0,sizeof(png_color_16));
327
328             if (png_get_bKGD(png_ptr, info_ptr, &image_background))
329             {
330                 png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
331             }
332             else
333             {
334                 png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
335             }
336         }
337
338         /* Little endian */
339         if ((color_depth == 16)
340             &&((colormodel == BC_RGBA16161616)||(colormodel == BC_RGB161616)))
341         {
342             png_set_swap(png_ptr);
343         }
344
345         if (!(color_type & PNG_COLOR_MASK_COLOR))
346         {
347             png_set_gray_to_rgb(png_ptr);
348         }
349
350         if (color_type & PNG_COLOR_MASK_PALETTE)
351         {
352             png_set_palette_to_rgb(png_ptr);
353         }
354
355         if (color_depth <= 8)
356         {
357             png_set_expand(png_ptr);
358         }
359
360 /* read the image */
361         png_read_image(png_ptr, output->get_rows());
362 //printf("FilePNG::read_frame 3\n");
363         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
364
365         input->set_compressed_size(size);
366
367 //printf("FilePNG::read_frame 4\n");
368         return result;
369 }
370
371 FrameWriterUnit* FilePNG::new_writer_unit(FrameWriter *writer)
372 {
373         return new PNGUnit(this, writer);
374 }
375
376
377
378
379
380
381
382
383
384
385
386
387 PNGUnit::PNGUnit(FilePNG *file, FrameWriter *writer)
388  : FrameWriterUnit(writer)
389 {
390         this->file = file;
391         temp_frame = 0;
392 }
393 PNGUnit::~PNGUnit()
394 {
395         if(temp_frame) delete temp_frame;
396 }
397
398
399
400
401
402
403
404
405
406 PNGConfigVideo::PNGConfigVideo(BC_WindowBase *parent_window, Asset *asset)
407  : BC_Window(_(PROGRAM_NAME ": Video Compression"),
408         parent_window->get_abs_cursor_x(1),
409         parent_window->get_abs_cursor_y(1),
410         200,
411         100)
412 {
413         this->parent_window = parent_window;
414         this->asset = asset;
415 }
416
417 PNGConfigVideo::~PNGConfigVideo()
418 {
419 }
420
421 void PNGConfigVideo::create_objects()
422 {
423         lock_window("PNGConfigVideo::create_objects()");
424         int x = 10, y = 10;
425         add_subwindow(new PNGUseAlpha(this, x, y));
426         add_subwindow(new BC_OKButton(this));
427         show_window(1);
428         unlock_window();
429 }
430
431 int PNGConfigVideo::close_event()
432 {
433         set_done(0);
434         return 1;
435 }
436
437
438 PNGUseAlpha::PNGUseAlpha(PNGConfigVideo *gui, int x, int y)
439  : BC_CheckBox(x, y, gui->asset->png_use_alpha, _("Use alpha"))
440 {
441         this->gui = gui;
442 }
443
444 int PNGUseAlpha::handle_event()
445 {
446         gui->asset->png_use_alpha = get_value();
447         return 1;
448 }
449
450
451