00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <stdio.h>
00022 #include <math.h>
00023 #include <common/Defines.h>
00024 #include <common/Logger.h>
00025 #include <image/ImagePng.h>
00026 #ifdef __DARWIN__
00027 #include <UnixImageIO/png.h>
00028 #else
00029 #include <png.h>
00030 #endif
00031
00032 ImagePng::ImagePng() :
00033 width_(0), height_(0), bits_(0), alpha_(false),
00034 owner_(true)
00035 {
00036
00037 }
00038
00039 ImagePng::ImagePng(int startWidth, int startHeight, bool alpha, unsigned char fill) :
00040 width_(startWidth), height_(startHeight), alpha_(alpha), bits_(0),
00041 owner_(true)
00042 {
00043 createBlankInternal(startWidth, startHeight, alpha, fill);
00044 }
00045
00046 bool ImagePng::loadFromFile(const std::string &filename,
00047 const std::string &alphafilename, bool invert)
00048 {
00049 ImagePng bitmap;
00050 if (!bitmap.loadFromFile(filename)) return false;
00051 ImagePng alpha;
00052 if (!alpha.loadFromFile(alphafilename)) return false;
00053
00054 if (bitmap.getBits() && alpha.getBits() &&
00055 bitmap.getWidth() == alpha.getWidth() &&
00056 bitmap.getHeight() == alpha.getHeight() &&
00057 bitmap.getComponents() == alpha.getComponents() &&
00058 bitmap.getComponents() == 3)
00059 {
00060 createBlankInternal(bitmap.getWidth(), bitmap.getHeight(), true);
00061 unsigned char *bbits = bitmap.getBits();
00062 unsigned char *abits = alpha.getBits();
00063 unsigned char *bits = getBits();
00064 for (int y=0; y<bitmap.getHeight(); y++)
00065 {
00066 for (int x=0; x<bitmap.getWidth(); x++)
00067 {
00068 bits[0] = bbits[0];
00069 bits[1] = bbits[1];
00070 bits[2] = bbits[2];
00071
00072 unsigned char avg = (unsigned char)
00073 ((
00074 int(abits[0]) +
00075 int(abits[1]) +
00076 int(abits[2])) / 3);
00077 if (invert)
00078 {
00079 bits[3] = (unsigned char)(255 - avg);
00080 }
00081 else
00082 {
00083 bits[3] = avg;
00084 }
00085
00086 bbits += 3;
00087 abits += 3;
00088 bits += 4;
00089 }
00090 }
00091 }
00092 return true;
00093 }
00094
00095 ImagePng::~ImagePng()
00096 {
00097 clear();
00098 }
00099
00100 void ImagePng::clear()
00101 {
00102 if (owner_) delete [] bits_;
00103 bits_ = 0;
00104 width_ = 0;
00105 height_ = 0;
00106 }
00107
00108 void ImagePng::createBlankInternal(int width, int height, bool alpha, unsigned char fill)
00109 {
00110 clear();
00111 width_ = width;
00112 height_ = height;
00113 alpha_ = alpha;
00114 int bitsize = getComponents() * width * height;
00115
00116 bits_ = new unsigned char[bitsize];
00117 memset(bits_, fill, bitsize);
00118 }
00119
00120 bool ImagePng::loadFromFile(const std::string &filename, bool readalpha)
00121 {
00122 FILE *file = fopen(filename.c_str(), "rb");
00123 if (!file) return false;
00124
00125 int read = 0;
00126 char buffer[256];
00127 NetBuffer netBuffer;
00128 while (read = fread(buffer, 1, 256, file))
00129 {
00130 netBuffer.addDataToBuffer(buffer, read);
00131 }
00132 fclose(file);
00133
00134 if (!loadFromBuffer(netBuffer, readalpha))
00135 {
00136 Logger::log(
00137 S3D::formatStringBuffer("Failed to load PNG file \"%s\"", filename.c_str()));
00138 return false;
00139 }
00140 return true;
00141 }
00142
00143 struct user_read_struct
00144 {
00145 user_read_struct(NetBuffer &b) : buffer(b), position(0) {}
00146
00147 int position;
00148 NetBuffer &buffer;
00149 };
00150
00151 static void user_png_error(png_structp png_ptr, png_const_charp msg)
00152 {
00153 longjmp(png_ptr->jmpbuf,1);
00154 }
00155
00156 static void user_png_warning(png_structp png_ptr, png_const_charp msg)
00157 {
00158 }
00159
00160 static void user_read_fn(png_structp png_ptr,
00161 png_bytep data, png_size_t length)
00162 {
00163 user_read_struct *read_io_ptr = (user_read_struct *) png_get_io_ptr(png_ptr);
00164
00165 int length_left = MIN(length, read_io_ptr->buffer.getBufferUsed() - read_io_ptr->position);
00166 memcpy(data, &read_io_ptr->buffer.getBuffer()[read_io_ptr->position], length_left);
00167 read_io_ptr->position += length_left;
00168 }
00169
00170
00171 bool ImagePng::loadFromBuffer(NetBuffer &buffer, bool readalpha)
00172 {
00173 png_structp png_ptr;
00174 png_infop info_ptr;
00175
00176
00177
00178
00179
00180
00181
00182 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
00183 if (png_ptr == NULL)
00184 {
00185 return false;
00186 }
00187
00188
00189 info_ptr = png_create_info_struct(png_ptr);
00190 if (info_ptr == NULL)
00191 {
00192 png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
00193 return false;
00194 }
00195
00196
00197
00198
00199
00200 if (setjmp(png_jmpbuf(png_ptr)))
00201 {
00202
00203 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
00204
00205 return false;
00206 }
00207 png_set_error_fn(png_ptr, NULL, user_png_error, user_png_warning);
00208
00209
00210
00211
00212 user_read_struct read_struct(buffer);
00213 png_set_read_fn(png_ptr, (void *)&read_struct, user_read_fn);
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224 unsigned int settings =
00225 PNG_TRANSFORM_PACKING |
00226 PNG_TRANSFORM_STRIP_16 |
00227 PNG_TRANSFORM_EXPAND;
00228 if (!readalpha) settings |= PNG_TRANSFORM_STRIP_ALPHA;
00229
00230 png_read_png(png_ptr, info_ptr, settings, NULL);
00231
00232
00233
00234
00235 png_uint_32 width = png_get_image_width(png_ptr, info_ptr);
00236 png_uint_32 height = png_get_image_height(png_ptr, info_ptr);
00237 png_uint_32 bytes = png_get_rowbytes(png_ptr, info_ptr);
00238 png_uint_32 bitdepth = png_get_bit_depth(png_ptr, info_ptr);
00239 png_uint_32 coltype = png_get_color_type(png_ptr, info_ptr);
00240 png_byte channels = png_get_channels(png_ptr, info_ptr);
00241
00242 if (coltype == (readalpha?PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB) &&
00243 bitdepth == 8 &&
00244 channels == (readalpha?4:3) &&
00245 (bytes / width) == (readalpha?4:3))
00246 {
00247 png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr);
00248 width_ = width;
00249 height_ = height;
00250 alpha_ = readalpha;
00251
00252 createBlankInternal(width, height, readalpha);
00253
00254 for (unsigned int h=0; h<height; h++)
00255 {
00256 memcpy(bits_ + bytes * (height - 1 - h), row_pointers[h], bytes);
00257 }
00258 }
00259 else
00260 {
00261 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
00262
00263 Logger::log(S3D::formatStringBuffer(
00264 "Invalid PNG format.\n"
00265 "width %d, hei %d, rowbytes %d, bitd %d, "
00266 "colt %d, channels %d\n",
00267 (int)width,(int)height,(int)bytes,(int)bitdepth,
00268 (int)coltype,(int)channels));
00269 return false;
00270 }
00271
00272
00273
00274
00275 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
00276
00277
00278 return true;
00279 }
00280
00281 struct user_write_struct
00282 {
00283 user_write_struct(NetBuffer &b) : buffer(b) {}
00284
00285 NetBuffer &buffer;
00286 };
00287
00288 static void user_write_fn(png_structp png_ptr,
00289 png_bytep data, png_size_t length)
00290 {
00291 user_write_struct *write_io_ptr = (user_write_struct *) png_get_io_ptr(png_ptr);
00292
00293 write_io_ptr->buffer.addDataToBuffer(data, length);
00294 }
00295
00296 bool ImagePng::writeToBuffer(NetBuffer &buffer)
00297 {
00298 png_structp png_ptr;
00299 png_infop info_ptr;
00300 int y;
00301
00302
00303 png_ptr =
00304 png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00305 if (!png_ptr) return false;
00306
00307 info_ptr =
00308 png_create_info_struct(png_ptr);
00309 if (!info_ptr) return false;
00310
00311
00312 if (setjmp(png_jmpbuf(png_ptr)))
00313 {
00314 png_destroy_write_struct(&png_ptr, &info_ptr);
00315 return false;
00316 }
00317 png_set_error_fn(png_ptr, NULL, user_png_error, user_png_warning);
00318
00319
00320 user_read_struct read_struct(buffer);
00321 png_set_read_fn(png_ptr, (void *)&read_struct, user_read_fn);
00322
00323
00324 user_write_struct write_struct(buffer);
00325 png_set_write_fn(png_ptr, (void *)&write_struct, user_write_fn, NULL);
00326
00327
00328 png_set_IHDR(png_ptr, info_ptr,
00329 width_, height_,
00330 8,
00331 PNG_COLOR_TYPE_RGB,
00332 PNG_INTERLACE_NONE,
00333 PNG_COMPRESSION_TYPE_DEFAULT,
00334 PNG_FILTER_TYPE_DEFAULT);
00335
00336
00337 png_write_info(png_ptr, info_ptr);
00338 for (y=0; y<height_; y++)
00339 {
00340 png_write_row(png_ptr, &bits_[(height_ - y - 1) * width_ * getComponents()]);
00341 }
00342 png_write_end(png_ptr, NULL);
00343
00344
00345 png_destroy_write_struct(&png_ptr, &info_ptr);
00346
00347 return true;
00348 }