summaryrefslogtreecommitdiff
path: root/source/pdf
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2017-07-13 17:32:32 +0100
committerRobin Watts <robin.watts@artifex.com>2017-09-08 17:48:07 +0100
commit7e4a177d55b3a290300f6671c0670e5a5897da24 (patch)
tree81190342149dc508787247efa78854383997cad8 /source/pdf
parenta7f36241cba4d1807ab4664201aa0975755d6772 (diff)
downloadmupdf-7e4a177d55b3a290300f6671c0670e5a5897da24.tar.xz
Update fz_separations equivalent color mechanism.
Incorporates fixes from Michael. Rather than specifically giving it rgb and cmyk values, separations now include the colorspace. Conversions can then be done into ANY colorspace we need. Note, that we maintain the old way of working for the gproof device. Also, fix pdf_page_separations to correctly find all separations. This involves recursively looking through colorspaces, forms and shadings for colorspaces therein, making sure we don't run into any circular references. We do 2 passes, so that we can pick up as many colorants as Separations as possible. On the second pass we pick up any colorants we missed in terms of DeviceN spaces. The purpose of this is to try to ensure that we get as many tint transforms as single input functions as we can. This may not be important in the grand scheme of things, but seems neater.
Diffstat (limited to 'source/pdf')
-rw-r--r--source/pdf/pdf-page.c188
1 files changed, 163 insertions, 25 deletions
diff --git a/source/pdf/pdf-page.c b/source/pdf/pdf-page.c
index 5b319e3a..9c7c8922 100644
--- a/source/pdf/pdf-page.c
+++ b/source/pdf/pdf-page.c
@@ -638,42 +638,115 @@ pdf_page_transform(fz_context *ctx, pdf_page *page, fz_rect *page_mediabox, fz_m
pdf_page_obj_transform(ctx, page->obj, page_mediabox, page_ctm);
}
-fz_separations *
-pdf_page_separations(fz_context *ctx, pdf_page *page)
+static void
+find_seps(fz_context *ctx, fz_separations **seps, pdf_obj *obj)
{
- pdf_obj *res = pdf_page_resources(ctx, page);
- fz_separations *seps = NULL;
- int i, len;
+ int i, n;
+ pdf_obj *nameobj = pdf_array_get(ctx, obj, 0);
- res = pdf_dict_get(ctx, res, PDF_NAME_ColorSpace);
- if (!res)
- return NULL;
+ if (pdf_name_eq(ctx, nameobj, PDF_NAME_Separation))
+ {
+ fz_colorspace *cs;
+ const char *name = pdf_to_name(ctx, pdf_array_get(ctx, obj, 1));
+
+ /* Skip 'special' colorants. */
+ if (!strcmp(name, "Black") ||
+ !strcmp(name, "Cyan") ||
+ !strcmp(name, "Magenta") ||
+ !strcmp(name, "Yellow") ||
+ !strcmp(name, "All") ||
+ !strcmp(name, "None"))
+ return;
+
+ n = fz_count_separations(ctx, *seps);
+ for (i = 0; i < n; i++)
+ {
+ if (!strcmp(name, fz_separation_name(ctx, *seps, i)))
+ return; /* Got that one already */
+ }
- fz_var(seps);
- fz_var(i);
+ cs = pdf_load_colorspace(ctx, obj);
+ if (!*seps)
+ *seps = fz_new_separations(ctx, 0);
+ fz_add_separation(ctx, *seps, name, cs, 0);
+ fz_drop_colorspace(ctx, cs);
+ }
+ else if (pdf_name_eq(ctx, nameobj, PDF_NAME_Indexed))
+ {
+ find_seps(ctx, seps, pdf_array_get(ctx, obj, 1));
+ }
+ else if (pdf_name_eq(ctx, nameobj, PDF_NAME_DeviceN))
+ {
+ /* If the separation colorants exists for this DeviceN color space
+ * add those prior to our search for DeviceN color */
+ pdf_obj *cols = pdf_dict_get(ctx, pdf_array_get(ctx, obj, 4), PDF_NAME_Colorants);
+ int i, n = pdf_dict_len(ctx, cols);
+ for (i = 0; i < n; i++)
+ find_seps(ctx, seps, pdf_dict_get_val(ctx, cols, i));
+ }
+}
- len = pdf_dict_len(ctx, res);
+static void
+find_devn(fz_context *ctx, fz_separations **seps, pdf_obj *obj)
+{
+ int i, j, n, m;
+ pdf_obj *arr;
+ pdf_obj *nameobj = pdf_array_get(ctx, obj, 0);
+
+ if (!pdf_name_eq(ctx, nameobj, PDF_NAME_DeviceN))
+ return;
+
+ arr = pdf_array_get(ctx, obj, 1);
+ m = pdf_array_len(ctx, arr);
+ for (j = 0; j < m; j++)
+ {
+ fz_colorspace *cs;
+ const char *name = pdf_to_name(ctx, pdf_array_get(ctx, arr, j));
+
+ /* Skip 'special' colorants. */
+ if (!strcmp(name, "Black") ||
+ !strcmp(name, "Cyan") ||
+ !strcmp(name, "Magenta") ||
+ !strcmp(name, "Yellow") ||
+ !strcmp(name, "All") ||
+ !strcmp(name, "None"))
+ continue;
+
+ n = fz_count_separations(ctx, *seps);
+ for (i = 0; i < n; i++)
+ {
+ if (!strcmp(name, fz_separation_name(ctx, *seps, i)))
+ break; /* Got that one already */
+ }
+
+ if (i == n)
+ {
+ cs = pdf_load_colorspace(ctx, obj);
+ if (!*seps)
+ *seps = fz_new_separations(ctx, 0);
+ fz_add_separation(ctx, *seps, name, cs, j);
+ fz_drop_colorspace(ctx, cs);
+ }
+ }
+}
+
+typedef void (res_finder_fn)(fz_context *ctx, fz_separations **seps, pdf_obj *obj);
+
+static void
+search_res(fz_context *ctx, fz_separations **seps, pdf_obj *res, res_finder_fn *fn)
+{
+ int i = 0;
+ int len = pdf_dict_len(ctx, res);
+
+ fz_var(i);
- i = 0;
while (i < len)
{
fz_try(ctx)
{
do
{
- pdf_obj *obj;
- i++;
- obj = pdf_dict_get_val(ctx, res, i-1);
-
- if (pdf_name_eq(ctx, pdf_array_get(ctx, obj, 0), PDF_NAME_Separation))
- {
- uint32_t rgba = 0; /* FIXME */
- uint32_t cmyk = 0; /* FIXME */
- const char *name = pdf_to_name(ctx, pdf_array_get(ctx, obj, 1));
- if (!seps)
- seps = fz_new_separations(ctx, 0);
- fz_add_separation(ctx, seps, rgba, cmyk, name);
- }
+ fn(ctx, seps, pdf_dict_get_val(ctx, res, i++));
}
while (i < len);
}
@@ -682,6 +755,71 @@ pdf_page_separations(fz_context *ctx, pdf_page *page)
/* Don't die because a single separation failed to load */
}
}
+}
+
+static void
+scan_page_seps(fz_context *ctx, pdf_obj *res, fz_separations **seps, res_finder_fn *fn)
+{
+ pdf_obj *forms;
+ pdf_obj *sh;
+ pdf_obj *xo = NULL;
+ int i, len;
+
+ fz_var(xo);
+
+ if (pdf_mark_obj(ctx, res))
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cycle in resources");
+
+ fz_try(ctx)
+ {
+ search_res(ctx, seps, pdf_dict_get(ctx, res, PDF_NAME_ColorSpace), fn);
+
+ sh = pdf_dict_get(ctx, res, PDF_NAME_Shading);
+ len = pdf_dict_len(ctx, sh);
+ for (i = 0; i < len; i++)
+ fn(ctx, seps, pdf_dict_get(ctx, pdf_dict_get_val(ctx, sh, i), PDF_NAME_ColorSpace));
+
+ forms = pdf_dict_get(ctx, res, PDF_NAME_XObject);
+ len = pdf_dict_len(ctx, forms);
+
+ /* Recurse on the forms. Throw if we cycle */
+ for (i = 0; i < len; i++)
+ {
+ xo = pdf_dict_get_val(ctx, forms, i++);
+
+ if (pdf_mark_obj(ctx, xo))
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cycle in forms");
+
+ scan_page_seps(ctx, pdf_dict_get(ctx, xo, PDF_NAME_Resources), seps, fn);
+ pdf_unmark_obj(ctx, xo);
+ xo = NULL;
+ }
+ }
+ fz_always(ctx)
+ {
+ pdf_unmark_obj(ctx, xo);
+ pdf_unmark_obj(ctx, res);
+ }
+ fz_catch(ctx)
+ fz_rethrow(ctx);
+}
+
+fz_separations *
+pdf_page_separations(fz_context *ctx, pdf_page *page)
+{
+ pdf_obj *res = pdf_page_resources(ctx, page);
+ fz_separations *seps = NULL;
+
+ /* Run through and look for separations first. This is
+ * because separations are simplest to deal with, and
+ * because DeviceN may be implemented on top of separations.
+ */
+ scan_page_seps(ctx, res, &seps, find_seps);
+
+ /* Now run through again, and look for DeviceNs. These may
+ * have spot colors in that aren't defined in terms of
+ * separations. */
+ scan_page_seps(ctx, res, &seps, find_devn);
return seps;
}