The Pedigree Project  0.1
applications/winman/Png.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "Png.h"
21 
22 #include <sys/klog.h>
23 #include <unistd.h>
24 
25 Png::Png(const char *filename)
26  : m_PngPtr(0), m_InfoPtr(0), m_nWidth(0), m_nHeight(0), m_pRowPointers(0)
27 {
28  // Open the file.
29  FILE *stream = fopen(filename, "rb");
30  if (!stream)
31  {
32  klog(LOG_ALERT, "PNG file failed to open");
33  return;
34  }
35 
36  // Read in some of the signature bytes.
37  char buf[4];
38  if (fread(buf, 1, 4, stream) != 4)
39  {
40  klog(LOG_ALERT, "PNG file failed to read ident");
41  fclose(stream);
42  return;
43  }
44  if (png_sig_cmp(reinterpret_cast<png_byte *>(buf), 0, 4) != 0)
45  {
46  klog(LOG_ALERT, "PNG file failed IDENT check");
47  fclose(stream);
48  return;
49  }
50 
51  m_PngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
52 
53  if (m_PngPtr == 0)
54  {
55  klog(LOG_ALERT, "PNG file failed to initialise");
56  fclose(stream);
57  return;
58  }
59 
60  m_InfoPtr = png_create_info_struct(m_PngPtr);
61  if (m_InfoPtr == 0)
62  {
63  klog(LOG_ALERT, "PNG info failed to initialise");
64  png_destroy_read_struct(&m_PngPtr, NULL, NULL);
65  fclose(stream);
66  return;
67  }
68 
69  png_init_io(m_PngPtr, stream);
70 
71  png_set_sig_bytes(m_PngPtr, 4);
72 
73  png_set_palette_to_rgb(m_PngPtr);
74 
75  png_read_png(
76  m_PngPtr, m_InfoPtr,
77  PNG_TRANSFORM_STRIP_16 | // 16-bit-per-channel down to 8.
78  PNG_TRANSFORM_STRIP_ALPHA | // No alpha
79  PNG_TRANSFORM_PACKING, // Unpack 2 and 4 bit samples.
80  reinterpret_cast<void *>(0));
81 
82  m_pRowPointers = png_get_rows(m_PngPtr, m_InfoPtr);
83 
84  // Grab the info header information.
85  int bit_depth, color_type, interlace_type, compression_type, filter_method;
86  png_uint_32 w, h;
87  png_get_IHDR(
88  m_PngPtr, m_InfoPtr, &w, &h, &bit_depth, &color_type, &interlace_type,
89  &compression_type, &filter_method);
90  m_nWidth = w;
91  m_nHeight = h;
92 
94  if (bit_depth != 8)
95  {
96  klog(LOG_ALERT, "PNG - invalid bit depth");
97  return;
98  }
99  if (color_type != PNG_COLOR_TYPE_RGB)
100  {
101  klog(LOG_ALERT, "PNG - invalid colour type: %d", color_type);
102  return;
103  }
104 
105  m_pBitmap = (uint32_t *) malloc(4 * w * h);
106  size_t x, y;
107  for (y = 0; y < m_nHeight; ++y)
108  {
109  png_byte *row = m_pRowPointers[y];
110  for (x = 0; x < m_nWidth; ++x)
111  {
112  png_byte *ptr = &(row[x * 3]);
113  m_pBitmap[(y * m_nWidth) + x] =
114  (ptr[0] << 16) | (ptr[1] << 8) | (ptr[2]);
115  }
116  }
117 
118  png_destroy_read_struct(&m_PngPtr, &m_InfoPtr, NULL);
119 
120  fclose(stream);
121 
122  klog(LOG_INFO, "PNG loaded %zd %zd", m_nWidth, m_nHeight);
123 }
124 
125 Png::~Png()
126 {
127 }
128 
129 void Png::render(cairo_t *cr, size_t x, size_t y, size_t width, size_t height)
130 {
131  cairo_surface_t *surface = cairo_image_surface_create_for_data(
132  (uint8_t *) m_pBitmap, CAIRO_FORMAT_RGB24, m_nWidth, m_nHeight,
133  m_nWidth * 4);
134 
135  cairo_save(cr);
136  cairo_identity_matrix(cr);
137  cairo_translate(cr, x, y);
138  cairo_scale(cr, width / (double) m_nWidth, height / (double) m_nHeight);
139  cairo_set_source_surface(cr, surface, 0, 0);
140  cairo_paint(cr);
141  cairo_restore(cr);
142 
143  cairo_surface_destroy(surface);
144 }
145 
146 void Png::renderPartial(
147  cairo_t *cr, size_t atX, size_t atY, size_t innerX, size_t innerY,
148  size_t partialWidth, size_t partialHeight, size_t scaleWidth,
149  size_t scaleHeight)
150 {
151  cairo_surface_t *surface = cairo_image_surface_create_for_data(
152  (uint8_t *) m_pBitmap, CAIRO_FORMAT_RGB24, m_nWidth, m_nHeight,
153  m_nWidth * 4);
154 
155  cairo_save(cr);
156 
157  cairo_rectangle(cr, atX, atY, partialWidth, partialHeight);
158  cairo_clip(cr);
159  cairo_new_path(cr);
160 
161  cairo_identity_matrix(cr);
162  cairo_scale(
163  cr, scaleWidth / (double) m_nWidth, scaleHeight / (double) m_nHeight);
164  cairo_translate(cr, innerX, innerY);
165  cairo_set_source_surface(cr, surface, 0, 0);
166  cairo_paint(cr);
167  cairo_restore(cr);
168 
169  cairo_surface_destroy(surface);
170 }
Png(const char *filename)