4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5 * Copyright (C) 2003-2016 Cinelerra CV contributors
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "interlacemodes.h"
29 #include "mwindow.inc"
31 #include "videodevice.inc"
32 #include "mainerror.h"
37 FilePNG::FilePNG(Asset *asset, File *file)
38 : FileList(asset, file, "PNGLIST", ".png", FILE_PNG, FILE_PNG_LIST)
49 int FilePNG::check_sig(Asset *asset)
51 FILE *stream = fopen(asset->path, "rb");
56 //printf("FilePNG::check_sig 1\n");
58 (void)fread(test, 16, 1, stream);
61 // if(png_sig_cmp((unsigned char*)test, 0, 8))
62 if(png_check_sig((unsigned char*)test, 8))
64 //printf("FilePNG::check_sig 1\n");
68 if(test[0] == 'P' && test[1] == 'N' && test[2] == 'G' &&
69 test[3] == 'L' && test[4] == 'I' && test[5] == 'S' && test[6] == 'T')
71 //printf("FilePNG::check_sig 1\n");
80 void FilePNG::get_parameters(BC_WindowBase *parent_window,
81 Asset *asset, BC_WindowBase* &format_window,
82 int audio_options, int video_options, EDL *edl)
86 PNGConfigVideo *window = new PNGConfigVideo(parent_window, asset);
87 format_window = window;
88 window->create_objects();
97 int FilePNG::can_copy_from(Asset *asset, int64_t position)
99 if(asset->format == FILE_PNG ||
100 asset->format == FILE_PNG_LIST)
106 int FilePNG::colormodel_supported(int colormodel)
108 if( colormodel == BC_RGB888 || colormodel == BC_RGBA8888 )
110 if( colormodel == BC_RGB161616 && native_cmodel == BC_RGBA16161616 )
112 if( native_cmodel >= 0 )
113 return native_cmodel;
114 int use_16bit = BC_CModels::is_float(colormodel) ||
115 BC_CModels::calculate_max(colormodel) > 255 ? 1 : 0;
116 return BC_CModels::has_alpha(colormodel) ?
117 (use_16bit ? BC_RGBA16161616 : BC_RGBA8888) :
118 (use_16bit ? BC_RGB161616 : BC_RGB888);
121 int FilePNG::get_best_colormodel(Asset *asset, int driver)
123 return asset->png_depth == 16 ?
124 (asset->png_use_alpha ? BC_RGBA16161616 : BC_RGB161616) :
125 (asset->png_use_alpha ? BC_RGBA8888 : BC_RGB888);
128 int FilePNG::read_frame_header(char *path)
137 if(!(stream = fopen(path, "rb")))
139 eprintf("Error while opening \"%s\" for reading. \n%m\n", asset->path);
145 png_infop end_info = 0;
146 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
147 info_ptr = png_create_info_struct(png_ptr);
148 png_init_io(png_ptr, stream);
151 png_read_info(png_ptr, info_ptr);
153 asset->width = png_get_image_width(png_ptr, info_ptr);
154 asset->height = png_get_image_height(png_ptr, info_ptr);
155 asset->interlace_mode = ILACE_MODE_NOTINTERLACED;
156 color_type = png_get_color_type(png_ptr, info_ptr);
157 color_depth = png_get_bit_depth(png_ptr,info_ptr);
159 png_get_tRNS(png_ptr, info_ptr, NULL, &num_trans, NULL);
160 native_cmodel = color_depth == 16 ?
161 ((color_type & PNG_COLOR_MASK_ALPHA) ?
162 BC_RGBA16161616 : BC_RGB161616) :
163 ((color_type & PNG_COLOR_MASK_ALPHA) || (num_trans > 0) ?
164 BC_RGBA8888 : BC_RGB888);
165 asset->png_use_alpha = BC_CModels::has_alpha(native_cmodel) ? 1 : 0;
167 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
175 static void read_function(png_structp png_ptr,
179 VFrame *input = (VFrame*)png_get_io_ptr(png_ptr);
181 memcpy(data, input->get_data() + input->get_compressed_size(), length);
182 input->set_compressed_size(input->get_compressed_size() + length);
185 static void write_function(png_structp png_ptr, png_bytep data, png_uint_32 length)
187 VFrame *output = (VFrame*)png_get_io_ptr(png_ptr);
188 long total_length = output->get_compressed_size() + length;
189 if(output->get_compressed_allocated() < total_length) {
190 long new_length = 2 * (output->get_compressed_allocated() + length);
191 output->allocate_compressed_data(new_length);
193 memcpy(output->get_data() + output->get_compressed_size(), data, length);
194 output->set_compressed_size(total_length);
197 static void flush_function(png_structp png_ptr)
202 int FilePNG::write_frame(VFrame *frame, VFrame *data, FrameWriterUnit *unit)
204 PNGUnit *png_unit = (PNGUnit*)unit;
205 png_structp png_ptr = 0;
206 png_infop info_ptr = 0;
207 VFrame *output_frame = frame;
209 data->set_compressed_size(0);
210 //printf("FilePNG::write_frame 1\n");
211 native_cmodel = asset->png_depth == 16 ?
212 (asset->png_use_alpha ? BC_RGBA16161616 : BC_RGB161616) :
213 (asset->png_use_alpha ? BC_RGBA8888 : BC_RGB888) ;
214 if( frame->get_color_model() != native_cmodel ) {
215 VFrame::get_temp(png_unit->temp_frame,
216 asset->width, asset->height, native_cmodel);
217 png_unit->temp_frame->transfer_from(frame);
218 output_frame = png_unit->temp_frame;
221 //printf("FilePNG::write_frame 1\n");
222 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
224 if( !setjmp(png_jmpbuf(png_ptr)) ) {
225 info_ptr = png_create_info_struct(png_ptr);
226 png_set_write_fn(png_ptr, data,
227 (png_rw_ptr)write_function, (png_flush_ptr)flush_function);
228 png_set_compression_level(png_ptr, asset->png_compression);
229 png_set_IHDR(png_ptr, info_ptr, asset->width, asset->height, asset->png_depth,
230 asset->png_use_alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
231 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
232 png_write_info(png_ptr, info_ptr);
233 if( BC_Resources::little_endian ) png_set_swap(png_ptr);
234 png_write_image(png_ptr, output_frame->get_rows());
235 png_write_end(png_ptr, info_ptr);
238 png_destroy_write_struct(&png_ptr, &info_ptr);
241 char error[256]; png_error(png_ptr, error);
242 fprintf(stderr, "FilePNG::write_frame failed: %s\n", error);
244 //printf("FilePNG::write_frame 3 %d\n", data->get_compressed_size());
248 int FilePNG::read_frame(VFrame *output, VFrame *input)
252 png_infop end_info = 0;
257 int size = input->get_compressed_size();
258 input->set_compressed_size(0);
260 //printf("FilePNG::read_frame 1 %d %d\n", native_cmodel, output->get_color_model());
261 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
262 if(!png_ptr) return 0;
263 info_ptr = png_create_info_struct(png_ptr);
264 if(!info_ptr) return 0;
265 if (setjmp(png_jmpbuf(png_ptr))) {
266 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
269 png_set_read_fn(png_ptr, input, (png_rw_ptr)read_function);
270 png_read_info(png_ptr, info_ptr);
272 int png_color_type = png_get_color_type(png_ptr, info_ptr);
273 if( png_color_type == PNG_COLOR_TYPE_GRAY ||
274 png_color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
275 png_set_gray_to_rgb(png_ptr);
277 colormodel = output->get_color_model();
278 color_type = png_get_color_type(png_ptr, info_ptr);
279 color_depth = png_get_bit_depth(png_ptr,info_ptr);
282 png_get_tRNS(png_ptr, info_ptr, NULL, &num_trans, NULL);
284 native_cmodel = color_depth == 16 ?
285 ((color_type & PNG_COLOR_MASK_ALPHA) ?
286 BC_RGBA16161616 : BC_RGB161616) :
287 ((color_type & PNG_COLOR_MASK_ALPHA) || (num_trans > 0) ?
288 BC_RGBA8888 : BC_RGB888);
290 if( ((native_cmodel == BC_RGBA16161616) || (native_cmodel == BC_RGB161616)) &&
291 ((colormodel == BC_RGBA8888) || (colormodel == BC_RGB888)) )
292 png_set_strip_16(png_ptr);
294 // If we're dropping the alpha channel
295 if( !BC_CModels::has_alpha(colormodel) && BC_CModels::has_alpha(native_cmodel) ) {
296 png_color_16 my_background;
297 png_color_16p image_background;
298 memset(&my_background,0,sizeof(png_color_16));
299 // use the background color of the image
300 if( png_get_bKGD(png_ptr, info_ptr, &image_background) )
301 png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
303 // otherwise, use black
304 png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
306 else if( BC_CModels::has_alpha(colormodel) && !BC_CModels::has_alpha(native_cmodel) )
307 // If we're adding the alpha channel, alpha = max pixel value
308 png_set_add_alpha(png_ptr, BC_CModels::calculate_max(colormodel), PNG_FILLER_AFTER);
311 if( (color_depth == 16) &&
312 ((colormodel == BC_RGBA16161616) || (colormodel == BC_RGB161616)) )
313 png_set_swap(png_ptr);
315 if( !(color_type & PNG_COLOR_MASK_COLOR) )
316 png_set_gray_to_rgb(png_ptr);
318 if( color_type & PNG_COLOR_MASK_PALETTE )
319 png_set_palette_to_rgb(png_ptr);
321 if( color_depth <= 8 )
322 png_set_expand(png_ptr);
325 png_read_image(png_ptr, output->get_rows());
327 //printf("FilePNG::read_frame 3\n");
328 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
329 input->set_compressed_size(size);
330 //printf("FilePNG::read_frame 4\n");
334 FrameWriterUnit* FilePNG::new_writer_unit(FrameWriter *writer)
336 return new PNGUnit(this, writer);
340 PNGUnit::PNGUnit(FilePNG *file, FrameWriter *writer)
341 : FrameWriterUnit(writer)
348 if(temp_frame) delete temp_frame;
352 PNGConfigVideo::PNGConfigVideo(BC_WindowBase *parent_window, Asset *asset)
353 : BC_Window(_(PROGRAM_NAME ": Video Compression"),
354 parent_window->get_abs_cursor_x(1), parent_window->get_abs_cursor_y(1),
357 this->parent_window = parent_window;
363 // *** CONTEXT_HELP ***
364 context_help_set_keyword("Single File Rendering");
367 PNGConfigVideo::~PNGConfigVideo()
372 void PNGConfigVideo::create_objects()
374 lock_window("PNGConfigVideo::create_objects");
376 int xs5 = xS(5), ys5 = yS(5), xs10 = xS(10), ys10 = yS(10);
377 int x = xs10, y = ys10;
378 add_subwindow(use_alpha = new PNGUseAlpha(this, x, y));
379 y += use_alpha->get_h() + ys10;
380 add_subwindow(title = new BC_Title(x,y,_("Compression:")));
381 int x1 = x + title->get_w() + xs10;
382 compression = new PNGCompression(this, x1, y);
383 compression->create_objects();
384 y += compression->get_h() + ys5;
385 add_subwindow(title = new BC_Title(x,y,_("Depth:")));
386 x1 = x + title->get_w() + xs10;
387 add_subwindow(depth8 = new PNGDepth8bit(this, x1, y));
388 x1 += depth8->get_w() + xs5;
389 add_subwindow(depth16 = new PNGDepth16bit(this, x1, y));
390 add_subwindow(new BC_OKButton(this));
395 int PNGConfigVideo::close_event()
401 int PNGConfigVideo::update_depth(int depth)
403 asset->png_depth = depth;
404 depth8->update(depth == 8);
405 depth16->update(depth == 16);
410 PNGUseAlpha::PNGUseAlpha(PNGConfigVideo *gui, int x, int y)
411 : BC_CheckBox(x, y, gui->asset->png_use_alpha, _("Use alpha"))
416 int PNGUseAlpha::handle_event()
418 gui->asset->png_use_alpha = get_value();
422 PNGCompression::PNGCompression(PNGConfigVideo *gui, int x, int y)
423 : BC_TumbleTextBox(gui, (int64_t)gui->asset->png_compression,
424 (int64_t)0, (int64_t)9, x, y, xS(40))
429 int PNGCompression::handle_event()
431 gui->asset->png_compression = atol(get_text());
435 PNGDepth8bit::PNGDepth8bit(PNGConfigVideo *gui, int x, int y)
436 : BC_Radial(x, y, gui->asset->png_depth==8,_("8 Bit"))
441 int PNGDepth8bit::handle_event()
443 return gui->update_depth(8);
446 PNGDepth16bit::PNGDepth16bit(PNGConfigVideo *gui, int x, int y)
447 : BC_Radial(x, y, gui->asset->png_depth==16,_("16 Bit"))
452 int PNGDepth16bit::handle_event()
454 return gui->update_depth(16);