images.c

Go to the documentation of this file.
00001 
00006 /*
00007  Copyright (C) 2002-2009 Quake2World.
00008  Copyright (C) 2002-2010 UFO: Alien Invasion.
00009 
00010  This program is free software; you can redistribute it and/or
00011  modify it under the terms of the GNU General Public License
00012  as published by the Free Software Foundation; either version 2
00013  of the License, or (at your option) any later version.
00014 
00015  This program is distributed in the hope that it will be useful,
00016  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018 
00019  See the GNU General Public License for more details.
00020 
00021  You should have received a copy of the GNU General Public License
00022  along with this program; if not, write to the Free Software
00023  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00024 
00025  */
00026 
00027 #include "images.h"
00028 
00029 /* Workaround for a warning about redeclaring the macro. jpeglib sets this macro
00030  * and SDL, too. */
00031 #undef HAVE_STDLIB_H
00032 
00033 #include <jpeglib.h>
00034 #include <png.h>
00035 
00037 static char *IMAGE_TYPES[] = { "tga", "png", "jpg", NULL };
00038 
00040 static SDL_PixelFormat format = {
00041     NULL,  
00042     32,  
00043     4,  
00044     0,  
00045     0,  
00046     0,  
00047     0,  
00048     24,  
00049     16,  
00050     8,  
00051     0,  
00052 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00053     0xff000000,
00054     0x00ff0000,
00055     0x0000ff00,
00056     0x000000ff,
00057 #else
00058     0x000000ff,
00059     0x0000ff00,
00060     0x00ff0000,
00061     0xff000000,
00062 #endif
00063     0,  
00064     1   
00065 };
00066 
00067 #define TGA_UNMAP_UNCOMP        2
00068 #define TGA_UNMAP_COMP          10
00069 
00070 const char** Img_GetImageTypes (void)
00071 {
00072     return (const char **)IMAGE_TYPES;
00073 }
00074 
00080 void R_WritePNG (qFILE *f, byte *buffer, int width, int height)
00081 {
00082     int         i;
00083     png_structp png_ptr;
00084     png_infop   info_ptr;
00085     png_bytep   *row_pointers;
00086 
00087     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00088     if (!png_ptr) {
00089         return;
00090     }
00091 
00092     info_ptr = png_create_info_struct(png_ptr);
00093     if (!info_ptr) {
00094         png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00095         return;
00096     }
00097 
00098     png_init_io(png_ptr, f->f);
00099 
00100     png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB,
00101                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
00102 
00103     png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
00104     png_set_compression_mem_level(png_ptr, 9);
00105 
00106     png_write_info(png_ptr, info_ptr);
00107 
00108     row_pointers = malloc(height * sizeof(png_bytep));
00109     for (i = 0; i < height; i++)
00110         row_pointers[i] = buffer + (height - 1 - i) * 3 * width;
00111 
00112     png_write_image(png_ptr, row_pointers);
00113     png_write_end(png_ptr, info_ptr);
00114 
00115     png_destroy_write_struct(&png_ptr, &info_ptr);
00116 
00117     free(row_pointers);
00118 }
00119 
00120 #define TGA_CHANNELS 3
00121 
00126 void R_WriteCompressedTGA (qFILE *f, const byte *buffer, int width, int height)
00127 {
00128     byte pixel_data[TGA_CHANNELS];
00129     byte block_data[TGA_CHANNELS * 128];
00130     byte rle_packet;
00131     int compress = 0;
00132     size_t block_length = 0;
00133     byte header[18];
00134     char footer[26];
00135 
00136     int y;
00137     size_t x;
00138 
00139     memset(header, 0, sizeof(header));
00140     memset(footer, 0, sizeof(footer));
00141 
00142     /* Fill in header */
00143     /* byte 0: image ID field length */
00144     /* byte 1: color map type */
00145     header[2] = TGA_UNMAP_COMP;     /* image type: Truecolor RLE encoded */
00146     /* byte 3 - 11: palette data */
00147     /* image width */
00148     header[12] = width & 255;
00149     header[13] = (width >> 8) & 255;
00150     /* image height */
00151     header[14] = height & 255;
00152     header[15] = (height >> 8) & 255;
00153     header[16] = 8 * TGA_CHANNELS;  /* Pixel size 24 (RGB) or 32 (RGBA) */
00154     header[17] = 0x20;  /* Origin at bottom left */
00155 
00156     /* write header */
00157     FS_Write(header, sizeof(header), f);
00158 
00159     for (y = height - 1; y >= 0; y--) {
00160         for (x = 0; x < width; x++) {
00161             const size_t index = y * width * TGA_CHANNELS + x * TGA_CHANNELS;
00162             pixel_data[0] = buffer[index + 2];
00163             pixel_data[1] = buffer[index + 1];
00164             pixel_data[2] = buffer[index];
00165 
00166             if (block_length == 0) {
00167                 memcpy(block_data, pixel_data, TGA_CHANNELS);
00168                 block_length++;
00169                 compress = 0;
00170             } else {
00171                 if (!compress) {
00172                     /* uncompressed block and pixel_data differs from the last pixel */
00173                     if (memcmp(&block_data[(block_length - 1) * TGA_CHANNELS], pixel_data, TGA_CHANNELS) != 0) {
00174                         /* append pixel */
00175                         memcpy(&block_data[block_length * TGA_CHANNELS], pixel_data, TGA_CHANNELS);
00176 
00177                         block_length++;
00178                     } else {
00179                         /* uncompressed block and pixel data is identical */
00180                         if (block_length > 1) {
00181                             /* write the uncompressed block */
00182                             rle_packet = block_length - 2;
00183                             FS_Write(&rle_packet,1, f);
00184                             FS_Write(block_data, (block_length - 1) * TGA_CHANNELS, f);
00185                             block_length = 1;
00186                         }
00187                         memcpy(block_data, pixel_data, TGA_CHANNELS);
00188                         block_length++;
00189                         compress = 1;
00190                     }
00191                 } else {
00192                     /* compressed block and pixel data is identical */
00193                     if (memcmp(block_data, pixel_data, TGA_CHANNELS) == 0) {
00194                         block_length++;
00195                     } else {
00196                         /* compressed block and pixel data differs */
00197                         if (block_length > 1) {
00198                             /* write the compressed block */
00199                             rle_packet = block_length + 127;
00200                             FS_Write(&rle_packet, 1, f);
00201                             FS_Write(block_data, TGA_CHANNELS, f);
00202                             block_length = 0;
00203                         }
00204                         memcpy(&block_data[block_length * TGA_CHANNELS], pixel_data, TGA_CHANNELS);
00205                         block_length++;
00206                         compress = 0;
00207                     }
00208                 }
00209             }
00210 
00211             if (block_length == 128) {
00212                 rle_packet = block_length - 1;
00213                 if (!compress) {
00214                     FS_Write(&rle_packet, 1, f);
00215                     FS_Write(block_data, 128 * TGA_CHANNELS, f);
00216                 } else {
00217                     rle_packet += 128;
00218                     FS_Write(&rle_packet, 1, f);
00219                     FS_Write(block_data, TGA_CHANNELS, f);
00220                 }
00221 
00222                 block_length = 0;
00223                 compress = 0;
00224             }
00225         }
00226     }
00227 
00228     /* write remaining bytes */
00229     if (block_length) {
00230         rle_packet = block_length - 1;
00231         if (!compress) {
00232             FS_Write(&rle_packet, 1, f);
00233             FS_Write(block_data, block_length * TGA_CHANNELS, f);
00234         } else {
00235             rle_packet += 128;
00236             FS_Write(&rle_packet, 1, f);
00237             FS_Write(block_data, TGA_CHANNELS, f);
00238         }
00239     }
00240 
00241     /* write footer (optional, but the specification recommends it) */
00242     strncpy(&footer[8] , "TRUEVISION-XFILE", 16);
00243     footer[24] = '.';
00244     footer[25] = 0;
00245     FS_Write(footer, sizeof(footer), f);
00246 }
00247 
00252 void R_WriteJPG (qFILE *f, byte *buffer, int width, int height, int quality)
00253 {
00254     int offset, w3;
00255     struct jpeg_compress_struct cinfo;
00256     struct jpeg_error_mgr jerr;
00257     byte *s;
00258 
00259     /* Initialise the jpeg compression object */
00260     cinfo.err = jpeg_std_error(&jerr);
00261     jpeg_create_compress(&cinfo);
00262     jpeg_stdio_dest(&cinfo, f->f);
00263 
00264     /* Setup jpeg parameters */
00265     cinfo.image_width = width;
00266     cinfo.image_height = height;
00267     cinfo.in_color_space = JCS_RGB;
00268     cinfo.input_components = 3;
00269     cinfo.progressive_mode = TRUE;
00270 
00271     jpeg_set_defaults(&cinfo);
00272     jpeg_set_quality(&cinfo, quality, TRUE);
00273     jpeg_start_compress(&cinfo, qtrue); /* start compression */
00274     jpeg_write_marker(&cinfo, JPEG_COM, (const byte *) "UFOAI", (uint32_t) 5);
00275 
00276     /* Feed scanline data */
00277     w3 = cinfo.image_width * 3;
00278     offset = w3 * cinfo.image_height - w3;
00279     while (cinfo.next_scanline < cinfo.image_height) {
00280         s = &buffer[offset - (cinfo.next_scanline * w3)];
00281         jpeg_write_scanlines(&cinfo, &s, 1);
00282     }
00283 
00284     /* Finish compression */
00285     jpeg_finish_compress(&cinfo);
00286     jpeg_destroy_compress(&cinfo);
00287 }
00288 
00293 static qboolean Img_LoadTypedImage (const char *name, char *type, SDL_Surface **surf)
00294 {
00295     char path[MAX_QPATH];
00296     byte *buf;
00297     int len;
00298     SDL_RWops *rw;
00299     SDL_Surface *s;
00300 
00301     snprintf(path, sizeof(path), "%s.%s", name, type);
00302 
00303     if ((len = FS_LoadFile(path, &buf)) == -1)
00304         return qfalse;
00305 
00306     if (!(rw = SDL_RWFromMem(buf, len))) {
00307         FS_FreeFile(buf);
00308         return qfalse;
00309     }
00310 
00311     if (!(*surf = IMG_LoadTyped_RW(rw, 0, type))) {
00312         SDL_FreeRW(rw);
00313         FS_FreeFile(buf);
00314         return qfalse;
00315     }
00316 
00317     SDL_FreeRW(rw);
00318     FS_FreeFile(buf);
00319 
00320     if (!(s = SDL_ConvertSurface(*surf, &format, 0))) {
00321         SDL_FreeSurface(*surf);
00322         return qfalse;
00323     }
00324 
00325     SDL_FreeSurface(*surf);
00326     *surf = s;
00327 
00328     return qtrue;
00329 }
00330 
00338 qboolean Img_LoadImage (const char *name, SDL_Surface **surf)
00339 {
00340     int i;
00341 
00342     i = 0;
00343     while (IMAGE_TYPES[i]) {
00344         if (Img_LoadTypedImage(name, IMAGE_TYPES[i++], surf))
00345             return qtrue;
00346     }
00347 
00348     return qfalse;
00349 }

Generated by  doxygen 1.6.2