/* * \brief PNG image element * \date 2005-11-07 * \author Norman Feske */ /* * Copyright (C) 2005-2013 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ #include #include #include #include "elements.h" using namespace Scout; class Png_stream { private: char *_addr; public: /** * Constructor */ Png_stream(char *addr) { _addr = addr; } /** * Read from png stream */ void read(char *dst, int len) { Scout::memcpy(dst, _addr, len); _addr += len; } }; /** * PNG read callback */ static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t len) { Png_stream *stream = (Png_stream *)png_get_io_ptr(png_ptr); stream->read((char *)data, len); } /** * Dummy to make libl4png happy */ extern "C" int l4libpng_fread(void *buf, int size, int nmemb, void *stream) { printf("l4libpng_fread called - function not implemented\n"); return 0; } /*********************** ** Element interface ** ***********************/ void Png_image::fill_cache(Canvas_base &canvas) { if (_texture) return; Png_stream *stream = new Png_stream((char *)_png_data); png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png_ptr) return; png_set_read_fn(png_ptr, stream, user_read_data); png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return; } png_read_info(png_ptr, info_ptr); /* get image data chunk */ int bit_depth, color_type, interlace_type; png_uint_32 w, h; png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); _min_size = Scout::Area(w, h); printf("png is %d x %d, depth=%d\n", _min_size.w(), _min_size.h(), bit_depth); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); _texture = canvas.alloc_texture(_min_size, true); /* allocate buffer for decoding a row */ static png_byte *row_ptr; static int curr_row_size; int needed_row_size = png_get_rowbytes(png_ptr, info_ptr)*8; if (curr_row_size < needed_row_size) { if (row_ptr) Scout::free(row_ptr); row_ptr = (png_byte *)Scout::malloc(needed_row_size); curr_row_size = needed_row_size; } /* fill texture */ for (unsigned j = 0; j < _min_size.h(); j++) { png_read_row(png_ptr, row_ptr, NULL); canvas.set_rgba_texture(_texture, (unsigned char *)row_ptr, _min_size.w(), j); } } void Png_image::flush_cache(Canvas_base &canvas) { canvas.free_texture(_texture); _texture = 0; } void Png_image::draw(Canvas_base &canvas, Point abs_position) { /* if texture is not ready, try to initialize it */ if (!_texture) fill_cache(canvas); /* draw texture */ if (_texture) canvas.draw_texture(abs_position + _position, *_texture); }