- メインページ
- モジュール
- ネームスペース
- データ構造
- ファイル

- ファイル一覧
- グローバル

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名前空間の始まり
63 _MIST_BEGIN
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