Subversion Repositories Kolibri OS

Rev

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

  1. #include "fitz.h"
  2.  
  3. #include <jpeglib.h>
  4. #include <setjmp.h>
  5.  
  6. typedef struct fz_dctd_s fz_dctd;
  7.  
  8. struct fz_dctd_s
  9. {
  10.         fz_stream *chain;
  11.         int color_transform;
  12.         int init;
  13.         int stride;
  14.         unsigned char *scanline;
  15.         unsigned char *rp, *wp;
  16.         struct jpeg_decompress_struct cinfo;
  17.         struct jpeg_source_mgr srcmgr;
  18.         struct jpeg_error_mgr errmgr;
  19.         jmp_buf jb;
  20.         char msg[JMSG_LENGTH_MAX];
  21. };
  22.  
  23. static void error_exit(j_common_ptr cinfo)
  24. {
  25.         fz_dctd *state = cinfo->client_data;
  26.         cinfo->err->format_message(cinfo, state->msg);
  27.         longjmp(state->jb, 1);
  28. }
  29.  
  30. static void init_source(j_decompress_ptr cinfo)
  31. {
  32.         /* nothing to do */
  33. }
  34.  
  35. static void term_source(j_decompress_ptr cinfo)
  36. {
  37.         /* nothing to do */
  38. }
  39.  
  40. static boolean fill_input_buffer(j_decompress_ptr cinfo)
  41. {
  42.         struct jpeg_source_mgr *src = cinfo->src;
  43.         fz_dctd *state = cinfo->client_data;
  44.         fz_stream *chain = state->chain;
  45.  
  46.         chain->rp = chain->wp;
  47.         fz_fill_buffer(chain);
  48.         src->next_input_byte = chain->rp;
  49.         src->bytes_in_buffer = chain->wp - chain->rp;
  50.  
  51.         if (src->bytes_in_buffer == 0)
  52.         {
  53.                 static unsigned char eoi[2] = { 0xFF, JPEG_EOI };
  54.                 fz_warn("premature end of file in jpeg");
  55.                 src->next_input_byte = eoi;
  56.                 src->bytes_in_buffer = 2;
  57.         }
  58.  
  59.         return 1;
  60. }
  61.  
  62. static void skip_input_data(j_decompress_ptr cinfo, long num_bytes)
  63. {
  64.         struct jpeg_source_mgr *src = cinfo->src;
  65.         if (num_bytes > 0)
  66.         {
  67.                 while ((size_t)num_bytes > src->bytes_in_buffer)
  68.                 {
  69.                         num_bytes -= src->bytes_in_buffer;
  70.                         (void) src->fill_input_buffer(cinfo);
  71.                 }
  72.                 src->next_input_byte += num_bytes;
  73.                 src->bytes_in_buffer -= num_bytes;
  74.         }
  75. }
  76.  
  77. static int
  78. read_dctd(fz_stream *stm, unsigned char *buf, int len)
  79. {
  80.         fz_dctd *state = stm->state;
  81.         j_decompress_ptr cinfo = &state->cinfo;
  82.         unsigned char *p = buf;
  83.         unsigned char *ep = buf + len;
  84.  
  85.         if (setjmp(state->jb))
  86.         {
  87.                 if (cinfo->src)
  88.                         state->chain->rp = state->chain->wp - cinfo->src->bytes_in_buffer;
  89.                 return fz_throw("jpeg error: %s", state->msg);
  90.         }
  91.  
  92.         if (!state->init)
  93.         {
  94.                 cinfo->client_data = state;
  95.                 cinfo->err = &state->errmgr;
  96.                 jpeg_std_error(cinfo->err);
  97.                 cinfo->err->error_exit = error_exit;
  98.                 jpeg_create_decompress(cinfo);
  99.  
  100.                 cinfo->src = &state->srcmgr;
  101.                 cinfo->src->init_source = init_source;
  102.                 cinfo->src->fill_input_buffer = fill_input_buffer;
  103.                 cinfo->src->skip_input_data = skip_input_data;
  104.                 cinfo->src->resync_to_restart = jpeg_resync_to_restart;
  105.                 cinfo->src->term_source = term_source;
  106.                 cinfo->src->next_input_byte = state->chain->rp;
  107.                 cinfo->src->bytes_in_buffer = state->chain->wp - state->chain->rp;
  108.  
  109.                 jpeg_read_header(cinfo, 1);
  110.  
  111.                 /* speed up jpeg decoding a bit */
  112.                 cinfo->dct_method = JDCT_FASTEST;
  113.                 cinfo->do_fancy_upsampling = FALSE;
  114.  
  115.                 /* default value if ColorTransform is not set */
  116.                 if (state->color_transform == -1)
  117.                 {
  118.                         if (state->cinfo.num_components == 3)
  119.                                 state->color_transform = 1;
  120.                         else
  121.                                 state->color_transform = 0;
  122.                 }
  123.  
  124.                 if (cinfo->saw_Adobe_marker)
  125.                         state->color_transform = cinfo->Adobe_transform;
  126.  
  127.                 /* Guess the input colorspace, and set output colorspace accordingly */
  128.                 switch (cinfo->num_components)
  129.                 {
  130.                 case 3:
  131.                         if (state->color_transform)
  132.                                 cinfo->jpeg_color_space = JCS_YCbCr;
  133.                         else
  134.                                 cinfo->jpeg_color_space = JCS_RGB;
  135.                         break;
  136.                 case 4:
  137.                         if (state->color_transform)
  138.                                 cinfo->jpeg_color_space = JCS_YCCK;
  139.                         else
  140.                                 cinfo->jpeg_color_space = JCS_CMYK;
  141.                         break;
  142.                 }
  143.  
  144.                 jpeg_start_decompress(cinfo);
  145.  
  146.                 state->stride = cinfo->output_width * cinfo->output_components;
  147.                 state->scanline = fz_malloc(state->stride);
  148.                 state->rp = state->scanline;
  149.                 state->wp = state->scanline;
  150.  
  151.                 state->init = 1;
  152.         }
  153.  
  154.         while (state->rp < state->wp && p < ep)
  155.                 *p++ = *state->rp++;
  156.  
  157.         while (p < ep)
  158.         {
  159.                 if (cinfo->output_scanline == cinfo->output_height)
  160.                         break;
  161.  
  162.                 if (p + state->stride <= ep)
  163.                 {
  164.                         jpeg_read_scanlines(cinfo, &p, 1);
  165.                         p += state->stride;
  166.                 }
  167.                 else
  168.                 {
  169.                         jpeg_read_scanlines(cinfo, &state->scanline, 1);
  170.                         state->rp = state->scanline;
  171.                         state->wp = state->scanline + state->stride;
  172.                 }
  173.  
  174.                 while (state->rp < state->wp && p < ep)
  175.                         *p++ = *state->rp++;
  176.         }
  177.  
  178.         return p - buf;
  179. }
  180.  
  181. static void
  182. close_dctd(fz_stream *stm)
  183. {
  184.         fz_dctd *state = stm->state;
  185.  
  186.         if (setjmp(state->jb))
  187.         {
  188.                 state->chain->rp = state->chain->wp - state->cinfo.src->bytes_in_buffer;
  189.                 fz_warn("jpeg error: %s", state->msg);
  190.                 goto skip;
  191.         }
  192.  
  193.         if (state->init)
  194.                 jpeg_finish_decompress(&state->cinfo);
  195.  
  196. skip:
  197.         state->chain->rp = state->chain->wp - state->cinfo.src->bytes_in_buffer;
  198.         jpeg_destroy_decompress(&state->cinfo);
  199.         fz_free(state->scanline);
  200.         fz_close(state->chain);
  201.         fz_free(state);
  202. }
  203.  
  204. fz_stream *
  205. fz_open_dctd(fz_stream *chain, fz_obj *params)
  206. {
  207.         fz_dctd *state;
  208.         fz_obj *obj;
  209.  
  210.         state = fz_malloc(sizeof(fz_dctd));
  211.         memset(state, 0, sizeof(fz_dctd));
  212.         state->chain = chain;
  213.         state->color_transform = -1; /* unset */
  214.         state->init = 0;
  215.  
  216.         obj = fz_dict_gets(params, "ColorTransform");
  217.         if (obj)
  218.                 state->color_transform = fz_to_int(obj);
  219.  
  220.         return fz_new_stream(state, read_dctd, close_dctd);
  221. }
  222.