Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.     IMGLIB:  An example image loading library for use with SDL
  3.     Copyright (C) 1999  Sam Lantinga
  4.  
  5.     This library is free software; you can redistribute it and/or
  6.     modify it under the terms of the GNU Library General Public
  7.     License as published by the Free Software Foundation; either
  8.     version 2 of the License, or (at your option) any later version.
  9.  
  10.     This library is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.     Library General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU Library General Public
  16.     License along with this library; if not, write to the Free
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.     Sam Lantinga
  20.     5635-34 Springhouse Dr.
  21.     Pleasanton, CA 94588 (USA)
  22.     slouken@devolution.com
  23. */
  24.  
  25. /* This is a JPEG image file loading framework */
  26.  
  27. #include <stdio.h>
  28. #include <string.h>
  29.  
  30. #include "SDL_image.h"
  31.  
  32. #ifdef LOAD_JPG
  33.  
  34. #include <jpeglib.h>
  35.  
  36. /* Define this for fast loading and not as good image quality */
  37. /*#define FAST_JPEG*/
  38.  
  39. /* See if an image is contained in a data source */
  40. int IMG_isJPG(SDL_RWops *src)
  41. {
  42.         int is_JPG;
  43.         Uint8 magic[4];
  44.  
  45.         is_JPG = 0;
  46.         if ( SDL_RWread(src, magic, 2, 1) ) {
  47.                 if ( (magic[0] == 0xFF) && (magic[1] == 0xD8) ) {
  48.                         SDL_RWread(src, magic, 4, 1);
  49.                         SDL_RWread(src, magic, 4, 1);
  50.                         if ( memcmp((char *)magic, "JFIF", 4) == 0 ) {
  51.                                 is_JPG = 1;
  52.                         }
  53.                 }
  54.         }
  55.         return(is_JPG);
  56. }
  57.  
  58. #define INPUT_BUFFER_SIZE       4096
  59. typedef struct {
  60.         struct jpeg_source_mgr pub;
  61.  
  62.         SDL_RWops *ctx;
  63.         Uint8 buffer[INPUT_BUFFER_SIZE];
  64. } my_source_mgr;
  65.  
  66. /*
  67.  * Initialize source --- called by jpeg_read_header
  68.  * before any data is actually read.
  69.  */
  70. static void init_source (j_decompress_ptr cinfo)
  71. {
  72.         /* We don't actually need to do anything */
  73.         return;
  74. }
  75.  
  76. /*
  77.  * Fill the input buffer --- called whenever buffer is emptied.
  78.  */
  79. static int fill_input_buffer (j_decompress_ptr cinfo)
  80. {
  81.         my_source_mgr * src = (my_source_mgr *) cinfo->src;
  82.         int nbytes;
  83.  
  84.         nbytes = SDL_RWread(src->ctx, src->buffer, 1, INPUT_BUFFER_SIZE);
  85.         if (nbytes <= 0) {
  86.                 /* Insert a fake EOI marker */
  87.                 src->buffer[0] = (Uint8) 0xFF;
  88.                 src->buffer[1] = (Uint8) JPEG_EOI;
  89.                 nbytes = 2;
  90.         }
  91.         src->pub.next_input_byte = src->buffer;
  92.         src->pub.bytes_in_buffer = nbytes;
  93.  
  94.         return TRUE;
  95. }
  96.  
  97.  
  98. /*
  99.  * Skip data --- used to skip over a potentially large amount of
  100.  * uninteresting data (such as an APPn marker).
  101.  *
  102.  * Writers of suspendable-input applications must note that skip_input_data
  103.  * is not granted the right to give a suspension return.  If the skip extends
  104.  * beyond the data currently in the buffer, the buffer can be marked empty so
  105.  * that the next read will cause a fill_input_buffer call that can suspend.
  106.  * Arranging for additional bytes to be discarded before reloading the input
  107.  * buffer is the application writer's problem.
  108.  */
  109. static void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
  110. {
  111.         my_source_mgr * src = (my_source_mgr *) cinfo->src;
  112.  
  113.         /* Just a dumb implementation for now.  Could use fseek() except
  114.          * it doesn't work on pipes.  Not clear that being smart is worth
  115.          * any trouble anyway --- large skips are infrequent.
  116.          */
  117.         if (num_bytes > 0) {
  118.                 while (num_bytes > (long) src->pub.bytes_in_buffer) {
  119.                         num_bytes -= (long) src->pub.bytes_in_buffer;
  120.                         (void) src->pub.fill_input_buffer(cinfo);
  121.                         /* note we assume that fill_input_buffer will never
  122.                          * return FALSE, so suspension need not be handled.
  123.                          */
  124.                 }
  125.                 src->pub.next_input_byte += (size_t) num_bytes;
  126.                 src->pub.bytes_in_buffer -= (size_t) num_bytes;
  127.         }
  128. }
  129.  
  130. /*
  131.  * Terminate source --- called by jpeg_finish_decompress
  132.  * after all data has been read.
  133.  */
  134. static void term_source (j_decompress_ptr cinfo)
  135. {
  136.         /* We don't actually need to do anything */
  137.         return;
  138. }
  139.  
  140. /*
  141.  * Prepare for input from a stdio stream.
  142.  * The caller must have already opened the stream, and is responsible
  143.  * for closing it after finishing decompression.
  144.  */
  145. static void jpeg_SDL_RW_src (j_decompress_ptr cinfo, SDL_RWops *ctx)
  146. {
  147.   my_source_mgr *src;
  148.  
  149.   /* The source object and input buffer are made permanent so that a series
  150.    * of JPEG images can be read from the same file by calling jpeg_stdio_src
  151.    * only before the first one.  (If we discarded the buffer at the end of
  152.    * one image, we'd likely lose the start of the next one.)
  153.    * This makes it unsafe to use this manager and a different source
  154.    * manager serially with the same JPEG object.  Caveat programmer.
  155.    */
  156.   if (cinfo->src == NULL) {     /* first time for this JPEG object? */
  157.     cinfo->src = (struct jpeg_source_mgr *)
  158.       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
  159.                                   sizeof(my_source_mgr));
  160.     src = (my_source_mgr *) cinfo->src;
  161.   }
  162.  
  163.   src = (my_source_mgr *) cinfo->src;
  164.   src->pub.init_source = init_source;
  165.   src->pub.fill_input_buffer = fill_input_buffer;
  166.   src->pub.skip_input_data = skip_input_data;
  167.   src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
  168.   src->pub.term_source = term_source;
  169.   src->ctx = ctx;
  170.   src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
  171.   src->pub.next_input_byte = NULL; /* until buffer loaded */
  172. }
  173.  
  174. /* Load a JPEG type image from an SDL datasource */
  175. SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src)
  176. {
  177.         struct jpeg_error_mgr errmgr;
  178.         struct jpeg_decompress_struct cinfo;
  179.         JSAMPROW rowptr[1];
  180.         SDL_Surface *surface;
  181.  
  182.         /* Create a decompression structure and load the JPEG header */
  183.         cinfo.err = jpeg_std_error(&errmgr);
  184.         jpeg_create_decompress(&cinfo);
  185.         jpeg_SDL_RW_src(&cinfo, src);
  186.         jpeg_read_header(&cinfo, TRUE);
  187.  
  188.         /* Set 24-bit RGB output */
  189.         cinfo.out_color_space = JCS_RGB;
  190.         cinfo.quantize_colors = FALSE;
  191. #ifdef FAST_JPEG
  192.         cinfo.scale_num   = 1;
  193.         cinfo.scale_denom = 1;
  194.         cinfo.dct_method = JDCT_FASTEST;
  195.         cinfo.do_fancy_upsampling = FALSE;
  196. #endif
  197.         jpeg_calc_output_dimensions(&cinfo);
  198.  
  199.         /* Allocate an output surface to hold the image */
  200.         surface = SDL_AllocSurface(SDL_SWSURFACE,
  201.                        cinfo.output_width, cinfo.output_height, 24,
  202. #if SDL_BYTEORDER == SDL_LIL_ENDIAN
  203.                                    0x0000FF, 0x00FF00, 0xFF0000,
  204. #else
  205.                                    0xFF0000, 0x00FF00, 0x0000FF,
  206. #endif
  207.                                    0);
  208.         if ( surface == NULL ) {
  209.                 IMG_SetError("Out of memory");
  210.                 goto done;
  211.         }
  212.  
  213.         /* Decompress the image */
  214.         jpeg_start_decompress(&cinfo);
  215.         while ( cinfo.output_scanline < cinfo.output_height ) {
  216.                 rowptr[0] = (JSAMPROW)(Uint8 *)surface->pixels +
  217.                                     cinfo.output_scanline * surface->pitch;
  218.                 jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1);
  219.         }
  220.         jpeg_finish_decompress(&cinfo);
  221.  
  222.         /* Clean up and return */
  223. done:
  224.         jpeg_destroy_decompress(&cinfo);
  225.         return(surface);
  226. }
  227.  
  228. #else
  229.  
  230. /* See if an image is contained in a data source */
  231. int IMG_isJPG(SDL_RWops *src)
  232. {
  233.         return(0);
  234. }
  235.  
  236. /* Load a JPEG type image from an SDL datasource */
  237. SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src)
  238. {
  239.         return(NULL);
  240. }
  241.  
  242. #endif /* LOAD_JPG */
  243.