00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00030
00031
00032
00033
00034
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <string.h>
00038 #include <png.h>
00039
00040 #include "stratagus.h"
00041 #include "video.h"
00042 #include "iolib.h"
00043 #include "iocompat.h"
00044
00045
00046
00047
00048
00049
00050
00051
00052
00060 static void CL_png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
00061 {
00062 png_size_t check;
00063 CFile *f;
00064
00065 f = (CFile *)png_get_io_ptr(png_ptr);
00066 check = (png_size_t)f->read(data,
00067 (size_t)length);
00068 if (check != length) {
00069 png_error(png_ptr, "Read Error");
00070 }
00071 }
00072
00081 int LoadGraphicPNG(CGraphic *g)
00082 {
00083 CFile fp;
00084 SDL_Surface *volatile surface;
00085 png_structp png_ptr;
00086 png_infop info_ptr;
00087 png_uint_32 width;
00088 png_uint_32 height;
00089 int bit_depth;
00090 int color_type;
00091 int interlace_type;
00092 Uint32 Rmask;
00093 Uint32 Gmask;
00094 Uint32 Bmask;
00095 Uint32 Amask;
00096 SDL_Palette *palette;
00097 png_bytep *volatile row_pointers;
00098 int row;
00099 int i;
00100 volatile int ckey;
00101 png_color_16 *transv;
00102 char name[PATH_MAX];
00103 int ret;
00104
00105 ckey = -1;
00106 ret = 0;
00107
00108 if (g->File.empty()) {
00109 return -1;
00110 }
00111
00112 name[0] = '\0';
00113 LibraryFileName(g->File.c_str(), name, sizeof(name));
00114 if (name[0] == '\0') {
00115 return -1;
00116 }
00117
00118 if (fp.open(name, CL_OPEN_READ) == -1) {
00119 perror("Can't open file");
00120 return -1;
00121 }
00122
00123
00124 png_ptr = NULL; info_ptr = NULL; row_pointers = NULL; surface = NULL;
00125
00126
00127 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
00128 NULL, NULL, NULL);
00129 if (png_ptr == NULL) {
00130 fprintf(stderr, "Couldn't allocate memory for PNG file");
00131 ret = -1;
00132 goto done;
00133 }
00134
00135
00136 info_ptr = png_create_info_struct(png_ptr);
00137 if (info_ptr == NULL) {
00138 fprintf(stderr, "Couldn't create image information for PNG file");
00139 ret = -1;
00140 goto done;
00141 }
00142
00143
00144
00145
00146
00147 if (setjmp(png_ptr->jmpbuf)) {
00148 fprintf(stderr, "Error reading the PNG file.\n");
00149 ret = -1;
00150 goto done;
00151 }
00152
00153
00154 png_set_read_fn(png_ptr, &fp, CL_png_read_data);
00155
00156
00157 png_read_info(png_ptr, info_ptr);
00158 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
00159 &color_type, &interlace_type, NULL, NULL);
00160
00161
00162 png_set_strip_16(png_ptr) ;
00163
00164
00165
00166
00167 png_set_packing(png_ptr);
00168
00169
00170 if (color_type == PNG_COLOR_TYPE_GRAY) {
00171 png_set_expand(png_ptr);
00172 }
00173
00174
00175
00176
00177 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
00178 int num_trans;
00179 png_bytep trans;
00180
00181 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans,
00182 &transv);
00183 if (color_type == PNG_COLOR_TYPE_PALETTE) {
00184
00185 int i;
00186 int t;
00187
00188 t = -1;
00189 for (i = 0; i < num_trans; ++i) {
00190 if (trans[i] == 0) {
00191 if (t >= 0) {
00192 break;
00193 }
00194 t = i;
00195 } else if (trans[i] != 255) {
00196 break;
00197 }
00198 }
00199 if (i == num_trans) {
00200
00201 ckey = t;
00202 } else {
00203
00204 png_set_expand(png_ptr);
00205 }
00206 } else {
00207 ckey = 0;
00208 }
00209 }
00210
00211 if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
00212 png_set_gray_to_rgb(png_ptr);
00213 }
00214
00215 png_read_update_info(png_ptr, info_ptr);
00216
00217 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
00218 &color_type, &interlace_type, NULL, NULL);
00219
00220
00221 Rmask = Gmask = Bmask = Amask = 0 ;
00222 if (color_type != PNG_COLOR_TYPE_PALETTE) {
00223 if (SDL_BYTEORDER == SDL_LIL_ENDIAN) {
00224 Rmask = 0x000000FF;
00225 Gmask = 0x0000FF00;
00226 Bmask = 0x00FF0000;
00227 Amask = (info_ptr->channels == 4) ? 0xFF000000 : 0;
00228 } else {
00229 int s;
00230
00231 s = (info_ptr->channels == 4) ? 0 : 8;
00232 Rmask = 0xFF000000 >> s;
00233 Gmask = 0x00FF0000 >> s;
00234 Bmask = 0x0000FF00 >> s;
00235 Amask = 0x000000FF >> s;
00236 }
00237 }
00238 surface = SDL_AllocSurface(SDL_SWSURFACE, width, height,
00239 bit_depth * info_ptr->channels, Rmask, Gmask, Bmask, Amask);
00240 if (surface == NULL) {
00241 fprintf(stderr, "Out of memory");
00242 goto done;
00243 }
00244
00245 if (ckey != -1) {
00246 if (color_type != PNG_COLOR_TYPE_PALETTE) {
00247
00248 ckey = SDL_MapRGB(surface->format,
00249 (Uint8)transv->red,
00250 (Uint8)transv->green,
00251 (Uint8)transv->blue);
00252 }
00253 SDL_SetColorKey(surface, SDL_SRCCOLORKEY | SDL_RLEACCEL, ckey);
00254 }
00255
00256
00257 row_pointers = new png_bytep[height];
00258 if (row_pointers == NULL) {
00259 fprintf(stderr, "Out of memory");
00260 SDL_FreeSurface(surface);
00261 surface = NULL;
00262 goto done;
00263 }
00264 for (row = 0; row < (int)height; ++row) {
00265 row_pointers[row] = (png_bytep)
00266 (Uint8 *)surface->pixels + row * surface->pitch;
00267 }
00268
00269
00270 png_read_image(png_ptr, row_pointers);
00271
00272
00273 png_read_end(png_ptr, info_ptr);
00274
00275
00276 palette = surface->format->palette;
00277 if (palette) {
00278 if (color_type == PNG_COLOR_TYPE_GRAY) {
00279 palette->ncolors = 256;
00280 for (i = 0; i < 256; ++i) {
00281 palette->colors[i].r = i;
00282 palette->colors[i].g = i;
00283 palette->colors[i].b = i;
00284 }
00285 } else if (info_ptr->num_palette > 0) {
00286 palette->ncolors = info_ptr->num_palette;
00287 for (i = 0; i < info_ptr->num_palette; ++i) {
00288 palette->colors[i].b = info_ptr->palette[i].blue;
00289 palette->colors[i].g = info_ptr->palette[i].green;
00290 palette->colors[i].r = info_ptr->palette[i].red;
00291 }
00292 }
00293 }
00294
00295 g->Surface = surface;
00296 g->GraphicWidth = surface->w;
00297 g->GraphicHeight = surface->h;
00298
00299 done:
00300 png_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : (png_infopp)0,
00301 (png_infopp)0);
00302 if (row_pointers) {
00303 delete[] row_pointers;
00304 }
00305 fp.close();
00306 return ret;
00307 }
00308
00314 void SaveScreenshotPNG(const std::string &name)
00315 {
00316 FILE *fp;
00317 png_structp png_ptr;
00318 png_infop info_ptr;
00319 int i;
00320 int j;
00321 int bpp;
00322
00323 bpp = TheScreen->format->BytesPerPixel;
00324
00325 fp = fopen(name.c_str(), "wb");
00326 if (fp == NULL) {
00327 return;
00328 }
00329
00330 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00331 if (png_ptr == NULL) {
00332 fclose(fp);
00333 return;
00334 }
00335
00336 info_ptr = png_create_info_struct(png_ptr);
00337 if (info_ptr == NULL) {
00338 fclose(fp);
00339 png_destroy_write_struct(&png_ptr, NULL);
00340 return;
00341 }
00342
00343 if (setjmp(png_ptr->jmpbuf)) {
00344
00345 fclose(fp);
00346 png_destroy_write_struct(&png_ptr, &info_ptr);
00347 return;
00348 }
00349
00350
00351 png_init_io(png_ptr, fp);
00352
00353 png_set_IHDR(png_ptr, info_ptr, Video.Width, Video.Height, 8,
00354 PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
00355 PNG_FILTER_TYPE_DEFAULT);
00356
00357 Video.LockScreen();
00358
00359 png_write_info(png_ptr, info_ptr);
00360
00361 if (UseOpenGL) {
00362 unsigned char *pixels = new unsigned char[Video.Width * Video.Height * 3];
00363 if (!pixels) {
00364 fprintf(stderr, "Out of memory\n");
00365 exit(1);
00366 }
00367 glReadBuffer(GL_FRONT);
00368 glReadPixels(0, 0, Video.Width, Video.Height, GL_RGB, GL_UNSIGNED_BYTE,
00369 pixels);
00370 for (i = 0; i < Video.Height; ++i) {
00371 png_write_row(png_ptr, pixels + (Video.Height - 1 - i) * Video.Width * 3);
00372 }
00373 delete[] pixels;
00374 } else {
00375 unsigned char *row = new unsigned char[Video.Width * 3];
00376 SDL_PixelFormat *fmt = TheScreen->format;
00377
00378 for (i = 0; i < Video.Height; ++i) {
00379 switch (Video.Depth) {
00380 case 15:
00381 case 16: {
00382 Uint16 c;
00383 for (j = 0; j < Video.Width; ++j) {
00384 c = ((Uint16 *)TheScreen->pixels)[j + i * Video.Width];
00385 row[j * 3 + 0] = ((c & fmt->Rmask) >> fmt->Rshift) << fmt->Rloss;
00386 row[j * 3 + 1] = ((c & fmt->Gmask) >> fmt->Gshift) << fmt->Gloss;
00387 row[j * 3 + 2] = ((c & fmt->Bmask) >> fmt->Bshift) << fmt->Bloss;
00388 }
00389 break;
00390 }
00391 case 24: {
00392 Uint8 c;
00393 for (j = 0; j < Video.Width; ++j) {
00394 c = ((Uint8 *)TheScreen->pixels)[j * bpp + i * Video.Width * 3];
00395 memcpy(row, (char *)TheScreen->pixels + i * Video.Width, Video.Width * 3);
00396 }
00397 break;
00398 }
00399 case 32: {
00400 Uint32 c;
00401 for (j = 0; j < Video.Width; ++j) {
00402 c = ((Uint32 *)TheScreen->pixels)[j + i * Video.Width];
00403 row[j * 3 + 0] = ((c & fmt->Rmask) >> fmt->Rshift);
00404 row[j * 3 + 1] = ((c & fmt->Gmask) >> fmt->Gshift);
00405 row[j * 3 + 2] = ((c & fmt->Bmask) >> fmt->Bshift);
00406 }
00407 break;
00408 }
00409 }
00410 png_write_row(png_ptr, row);
00411 }
00412
00413 delete[] row;
00414 }
00415
00416 png_write_end(png_ptr, info_ptr);
00417
00418 Video.UnlockScreen();
00419
00420
00421 png_destroy_write_struct(&png_ptr, &info_ptr);
00422
00423 fclose(fp);
00424 }
00425