Claw  1.7.3
png_writer.cpp
Go to the documentation of this file.
1 /*
2  CLAW - a C++ Library Absolutely Wonderful
3 
4  CLAW is a free library without any particular aim but being useful to
5  anyone.
6 
7  Copyright (C) 2005-2011 Julien Jorge
8 
9  This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Lesser General Public
11  License as published by the Free Software Foundation; either
12  version 2.1 of the License, or (at your option) any later version.
13 
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public
20  License along with this library; if not, write to the Free Software
21  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 
23  contact: julien.jorge@gamned.org
24 */
30 #include <claw/png.hpp>
31 
32 #include <claw/exception.hpp>
33 #include <claw/assert.hpp>
34 
35 /*----------------------------------------------------------------------------*/
43 ( png_structp png_ptr, png_bytep data, png_size_t length )
44 {
46  (claw::graphic::png::writer::target_manager*)png_get_io_ptr(png_ptr);
47 
48  self->write(data, length);
49 } // claw__graphic__png__target_manager__write()
50 
51 /*----------------------------------------------------------------------------*/
56 void claw__graphic__png__target_manager__flush( png_structp png_ptr )
57 {
59  (claw::graphic::png::writer::target_manager*)png_get_io_ptr(png_ptr);
60 
61  self->flush();
62 } // claw__graphic__png__target_manager__write()
63 
64 
65 
66 
67 /*----------------------------------------------------------------------------*/
73  : m_output(os)
74 {
75  CLAW_PRECOND( !!os );
76 } // png::writer::target_manager::target_manager()
77 
78 /*----------------------------------------------------------------------------*/
85 ( png_bytep data, png_size_t length )
86 {
87  m_output.write( (char*)data, length * sizeof(png_byte) );
88 } // png::writer::target_manager::write()
89 
90 /*----------------------------------------------------------------------------*/
95 {
96  m_output.flush();
97 } // png::writer::target_manager::flush()
98 
99 
100 
101 
102 /*----------------------------------------------------------------------------*/
107  : compression(default_compression), interlace(none)
108 {
109 
110 } // png::writer::options::options()
111 
112 /*----------------------------------------------------------------------------*/
119 ( compression_level compression_level_, interlace_type interlace_ )
120  : compression(compression_level_), interlace(interlace_)
121 {
122 
123 } // png::writer::options::options()
124 
125 
126 
127 
128 /*----------------------------------------------------------------------------*/
129 const unsigned int claw::graphic::png::writer::s_rgba_pixel_size = 4;
130 
131 /*----------------------------------------------------------------------------*/
137  : m_image( img )
138 {
139 
140 } // png::writer::writer()
141 
142 /*----------------------------------------------------------------------------*/
150 ( const image& img, std::ostream& f, const options& opt )
151  : m_image( img )
152 {
153  save(f, opt);
154 } // png::writer::writer()
155 
156 /*----------------------------------------------------------------------------*/
162 void
163 claw::graphic::png::writer::save( std::ostream& f, const options& opt ) const
164 {
165  CLAW_PRECOND( !!f );
166 
167  target_manager outfile(f);
168  png_structp png_ptr;
169  png_infop info_ptr;
170 
171  create_write_structures(png_ptr, info_ptr);
172 
173  if (setjmp(png_jmpbuf(png_ptr)))
174  {
175  /* If we get here, we had a problem reading the file */
176  /* Free all of the memory associated with the png_ptr and info_ptr */
177  png_destroy_write_struct(&png_ptr, &info_ptr);
178  throw CLAW_EXCEPTION("Invalid PNG file.");
179  }
180 
181  png_set_write_fn( png_ptr, (void *)&outfile,
184 
185  set_options( png_ptr, info_ptr, opt );
186  save_image( png_ptr, info_ptr );
187 
188  png_destroy_write_struct(&png_ptr, &info_ptr);
189 } // png::writer::save()
190 
191 /*----------------------------------------------------------------------------*/
198 void claw::graphic::png::writer::set_options
199 ( png_structp png_ptr, png_infop info_ptr, const options& opt ) const
200 {
201  CLAW_PRECOND( png_ptr );
202  CLAW_PRECOND( info_ptr );
203 
204  png_set_compression_level( png_ptr, opt.compression );
205 
206  png_set_IHDR( png_ptr, info_ptr, m_image.width(), m_image.height(),
207  sizeof(pixel_type::component_type) * 8, /* 8 bits per byte */
208  PNG_COLOR_TYPE_RGB_ALPHA,
209  opt.interlace, PNG_COMPRESSION_TYPE_DEFAULT,
210  PNG_FILTER_TYPE_DEFAULT );
211 } // png::writer::set_options()
212 
213 /*----------------------------------------------------------------------------*/
219 void claw::graphic::png::writer::save_image
220 ( png_structp png_ptr, png_infop info_ptr ) const
221 {
222  CLAW_PRECOND( png_ptr );
223  CLAW_PRECOND( info_ptr );
224 
225  const unsigned int row_length = s_rgba_pixel_size * m_image.width();
226  png_bytepp data =
227  (png_bytepp)png_malloc( png_ptr, sizeof(png_bytep) * m_image.height() );
228  unsigned int i=0;
229 
230  try
231  {
232  for (i=0; i!=m_image.height(); ++i)
233  {
234  data[i] = (png_bytep)png_malloc( png_ptr, row_length );
235 
236  if (!data[i])
237  throw std::bad_alloc();
238 
239  copy_pixel_line( data[i], i );
240  }
241 
242  png_set_rows(png_ptr, info_ptr, data);
243  png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
244  }
245  catch(...)
246  {
247  for(unsigned int j=0; j!=i; ++j)
248  png_free(png_ptr, data[j]);
249 
250  png_free(png_ptr, data);
251  throw;
252  }
253 
254  for(i=0; i!=m_image.height(); ++i)
255  png_free(png_ptr, data[i]);
256 
257  png_free(png_ptr, data);
258 } // png::writer::save_image()
259 
260 /*----------------------------------------------------------------------------*/
267 void claw::graphic::png::writer::copy_pixel_line
268 ( png_bytep data, unsigned int y ) const
269 {
270  CLAW_PRECOND( data );
271  CLAW_PRECOND( y < m_image.height() );
272 
273  // four bytes for each pixel in the line
274  for (unsigned int x=0; x!=m_image.width(); ++x, data+=s_rgba_pixel_size)
275  {
276  data[0] = m_image[y][x].components.red;
277  data[1] = m_image[y][x].components.green;
278  data[2] = m_image[y][x].components.blue;
279  data[3] = m_image[y][x].components.alpha;
280  }
281 } // png::writer::copy_pixel_line()
282 
283 /*----------------------------------------------------------------------------*/
289 void claw::graphic::png::writer::create_write_structures
290 ( png_structp& png_ptr, png_infop& info_ptr ) const
291 {
292  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
293 
294  if (png_ptr)
295  {
296  info_ptr = png_create_info_struct(png_ptr);
297 
298  if (!info_ptr)
299  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
300  }
301 
302  if (!png_ptr || !info_ptr)
303  throw CLAW_EXCEPTION("Can't create PNG write structures.");
304 } // png::writer::create_write_structures()