00001
00005 #include "Image.h"
00006 #include <fstream>
00007 #include <iostream>
00008 #include <stdio.h>
00009 #include <stdlib.h>
00010 #include <stdarg.h>
00011 #include <png.h>
00012
00013 using namespace std;
00014
00015 static void error(const std::string& filename, const std::string& errtext)
00016 {
00017 cerr << "Error reading image: " << filename << ": " << errtext << '\n';
00018 exit(1);
00019 }
00020
00021 Image::Image(const std::string& filename)
00022 {
00023 cerr << "Reading " << filename << "...";
00024
00025 size_t found = filename.rfind(".png");
00026 if (found != string::npos) {
00027
00028
00029 read_png_file(filename.c_str(), xres, yres);
00030
00031 return;
00032 }
00033
00034
00035 ifstream in(filename.c_str(), ios::in | ios::binary);
00036 if(!in)
00037 error(filename, "Error opening file");
00038 if(in.get() != 'P' || !in)
00039 error(filename, "Error reading magic number (1st digit)");
00040 if(in.get() != '6' || !in)
00041 error(filename, "Error reading magic number (2nd digit)");
00042 int maxValue;
00043 in >> xres >> yres >> maxValue;
00044 in.get();
00045 cerr << " " << xres << "x" << yres << "...";
00046 if(!in)
00047 error(filename, "Error reading metadaa");
00048 data = new Pixel*[yres];
00049 Pixel* p = new Pixel[xres*yres];
00050 for(int i=0;i<yres;i++)
00051 data[i] = p + i*xres;
00052 for(int i=yres-1;i>=0;i--)
00053 in.read(reinterpret_cast<char*>(data[i]), sizeof(Pixel)*xres);
00054 if(!in)
00055 error(filename, "Error reading pixels");
00056 cerr << " done\n";
00057 }
00058
00059
00060 Image::Image(int xres, int yres)
00061 : xres(xres), yres(yres)
00062 {
00063 data = new Pixel*[yres];
00064 Pixel* p = new Pixel[xres*yres];
00065 for(int i=0;i<yres;i++)
00066 data[i] = p + i*xres;
00067 }
00068
00069 Image::~Image()
00070 {
00071 delete[] data[0];
00072 delete[] data;
00073 }
00074
00075
00076 void abort_(const char * s, ...)
00077 {
00078 va_list args;
00079 va_start(args, s);
00080 vfprintf(stderr, s, args);
00081 fprintf(stderr, "\n");
00082 va_end(args);
00083 abort();
00084 }
00085
00086
00087 void Image::write_png_file(const char* file_name, int width, int height) const
00088 {
00089 png_structp png_ptr;
00090 png_infop info_ptr;
00091 png_byte color_type = PNG_COLOR_TYPE_RGB;
00092 png_byte bit_depth = 8;
00093
00094
00095
00096 FILE *fp = fopen(file_name, "wb");
00097 if (!fp)
00098 abort_("[write_png_file] File %s could not be opened for writing", file_name);
00099
00100
00101
00102 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00103
00104 if (!png_ptr)
00105 abort_("[write_png_file] png_create_write_struct failed");
00106
00107 info_ptr = png_create_info_struct(png_ptr);
00108 if (!info_ptr)
00109 abort_("[write_png_file] png_create_info_struct failed");
00110
00111 if (setjmp(png_jmpbuf(png_ptr)))
00112 abort_("[write_png_file] Error during init_io");
00113
00114 png_init_io(png_ptr, fp);
00115
00116
00117
00118 if (setjmp(png_jmpbuf(png_ptr)))
00119 abort_("[write_png_file] Error during writing header");
00120
00121 png_set_IHDR(png_ptr, info_ptr, width, height,
00122 bit_depth, color_type, PNG_INTERLACE_NONE,
00123 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
00124
00125 png_write_info(png_ptr, info_ptr);
00126
00127
00128
00129 if (setjmp(png_jmpbuf(png_ptr)))
00130 abort_("[write_png_file] Error during writing bytes");
00131
00132
00133 png_bytep *row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * height);
00134 for (int y=0 ; y < height ; y++)
00135 row_pointers[(height-1)-y] = (png_bytep) &data[y][0];
00136
00137 png_write_image(png_ptr, row_pointers);
00138
00139
00140
00141 if (setjmp(png_jmpbuf(png_ptr)))
00142 abort_("[write_png_file] Error during end of write");
00143
00144 png_write_end(png_ptr, NULL);
00145
00146
00147
00148
00149 free(row_pointers);
00150
00151 fclose(fp);
00152 }
00153
00154 void Image::write(const std::string& filename) const
00155 {
00156 #if 0
00157 std::ofstream out(filename.c_str(), std::ios::out | std::ios::binary);
00158 out << "P6 " << xres << " " << yres << " 255\n";
00159 for(int i=yres-1;i>=0;i--)
00160 out.write(reinterpret_cast<char*>(data[i]), sizeof(Pixel)*xres);
00161 #else
00162 write_png_file(filename.c_str(), xres, yres);
00163 #endif
00164
00165 }
00166
00167 void Image::read_png_file(const char* file_name, int &width, int &height)
00168 {
00169 png_structp png_ptr;
00170 png_infop info_ptr;
00171 png_byte color_type = PNG_COLOR_TYPE_RGB;
00172 png_byte bit_depth = 8;
00173
00174 char header[8];
00175
00176
00177 FILE *fp = fopen(file_name, "rb");
00178 if (!fp)
00179 abort_("[read_png_file] File %s could not be opened for reading", file_name);
00180 fread(header, 1, 8, fp);
00181 if (png_sig_cmp((png_byte *)header, 0, 8))
00182 abort_("[read_png_file] File %s is not recognized as a PNG file", file_name);
00183
00184
00185
00186 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00187
00188 if (!png_ptr)
00189 abort_("[read_png_file] png_create_read_struct failed");
00190
00191 info_ptr = png_create_info_struct(png_ptr);
00192 if (!info_ptr)
00193 abort_("[read_png_file] png_create_info_struct failed");
00194
00195 if (setjmp(png_jmpbuf(png_ptr)))
00196 abort_("[read_png_file] Error during init_io");
00197
00198 png_init_io(png_ptr, fp);
00199 png_set_sig_bytes(png_ptr, 8);
00200
00201 png_read_info(png_ptr, info_ptr);
00202
00203 width = info_ptr->width;
00204 height = info_ptr->height;
00205 color_type = info_ptr->color_type;
00206 bit_depth = info_ptr->bit_depth;
00207
00208 png_set_interlace_handling(png_ptr);
00209 png_read_update_info(png_ptr, info_ptr);
00210
00211
00212
00213 if (setjmp(png_jmpbuf(png_ptr)))
00214 abort_("[read_png_file] Error during read_image");
00215
00216 png_bytep *row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
00217 for (int y=0; y<height; y++)
00218 row_pointers[y] = (png_byte*) malloc(info_ptr->rowbytes);
00219
00220 png_read_image(png_ptr, row_pointers);
00221
00222 fclose(fp);
00223
00224
00225 }