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. /* ICCBased */
  5.  
  6. static fz_error
  7. load_icc_based(fz_colorspace **csp, pdf_xref *xref, fz_obj *dict)
  8. {
  9.         int n;
  10.  
  11.         n = fz_to_int(fz_dict_gets(dict, "N"));
  12.  
  13.         switch (n)
  14.         {
  15.         case 1: *csp = fz_device_gray; return fz_okay;
  16.         case 3: *csp = fz_device_rgb; return fz_okay;
  17.         case 4: *csp = fz_device_cmyk; return fz_okay;
  18.         }
  19.  
  20.         return fz_throw("syntaxerror: ICCBased must have 1, 3 or 4 components");
  21. }
  22.  
  23. /* Lab */
  24.  
  25. static inline float fung(float x)
  26. {
  27.         if (x >= 6.0f / 29.0f)
  28.                 return x * x * x;
  29.         return (108.0f / 841.0f) * (x - (4.0f / 29.0f));
  30. }
  31.  
  32. static void
  33. lab_to_rgb(fz_colorspace *cs, float *lab, float *rgb)
  34. {
  35.         /* input is in range (0..100, -128..127, -128..127) not (0..1, 0..1, 0..1) */
  36.         float lstar, astar, bstar, l, m, n, x, y, z, r, g, b;
  37.         lstar = lab[0];
  38.         astar = lab[1];
  39.         bstar = lab[2];
  40.         m = (lstar + 16) / 116;
  41.         l = m + astar / 500;
  42.         n = m - bstar / 200;
  43.         x = fung(l);
  44.         y = fung(m);
  45.         z = fung(n);
  46.         r = (3.240449f * x + -1.537136f * y + -0.498531f * z) * 0.830026f;
  47.         g = (-0.969265f * x + 1.876011f * y + 0.041556f * z) * 1.05452f;
  48.         b = (0.055643f * x + -0.204026f * y + 1.057229f * z) * 1.1003f;
  49.         rgb[0] = sqrtf(CLAMP(r, 0, 1));
  50.         rgb[1] = sqrtf(CLAMP(g, 0, 1));
  51.         rgb[2] = sqrtf(CLAMP(b, 0, 1));
  52. }
  53.  
  54. static void
  55. rgb_to_lab(fz_colorspace *cs, float *rgb, float *lab)
  56. {
  57.         fz_warn("cannot convert into L*a*b colorspace");
  58.         lab[0] = rgb[0];
  59.         lab[1] = rgb[1];
  60.         lab[2] = rgb[2];
  61. }
  62.  
  63. static fz_colorspace k_device_lab = { -1, "Lab", 3, lab_to_rgb, rgb_to_lab };
  64. static fz_colorspace *fz_device_lab = &k_device_lab;
  65.  
  66. /* Separation and DeviceN */
  67.  
  68. struct separation
  69. {
  70.         fz_colorspace *base;
  71.         pdf_function *tint;
  72. };
  73.  
  74. static void
  75. separation_to_rgb(fz_colorspace *cs, float *color, float *rgb)
  76. {
  77.         struct separation *sep = cs->data;
  78.         float alt[FZ_MAX_COLORS];
  79.         pdf_eval_function(sep->tint, color, cs->n, alt, sep->base->n);
  80.         sep->base->to_rgb(sep->base, alt, rgb);
  81. }
  82.  
  83. static void
  84. free_separation(fz_colorspace *cs)
  85. {
  86.         struct separation *sep = cs->data;
  87.         fz_drop_colorspace(sep->base);
  88.         pdf_drop_function(sep->tint);
  89.         fz_free(sep);
  90. }
  91.  
  92. static fz_error
  93. load_separation(fz_colorspace **csp, pdf_xref *xref, fz_obj *array)
  94. {
  95.         fz_error error;
  96.         fz_colorspace *cs;
  97.         struct separation *sep;
  98.         fz_obj *nameobj = fz_array_get(array, 1);
  99.         fz_obj *baseobj = fz_array_get(array, 2);
  100.         fz_obj *tintobj = fz_array_get(array, 3);
  101.         fz_colorspace *base;
  102.         pdf_function *tint;
  103.         int n;
  104.  
  105.         if (fz_is_array(nameobj))
  106.                 n = fz_array_len(nameobj);
  107.         else
  108.                 n = 1;
  109.  
  110.         if (n > FZ_MAX_COLORS)
  111.                 return fz_throw("too many components in colorspace");
  112.  
  113.         error = pdf_load_colorspace(&base, xref, baseobj);
  114.         if (error)
  115.                 return fz_rethrow(error, "cannot load base colorspace (%d %d R)", fz_to_num(baseobj), fz_to_gen(baseobj));
  116.  
  117.         error = pdf_load_function(&tint, xref, tintobj);
  118.         if (error)
  119.         {
  120.                 fz_drop_colorspace(base);
  121.                 return fz_rethrow(error, "cannot load tint function (%d %d R)", fz_to_num(tintobj), fz_to_gen(tintobj));
  122.         }
  123.  
  124.         sep = fz_malloc(sizeof(struct separation));
  125.         sep->base = base;
  126.         sep->tint = tint;
  127.  
  128.         cs = fz_new_colorspace(n == 1 ? "Separation" : "DeviceN", n);
  129.         cs->to_rgb = separation_to_rgb;
  130.         cs->free_data = free_separation;
  131.         cs->data = sep;
  132.  
  133.         *csp = cs;
  134.         return fz_okay;
  135. }
  136.  
  137. /* Indexed */
  138.  
  139. struct indexed
  140. {
  141.         fz_colorspace *base;
  142.         int high;
  143.         unsigned char *lookup;
  144. };
  145.  
  146. static void
  147. indexed_to_rgb(fz_colorspace *cs, float *color, float *rgb)
  148. {
  149.         struct indexed *idx = cs->data;
  150.         float alt[FZ_MAX_COLORS];
  151.         int i, k;
  152.         i = color[0] * 255;
  153.         i = CLAMP(i, 0, idx->high);
  154.         for (k = 0; k < idx->base->n; k++)
  155.                 alt[k] = idx->lookup[i * idx->base->n + k] / 255.0f;
  156.         idx->base->to_rgb(idx->base, alt, rgb);
  157. }
  158.  
  159. static void
  160. free_indexed(fz_colorspace *cs)
  161. {
  162.         struct indexed *idx = cs->data;
  163.         if (idx->base)
  164.                 fz_drop_colorspace(idx->base);
  165.         fz_free(idx->lookup);
  166.         fz_free(idx);
  167. }
  168.  
  169. fz_pixmap *
  170. pdf_expand_indexed_pixmap(fz_pixmap *src)
  171. {
  172.         struct indexed *idx;
  173.         fz_pixmap *dst;
  174.         unsigned char *s, *d;
  175.         int y, x, k, n, high;
  176.         unsigned char *lookup;
  177.  
  178.         assert(src->colorspace->to_rgb == indexed_to_rgb);
  179.         assert(src->n == 2);
  180.  
  181.         idx = src->colorspace->data;
  182.         high = idx->high;
  183.         lookup = idx->lookup;
  184.         n = idx->base->n;
  185.  
  186.         dst = fz_new_pixmap_with_rect(idx->base, fz_bound_pixmap(src));
  187.         s = src->samples;
  188.         d = dst->samples;
  189.  
  190.         for (y = 0; y < src->h; y++)
  191.         {
  192.                 for (x = 0; x < src->w; x++)
  193.                 {
  194.                         int v = *s++;
  195.                         int a = *s++;
  196.                         v = MIN(v, high);
  197.                         for (k = 0; k < n; k++)
  198.                                 *d++ = fz_mul255(lookup[v * n + k], a);
  199.                         *d++ = a;
  200.                 }
  201.         }
  202.  
  203.         if (src->mask)
  204.                 dst->mask = fz_keep_pixmap(src->mask);
  205.         dst->interpolate = src->interpolate;
  206.  
  207.         return dst;
  208. }
  209.  
  210. static fz_error
  211. load_indexed(fz_colorspace **csp, pdf_xref *xref, fz_obj *array)
  212. {
  213.         fz_error error;
  214.         fz_colorspace *cs;
  215.         struct indexed *idx;
  216.         fz_obj *baseobj = fz_array_get(array, 1);
  217.         fz_obj *highobj = fz_array_get(array, 2);
  218.         fz_obj *lookup = fz_array_get(array, 3);
  219.         fz_colorspace *base;
  220.         int i, n;
  221.  
  222.         error = pdf_load_colorspace(&base, xref, baseobj);
  223.         if (error)
  224.                 return fz_rethrow(error, "cannot load base colorspace (%d %d R)", fz_to_num(baseobj), fz_to_gen(baseobj));
  225.  
  226.         idx = fz_malloc(sizeof(struct indexed));
  227.         idx->base = base;
  228.         idx->high = fz_to_int(highobj);
  229.         idx->high = CLAMP(idx->high, 0, 255);
  230.         n = base->n * (idx->high + 1);
  231.         idx->lookup = fz_malloc(n);
  232.         memset(idx->lookup, 0, n);
  233.  
  234.         cs = fz_new_colorspace("Indexed", 1);
  235.         cs->to_rgb = indexed_to_rgb;
  236.         cs->free_data = free_indexed;
  237.         cs->data = idx;
  238.  
  239.         if (fz_is_string(lookup) && fz_to_str_len(lookup) == n)
  240.         {
  241.                 unsigned char *buf = (unsigned char *) fz_to_str_buf(lookup);
  242.                 for (i = 0; i < n; i++)
  243.                         idx->lookup[i] = buf[i];
  244.         }
  245.         else if (fz_is_indirect(lookup))
  246.         {
  247.                 fz_stream *file;
  248.  
  249.                 error = pdf_open_stream(&file, xref, fz_to_num(lookup), fz_to_gen(lookup));
  250.                 if (error)
  251.                 {
  252.                         fz_drop_colorspace(cs);
  253.                         return fz_rethrow(error, "cannot open colorspace lookup table (%d 0 R)", fz_to_num(lookup));
  254.                 }
  255.  
  256.                 i = fz_read(file, idx->lookup, n);
  257.                 if (i < 0)
  258.                 {
  259.                         fz_drop_colorspace(cs);
  260.                         return fz_throw("cannot read colorspace lookup table (%d 0 R)", fz_to_num(lookup));
  261.                 }
  262.  
  263.                 fz_close(file);
  264.         }
  265.         else
  266.         {
  267.                 fz_drop_colorspace(cs);
  268.                 return fz_throw("cannot parse colorspace lookup table");
  269.         }
  270.  
  271.         *csp = cs;
  272.         return fz_okay;
  273. }
  274.  
  275. /* Parse and create colorspace from PDF object */
  276.  
  277. static fz_error
  278. pdf_load_colorspace_imp(fz_colorspace **csp, pdf_xref *xref, fz_obj *obj)
  279. {
  280.         if (fz_is_name(obj))
  281.         {
  282.                 if (!strcmp(fz_to_name(obj), "Pattern"))
  283.                         *csp = fz_device_gray;
  284.                 else if (!strcmp(fz_to_name(obj), "G"))
  285.                         *csp = fz_device_gray;
  286.                 else if (!strcmp(fz_to_name(obj), "RGB"))
  287.                         *csp = fz_device_rgb;
  288.                 else if (!strcmp(fz_to_name(obj), "CMYK"))
  289.                         *csp = fz_device_cmyk;
  290.                 else if (!strcmp(fz_to_name(obj), "DeviceGray"))
  291.                         *csp = fz_device_gray;
  292.                 else if (!strcmp(fz_to_name(obj), "DeviceRGB"))
  293.                         *csp = fz_device_rgb;
  294.                 else if (!strcmp(fz_to_name(obj), "DeviceCMYK"))
  295.                         *csp = fz_device_cmyk;
  296.                 else
  297.                         return fz_throw("unknown colorspace: %s", fz_to_name(obj));
  298.                 return fz_okay;
  299.         }
  300.  
  301.         else if (fz_is_array(obj))
  302.         {
  303.                 fz_obj *name = fz_array_get(obj, 0);
  304.  
  305.                 if (fz_is_name(name))
  306.                 {
  307.                         /* load base colorspace instead */
  308.                         if (!strcmp(fz_to_name(name), "Pattern"))
  309.                         {
  310.                                 fz_error error;
  311.  
  312.                                 obj = fz_array_get(obj, 1);
  313.                                 if (!obj)
  314.                                 {
  315.                                         *csp = fz_device_gray;
  316.                                         return fz_okay;
  317.                                 }
  318.  
  319.                                 error = pdf_load_colorspace(csp, xref, obj);
  320.                                 if (error)
  321.                                         return fz_rethrow(error, "cannot load pattern (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
  322.                         }
  323.  
  324.                         else if (!strcmp(fz_to_name(name), "G"))
  325.                                 *csp = fz_device_gray;
  326.                         else if (!strcmp(fz_to_name(name), "RGB"))
  327.                                 *csp = fz_device_rgb;
  328.                         else if (!strcmp(fz_to_name(name), "CMYK"))
  329.                                 *csp = fz_device_cmyk;
  330.                         else if (!strcmp(fz_to_name(name), "DeviceGray"))
  331.                                 *csp = fz_device_gray;
  332.                         else if (!strcmp(fz_to_name(name), "DeviceRGB"))
  333.                                 *csp = fz_device_rgb;
  334.                         else if (!strcmp(fz_to_name(name), "DeviceCMYK"))
  335.                                 *csp = fz_device_cmyk;
  336.                         else if (!strcmp(fz_to_name(name), "CalGray"))
  337.                                 *csp = fz_device_gray;
  338.                         else if (!strcmp(fz_to_name(name), "CalRGB"))
  339.                                 *csp = fz_device_rgb;
  340.                         else if (!strcmp(fz_to_name(name), "CalCMYK"))
  341.                                 *csp = fz_device_cmyk;
  342.                         else if (!strcmp(fz_to_name(name), "Lab"))
  343.                                 *csp = fz_device_lab;
  344.  
  345.                         else if (!strcmp(fz_to_name(name), "ICCBased"))
  346.                                 return load_icc_based(csp, xref, fz_array_get(obj, 1));
  347.  
  348.                         else if (!strcmp(fz_to_name(name), "Indexed"))
  349.                                 return load_indexed(csp, xref, obj);
  350.                         else if (!strcmp(fz_to_name(name), "I"))
  351.                                 return load_indexed(csp, xref, obj);
  352.  
  353.                         else if (!strcmp(fz_to_name(name), "Separation"))
  354.                                 return load_separation(csp, xref, obj);
  355.  
  356.                         else if (!strcmp(fz_to_name(name), "DeviceN"))
  357.                                 return load_separation(csp, xref, obj);
  358.  
  359.                         else
  360.                                 return fz_throw("syntaxerror: unknown colorspace %s", fz_to_name(name));
  361.  
  362.                         return fz_okay;
  363.                 }
  364.         }
  365.  
  366.         return fz_throw("syntaxerror: could not parse color space (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
  367. }
  368.  
  369. fz_error
  370. pdf_load_colorspace(fz_colorspace **csp, pdf_xref *xref, fz_obj *obj)
  371. {
  372.         fz_error error;
  373.  
  374.         if ((*csp = pdf_find_item(xref->store, fz_drop_colorspace, obj)))
  375.         {
  376.                 fz_keep_colorspace(*csp);
  377.                 return fz_okay;
  378.         }
  379.  
  380.         error = pdf_load_colorspace_imp(csp, xref, obj);
  381.         if (error)
  382.                 return fz_rethrow(error, "cannot load colorspace (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
  383.  
  384.         pdf_store_item(xref->store, fz_keep_colorspace, fz_drop_colorspace, obj, *csp);
  385.  
  386.         return fz_okay;
  387. }
  388.