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