]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/scout-gfx/lib/png_image.cc
032ed40e6ef7edc18c118dff081f8df145089a16
[l4.git] / l4 / pkg / scout-gfx / lib / png_image.cc
1 /*
2  * \brief   PNG image element
3  * \date    2005-11-07
4  * \author  Norman Feske <norman.feske@genode-labs.com>
5  */
6
7 /*
8  * Copyright (C) 2005-2009
9  * Genode Labs, Feske & Helmuth Systementwicklung GbR
10  *
11  * This file is part of the Genode OS framework, which is distributed
12  * under the terms of the GNU General Public License version 2.
13  */
14
15 #include <png.h>
16
17 #include <l4/scout-gfx/png_image>
18
19 #include <l4/mag-gfx/canvas>
20 #include <l4/mag-gfx/factory>
21 #include <l4/mag-gfx/mem_texture>
22
23 using namespace Mag_gfx;
24 using namespace Scout_gfx;
25
26 namespace {
27 class Png_stream
28 {
29 private:
30
31   char *_addr;
32
33 public:
34
35   /**
36    * Constructor
37    */
38   Png_stream(char *addr) { _addr = addr; }
39
40   /**
41    * Read from png stream
42    */
43   void read(char *dst, int len)
44     {
45       memcpy(dst, _addr, len);
46       _addr += len;
47     }
48 };
49
50
51 /**
52  * PNG read callback
53  */
54 static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t len)
55 {
56   Png_stream *stream = (Png_stream *)png_get_io_ptr(png_ptr);
57
58   stream->read((char *)data, len);
59 }
60
61 }
62
63 /**
64  * Dummy to make libl4png happy
65  */
66 extern "C" int l4libpng_fread(void *, int, int, void *)
67 {
68   printf("l4libpng_fread called - function not implemented\n");
69   return 0;
70 }
71
72
73 /***********************
74  ** Element interface **
75  ***********************/
76
77 void Png_image::fill_cache(Mag_gfx::Pixel_info const *c)
78 {
79   if (_texture)
80     return;
81
82   Png_stream *stream = new Png_stream((char *)_png_data);
83
84   png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
85   if (!png_ptr) return;
86
87   png_set_read_fn(png_ptr, stream, user_read_data);
88
89   png_infop info_ptr = png_create_info_struct(png_ptr);
90   if (!info_ptr) {
91       png_destroy_read_struct(&png_ptr, NULL, NULL);
92       return;
93   }
94
95   png_read_info(png_ptr, info_ptr);
96
97   /* get image data chunk */
98   int bit_depth, color_type, interlace_type;
99   png_uint_32 w, h;
100   png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type,
101                &interlace_type, NULL, NULL);
102
103   _size = Area(w, h);
104
105   // printf("png[%p] : load -> sz=%d,%d\n", this, w, h);
106
107   if (color_type == PNG_COLOR_TYPE_PALETTE)
108     png_set_palette_to_rgb(png_ptr);
109
110   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
111     png_set_expand_gray_1_2_4_to_8(png_ptr);
112
113   if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
114     png_set_gray_to_rgb(png_ptr);
115
116   if (!(color_type & PNG_COLOR_MASK_ALPHA))
117     png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER);
118
119   png_set_bgr(png_ptr);
120
121   if (bit_depth < 8) png_set_packing(png_ptr);
122   if (bit_depth == 16) png_set_strip_16(png_ptr);
123
124   _texture = c->factory->create_texture(_size, 0, true);
125
126   /* allocate buffer for decoding a row */
127   static png_byte *row_ptr;
128   static int curr_row_size;
129
130   int needed_row_size = png_get_rowbytes(png_ptr, info_ptr)*8;
131
132   if (curr_row_size < needed_row_size)
133     {
134       if (row_ptr)
135         free(row_ptr);
136
137       row_ptr = (png_byte *)malloc(needed_row_size);
138       curr_row_size = needed_row_size;
139     }
140
141   Mem::Texture<Rgba32> tt((Rgba32::Pixel *)row_ptr, Area(_size.w(), 1));
142
143   /* fill texture */
144   for (int j = 0; j < _size.h(); j++)
145     {
146       png_read_row(png_ptr, row_ptr, NULL);
147       _texture->blit(&tt, j);
148     }
149   invalidate();
150 }
151
152
153 void Png_image::flush_cache(Mag_gfx::Pixel_info const *)
154 {
155   delete _texture;
156   _texture = 0;
157 }
158
159
160 void Png_image::draw(Canvas *c, Point const &p)
161 {
162   Rect cl = c->clip();
163   /* if texture is not ready, try to initialize it */
164   if (!_texture)
165     {
166       fill_cache(c->type());
167       refresh();
168       return;
169     }
170
171   /* draw texture */
172   if (_texture)
173     c->draw_texture(_texture, Rgb32::Black, p, Canvas::Alpha);
174 }