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. #include "mupdf.h"
  3.  
  4. /* TODO: store JPEG compressed samples */
  5. /* TODO: store flate compressed samples */
  6.  
  7. static fz_error pdf_load_jpx_image(fz_pixmap **imgp, pdf_xref *xref, fz_obj *dict);
  8.  
  9. static void
  10. pdf_mask_color_key(fz_pixmap *pix, int n, int *colorkey)
  11. {
  12.         unsigned char *p = pix->samples;
  13.         int len = pix->w * pix->h;
  14.         int k, t;
  15.         while (len--)
  16.         {
  17.                 t = 1;
  18.                 for (k = 0; k < n; k++)
  19.                         if (p[k] < colorkey[k * 2] || p[k] > colorkey[k * 2 + 1])
  20.                                 t = 0;
  21.                 if (t)
  22.                         for (k = 0; k < pix->n; k++)
  23.                                 p[k] = 0;
  24.                 p += pix->n;
  25.         }
  26. }
  27.  
  28. static fz_error
  29. pdf_load_image_imp(fz_pixmap **imgp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cstm, int forcemask)
  30. {
  31.         fz_stream *stm;
  32.         fz_pixmap *tile;
  33.         fz_obj *obj, *res;
  34.         fz_error error;
  35.  
  36.         int w, h, bpc, n;
  37.         int imagemask;
  38.         int interpolate;
  39.         int indexed;
  40.         fz_colorspace *colorspace;
  41.         fz_pixmap *mask; /* explicit mask/softmask image */
  42.         int usecolorkey;
  43.         int colorkey[FZ_MAX_COLORS * 2];
  44.         float decode[FZ_MAX_COLORS * 2];
  45.  
  46.         int stride;
  47.         unsigned char *samples;
  48.         int i, len;
  49.  
  50.         /* special case for JPEG2000 images */
  51.         if (pdf_is_jpx_image(dict))
  52.         {
  53.                 tile = NULL;
  54.                 error = pdf_load_jpx_image(&tile, xref, dict);
  55.                 if (error)
  56.                         return fz_rethrow(error, "cannot load jpx image");
  57.                 if (forcemask)
  58.                 {
  59.                         if (tile->n != 2)
  60.                         {
  61.                                 fz_drop_pixmap(tile);
  62.                                 return fz_throw("softmask must be grayscale");
  63.                         }
  64.                         mask = fz_alpha_from_gray(tile, 1);
  65.                         fz_drop_pixmap(tile);
  66.                         *imgp = mask;
  67.                         return fz_okay;
  68.                 }
  69.                 *imgp = tile;
  70.                 return fz_okay;
  71.         }
  72.  
  73.         w = fz_to_int(fz_dict_getsa(dict, "Width", "W"));
  74.         h = fz_to_int(fz_dict_getsa(dict, "Height", "H"));
  75.         bpc = fz_to_int(fz_dict_getsa(dict, "BitsPerComponent", "BPC"));
  76.         imagemask = fz_to_bool(fz_dict_getsa(dict, "ImageMask", "IM"));
  77.         interpolate = fz_to_bool(fz_dict_getsa(dict, "Interpolate", "I"));
  78.  
  79.         indexed = 0;
  80.         usecolorkey = 0;
  81.         colorspace = NULL;
  82.         mask = NULL;
  83.  
  84.         if (imagemask)
  85.                 bpc = 1;
  86.  
  87.         if (w == 0)
  88.                 return fz_throw("image width is zero");
  89.         if (h == 0)
  90.                 return fz_throw("image height is zero");
  91.         if (bpc == 0)
  92.                 return fz_throw("image depth is zero");
  93.         if (bpc > 16)
  94.                 return fz_throw("image depth is too large: %d", bpc);
  95.         if (w > (1 << 16))
  96.                 return fz_throw("image is too wide");
  97.         if (h > (1 << 16))
  98.                 return fz_throw("image is too high");
  99.  
  100.         obj = fz_dict_getsa(dict, "ColorSpace", "CS");
  101.         if (obj && !imagemask && !forcemask)
  102.         {
  103.                 /* colorspace resource lookup is only done for inline images */
  104.                 if (fz_is_name(obj))
  105.                 {
  106.                         res = fz_dict_get(fz_dict_gets(rdb, "ColorSpace"), obj);
  107.                         if (res)
  108.                                 obj = res;
  109.                 }
  110.  
  111.                 error = pdf_load_colorspace(&colorspace, xref, obj);
  112.                 if (error)
  113.                         return fz_rethrow(error, "cannot load image colorspace");
  114.  
  115.                 if (!strcmp(colorspace->name, "Indexed"))
  116.                         indexed = 1;
  117.  
  118.                 n = colorspace->n;
  119.         }
  120.         else
  121.         {
  122.                 n = 1;
  123.         }
  124.  
  125.         obj = fz_dict_getsa(dict, "Decode", "D");
  126.         if (obj)
  127.         {
  128.                 for (i = 0; i < n * 2; i++)
  129.                         decode[i] = fz_to_real(fz_array_get(obj, i));
  130.         }
  131.         else
  132.         {
  133.                 float maxval = indexed ? (1 << bpc) - 1 : 1;
  134.                 for (i = 0; i < n * 2; i++)
  135.                         decode[i] = i & 1 ? maxval : 0;
  136.         }
  137.  
  138.         obj = fz_dict_getsa(dict, "SMask", "Mask");
  139.         if (fz_is_dict(obj))
  140.         {
  141.                 /* Not allowed for inline images */
  142.                 if (!cstm)
  143.                 {
  144.                         error = pdf_load_image_imp(&mask, xref, rdb, obj, NULL, 1);
  145.                         if (error)
  146.                         {
  147.                                 if (colorspace)
  148.                                         fz_drop_colorspace(colorspace);
  149.                                 return fz_rethrow(error, "cannot load image mask/softmask");
  150.                         }
  151.                 }
  152.         }
  153.         else if (fz_is_array(obj))
  154.         {
  155.                 usecolorkey = 1;
  156.                 for (i = 0; i < n * 2; i++)
  157.                         colorkey[i] = fz_to_int(fz_array_get(obj, i));
  158.         }
  159.  
  160.         /* Allocate now, to fail early if we run out of memory */
  161.         tile = fz_new_pixmap_with_limit(colorspace, w, h);
  162.         if (!tile)
  163.         {
  164.                 if (colorspace)
  165.                         fz_drop_colorspace(colorspace);
  166.                 if (mask)
  167.                         fz_drop_pixmap(mask);
  168.                 return fz_throw("out of memory");
  169.         }
  170.  
  171.         if (colorspace)
  172.                 fz_drop_colorspace(colorspace);
  173.  
  174.         tile->mask = mask;
  175.         tile->interpolate = interpolate;
  176.  
  177.         stride = (w * n * bpc + 7) / 8;
  178.  
  179.         if (cstm)
  180.         {
  181.                 stm = pdf_open_inline_stream(cstm, xref, dict, stride * h);
  182.         }
  183.         else
  184.         {
  185.                 error = pdf_open_stream(&stm, xref, fz_to_num(dict), fz_to_gen(dict));
  186.                 if (error)
  187.                 {
  188.                         fz_drop_pixmap(tile);
  189.                         return fz_rethrow(error, "cannot open image data stream (%d 0 R)", fz_to_num(dict));
  190.                 }
  191.         }
  192.  
  193.         samples = fz_calloc(h, stride);
  194.  
  195.         len = fz_read(stm, samples, h * stride);
  196.         if (len < 0)
  197.         {
  198.                 fz_close(stm);
  199.                 fz_free(samples);
  200.                 fz_drop_pixmap(tile);
  201.                 return fz_rethrow(len, "cannot read image data");
  202.         }
  203.  
  204.         /* Make sure we read the EOF marker (for inline images only) */
  205.         if (cstm)
  206.         {
  207.                 unsigned char tbuf[512];
  208.                 int tlen = fz_read(stm, tbuf, sizeof tbuf);
  209.                 if (tlen < 0)
  210.                         fz_catch(tlen, "ignoring error at end of image");
  211.                 if (tlen > 0)
  212.                         fz_warn("ignoring garbage at end of image");
  213.         }
  214.  
  215.         fz_close(stm);
  216.  
  217.         /* Pad truncated images */
  218.         if (len < stride * h)
  219.         {
  220.                 fz_warn("padding truncated image (%d 0 R)", fz_to_num(dict));
  221.                 memset(samples + len, 0, stride * h - len);
  222.         }
  223.  
  224.         /* Invert 1-bit image masks */
  225.         if (imagemask)
  226.         {
  227.                 /* 0=opaque and 1=transparent so we need to invert */
  228.                 unsigned char *p = samples;
  229.                 len = h * stride;
  230.                 for (i = 0; i < len; i++)
  231.                         p[i] = ~p[i];
  232.         }
  233.  
  234.         fz_unpack_tile(tile, samples, n, bpc, stride, indexed);
  235.  
  236.         fz_free(samples);
  237.  
  238.         if (usecolorkey)
  239.                 pdf_mask_color_key(tile, n, colorkey);
  240.  
  241.         if (indexed)
  242.         {
  243.                 fz_pixmap *conv;
  244.                 fz_decode_indexed_tile(tile, decode, (1 << bpc) - 1);
  245.                 conv = pdf_expand_indexed_pixmap(tile);
  246.                 fz_drop_pixmap(tile);
  247.                 tile = conv;
  248.         }
  249.         else
  250.         {
  251.                 fz_decode_tile(tile, decode);
  252.         }
  253.  
  254.         *imgp = tile;
  255.         return fz_okay;
  256. }
  257.  
  258. fz_error
  259. pdf_load_inline_image(fz_pixmap **pixp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict, fz_stream *file)
  260. {
  261.         fz_error error;
  262.  
  263.         error = pdf_load_image_imp(pixp, xref, rdb, dict, file, 0);
  264.         if (error)
  265.                 return fz_rethrow(error, "cannot load inline image");
  266.  
  267.         return fz_okay;
  268. }
  269.  
  270. int
  271. pdf_is_jpx_image(fz_obj *dict)
  272. {
  273.         fz_obj *filter;
  274.         int i;
  275.  
  276.         filter = fz_dict_gets(dict, "Filter");
  277.         if (!strcmp(fz_to_name(filter), "JPXDecode"))
  278.                 return 1;
  279.         for (i = 0; i < fz_array_len(filter); i++)
  280.                 if (!strcmp(fz_to_name(fz_array_get(filter, i)), "JPXDecode"))
  281.                         return 1;
  282.         return 0;
  283. }
  284.  
  285. static fz_error
  286. pdf_load_jpx_image(fz_pixmap **imgp, pdf_xref *xref, fz_obj *dict)
  287. {
  288.         fz_error error;
  289.         fz_buffer *buf;
  290.         fz_colorspace *colorspace;
  291.         fz_pixmap *img;
  292.         fz_obj *obj;
  293.  
  294.         colorspace = NULL;
  295.  
  296.         error = pdf_load_stream(&buf, xref, fz_to_num(dict), fz_to_gen(dict));
  297.         if (error)
  298.                 return fz_rethrow(error, "cannot load jpx image data");
  299.  
  300.         obj = fz_dict_gets(dict, "ColorSpace");
  301.         if (obj)
  302.         {
  303.                 error = pdf_load_colorspace(&colorspace, xref, obj);
  304.                 if (error)
  305.                         fz_catch(error, "cannot load image colorspace");
  306.         }
  307.  
  308.         error = fz_load_jpx_image(&img, buf->data, buf->len, colorspace);
  309.         if (error)
  310.         {
  311.                 if (colorspace)
  312.                         fz_drop_colorspace(colorspace);
  313.                 fz_drop_buffer(buf);
  314.                 return fz_rethrow(error, "cannot load jpx image");
  315.         }
  316.  
  317.         if (colorspace)
  318.                 fz_drop_colorspace(colorspace);
  319.         fz_drop_buffer(buf);
  320.  
  321.         obj = fz_dict_getsa(dict, "SMask", "Mask");
  322.         if (fz_is_dict(obj))
  323.         {
  324.                 error = pdf_load_image_imp(&img->mask, xref, NULL, obj, NULL, 1);
  325.                 if (error)
  326.                 {
  327.                         fz_drop_pixmap(img);
  328.                         return fz_rethrow(error, "cannot load image mask/softmask");
  329.                 }
  330.         }
  331.  
  332.         *imgp = img;
  333.         return fz_okay;
  334. }
  335.  
  336. fz_error
  337. pdf_load_image(fz_pixmap **pixp, pdf_xref *xref, fz_obj *dict)
  338. {
  339.         fz_error error;
  340.  
  341.         if ((*pixp = pdf_find_item(xref->store, fz_drop_pixmap, dict)))
  342.         {
  343.                 fz_keep_pixmap(*pixp);
  344.                 return fz_okay;
  345.         }
  346.  
  347.         error = pdf_load_image_imp(pixp, xref, NULL, dict, NULL, 0);
  348.         if (error)
  349.                 return fz_rethrow(error, "cannot load image (%d 0 R)", fz_to_num(dict));
  350.  
  351.         pdf_store_item(xref->store, fz_keep_pixmap, fz_drop_pixmap, dict, *pixp);
  352.  
  353.         return fz_okay;
  354. }
  355.