imagelib.c

Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 1997-2001 Id Software, Inc.
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (at your option) any later version.
00013 
00014 This program is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018 See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 
00024 */
00025 
00026 #include "shared.h"
00027 #include "imagelib.h"
00028 
00029 #include <jpeglib.h>
00030 #include <png.h>
00031 
00032 /*
00033 ============================================================================
00034 TARGA IMAGE
00035 ============================================================================
00036 */
00037 
00038 typedef struct _TargaHeader {
00039     unsigned char   id_length, colormap_type, image_type;
00040     unsigned short  colormap_index, colormap_length;
00041     unsigned char   colormap_size;
00042     unsigned short  x_origin, y_origin, width, height;
00043     unsigned char   pixel_size, attributes;
00044 } TargaHeader;
00045 
00046 static void LoadTGA (const char *name, byte ** pic, int *width, int *height)
00047 {
00048     int columns, rows, numPixels;
00049     byte *pixbuf;
00050     int row, column;
00051     byte *buf_p;
00052     byte *buffer;
00053     int length;
00054     TargaHeader targa_header;
00055     byte *targa_rgba;
00056     byte tmp[2];
00057 
00058     if (*pic != NULL)
00059         Sys_Error("possible mem leak in LoadTGA");
00060 
00061     /* load the file */
00062     length = FS_LoadFile(name, (byte **) &buffer);
00063     if (length == -1)
00064         return;
00065 
00066     buf_p = buffer;
00067 
00068     targa_header.id_length = *buf_p++;
00069     targa_header.colormap_type = *buf_p++;
00070     targa_header.image_type = *buf_p++;
00071 
00072     tmp[0] = buf_p[0];
00073     tmp[1] = buf_p[1];
00074     targa_header.colormap_index = LittleShort(*((short *) tmp));
00075     buf_p += 2;
00076     tmp[0] = buf_p[0];
00077     tmp[1] = buf_p[1];
00078     targa_header.colormap_length = LittleShort(*((short *) tmp));
00079     buf_p += 2;
00080     targa_header.colormap_size = *buf_p++;
00081     targa_header.x_origin = LittleShort(*((short *) buf_p));
00082     buf_p += 2;
00083     targa_header.y_origin = LittleShort(*((short *) buf_p));
00084     buf_p += 2;
00085     targa_header.width = LittleShort(*((short *) buf_p));
00086     buf_p += 2;
00087     targa_header.height = LittleShort(*((short *) buf_p));
00088     buf_p += 2;
00089     targa_header.pixel_size = *buf_p++;
00090     targa_header.attributes = *buf_p++;
00091 
00092     if (targa_header.image_type != 2 && targa_header.image_type != 10)
00093         Sys_Error("LoadTGA: Only type 2 and 10 targa RGB images supported (%s) (type: %i)", name, targa_header.image_type);
00094 
00095     if (targa_header.colormap_type != 0 || (targa_header.pixel_size != 32 && targa_header.pixel_size != 24))
00096         Sys_Error("LoadTGA: Only 32 or 24 bit images supported (no colormaps) (%s) (pixel_size: %i)", name, targa_header.pixel_size);
00097 
00098     columns = targa_header.width;
00099     rows = targa_header.height;
00100     numPixels = columns * rows;
00101 
00102     if (width)
00103         *width = columns;
00104     if (height)
00105         *height = rows;
00106 
00107     targa_rgba = Mem_Alloc(numPixels * 4);
00108     *pic = targa_rgba;
00109 
00110     if (targa_header.id_length != 0)
00111         buf_p += targa_header.id_length;    /* skip TARGA image comment */
00112 
00113     if (targa_header.image_type == 2) { /* Uncompressed, RGB images */
00114         for (row = rows - 1; row >= 0; row--) {
00115             pixbuf = targa_rgba + row * columns * 4;
00116             for (column = 0; column < columns; column++) {
00117                 unsigned char red, green, blue, alphabyte;
00118 
00119                 red = green = blue = alphabyte = 0;
00120                 switch (targa_header.pixel_size) {
00121                 case 24:
00122 
00123                     blue = *buf_p++;
00124                     green = *buf_p++;
00125                     red = *buf_p++;
00126                     *pixbuf++ = red;
00127                     *pixbuf++ = green;
00128                     *pixbuf++ = blue;
00129                     *pixbuf++ = 255;
00130                     break;
00131                 case 32:
00132                     blue = *buf_p++;
00133                     green = *buf_p++;
00134                     red = *buf_p++;
00135                     alphabyte = *buf_p++;
00136                     *pixbuf++ = red;
00137                     *pixbuf++ = green;
00138                     *pixbuf++ = blue;
00139                     *pixbuf++ = alphabyte;
00140                     break;
00141                 default:
00142                     break;
00143                 }
00144             }
00145         }
00146     } else if (targa_header.image_type == 10) { /* Runlength encoded RGB images */
00147         unsigned char red, green, blue, alphabyte, packetHeader, packetSize, j;
00148 
00149         red = green = blue = alphabyte = 0;
00150         for (row = rows - 1; row >= 0; row--) {
00151             pixbuf = targa_rgba + row * columns * 4;
00152             for (column = 0; column < columns;) {
00153                 packetHeader = *buf_p++;
00154                 /* SCHAR_MAX although it's unsigned */
00155                 packetSize = 1 + (packetHeader & SCHAR_MAX);
00156                 if (packetHeader & 0x80) {  /* run-length packet */
00157                     switch (targa_header.pixel_size) {
00158                     case 24:
00159                         blue = *buf_p++;
00160                         green = *buf_p++;
00161                         red = *buf_p++;
00162                         alphabyte = 255;
00163                         break;
00164                     case 32:
00165                         blue = *buf_p++;
00166                         green = *buf_p++;
00167                         red = *buf_p++;
00168                         alphabyte = *buf_p++;
00169                         break;
00170                     default:
00171                         break;
00172                     }
00173 
00174                     for (j = 0; j < packetSize; j++) {
00175                         *pixbuf++ = red;
00176                         *pixbuf++ = green;
00177                         *pixbuf++ = blue;
00178                         *pixbuf++ = alphabyte;
00179                         column++;
00180                         if (column == columns) {    /* run spans across rows */
00181                             column = 0;
00182                             if (row > 0)
00183                                 row--;
00184                             else
00185                                 goto breakOut;
00186                             pixbuf = targa_rgba + row * columns * 4;
00187                         }
00188                     }
00189                 } else {        /* non run-length packet */
00190                     for (j = 0; j < packetSize; j++) {
00191                         switch (targa_header.pixel_size) {
00192                         case 24:
00193                             blue = *buf_p++;
00194                             green = *buf_p++;
00195                             red = *buf_p++;
00196                             *pixbuf++ = red;
00197                             *pixbuf++ = green;
00198                             *pixbuf++ = blue;
00199                             *pixbuf++ = 255;
00200                             break;
00201                         case 32:
00202                             blue = *buf_p++;
00203                             green = *buf_p++;
00204                             red = *buf_p++;
00205                             alphabyte = *buf_p++;
00206                             *pixbuf++ = red;
00207                             *pixbuf++ = green;
00208                             *pixbuf++ = blue;
00209                             *pixbuf++ = alphabyte;
00210                             break;
00211                         default:
00212                             break;
00213                         }
00214                         column++;
00215                         if (column == columns) {    /* pixel packet run spans across rows */
00216                             column = 0;
00217                             if (row > 0)
00218                                 row--;
00219                             else
00220                                 goto breakOut;
00221                             pixbuf = targa_rgba + row * columns * 4;
00222                         }
00223                     }
00224                 }
00225             }
00226           breakOut:;
00227         }
00228     }
00229 
00230     FS_FreeFile(buffer);
00231 }
00232 
00237 int TryLoadTGA (const char *path, miptex_t **mt)
00238 {
00239     byte *pic = NULL;
00240     int width, height;
00241     size_t size;
00242     byte *dest;
00243 
00244     LoadTGA(path, &pic, &width, &height);
00245     if (pic == NULL)
00246         return -1;
00247 
00248     size = sizeof(*mt) + width * height * 4;
00249     *mt = (miptex_t *)Mem_Alloc(size);
00250 
00251     dest = (byte*)(*mt) + sizeof(*mt);
00252     memcpy(dest, pic, width * height * 4);  /* stuff RGBA into this opaque space */
00253     Mem_Free(pic);
00254 
00255     /* copy relevant header fields to miptex_t */
00256     (*mt)->width = width;
00257     (*mt)->height = height;
00258     (*mt)->offsets[0] = sizeof(*mt);
00259 
00260     return 0;
00261 }
00262 
00263 /*
00264 ==============================================================================
00265 PNG LOADING
00266 ==============================================================================
00267 */
00268 
00269 #include <png.h>
00270 
00271 typedef struct pngBuf_s {
00272     byte    *buffer;
00273     size_t  pos;
00274 } pngBuf_t;
00275 
00276 static void PngReadFunc (png_struct *Png, png_bytep buf, png_size_t size)
00277 {
00278     pngBuf_t *PngFileBuffer = (pngBuf_t*)png_get_io_ptr(Png);
00279     memcpy(buf,PngFileBuffer->buffer + PngFileBuffer->pos, size);
00280     PngFileBuffer->pos += size;
00281 }
00282 
00287 static void LoadPNG (const char *name, byte **pic, int *width, int *height)
00288 {
00289     int rowptr;
00290     int color_type, bit_depth;
00291     png_structp png_ptr;
00292     png_infop info_ptr;
00293     png_infop end_info;
00294     byte **row_pointers;
00295     byte *img;
00296     uint32_t i;
00297     pngBuf_t PngFileBuffer = {NULL, 0};
00298     png_uint_32 png_height, png_width, rowbytes;
00299     png_byte channels;
00300 
00301     if (*pic != NULL)
00302         Sys_Error("possible mem leak in LoadPNG");
00303 
00304     /* Load the file */
00305     FS_LoadFile(name, (byte **)&PngFileBuffer.buffer);
00306     if (!PngFileBuffer.buffer)
00307         return;
00308 
00309     /* Parse the PNG file */
00310     if ((png_sig_cmp(PngFileBuffer.buffer, 0, 8)) != 0) {
00311         Com_Printf("LoadPNG: Not a PNG file: %s\n", name);
00312         FS_FreeFile(PngFileBuffer.buffer);
00313         return;
00314     }
00315 
00316     PngFileBuffer.pos = 0;
00317 
00318     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00319     if (!png_ptr) {
00320         Com_Printf("LoadPNG: Bad PNG file: %s\n", name);
00321         FS_FreeFile(PngFileBuffer.buffer);
00322         return;
00323     }
00324 
00325     info_ptr = png_create_info_struct(png_ptr);
00326     if (!info_ptr) {
00327         png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
00328         Com_Printf("LoadPNG: Bad PNG file: %s\n", name);
00329         FS_FreeFile(PngFileBuffer.buffer);
00330         return;
00331     }
00332 
00333     end_info = png_create_info_struct(png_ptr);
00334     if (!end_info) {
00335         png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00336         Com_Printf("LoadPNG: Bad PNG file: %s\n", name);
00337         FS_FreeFile(PngFileBuffer.buffer);
00338         return;
00339     }
00340 
00341     /* get some usefull information from header */
00342     bit_depth = png_get_bit_depth(png_ptr, info_ptr);
00343     color_type = png_get_color_type(png_ptr, info_ptr);
00344 
00352     /* convert index color images to RGB images */
00353     if (color_type == PNG_COLOR_TYPE_PALETTE)
00354         png_set_palette_to_rgb(png_ptr);
00355     /* convert 1-2-4 bits grayscale images to 8 bits grayscale */
00356     if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
00357         png_set_expand_gray_1_2_4_to_8(png_ptr);
00358     if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
00359         png_set_tRNS_to_alpha(png_ptr);
00360 
00361     if (bit_depth == 16)
00362         png_set_strip_16(png_ptr);
00363     else if (bit_depth < 8)
00364         png_set_packing(png_ptr);
00365 
00366     png_set_read_fn(png_ptr, (png_voidp)&PngFileBuffer, (png_rw_ptr)PngReadFunc);
00367     png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
00368     row_pointers = png_get_rows(png_ptr, info_ptr);
00369     rowptr = 0;
00370 
00371     png_height = png_get_image_height(png_ptr, info_ptr);
00372     png_width = png_get_image_width(png_ptr, info_ptr);
00373     img = Mem_Alloc(png_width * png_height * 4);
00374     if (pic)
00375         *pic = img;
00376 
00377     channels = png_get_channels(png_ptr, info_ptr);
00378     rowbytes = png_get_rowbytes(png_ptr, info_ptr);
00379     if (channels == 4) {
00380         for (i = 0; i < png_height; i++) {
00381             memcpy(img + rowptr, row_pointers[i], rowbytes);
00382             rowptr += rowbytes;
00383         }
00384     } else {
00385         uint32_t j;
00386 
00387         memset(img, 255, png_width * png_height * 4);
00388         for (rowptr = 0, i = 0; i < png_height; i++) {
00389             for (j = 0; j < rowbytes; j += channels) {
00390                 memcpy(img + rowptr, row_pointers[i] + j, channels);
00391                 rowptr += 4;
00392             }
00393         }
00394     }
00395 
00396     if (width)
00397         *width = (int)png_width;
00398     if (height)
00399         *height = (int)png_height;
00400 
00401     png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
00402 
00403     FS_FreeFile(PngFileBuffer.buffer);
00404 }
00405 
00410 int TryLoadPNG (const char *path, miptex_t **mt)
00411 {
00412     byte *pic = NULL;
00413     int width, height;
00414     size_t size;
00415     byte *dest;
00416 
00417     LoadPNG(path, &pic, &width, &height);
00418     if (pic == NULL)
00419         return -1;
00420 
00421     size = sizeof(*mt) + width * height * 4;
00422     *mt = (miptex_t *)Mem_Alloc(size);
00423 
00424     dest = (byte*)(*mt) + sizeof(*mt);
00425     memcpy(dest, pic, width * height * 4);  /* stuff RGBA into this opaque space */
00426     Mem_Free(pic);
00427 
00428     /* copy relevant header fields to miptex_t */
00429     (*mt)->width = width;
00430     (*mt)->height = height;
00431     (*mt)->offsets[0] = sizeof(*mt);
00432 
00433     return 0;
00434 }
00435 
00436 
00437 /*
00438 =================================================================
00439 JPEG LOADING
00440 By Robert 'Heffo' Heffernan
00441 =================================================================
00442 */
00443 
00444 static void ufo_jpg_null (j_decompress_ptr cinfo)
00445 {
00446 }
00447 
00448 static boolean ufo_jpg_fill_input_buffer (j_decompress_ptr cinfo)
00449 {
00450     Verb_Printf(VERB_EXTRA, "Premature end of JPEG data\n");
00451     return 1;
00452 }
00453 
00454 static void ufo_jpg_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
00455 {
00456     if (cinfo->src->bytes_in_buffer < (size_t) num_bytes)
00457         Verb_Printf(VERB_EXTRA, "Premature end of JPEG data\n");
00458 
00459     cinfo->src->next_input_byte += (size_t) num_bytes;
00460     cinfo->src->bytes_in_buffer -= (size_t) num_bytes;
00461 }
00462 
00463 static void ufo_jpeg_mem_src (j_decompress_ptr cinfo, byte * mem, int len)
00464 {
00465     cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(struct jpeg_source_mgr));
00466     cinfo->src->init_source = ufo_jpg_null;
00467     cinfo->src->fill_input_buffer = ufo_jpg_fill_input_buffer;
00468     cinfo->src->skip_input_data = ufo_jpg_skip_input_data;
00469     cinfo->src->resync_to_restart = jpeg_resync_to_restart;
00470     cinfo->src->term_source = ufo_jpg_null;
00471     cinfo->src->bytes_in_buffer = len;
00472     cinfo->src->next_input_byte = mem;
00473 }
00474 
00480 static void LoadJPG (const char *filename, byte ** pic, int *width, int *height)
00481 {
00482     struct jpeg_decompress_struct cinfo;
00483     struct jpeg_error_mgr jerr;
00484     byte *rawdata, *rgbadata, *scanline, *p, *q;
00485     int rawsize, i;
00486 
00487     if (*pic != NULL)
00488         Sys_Error("possible mem leak in LoadJPG");
00489 
00490     /* Load JPEG file into memory */
00491     rawsize = FS_LoadFile(filename, (byte **) &rawdata);
00492     if (rawsize == -1)
00493         return;
00494 
00495     /* Knightmare- check for bad data */
00496     if (rawdata[6] != 'J' || rawdata[7] != 'F' || rawdata[8] != 'I' || rawdata[9] != 'F') {
00497         Com_Printf("Bad jpg file %s\n", filename);
00498         Mem_Free(rawdata);
00499         return;
00500     }
00501 
00502     /* Initialise libJpeg Object */
00503     cinfo.err = jpeg_std_error(&jerr);
00504     jpeg_create_decompress(&cinfo);
00505 
00506     /* Feed JPEG memory into the libJpeg Object */
00507     ufo_jpeg_mem_src(&cinfo, rawdata, rawsize);
00508 
00509     /* Process JPEG header */
00510     jpeg_read_header(&cinfo, qtrue);
00511 
00512     /* Start Decompression */
00513     jpeg_start_decompress(&cinfo);
00514 
00515     /* Check Colour Components */
00516     if (cinfo.output_components != 3 && cinfo.output_components != 4) {
00517         Com_Printf("Invalid JPEG colour components\n");
00518         jpeg_destroy_decompress(&cinfo);
00519         Mem_Free(rawdata);
00520         return;
00521     }
00522 
00523     /* Allocate Memory for decompressed image */
00524     rgbadata = Mem_Alloc(cinfo.output_width * cinfo.output_height * 4);
00525     if (!rgbadata) {
00526         Com_Printf("Insufficient RAM for JPEG buffer\n");
00527         jpeg_destroy_decompress(&cinfo);
00528         Mem_Free(rawdata);
00529         return;
00530     }
00531 
00532     /* Pass sizes to output */
00533     *width = cinfo.output_width;
00534     *height = cinfo.output_height;
00535 
00536     /* Allocate Scanline buffer */
00537     scanline = Mem_Alloc(cinfo.output_width * 4);
00538     if (!scanline) {
00539         Com_Printf("Insufficient RAM for JPEG scanline buffer\n");
00540         Mem_Free(rgbadata);
00541         jpeg_destroy_decompress(&cinfo);
00542         Mem_Free(rawdata);
00543         return;
00544     }
00545 
00546     /* Read Scanlines, and expand from RGB to RGBA */
00547     q = rgbadata;
00548     while (cinfo.output_scanline < cinfo.output_height) {
00549         p = scanline;
00550         jpeg_read_scanlines(&cinfo, &scanline, 1);
00551 
00552         for (i = 0; i < cinfo.output_width; i++) {
00553             q[0] = p[0];
00554             q[1] = p[1];
00555             q[2] = p[2];
00556             q[3] = 255;
00557 
00558             p += 3;
00559             q += 4;
00560         }
00561     }
00562 
00563     /* Free the scanline buffer */
00564     Mem_Free(scanline);
00565 
00566     /* Finish Decompression */
00567     jpeg_finish_decompress(&cinfo);
00568 
00569     /* Destroy JPEG object */
00570     jpeg_destroy_decompress(&cinfo);
00571 
00572     /* Return the 'rgbadata' */
00573     *pic = rgbadata;
00574     Mem_Free(rawdata);
00575 }
00576 
00581 int TryLoadJPG (const char *path, miptex_t **mt)
00582 {
00583     byte *pic = NULL;
00584     int width, height;
00585     size_t size;
00586     byte *dest;
00587 
00588     LoadJPG(path, &pic, &width, &height);
00589     if (pic == NULL)
00590         return -1;
00591 
00592     size = sizeof(*mt) + width * height * 4;
00593     *mt = (miptex_t *)Mem_Alloc(size);
00594 
00595     dest = (byte*)(*mt) + sizeof(*mt);
00596     memcpy(dest, pic, width * height * 4);  /* stuff RGBA into this opaque space */
00597     Mem_Free(pic);
00598 
00599     /* copy relevant header fields to miptex_t */
00600     (*mt)->width = width;
00601     (*mt)->height = height;
00602     (*mt)->offsets[0] = sizeof(*mt);
00603 
00604     return 0;
00605 }

Generated by  doxygen 1.6.2