png.h
説明を見る。
1 //
2 // Copyright (c) 2003-2011, MIST Project, Nagoya University
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
14 //
15 // 3. Neither the name of the Nagoya University nor the names of its contributors
16 // may be used to endorse or promote products derived from this software
17 // without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
20 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 //
28 
36 #ifndef __INCLUDE_MIST_PNG__
37 #define __INCLUDE_MIST_PNG__
38 
39 
40 #ifndef __INCLUDE_MIST_H__
41 #include "../mist.h"
42 #endif
43 
44 // カラー画像の設定を読み込む
45 #ifndef __INCLUDE_MIST_COLOR_H__
46 #include "../config/color.h"
47 #endif
48 
49 #ifndef __INCLUDE_MIST_LIMITS__
50 #include "../limits.h"
51 #endif
52 
53 
54 #include <string>
55 
56 #include <png.h>
57 
58 // 以下のコードは libpng に付属のサンプルコード,および KATO 氏が http://www5.cds.ne.jp/~kato/png/ にて
59 // 掲載しているソースを参考に作成し,MISTで利用できるように独自の拡張を施したものである.
60 
61 
62 // mist名前空間の始まり
64 
65 
66 namespace __png_controller__
67 {
68  template < class T, class Allocator >
69  struct png_controller
70  {
71  typedef _pixel_converter_< T > pixel_converter;
72  typedef typename pixel_converter::color_type color_type;
73  typedef typename array2< T, Allocator >::size_type size_type;
74 
75  static bool read( array2< T, Allocator > &image, const std::string &filename )
76  {
77  FILE *fp = fopen( filename.c_str( ), "rb" ); // 読み込むPNG画像ファイルを開く
78  if( !fp )
79  {
80  return( false );
81  }
82 
83  // PNGの画像を読み込む際に,必要となる各種構造体を初期化する
84  png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
85  png_infop info_ptr = png_create_info_struct( png_ptr ); // png_infop 構造体を初期化する
86  png_init_io( png_ptr, fp ); // png_structp にファイルポインタを設定する
87  png_read_info( png_ptr, info_ptr ); // PNGファイルのヘッダを読み込む
88 
89 
90  png_uint_32 width, height;
91  png_colorp palette = NULL;
92  int bit_depth, color_type, interlace_type, npalette = 0;
93 
94  png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); // IHDRチャンク情報を取得する
95  png_get_PLTE( png_ptr, info_ptr, &palette, &npalette ); // パレット情報を取得する
96 
97  if( bit_depth < 8 )
98  {
99  png_set_packing( png_ptr );
100  }
101 
102  // カラーパレットをRGBに変換する
103  if( color_type == PNG_COLOR_TYPE_PALETTE )
104  {
105  png_set_palette_to_rgb( png_ptr );
106  }
107 
108  // 8ビット未満のグレースケールを8ビットに変換する
109  if( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 )
110  {
111  png_set_expand_gray_1_2_4_to_8( png_ptr );
112  }
113 
114  // アルファチャンネルを有効化する
115  if( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) )
116  {
117  png_set_tRNS_to_alpha( png_ptr );
118  }
119 
120  png_read_update_info( png_ptr, info_ptr );
121 
122  // IHDRチャンク情報を再度取得する
123  png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
124 
125  image.resize( width, height );
126 
127  bool ret = true;
128 
129  if( interlace_type == 0 )
130  {
131  // PNGの画像を操作するための一時配列を用意する
132  png_bytep png_buff = ( png_bytep )malloc( png_get_rowbytes( png_ptr, info_ptr ) );
133 
134  for( size_type j = 0 ; j < ( size_type )height ; j++ )
135  {
136  // 画像データを読み込む
137  png_read_rows( png_ptr, &png_buff, NULL, 1 );
138 
139  // 出力先のポインタ
140  typename array2< T, Allocator >::pointer op = &image( 0, j );
141 
142  // PNG に格納されている画像の形式に応じてデータを読み込む
143  switch( color_type )
144  {
145  case PNG_COLOR_TYPE_GRAY:
146  for( size_type i = 0 ; i < ( size_type )width ; i++ )
147  {
148  op[ i ] = pixel_converter::convert_to( png_buff[ i ], png_buff[ i ], png_buff[ i ] );
149  }
150  break;
151 
152  case PNG_COLOR_TYPE_RGB:
153  for( size_type i = 0 ; i < ( size_type )width ; i++ )
154  {
155  op[ i ] = pixel_converter::convert_to( png_buff[ i * 3 + 0 ], png_buff[ i * 3 + 1 ], png_buff[ i * 3 + 2 ] );
156  }
157  break;
158 
159  case PNG_COLOR_TYPE_RGBA:
160  for( size_type i = 0 ; i < ( size_type )width ; i++ )
161  {
162  op[ i ] = pixel_converter::convert_to( png_buff[ i * 4 + 0 ], png_buff[ i * 4 + 1 ], png_buff[ i * 4 + 2 ], png_buff[ i * 4 + 3 ] );
163  }
164  break;
165 
166  case PNG_COLOR_TYPE_GA:
167  for( size_type i = 0 ; i < ( size_type )width ; i++ )
168  {
169  op[ i ] = pixel_converter::convert_to( png_buff[ i * 2 ], png_buff[ i * 2 ], png_buff[ i * 2 ], png_buff[ i * 2 + 1 ] );
170  }
171  break;
172 
173  case PNG_COLOR_TYPE_PALETTE:
174  for( size_type i = 0 ; i < ( size_type )width ; i++ )
175  {
176  png_color &p = palette[ png_buff[ i ] ];
177  op[ i ] = pixel_converter::convert_to( p.red, p.green, p.blue );
178  }
179  break;
180 
181  default:
182  ret = false;
183  break;
184  }
185  }
186 
187  // 一時画像用に確保したメモリを開放する
188  free( png_buff );
189  }
190  else
191  {
192  // PNGの画像を操作するための一時配列を用意する
193  png_bytepp png_buff;
194  png_buff = ( png_bytepp )malloc( height * sizeof( png_bytep ) );
195  for( size_type i = 0 ; i < ( size_type )height ; i++ )
196  {
197  png_size_t nbytes = png_get_rowbytes( png_ptr, info_ptr );
198  png_buff[ i ] = ( png_bytep )malloc( nbytes );
199  }
200 
201  // 画像データを読み込む
202  png_read_image( png_ptr, png_buff );
203 
204  // PNG に格納されている画像の形式に応じてデータを読み込む
205  switch( color_type )
206  {
207  case PNG_COLOR_TYPE_GRAY:
208  for( size_type j = 0 ; j < ( size_type )height ; j++ )
209  {
210  for( size_type i = 0 ; i < ( size_type )width ; i++ )
211  {
212  image( i, j ) = pixel_converter::convert_to( png_buff[ j ][ i ], png_buff[ j ][ i ], png_buff[ j ][ i ] );
213  }
214  }
215  break;
216 
217  case PNG_COLOR_TYPE_RGB:
218  for( size_type j = 0 ; j < ( size_type )height ; j++ )
219  {
220  for( size_type i = 0 ; i < ( size_type )width ; i++ )
221  {
222  image( i, j ) = pixel_converter::convert_to( png_buff[ j ][ i * 3 + 0 ], png_buff[ j ][ i * 3 + 1 ], png_buff[ j ][ i * 3 + 2 ] );
223  }
224  }
225  break;
226 
227  case PNG_COLOR_TYPE_RGBA:
228  for( size_type j = 0 ; j < ( size_type )height ; j++ )
229  {
230  for( size_type i = 0 ; i < ( size_type )width ; i++ )
231  {
232  image( i, j ) = pixel_converter::convert_to( png_buff[ j ][ i * 4 + 0 ], png_buff[ j ][ i * 4 + 1 ], png_buff[ j ][ i * 4 + 2 ], png_buff[ j ][ i * 4 + 3 ] );
233  }
234  }
235  break;
236 
237  case PNG_COLOR_TYPE_GA:
238  for( size_type j = 0 ; j < ( size_type )height ; j++ )
239  {
240  for( size_type i = 0 ; i < ( size_type )width ; i++ )
241  {
242  image( i, j ) = pixel_converter::convert_to( png_buff[ j ][ i * 2 ], png_buff[ j ][ i * 2 ], png_buff[ j ][ i * 2 ], png_buff[ j ][ i * 2 + 1 ] );
243  }
244  }
245  break;
246 
247  case PNG_COLOR_TYPE_PALETTE:
248  for( size_type j = 0 ; j < ( size_type )height ; j++ )
249  {
250  for( size_type i = 0 ; i < ( size_type )width ; i++ )
251  {
252  png_color &p = palette[ png_buff[ j ][ i ] ];
253  image( i, j ) = pixel_converter::convert_to( p.red, p.green, p.blue );
254  }
255  }
256  break;
257 
258  default:
259  ret = false;
260  break;
261  }
262 
263  // 一時画像用に確保したメモリを開放する
264  for( size_type i = 0 ; i < ( size_type )height ; i++ )
265  {
266  free( png_buff[ i ] );
267  }
268  free( png_buff );
269  }
270 
271  // PNG の操作用に使用した構造体のメモリを解放する
272  png_destroy_read_struct( &png_ptr, &info_ptr, NULL );
273 
274  // PNG のファイルを閉じる
275  fclose( fp );
276 
277  return( ret );
278  }
279 
280  static bool write( const array2< T, Allocator > &image, const std::string &filename, int compression_level__ )
281  {
282  int compression_level = compression_level__ > 9 ? 9 : compression_level__;
283 
284  if( image.width( ) == 0 )
285  {
286  std::cerr << "Image width is zero!" << std::endl;
287  return( false );
288  }
289  else if( image.height( ) == 0 )
290  {
291  std::cerr << "Image height is zero!" << std::endl;
292  return( false );
293  }
294 
295  FILE *fp;
296  png_structp png_ptr;
297  png_infop info_ptr;
298  size_type width = image.width( );
299  size_type height = image.height( );
300 
301  if( ( fp = fopen( filename.c_str( ), "wb" ) ) == NULL )
302  {
303  return( false );
304  }
305 
306  png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
307  if( png_ptr == NULL )
308  {
309  fclose( fp );
310  return( false );
311  }
312 
313  info_ptr = png_create_info_struct( png_ptr );
314  if( info_ptr == NULL )
315  {
316  png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
317  fclose( fp );
318  return( false );
319  }
320  if( setjmp( png_jmpbuf( png_ptr ) ) )
321  {
322  png_destroy_write_struct( &png_ptr, &info_ptr );
323  fclose( fp );
324  return( false );
325  }
326 
327  if( compression_level > 9 ) compression_level = 9;
328 
329  png_init_io( png_ptr, fp );
330  //png_set_write_status_fn(png_ptr, write_row_callback);
331  png_set_filter( png_ptr, 0, PNG_ALL_FILTERS );
332  if( compression_level < 0 )
333  {
334  png_set_compression_level( png_ptr, 6 );
335  }
336  else
337  {
338  png_set_compression_level( png_ptr, compression_level );
339  }
340 
341  int png_color_type = pixel_converter::color_num == 4 ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB;
342  png_set_IHDR( png_ptr, info_ptr, static_cast< png_uint_32 >( width ), static_cast< png_uint_32 >( height ), 8, png_color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT );
343  png_set_gAMA( png_ptr, info_ptr, 1.0 );
344 
345  {
346  time_t gmt;
347  png_time mod_time;
348  png_text text_ptr[5];
349 
350  time( &gmt );
351  png_convert_from_time_t( &mod_time, gmt );
352  png_set_tIME( png_ptr, info_ptr, &mod_time );
353 
354  static char text[][64] = {
355  "Title",
356  "MIST PNG Library",
357  "Author",
358  "",
359  "Description",
360  "Created by using MIST library",
361  "Creation Time",
362  "Software",
363  "MIST PNG converter",
364  };
365 
366  text_ptr[ 0 ].key = text[ 0 ];
367  text_ptr[ 0 ].text = text[ 1 ];
368  text_ptr[ 0 ].compression = PNG_TEXT_COMPRESSION_NONE;
369  text_ptr[ 1 ].key = text[ 2 ];
370  text_ptr[ 1 ].text = text[ 3 ];
371  text_ptr[ 1 ].compression = PNG_TEXT_COMPRESSION_NONE;
372  text_ptr[ 2 ].key = text[ 4 ];
373  text_ptr[ 2 ].text = text[ 5 ];
374  text_ptr[ 2 ].compression = PNG_TEXT_COMPRESSION_NONE;
375  text_ptr[ 3 ].key = text[ 6 ];
376  text_ptr[ 3 ].text = ( png_charp )png_convert_to_rfc1123( png_ptr, &mod_time );
377  text_ptr[ 3 ].compression = PNG_TEXT_COMPRESSION_NONE;
378  text_ptr[ 4 ].key = text[ 7 ];
379  text_ptr[ 4 ].text = text[ 8 ];
380  text_ptr[ 4 ].compression = PNG_TEXT_COMPRESSION_NONE;
381  png_set_text( png_ptr, info_ptr, text_ptr, 5 );
382  }
383 
384  png_write_info( png_ptr, info_ptr );
385 
386  if( pixel_converter::color_num == 4 )
387  {
388  png_bytep png_buff = new png_byte[ width * 4 ];
389  for( size_type j = 0 ; j < height ; j++ )
390  {
391  typename array2< T, Allocator >::const_pointer ip = &image( 0, j );
392  for( size_type i = 0 ; i < width ; i++ )
393  {
394  color_type c = limits_0_255( pixel_converter::convert_from( ip[ i ] ) );
395  png_buff[ i * 4 + 0 ] = static_cast< png_byte >( c.r );
396  png_buff[ i * 4 + 1 ] = static_cast< png_byte >( c.g );
397  png_buff[ i * 4 + 2 ] = static_cast< png_byte >( c.b );
398  png_buff[ i * 4 + 3 ] = static_cast< png_byte >( c.a );
399  }
400 
401  png_write_rows( png_ptr, &png_buff, 1 );
402  }
403 
404  delete [] png_buff;
405  }
406  else
407  {
408  png_bytep png_buff = new png_byte[ width * 4 ];
409  for( size_type j = 0 ; j < height ; j++ )
410  {
411  typename array2< T, Allocator >::const_pointer ip = &image( 0, j );
412  for( size_type i = 0 ; i < width ; i++ )
413  {
414  color_type c = limits_0_255( pixel_converter::convert_from( ip[ i ] ) );
415  png_buff[ i * 3 + 0 ] = static_cast< png_byte >( c.r );
416  png_buff[ i * 3 + 1 ] = static_cast< png_byte >( c.g );
417  png_buff[ i * 3 + 2 ] = static_cast< png_byte >( c.b );
418  }
419 
420  png_write_rows( png_ptr, &png_buff, 1 );
421  }
422 
423  delete [] png_buff;
424  }
425 
426  png_write_end( png_ptr, info_ptr );
427  png_destroy_write_struct( &png_ptr, &info_ptr );
428  fclose( fp );
429 
430  return( true );
431  }
432  };
433 }
434 
435 
438 
450 
451 
462 template < class T, class Allocator >
463 bool read_png( array2< T, Allocator > &image, const std::string &filename )
464 {
465  return( __png_controller__::png_controller< T, Allocator >::read( image, filename ) );
466 }
467 
468 
479 template < class T, class Allocator >
480 bool read_png( array2< T, Allocator > &image, const std::wstring &filename )
481 {
482  return( read_png( image, wstr2str( filename ) ) );
483 }
484 
485 
497 template < class T, class Allocator >
498 bool write_png( const array2< T, Allocator > &image, const std::string &filename, int compression_level = 6 )
499 {
500  return( __png_controller__::png_controller< T, Allocator >::write( image, filename, compression_level ) );
501 }
502 
503 
515 template < class T, class Allocator >
516 bool write_png( const array2< T, Allocator > &image, const std::wstring &filename, int compression_level = 6 )
517 {
518  return( write_png( image, wstr2str( filename ), compression_level ) );
519 }
520 
521 
523 // PNG 画像入出力グループの終わり
524 
526 // 画像入出力グループの終わり
527 
528 
529 // mist名前空間の終わり
530 _MIST_END
531 
532 
533 #endif // __INCLUDE_MIST_PNG__
534 

Generated on Wed Nov 12 2014 19:44:21 for MIST by doxygen 1.8.1.2