OSDN Git Service

first
[psychlops/cpp.git] / psychlops / extension / FileFormat / PNG / psychlops_g_PNG_bridge.cpp
1 /*
2  *  psychlops_g_PNG_bridge.cpp
3  *  Psychlops Standard Library (Universal)
4  *
5  *  Last Modified 2006/08/22 by Kenchi HOSOKAWA
6  *  (C) 2006- Kenchi HOSOKAWA, Kazushi MARUYA and Takao SATO
7  */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include "png.h"
12
13 #include "../../../core/ApplicationInterfaces/psychlops_code_exception.h"
14 #include "../../../core/graphic/psychlops_g_image.h"
15 #include "psychlops_g_PNG_bridge.h"
16
17
18 namespace Psychlops {
19 namespace IMAGE_FORMATS {
20
21
22         PNG_BRIDGE::PNG_BRIDGE() {
23                 is_opened_ = false;
24         }
25         PNG_BRIDGE::~PNG_BRIDGE() {
26                 close();
27         }
28
29
30         void PNG_BRIDGE::load(const char *file_name, Image * target) {
31                 open(file_name, "rb");
32
33                 check_before_read();
34                 read(target);
35
36                 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
37         }
38         void PNG_BRIDGE::save(const char *file_name, Image * target) {
39                 open(file_name, "wb");
40
41                 prepare_before_write();
42                 write(target);
43
44
45                 png_destroy_write_struct(&png_ptr, &info_ptr);
46         }
47         void PNG_BRIDGE::open(const char *file_name, const char *mode) {
48                 if(!is_opened_)
49                         if ((fp = fopen(file_name, mode)) == NULL)
50                                         throw Exception(typeid(*this), "FILE ACCESS ERROR", "Failed to open the requested file.");
51                 is_opened_ = true;
52         }
53         void PNG_BRIDGE::close() {
54                 if(is_opened_) fclose(fp);
55                 is_opened_ = false;
56         }
57
58
59         void PNG_BRIDGE::check_before_read() {
60                 png_byte sig[PNG_BYTES_TO_CHECK];
61
62                 if (fread(sig, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK) {
63                         close();
64                         throw Exception(typeid(*this), "FILE FORMAT ERROR", "The requested file is not PNG.");
65                 }
66                 if (!png_check_sig(sig, PNG_BYTES_TO_CHECK)) {
67                         close();
68                         throw Exception(typeid(*this), "FILE FORMAT ERROR", "The requested file is not PNG.");
69                 }
70                 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
71                 if (!png_ptr) {
72                         close();
73                         throw Exception(typeid(*this), "FILE FORMAT ERROR", "The requested file is not PNG.");
74                 }
75                 info_ptr = png_create_info_struct(png_ptr);
76                 if (!info_ptr) {
77                         png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
78                         close();
79                         throw Exception(typeid(*this), "FILE FORMAT ERROR", "The requested file is not PNG.");
80                 }
81                 end_info_ptr = png_create_info_struct(png_ptr);
82                 if (!end_info_ptr) {
83                         png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
84                         close();
85                         throw Exception(typeid(*this), "FILE FORMAT ERROR", "The requested file is not PNG.");
86                 }
87                 if (setjmp(png_jmpbuf(png_ptr))) {
88                         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr);
89                         close();
90                         throw Exception(typeid(*this), "FILE FORMAT ERROR", "The requested file is not PNG.");
91                 }
92                 png_init_io(png_ptr, fp);
93                 png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
94                 png_read_info(png_ptr, info_ptr);
95         }
96
97         void PNG_BRIDGE::read(Image * target) {
98                 unsigned int width = png_get_image_width(png_ptr, info_ptr);
99                 unsigned int height = png_get_image_height(png_ptr, info_ptr);
100                 Image::PixelComponentsCnt pix_component;
101                 switch (png_get_color_type(png_ptr, info_ptr)) {
102                         case PNG_COLOR_TYPE_GRAY:
103                                 pix_component = Image::GRAY;
104                                 break;
105                         case PNG_COLOR_TYPE_RGB:
106                                 pix_component = Image::RGB;
107                                 break;
108                         case PNG_COLOR_TYPE_RGB_ALPHA:
109                                 pix_component = Image::RGBA;
110                                 break;
111                         default:
112                                 pix_component = Image::RGBA;
113                                 break;
114                 }
115                 png_bytep *row_pointers = new png_bytep[height];
116
117                 target->set(width, height, pix_component);
118                 readTargetMemoryAlignment(target);
119                 for(unsigned int i=0; i<height; i++) row_pointers[i] = target_bitmap_ub_ + (height-i-1)*(target_bytes_per_line_);
120
121                 png_read_image(png_ptr, row_pointers);
122                 png_read_end(png_ptr, end_info_ptr);
123                 delete [] row_pointers;
124         }
125
126
127
128
129         void PNG_BRIDGE::prepare_before_write() {
130                 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
131                 if (!png_ptr) {
132                         close();
133                         throw Exception(typeid(*this), "FILE FORMAT ERROR", "The requested data is not able to be put as a PNG file.");
134                 }
135                 info_ptr = png_create_info_struct(png_ptr);
136                 if (!info_ptr) {
137                         png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
138                         close();
139                         throw Exception(typeid(*this), "FILE FORMAT ERROR", "The requested data is not able to be put as a PNG file.");
140                 }
141                 if (setjmp(png_jmpbuf(png_ptr))) {
142                         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr);
143                         close();
144                         throw Exception(typeid(*this), "FILE FORMAT ERROR", "The requested data is not able to be put as a PNG file.");
145                 }
146                 png_init_io(png_ptr, fp);
147                 png_set_write_status_fn(png_ptr, NULL); //callback_function_per_row(png_ptr, png_uint_32 row, int pass)
148         }
149
150         void PNG_BRIDGE::write(Image * target) {
151                 readTargetMemoryAlignment(target);
152
153                 unsigned int width = (unsigned int)target->getWidth();
154                 unsigned int height = (unsigned int)target->getHeight();
155
156                 int color_type;
157                 switch (pix_components_) {
158                         case Image::GRAY:
159                                 color_type = PNG_COLOR_TYPE_GRAY;
160                                 break;
161                         case Image::RGB:
162                                 color_type = PNG_COLOR_TYPE_RGB;
163                                 break;
164                         case Image::RGBA:
165                                 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
166                                 break;
167                         default:
168                                 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
169                                 break;
170                 }
171
172                 unsigned int bit_depth;
173                 switch(pix_precision_) {
174                         case Image::FLOAT:
175                                 throw Exception(typeid(*this), "FILE FORMAT ERROR", "The requested data is not able to be put as a PNG file.");
176                                 break;
177                         case Image::BYTE:
178                                 bit_depth = 8;
179                                 break;
180                         default:
181                                 bit_depth = 8;
182                                 break;
183                 }
184
185                 int interlace_type = PNG_INTERLACE_NONE;
186                 int compression_type = PNG_COMPRESSION_TYPE_DEFAULT;
187                 int filter_method = PNG_FILTER_TYPE_DEFAULT;
188
189                 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type, compression_type, filter_method);
190
191
192                 png_write_info(png_ptr, info_ptr);
193
194                 png_bytep *row_pointers = new png_bytep[height];
195                 for(unsigned int i=0; i<height; i++) row_pointers[i] = target_bitmap_ub_ + (height-i-1)*(target_bytes_per_line_);
196                 png_write_image(png_ptr, row_pointers);
197
198                 png_write_end(png_ptr, NULL);
199                 delete [] row_pointers;
200         }
201
202
203 }
204 }