summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/cbz/mucbz.c2
-rw-r--r--source/cbz/muimg.c2
-rw-r--r--source/cbz/mutiff.c2
-rw-r--r--source/fitz/bbox-device.c16
-rw-r--r--source/fitz/bitmap.c8
-rw-r--r--source/fitz/buffer.c19
-rw-r--r--source/fitz/color-icc-create.c448
-rw-r--r--source/fitz/color-lcms.c345
-rw-r--r--source/fitz/colorspace-imp.h57
-rw-r--r--source/fitz/colorspace.c1396
-rw-r--r--source/fitz/context.c3
-rw-r--r--source/fitz/device.c39
-rw-r--r--source/fitz/document.c8
-rw-r--r--source/fitz/draw-device.c177
-rw-r--r--source/fitz/draw-mesh.c7
-rw-r--r--source/fitz/fitz-imp.h2
-rw-r--r--source/fitz/icc34.h1022
-rw-r--r--source/fitz/list-device.c146
-rw-r--r--source/fitz/output-cbz.c2
-rw-r--r--source/fitz/output-pcl.c8
-rw-r--r--source/fitz/output-png.c79
-rw-r--r--source/fitz/output-pnm.c12
-rw-r--r--source/fitz/output-ps.c4
-rw-r--r--source/fitz/output-pwg.c8
-rw-r--r--source/fitz/output-tga.c4
-rw-r--r--source/fitz/output.c4
-rw-r--r--source/fitz/pixmap.c9
-rw-r--r--source/fitz/stext-device.c10
-rw-r--r--source/fitz/stext-output.c2
-rw-r--r--source/fitz/svg-device.c76
-rw-r--r--source/fitz/test-device.c82
-rw-r--r--source/fitz/trace-device.c16
-rw-r--r--source/gprf/gprf-doc.c2
-rw-r--r--source/html/html-layout.c12
-rw-r--r--source/pdf/pdf-appearance.c22
-rw-r--r--source/pdf/pdf-colorspace.c310
-rw-r--r--source/pdf/pdf-device.c30
-rw-r--r--source/pdf/pdf-image.c2
-rw-r--r--source/pdf/pdf-interpret.c22
-rw-r--r--source/pdf/pdf-op-buffer.c26
-rw-r--r--source/pdf/pdf-op-filter.c42
-rw-r--r--source/pdf/pdf-op-run.c98
-rw-r--r--source/pdf/pdf-page.c55
-rw-r--r--source/pdf/pdf-run.c10
-rw-r--r--source/pdf/pdf-xref.c3
-rw-r--r--source/svg/svg-run.c4
-rw-r--r--source/tools/mudraw.c27
-rw-r--r--source/tools/muraster.c4
-rw-r--r--source/tools/murun.c100
-rw-r--r--source/tools/pdfextract.c2
-rw-r--r--source/xps/xps-common.c2
-rw-r--r--source/xps/xps-glyphs.c2
-rw-r--r--source/xps/xps-gradient.c6
-rw-r--r--source/xps/xps-image.c2
-rw-r--r--source/xps/xps-path.c4
55 files changed, 4225 insertions, 577 deletions
diff --git a/source/cbz/mucbz.c b/source/cbz/mucbz.c
index 7000dc8f..2d357b6e 100644
--- a/source/cbz/mucbz.c
+++ b/source/cbz/mucbz.c
@@ -162,7 +162,7 @@ cbz_run_page(fz_context *ctx, fz_page *page_, fz_device *dev, const fz_matrix *c
w = image->w * DPI / xres;
h = image->h * DPI / yres;
fz_pre_scale(&local_ctm, w, h);
- fz_fill_image(ctx, dev, image, &local_ctm, 1);
+ fz_fill_image(ctx, dev, image, &local_ctm, 1, NULL);
}
static void
diff --git a/source/cbz/muimg.c b/source/cbz/muimg.c
index 6fe0687d..4cb8cc4a 100644
--- a/source/cbz/muimg.c
+++ b/source/cbz/muimg.c
@@ -57,7 +57,7 @@ img_run_page(fz_context *ctx, fz_page *page_, fz_device *dev, const fz_matrix *c
w = image->w * DPI / xres;
h = image->h * DPI / yres;
fz_pre_scale(&local_ctm, w, h);
- fz_fill_image(ctx, dev, image, &local_ctm, 1);
+ fz_fill_image(ctx, dev, image, &local_ctm, 1, NULL);
}
static void
diff --git a/source/cbz/mutiff.c b/source/cbz/mutiff.c
index 9cd306f2..b6500159 100644
--- a/source/cbz/mutiff.c
+++ b/source/cbz/mutiff.c
@@ -47,7 +47,7 @@ tiff_run_page(fz_context *ctx, fz_page *page_, fz_device *dev, const fz_matrix *
w = image->w * DPI / xres;
h = image->h * DPI / yres;
fz_pre_scale(&local_ctm, w, h);
- fz_fill_image(ctx, dev, image, &local_ctm, 1);
+ fz_fill_image(ctx, dev, image, &local_ctm, 1, NULL);
}
static void
diff --git a/source/fitz/bbox-device.c b/source/fitz/bbox-device.c
index 99c46953..a288ec45 100644
--- a/source/fitz/bbox-device.c
+++ b/source/fitz/bbox-device.c
@@ -37,7 +37,7 @@ fz_bbox_add_rect(fz_context *ctx, fz_device *dev, const fz_rect *rect, int clip)
static void
fz_bbox_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_rect r;
fz_bbox_add_rect(ctx, dev, fz_bound_path(ctx, path, NULL, ctm, &r), 0);
@@ -45,7 +45,7 @@ fz_bbox_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even
static void
fz_bbox_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke,
- const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha)
+ const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_rect r;
fz_bbox_add_rect(ctx, dev, fz_bound_path(ctx, path, stroke, ctm, &r), 0);
@@ -53,7 +53,7 @@ fz_bbox_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const
static void
fz_bbox_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_rect r;
fz_bbox_add_rect(ctx, dev, fz_bound_text(ctx, text, NULL, ctm, &r), 0);
@@ -61,21 +61,21 @@ fz_bbox_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz
static void
fz_bbox_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke,
- const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha)
+ const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_rect r;
fz_bbox_add_rect(ctx, dev, fz_bound_text(ctx, text, stroke, ctm, &r), 0);
}
static void
-fz_bbox_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha)
+fz_bbox_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha, const fz_color_params *color_params)
{
fz_rect r;
fz_bbox_add_rect(ctx, dev, fz_bound_shade(ctx, shade, ctm, &r), 0);
}
static void
-fz_bbox_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha)
+fz_bbox_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha, const fz_color_params *color_params)
{
fz_rect r = fz_unit_rect;
fz_bbox_add_rect(ctx, dev, fz_transform_rect(&r, ctm), 0);
@@ -83,7 +83,7 @@ fz_bbox_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_ma
static void
fz_bbox_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_rect r = fz_unit_rect;
fz_bbox_add_rect(ctx, dev, fz_transform_rect(&r, ctm), 0);
@@ -135,7 +135,7 @@ fz_bbox_pop_clip(fz_context *ctx, fz_device *dev)
}
static void
-fz_bbox_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *rect, int luminosity, fz_colorspace *colorspace, const float *color)
+fz_bbox_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *rect, int luminosity, fz_colorspace *colorspace, const float *color, const fz_color_params *color_params)
{
fz_bbox_device *bdev = (fz_bbox_device*)dev;
fz_bbox_add_rect(ctx, dev, rect, 1);
diff --git a/source/fitz/bitmap.c b/source/fitz/bitmap.c
index eefaebd7..37aabe7b 100644
--- a/source/fitz/bitmap.c
+++ b/source/fitz/bitmap.c
@@ -306,7 +306,7 @@ fz_clear_bitmap(fz_context *ctx, fz_bitmap *bit)
}
static void
-pbm_write_header(fz_context *ctx, fz_band_writer *writer)
+pbm_write_header(fz_context *ctx, fz_band_writer *writer, const fz_colorspace *cs)
{
fz_output *out = writer->out;
int w = writer->w;
@@ -316,7 +316,7 @@ pbm_write_header(fz_context *ctx, fz_band_writer *writer)
}
static void
-pkm_write_header(fz_context *ctx, fz_band_writer *writer)
+pkm_write_header(fz_context *ctx, fz_band_writer *writer, const fz_colorspace *cs)
{
fz_output *out = writer->out;
int w = writer->w;
@@ -336,7 +336,7 @@ fz_write_bitmap_as_pbm(fz_context *ctx, fz_output *out, fz_bitmap *bitmap)
writer = fz_new_pbm_band_writer(ctx, out);
fz_try(ctx)
{
- fz_write_header(ctx, writer, bitmap->w, bitmap->h, 1, 0, 0, 0, 0);
+ fz_write_header(ctx, writer, bitmap->w, bitmap->h, 1, 0, 0, 0, 0, NULL);
fz_write_band(ctx, writer, bitmap->stride, bitmap->h, bitmap->samples);
}
fz_always(ctx)
@@ -356,7 +356,7 @@ fz_write_bitmap_as_pkm(fz_context *ctx, fz_output *out, fz_bitmap *bitmap)
writer = fz_new_pkm_band_writer(ctx, out);
fz_try(ctx)
{
- fz_write_header(ctx, writer, bitmap->w, bitmap->h, 4, 0, 0, 0, 0);
+ fz_write_header(ctx, writer, bitmap->w, bitmap->h, 4, 0, 0, 0, 0, NULL);
fz_write_band(ctx, writer, bitmap->stride, bitmap->h, bitmap->samples);
}
fz_always(ctx)
diff --git a/source/fitz/buffer.c b/source/fitz/buffer.c
index 8212f782..96aa36a6 100644
--- a/source/fitz/buffer.c
+++ b/source/fitz/buffer.c
@@ -251,6 +251,22 @@ fz_append_rune(fz_context *ctx, fz_buffer *buf, int c)
}
void
+fz_append_int32_be(fz_context *ctx, fz_buffer *buf, int x)
+{
+ fz_append_byte(ctx, buf, (x >> 24) & 0xFF);
+ fz_append_byte(ctx, buf, (x >> 16) & 0xFF);
+ fz_append_byte(ctx, buf, (x >> 8) & 0xFF);
+ fz_append_byte(ctx, buf, (x) & 0xFF);
+}
+
+void
+fz_append_int16_be(fz_context *ctx, fz_buffer *buf, int x)
+{
+ fz_append_byte(ctx, buf, (x >> 8) & 0xFF);
+ fz_append_byte(ctx, buf, (x) & 0xFF);
+}
+
+void
fz_append_int32_le(fz_context *ctx, fz_buffer *buf, int x)
{
fz_append_byte(ctx, buf, (x)&0xFF);
@@ -435,7 +451,8 @@ fz_md5_buffer(fz_context *ctx, fz_buffer *buffer, unsigned char digest[16])
{
fz_md5 state;
fz_md5_init(&state);
- fz_md5_update(&state, buffer->data, buffer->len);
+ if (buffer)
+ fz_md5_update(&state, buffer->data, buffer->len);
fz_md5_final(&state, digest);
}
diff --git a/source/fitz/color-icc-create.c b/source/fitz/color-icc-create.c
new file mode 100644
index 00000000..58acedf5
--- /dev/null
+++ b/source/fitz/color-icc-create.c
@@ -0,0 +1,448 @@
+#include "mupdf/fitz.h"
+#include "icc34.h"
+
+#define SAVEICCPROFILE 0
+#define ICC_HEADER_SIZE 128
+#define ICC_TAG_SIZE 12
+#define ICC_NUMBER_COMMON_TAGS 2
+#define ICC_XYZPT_SIZE 12
+#define ICC_DATATYPE_SIZE 8
+#define D50_X 0.9642f
+#define D50_Y 1.0f
+#define D50_Z 0.8249f
+static const char desc_name[] = "MuPDF Internal Profile";
+static const char copy_right[] = "Copyright Artifex Software 2017";
+#if SAVEICCPROFILE
+unsigned int icc_debug_index = 0;
+#endif
+
+typedef struct fz_icc_tag_s fz_icc_tag;
+
+struct fz_icc_tag_s
+{
+ icTagSignature sig;
+ icUInt32Number offset;
+ icUInt32Number size;
+ unsigned char byte_padding;
+};
+
+#if SAVEICCPROFILE
+static void
+save_profile(fz_context *ctx, fz_buffer *buf, const char *name)
+{
+ char full_file_name[50];
+ fz_snprintf(full_file_name, sizeof full_file_name, "profile%d-%s.icc", icc_debug_index, name);
+ fz_save_buffer(ctx, buf, full_file_name);
+ icc_debug_index++;
+}
+#endif
+
+static void
+fz_append_byte_n(fz_context *ctx, fz_buffer *buf, int c, int n)
+{
+ int k;
+
+ for (k = 0; k < n; k++)
+ fz_append_byte(ctx, buf, c);
+}
+
+static int
+get_padding(int x)
+{
+ return (4 - x % 4) % 4;
+}
+
+static void
+setdatetime(fz_context *ctx, icDateTimeNumber *datetime)
+{
+ datetime->day = 0;
+ datetime->hours = 0;
+ datetime->minutes = 0;
+ datetime->month = 0;
+ datetime->seconds = 0;
+ datetime->year = 0;
+}
+
+static void
+add_gammadata(fz_context *ctx, fz_buffer *buf, unsigned short gamma, icTagTypeSignature curveType)
+{
+ fz_append_int32_be(ctx, buf, curveType);
+ fz_append_byte_n(ctx, buf, 0, 4);
+
+ /* one entry for gamma */
+ fz_append_int32_be(ctx, buf, 1);
+
+ /* The encode (8frac8) gamma, with padding */
+ fz_append_int16_be(ctx, buf, gamma);
+
+ /* pad two bytes */
+ fz_append_byte_n(ctx, buf, 0, 2);
+}
+
+static unsigned short
+float2u8Fixed8(fz_context *ctx, float number_in)
+{
+ return (unsigned short)(number_in * 256);
+}
+
+static void
+add_xyzdata(fz_context *ctx, fz_buffer *buf, icS15Fixed16Number temp_XYZ[])
+{
+ int j;
+
+ fz_append_int32_be(ctx, buf, icSigXYZType);
+ fz_append_byte_n(ctx, buf, 0, 4);
+
+ for (j = 0; j < 3; j++)
+ fz_append_int32_be(ctx, buf, temp_XYZ[j]);
+}
+
+static icS15Fixed16Number
+double2XYZtype(fz_context *ctx, float number_in)
+{
+ short s;
+ unsigned short m;
+
+ if (number_in < 0)
+ number_in = 0;
+ s = (short)number_in;
+ m = (unsigned short)((number_in - s) * 65536);
+ return (icS15Fixed16Number) ((s << 16) | m);
+}
+
+static void
+get_D50(fz_context *ctx, icS15Fixed16Number XYZ[])
+{
+ XYZ[0] = double2XYZtype(ctx, D50_X);
+ XYZ[1] = double2XYZtype(ctx, D50_Y);
+ XYZ[2] = double2XYZtype(ctx, D50_Z);
+}
+
+static void
+get_XYZ_doubletr(fz_context *ctx, icS15Fixed16Number XYZ[], float vector[])
+{
+ XYZ[0] = double2XYZtype(ctx, vector[0]);
+ XYZ[1] = double2XYZtype(ctx, vector[1]);
+ XYZ[2] = double2XYZtype(ctx, vector[2]);
+}
+
+static void
+add_desc_tag(fz_context *ctx, fz_buffer *buf, const char text[], fz_icc_tag tag_list[], int curr_tag)
+{
+ int len = strlen(text);
+
+ fz_append_int32_be(ctx, buf, icSigTextDescriptionType);
+ fz_append_byte_n(ctx, buf, 0, 4);
+ fz_append_int32_be(ctx, buf, len + 1);
+ fz_append_string(ctx, buf, text);
+ /* 1 + 4 + 4 + 2 + 1 + 67 */
+ fz_append_byte_n(ctx, buf, 0, 79);
+ fz_append_byte_n(ctx, buf, 0, tag_list[curr_tag].byte_padding);
+}
+
+static void
+add_text_tag(fz_context *ctx, fz_buffer *buf, const char text[], fz_icc_tag tag_list[], int curr_tag)
+{
+ fz_append_int32_be(ctx, buf, icSigTextType);
+ fz_append_byte_n(ctx, buf, 0, 4);
+ fz_append_string(ctx, buf, text);
+ fz_append_byte(ctx, buf, 0);
+ fz_append_byte_n(ctx, buf, 0, tag_list[curr_tag].byte_padding);
+}
+
+static void
+add_common_tag_data(fz_context *ctx, fz_buffer *buf, fz_icc_tag tag_list[])
+{
+ add_desc_tag(ctx, buf, desc_name, tag_list, 0);
+ add_text_tag(ctx, buf, copy_right, tag_list, 1);
+}
+
+static void
+init_common_tags(fz_context *ctx, fz_icc_tag tag_list[], int num_tags, int *last_tag)
+{
+ int curr_tag, temp_size;
+
+ if (*last_tag < 0)
+ curr_tag = 0;
+ else
+ curr_tag = (*last_tag) + 1;
+
+ tag_list[curr_tag].offset = ICC_HEADER_SIZE + num_tags * ICC_TAG_SIZE + 4;
+ tag_list[curr_tag].sig = icSigProfileDescriptionTag;
+
+ /* temp_size = DATATYPE_SIZE + 4 (zeros) + 4 (len) + strlen(desc_name) + 1 (null) + 4 + 4 + 2 + 1 + 67 + bytepad; */
+ temp_size = strlen(desc_name) + 91;
+
+ tag_list[curr_tag].byte_padding = get_padding(temp_size);
+ tag_list[curr_tag].size = temp_size + tag_list[curr_tag].byte_padding;
+ curr_tag++;
+ tag_list[curr_tag].offset = tag_list[curr_tag - 1].offset + tag_list[curr_tag - 1].size;
+ tag_list[curr_tag].sig = icSigCopyrightTag;
+
+ /* temp_size = DATATYPE_SIZE + 4 (zeros) + strlen(copy_right) + 1 (null); */
+ temp_size = strlen(copy_right) + 9;
+ tag_list[curr_tag].byte_padding = get_padding(temp_size);
+ tag_list[curr_tag].size = temp_size + tag_list[curr_tag].byte_padding;
+ *last_tag = curr_tag;
+}
+
+static void
+copy_header(fz_context *ctx, fz_buffer *buffer, icHeader *header)
+{
+ fz_append_int32_be(ctx, buffer, header->size);
+ fz_append_byte_n(ctx, buffer, 0, 4);
+ fz_append_int32_be(ctx, buffer, header->version);
+ fz_append_int32_be(ctx, buffer, header->deviceClass);
+ fz_append_int32_be(ctx, buffer, header->colorSpace);
+ fz_append_int32_be(ctx, buffer, header->pcs);
+ fz_append_byte_n(ctx, buffer, 0, 12);
+ fz_append_int32_be(ctx, buffer, header->magic);
+ fz_append_int32_be(ctx, buffer, header->platform);
+ fz_append_byte_n(ctx, buffer, 0, 24);
+ fz_append_int32_be(ctx, buffer, header->illuminant.X);
+ fz_append_int32_be(ctx, buffer, header->illuminant.Y);
+ fz_append_int32_be(ctx, buffer, header->illuminant.Z);
+ fz_append_byte_n(ctx, buffer, 0, 48);
+}
+
+static void
+setheader_common(fz_context *ctx, icHeader *header)
+{
+ header->cmmId = 0;
+ header->version = 0x02200000;
+ setdatetime(ctx, &(header->date));
+ header->magic = icMagicNumber;
+ header->platform = icSigMacintosh;
+ header->flags = 0;
+ header->manufacturer = 0;
+ header->model = 0;
+ header->attributes[0] = 0;
+ header->attributes[1] = 0;
+ header->renderingIntent = 3;
+ header->illuminant.X = double2XYZtype(ctx, (float) 0.9642);
+ header->illuminant.Y = double2XYZtype(ctx, (float) 1.0);
+ header->illuminant.Z = double2XYZtype(ctx, (float) 0.8249);
+ header->creator = 0;
+ memset(header->reserved, 0, 44);
+}
+
+static void
+copy_tagtable(fz_context *ctx, fz_buffer *buf, fz_icc_tag *tag_list, int num_tags)
+{
+ int k;
+
+ fz_append_int32_be(ctx, buf, num_tags);
+ for (k = 0; k < num_tags; k++)
+ {
+ fz_append_int32_be(ctx, buf, tag_list[k].sig);
+ fz_append_int32_be(ctx, buf, tag_list[k].offset);
+ fz_append_int32_be(ctx, buf, tag_list[k].size);
+ }
+}
+
+static void
+init_tag(fz_context *ctx, fz_icc_tag tag_list[], int *last_tag, icTagSignature tagsig, int datasize)
+{
+ int curr_tag = (*last_tag) + 1;
+
+ tag_list[curr_tag].offset = tag_list[curr_tag - 1].offset + tag_list[curr_tag - 1].size;
+ tag_list[curr_tag].sig = tagsig;
+ tag_list[curr_tag].byte_padding = get_padding(ICC_DATATYPE_SIZE + datasize);
+ tag_list[curr_tag].size = ICC_DATATYPE_SIZE + datasize + tag_list[curr_tag].byte_padding;
+ *last_tag = curr_tag;
+}
+
+static void
+matrixmult(fz_context *ctx, float leftmatrix[], int nlrow, int nlcol, float rightmatrix[], int nrrow, int nrcol, float result[])
+{
+ float *curr_row;
+ int k, l, j, ncols, nrows;
+ float sum;
+
+ nrows = nlrow;
+ ncols = nrcol;
+ if (nlcol == nrrow)
+ {
+ for (k = 0; k < nrows; k++)
+ {
+ curr_row = &(leftmatrix[k*nlcol]);
+ for (l = 0; l < ncols; l++)
+ {
+ sum = 0.0;
+ for (j = 0; j < nlcol; j++)
+ sum = sum + curr_row[j] * rightmatrix[j*nrcol + l];
+ result[k*ncols + l] = sum;
+ }
+ }
+ }
+}
+
+static void
+apply_adaption(fz_context *ctx, float matrix[], float in[], float out[])
+{
+ out[0] = matrix[0] * in[0] + matrix[1] * in[1] + matrix[2] * in[2];
+ out[1] = matrix[3] * in[0] + matrix[4] * in[1] + matrix[5] * in[2];
+ out[2] = matrix[6] * in[0] + matrix[7] * in[1] + matrix[8] * in[2];
+}
+
+/*
+ Compute the CAT02 transformation to get us from the Cal White point to the
+ D50 white point
+*/
+static void
+gsicc_create_compute_cam(fz_context *ctx, float white_src[], float *cam)
+{
+ float cat02matrix[] = { 0.7328f, 0.4296f, -0.1624f, -0.7036f, 1.6975f, 0.0061f, 0.003f, 0.0136f, 0.9834f };
+ float cat02matrixinv[] = { 1.0961f, -0.2789f, 0.1827f, 0.4544f, 0.4735f, 0.0721f, -0.0096f, -0.0057f, 1.0153f };
+ float vonkries_diag[9];
+ float temp_matrix[9];
+ float lms_wp_src[3], lms_wp_des[3];
+ int k;
+ float d50[3] = { D50_X, D50_Y, D50_Z };
+
+ matrixmult(ctx, cat02matrix, 3, 3, white_src, 3, 1, lms_wp_src);
+ matrixmult(ctx, cat02matrix, 3, 3, d50, 3, 1, lms_wp_des);
+ memset(&(vonkries_diag[0]), 0, sizeof(float) * 9);
+
+ for (k = 0; k < 3; k++)
+ {
+ if (lms_wp_src[k] > 0)
+ vonkries_diag[k * 3 + k] = lms_wp_des[k] / lms_wp_src[k];
+ else
+ vonkries_diag[k * 3 + k] = 1;
+ }
+ matrixmult(ctx, &(vonkries_diag[0]), 3, 3, cat02matrix, 3, 3, temp_matrix);
+ matrixmult(ctx, &(cat02matrixinv[0]), 3, 3, temp_matrix, 3, 3, cam);
+}
+
+/* Create ICC profile from PDF calGray and calRGB definitions */
+fz_buffer *
+fz_new_icc_data_from_cal_colorspace(fz_context *ctx, fz_cal_colorspace *cal)
+{
+ fz_icc_tag *tag_list;
+ icProfile iccprofile;
+ icHeader *header = &(iccprofile.header);
+ fz_buffer *profile;
+ size_t profile_size;
+ int k;
+ int num_tags;
+ unsigned short encode_gamma;
+ int last_tag;
+ icS15Fixed16Number temp_XYZ[3];
+ int tag_location;
+ icTagSignature TRC_Tags[3] = { icSigRedTRCTag, icSigGreenTRCTag, icSigBlueTRCTag };
+ int trc_tag_size;
+ float cat02[9];
+ float black_adapt[3];
+ int n = cal->n;
+
+ /* common */
+ setheader_common(ctx, header);
+ header->pcs = icSigXYZData;
+ profile_size = ICC_HEADER_SIZE;
+ header->deviceClass = icSigInputClass;
+
+ if (n == 3)
+ {
+ header->colorSpace = icSigRgbData;
+ num_tags = 10; /* common (2) + rXYZ, gXYZ, bXYZ, rTRC, gTRC, bTRC, bkpt, wtpt */
+ }
+ else
+ {
+ header->colorSpace = icSigGrayData;
+ num_tags = 5; /* common (2) + GrayTRC, bkpt, wtpt */
+ TRC_Tags[0] = icSigGrayTRCTag;
+ }
+
+ tag_list = fz_malloc(ctx, sizeof(fz_icc_tag) * num_tags);
+
+ /* precompute sizes and offsets */
+ profile_size += ICC_TAG_SIZE * num_tags;
+ profile_size += 4; /* number of tags.... */
+ last_tag = -1;
+ init_common_tags(ctx, tag_list, num_tags, &last_tag);
+ if (n == 3)
+ {
+ init_tag(ctx, tag_list, &last_tag, icSigRedColorantTag, ICC_XYZPT_SIZE);
+ init_tag(ctx, tag_list, &last_tag, icSigGreenColorantTag, ICC_XYZPT_SIZE);
+ init_tag(ctx, tag_list, &last_tag, icSigBlueColorantTag, ICC_XYZPT_SIZE);
+ }
+ init_tag(ctx, tag_list, &last_tag, icSigMediaWhitePointTag, ICC_XYZPT_SIZE);
+ init_tag(ctx, tag_list, &last_tag, icSigMediaBlackPointTag, ICC_XYZPT_SIZE);
+
+ /* 4 for count, 2 for gamma, Extra 2 bytes for 4 byte alignment requirement */
+ trc_tag_size = 8;
+ for (k = 0; k < n; k++)
+ init_tag(ctx, tag_list, &last_tag, TRC_Tags[k], trc_tag_size);
+ for (k = 0; k < num_tags; k++)
+ profile_size += tag_list[k].size;
+
+ /* Allocate buffer */
+ fz_try(ctx)
+ {
+ profile = fz_new_buffer(ctx, profile_size);
+ }
+ fz_catch(ctx)
+ {
+ fz_free(ctx, tag_list);
+ fz_rethrow(ctx);
+ }
+
+ /* Header */
+ header->size = (icUInt32Number)profile_size;
+ copy_header(ctx, profile, header);
+
+ /* Tag table */
+ copy_tagtable(ctx, profile, tag_list, num_tags);
+
+ /* Common tags */
+ add_common_tag_data(ctx, profile, tag_list);
+ tag_location = ICC_NUMBER_COMMON_TAGS;
+
+ /* Get the cat02 matrix */
+ gsicc_create_compute_cam(ctx, cal->wp, cat02);
+
+ /* The matrix */
+ if (n == 3)
+ {
+ float primary[3];
+
+ for (k = 0; k < 3; k++)
+ {
+ /* Apply the cat02 matrix to the primaries */
+ apply_adaption(ctx, cat02, &(cal->matrix[k * 3]), &(primary[0]));
+ get_XYZ_doubletr(ctx, temp_XYZ, &(primary[0]));
+ add_xyzdata(ctx, profile, temp_XYZ);
+ tag_location++;
+ }
+ }
+
+ /* White and black points. WP is D50 */
+ get_D50(ctx, temp_XYZ);
+ add_xyzdata(ctx, profile, temp_XYZ);
+ tag_location++;
+
+ /* Black point. Apply cat02*/
+ apply_adaption(ctx, cat02, cal->bp, &(black_adapt[0]));
+ get_XYZ_doubletr(ctx, temp_XYZ, &(black_adapt[0]));
+ add_xyzdata(ctx, profile, temp_XYZ);
+ tag_location++;
+
+ /* Gamma */
+ for (k = 0; k < n; k++)
+ {
+ encode_gamma = float2u8Fixed8(ctx, cal->gamma[k]);
+ add_gammadata(ctx, profile, encode_gamma, icSigCurveType);
+ tag_location++;
+ }
+
+ fz_free(ctx, tag_list);
+
+#if SAVEICCPROFILE
+ if (n == 3)
+ save_profile(ctx, profile, "calRGB");
+ else
+ save_profile(ctx, profile, "calGray");
+#endif
+ return profile;
+}
diff --git a/source/fitz/color-lcms.c b/source/fitz/color-lcms.c
new file mode 100644
index 00000000..4e75850f
--- /dev/null
+++ b/source/fitz/color-lcms.c
@@ -0,0 +1,345 @@
+#include "mupdf/fitz.h"
+#include "lcms2.h"
+#include "lcms2_plugin.h"
+#include "colorspace-imp.h"
+
+#define LCMS_BYTES_MASK 0x7
+/* #define DEBUG_LCMS_MEM(A) do { printf A; fflush(stdout); } while (0) */
+#define DEBUG_LCMS_MEM(A) do { } while (0)
+
+static void
+fz_lcms_log_error(cmsContext id, cmsUInt32Number error_code, const char *error_text)
+{
+ fz_context *ctx = (fz_context *)cmsGetContextUserData(id);
+ fz_warn(ctx, "lcms error: %s", error_text);
+}
+
+static void
+*fz_lcms_malloc(cmsContext id, unsigned int size)
+{
+ void *result;
+ fz_context *ctx = (fz_context *)cmsGetContextUserData(id);
+ result = fz_malloc_no_throw(ctx, size);
+ DEBUG_LCMS_MEM(("Allocation:: mupdf ctx = %p lcms ctx = %p allocation = %p \n", (void*) ctx, (void*) id, (void*) result));
+ return result;
+}
+
+static void
+fz_lcms_free(cmsContext id, void *ptr)
+{
+ fz_context *ctx = (fz_context *)cmsGetContextUserData(id);
+ DEBUG_LCMS_MEM(("Free:: mupdf ctx = %p lcms ctx = %p allocation = %p \n", (void*) ctx, (void*) id, (void*) ptr));
+ fz_free(ctx, ptr);
+}
+
+static void*
+fz_lcms_realloc(cmsContext id, void *ptr, unsigned int size)
+{
+ fz_context *ctx = (fz_context *)cmsGetContextUserData(id);
+ DEBUG_LCMS_MEM(("Realloc:: mupdf ctx = %p lcms ctx = %p allocation = %p \n", (void*) ctx, (void*) id, (void*) ptr));
+ if (ptr == 0)
+ return fz_lcms_malloc(id, size);
+ if (size == 0)
+ {
+ fz_lcms_free(id, ptr);
+ return NULL;
+ }
+ return fz_resize_array_no_throw(ctx, ptr, size, 1);
+}
+
+static cmsPluginMemHandler fz_lcms_memhandler =
+{
+ {
+ cmsPluginMagicNumber,
+ 2000,
+ cmsPluginMemHandlerSig,
+ NULL
+ },
+ fz_lcms_malloc,
+ fz_lcms_free,
+ fz_lcms_realloc,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static int
+fz_lcms_num_devcomps(cmsContext cmm_ctx, fz_iccprofile *profile)
+{
+ return cmsChannelsOf(cmm_ctx, cmsGetColorSpace(cmm_ctx, profile->cmm_handle));
+}
+
+static void
+fz_lcms_premultiply_row(fz_context *ctx, int n, int w, unsigned char *s)
+{
+ unsigned char a;
+ int k;
+ int n1 = n-1;
+
+ for (; w > 0; w--)
+ {
+ a = s[n1];
+ for (k = 0; k < n1; k++)
+ s[k] = fz_mul255(s[k], a);
+ s += n;
+ }
+}
+
+static void
+fz_lcms_unmultiply_row(fz_context *ctx, int n, int w, unsigned char *s, const unsigned char *in)
+{
+ int a, inva;
+ int k;
+ int n1 = n-1;
+
+ for (; w > 0; w--)
+ {
+ a = in[n1];
+ inva = a ? 255 * 256 / a : 0;
+ for (k = 0; k < n1; k++)
+ s[k] = (in[k] * inva) >> 8;
+ s += n;
+ in += n;
+ }
+}
+
+/* Transform pixmap */
+void
+fz_lcms_transform_pixmap(fz_cmm_instance *instance, fz_icclink *link, fz_pixmap *dst, fz_pixmap *src)
+{
+ cmsContext cmm_ctx = (cmsContext)instance;
+ fz_context *ctx = (fz_context *)cmsGetContextUserData(cmm_ctx);
+ cmsHTRANSFORM hTransform = (cmsHTRANSFORM)link->cmm_handle;
+ int cmm_num_src, cmm_num_des;
+ unsigned char *inputpos, *outputpos, *buffer;
+ int ss = src->stride;
+ int ds = dst->stride;
+ int sw = src->w;
+ int dw = dst->w;
+ int sn = src->n;
+ int dn = dst->n;
+ int sa = src->alpha;
+ int da = dst->alpha;
+ int h = src->h;
+ DEBUG_LCMS_MEM(("@@@@@@@ Transform Pixmap Start:: mupdf ctx = %p lcms ctx = %p link = %p \n", (void*)ctx, (void*)cmm_ctx, (void*)link->cmm_handle));
+
+ /* check the channels. */
+ cmm_num_src = T_CHANNELS(cmsGetTransformInputFormat(cmm_ctx, hTransform));
+ cmm_num_des = T_CHANNELS(cmsGetTransformOutputFormat(cmm_ctx, hTransform));
+ if (cmm_num_src != sn - sa || cmm_num_des != dn - da || sa != da)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Mismatching color setup in cmm pixmap transformation: src: %d vs %d+%d, dst: %d vs %d+%d", cmm_num_src, sn-sa, sa, cmm_num_des, dn-da, da);
+
+ /* Transform */
+ inputpos = src->samples;
+ outputpos = dst->samples;
+ if (src->alpha)
+ {
+ /* Allow for premultiplied alpha */
+ buffer = fz_malloc(ctx, ss);
+ for (; h > 0; h--)
+ {
+ fz_lcms_unmultiply_row(ctx, sn, sw, buffer, inputpos);
+ cmsDoTransform(cmm_ctx, hTransform, inputpos, outputpos, sw);
+ fz_lcms_premultiply_row(ctx, dn, dw, outputpos);
+ inputpos += ss;
+ outputpos += ds;
+ }
+ fz_free(ctx, buffer);
+ }
+ else
+ {
+ for (; h > 0; h--)
+ {
+ cmsDoTransform(cmm_ctx, hTransform, inputpos, outputpos, sw);
+ inputpos += ss;
+ outputpos += ds;
+ }
+ }
+ DEBUG_LCMS_MEM(("@@@@@@@ Transform Pixmap End:: mupdf ctx = %p lcms ctx = %p link = %p \n", (void*)ctx, (void*)cmm_ctx, (void*)link->cmm_handle));
+}
+
+/* Transform a single color. */
+void
+fz_lcms_transform_color(fz_cmm_instance *instance, fz_icclink *link, unsigned short *dst, const unsigned short *src)
+{
+ cmsContext cmm_ctx = (cmsContext)instance;
+ cmsHTRANSFORM hTransform = (cmsHTRANSFORM) link->cmm_handle;
+
+ cmsDoTransform(cmm_ctx, hTransform, src, dst, 1);
+}
+
+void
+fz_lcms_init_link(fz_cmm_instance *instance, fz_icclink *link, const fz_color_params *rend, int cmm_flags, int num_bytes, int alpha, const fz_iccprofile *src, const fz_iccprofile *prf, const fz_iccprofile *dst)
+{
+ cmsContext cmm_ctx = (cmsContext)instance;
+ fz_context *ctx = (fz_context *)cmsGetContextUserData(cmm_ctx);
+
+ cmsUInt32Number src_data_type, des_data_type;
+ cmsColorSpaceSignature src_cs, des_cs;
+ int src_num_chan, des_num_chan;
+ int lcms_src_cs, lcms_des_cs;
+ unsigned int flag = cmsFLAGS_LOWRESPRECALC | cmm_flags;
+
+ DEBUG_LCMS_MEM(("@@@@@@@ Create Link Start:: mupdf ctx = %p lcms ctx = %p src = %p des = %p \n", (void*)ctx, (void*)cmm_ctx, (void*)src->cmm_handle, (void*)dst->cmm_handle));
+
+ /* src */
+ src_cs = cmsGetColorSpace(cmm_ctx, src->cmm_handle);
+ lcms_src_cs = _cmsLCMScolorSpace(cmm_ctx, src_cs);
+ if (lcms_src_cs < 0)
+ lcms_src_cs = 0;
+ src_num_chan = cmsChannelsOf(cmm_ctx, src_cs);
+ src_data_type = (COLORSPACE_SH(lcms_src_cs) | CHANNELS_SH(src_num_chan) | DOSWAP_SH(src->bgr) | BYTES_SH(num_bytes) | EXTRA_SH(alpha));
+
+ /* dst */
+ des_cs = cmsGetColorSpace(cmm_ctx, dst->cmm_handle);
+ lcms_des_cs = _cmsLCMScolorSpace(cmm_ctx, des_cs);
+ if (lcms_des_cs < 0)
+ lcms_des_cs = 0;
+ des_num_chan = cmsChannelsOf(cmm_ctx, des_cs);
+ des_data_type = (COLORSPACE_SH(lcms_des_cs) | CHANNELS_SH(des_num_chan) | DOSWAP_SH(dst->bgr) | BYTES_SH(num_bytes) | EXTRA_SH(alpha));
+
+ /* flags */
+ if (rend->bp)
+ flag |= cmsFLAGS_BLACKPOINTCOMPENSATION;
+
+ if (alpha)
+ flag |= cmsFLAGS_COPY_ALPHA;
+
+ link->depth = num_bytes;
+ link->alpha = alpha;
+
+ if (prf == NULL)
+ {
+ link->cmm_handle = cmsCreateTransformTHR(cmm_ctx, src->cmm_handle, src_data_type, dst->cmm_handle, des_data_type, rend->ri, flag);
+ if (!link->cmm_handle)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cmsCreateTransform failed");
+ }
+ else
+ {
+ /* littleCMS proof creation links don't work properly with the Ghent
+ * test files. Handle this in a brutish manner.
+ */
+ if (src == prf)
+ {
+ link->cmm_handle = cmsCreateTransformTHR(cmm_ctx, src->cmm_handle, src_data_type, dst->cmm_handle, des_data_type, INTENT_RELATIVE_COLORIMETRIC, flag);
+ if (!link->cmm_handle)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cmsCreateTransform failed");
+ }
+ else if (prf == dst)
+ {
+ link->cmm_handle = cmsCreateTransformTHR(cmm_ctx, src->cmm_handle, src_data_type, prf->cmm_handle, des_data_type, rend->ri, flag);
+ if (!link->cmm_handle)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cmsCreateTransform failed");
+ }
+ else
+ {
+ cmsHPROFILE src_to_prf_profile;
+ cmsHTRANSFORM src_to_prf_link;
+ cmsColorSpaceSignature prf_cs;
+ int prf_num_chan;
+ int lcms_prf_cs;
+ cmsUInt32Number prf_data_type;
+ cmsHPROFILE hProfiles[3];
+
+ prf_cs = cmsGetColorSpace(cmm_ctx, prf->cmm_handle);
+ lcms_prf_cs = _cmsLCMScolorSpace(cmm_ctx, prf_cs);
+ if (lcms_prf_cs < 0)
+ lcms_prf_cs = 0;
+ prf_num_chan = cmsChannelsOf(cmm_ctx, prf_cs);
+ prf_data_type = (COLORSPACE_SH(lcms_prf_cs) | CHANNELS_SH(prf_num_chan) | BYTES_SH(num_bytes));
+ src_to_prf_link = cmsCreateTransformTHR(cmm_ctx, src->cmm_handle, src_data_type, prf->cmm_handle, prf_data_type, rend->ri, flag);
+ if (!src_to_prf_link)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cmsCreateTransform failed");
+ src_to_prf_profile = cmsTransform2DeviceLink(cmm_ctx, src_to_prf_link, 3.4, flag);
+ cmsDeleteTransform(cmm_ctx, src_to_prf_link);
+ if (!src_to_prf_profile)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cmsTransform2DeviceLink failed");
+
+ hProfiles[0] = src_to_prf_profile;
+ hProfiles[1] = prf->cmm_handle;
+ hProfiles[2] = dst->cmm_handle;
+ link->cmm_handle = cmsCreateMultiprofileTransformTHR(cmm_ctx, hProfiles, 3, src_data_type, des_data_type, INTENT_RELATIVE_COLORIMETRIC, flag);
+ cmsCloseProfile(cmm_ctx, src_to_prf_profile);
+ if (!link->cmm_handle)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cmsCreateMultiprofileTransform failed");
+ }
+ }
+
+ DEBUG_LCMS_MEM(("@@@@@@@ Create Link End:: mupdf ctx = %p lcms ctx = %p link = %p link_cmm = %p src = %p des = %p \n", (void*)ctx, (void*)cmm_ctx, (void*)link, (void*)link->cmm_handle, (void*)src->cmm_handle, (void*)dst->cmm_handle));
+}
+
+void
+fz_lcms_fin_link(fz_cmm_instance *instance, fz_icclink *link)
+{
+ cmsContext cmm_ctx = (cmsContext)instance;
+ DEBUG_LCMS_MEM(("Free Link:: link = %p \n", (void*)link->cmm_handle));
+ if (link->cmm_handle != NULL)
+ cmsDeleteTransform(cmm_ctx, link->cmm_handle);
+ link->cmm_handle = NULL;
+}
+
+static fz_cmm_instance *
+fz_lcms_new_instance(fz_context *ctx)
+{
+ cmsContext cmm_ctx;
+
+ cmm_ctx = cmsCreateContext(&fz_lcms_memhandler, ctx);
+ DEBUG_LCMS_MEM(("Context Creation:: mupdf ctx = %p lcms ctx = %p \n", (void*) ctx, (void*) cmm_ctx));
+ if (cmm_ctx == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cmsCreateContext failed");
+ cmsSetLogErrorHandlerTHR(cmm_ctx, fz_lcms_log_error);
+ return (fz_cmm_instance *)cmm_ctx;
+}
+
+static void
+fz_lcms_drop_instance(fz_cmm_instance *instance)
+{
+ DEBUG_LCMS_MEM(("Context Destruction:: lcms ctx = %p \n", (void*)instance));
+ if (instance == NULL)
+ return;
+ cmsDeleteContext((cmsContext)instance);
+}
+
+static void
+fz_lcms_init_profile(fz_cmm_instance *instance, fz_iccprofile *profile)
+{
+ cmsContext cmm_ctx = (cmsContext)instance;
+ fz_context *ctx = (fz_context *)cmsGetContextUserData(cmm_ctx);
+ size_t size;
+ unsigned char *data;
+
+ DEBUG_LCMS_MEM(("@@@@@@@ Create Profile Start:: mupdf ctx = %p lcms ctx = %p \n", (void*)ctx, (void*)cmm_ctx));
+
+ size = fz_buffer_storage(ctx, profile->buffer, &data);
+ profile->cmm_handle = cmsOpenProfileFromMemTHR(cmm_ctx, data, size);
+ if (profile->cmm_handle == NULL)
+ {
+ profile->num_devcomp = 0;
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cmsOpenProfileFromMem failed");
+ }
+ profile->num_devcomp = fz_lcms_num_devcomps(cmm_ctx, profile);
+
+ DEBUG_LCMS_MEM(("@@@@@@@ Create Profile End:: mupdf ctx = %p lcms ctx = %p profile = %p profile_cmm = %p \n", (void*)ctx, (void*)cmm_ctx, (void*)profile, (void*)profile->cmm_handle));
+}
+
+static void
+fz_lcms_fin_profile(fz_cmm_instance *instance, fz_iccprofile *profile)
+{
+ cmsContext cmm_ctx = (cmsContext)instance;
+ DEBUG_LCMS_MEM(("Free Profile:: profile = %p \n", (void*) profile->cmm_handle));
+ if (profile->cmm_handle != NULL)
+ cmsCloseProfile(cmm_ctx, profile->cmm_handle);
+ profile->cmm_handle = NULL;
+}
+
+fz_cmm_engine fz_cmm_engine_lcms = {
+ fz_lcms_new_instance,
+ fz_lcms_drop_instance,
+ fz_lcms_transform_pixmap,
+ fz_lcms_transform_color,
+ fz_lcms_init_link,
+ fz_lcms_fin_link,
+ fz_lcms_init_profile,
+ fz_lcms_fin_profile,
+ cmsFLAGS_NOWHITEONWHITEFIXUP
+};
diff --git a/source/fitz/colorspace-imp.h b/source/fitz/colorspace-imp.h
index bf8f3fef..9c909a4d 100644
--- a/source/fitz/colorspace-imp.h
+++ b/source/fitz/colorspace-imp.h
@@ -1,6 +1,21 @@
#ifndef MUPDF_FITZ_COLORSPACE_IMP_H
#define MUPDF_FITZ_COLORSPACE_IMP_H
+#include "mupdf/fitz/context.h"
+#include "mupdf/fitz/colorspace.h"
+#include "mupdf/fitz/color-management.h"
+#include "mupdf/fitz/pixmap.h"
+
+int fz_cmm_avoid_white_fix_flag(fz_context *ctx);
+void fz_cmm_transform_pixmap(fz_context *ctx, fz_icclink *link, fz_pixmap *dst, fz_pixmap *src);
+void fz_cmm_transform_color(fz_context *ctx, fz_icclink *link, unsigned short *dst, const unsigned short *src);
+void fz_cmm_init_link(fz_context *ctx, fz_icclink *link, const fz_color_params *rend, int cmm_flags, int num_bytes, int alpha, const fz_iccprofile *src, const fz_iccprofile *prf, const fz_iccprofile *des);
+void fz_cmm_fin_link(fz_context *ctx, fz_icclink *link);
+fz_cmm_instance *fz_cmm_new_instance(fz_context *ctx);
+void fz_cmm_drop_instance(fz_context *ctx);
+void fz_cmm_init_profile(fz_context *ctx, fz_iccprofile *profile);
+void fz_cmm_fin_profile(fz_context *ctx, fz_iccprofile *profile);
+
struct fz_colorspace_s
{
fz_storable storable;
@@ -8,10 +23,48 @@ struct fz_colorspace_s
char name[16];
int n;
int is_subtractive;
- fz_colorspace_convert_fn *to_rgb;
- fz_colorspace_convert_fn *from_rgb;
+ fz_colorspace_convert_fn *to_ccs;
+ fz_colorspace_convert_fn *from_ccs;
+ fz_colorspace_clamp_fn *clamp;
+ fz_colorspace_base_fn *get_base;
fz_colorspace_destruct_fn *free_data;
void *data;
};
+struct fz_iccprofile_s
+{
+ int num_devcomp;
+ int bgr;
+ fz_buffer *buffer;
+ unsigned char md5[16];
+ void *cmm_handle;
+};
+
+struct fz_icclink_s
+{
+ fz_storable storable;
+ int num_in;
+ int num_out;
+ int depth;
+ int alpha;
+ int is_identity;
+ void *cmm_handle;
+};
+
+struct fz_default_colorspaces_s
+{
+ int refs;
+ fz_colorspace *gray;
+ fz_colorspace *rgb;
+ fz_colorspace *cmyk;
+ fz_colorspace *oi;
+};
+
+struct fz_colorspace_context_s
+{
+ int ctx_refs;
+ const fz_cmm_engine *cmm;
+ fz_colorspace *gray, *rgb, *bgr, *cmyk, *lab;
+};
+
#endif
diff --git a/source/fitz/colorspace.c b/source/fitz/colorspace.c
index 6113e496..d040b076 100644
--- a/source/fitz/colorspace.c
+++ b/source/fitz/colorspace.c
@@ -1,13 +1,139 @@
#include "mupdf/fitz.h"
#include "colorspace-imp.h"
+#include "fitz-imp.h"
#include <assert.h>
#include <math.h>
#include <string.h>
+/* CMM module */
+
+int
+fz_cmm_avoid_white_fix_flag(fz_context *ctx)
+{
+ if (ctx && ctx->colorspace && ctx->colorspace->cmm && ctx->cmm_instance)
+ return ctx->colorspace->cmm->avoid_white_fix_flag;
+ return 0;
+}
+
+void
+fz_cmm_transform_pixmap(fz_context *ctx, fz_icclink *link, fz_pixmap *dst, fz_pixmap *src)
+{
+ if (ctx && ctx->colorspace && ctx->colorspace->cmm && ctx->cmm_instance)
+ ctx->colorspace->cmm->transform_pixmap(ctx->cmm_instance, link, dst, src);
+}
+
+void
+fz_cmm_transform_color(fz_context *ctx, fz_icclink *link, unsigned short *dst, const unsigned short *src)
+{
+ if (ctx && ctx->colorspace && ctx->colorspace->cmm && ctx->cmm_instance)
+ ctx->colorspace->cmm->transform_color(ctx->cmm_instance, link, dst, src);
+}
+
+void
+fz_cmm_init_link(fz_context *ctx, fz_icclink *link, const fz_color_params *rend, int cmm_flags, int num_bytes, int alpha, const fz_iccprofile *src, const fz_iccprofile *prf, const fz_iccprofile *des)
+{
+ if (ctx && ctx->colorspace && ctx->colorspace->cmm && ctx->cmm_instance)
+ ctx->colorspace->cmm->init_link(ctx->cmm_instance, link, rend, cmm_flags, num_bytes, alpha, src, prf, des);
+}
+
+void
+fz_cmm_fin_link(fz_context *ctx, fz_icclink *link)
+{
+ if (ctx && ctx->colorspace && ctx->colorspace->cmm && ctx->cmm_instance)
+ ctx->colorspace->cmm->fin_link(ctx->cmm_instance, link);
+}
+
+fz_cmm_instance *fz_cmm_new_instance(fz_context *ctx)
+{
+ if (ctx && ctx->colorspace && ctx->colorspace->cmm)
+ return ctx->colorspace->cmm->new_instance(ctx);
+ return NULL;
+}
+
+void fz_cmm_drop_instance(fz_context *ctx)
+{
+ if (ctx && ctx->colorspace && ctx->colorspace->cmm && ctx->cmm_instance)
+ ctx->colorspace->cmm->drop_instance(ctx->cmm_instance);
+}
+
+void fz_cmm_init_profile(fz_context *ctx, fz_iccprofile *profile)
+{
+ if (ctx && ctx->colorspace && ctx->colorspace->cmm && ctx->cmm_instance)
+ ctx->colorspace->cmm->init_profile(ctx->cmm_instance, profile);
+}
+
+void fz_cmm_fin_profile(fz_context *ctx, fz_iccprofile *profile)
+{
+ if (ctx && ctx->colorspace && ctx->colorspace->cmm && ctx->cmm_instance)
+ if (profile && profile->cmm_handle != NULL)
+ ctx->colorspace->cmm->fin_profile(ctx->cmm_instance, profile);
+}
+
#define SLOWCMYK
+const unsigned char *
+fz_lookup_icc(fz_context *ctx, const char *name, size_t *size)
+{
+#ifndef NO_ICC
+ if (fz_get_cmm_engine(ctx) == NULL)
+ return *size = 0, NULL;
+ if (!strcmp(name, "gray-icc")) {
+ extern const int fz_resources_icc_gray_icc_size;
+ extern const unsigned char fz_resources_icc_gray_icc[];
+ *size = fz_resources_icc_gray_icc_size;
+ return fz_resources_icc_gray_icc;
+ }
+ if (!strcmp(name, "rgb-icc") || !strcmp(name, "bgr-icc")) {
+ extern const int fz_resources_icc_rgb_icc_size;
+ extern const unsigned char fz_resources_icc_rgb_icc[];
+ *size = fz_resources_icc_rgb_icc_size;
+ return fz_resources_icc_rgb_icc;
+ }
+ if (!strcmp(name, "cmyk-icc")) {
+ extern const int fz_resources_icc_cmyk_icc_size;
+ extern const unsigned char fz_resources_icc_cmyk_icc[];
+ *size = fz_resources_icc_cmyk_icc_size;
+ return fz_resources_icc_cmyk_icc;
+ }
+ if (!strcmp(name, "lab-icc")) {
+ extern const int fz_resources_icc_lab_icc_size;
+ extern const unsigned char fz_resources_icc_lab_icc[];
+ *size = fz_resources_icc_lab_icc_size;
+ return fz_resources_icc_lab_icc;
+ }
+#endif
+ return *size = 0, NULL;
+}
+
+/* Same order as needed by lcms */
+static const char *fz_intent_names[] =
+{
+ "Perceptual",
+ "RelativeColorimetric",
+ "Saturation",
+ "AbsoluteColorimetric",
+};
+
+int
+fz_lookup_rendering_intent(const char *name)
+{
+ int i;
+ for (i = 0; i < nelem(fz_intent_names); i++)
+ if (!strcmp(name, fz_intent_names[i]))
+ return i;
+ return FZ_RI_RELATIVE_COLORIMETRIC;
+}
+
+char *
+fz_rendering_intent_name(int ri)
+{
+ if (ri >= 0 && ri < nelem(fz_intent_names))
+ return (char*)fz_intent_names[ri];
+ return "RelativeColorimetric";
+}
+
void
fz_drop_colorspace_imp(fz_context *ctx, fz_storable *cs_)
{
@@ -18,17 +144,33 @@ fz_drop_colorspace_imp(fz_context *ctx, fz_storable *cs_)
fz_free(ctx, cs);
}
+static void
+clamp_default(const fz_colorspace *cs, const float *src, float *dst)
+{
+ int i;
+
+ for (i = 0; i < cs->n; i++)
+ dst[i] = fz_clamp(src[i], 0, 1);
+}
+
fz_colorspace *
-fz_new_colorspace(fz_context *ctx, char *name, int n, int is_subtractive, fz_colorspace_convert_fn *to_rgb, fz_colorspace_convert_fn *from_rgb, fz_colorspace_destruct_fn *destruct, void *data, size_t size)
+fz_new_colorspace(fz_context *ctx, char *name, int is_static, int n, int is_subtractive, fz_colorspace_convert_fn *to_ccs, fz_colorspace_convert_fn *from_ccs, fz_colorspace_base_fn *base, fz_colorspace_clamp_fn *clamp, fz_colorspace_destruct_fn *destruct, void *data, size_t size)
{
fz_colorspace *cs = fz_malloc_struct(ctx, fz_colorspace);
- FZ_INIT_STORABLE(cs, 1, fz_drop_colorspace_imp);
+ FZ_INIT_STORABLE(cs, is_static ? -1 : 1, fz_drop_colorspace_imp);
cs->size = sizeof(fz_colorspace) + size;
fz_strlcpy(cs->name, name, sizeof cs->name);
cs->n = n;
cs->is_subtractive = is_subtractive;
- cs->to_rgb = to_rgb;
- cs->from_rgb = from_rgb;
+ cs->to_ccs = to_ccs;
+ cs->from_ccs = from_ccs;
+ cs->get_base = base;
+
+ if (clamp != NULL)
+ cs->clamp = clamp;
+ else
+ cs->clamp = clamp_default;
+
cs->free_data = destruct;
cs->data = data;
return cs;
@@ -46,8 +188,296 @@ fz_drop_colorspace(fz_context *ctx, fz_colorspace *cs)
fz_drop_storable(ctx, &cs->storable);
}
-/* Device colorspace definitions */
+/* icc links */
+
+typedef struct fz_link_key_s fz_link_key;
+
+struct fz_link_key_s {
+ int refs;
+ unsigned char src_md5[16];
+ unsigned char dst_md5[16];
+ fz_color_params rend;
+ int alpha;
+ int depth;
+ int proof;
+};
+
+static void *
+fz_keep_link_key(fz_context *ctx, void *key_)
+{
+ fz_link_key *key = (fz_link_key *)key_;
+ return fz_keep_imp(ctx, key, &key->refs);
+}
+
+static void
+fz_drop_link_key(fz_context *ctx, void *key_)
+{
+ fz_link_key *key = (fz_link_key *)key_;
+ if (fz_drop_imp(ctx, key, &key->refs))
+ fz_free(ctx, key);
+}
+
+static int
+fz_cmp_link_key(fz_context *ctx, void *k0_, void *k1_)
+{
+ fz_link_key *k0 = (fz_link_key *)k0_;
+ fz_link_key *k1 = (fz_link_key *)k1_;
+ return k0->proof == k1->proof &&
+ k0->alpha == k1->alpha &&
+ k0->depth == k1->depth &&
+ k0->rend.bp == k1->rend.bp &&
+ k0->rend.ri == k1->rend.ri &&
+ memcmp(k0->dst_md5, k1->dst_md5, 16) == 0 &&
+ memcmp(k0->src_md5, k1->src_md5, 16);
+}
+
+static void
+fz_format_link_key(fz_context *ctx, char *s, int n, void *key_)
+{
+ static const char *hex = "0123456789abcdef";
+ fz_link_key *key = (fz_link_key *)key_;
+ char sm[33], dm[33];
+ int i;
+ for (i = 0; i < 16; ++i)
+ {
+ sm[i*2+0] = hex[key->src_md5[i]>>4];
+ sm[i*2+1] = hex[key->src_md5[i]&15];
+ dm[i*2+0] = hex[key->dst_md5[i]>>4];
+ dm[i*2+1] = hex[key->dst_md5[i]&15];
+ }
+ sm[32] = 0;
+ dm[32] = 0;
+ fz_snprintf(s, n, "(link src_md5=%s dst_md5=%s)", sm, dm);
+}
+
+static int
+fz_make_hash_link_key(fz_context *ctx, fz_store_hash *hash, void *key_)
+{
+ fz_link_key *key = (fz_link_key *)key_;
+ memcpy(hash->u.link.dst_md5, key->dst_md5, 16);
+ memcpy(hash->u.link.src_md5, key->src_md5, 16);
+ hash->u.link.ri = key->rend.ri;
+ hash->u.link.bp = key->rend.bp;
+ hash->u.link.alpha = key->alpha;
+ hash->u.link.depth = key->depth;
+ hash->u.link.proof = key->proof;
+ return 1;
+}
+
+static fz_store_type fz_link_store_type =
+{
+ fz_make_hash_link_key,
+ fz_keep_link_key,
+ fz_drop_link_key,
+ fz_cmp_link_key,
+ fz_format_link_key,
+ NULL
+};
+
+static void
+fz_drop_link_imp(fz_context *ctx, fz_storable *storable)
+{
+ fz_icclink *link = (fz_icclink *)storable;
+ fz_cmm_fin_link(ctx, link);
+ fz_free(ctx, link);
+}
+
+static void
+fz_drop_icclink(fz_context *ctx, fz_icclink *link)
+{
+ fz_drop_storable(ctx, &link->storable);
+}
+
+static fz_iccprofile *
+get_base_icc_profile(fz_context *ctx, fz_colorspace *cs)
+{
+ fz_colorspace *base;
+ fz_cal_colorspace *cal;
+ fz_iccprofile *cal_icc;
+
+ if (!cs || !cs->get_base)
+ return NULL;
+
+ base = cs->get_base(cs);
+ if (base == NULL)
+ return NULL;
+
+ if (fz_colorspace_is_icc(ctx, base))
+ return base->data;
+ if (!fz_colorspace_is_cal(ctx, base))
+ return get_base_icc_profile(ctx, base);
+
+ cal = base->data;
+ cal_icc = cal->profile;
+ if (cal_icc && cal_icc->cmm_handle == NULL)
+ fz_cmm_init_profile(ctx, cal_icc);
+
+ return cal_icc;
+}
+
+static fz_icclink *
+fz_new_icc_link(fz_context *ctx, fz_iccprofile *src, fz_iccprofile *prf, fz_iccprofile *dst, const fz_color_params *rend, int num_bytes, int alpha)
+{
+ fz_icclink *link = fz_malloc_struct(ctx, fz_icclink);
+ FZ_INIT_STORABLE(link, 1, fz_drop_link_imp);
+
+ link->num_in = src->num_devcomp;
+ link->num_out = dst->num_devcomp;
+
+ if (memcmp(src->md5, dst->md5, 16) == 0 && rend->ri == FZ_RI_RELATIVE_COLORIMETRIC && prf == NULL)
+ {
+ link->is_identity = 1;
+ return link;
+ }
+
+ fz_try(ctx)
+ fz_cmm_init_link(ctx, link, rend, 0, num_bytes, alpha, src, prf, dst);
+ fz_catch(ctx)
+ {
+ fz_free(ctx, link);
+ fz_rethrow(ctx);
+ }
+
+ return link;
+}
+
+static void
+fz_md5_icc(fz_context *ctx, fz_iccprofile *profile)
+{
+ if (profile)
+ fz_md5_buffer(ctx, profile->buffer, profile->md5);
+}
+/* Create icc profile from calrgb, calgray values */
+static fz_iccprofile *
+fz_icc_from_cal(fz_context *ctx, fz_colorspace *cs)
+{
+ fz_cal_colorspace *cal_data = cs->data;
+ fz_iccprofile *profile;
+
+ if (cal_data->profile != NULL)
+ return cal_data->profile;
+ profile = fz_malloc_struct(ctx, fz_iccprofile);
+
+ fz_try(ctx)
+ {
+ profile->buffer = fz_new_icc_data_from_cal_colorspace(ctx, cal_data);
+ fz_md5_icc(ctx, profile);
+ cal_data->profile = profile;
+ }
+ fz_catch(ctx)
+ {
+ fz_free(ctx, profile);
+ fz_rethrow(ctx);
+ }
+
+ return profile;
+}
+
+static fz_icclink *
+fz_get_icc_link(fz_context *ctx, fz_colorspace *src, fz_colorspace *prf, fz_colorspace *dst, const fz_color_params *rend, int num_bytes, int alpha, int *src_n)
+{
+ fz_icclink *link = NULL;
+ fz_iccprofile *src_icc = NULL;
+ fz_iccprofile *dst_icc = dst->data;
+ fz_iccprofile *prf_icc = NULL;
+ fz_link_key *key;
+ fz_icclink *new_link;
+
+ if (prf != NULL)
+ prf_icc = prf->data;
+
+ if (fz_colorspace_is_icc(ctx, src))
+ src_icc = src->data;
+ else if (fz_colorspace_is_cal(ctx, src))
+ {
+ fz_cal_colorspace *cal;
+
+ cal = src->data;
+ src_icc = cal->profile;
+ /* Check if we have any work to do. */
+ if (src_icc == NULL)
+ src_icc = fz_icc_from_cal(ctx, src);
+ if (src_icc->cmm_handle == NULL)
+ {
+ fz_cmm_init_profile(ctx, src_icc);
+
+ /* The CMM failed to make a profile. Use the default. */
+ if (src_icc->cmm_handle == NULL)
+ {
+ switch (src->n)
+ {
+ case 1:
+ src_icc = fz_device_gray(ctx)->data;
+ break;
+ case 3:
+ src_icc = fz_device_rgb(ctx)->data;
+ break;
+ case 4:
+ src_icc = fz_device_cmyk(ctx)->data;
+ break;
+ default:
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Poorly formed Cal color space");
+ }
+ /* To avoid repeated failures building the pdf-cal color space,
+ * assign the default profile. */
+ fz_cmm_fin_profile(ctx, src_icc);
+ cal->profile = src_icc;
+ }
+ }
+ }
+ else
+ src_icc = get_base_icc_profile(ctx, src);
+
+ if (src_icc == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Profile missing during link creation");
+
+ *src_n = src_icc->num_devcomp;
+
+ fz_var(link);
+ fz_var(key);
+
+ fz_try(ctx)
+ {
+ /* Check the storable to see if we have a copy. */
+ key = fz_malloc_struct(ctx, fz_link_key);
+ key->refs = 1;
+ memcpy(&key->dst_md5, dst_icc->md5, 16);
+ memcpy(&key->src_md5, src_icc->md5, 16);
+ key->rend.ri = rend->ri;
+ key->rend.bp = rend->bp;
+ key->alpha = alpha;
+ key->depth = num_bytes;
+ key->proof = (prf_icc != NULL);
+ link = fz_find_item(ctx, fz_drop_link_imp, key, &fz_link_store_type);
+
+ /* Not found. Make new one add to store. */
+ if (link == NULL)
+ {
+ link = fz_new_icc_link(ctx, src_icc, prf_icc, dst_icc, rend, num_bytes, alpha);
+ new_link = fz_store_item(ctx, key, link, sizeof(fz_icclink), &fz_link_store_type);
+ if (new_link != NULL)
+ {
+ /* Found one while adding! Perhaps from another thread? */
+ fz_drop_icclink(ctx, link);
+ link = new_link;
+ }
+ }
+ }
+ fz_always(ctx)
+ {
+ fz_drop_link_key(ctx, key);
+ }
+ fz_catch(ctx)
+ {
+ /* Ignore any error that came just from the enstoring. */
+ if (link == NULL)
+ fz_rethrow(ctx);
+ }
+ return link;
+}
+
+/* Device colorspace definitions */
static void gray_to_rgb(fz_context *ctx, fz_colorspace *cs, const float *gray, float *rgb)
{
rgb[0] = gray[0];
@@ -214,10 +644,19 @@ rgb_to_lab(fz_context *ctx, fz_colorspace *cs, const float *rgb, float *lab)
lab[2] = rgb[2];
}
-int
-fz_colorspace_is_lab(fz_context *ctx, fz_colorspace *cs)
+/* This could be different for a, b */
+static void
+clamp_lab(const fz_colorspace *cs, const float *src, float *dst)
{
- return (cs && cs->to_rgb == lab_to_rgb);
+ int i;
+
+ for (i = 0; i < 3; i++)
+ dst[i] = fz_clamp(src[i], i ? -128 : 0, i ? 127 : 100);
+}
+
+static int fz_colorspace_is_lab(fz_context *ctx, const fz_colorspace *cs)
+{
+ return cs && cs->to_ccs == lab_to_rgb;
}
int
@@ -226,33 +665,101 @@ fz_colorspace_is_subtractive(fz_context *ctx, fz_colorspace *cs)
return (cs && cs->is_subtractive);
}
-static fz_colorspace k_default_gray = { {-1, fz_drop_colorspace_imp}, 0, "DeviceGray", 1, 0, gray_to_rgb, rgb_to_gray };
-static fz_colorspace k_default_rgb = { {-1, fz_drop_colorspace_imp}, 0, "DeviceRGB", 3, 0, rgb_to_rgb, rgb_to_rgb };
-static fz_colorspace k_default_bgr = { {-1, fz_drop_colorspace_imp}, 0, "DeviceBGR", 3, 0, bgr_to_rgb, rgb_to_bgr };
-static fz_colorspace k_default_cmyk = { {-1, fz_drop_colorspace_imp}, 0, "DeviceCMYK", 4, 1, cmyk_to_rgb, rgb_to_cmyk };
-static fz_colorspace k_default_lab = { {-1, fz_drop_colorspace_imp}, 0, "Lab", 3, 0, lab_to_rgb, rgb_to_lab };
+static fz_colorspace k_default_gray = { {-1, fz_drop_colorspace_imp}, 0, "DeviceGray", 1, 0, gray_to_rgb, rgb_to_gray, clamp_default, NULL, NULL, NULL };
+static fz_colorspace k_default_rgb = { {-1, fz_drop_colorspace_imp}, 0, "DeviceRGB", 3, 0, rgb_to_rgb, rgb_to_rgb, clamp_default, NULL, NULL, NULL };
+static fz_colorspace k_default_bgr = { {-1, fz_drop_colorspace_imp}, 0, "DeviceBGR", 3, 0, bgr_to_rgb, rgb_to_bgr, clamp_default, NULL, NULL, NULL };
+static fz_colorspace k_default_cmyk = { {-1, fz_drop_colorspace_imp}, 0, "DeviceCMYK", 4, 1, cmyk_to_rgb, rgb_to_cmyk, clamp_default, NULL, NULL, NULL };
+static fz_colorspace k_default_lab = { {-1, fz_drop_colorspace_imp}, 0, "Lab", 3, 0, lab_to_rgb, rgb_to_lab, clamp_lab, NULL, NULL, NULL};
+static fz_color_params k_default_color_params = { FZ_RI_RELATIVE_COLORIMETRIC, 1, 0, 0 };
-static fz_colorspace *fz_default_gray = &k_default_gray;
-static fz_colorspace *fz_default_rgb = &k_default_rgb;
-static fz_colorspace *fz_default_bgr = &k_default_bgr;
-static fz_colorspace *fz_default_cmyk = &k_default_cmyk;
-static fz_colorspace *fz_default_lab = &k_default_lab;
+static fz_colorspace *default_gray = &k_default_gray;
+static fz_colorspace *default_rgb = &k_default_rgb;
+static fz_colorspace *default_bgr = &k_default_bgr;
+static fz_colorspace *default_cmyk = &k_default_cmyk;
+static fz_colorspace *default_lab = &k_default_lab;
+static fz_color_params *default_color_params = &k_default_color_params;
-struct fz_colorspace_context_s
+const fz_cmm_engine *fz_get_cmm_engine(fz_context *ctx)
{
- int ctx_refs;
- fz_colorspace *gray, *rgb, *bgr, *cmyk, *lab;
-};
+ return ctx->colorspace ? ctx->colorspace->cmm : NULL;
+}
+
+static void
+set_no_icc(fz_colorspace_context *cct)
+{
+ cct->gray = default_gray;
+ cct->rgb = default_rgb;
+ cct->bgr = default_bgr;
+ cct->cmyk = default_cmyk;
+ cct->lab = default_lab;
+}
+
+void fz_set_cmm_engine(fz_context *ctx, const fz_cmm_engine *engine)
+{
+ fz_colorspace_context *cct;
+
+ if (!ctx)
+ return;
+ cct = ctx->colorspace;
+ if (!cct)
+ return;
+
+#ifdef NO_ICC
+ if (engine)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "ICC workflow not supported in NO_ICC build");
+#else
+ if (cct->cmm == engine)
+ return;
+
+ fz_drop_cmm_context(ctx);
+ fz_drop_colorspace(ctx, cct->gray);
+ fz_drop_colorspace(ctx, cct->rgb);
+ fz_drop_colorspace(ctx, cct->bgr);
+ fz_drop_colorspace(ctx, cct->cmyk);
+ fz_drop_colorspace(ctx, cct->lab);
+ cct->gray = NULL;
+ cct->rgb = NULL;
+ cct->bgr = NULL;
+ cct->cmyk = NULL;
+ cct->lab = NULL;
+ cct->cmm = engine;
+ fz_new_cmm_context(ctx);
+ if (engine)
+ {
+ cct->gray = fz_new_icc_colorspace(ctx, 1, 1, NULL, "gray-icc");
+ cct->rgb = fz_new_icc_colorspace(ctx, 1, 3, NULL, "rgb-icc");
+ cct->bgr = fz_new_icc_colorspace(ctx, 1, 3, NULL, "bgr-icc");
+ cct->cmyk = fz_new_icc_colorspace(ctx, 1, 4, NULL, "cmyk-icc");
+ cct->lab = fz_new_icc_colorspace(ctx, 1, 3, NULL, "lab-icc");
+ }
+ else
+ set_no_icc(cct);
+#endif
+}
void fz_new_colorspace_context(fz_context *ctx)
{
ctx->colorspace = fz_malloc_struct(ctx, fz_colorspace_context);
ctx->colorspace->ctx_refs = 1;
- ctx->colorspace->gray = fz_default_gray;
- ctx->colorspace->rgb = fz_default_rgb;
- ctx->colorspace->bgr = fz_default_bgr;
- ctx->colorspace->cmyk = fz_default_cmyk;
- ctx->colorspace->lab = fz_default_lab;
+ set_no_icc(ctx->colorspace);
+#ifdef NO_ICC
+ fz_set_cmm_engine(ctx, NULL);
+#else
+ fz_set_cmm_engine(ctx, &fz_cmm_engine_lcms);
+#endif
+}
+
+void
+fz_new_cmm_context(fz_context *ctx)
+{
+ ctx->cmm_instance = fz_cmm_new_instance(ctx);
+}
+
+void
+fz_drop_cmm_context(fz_context *ctx)
+{
+ fz_cmm_drop_instance(ctx);
+ ctx->cmm_instance = NULL;
}
fz_colorspace_context *
@@ -269,6 +776,12 @@ void fz_drop_colorspace_context(fz_context *ctx)
return;
if (fz_drop_imp(ctx, ctx->colorspace, &ctx->colorspace->ctx_refs))
{
+ fz_drop_colorspace(ctx, ctx->colorspace->gray);
+ fz_drop_colorspace(ctx, ctx->colorspace->rgb);
+ /* FIXME: bgr */
+ fz_drop_colorspace(ctx, ctx->colorspace->cmyk);
+ fz_drop_colorspace(ctx, ctx->colorspace->lab);
+ fz_drop_cmm_context(ctx);
fz_free(ctx, ctx->colorspace);
ctx->colorspace = NULL;
}
@@ -304,54 +817,15 @@ fz_device_lab(fz_context *ctx)
return ctx->colorspace->lab;
}
-void
-fz_set_device_gray(fz_context *ctx, fz_colorspace *cs)
-{
- fz_lock(ctx, FZ_LOCK_ALLOC);
- fz_drop_colorspace(ctx, ctx->colorspace->gray);
- ctx->colorspace->gray = fz_keep_colorspace(ctx, cs);
- fz_unlock(ctx, FZ_LOCK_ALLOC);
-}
-
-void
-fz_set_device_rgb(fz_context *ctx, fz_colorspace *cs)
-{
- fz_lock(ctx, FZ_LOCK_ALLOC);
- fz_drop_colorspace(ctx, ctx->colorspace->rgb);
- ctx->colorspace->rgb = fz_keep_colorspace(ctx, cs);
- fz_unlock(ctx, FZ_LOCK_ALLOC);
-}
-
-void
-fz_set_device_bgr(fz_context *ctx, fz_colorspace *cs)
-{
- fz_lock(ctx, FZ_LOCK_ALLOC);
- fz_drop_colorspace(ctx, ctx->colorspace->bgr);
- ctx->colorspace->bgr = fz_keep_colorspace(ctx, cs);
- fz_unlock(ctx, FZ_LOCK_ALLOC);
-}
-
-void
-fz_set_device_cmyk(fz_context *ctx, fz_colorspace *cs)
-{
- fz_lock(ctx, FZ_LOCK_ALLOC);
- fz_drop_colorspace(ctx, ctx->colorspace->cmyk);
- ctx->colorspace->cmyk = fz_keep_colorspace(ctx, cs);
- fz_unlock(ctx, FZ_LOCK_ALLOC);
-}
-
-void
-fz_set_device_lab(fz_context *ctx, fz_colorspace *cs)
+const fz_color_params *
+fz_default_color_params(fz_context *ctx)
{
- fz_lock(ctx, FZ_LOCK_ALLOC);
- fz_drop_colorspace(ctx, ctx->colorspace->lab);
- ctx->colorspace->lab = fz_keep_colorspace(ctx, cs);
- fz_unlock(ctx, FZ_LOCK_ALLOC);
+ return default_color_params;
}
/* Fast pixmap color conversions */
-static void fast_gray_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
+static void fast_gray_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, fz_default_colorspaces *default_cs, const fz_color_params *color_params)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -429,7 +903,7 @@ static void fast_gray_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
}
}
-static void fast_gray_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
+static void fast_gray_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, fz_default_colorspaces *default_cs, const fz_color_params *color_params)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -510,7 +984,7 @@ static void fast_gray_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
}
}
-static void fast_rgb_to_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
+static void fast_rgb_to_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, fz_default_colorspaces *default_cs, const fz_color_params *color_params)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -582,7 +1056,7 @@ static void fast_rgb_to_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
}
}
-static void fast_bgr_to_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
+static void fast_bgr_to_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, fz_default_colorspaces *default_cs, const fz_color_params *color_params)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -654,7 +1128,7 @@ static void fast_bgr_to_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
}
}
-static void fast_rgb_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
+static void fast_rgb_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, fz_default_colorspaces *default_cs, const fz_color_params *color_params)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -747,7 +1221,7 @@ static void fast_rgb_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
}
}
-static void fast_bgr_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
+static void fast_bgr_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, fz_default_colorspaces *default_cs, const fz_color_params *color_params)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -840,7 +1314,7 @@ static void fast_bgr_to_cmyk(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
}
}
-static void fast_cmyk_to_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
+static void fast_cmyk_to_gray(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, fz_default_colorspaces *default_cs, const fz_color_params *color_params)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -1247,7 +1721,7 @@ static inline void cached_cmyk_conv(unsigned char *restrict const pr, unsigned c
#endif
}
-static void fast_cmyk_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
+static void fast_cmyk_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, fz_default_colorspaces *default_cs, const fz_color_params *color_params)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -1346,7 +1820,7 @@ static void fast_cmyk_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
}
}
-static void fast_cmyk_to_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
+static void fast_cmyk_to_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, fz_default_colorspaces *default_cs, const fz_color_params *color_params)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -1438,7 +1912,7 @@ static void fast_cmyk_to_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
}
}
-static void fast_rgb_to_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
+static void fast_rgb_to_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, fz_default_colorspaces *default_cs, const fz_color_params *color_params)
{
unsigned char *s = src->samples;
unsigned char *d = dst->samples;
@@ -1512,7 +1986,148 @@ static void fast_rgb_to_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
}
static void
-fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
+icc_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, fz_default_colorspaces *default_cs, const fz_color_params *color_params)
+{
+ fz_colorspace *srcs = src->colorspace;
+ fz_colorspace *dsts = dst->colorspace;
+ fz_icclink *link;
+ int i;
+ unsigned char *inputpos, *outputpos;
+ int src_n;
+
+ /* Check if we have to do a color space default substitution */
+ if (default_cs)
+ {
+ switch (fz_colorspace_n(ctx, src->colorspace))
+ {
+ case 1:
+ if (src->colorspace == fz_device_gray(ctx))
+ srcs = fz_default_gray(ctx, default_cs);
+ break;
+ case 3:
+ if (src->colorspace == fz_device_rgb(ctx))
+ srcs = fz_default_rgb(ctx, default_cs);
+ break;
+ case 4:
+ if (src->colorspace == fz_device_cmyk(ctx))
+ srcs = fz_default_cmyk(ctx, default_cs);
+ break;
+ }
+ }
+
+ inputpos = src->samples;
+ outputpos = dst->samples;
+
+ link = fz_get_icc_link(ctx, srcs, prf, dsts, color_params, 1, dst->alpha, &src_n);
+
+ if (link->is_identity)
+ {
+ for (i = 0; i < src->h; i++)
+ {
+ memcpy(outputpos, inputpos, src->stride);
+ inputpos = inputpos + src->stride;
+ outputpos = outputpos + dst->stride;
+ }
+ }
+ else
+ fz_cmm_transform_pixmap(ctx, link, dst, src);
+
+ fz_drop_icclink(ctx, link);
+}
+
+/* Drill down through the base spaces until we get the either a pdf-cal or
+ * an ICC base space. This is where we want our pixmap to be decoded prior
+ * to application of the link transform */
+static fz_colorspace*
+get_base_icc_space(fz_context *ctx, fz_colorspace *srcs)
+{
+ while (1)
+ {
+ srcs = srcs->get_base(srcs);
+ if (srcs == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Final color space should be icc or pdf-cal or lab");
+
+ if (fz_colorspace_is_icc(ctx, srcs) || fz_colorspace_is_cal(ctx, srcs) || fz_colorspace_is_lab(ctx, srcs))
+ return srcs;
+ }
+}
+
+/* Cope with cases where we have to convert through multiple base spaces before
+ * getting to the final cm color space */
+static void
+convert_to_icc_base(fz_context *ctx, fz_colorspace *srcs, float *src_f, float *des_f)
+{
+ float temp_f[FZ_MAX_COLORS];
+ fz_colorspace *base_cs = srcs->get_base(srcs);
+
+ if (fz_colorspace_is_icc(ctx, base_cs) || fz_colorspace_is_cal(ctx, base_cs) || fz_colorspace_is_lab(ctx, base_cs))
+ srcs->to_ccs(ctx, srcs, src_f, des_f);
+ else
+ {
+ srcs->to_ccs(ctx, srcs, src_f, temp_f);
+ convert_to_icc_base(ctx, base_cs, temp_f, des_f);
+ }
+}
+
+/* For DeviceN and Separation CS, where we require an alternate tint tranform
+ * prior to the application of an icc profile. Also, indexed images have to
+ * be handled. Realize those can map from index->devn->pdf-cal->icc for
+ * example. */
+static void
+icc_base_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, fz_default_colorspaces *default_cs, const fz_color_params *color_params)
+{
+ fz_colorspace *srcs = src->colorspace;
+ fz_colorspace *base_cs = get_base_icc_space(ctx, srcs);
+ int i;
+ unsigned char *inputpos, *outputpos;
+ fz_pixmap *base;
+ fz_irect bbox;
+ int h, len;
+ float src_f[FZ_MAX_COLORS], des_f[FZ_MAX_COLORS];
+ int sn = src->n;
+ int stride_src = src->stride - src->w * sn;
+ int stride_base;
+ int bn;
+
+ base = fz_new_pixmap_with_bbox(ctx, base_cs, fz_pixmap_bbox(ctx, src, &bbox), src->alpha);
+ bn = base->n;
+ stride_base = base->stride - base->w * bn;
+
+ inputpos = src->samples;
+ outputpos = base->samples;
+
+ h = src->h;
+ while (h--)
+ {
+ len = src->w;
+ while (len--)
+ {
+ for (i = 0; i < sn; i++)
+ src_f[i] = (float) inputpos[i] / 255.0;
+
+ convert_to_icc_base(ctx, srcs, src_f, des_f);
+ base_cs->clamp(base_cs, des_f, des_f);
+
+ for (i = 0; i < bn; i++)
+ outputpos[i] = des_f[i] * 255.0;
+
+ outputpos += bn;
+ inputpos += sn;
+ }
+ outputpos += stride_base;
+ inputpos += stride_src;
+ }
+
+ fz_try(ctx)
+ icc_conv_pixmap(ctx, dst, base, prf, default_cs, color_params);
+ fz_always(ctx)
+ fz_drop_pixmap(ctx, base);
+ fz_catch(ctx)
+ fz_rethrow(ctx);
+}
+
+static void
+std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, fz_default_colorspaces *default_cs, const fz_color_params *color_params)
{
float srcv[FZ_MAX_COLORS];
float dstv[FZ_MAX_COLORS];
@@ -1534,6 +2149,9 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
if ((int)w < 0 || h < 0)
return;
+ if (color_params == NULL)
+ color_params = fz_default_color_params(ctx);
+
srcn = ss->n;
dstn = ds->n;
@@ -1548,11 +2166,11 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
}
/* Special case for Lab colorspace (scaling of components to float) */
- if (!strcmp(ss->name, "Lab") && srcn == 3)
+ if ((fz_colorspace_is_lab(ctx, ss) || fz_colorspace_is_lab_icc(ctx, ss)) && srcn == 3)
{
fz_color_converter cc;
- fz_lookup_color_converter(ctx, &cc, ds, ss);
+ fz_find_color_converter(ctx, &cc, NULL, ds, ss, color_params);
while (h--)
{
size_t ww = w;
@@ -1573,6 +2191,7 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
d += d_line_inc;
s += s_line_inc;
}
+ fz_drop_color_converter(ctx, &cc);
}
/* Brute-force for small images */
@@ -1580,7 +2199,7 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
{
fz_color_converter cc;
- fz_lookup_color_converter(ctx, &cc, ds, ss);
+ fz_find_color_converter(ctx, &cc, NULL, ds, ss, color_params);
while (h--)
{
size_t ww = w;
@@ -1600,6 +2219,7 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
d += d_line_inc;
s += s_line_inc;
}
+ fz_drop_color_converter(ctx, &cc);
}
/* 1-d lookup table for separation and similar colorspaces */
@@ -1608,7 +2228,7 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
unsigned char lookup[FZ_MAX_COLORS * 256];
fz_color_converter cc;
- fz_lookup_color_converter(ctx, &cc, ds, ss);
+ fz_find_color_converter(ctx, &cc, NULL, ds, ss, color_params);
for (i = 0; i < 256; i++)
{
srcv[0] = i / 255.0f;
@@ -1616,6 +2236,7 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
for (k = 0; k < dstn; k++)
lookup[i * dstn + k] = dstv[k] * 255;
}
+ fz_drop_color_converter(ctx, &cc);
while (h--)
{
@@ -1644,63 +2265,70 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
unsigned char *dold;
fz_color_converter cc;
- fz_lookup_color_converter(ctx, &cc, ds, ss);
lookup = fz_new_hash_table(ctx, 509, srcn, -1, NULL);
+ fz_find_color_converter(ctx, &cc, NULL, ds, ss, color_params);
- while (h--)
+ fz_try(ctx)
{
- size_t ww = w;
- while (ww--)
+ while (h--)
{
- if (*s == *sold && memcmp(sold,s,srcn) == 0)
- {
- sold = s;
- memcpy(d, dold, dstn);
- d += dstn;
- s += srcn;
- if (da)
- *d++ = (sa ? *s : 255);
- s += sa;
- }
- else
+ size_t ww = w;
+ while (ww--)
{
- sold = s;
- dold = d;
- color = fz_hash_find(ctx, lookup, s);
- if (color)
+ if (*s == *sold && memcmp(sold,s,srcn) == 0)
{
- memcpy(d, color, dstn);
- s += srcn;
+ sold = s;
+ memcpy(d, dold, dstn);
d += dstn;
- if (dst->alpha)
+ s += srcn;
+ if (da)
*d++ = (sa ? *s : 255);
s += sa;
}
else
{
- for (k = 0; k < srcn; k++)
- srcv[k] = *s++ / 255.0f;
- cc.convert(ctx, &cc, dstv, srcv);
- for (k = 0; k < dstn; k++)
- *d++ = dstv[k] * 255;
-
- fz_hash_insert(ctx, lookup, s - srcn, d - dstn);
-
- if (dst->alpha)
- *d++ = (sa ? *s : 255);
- s += sa;
+ sold = s;
+ dold = d;
+ color = fz_hash_find(ctx, lookup, s);
+ if (color)
+ {
+ memcpy(d, color, dstn);
+ s += srcn;
+ d += dstn;
+ if (dst->alpha)
+ *d++ = (sa ? *s : 255);
+ s += sa;
+ }
+ else
+ {
+ for (k = 0; k < srcn; k++)
+ srcv[k] = *s++ / 255.0f;
+ cc.convert(ctx, &cc, dstv, srcv);
+ for (k = 0; k < dstn; k++)
+ *d++ = dstv[k] * 255;
+
+ fz_hash_insert(ctx, lookup, s - srcn, d - dstn);
+
+ if (dst->alpha)
+ *d++ = (sa ? *s : 255);
+ s += sa;
+ }
}
}
+ d += d_line_inc;
+ s += s_line_inc;
}
- d += d_line_inc;
- s += s_line_inc;
}
+ fz_always(ctx)
+ fz_drop_color_converter(ctx, &cc);
+ fz_catch(ctx)
+ fz_rethrow(ctx);
fz_drop_hash_table(ctx, lookup);
}
}
-static void fast_any_to_alpha(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
+static void fast_any_to_alpha(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, fz_colorspace *prf, fz_default_colorspaces *default_cs, const fz_color_params *color_params)
{
if (!src->alpha)
fz_clear_pixmap_with_value(ctx, dst, 255);
@@ -1740,48 +2368,128 @@ static void fast_any_to_alpha(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src)
}
}
+/* Used for testing all color managed source color spaces. If it is icc, cal or
+ * has a base space that is managed */
+static fz_colorspace *
+fz_source_colorspace_cm(fz_context *ctx, fz_colorspace *cs)
+{
+ while (cs)
+ {
+ if (fz_colorspace_is_icc(ctx, cs))
+ return cs;
+ if (fz_colorspace_is_cal(ctx, cs))
+ return cs;
+ cs = fz_colorspace_base(ctx, cs);
+ }
+ return NULL;
+}
+
fz_pixmap_converter *fz_lookup_pixmap_converter(fz_context *ctx, fz_colorspace *ds, fz_colorspace *ss)
{
if (ds == NULL)
return fast_any_to_alpha;
- if (ss == fz_default_gray)
+ if (ss == default_gray)
{
- if (ds == fz_default_rgb) return fast_gray_to_rgb;
- else if (ds == fz_default_bgr) return fast_gray_to_rgb; /* bgr == rgb here */
- else if (ds == fz_default_cmyk) return fast_gray_to_cmyk;
- else return fz_std_conv_pixmap;
+ if (ds == default_rgb) return fast_gray_to_rgb;
+ else if (ds == default_bgr) return fast_gray_to_rgb; /* bgr == rgb here */
+ else if (ds == default_cmyk) return fast_gray_to_cmyk;
+ else return std_conv_pixmap;
}
- else if (ss == fz_default_rgb)
+ else if (ss == default_rgb)
{
- if (ds == fz_default_gray) return fast_rgb_to_gray;
- else if (ds == fz_default_bgr) return fast_rgb_to_bgr;
- else if (ds == fz_default_cmyk) return fast_rgb_to_cmyk;
- else return fz_std_conv_pixmap;
+ if (ds == default_gray) return fast_rgb_to_gray;
+ else if (ds == default_bgr) return fast_rgb_to_bgr;
+ else if (ds == default_cmyk) return fast_rgb_to_cmyk;
+ else return std_conv_pixmap;
}
- else if (ss == fz_default_bgr)
+ else if (ss == default_bgr)
{
- if (ds == fz_default_gray) return fast_bgr_to_gray;
- else if (ds == fz_default_rgb) return fast_rgb_to_bgr; /* bgr = rgb here */
- else if (ds == fz_default_cmyk) return fast_bgr_to_cmyk;
- else return fz_std_conv_pixmap;
+ if (ds == default_gray) return fast_bgr_to_gray;
+ else if (ds == default_rgb) return fast_rgb_to_bgr; /* bgr = rgb here */
+ else if (ds == default_cmyk) return fast_bgr_to_cmyk;
+ else return std_conv_pixmap;
}
- else if (ss == fz_default_cmyk)
+ else if (ss == default_cmyk)
{
- if (ds == fz_default_gray) return fast_cmyk_to_gray;
- else if (ds == fz_default_bgr) return fast_cmyk_to_bgr;
- else if (ds == fz_default_rgb) return fast_cmyk_to_rgb;
- else return fz_std_conv_pixmap;
+ if (ds == default_gray) return fast_cmyk_to_gray;
+ else if (ds == default_bgr) return fast_cmyk_to_bgr;
+ else if (ds == default_rgb) return fast_cmyk_to_rgb;
+ else return std_conv_pixmap;
}
- else return fz_std_conv_pixmap;
+ else
+ {
+ fz_colorspace *ss_base = fz_source_colorspace_cm(ctx, ss);
+ if (ss_base != NULL && fz_colorspace_is_icc(ctx, ds))
+ {
+ if (ss_base == ss)
+ return icc_conv_pixmap;
+ else
+ return icc_base_conv_pixmap;
+ }
+ else return std_conv_pixmap;
+ }
}
-/* Convert a single color */
+/* Single color conversion with ICC profiles. ToDo: Check if it makes sense
+ * to use lcms float link here or to do the conversion to short and back.
+ */
+static void
+icc_conv_color(fz_context *ctx, fz_color_converter *cc, float *dstv, const float *srcv)
+{
+ fz_colorspace *dsts = cc->ds;
+ int src_n = cc->n;
+ int dst_n = dsts->n;
+
+ fz_icclink *link = (fz_icclink *)cc->link;
+ int i;
+ unsigned short dstv_s[FZ_MAX_COLORS];
+ unsigned short srcv_s[FZ_MAX_COLORS];
+
+ if (link->is_identity)
+ {
+ for (i = 0; i < src_n; i++)
+ dstv[i] = srcv[i];
+ }
+ else
+ {
+ for (i = 0; i < src_n; i++)
+ srcv_s[i] = srcv[i] * 65535;
+ fz_cmm_transform_color(ctx, link, dstv_s, srcv_s);
+ for (i = 0; i < dst_n; i++)
+ dstv[i] = fz_clamp((float) dstv_s[i] / 65535.0, 0, 1);
+ }
+}
+/* Single ICC color conversion but for DeviceN, Sep and Indexed spaces.
+ * Does premapping to get to ICC */
+static void
+icc_base_conv_color(fz_context *ctx, fz_color_converter *cc, float *dstv, const float *srcv)
+{
+ fz_colorspace *srcs = cc->ss;
+
+ float local_src_map[FZ_MAX_COLORS];
+ float local_src_map2[FZ_MAX_COLORS];
+ float *src_map = local_src_map;
+
+ do
+ {
+ srcs->to_ccs(ctx, srcs, srcv, src_map);
+ srcs = srcs->get_base(srcs);
+ srcs->clamp(srcs, src_map, src_map);
+ srcv = src_map;
+ src_map = (src_map == local_src_map ? local_src_map2 : local_src_map);
+ }
+ while (!fz_colorspace_is_icc(ctx, srcs) && !fz_colorspace_is_cal(ctx, srcs));
+
+ icc_conv_color(ctx, cc, dstv, srcv);
+}
+
+/* Convert a single color */
static void
std_conv_color(fz_context *ctx, fz_color_converter *cc, float *dstv, const float *srcv)
{
@@ -1797,9 +2505,9 @@ std_conv_color(fz_context *ctx, fz_color_converter *cc, float *dstv, const float
if (srcs != dsts)
{
- assert(srcs->to_rgb && dsts->from_rgb);
- srcs->to_rgb(ctx, srcs, srcv, rgb);
- dsts->from_rgb(ctx, dsts, rgb, dstv);
+ assert(srcs->to_ccs && dsts->from_ccs);
+ srcs->to_ccs(ctx, srcs, srcv, rgb);
+ dsts->from_ccs(ctx, dsts, rgb, dstv);
for (i = 0; i < dsts->n; i++)
dstv[i] = fz_clamp(dstv[i], 0, 1);
}
@@ -1910,66 +2618,90 @@ cmyk2bgr(fz_context *ctx, fz_color_converter *cc, float *dv, const float *sv)
#endif
}
-void fz_lookup_color_converter(fz_context *ctx, fz_color_converter *cc, fz_colorspace *ds, fz_colorspace *ss)
+void fz_find_color_converter(fz_context *ctx, fz_color_converter *cc, fz_colorspace *is, fz_colorspace *ds, fz_colorspace *ss, const fz_color_params *params)
{
cc->ds = ds;
cc->ss = ss;
- if (ss == fz_default_gray)
+ cc->is = is;
+ cc->link = NULL;
+ if (ss == default_gray)
{
- if ((ds == fz_default_rgb) || (ds == fz_default_bgr))
+ if ((ds == default_rgb) || (ds == default_bgr))
cc->convert = g2rgb;
- else if (ds == fz_default_cmyk)
+ else if (ds == default_cmyk)
cc->convert = g2cmyk;
else
cc->convert = std_conv_color;
}
- else if (ss == fz_default_rgb)
+ else if (ss == default_rgb)
{
- if (ds == fz_default_gray)
+ if (ds == default_gray)
cc->convert = rgb2g;
- else if (ds == fz_default_bgr)
+ else if (ds == default_bgr)
cc->convert = rgb2bgr;
- else if (ds == fz_default_cmyk)
+ else if (ds == default_cmyk)
cc->convert = rgb2cmyk;
else
cc->convert = std_conv_color;
}
- else if (ss == fz_default_bgr)
+ else if (ss == default_bgr)
{
- if (ds == fz_default_gray)
+ if (ds == default_gray)
cc->convert = bgr2g;
- else if (ds == fz_default_rgb)
+ else if (ds == default_rgb)
cc->convert = rgb2bgr;
- else if (ds == fz_default_cmyk)
+ else if (ds == default_cmyk)
cc->convert = bgr2cmyk;
else
cc->convert = std_conv_color;
}
- else if (ss == fz_default_cmyk)
+ else if (ss == default_cmyk)
{
- if (ds == fz_default_gray)
+ if (ds == default_gray)
cc->convert = cmyk2g;
- else if (ds == fz_default_rgb)
+ else if (ds == default_rgb)
cc->convert = cmyk2rgb;
- else if (ds == fz_default_bgr)
+ else if (ds == default_bgr)
cc->convert = cmyk2bgr;
else
cc->convert = std_conv_color;
}
-
else
- cc->convert = std_conv_color;
+ {
+ fz_colorspace *ss_base = fz_source_colorspace_cm(ctx, ss);
+ if (ss_base != NULL && fz_colorspace_is_icc(ctx, ds))
+ {
+ if (ss_base == ss)
+ cc->convert = icc_conv_color;
+ else
+ cc->convert = icc_base_conv_color;
+ cc->link = fz_get_icc_link(ctx, ss_base, is, ds, params, 2, 0, &cc->n);
+ }
+ else
+ cc->convert = std_conv_color;
+ }
}
void
-fz_convert_color(fz_context *ctx, fz_colorspace *ds, float *dv, fz_colorspace *ss, const float *sv)
+fz_drop_color_converter(fz_context *ctx, fz_color_converter *cc)
+{
+ fz_icclink *link = (fz_icclink *)cc->link;
+ if (link)
+ fz_drop_icclink(ctx, link);
+ cc->link = NULL;
+
+}
+
+void
+fz_convert_color(fz_context *ctx, const fz_color_params *params, fz_colorspace *is, fz_colorspace *ds, float *dv, fz_colorspace *ss, const float *sv)
{
fz_color_converter cc;
- fz_lookup_color_converter(ctx, &cc, ds, ss);
+ fz_find_color_converter(ctx, &cc, is, ds, ss, params);
cc.convert(ctx, &cc, dv, sv);
+ fz_drop_color_converter(ctx, &cc);
}
/* Indexed */
@@ -1982,16 +2714,26 @@ struct indexed
};
static void
-indexed_to_rgb(fz_context *ctx, fz_colorspace *cs, const float *color, float *rgb)
+indexed_to_alt(fz_context *ctx, fz_colorspace *cs, const float *color, float *alt)
{
struct indexed *idx = cs->data;
- float alt[FZ_MAX_COLORS];
int i, k;
+ int n = idx->base->n;
+
i = color[0] * 255;
i = fz_clampi(i, 0, idx->high);
- for (k = 0; k < idx->base->n; k++)
- alt[k] = idx->lookup[i * idx->base->n + k] / 255.0f;
- idx->base->to_rgb(ctx, idx->base, alt, rgb);
+ for (k = 0; k < n; k++)
+ alt[k] = idx->lookup[i * n + k] / 255.0f;
+}
+
+static void
+indexed_to_rgb(fz_context *ctx, fz_colorspace *cs, const float *color, float *rgb)
+{
+ float alt[FZ_MAX_COLORS];
+ struct indexed *idx = cs->data;
+
+ indexed_to_alt(ctx, cs, color, alt);
+ idx->base->to_ccs(ctx, idx->base, alt, rgb);
}
static void
@@ -2003,10 +2745,25 @@ free_indexed(fz_context *ctx, fz_colorspace *cs)
fz_free(ctx, idx);
}
-int
-fz_colorspace_is_indexed(fz_context *ctx, fz_colorspace *cs)
+static fz_colorspace *
+base_indexed(const fz_colorspace *cs)
{
- return (cs && cs->to_rgb == indexed_to_rgb);
+ struct indexed *idx = cs->data;
+
+ return idx->base;
+}
+
+static void
+clamp_indexed(const fz_colorspace *cs, const float *in, float *out)
+{
+ struct indexed *idx = cs->data;
+
+ *out = fz_clamp(*in, 0, idx->high) / 255.0; /* To do, avoid 255 divide */
+}
+
+int fz_colorspace_is_indexed(fz_context *ctx, const fz_colorspace *cs)
+{
+ return cs && cs->clamp == clamp_indexed;
}
fz_colorspace *
@@ -2021,9 +2778,7 @@ fz_new_indexed_colorspace(fz_context *ctx, fz_colorspace *base, int high, unsign
idx->high = high;
fz_try(ctx)
- {
- cs = fz_new_colorspace(ctx, "Indexed", 1, 0, indexed_to_rgb, NULL, free_indexed, idx, sizeof(*idx) + (base->n * (idx->high + 1)) + base->size);
- }
+ cs = fz_new_colorspace(ctx, "Indexed", 0, 1, 0, fz_colorspace_is_icc(ctx, fz_device_rgb(ctx)) ? indexed_to_alt : indexed_to_rgb, NULL, base_indexed, clamp_indexed, free_indexed, idx, sizeof(*idx) + (base->n * (idx->high + 1)) + base->size);
fz_catch(ctx)
{
fz_free(ctx, idx);
@@ -2044,7 +2799,7 @@ fz_expand_indexed_pixmap(fz_context *ctx, const fz_pixmap *src, int alpha)
fz_irect bbox;
int s_line_inc, d_line_inc;
- assert(src->colorspace->to_rgb == indexed_to_rgb);
+ assert(src->colorspace->to_ccs == indexed_to_rgb || src->colorspace->to_ccs == indexed_to_alt);
assert(src->n == 1 + alpha);
idx = src->colorspace->data;
@@ -2129,23 +2884,26 @@ static void fz_cached_color_convert(fz_context *ctx, fz_color_converter *cc_, fl
}
}
-void fz_init_cached_color_converter(fz_context *ctx, fz_color_converter *cc, fz_colorspace *ds, fz_colorspace *ss)
+void fz_init_cached_color_converter(fz_context *ctx, fz_color_converter *cc, fz_colorspace *is, fz_colorspace *ds, fz_colorspace *ss, const fz_color_params *params)
{
int n = ss->n;
fz_cached_color_converter *cached = fz_malloc_struct(ctx, fz_cached_color_converter);
fz_try(ctx)
{
- fz_lookup_color_converter(ctx, &cached->base, ds, ss);
+ fz_find_color_converter(ctx, &cached->base, is, ds, ss, params);
cached->hash = fz_new_hash_table(ctx, 256, n * sizeof(float), -1, fz_free);
cc->convert = fz_cached_color_convert;
cc->ds = ds;
cc->ss = ss;
+ cc->is = is;
cc->opaque = cached;
}
fz_catch(ctx)
{
+ fz_drop_color_converter(ctx, &cached->base);
fz_drop_hash_table(ctx, cached->hash);
+ fz_free(ctx, cached);
fz_rethrow(ctx);
}
}
@@ -2160,12 +2918,13 @@ void fz_fin_cached_color_converter(fz_context *ctx, fz_color_converter *cc_)
return;
cc_->opaque = NULL;
fz_drop_hash_table(ctx, cc->hash);
+ fz_drop_color_converter(ctx, &cc->base);
fz_free(ctx, cc);
}
-int fz_colorspace_is(fz_context *ctx, const fz_colorspace *cs, fz_colorspace_convert_fn *to_rgb)
+fz_colorspace *fz_colorspace_base(fz_context *ctx, const fz_colorspace *cs)
{
- return cs && cs->to_rgb == to_rgb;
+ return cs && cs->get_base ? cs->get_base(cs) : NULL;
}
int fz_colorspace_n(fz_context *ctx, const fz_colorspace *cs)
@@ -2177,3 +2936,278 @@ const char *fz_colorspace_name(fz_context *ctx, const fz_colorspace *cs)
{
return cs ? cs->name : "";
}
+
+static void
+free_icc(fz_context *ctx, fz_colorspace *cs)
+{
+ fz_iccprofile *profile = cs->data;
+ fz_drop_buffer(ctx, profile->buffer);
+ fz_cmm_fin_profile(ctx, profile);
+ fz_free(ctx, profile);
+}
+
+/* This could be different for a* b* */
+static void
+clamp_lab_icc(const fz_colorspace *cs, const float *src, float *dst)
+{
+ dst[0] = (fz_clamp(src[0], 0, 100)) / 100.0;
+ dst[1] = (fz_clamp(src[1], -128, 127) + 128.0) / 256;
+ dst[2] = (fz_clamp(src[2], -128, 127) + 128.0) / 256;
+}
+
+/* Embedded icc profiles could have different range */
+static void
+clamp_default_icc(const fz_colorspace *cs, const float *src, float *dst)
+{
+ int i;
+ fz_iccprofile *profile = cs->data;
+
+ for (i = 0; i < profile->num_devcomp; i++)
+ dst[i] = fz_clamp(src[i], 0, 1);
+}
+
+int fz_colorspace_is_icc(fz_context *ctx, const fz_colorspace *cs)
+{
+ return cs && cs->free_data == free_icc;
+}
+
+int fz_colorspace_is_lab_icc(fz_context *ctx, const fz_colorspace *cs)
+{
+ return cs && cs->clamp == clamp_lab_icc;
+}
+
+fz_colorspace *
+fz_new_icc_colorspace(fz_context *ctx, int is_static, int num, fz_buffer *buf, const char *name)
+{
+ fz_colorspace *cs = NULL;
+ fz_iccprofile *profile;
+ int is_lab = 0;
+
+ profile = fz_malloc_struct(ctx, fz_iccprofile);
+ fz_try(ctx)
+ {
+ profile->buffer = buf;
+ if (name != NULL)
+ {
+ size_t size;
+ const unsigned char *data;
+ data = fz_lookup_icc(ctx, name, &size);
+ profile->buffer = fz_new_buffer_from_shared_data(ctx, (const char *)data, size);
+ is_lab = (strcmp(name, "lab-icc") == 0);
+ profile->bgr = (strcmp(name, "bgr-icc") == 0);
+ }
+
+ fz_cmm_init_profile(ctx, profile);
+
+ /* Check if correct type */
+ if (num != profile->num_devcomp)
+ {
+ if (name != NULL)
+ fz_drop_buffer(ctx, profile->buffer);
+ fz_cmm_fin_profile(ctx, profile);
+ fz_free(ctx, profile);
+ }
+ else
+ {
+ fz_keep_buffer(ctx, buf);
+ fz_md5_icc(ctx, profile);
+ cs = fz_new_colorspace(ctx, "icc", is_static, num, 0, NULL, NULL, NULL, is_lab ? clamp_lab_icc : clamp_default_icc, free_icc, profile, sizeof(profile));
+ }
+ }
+ fz_catch(ctx)
+ {
+ fz_drop_buffer(ctx, profile->buffer);
+ fz_cmm_fin_profile(ctx, profile);
+ fz_free(ctx, profile);
+ }
+ return cs;
+}
+
+/* Gets the icc data from a color space. Used in the writing out of the icc
+ * data for output formats.
+ */
+fz_buffer *
+fz_icc_data_from_icc_colorspace(fz_context *ctx, const fz_colorspace *cs)
+{
+ fz_iccprofile *profile;
+
+ if (cs == NULL || !fz_colorspace_is_icc(ctx, cs))
+ return NULL;
+ profile = cs->data;
+ if (!profile)
+ return NULL;
+ return profile->buffer;
+}
+
+static void
+free_cal(fz_context *ctx, fz_colorspace *cs)
+{
+ fz_cal_colorspace *cal_data = cs->data;
+ if (cal_data->profile != NULL)
+ {
+ fz_drop_buffer(ctx, cal_data->profile->buffer);
+ fz_cmm_fin_profile(ctx, cal_data->profile);
+ fz_free(ctx, cal_data->profile);
+ }
+ fz_free(ctx, cal_data);
+}
+
+int fz_colorspace_is_cal(fz_context *ctx, const fz_colorspace *cs)
+{
+ return cs && cs->free_data == free_cal;
+}
+
+/* Profile created if needed during draw command. */
+fz_colorspace *
+fz_new_cal_colorspace(fz_context *ctx, float *wp, float *bp, float *gamma, float *matrix)
+{
+ fz_colorspace *cs = NULL;
+ int num = (matrix == NULL ? 1 : 3);
+ fz_cal_colorspace *cal_data = fz_malloc_struct(ctx, fz_cal_colorspace);
+
+ memcpy(&cal_data->bp, bp, sizeof(float) * 3);
+ memcpy(&cal_data->wp, wp, sizeof(float) * 3);
+ memcpy(&cal_data->gamma, gamma, sizeof(float) * num);
+ if (matrix != NULL)
+ memcpy(&cal_data->matrix, matrix, sizeof(float) * 9);
+ cal_data->n = num;
+
+ fz_try(ctx)
+ cs = fz_new_colorspace(ctx, "pdf-cal", 0, num, 0, NULL, NULL, NULL, NULL, free_cal, cal_data, sizeof(cal_data));
+ fz_catch(ctx)
+ {
+ fz_free(ctx, cal_data);
+ fz_rethrow(ctx);
+ }
+ return cs;
+}
+
+void
+fz_clamp_color(fz_context *ctx, const fz_colorspace *cs, const float *in, float *out)
+{
+ cs->clamp(cs, in, out);
+}
+
+/* Default CS. To handle the page specific default settings that PDF can do in
+ * its page resource dictionary as well as the output intent. Both need to
+ * to be accessible by the device on the other side of the display list.
+ * Same with the output intent. */
+void
+fz_set_default_gray(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs)
+{
+ if (cs->n == 1)
+ {
+ fz_drop_colorspace(ctx, default_cs->gray);
+ default_cs->gray = fz_keep_colorspace(ctx, cs);
+ }
+}
+
+void
+fz_set_default_rgb(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs)
+{
+ if (cs->n == 3)
+ {
+ fz_drop_colorspace(ctx, default_cs->rgb);
+ default_cs->rgb = fz_keep_colorspace(ctx, cs);
+ }
+}
+
+void
+fz_set_default_cmyk(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs)
+{
+ if (cs->n == 4)
+ {
+ fz_drop_colorspace(ctx, default_cs->cmyk);
+ default_cs->cmyk = fz_keep_colorspace(ctx, cs);
+ }
+}
+
+void
+fz_set_default_output_intent(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs)
+{
+ fz_drop_colorspace(ctx, default_cs->oi);
+ default_cs->oi = fz_keep_colorspace(ctx, cs);
+
+ switch (cs->n)
+ {
+ case 1:
+ fz_drop_colorspace(ctx, default_cs->gray);
+ default_cs->gray = fz_keep_colorspace(ctx, cs);
+ break;
+ case 3:
+ fz_drop_colorspace(ctx, default_cs->rgb);
+ default_cs->rgb = fz_keep_colorspace(ctx, cs);
+ break;
+ case 4:
+ fz_drop_colorspace(ctx, default_cs->cmyk);
+ default_cs->cmyk = fz_keep_colorspace(ctx, cs);
+ break;
+ }
+}
+
+fz_colorspace *
+fz_default_gray(fz_context *ctx, fz_default_colorspaces *default_cs)
+{
+ if (default_cs)
+ return default_cs->gray;
+ else
+ return fz_device_gray(ctx);
+}
+
+fz_colorspace *
+fz_default_rgb(fz_context *ctx, fz_default_colorspaces *default_cs)
+{
+ if (default_cs)
+ return default_cs->rgb;
+ else
+ return fz_device_rgb(ctx);
+}
+
+fz_colorspace *
+fz_default_cmyk(fz_context *ctx, fz_default_colorspaces *default_cs)
+{
+ if (default_cs)
+ return default_cs->cmyk;
+ else
+ return fz_device_cmyk(ctx);
+}
+
+fz_colorspace *
+fz_default_output_intent(fz_context *ctx, fz_default_colorspaces *default_cs)
+{
+ if (default_cs)
+ return default_cs->oi;
+ else
+ return NULL;
+}
+
+fz_default_colorspaces *
+fz_new_default_colorspaces(fz_context *ctx)
+{
+ fz_default_colorspaces *default_cs = fz_malloc_struct(ctx, fz_default_colorspaces);
+ default_cs->refs = 1;
+ default_cs->gray = fz_keep_colorspace(ctx, fz_device_gray(ctx));
+ default_cs->rgb = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
+ default_cs->cmyk = fz_keep_colorspace(ctx, fz_device_cmyk(ctx));
+ default_cs->oi = NULL;
+ return default_cs;
+}
+
+fz_default_colorspaces *
+fz_keep_default_colorspaces(fz_context *ctx, fz_default_colorspaces *default_cs)
+{
+ return fz_keep_imp(ctx, default_cs, &default_cs->refs);
+}
+
+void
+fz_drop_default_colorspaces(fz_context *ctx, fz_default_colorspaces *default_cs)
+{
+ if (fz_drop_imp(ctx, default_cs, &default_cs->refs))
+ {
+ fz_drop_colorspace(ctx, default_cs->gray);
+ fz_drop_colorspace(ctx, default_cs->rgb);
+ fz_drop_colorspace(ctx, default_cs->cmyk);
+ fz_drop_colorspace(ctx, default_cs->oi);
+ fz_free(ctx, default_cs);
+ }
+}
diff --git a/source/fitz/context.c b/source/fitz/context.c
index 42806bc0..380af9a3 100644
--- a/source/fitz/context.c
+++ b/source/fitz/context.c
@@ -146,6 +146,7 @@ fz_drop_context(fz_context *ctx)
fz_drop_style_context(ctx);
fz_drop_tuning_context(ctx);
fz_drop_colorspace_context(ctx);
+ fz_drop_cmm_context(ctx);
fz_drop_font_context(ctx);
fz_drop_id_context(ctx);
fz_drop_output_context(ctx);
@@ -242,6 +243,7 @@ fz_new_context_imp(const fz_alloc_context *alloc, const fz_locks_context *locks,
fz_new_output_context(ctx);
fz_new_store_context(ctx, max_store);
fz_new_glyph_cache_context(ctx);
+ fz_new_cmm_context(ctx);
fz_new_colorspace_context(ctx);
fz_new_font_context(ctx);
fz_new_id_context(ctx);
@@ -291,6 +293,7 @@ fz_clone_context_internal(fz_context *ctx)
new_ctx->store = fz_keep_store_context(new_ctx);
new_ctx->glyph_cache = ctx->glyph_cache;
new_ctx->glyph_cache = fz_keep_glyph_cache(new_ctx);
+ fz_new_cmm_context(new_ctx);
new_ctx->colorspace = ctx->colorspace;
new_ctx->colorspace = fz_keep_colorspace_context(new_ctx);
new_ctx->font = ctx->font;
diff --git a/source/fitz/device.c b/source/fitz/device.c
index 21f74f65..fcf135d0 100644
--- a/source/fitz/device.c
+++ b/source/fitz/device.c
@@ -109,22 +109,22 @@ pop_clip_stack(fz_context *ctx, fz_device *dev)
void
fz_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
if (dev->error_depth)
return;
if (dev->fill_path)
- dev->fill_path(ctx, dev, path, even_odd, ctm, colorspace, color, alpha);
+ dev->fill_path(ctx, dev, path, even_odd, ctm, colorspace, color, alpha, color_params);
}
void
fz_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
if (dev->error_depth)
return;
if (dev->stroke_path)
- dev->stroke_path(ctx, dev, path, stroke, ctm, colorspace, color, alpha);
+ dev->stroke_path(ctx, dev, path, stroke, ctm, colorspace, color, alpha, color_params);
}
void
@@ -195,22 +195,22 @@ fz_clip_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const
void
fz_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
if (dev->error_depth)
return;
if (dev->fill_text)
- dev->fill_text(ctx, dev, text, ctm, colorspace, color, alpha);
+ dev->fill_text(ctx, dev, text, ctm, colorspace, color, alpha, color_params);
}
void
fz_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
if (dev->error_depth)
return;
if (dev->stroke_text)
- dev->stroke_text(ctx, dev, text, stroke, ctm, colorspace, color, alpha);
+ dev->stroke_text(ctx, dev, text, stroke, ctm, colorspace, color, alpha, color_params);
}
void
@@ -305,31 +305,31 @@ fz_pop_clip(fz_context *ctx, fz_device *dev)
}
void
-fz_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha)
+fz_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha, const fz_color_params *color_params)
{
if (dev->error_depth)
return;
if (dev->fill_shade)
- dev->fill_shade(ctx, dev, shade, ctm, alpha);
+ dev->fill_shade(ctx, dev, shade, ctm, alpha, color_params);
}
void
-fz_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha)
+fz_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha, const fz_color_params *color_params)
{
if (dev->error_depth)
return;
if (dev->fill_image)
- dev->fill_image(ctx, dev, image, ctm, alpha);
+ dev->fill_image(ctx, dev, image, ctm, alpha, color_params);
}
void
fz_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
if (dev->error_depth)
return;
if (dev->fill_image_mask)
- dev->fill_image_mask(ctx, dev, image, ctm, colorspace, color, alpha);
+ dev->fill_image_mask(ctx, dev, image, ctm, colorspace, color, alpha, color_params);
}
void
@@ -366,7 +366,7 @@ fz_clip_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const fz_ma
}
void
-fz_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *area, int luminosity, fz_colorspace *colorspace, const float *bc)
+fz_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *area, int luminosity, fz_colorspace *colorspace, const float *bc, const fz_color_params *color_params)
{
if (dev->error_depth)
{
@@ -379,7 +379,7 @@ fz_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *area, int luminosi
if (dev->hints & FZ_MAINTAIN_CONTAINER_STACK)
push_clip_stack(ctx, dev, area, fz_device_container_stack_in_mask);
if (dev->begin_mask)
- dev->begin_mask(ctx, dev, area, luminosity, colorspace, bc);
+ dev->begin_mask(ctx, dev, area, luminosity, colorspace, bc, color_params);
}
fz_catch(ctx)
{
@@ -513,3 +513,10 @@ fz_render_flags(fz_context *ctx, fz_device *dev, int set, int clear)
if (dev->render_flags)
dev->render_flags(ctx, dev, set, clear);
}
+
+void
+fz_set_default_colorspaces(fz_context *ctx, fz_device *dev, fz_default_colorspaces *default_cs)
+{
+ if (dev->set_default_colorspaces)
+ dev->set_default_colorspaces(ctx, dev, default_cs);
+}
diff --git a/source/fitz/document.c b/source/fitz/document.c
index 8f34026a..ceccd26d 100644
--- a/source/fitz/document.c
+++ b/source/fitz/document.c
@@ -296,6 +296,14 @@ fz_lookup_metadata(fz_context *ctx, fz_document *doc, const char *key, char *buf
return -1;
}
+fz_colorspace *
+fz_document_output_intent(fz_context *ctx, fz_document *doc)
+{
+ if (doc && doc->get_output_intent)
+ return doc->get_output_intent(ctx, doc);
+ return NULL;
+}
+
fz_page *
fz_load_page(fz_context *ctx, fz_document *doc, int number)
{
diff --git a/source/fitz/draw-device.c b/source/fitz/draw-device.c
index af8e8384..b4cb88c2 100644
--- a/source/fitz/draw-device.c
+++ b/source/fitz/draw-device.c
@@ -44,6 +44,7 @@ struct fz_draw_device_s
fz_device super;
fz_matrix transform;
fz_rasterizer *rast;
+ fz_default_colorspaces *default_cs;
int flags;
int top;
fz_scale_cache *cache_x;
@@ -107,6 +108,50 @@ static void stack_change(fz_context *ctx, fz_draw_device *dev, char *s)
#define STACK_CONVERT(A) do {} while (0)
#endif
+/* Based upon the existence of a proof color space, and if we happen to be
+ * in a color space that is our target color space or a transparency group
+ * color space decide if we should be using the proof color space at this time */
+static fz_colorspace *
+fz_proof_cs(fz_context *ctx, fz_device *devp)
+{
+ fz_draw_device *dev = (fz_draw_device*)devp;
+ fz_colorspace *prf = fz_default_output_intent(ctx, dev->default_cs);
+ fz_draw_state *state = &dev->stack[dev->top];
+ fz_colorspace *model = state->dest->colorspace;
+
+ if (prf == NULL || model == prf)
+ return NULL;
+ return prf;
+}
+
+/* Logic below assumes that default cs is set to color context cs if there
+ * was not a default in the document for that particular cs
+ */
+static fz_colorspace *fz_default_colorspace(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs)
+{
+ if (cs == NULL)
+ return NULL;
+ if (default_cs == NULL)
+ return cs;
+
+ switch (fz_colorspace_n(ctx, cs))
+ {
+ case 1:
+ if (cs == fz_device_gray(ctx))
+ return fz_default_gray(ctx, default_cs);
+ break;
+ case 3:
+ if (cs == fz_device_rgb(ctx))
+ return fz_default_rgb(ctx, default_cs);
+ break;
+ case 4:
+ if (cs == fz_device_cmyk(ctx))
+ return fz_default_cmyk(ctx, default_cs);
+ break;
+ }
+ return cs;
+}
+
static void fz_grow_stack(fz_context *ctx, fz_draw_device *dev)
{
int max = dev->stack_cap * 2;
@@ -281,12 +326,13 @@ static inline fz_matrix concat(const fz_matrix *one, const fz_matrix *two)
static void
fz_draw_fill_path(fz_context *ctx, fz_device *devp, const fz_path *path, int even_odd, const fz_matrix *in_ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace_in, const float *color, float alpha, const fz_color_params *color_params)
{
fz_draw_device *dev = (fz_draw_device*)devp;
fz_matrix ctm = concat(in_ctm, &dev->transform);
fz_rasterizer *rast = dev->rast;
-
+ fz_colorspace *colorspace = fz_default_colorspace(ctx, dev->default_cs, colorspace_in);
+ fz_colorspace *prf = fz_proof_cs(ctx, devp);
float expansion = fz_matrix_expansion(&ctm);
float flatness = 0.3f / expansion;
unsigned char colorbv[FZ_MAX_COLORS + 1];
@@ -299,6 +345,9 @@ fz_draw_fill_path(fz_context *ctx, fz_device *devp, const fz_path *path, int eve
if (colorspace == NULL && model != NULL)
fz_throw(ctx, FZ_ERROR_GENERIC, "color destination requires source color");
+ if (color_params == NULL)
+ color_params = fz_default_color_params(ctx);
+
if (flatness < 0.001f)
flatness = 0.001f;
@@ -312,7 +361,7 @@ fz_draw_fill_path(fz_context *ctx, fz_device *devp, const fz_path *path, int eve
n = fz_colorspace_n(ctx, model);
if (n > 0)
{
- fz_convert_color(ctx, model, colorfv, colorspace, color);
+ fz_convert_color(ctx, color_params, prf, model, colorfv, colorspace, color);
for (i = 0; i < n; i++)
colorbv[i] = colorfv[i] * 255;
}
@@ -336,12 +385,13 @@ fz_draw_fill_path(fz_context *ctx, fz_device *devp, const fz_path *path, int eve
static void
fz_draw_stroke_path(fz_context *ctx, fz_device *devp, const fz_path *path, const fz_stroke_state *stroke, const fz_matrix *in_ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace_in, const float *color, float alpha, const fz_color_params *color_params)
{
fz_draw_device *dev = (fz_draw_device*)devp;
fz_matrix ctm = concat(in_ctm, &dev->transform);
fz_rasterizer *rast = dev->rast;
-
+ fz_colorspace *colorspace = fz_default_colorspace(ctx, dev->default_cs, colorspace_in);
+ fz_colorspace *prf = fz_proof_cs(ctx, devp);
float expansion = fz_matrix_expansion(&ctm);
float flatness = 0.3f / expansion;
float linewidth = stroke->linewidth;
@@ -354,9 +404,13 @@ fz_draw_stroke_path(fz_context *ctx, fz_device *devp, const fz_path *path, const
fz_colorspace *model = state->dest->colorspace;
float mlw = fz_graphics_min_line_width(ctx);
+
if (colorspace == NULL && model != NULL)
fz_throw(ctx, FZ_ERROR_GENERIC, "color destination requires source color");
+ if (color_params == NULL)
+ color_params = fz_default_color_params(ctx);
+
if (mlw > aa_level)
aa_level = mlw;
if (linewidth * expansion < aa_level)
@@ -374,7 +428,7 @@ fz_draw_stroke_path(fz_context *ctx, fz_device *devp, const fz_path *path, const
n = fz_colorspace_n(ctx, model);
if (n > 0)
{
- fz_convert_color(ctx, model, colorfv, colorspace, color);
+ fz_convert_color(ctx, color_params, prf, model, colorfv, colorspace, color);
for (i = 0; i < n; i++)
colorbv[i] = colorfv[i] * 255;
}
@@ -626,7 +680,7 @@ draw_glyph(unsigned char *colorbv, fz_pixmap *dst, fz_glyph *glyph,
static void
fz_draw_fill_text(fz_context *ctx, fz_device *devp, const fz_text *text, const fz_matrix *in_ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace_in, const float *color, float alpha, const fz_color_params *color_params)
{
fz_draw_device *dev = (fz_draw_device*)devp;
fz_matrix ctm = concat(in_ctm, &dev->transform);
@@ -637,17 +691,25 @@ fz_draw_fill_text(fz_context *ctx, fz_device *devp, const fz_text *text, const f
float colorfv[FZ_MAX_COLORS];
fz_text_span *span;
int i, n;
+ fz_colorspace *colorspace = NULL;
+ fz_colorspace *prf = fz_proof_cs(ctx, devp);
+
+ if (colorspace_in)
+ colorspace = fz_default_colorspace(ctx, dev->default_cs, colorspace_in);
if (colorspace == NULL && model != NULL)
fz_throw(ctx, FZ_ERROR_GENERIC, "color destination requires source color");
+ if (color_params == NULL)
+ color_params = fz_default_color_params(ctx);
+
if (state->blendmode & FZ_BLEND_KNOCKOUT)
state = fz_knockout_begin(ctx, dev);
n = fz_colorspace_n(ctx, model);
if (n > 0)
{
- fz_convert_color(ctx, model, colorfv, colorspace, color);
+ fz_convert_color(ctx, color_params, prf, model, colorfv, colorspace, color);
for (i = 0; i < n; i++)
colorbv[i] = colorfv[i] * 255;
}
@@ -700,7 +762,7 @@ fz_draw_fill_text(fz_context *ctx, fz_device *devp, const fz_text *text, const f
fz_path *path = fz_outline_glyph(ctx, span->font, gid, &tm);
if (path)
{
- fz_draw_fill_path(ctx, devp, path, 0, in_ctm, colorspace, color, alpha);
+ fz_draw_fill_path(ctx, devp, path, 0, in_ctm, colorspace, color, alpha, color_params);
fz_drop_path(ctx, path);
}
else
@@ -717,8 +779,7 @@ fz_draw_fill_text(fz_context *ctx, fz_device *devp, const fz_text *text, const f
static void
fz_draw_stroke_text(fz_context *ctx, fz_device *devp, const fz_text *text, const fz_stroke_state *stroke,
- const fz_matrix *in_ctm, fz_colorspace *colorspace,
- const float *color, float alpha)
+ const fz_matrix *in_ctm, fz_colorspace *colorspace_in, const float *color, float alpha, const fz_color_params *color_params)
{
fz_draw_device *dev = (fz_draw_device*)devp;
fz_matrix ctm = concat(in_ctm, &dev->transform);
@@ -728,17 +789,25 @@ fz_draw_stroke_text(fz_context *ctx, fz_device *devp, const fz_text *text, const
float colorfv[FZ_MAX_COLORS];
fz_text_span *span;
int i, n;
+ fz_colorspace *colorspace = NULL;
+ fz_colorspace *prf = fz_proof_cs(ctx, devp);
+
+ if (colorspace_in)
+ colorspace = fz_default_colorspace(ctx, dev->default_cs, colorspace_in);
if (colorspace == NULL && model != NULL)
fz_throw(ctx, FZ_ERROR_GENERIC, "color destination requires source color");
+ if (color_params == NULL)
+ color_params = fz_default_color_params(ctx);
+
if (state->blendmode & FZ_BLEND_KNOCKOUT)
state = fz_knockout_begin(ctx, dev);
n = fz_colorspace_n(ctx, model);
if (n > 0)
{
- fz_convert_color(ctx, model, colorfv, colorspace, color);
+ fz_convert_color(ctx, color_params, prf, model, colorfv, colorspace, color);
for (i = 0; i < n; i++)
colorbv[i] = colorfv[i] * 255;
}
@@ -779,7 +848,7 @@ fz_draw_stroke_text(fz_context *ctx, fz_device *devp, const fz_text *text, const
fz_path *path = fz_outline_glyph(ctx, span->font, gid, &tm);
if (path)
{
- fz_draw_stroke_path(ctx, devp, path, stroke, in_ctm, colorspace, color, alpha);
+ fz_draw_stroke_path(ctx, devp, path, stroke, in_ctm, colorspace, color, alpha, color_params);
fz_drop_path(ctx, path);
}
else
@@ -893,7 +962,7 @@ fz_draw_clip_text(fz_context *ctx, fz_device *devp, const fz_text *text, const f
state[1].mask = NULL;
fz_try(ctx)
{
- fz_draw_fill_path(ctx, devp, path, 0, in_ctm, fz_device_gray(ctx), &white, 1);
+ fz_draw_fill_path(ctx, devp, path, 0, in_ctm, fz_device_gray(ctx), &white, 1, NULL);
}
fz_always(ctx)
{
@@ -1016,7 +1085,7 @@ fz_draw_clip_stroke_text(fz_context *ctx, fz_device *devp, const fz_text *text,
state[0].mask = NULL;
fz_try(ctx)
{
- fz_draw_stroke_path(ctx, devp, path, stroke, in_ctm, fz_device_gray(ctx), &white, 1);
+ fz_draw_stroke_path(ctx, devp, path, stroke, in_ctm, fz_device_gray(ctx), &white, 1, NULL);
}
fz_always(ctx)
{
@@ -1050,7 +1119,7 @@ fz_draw_ignore_text(fz_context *ctx, fz_device *dev, const fz_text *text, const
}
static void
-fz_draw_fill_shade(fz_context *ctx, fz_device *devp, fz_shade *shade, const fz_matrix *in_ctm, float alpha)
+fz_draw_fill_shade(fz_context *ctx, fz_device *devp, fz_shade *shade, const fz_matrix *in_ctm, float alpha, const fz_color_params *color_params)
{
fz_draw_device *dev = (fz_draw_device*)devp;
fz_matrix ctm = concat(in_ctm, &dev->transform);
@@ -1061,6 +1130,7 @@ fz_draw_fill_shade(fz_context *ctx, fz_device *devp, fz_shade *shade, const fz_m
unsigned char colorbv[FZ_MAX_COLORS + 1];
fz_draw_state *state = &dev->stack[dev->top];
fz_colorspace *model = state->dest->colorspace;
+ fz_colorspace *prf = fz_proof_cs(ctx, devp);
fz_bound_shade(ctx, shade, &ctm, &bounds);
scissor = state->scissor;
@@ -1069,6 +1139,9 @@ fz_draw_fill_shade(fz_context *ctx, fz_device *devp, fz_shade *shade, const fz_m
if (fz_is_empty_irect(&bbox))
return;
+ if (color_params == NULL)
+ color_params = fz_default_color_params(ctx);
+
if (state->blendmode & FZ_BLEND_KNOCKOUT)
state = fz_knockout_begin(ctx, dev);
@@ -1096,7 +1169,7 @@ fz_draw_fill_shade(fz_context *ctx, fz_device *devp, fz_shade *shade, const fz_m
n = fz_colorspace_n(ctx, model);
if (n > 0)
{
- fz_convert_color(ctx, model, colorfv, shade->colorspace, shade->background);
+ fz_convert_color(ctx, color_params, prf, model, colorfv, fz_default_colorspace(ctx, dev->default_cs, shade->colorspace), shade->background);
for (i = 0; i < n; i++)
colorbv[i] = colorfv[i] * 255;
}
@@ -1127,7 +1200,7 @@ fz_draw_fill_shade(fz_context *ctx, fz_device *devp, fz_shade *shade, const fz_m
}
}
- fz_paint_shade(ctx, shade, &ctm, dest, &bbox);
+ fz_paint_shade(ctx, shade, &ctm, dest, prf, color_params, &bbox);
if (shape)
fz_clear_pixmap_rect_with_value(ctx, shape, 255, &bbox);
@@ -1219,7 +1292,7 @@ fz_default_image_scale(void *arg, int dst_w, int dst_h, int src_w, int src_h)
}
static void
-fz_draw_fill_image(fz_context *ctx, fz_device *devp, fz_image *image, const fz_matrix *in_ctm, float alpha)
+fz_draw_fill_image(fz_context *ctx, fz_device *devp, fz_image *image, const fz_matrix *in_ctm, float alpha, const fz_color_params *color_params)
{
fz_draw_device *dev = (fz_draw_device*)devp;
fz_matrix local_ctm = concat(in_ctm, &dev->transform);
@@ -1231,6 +1304,8 @@ fz_draw_fill_image(fz_context *ctx, fz_device *devp, fz_image *image, const fz_m
fz_irect clip;
fz_matrix inverse;
fz_irect src_area;
+ fz_colorspace *src_cs;
+ fz_colorspace *prf = fz_proof_cs(ctx, devp);
fz_intersect_irect(fz_pixmap_bbox(ctx, state->dest, &clip), &state->scissor);
@@ -1273,6 +1348,7 @@ fz_draw_fill_image(fz_context *ctx, fz_device *devp, fz_image *image, const fz_m
}
pixmap = fz_get_pixmap_from_image(ctx, image, &src_area, &local_ctm, &dx, &dy);
+ src_cs = fz_default_colorspace(ctx, dev->default_cs, pixmap->colorspace);
/* convert images with more components (cmyk->rgb) before scaling */
/* convert images with fewer components (gray->rgb) after scaling */
@@ -1286,12 +1362,12 @@ fz_draw_fill_image(fz_context *ctx, fz_device *devp, fz_image *image, const fz_m
state = fz_knockout_begin(ctx, dev);
after = 0;
- if (pixmap->colorspace == fz_device_gray(ctx))
+ if (src_cs == fz_device_gray(ctx))
after = 1;
- if (pixmap->colorspace != model && !after)
+ if (src_cs != model && !after)
{
- fz_pixmap *converted = fz_convert_pixmap(ctx, pixmap, model, 1);
+ fz_pixmap *converted = fz_convert_pixmap(ctx, pixmap, model, prf, dev->default_cs, color_params, 1);
fz_drop_pixmap(ctx, pixmap);
pixmap = converted;
}
@@ -1315,18 +1391,18 @@ fz_draw_fill_image(fz_context *ctx, fz_device *devp, fz_image *image, const fz_m
}
}
- if (pixmap->colorspace != model)
+ if (src_cs != model && after)
{
#if FZ_PLOTTERS_RGB
- if ((pixmap->colorspace == fz_device_gray(ctx) && model == fz_device_rgb(ctx)) ||
- (pixmap->colorspace == fz_device_gray(ctx) && model == fz_device_bgr(ctx)))
+ if ((src_cs == fz_device_gray(ctx) && model == fz_device_rgb(ctx)) ||
+ (src_cs == fz_device_gray(ctx) && model == fz_device_bgr(ctx)))
{
/* We have special case rendering code for gray -> rgb/bgr */
}
else
#endif
{
- fz_pixmap *converted = fz_convert_pixmap(ctx, pixmap, model, 1);
+ fz_pixmap *converted = fz_convert_pixmap(ctx, pixmap, model, prf, dev->default_cs, color_params, 1);
fz_drop_pixmap(ctx, pixmap);
pixmap = converted;
}
@@ -1345,7 +1421,7 @@ fz_draw_fill_image(fz_context *ctx, fz_device *devp, fz_image *image, const fz_m
static void
fz_draw_fill_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const fz_matrix *in_ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace_in, const float *color, float alpha, const fz_color_params *color_params)
{
fz_draw_device *dev = (fz_draw_device*)devp;
fz_matrix local_ctm = concat(in_ctm, &dev->transform);
@@ -1360,6 +1436,14 @@ fz_draw_fill_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const
fz_irect clip;
fz_matrix inverse;
fz_irect src_area;
+ fz_colorspace *colorspace = NULL;
+ fz_colorspace *prf = fz_proof_cs(ctx, devp);
+
+ if (colorspace_in)
+ colorspace = fz_default_colorspace(ctx, dev->default_cs, colorspace_in);
+
+ if (color_params == NULL)
+ color_params = fz_default_color_params(ctx);
if (colorspace == NULL && model != NULL)
fz_throw(ctx, FZ_ERROR_GENERIC, "color destination requires source color");
@@ -1436,7 +1520,7 @@ fz_draw_fill_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const
n = fz_colorspace_n(ctx, model);
if (n > 0)
{
- fz_convert_color(ctx, model, colorfv, colorspace, color);
+ fz_convert_color(ctx, color_params, prf, model, colorfv, colorspace, color);
for (i = 0; i < n; i++)
colorbv[i] = colorfv[i] * 255;
}
@@ -1629,7 +1713,7 @@ fz_draw_pop_clip(fz_context *ctx, fz_device *devp)
}
static void
-fz_draw_begin_mask(fz_context *ctx, fz_device *devp, const fz_rect *rect, int luminosity, fz_colorspace *colorspace, const float *colorfv)
+fz_draw_begin_mask(fz_context *ctx, fz_device *devp, const fz_rect *rect, int luminosity, fz_colorspace *colorspace_in, const float *colorfv, const fz_color_params *color_params)
{
fz_draw_device *dev = (fz_draw_device*)devp;
fz_pixmap *dest;
@@ -1637,6 +1721,13 @@ fz_draw_begin_mask(fz_context *ctx, fz_device *devp, const fz_rect *rect, int lu
fz_draw_state *state = push_stack(ctx, dev);
fz_pixmap *shape = state->shape;
fz_rect trect = *rect;
+ fz_colorspace *colorspace = NULL;
+
+ if (colorspace_in)
+ colorspace = fz_default_colorspace(ctx, dev->default_cs, colorspace_in);
+
+ if (color_params == NULL)
+ color_params = fz_default_color_params(ctx);
STACK_PUSHED("mask");
fz_transform_rect(&trect, &dev->transform);
@@ -1671,7 +1762,7 @@ fz_draw_begin_mask(fz_context *ctx, fz_device *devp, const fz_rect *rect, int lu
float bc;
if (!colorspace)
colorspace = fz_device_gray(ctx);
- fz_convert_color(ctx, fz_device_gray(ctx), &bc, colorspace, colorfv);
+ fz_convert_color(ctx, color_params, NULL, fz_device_gray(ctx), &bc, colorspace, colorfv);
fz_clear_pixmap_with_value(ctx, dest, bc * 255);
if (shape)
fz_clear_pixmap_with_value(ctx, shape, 255);
@@ -2247,11 +2338,28 @@ fz_draw_end_tile(fz_context *ctx, fz_device *devp)
}
static void
+fz_draw_render_flags(fz_context *ctx, fz_device *devp, int set, int clear)
+{
+ fz_draw_device *dev = (fz_draw_device*)devp;
+ dev->flags = (dev->flags | set ) & ~clear;
+}
+
+static void
+fz_draw_set_default_colorspaces(fz_context *ctx, fz_device *devp, fz_default_colorspaces *default_cs)
+{
+ fz_draw_device *dev = (fz_draw_device*)devp;
+ fz_drop_default_colorspaces(ctx, dev->default_cs);
+ dev->default_cs = fz_keep_default_colorspaces(ctx, default_cs);
+}
+
+static void
fz_draw_drop_device(fz_context *ctx, fz_device *devp)
{
fz_draw_device *dev = (fz_draw_device*)devp;
fz_rasterizer *rast = dev->rast;
+ fz_drop_default_colorspaces(ctx, dev->default_cs);
+
/* pop and free the stacks */
if (dev->top > 0)
fz_warn(ctx, "items left on stack in draw device: %d", dev->top+1);
@@ -2277,14 +2385,6 @@ fz_draw_drop_device(fz_context *ctx, fz_device *devp)
fz_drop_rasterizer(ctx, rast);
}
-static void
-fz_draw_render_flags(fz_context *ctx, fz_device *devp, int set, int clear)
-{
- fz_draw_device *dev = (fz_draw_device*)devp;
-
- dev->flags = (dev->flags | set ) & ~clear;
-}
-
fz_device *
fz_new_draw_device(fz_context *ctx, const fz_matrix *transform, fz_pixmap *dest)
{
@@ -2319,6 +2419,7 @@ fz_new_draw_device(fz_context *ctx, const fz_matrix *transform, fz_pixmap *dest)
dev->super.end_tile = fz_draw_end_tile;
dev->super.render_flags = fz_draw_render_flags;
+ dev->super.set_default_colorspaces = fz_draw_set_default_colorspaces;
dev->transform = transform ? *transform : fz_identity;
dev->flags = 0;
diff --git a/source/fitz/draw-mesh.c b/source/fitz/draw-mesh.c
index a40cdd12..10091521 100644
--- a/source/fitz/draw-mesh.c
+++ b/source/fitz/draw-mesh.c
@@ -205,7 +205,7 @@ do_paint_tri(fz_context *ctx, void *arg, fz_vertex *av, fz_vertex *bv, fz_vertex
}
void
-fz_paint_shade(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, fz_pixmap *dest, const fz_irect *bbox)
+fz_paint_shade(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, fz_pixmap *dest, fz_colorspace *prf, const fz_color_params *color_params, const fz_irect *bbox)
{
unsigned char clut[256][FZ_MAX_COLORS];
fz_pixmap *temp = NULL;
@@ -227,7 +227,7 @@ fz_paint_shade(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, fz_pixmap
fz_color_converter cc;
int cn = fz_colorspace_n(ctx, shade->colorspace);
n = fz_colorspace_n(ctx, dest->colorspace);
- fz_lookup_color_converter(ctx, &cc, dest->colorspace, shade->colorspace);
+ fz_find_color_converter(ctx, &cc, prf, dest->colorspace, shade->colorspace, color_params);
for (i = 0; i < 256; i++)
{
cc.convert(ctx, &cc, color, shade->function[i]);
@@ -235,6 +235,7 @@ fz_paint_shade(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, fz_pixmap
clut[i][k] = color[k] * 255;
clut[i][k] = shade->function[i][cn] * 255;
}
+ fz_drop_color_converter(ctx, &cc);
/* We need to use alpha = 1 here, because the shade might not fill
* the bbox. */
conv = fz_new_pixmap_with_bbox(ctx, dest->colorspace, bbox, 1);
@@ -250,7 +251,7 @@ fz_paint_shade(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, fz_pixmap
ptd.shade = shade;
ptd.bbox = bbox;
- fz_init_cached_color_converter(ctx, &ptd.cc, temp->colorspace, shade->colorspace);
+ fz_init_cached_color_converter(ctx, &ptd.cc, NULL, temp->colorspace, shade->colorspace, color_params);
fz_process_shade(ctx, shade, &local_ctm, prepare_mesh_vertex, &do_paint_tri, &ptd);
if (shade->use_function)
diff --git a/source/fitz/fitz-imp.h b/source/fitz/fitz-imp.h
index d75e2242..23908a8d 100644
--- a/source/fitz/fitz-imp.h
+++ b/source/fitz/fitz-imp.h
@@ -13,6 +13,8 @@ struct fz_buffer_s
};
void fz_new_colorspace_context(fz_context *ctx);
+void fz_new_cmm_context(fz_context *ctx);
+void fz_drop_cmm_context(fz_context *ctx);
fz_colorspace_context *fz_keep_colorspace_context(fz_context *ctx);
void fz_drop_colorspace_context(fz_context *ctx);
diff --git a/source/fitz/icc34.h b/source/fitz/icc34.h
new file mode 100644
index 00000000..3b63abcf
--- /dev/null
+++ b/source/fitz/icc34.h
@@ -0,0 +1,1022 @@
+/* Header file guard bands */
+#ifndef ICC_H
+#define ICC_H
+
+/*****************************************************************
+ Copyright (c) 1994-1996 SunSoft, Inc.
+
+ Rights Reserved
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without restrict-
+ion, including without limitation the rights to use, copy, modify,
+merge, publish distribute, sublicense, and/or sell copies of the
+Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-
+INFRINGEMENT. IN NO EVENT SHALL SUNSOFT, INC. OR ITS PARENT
+COMPANY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of SunSoft, Inc.
+shall not be used in advertising or otherwise to promote the
+sale, use or other dealings in this Software without written
+authorization from SunSoft Inc.
+******************************************************************/
+
+/*
+ * This version of the header file corresponds to the profile
+ * specification version 3.4.
+ *
+ * All header file entries are pre-fixed with "ic" to help
+ * avoid name space collisions. Signatures are pre-fixed with
+ * icSig.
+ *
+ * The structures defined in this header file were created to
+ * represent a description of an ICC profile on disk. Rather
+ * than use pointers a technique is used where a single byte array
+ * was placed at the end of each structure. This allows us in "C"
+ * to extend the structure by allocating more data than is needed
+ * to account for variable length structures.
+ *
+ * This also ensures that data following is allocated
+ * contiguously and makes it easier to write and read data from
+ * the file.
+ *
+ * For example to allocate space for a 256 count length UCR
+ * and BG array, and fill the allocated data. Note strlen + 1
+ * to remember NULL terminator.
+ *
+ icUcrBgCurve *ucrCurve, *bgCurve;
+ int ucr_nbytes, bg_nbytes, string_bytes;
+ icUcrBg *ucrBgWrite;
+ char ucr_string[100], *ucr_char;
+
+ strcpy(ucr_string, "Example ucrBG curves");
+ ucr_nbytes = sizeof(icUInt32Number) +
+ (UCR_CURVE_SIZE * sizeof(icUInt16Number));
+ bg_nbytes = sizeof(icUInt32Number) +
+ (BG_CURVE_SIZE * sizeof(icUInt16Number));
+ string_bytes = strlen(ucr_string) + 1;
+
+ ucrBgWrite = (icUcrBg *)malloc(
+ (ucr_nbytes + bg_nbytes + string_bytes));
+
+ ucrCurve = (icUcrBgCurve *)ucrBgWrite->data;
+ ucrCurve->count = UCR_CURVE_SIZE;
+ for (i=0; i<ucrCurve->count; i++)
+ ucrCurve->curve[i] = (icUInt16Number)i;
+
+ bgCurve = (icUcrBgCurve *)((char *)ucrCurve + ucr_nbytes);
+ bgCurve->count = BG_CURVE_SIZE;
+ for (i=0; i<bgCurve->count; i++)
+ bgCurve->curve[i] = 255 - (icUInt16Number)i;
+
+ ucr_char = (char *)((char *)bgCurve + bg_nbytes);
+ memcpy(ucr_char, ucr_string, string_bytes);
+ *
+ */
+
+/*
+ * Many of the structures contain variable length arrays. This
+ * is represented by the use of the convention.
+ *
+ * type data[icAny];
+ */
+
+/*------------------------------------------------------------------------*/
+/*
+ * Defines used in the specification
+ */
+#define icMagicNumber 0x61637370L /* 'acsp' */
+#define icVersionNumber 0x02100000L /* 2.1.0, BCD */
+
+/* Screening Encodings */
+#define icPrtrDefaultScreensFalse 0x00000000L /* Bit pos 0 */
+#define icPrtrDefaultScreensTrue 0x00000001L /* Bit pos 0 */
+#define icLinesPerInch 0x00000002L /* Bit pos 1 */
+#define icLinesPerCm 0x00000000L /* Bit pos 1 */
+
+/*
+ * Device attributes, currently defined values correspond
+ * to the low 4 bytes of the 8 byte attribute quantity, see
+ * the header for their location.
+ */
+#define icReflective 0x00000000L /* Bit pos 0 */
+#define icTransparency 0x00000001L /* Bit pos 0 */
+#define icGlossy 0x00000000L /* Bit pos 1 */
+#define icMatte 0x00000002L /* Bit pos 1 */
+
+/*
+ * Profile header flags, the low 16 bits are reserved for consortium
+ * use.
+ */
+#define icEmbeddedProfileFalse 0x00000000L /* Bit pos 0 */
+#define icEmbeddedProfileTrue 0x00000001L /* Bit pos 0 */
+#define icUseAnywhere 0x00000000L /* Bit pos 1 */
+#define icUseWithEmbeddedDataOnly 0x00000002L /* Bit pos 1 */
+
+/* Ascii or Binary data */
+#define icAsciiData 0x00000000L
+#define icBinaryData 0x00000001L
+
+/*
+ * Define used to indicate that this is a variable length array
+ */
+#define icAny 1
+
+
+/*------------------------------------------------------------------------*/
+/*
+ * Use this area to translate platform definitions of long
+ * etc into icXXX form. The rest of the header uses the icXXX
+ * typedefs. Signatures are 4 byte quantities.
+ *
+ */
+
+
+#ifdef PACKAGE_NAME
+/*
+ June 9, 2003, Adapted for use with configure by Bob Friesenhahn
+ Added the stupid check for autoconf by Marti Maria.
+ PACKAGE_NAME is defined if autoconf is being used
+*/
+
+typedef @UINT8_T@ icUInt8Number;
+typedef @UINT16_T@ icUInt16Number;
+typedef @UINT32_T@ icUInt32Number;
+typedef @UINT32_T@ icUInt64Number[2];
+
+typedef @INT8_T@ icInt8Number;
+typedef @INT16_T@ icInt16Number;
+typedef @INT32_T@ icInt32Number;
+typedef @INT32_T@ icInt64Number[2];
+
+#elif defined (__digital__) && defined (__unix__)
+
+/*
+ *Apr-17-2002: Modified by Marti Maria in order to provide wider portability.
+ */
+
+/* Tru64 */
+
+#include <inttypes.h>
+
+typedef uint8_t icUInt8Number;
+typedef uint16_t icUInt16Number;
+typedef uint32_t icUInt32Number;
+typedef uint32_t icUInt64Number[2];
+
+typedef int8_t icInt8Number;
+typedef int16_t icInt16Number;
+typedef int32_t icInt32Number;
+typedef int32_t icInt64Number[2];
+
+#elif defined(__sgi)
+#include "sgidefs.h"
+
+
+/*
+ * Number definitions
+ */
+
+/* Unsigned integer numbers */
+typedef unsigned char icUInt8Number;
+typedef unsigned short icUInt16Number;
+typedef __uint32_t icUInt32Number;
+typedef __uint32_t icUInt64Number[2];
+
+/* Signed numbers */
+typedef char icInt8Number;
+typedef short icInt16Number;
+typedef __int32_t icInt32Number;
+typedef __int32_t icInt64Number[2];
+
+
+#elif defined(__GNUC__) || defined(__unix__) || defined(__unix)
+
+#include <sys/types.h>
+
+#if defined(__sun) || defined(__hpux) || defined (__MINGW) || defined(__MINGW32__) || defined(HAVE_STDINT_H)
+
+#if defined (__MINGW) || defined(__MINGW32__) || defined(HAVE_STDINT_H)
+#include <stdint.h>
+#endif
+
+
+typedef uint8_t icUInt8Number;
+typedef uint16_t icUInt16Number;
+typedef uint32_t icUInt32Number;
+typedef uint32_t icUInt64Number[2];
+
+#else
+
+/* Unsigned integer numbers */
+typedef u_int8_t icUInt8Number;
+typedef u_int16_t icUInt16Number;
+typedef u_int32_t icUInt32Number;
+typedef u_int32_t icUInt64Number[2];
+
+#endif /* defined(__sun) || defined(__hpux) || defined (__MINGW) || defined(__MINGW32__) || defined(HAVE_STDINT_H) */
+
+
+/* Signed numbers */
+typedef int8_t icInt8Number;
+typedef int16_t icInt16Number;
+typedef int32_t icInt32Number;
+typedef int32_t icInt64Number[2];
+
+
+#else /* default definitions */
+
+/*
+ * Number definitions
+ */
+
+/* Unsigned integer numbers */
+typedef unsigned char icUInt8Number;
+typedef unsigned short icUInt16Number;
+typedef unsigned long icUInt32Number;
+typedef unsigned long icUInt64Number[2];
+
+/* Signed numbers */
+typedef char icInt8Number;
+typedef short icInt16Number;
+typedef long icInt32Number;
+typedef long icInt64Number[2];
+
+
+#endif /* default defs */
+
+/* Base types */
+
+typedef icInt32Number icSignature;
+typedef icInt32Number icS15Fixed16Number;
+typedef icUInt32Number icU16Fixed16Number;
+
+
+/*------------------------------------------------------------------------*/
+/* public tags and sizes */
+typedef enum {
+ icSigAToB0Tag = 0x41324230L, /* 'A2B0' */
+ icSigAToB1Tag = 0x41324231L, /* 'A2B1' */
+ icSigAToB2Tag = 0x41324232L, /* 'A2B2' */
+ icSigBlueColorantTag = 0x6258595AL, /* 'bXYZ' */
+ icSigBlueTRCTag = 0x62545243L, /* 'bTRC' */
+ icSigBToA0Tag = 0x42324130L, /* 'B2A0' */
+ icSigBToA1Tag = 0x42324131L, /* 'B2A1' */
+ icSigBToA2Tag = 0x42324132L, /* 'B2A2' */
+ icSigCalibrationDateTimeTag = 0x63616C74L, /* 'calt' */
+ icSigCharTargetTag = 0x74617267L, /* 'targ' */
+ icSigCopyrightTag = 0x63707274L, /* 'cprt' */
+ icSigCrdInfoTag = 0x63726469L, /* 'crdi' */
+ icSigDeviceMfgDescTag = 0x646D6E64L, /* 'dmnd' */
+ icSigDeviceModelDescTag = 0x646D6464L, /* 'dmdd' */
+ icSigGamutTag = 0x67616D74L, /* 'gamt ' */
+ icSigGrayTRCTag = 0x6b545243L, /* 'kTRC' */
+ icSigGreenColorantTag = 0x6758595AL, /* 'gXYZ' */
+ icSigGreenTRCTag = 0x67545243L, /* 'gTRC' */
+ icSigLuminanceTag = 0x6C756d69L, /* 'lumi' */
+ icSigMeasurementTag = 0x6D656173L, /* 'meas' */
+ icSigMediaBlackPointTag = 0x626B7074L, /* 'bkpt' */
+ icSigMediaWhitePointTag = 0x77747074L, /* 'wtpt' */
+ icSigNamedColorTag = 0x6E636f6CL, /* 'ncol'
+ * OBSOLETE, use ncl2 */
+ icSigNamedColor2Tag = 0x6E636C32L, /* 'ncl2' */
+ icSigPreview0Tag = 0x70726530L, /* 'pre0' */
+ icSigPreview1Tag = 0x70726531L, /* 'pre1' */
+ icSigPreview2Tag = 0x70726532L, /* 'pre2' */
+ icSigProfileDescriptionTag = 0x64657363L, /* 'desc' */
+ icSigProfileSequenceDescTag = 0x70736571L, /* 'pseq' */
+ icSigPs2CRD0Tag = 0x70736430L, /* 'psd0' */
+ icSigPs2CRD1Tag = 0x70736431L, /* 'psd1' */
+ icSigPs2CRD2Tag = 0x70736432L, /* 'psd2' */
+ icSigPs2CRD3Tag = 0x70736433L, /* 'psd3' */
+ icSigPs2CSATag = 0x70733273L, /* 'ps2s' */
+ icSigPs2RenderingIntentTag = 0x70733269L, /* 'ps2i' */
+ icSigRedColorantTag = 0x7258595AL, /* 'rXYZ' */
+ icSigRedTRCTag = 0x72545243L, /* 'rTRC' */
+ icSigScreeningDescTag = 0x73637264L, /* 'scrd' */
+ icSigScreeningTag = 0x7363726EL, /* 'scrn' */
+ icSigTechnologyTag = 0x74656368L, /* 'tech' */
+ icSigUcrBgTag = 0x62666420L, /* 'bfd ' */
+ icSigViewingCondDescTag = 0x76756564L, /* 'vued' */
+ icSigViewingConditionsTag = 0x76696577L, /* 'view' */
+ icMaxEnumTag = 0xFFFFFFFFL
+} icTagSignature;
+
+/* technology signature descriptions */
+typedef enum {
+ icSigDigitalCamera = 0x6463616DL, /* 'dcam' */
+ icSigFilmScanner = 0x6673636EL, /* 'fscn' */
+ icSigReflectiveScanner = 0x7273636EL, /* 'rscn' */
+ icSigInkJetPrinter = 0x696A6574L, /* 'ijet' */
+ icSigThermalWaxPrinter = 0x74776178L, /* 'twax' */
+ icSigElectrophotographicPrinter = 0x6570686FL, /* 'epho' */
+ icSigElectrostaticPrinter = 0x65737461L, /* 'esta' */
+ icSigDyeSublimationPrinter = 0x64737562L, /* 'dsub' */
+ icSigPhotographicPaperPrinter = 0x7270686FL, /* 'rpho' */
+ icSigFilmWriter = 0x6670726EL, /* 'fprn' */
+ icSigVideoMonitor = 0x7669646DL, /* 'vidm' */
+ icSigVideoCamera = 0x76696463L, /* 'vidc' */
+ icSigProjectionTelevision = 0x706A7476L, /* 'pjtv' */
+ icSigCRTDisplay = 0x43525420L, /* 'CRT ' */
+ icSigPMDisplay = 0x504D4420L, /* 'PMD ' */
+ icSigAMDisplay = 0x414D4420L, /* 'AMD ' */
+ icSigPhotoCD = 0x4B504344L, /* 'KPCD' */
+ icSigPhotoImageSetter = 0x696D6773L, /* 'imgs' */
+ icSigGravure = 0x67726176L, /* 'grav' */
+ icSigOffsetLithography = 0x6F666673L, /* 'offs' */
+ icSigSilkscreen = 0x73696C6BL, /* 'silk' */
+ icSigFlexography = 0x666C6578L, /* 'flex' */
+ icMaxEnumTechnology = 0xFFFFFFFFL
+} icTechnologySignature;
+
+/* type signatures */
+typedef enum {
+ icSigCurveType = 0x63757276L, /* 'curv' */
+ icSigDataType = 0x64617461L, /* 'data' */
+ icSigDateTimeType = 0x6474696DL, /* 'dtim' */
+ icSigLut16Type = 0x6d667432L, /* 'mft2' */
+ icSigLut8Type = 0x6d667431L, /* 'mft1' */
+ icSigMeasurementType = 0x6D656173L, /* 'meas' */
+ icSigNamedColorType = 0x6E636f6CL, /* 'ncol'
+ * OBSOLETE, use ncl2 */
+ icSigProfileSequenceDescType = 0x70736571L, /* 'pseq' */
+ icSigS15Fixed16ArrayType = 0x73663332L, /* 'sf32' */
+ icSigScreeningType = 0x7363726EL, /* 'scrn' */
+ icSigSignatureType = 0x73696720L, /* 'sig ' */
+ icSigTextType = 0x74657874L, /* 'text' */
+ icSigTextDescriptionType = 0x64657363L, /* 'desc' */
+ icSigU16Fixed16ArrayType = 0x75663332L, /* 'uf32' */
+ icSigUcrBgType = 0x62666420L, /* 'bfd ' */
+ icSigUInt16ArrayType = 0x75693136L, /* 'ui16' */
+ icSigUInt32ArrayType = 0x75693332L, /* 'ui32' */
+ icSigUInt64ArrayType = 0x75693634L, /* 'ui64' */
+ icSigUInt8ArrayType = 0x75693038L, /* 'ui08' */
+ icSigViewingConditionsType = 0x76696577L, /* 'view' */
+ icSigXYZType = 0x58595A20L, /* 'XYZ ' */
+ icSigXYZArrayType = 0x58595A20L, /* 'XYZ ' */
+ icSigNamedColor2Type = 0x6E636C32L, /* 'ncl2' */
+ icSigCrdInfoType = 0x63726469L, /* 'crdi' */
+ icMaxEnumType = 0xFFFFFFFFL
+} icTagTypeSignature;
+
+/*
+ * Color Space Signatures
+ * Note that only icSigXYZData and icSigLabData are valid
+ * Profile Connection Spaces (PCSs)
+ */
+typedef enum {
+ icSigXYZData = 0x58595A20L, /* 'XYZ ' */
+ icSigLabData = 0x4C616220L, /* 'Lab ' */
+ icSigLuvData = 0x4C757620L, /* 'Luv ' */
+ icSigYCbCrData = 0x59436272L, /* 'YCbr' */
+ icSigYxyData = 0x59787920L, /* 'Yxy ' */
+ icSigRgbData = 0x52474220L, /* 'RGB ' */
+ icSigGrayData = 0x47524159L, /* 'GRAY' */
+ icSigHsvData = 0x48535620L, /* 'HSV ' */
+ icSigHlsData = 0x484C5320L, /* 'HLS ' */
+ icSigCmykData = 0x434D594BL, /* 'CMYK' */
+ icSigCmyData = 0x434D5920L, /* 'CMY ' */
+ icSig2colorData = 0x32434C52L, /* '2CLR' */
+ icSig3colorData = 0x33434C52L, /* '3CLR' */
+ icSig4colorData = 0x34434C52L, /* '4CLR' */
+ icSig5colorData = 0x35434C52L, /* '5CLR' */
+ icSig6colorData = 0x36434C52L, /* '6CLR' */
+ icSig7colorData = 0x37434C52L, /* '7CLR' */
+ icSig8colorData = 0x38434C52L, /* '8CLR' */
+ icSig9colorData = 0x39434C52L, /* '9CLR' */
+ icSig10colorData = 0x41434C52L, /* 'ACLR' */
+ icSig11colorData = 0x42434C52L, /* 'BCLR' */
+ icSig12colorData = 0x43434C52L, /* 'CCLR' */
+ icSig13colorData = 0x44434C52L, /* 'DCLR' */
+ icSig14colorData = 0x45434C52L, /* 'ECLR' */
+ icSig15colorData = 0x46434C52L, /* 'FCLR' */
+ icMaxEnumData = 0xFFFFFFFFL
+} icColorSpaceSignature;
+
+/* profileClass enumerations */
+typedef enum {
+ icSigInputClass = 0x73636E72L, /* 'scnr' */
+ icSigDisplayClass = 0x6D6E7472L, /* 'mntr' */
+ icSigOutputClass = 0x70727472L, /* 'prtr' */
+ icSigLinkClass = 0x6C696E6BL, /* 'link' */
+ icSigAbstractClass = 0x61627374L, /* 'abst' */
+ icSigColorSpaceClass = 0x73706163L, /* 'spac' */
+ icSigNamedColorClass = 0x6e6d636cL, /* 'nmcl' */
+ icMaxEnumClass = 0xFFFFFFFFL
+} icProfileClassSignature;
+
+/* Platform Signatures */
+typedef enum {
+ icSigMacintosh = 0x4150504CL, /* 'APPL' */
+ icSigMicrosoft = 0x4D534654L, /* 'MSFT' */
+ icSigSolaris = 0x53554E57L, /* 'SUNW' */
+ icSigSGI = 0x53474920L, /* 'SGI ' */
+ icSigTaligent = 0x54474E54L, /* 'TGNT' */
+ icMaxEnumPlatform = 0xFFFFFFFFL
+} icPlatformSignature;
+
+/*------------------------------------------------------------------------*/
+/*
+ * Other enums
+ */
+
+/* Measurement Flare, used in the measurmentType tag */
+typedef enum {
+ icFlare0 = 0x00000000L, /* 0% flare */
+ icFlare100 = 0x00000001L, /* 100% flare */
+ icMaxFlare = 0xFFFFFFFFL
+} icMeasurementFlare;
+
+/* Measurement Geometry, used in the measurmentType tag */
+typedef enum {
+ icGeometryUnknown = 0x00000000L, /* Unknown */
+ icGeometry045or450 = 0x00000001L, /* 0/45, 45/0 */
+ icGeometry0dord0 = 0x00000002L, /* 0/d or d/0 */
+ icMaxGeometry = 0xFFFFFFFFL
+} icMeasurementGeometry;
+
+/* Rendering Intents, used in the profile header */
+typedef enum {
+ icPerceptual = 0,
+ icRelativeColorimetric = 1,
+ icSaturation = 2,
+ icAbsoluteColorimetric = 3,
+ icMaxEnumIntent = 0xFFFFFFFFL
+} icRenderingIntent;
+
+/* Different Spot Shapes currently defined, used for screeningType */
+typedef enum {
+ icSpotShapeUnknown = 0,
+ icSpotShapePrinterDefault = 1,
+ icSpotShapeRound = 2,
+ icSpotShapeDiamond = 3,
+ icSpotShapeEllipse = 4,
+ icSpotShapeLine = 5,
+ icSpotShapeSquare = 6,
+ icSpotShapeCross = 7,
+ icMaxEnumSpot = 0xFFFFFFFFL
+} icSpotShape;
+
+/* Standard Observer, used in the measurmentType tag */
+typedef enum {
+ icStdObsUnknown = 0x00000000L, /* Unknown */
+ icStdObs1931TwoDegrees = 0x00000001L, /* 2 deg */
+ icStdObs1964TenDegrees = 0x00000002L, /* 10 deg */
+ icMaxStdObs = 0xFFFFFFFFL
+} icStandardObserver;
+
+/* Pre-defined illuminants, used in measurement and viewing conditions type */
+typedef enum {
+ icIlluminantUnknown = 0x00000000L,
+ icIlluminantD50 = 0x00000001L,
+ icIlluminantD65 = 0x00000002L,
+ icIlluminantD93 = 0x00000003L,
+ icIlluminantF2 = 0x00000004L,
+ icIlluminantD55 = 0x00000005L,
+ icIlluminantA = 0x00000006L,
+ icIlluminantEquiPowerE = 0x00000007L,
+ icIlluminantF8 = 0x00000008L,
+ icMaxEnumIluminant = 0xFFFFFFFFL
+} icIlluminant;
+
+
+/*------------------------------------------------------------------------*/
+/*
+ * Arrays of numbers
+ */
+
+/* Int8 Array */
+typedef struct {
+ icInt8Number data[icAny]; /* Variable array of values */
+} icInt8Array;
+
+/* UInt8 Array */
+typedef struct {
+ icUInt8Number data[icAny]; /* Variable array of values */
+} icUInt8Array;
+
+/* uInt16 Array */
+typedef struct {
+ icUInt16Number data[icAny]; /* Variable array of values */
+} icUInt16Array;
+
+/* Int16 Array */
+typedef struct {
+ icInt16Number data[icAny]; /* Variable array of values */
+} icInt16Array;
+
+/* uInt32 Array */
+typedef struct {
+ icUInt32Number data[icAny]; /* Variable array of values */
+} icUInt32Array;
+
+/* Int32 Array */
+typedef struct {
+ icInt32Number data[icAny]; /* Variable array of values */
+} icInt32Array;
+
+/* UInt64 Array */
+typedef struct {
+ icUInt64Number data[icAny]; /* Variable array of values */
+} icUInt64Array;
+
+/* Int64 Array */
+typedef struct {
+ icInt64Number data[icAny]; /* Variable array of values */
+} icInt64Array;
+
+/* u16Fixed16 Array */
+typedef struct {
+ icU16Fixed16Number data[icAny]; /* Variable array of values */
+} icU16Fixed16Array;
+
+/* s15Fixed16 Array */
+typedef struct {
+ icS15Fixed16Number data[icAny]; /* Variable array of values */
+} icS15Fixed16Array;
+
+/* The base date time number */
+typedef struct {
+ icUInt16Number year;
+ icUInt16Number month;
+ icUInt16Number day;
+ icUInt16Number hours;
+ icUInt16Number minutes;
+ icUInt16Number seconds;
+} icDateTimeNumber;
+
+/* XYZ Number */
+typedef struct {
+ icS15Fixed16Number X;
+ icS15Fixed16Number Y;
+ icS15Fixed16Number Z;
+} icXYZNumber;
+
+/* XYZ Array */
+typedef struct {
+ icXYZNumber data[icAny]; /* Variable array of XYZ numbers */
+} icXYZArray;
+
+/* Curve */
+typedef struct {
+ icUInt32Number count; /* Number of entries */
+ icUInt16Number data[icAny]; /* The actual table data, real
+ * number is determined by count
+ * Interpretation depends on how
+ * data is used with a given tag
+ */
+} icCurve;
+
+/* Data */
+typedef struct {
+ icUInt32Number dataFlag; /* 0 = ascii, 1 = binary */
+ icInt8Number data[icAny]; /* Data, size from tag */
+} icData;
+
+/* lut16 */
+typedef struct {
+ icUInt8Number inputChan; /* Number of input channels */
+ icUInt8Number outputChan; /* Number of output channels */
+ icUInt8Number clutPoints; /* Number of grid points */
+ icInt8Number pad; /* Padding for byte alignment */
+ icS15Fixed16Number e00; /* e00 in the 3 * 3 */
+ icS15Fixed16Number e01; /* e01 in the 3 * 3 */
+ icS15Fixed16Number e02; /* e02 in the 3 * 3 */
+ icS15Fixed16Number e10; /* e10 in the 3 * 3 */
+ icS15Fixed16Number e11; /* e11 in the 3 * 3 */
+ icS15Fixed16Number e12; /* e12 in the 3 * 3 */
+ icS15Fixed16Number e20; /* e20 in the 3 * 3 */
+ icS15Fixed16Number e21; /* e21 in the 3 * 3 */
+ icS15Fixed16Number e22; /* e22 in the 3 * 3 */
+ icUInt16Number inputEnt; /* Num of in-table entries */
+ icUInt16Number outputEnt; /* Num of out-table entries */
+ icUInt16Number data[icAny]; /* Data follows see spec */
+/*
+ * Data that follows is of this form
+ *
+ * icUInt16Number inputTable[inputChan][icAny]; * The in-table
+ * icUInt16Number clutTable[icAny]; * The clut
+ * icUInt16Number outputTable[outputChan][icAny]; * The out-table
+ */
+} icLut16;
+
+/* lut8, input & output tables are always 256 bytes in length */
+typedef struct {
+ icUInt8Number inputChan; /* Num of input channels */
+ icUInt8Number outputChan; /* Num of output channels */
+ icUInt8Number clutPoints; /* Num of grid points */
+ icInt8Number pad;
+ icS15Fixed16Number e00; /* e00 in the 3 * 3 */
+ icS15Fixed16Number e01; /* e01 in the 3 * 3 */
+ icS15Fixed16Number e02; /* e02 in the 3 * 3 */
+ icS15Fixed16Number e10; /* e10 in the 3 * 3 */
+ icS15Fixed16Number e11; /* e11 in the 3 * 3 */
+ icS15Fixed16Number e12; /* e12 in the 3 * 3 */
+ icS15Fixed16Number e20; /* e20 in the 3 * 3 */
+ icS15Fixed16Number e21; /* e21 in the 3 * 3 */
+ icS15Fixed16Number e22; /* e22 in the 3 * 3 */
+ icUInt8Number data[icAny]; /* Data follows see spec */
+/*
+ * Data that follows is of this form
+ *
+ * icUInt8Number inputTable[inputChan][256]; * The in-table
+ * icUInt8Number clutTable[icAny]; * The clut
+ * icUInt8Number outputTable[outputChan][256]; * The out-table
+ */
+} icLut8;
+
+/* Measurement Data */
+typedef struct {
+ icStandardObserver stdObserver; /* Standard observer */
+ icXYZNumber backing; /* XYZ for backing */
+ icMeasurementGeometry geometry; /* Meas. geometry */
+ icMeasurementFlare flare; /* Measurement flare */
+ icIlluminant illuminant; /* Illuminant */
+} icMeasurement;
+
+/* Named color */
+
+/*
+ * icNamedColor2 takes the place of icNamedColor
+ */
+typedef struct {
+ icUInt32Number vendorFlag; /* Bottom 16 bits for IC use */
+ icUInt32Number count; /* Count of named colors */
+ icUInt32Number nDeviceCoords; /* Num of device coordinates */
+ icInt8Number prefix[32]; /* Prefix for each color name */
+ icInt8Number suffix[32]; /* Suffix for each color name */
+ icInt8Number data[icAny]; /* Named color data follows */
+/*
+ * Data that follows is of this form
+ *
+ * icInt8Number root1[32]; * Root name for 1st color
+ * icUInt16Number pcsCoords1[icAny]; * PCS coords of 1st color
+ * icUInt16Number deviceCoords1[icAny]; * Dev coords of 1st color
+ * icInt8Number root2[32]; * Root name for 2nd color
+ * icUInt16Number pcsCoords2[icAny]; * PCS coords of 2nd color
+ * icUInt16Number deviceCoords2[icAny]; * Dev coords of 2nd color
+ * :
+ * :
+ * Repeat for name and PCS and device color coordinates up to (count-1)
+ *
+ * NOTES:
+ * PCS and device space can be determined from the header.
+ *
+ * PCS coordinates are icUInt16 numbers and are described in Annex A of
+ * the ICC spec. Only 16 bit L*a*b* and XYZ are allowed. The number of
+ * coordinates is consistent with the headers PCS.
+ *
+ * Device coordinates are icUInt16 numbers where 0x0000 represents
+ * the minimum value and 0xFFFF represents the maximum value.
+ * If the nDeviceCoords value is 0 this field is not given.
+ */
+} icNamedColor2;
+
+/* Profile sequence structure */
+typedef struct {
+ icSignature deviceMfg; /* Dev Manufacturer */
+ icSignature deviceModel; /* Dev Model */
+ icUInt64Number attributes; /* Dev attributes */
+ icTechnologySignature technology; /* Technology sig */
+ icInt8Number data[icAny]; /* Desc text follows */
+/*
+ * Data that follows is of this form, this is an icInt8Number
+ * to avoid problems with a compiler generating bad code as
+ * these arrays are variable in length.
+ *
+ * icTextDescription deviceMfgDesc; * Manufacturer text
+ * icTextDescription modelDesc; * Model text
+ */
+} icDescStruct;
+
+/* Profile sequence description */
+typedef struct {
+ icUInt32Number count; /* Number of descriptions */
+ icUInt8Number data[icAny]; /* Array of desc structs */
+} icProfileSequenceDesc;
+
+/* textDescription */
+typedef struct {
+ icUInt32Number count; /* Description length */
+ icInt8Number data[icAny]; /* Descriptions follow */
+/*
+ * Data that follows is of this form
+ *
+ * icInt8Number desc[count] * NULL terminated ascii string
+ * icUInt32Number ucLangCode; * UniCode language code
+ * icUInt32Number ucCount; * UniCode description length
+ * icInt16Number ucDesc[ucCount];* The UniCode description
+ * icUInt16Number scCode; * ScriptCode code
+ * icUInt8Number scCount; * ScriptCode count
+ * icInt8Number scDesc[67]; * ScriptCode Description
+ */
+} icTextDescription;
+
+/* Screening Data */
+typedef struct {
+ icS15Fixed16Number frequency; /* Frequency */
+ icS15Fixed16Number angle; /* Screen angle */
+ icSpotShape spotShape; /* Spot Shape encodings below */
+} icScreeningData;
+
+typedef struct {
+ icUInt32Number screeningFlag; /* Screening flag */
+ icUInt32Number channels; /* Number of channels */
+ icScreeningData data[icAny]; /* Array of screening data */
+} icScreening;
+
+/* Text Data */
+typedef struct {
+ icInt8Number data[icAny]; /* Variable array of chars */
+} icText;
+
+/* Structure describing either a UCR or BG curve */
+typedef struct {
+ icUInt32Number count; /* Curve length */
+ icUInt16Number curve[icAny]; /* The array of curve values */
+} icUcrBgCurve;
+
+/* Under color removal, black generation */
+typedef struct {
+ icInt8Number data[icAny]; /* The Ucr BG data */
+/*
+ * Data that follows is of this form, this is a icInt8Number
+ * to avoid problems with a compiler generating bad code as
+ * these arrays are variable in length.
+ *
+ * icUcrBgCurve ucr; * Ucr curve
+ * icUcrBgCurve bg; * Bg curve
+ * icInt8Number string; * UcrBg description
+ */
+} icUcrBg;
+
+/* viewingConditionsType */
+typedef struct {
+ icXYZNumber illuminant; /* In candelas per sq. meter */
+ icXYZNumber surround; /* In candelas per sq. meter */
+ icIlluminant stdIluminant; /* See icIlluminant defines */
+} icViewingCondition;
+
+/* CrdInfo type */
+typedef struct {
+ icUInt32Number count; /* Char count includes NULL */
+ icInt8Number desc[icAny]; /* Null terminated string */
+} icCrdInfo;
+
+/*------------------------------------------------------------------------*/
+/*
+ * Tag Type definitions
+ */
+
+/*
+ * Many of the structures contain variable length arrays. This
+ * is represented by the use of the convention.
+ *
+ * type data[icAny];
+ */
+
+/* The base part of each tag */
+typedef struct {
+ icTagTypeSignature sig; /* Signature */
+ icInt8Number reserved[4]; /* Reserved, set to 0 */
+} icTagBase;
+
+/* curveType */
+typedef struct {
+ icTagBase base; /* Signature, "curv" */
+ icCurve curve; /* The curve data */
+} icCurveType;
+
+/* dataType */
+typedef struct {
+ icTagBase base; /* Signature, "data" */
+ icData data; /* The data structure */
+} icDataType;
+
+/* dateTimeType */
+typedef struct {
+ icTagBase base; /* Signature, "dtim" */
+ icDateTimeNumber date; /* The date */
+} icDateTimeType;
+
+/* lut16Type */
+typedef struct {
+ icTagBase base; /* Signature, "mft2" */
+ icLut16 lut; /* Lut16 data */
+} icLut16Type;
+
+/* lut8Type, input & output tables are always 256 bytes in length */
+typedef struct {
+ icTagBase base; /* Signature, "mft1" */
+ icLut8 lut; /* Lut8 data */
+} icLut8Type;
+
+/* Measurement Type */
+typedef struct {
+ icTagBase base; /* Signature, "meas" */
+ icMeasurement measurement; /* Measurement data */
+} icMeasurementType;
+
+/* Named color type */
+/* icNamedColor2Type, replaces icNamedColorType */
+typedef struct {
+ icTagBase base; /* Signature, "ncl2" */
+ icNamedColor2 ncolor; /* Named color data */
+} icNamedColor2Type;
+
+/* Profile sequence description type */
+typedef struct {
+ icTagBase base; /* Signature, "pseq" */
+ icProfileSequenceDesc desc; /* The seq description */
+} icProfileSequenceDescType;
+
+/* textDescriptionType */
+typedef struct {
+ icTagBase base; /* Signature, "desc" */
+ icTextDescription desc; /* The description */
+} icTextDescriptionType;
+
+/* s15Fixed16Type */
+typedef struct {
+ icTagBase base; /* Signature, "sf32" */
+ icS15Fixed16Array data; /* Array of values */
+} icS15Fixed16ArrayType;
+
+typedef struct {
+ icTagBase base; /* Signature, "scrn" */
+ icScreening screen; /* Screening structure */
+} icScreeningType;
+
+/* sigType */
+typedef struct {
+ icTagBase base; /* Signature, "sig" */
+ icSignature signature; /* The signature data */
+} icSignatureType;
+
+/* textType */
+typedef struct {
+ icTagBase base; /* Signature, "text" */
+ icText data; /* Variable array of chars */
+} icTextType;
+
+/* u16Fixed16Type */
+typedef struct {
+ icTagBase base; /* Signature, "uf32" */
+ icU16Fixed16Array data; /* Variable array of values */
+} icU16Fixed16ArrayType;
+
+/* Under color removal, black generation type */
+typedef struct {
+ icTagBase base; /* Signature, "bfd " */
+ icUcrBg data; /* ucrBg structure */
+} icUcrBgType;
+
+/* uInt16Type */
+typedef struct {
+ icTagBase base; /* Signature, "ui16" */
+ icUInt16Array data; /* Variable array of values */
+} icUInt16ArrayType;
+
+/* uInt32Type */
+typedef struct {
+ icTagBase base; /* Signature, "ui32" */
+ icUInt32Array data; /* Variable array of values */
+} icUInt32ArrayType;
+
+/* uInt64Type */
+typedef struct {
+ icTagBase base; /* Signature, "ui64" */
+ icUInt64Array data; /* Variable array of values */
+} icUInt64ArrayType;
+
+/* uInt8Type */
+typedef struct {
+ icTagBase base; /* Signature, "ui08" */
+ icUInt8Array data; /* Variable array of values */
+} icUInt8ArrayType;
+
+/* viewingConditionsType */
+typedef struct {
+ icTagBase base; /* Signature, "view" */
+ icViewingCondition view; /* Viewing conditions */
+} icViewingConditionType;
+
+/* XYZ Type */
+typedef struct {
+ icTagBase base; /* Signature, "XYZ" */
+ icXYZArray data; /* Variable array of XYZ nums */
+} icXYZType;
+
+/* CRDInfoType where [0] is the CRD product name count and string and
+ * [1] -[5] are the rendering intents 0-4 counts and strings
+ */
+typedef struct {
+ icTagBase base; /* Signature, "crdi" */
+ icCrdInfo info; /* 5 sets of counts & strings */
+}icCrdInfoType;
+ /* icCrdInfo productName; PS product count/string */
+ /* icCrdInfo CRDName0; CRD name for intent 0 */
+ /* icCrdInfo CRDName1; CRD name for intent 1 */
+ /* icCrdInfo CRDName2; CRD name for intent 2 */
+ /* icCrdInfo CRDName3; CRD name for intent 3 */
+
+/*------------------------------------------------------------------------*/
+
+/*
+ * Lists of tags, tags, profile header and profile structure
+ */
+
+/* A tag */
+typedef struct {
+ icTagSignature sig; /* The tag signature */
+ icUInt32Number offset; /* Start of tag relative to
+ * start of header, Spec
+ * Clause 5 */
+ icUInt32Number size; /* Size in bytes */
+} icTag;
+
+/* A Structure that may be used independently for a list of tags */
+typedef struct {
+ icUInt32Number count; /* Num tags in the profile */
+ icTag tags[icAny]; /* Variable array of tags */
+} icTagList;
+
+/* The Profile header */
+typedef struct {
+ icUInt32Number size; /* Prof size in bytes */
+ icSignature cmmId; /* CMM for profile */
+ icUInt32Number version; /* Format version */
+ icProfileClassSignature deviceClass; /* Type of profile */
+ icColorSpaceSignature colorSpace; /* Clr space of data */
+ icColorSpaceSignature pcs; /* PCS, XYZ or Lab */
+ icDateTimeNumber date; /* Creation Date */
+ icSignature magic; /* icMagicNumber */
+ icPlatformSignature platform; /* Primary Platform */
+ icUInt32Number flags; /* Various bits */
+ icSignature manufacturer; /* Dev manufacturer */
+ icUInt32Number model; /* Dev model number */
+ icUInt64Number attributes; /* Device attributes */
+ icUInt32Number renderingIntent;/* Rendering intent */
+ icXYZNumber illuminant; /* Profile illuminant */
+ icSignature creator; /* Profile creator */
+ icInt8Number reserved[44]; /* Reserved */
+} icHeader;
+
+/*
+ * A profile,
+ * we can't use icTagList here because its not at the end of the structure
+ */
+typedef struct {
+ icHeader header; /* The header */
+ icUInt32Number count; /* Num tags in the profile */
+ icInt8Number data[icAny]; /* The tagTable and tagData */
+/*
+ * Data that follows is of the form
+ *
+ * icTag tagTable[icAny]; * The tag table
+ * icInt8Number tagData[icAny]; * The tag data
+ */
+} icProfile;
+
+/*------------------------------------------------------------------------*/
+/* Obsolete entries */
+
+/* icNamedColor was replaced with icNamedColor2 */
+typedef struct {
+ icUInt32Number vendorFlag; /* Bottom 16 bits for IC use */
+ icUInt32Number count; /* Count of named colors */
+ icInt8Number data[icAny]; /* Named color data follows */
+/*
+ * Data that follows is of this form
+ *
+ * icInt8Number prefix[icAny]; * Prefix
+ * icInt8Number suffix[icAny]; * Suffix
+ * icInt8Number root1[icAny]; * Root name
+ * icInt8Number coords1[icAny]; * Color coordinates
+ * icInt8Number root2[icAny]; * Root name
+ * icInt8Number coords2[icAny]; * Color coordinates
+ * :
+ * :
+ * Repeat for root name and color coordinates up to (count-1)
+ */
+} icNamedColor;
+
+/* icNamedColorType was replaced by icNamedColor2Type */
+typedef struct {
+ icTagBase base; /* Signature, "ncol" */
+ icNamedColor ncolor; /* Named color data */
+} icNamedColorType;
+
+#endif /* ICC_H */
diff --git a/source/fitz/list-device.c b/source/fitz/list-device.c
index fdd5ea18..a8f0bb09 100644
--- a/source/fitz/list-device.c
+++ b/source/fitz/list-device.c
@@ -30,7 +30,8 @@ typedef enum fz_display_command_e
FZ_CMD_END_GROUP,
FZ_CMD_BEGIN_TILE,
FZ_CMD_END_TILE,
- FZ_CMD_RENDER_FLAGS
+ FZ_CMD_RENDER_FLAGS,
+ FZ_CMD_DEFAULT_COLORSPACES
} fz_display_command;
/* The display list is a list of nodes.
@@ -132,6 +133,7 @@ struct fz_list_device_s
fz_matrix ctm;
fz_stroke_state *stroke;
fz_colorspace *colorspace;
+ fz_color_params *color_params;
float color[FZ_MAX_COLORS];
fz_rect rect;
@@ -144,6 +146,8 @@ struct fz_list_device_s
};
enum { ISOLATED = 1, KNOCKOUT = 2 };
+enum { OPM = 1, OP = 2, BP = 3, RI = 4};
+
#define SIZE_IN_NODES(t) \
((t + sizeof(fz_display_node) - 1) / sizeof(fz_display_node))
@@ -530,38 +534,38 @@ fz_append_display_node(
switch(node.cs)
{
case CS_GRAY_0:
- writer->colorspace = fz_device_gray(ctx);
+ writer->colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx));
writer->color[0] = 0;
break;
case CS_GRAY_1:
- writer->colorspace = fz_device_gray(ctx);
+ writer->colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx));
writer->color[0] = 1;
break;
case CS_RGB_0:
writer->color[0] = 0;
writer->color[1] = 0;
writer->color[2] = 0;
- writer->colorspace = fz_device_rgb(ctx);
+ writer->colorspace = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
break;
case CS_RGB_1:
writer->color[0] = 1;
writer->color[1] = 1;
writer->color[2] = 1;
- writer->colorspace = fz_device_rgb(ctx);
+ writer->colorspace = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
break;
case CS_CMYK_0:
writer->color[0] = 0;
writer->color[1] = 0;
writer->color[2] = 0;
writer->color[3] = 0;
- writer->colorspace = fz_device_cmyk(ctx);
+ writer->colorspace = fz_keep_colorspace(ctx, fz_device_cmyk(ctx));
break;
case CS_CMYK_1:
writer->color[0] = 0;
writer->color[1] = 0;
writer->color[2] = 0;
writer->color[3] = 1;
- writer->colorspace = fz_device_cmyk(ctx);
+ writer->colorspace = fz_keep_colorspace(ctx, fz_device_cmyk(ctx));
break;
default:
{
@@ -628,9 +632,35 @@ fz_append_display_node(
list->len += size;
}
+/* Pack ri, op, opm, bp into flags upper bits, even/odd in lower bit */
+static int
+fz_pack_color_params(const fz_color_params *color_params)
+{
+ int flags = 0;
+
+ if (color_params == NULL)
+ return 0;
+
+ flags = color_params->ri << RI; /* 2 bits */
+ flags = flags | (color_params->bp << BP);
+ flags = flags | (color_params->op << OP);
+ flags = flags | (color_params->opm << OPM);
+ return flags;
+}
+
+/* unpack ri, op, opm, bp from flags, even/odd in lower bit */
+static void
+fz_unpack_color_params(fz_color_params *color_params, int flags)
+{
+ color_params->ri = (flags >> RI) & 3;
+ color_params->bp = (flags >> BP) & 1;
+ color_params->op = (flags >> OP) & 1;
+ color_params->opm = (flags >> OPM) & 1;
+}
+
static void
fz_list_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_rect rect;
@@ -639,7 +669,7 @@ fz_list_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even
ctx,
dev,
FZ_CMD_FILL_PATH,
- even_odd, /* flags */
+ even_odd | fz_pack_color_params(color_params), /* flags */
&rect,
path, /* path */
color,
@@ -653,7 +683,7 @@ fz_list_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even
static void
fz_list_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke,
- const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha)
+ const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_rect rect;
@@ -662,7 +692,7 @@ fz_list_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const
ctx,
dev,
FZ_CMD_STROKE_PATH,
- 0, /* flags */
+ fz_pack_color_params(color_params), /* flags */
&rect,
path, /* path */
color,
@@ -724,7 +754,7 @@ fz_list_clip_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, c
static void
fz_list_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_rect rect;
fz_text *cloned_text = fz_keep_text(ctx, text);
@@ -736,7 +766,7 @@ fz_list_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz
ctx,
dev,
FZ_CMD_FILL_TEXT,
- 0, /* flags */
+ fz_pack_color_params(color_params), /* flags */
&rect,
NULL, /* path */
color, /* color */
@@ -756,7 +786,7 @@ fz_list_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz
static void
fz_list_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_rect rect;
fz_text *cloned_text = fz_keep_text(ctx, text);
@@ -768,7 +798,7 @@ fz_list_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const
ctx,
dev,
FZ_CMD_STROKE_TEXT,
- 0, /* flags */
+ fz_pack_color_params(color_params), /* flags */
&rect,
NULL, /* path */
color, /* color */
@@ -903,7 +933,7 @@ fz_list_pop_clip(fz_context *ctx, fz_device *dev)
}
static void
-fz_list_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha)
+fz_list_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha, const fz_color_params *color_params)
{
fz_shade *shade2 = fz_keep_shade(ctx, shade);
fz_rect rect;
@@ -915,7 +945,7 @@ fz_list_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_ma
ctx,
dev,
FZ_CMD_FILL_SHADE,
- 0, /* flags */
+ fz_pack_color_params(color_params), /* flags */
&rect,
NULL, /* path */
NULL, /* color */
@@ -934,7 +964,7 @@ fz_list_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_ma
}
static void
-fz_list_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha)
+fz_list_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha, const fz_color_params *color_params)
{
fz_image *image2 = fz_keep_image(ctx, image);
fz_rect rect = fz_unit_rect;
@@ -946,7 +976,7 @@ fz_list_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_ma
ctx,
dev,
FZ_CMD_FILL_IMAGE,
- 0, /* flags */
+ fz_pack_color_params(color_params), /* flags */
&rect,
NULL, /* path */
NULL, /* color */
@@ -966,7 +996,7 @@ fz_list_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_ma
static void
fz_list_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_image *image2 = fz_keep_image(ctx, image);
fz_rect rect = fz_unit_rect;
@@ -978,7 +1008,7 @@ fz_list_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const
ctx,
dev,
FZ_CMD_FILL_IMAGE_MASK,
- 0, /* flags */
+ fz_pack_color_params(color_params), /* flags */
&rect,
NULL, /* path */
color,
@@ -1030,13 +1060,13 @@ fz_list_clip_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const
}
static void
-fz_list_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *rect, int luminosity, fz_colorspace *colorspace, const float *color)
+fz_list_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *rect, int luminosity, fz_colorspace *colorspace, const float *color, const fz_color_params *color_params)
{
fz_append_display_node(
ctx,
dev,
FZ_CMD_BEGIN_MASK,
- luminosity, /* flags */
+ (!!luminosity) | fz_pack_color_params(color_params), /* flags */
rect,
NULL, /* path */
color,
@@ -1198,6 +1228,27 @@ fz_list_render_flags(fz_context *ctx, fz_device *dev, int set, int clear)
}
static void
+fz_list_set_default_colorspaces(fz_context *ctx, fz_device *dev, fz_default_colorspaces *default_cs)
+{
+ fz_default_colorspaces *default_cs2 = fz_keep_default_colorspaces(ctx, default_cs);
+
+ fz_append_display_node(
+ ctx,
+ dev,
+ FZ_CMD_DEFAULT_COLORSPACES,
+ 0, /* flags */
+ NULL,
+ NULL, /* path */
+ NULL, /* color */
+ NULL, /* colorspace */
+ NULL, /* alpha */
+ NULL, /* ctm */
+ NULL, /* stroke */
+ &default_cs2, /* private_data */
+ sizeof(default_cs2)); /* private_data_len */
+}
+
+static void
fz_list_drop_device(fz_context *ctx, fz_device *dev)
{
fz_list_device *writer = (fz_list_device *)dev;
@@ -1241,6 +1292,7 @@ fz_new_list_device(fz_context *ctx, fz_display_list *list)
dev->super.end_tile = fz_list_end_tile;
dev->super.render_flags = fz_list_render_flags;
+ dev->super.set_default_colorspaces = fz_list_set_default_colorspaces;
dev->super.drop_device = fz_list_drop_device;
@@ -1342,8 +1394,10 @@ fz_drop_display_list_imp(fz_context *ctx, fz_storable *list_)
case FZ_CMD_CLIP_IMAGE_MASK:
fz_drop_image(ctx, *(fz_image **)node);
break;
+ case FZ_CMD_DEFAULT_COLORSPACES:
+ fz_drop_default_colorspaces(ctx, *(fz_default_colorspaces **)node);
+ break;
}
-
node = next;
}
fz_free(ctx, list->list);
@@ -1405,6 +1459,7 @@ fz_run_display_list(fz_context *ctx, fz_display_list *list, fz_device *dev, cons
fz_stroke_state *stroke = NULL;
float color[FZ_MAX_COLORS] = { 0 };
fz_colorspace *colorspace = fz_device_gray(ctx);
+ fz_color_params color_params;
fz_rect rect = { 0 };
/* Transformed versions of graphic state entries */
@@ -1423,6 +1478,8 @@ fz_run_display_list(fz_context *ctx, fz_display_list *list, fz_device *dev, cons
cookie->progress = 0;
}
+ color_params = *fz_default_color_params(ctx);
+
node = list->list;
node_end = &list->list[list->len];
for (; node != node_end ; node = next_node)
@@ -1455,34 +1512,34 @@ fz_run_display_list(fz_context *ctx, fz_display_list *list, fz_device *dev, cons
{
default:
case CS_GRAY_0:
- colorspace = fz_device_gray(ctx);
+ colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx));
color[0] = 0.0f;
break;
case CS_GRAY_1:
- colorspace = fz_device_gray(ctx);
+ colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx));
color[0] = 1.0f;
break;
case CS_RGB_0:
- colorspace = fz_device_rgb(ctx);
+ colorspace = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
color[0] = 0.0f;
color[1] = 0.0f;
color[2] = 0.0f;
break;
case CS_RGB_1:
- colorspace = fz_device_rgb(ctx);
+ colorspace = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
color[0] = 1.0f;
color[1] = 1.0f;
color[2] = 1.0f;
break;
case CS_CMYK_0:
- colorspace = fz_device_cmyk(ctx);
+ colorspace = fz_keep_colorspace(ctx, fz_device_cmyk(ctx));
color[0] = 0.0f;
color[1] = 0.0f;
color[2] = 0.0f;
color[3] = 0.0f;
break;
case CS_CMYK_1:
- colorspace = fz_device_cmyk(ctx);
+ colorspace = fz_keep_colorspace(ctx, fz_device_cmyk(ctx));
color[0] = 0.0f;
color[1] = 0.0f;
color[2] = 0.0f;
@@ -1572,7 +1629,7 @@ fz_run_display_list(fz_context *ctx, fz_display_list *list, fz_device *dev, cons
if (tiled ||
n.cmd == FZ_CMD_BEGIN_TILE || n.cmd == FZ_CMD_END_TILE ||
- n.cmd == FZ_CMD_RENDER_FLAGS)
+ n.cmd == FZ_CMD_RENDER_FLAGS || n.cmd == FZ_CMD_DEFAULT_COLORSPACES)
{
empty = 0;
}
@@ -1619,10 +1676,12 @@ visible:
switch (n.cmd)
{
case FZ_CMD_FILL_PATH:
- fz_fill_path(ctx, dev, path, n.flags, &trans_ctm, colorspace, color, alpha);
+ fz_unpack_color_params(&color_params, n.flags);
+ fz_fill_path(ctx, dev, path, n.flags & 1, &trans_ctm, colorspace, color, alpha, &color_params);
break;
case FZ_CMD_STROKE_PATH:
- fz_stroke_path(ctx, dev, path, stroke, &trans_ctm, colorspace, color, alpha);
+ fz_unpack_color_params(&color_params, n.flags);
+ fz_stroke_path(ctx, dev, path, stroke, &trans_ctm, colorspace, color, alpha, &color_params);
break;
case FZ_CMD_CLIP_PATH:
fz_clip_path(ctx, dev, path, n.flags, &trans_ctm, &trans_rect);
@@ -1631,10 +1690,12 @@ visible:
fz_clip_stroke_path(ctx, dev, path, stroke, &trans_ctm, &trans_rect);
break;
case FZ_CMD_FILL_TEXT:
- fz_fill_text(ctx, dev, *(fz_text **)node, &trans_ctm, colorspace, color, alpha);
+ fz_unpack_color_params(&color_params, n.flags);
+ fz_fill_text(ctx, dev, *(fz_text **)node, &trans_ctm, colorspace, color, alpha, &color_params);
break;
case FZ_CMD_STROKE_TEXT:
- fz_stroke_text(ctx, dev, *(fz_text **)node, stroke, &trans_ctm, colorspace, color, alpha);
+ fz_unpack_color_params(&color_params, n.flags);
+ fz_stroke_text(ctx, dev, *(fz_text **)node, stroke, &trans_ctm, colorspace, color, alpha, &color_params);
break;
case FZ_CMD_CLIP_TEXT:
fz_clip_text(ctx, dev, *(fz_text **)node, &trans_ctm, &trans_rect);
@@ -1646,13 +1707,16 @@ visible:
fz_ignore_text(ctx, dev, *(fz_text **)node, &trans_ctm);
break;
case FZ_CMD_FILL_SHADE:
- fz_fill_shade(ctx, dev, *(fz_shade **)node, &trans_ctm, alpha);
+ fz_unpack_color_params(&color_params, n.flags);
+ fz_fill_shade(ctx, dev, *(fz_shade **)node, &trans_ctm, alpha, &color_params);
break;
case FZ_CMD_FILL_IMAGE:
- fz_fill_image(ctx, dev, *(fz_image **)node, &trans_ctm, alpha);
+ fz_unpack_color_params(&color_params, n.flags);
+ fz_fill_image(ctx, dev, *(fz_image **)node, &trans_ctm, alpha, &color_params);
break;
case FZ_CMD_FILL_IMAGE_MASK:
- fz_fill_image_mask(ctx, dev, *(fz_image **)node, &trans_ctm, colorspace, color, alpha);
+ fz_unpack_color_params(&color_params, n.flags);
+ fz_fill_image_mask(ctx, dev, *(fz_image **)node, &trans_ctm, colorspace, color, alpha, &color_params);
break;
case FZ_CMD_CLIP_IMAGE_MASK:
fz_clip_image_mask(ctx, dev, *(fz_image **)node, &trans_ctm, &trans_rect);
@@ -1661,7 +1725,8 @@ visible:
fz_pop_clip(ctx, dev);
break;
case FZ_CMD_BEGIN_MASK:
- fz_begin_mask(ctx, dev, &trans_rect, n.flags, colorspace, color);
+ fz_unpack_color_params(&color_params, n.flags);
+ fz_begin_mask(ctx, dev, &trans_rect, n.flags, colorspace, color, &color_params);
break;
case FZ_CMD_END_MASK:
fz_end_mask(ctx, dev);
@@ -1694,6 +1759,9 @@ visible:
else if (n.flags == 1)
fz_render_flags(ctx, dev, FZ_DEVFLAG_GRIDFIT_AS_TILED, 0);
break;
+ case FZ_CMD_DEFAULT_COLORSPACES:
+ fz_set_default_colorspaces(ctx, dev, *(fz_default_colorspaces **)node);
+ break;
}
}
fz_catch(ctx)
diff --git a/source/fitz/output-cbz.c b/source/fitz/output-cbz.c
index c7ab5805..55c28e77 100644
--- a/source/fitz/output-cbz.c
+++ b/source/fitz/output-cbz.c
@@ -40,7 +40,7 @@ cbz_end_page(fz_context *ctx, fz_document_writer *wri_, fz_device *dev)
fz_snprintf(name, sizeof name, "p%04d.png", wri->count);
- buffer = fz_new_buffer_from_pixmap_as_png(ctx, wri->pixmap);
+ buffer = fz_new_buffer_from_pixmap_as_png(ctx, wri->pixmap, NULL);
fz_try(ctx)
fz_write_zip_entry(ctx, wri->zip, name, buffer, 0);
fz_always(ctx)
diff --git a/source/fitz/output-pcl.c b/source/fitz/output-pcl.c
index 2c680f8f..7f676cf5 100644
--- a/source/fitz/output-pcl.c
+++ b/source/fitz/output-pcl.c
@@ -691,7 +691,7 @@ fz_write_pixmap_as_pcl(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap,
writer = fz_new_color_pcl_band_writer(ctx, out, pcl);
fz_try(ctx)
{
- fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0);
+ fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0, pixmap->colorspace);
fz_write_band(ctx, writer, pixmap->stride, pixmap->h, pixmap->samples);
}
fz_always(ctx)
@@ -713,7 +713,7 @@ typedef struct color_pcl_band_writer_s
} color_pcl_band_writer;
static void
-color_pcl_write_header(fz_context *ctx, fz_band_writer *writer_)
+color_pcl_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colorspace *cs)
{
color_pcl_band_writer *writer = (color_pcl_band_writer *)writer_;
fz_output *out = writer->super.out;
@@ -1078,7 +1078,7 @@ fz_write_bitmap_as_pcl(fz_context *ctx, fz_output *out, const fz_bitmap *bitmap,
writer = fz_new_mono_pcl_band_writer(ctx, out, pcl);
fz_try(ctx)
{
- fz_write_header(ctx, writer, bitmap->w, bitmap->h, 1, 0, bitmap->xres, bitmap->yres, 0);
+ fz_write_header(ctx, writer, bitmap->w, bitmap->h, 1, 0, bitmap->xres, bitmap->yres, 0, NULL);
fz_write_band(ctx, writer, bitmap->stride, bitmap->h, bitmap->samples);
}
fz_always(ctx)
@@ -1099,7 +1099,7 @@ typedef struct mono_pcl_band_writer_s
} mono_pcl_band_writer;
static void
-mono_pcl_write_header(fz_context *ctx, fz_band_writer *writer_)
+mono_pcl_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colorspace *cs)
{
mono_pcl_band_writer *writer = (mono_pcl_band_writer *)writer_;
fz_output *out = writer->super.out;
diff --git a/source/fitz/output-png.c b/source/fitz/output-png.c
index c8972b25..4a325959 100644
--- a/source/fitz/output-png.c
+++ b/source/fitz/output-png.c
@@ -33,7 +33,7 @@ fz_save_pixmap_as_png(fz_context *ctx, fz_pixmap *pixmap, const char *filename)
fz_try(ctx)
{
writer = fz_new_png_band_writer(ctx, out);
- fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0);
+ fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0, pixmap->colorspace);
fz_write_band(ctx, writer, pixmap->stride, pixmap->h, pixmap->samples);
}
fz_always(ctx)
@@ -59,7 +59,7 @@ fz_write_pixmap_as_png(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap)
fz_try(ctx)
{
- fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0);
+ fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0, pixmap->colorspace);
fz_write_band(ctx, writer, pixmap->stride, pixmap->h, pixmap->samples);
}
fz_always(ctx)
@@ -82,7 +82,59 @@ typedef struct png_band_writer_s
} png_band_writer;
static void
-png_write_header(fz_context *ctx, fz_band_writer *writer_)
+png_write_icc(fz_context *ctx, png_band_writer *writer, const fz_colorspace *cs)
+{
+ fz_output *out = writer->super.out;
+ int size;
+ fz_buffer *buffer = fz_icc_data_from_icc_colorspace(ctx, cs);
+ unsigned char *data;
+ unsigned char *chunk, *pos, *cdata;
+ uLong bound;
+ uLongf csize;
+ uLong long_size;
+ int t;
+
+ long_size = (uLong)fz_buffer_storage(ctx, buffer, &data);
+
+ if (!data)
+ return;
+
+ /* Deflate the profile */
+ bound = compressBound(long_size);
+ cdata = fz_malloc(ctx, bound);
+ csize = (uLongf)bound;
+ t = compress(cdata, &csize, data, long_size);
+ if (t != Z_OK)
+ {
+ fz_free(ctx, cdata);
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot deflate icc buffer");
+ }
+ size = csize + strlen("MuPDF Profile") + 2;
+
+ fz_var(cdata);
+
+ fz_try(ctx)
+ {
+ chunk = fz_calloc(ctx, size, 1);
+ pos = chunk;
+ memcpy(chunk, "MuPDF Profile", strlen("MuPDF Profile"));
+ pos += strlen("MuPDF Profile") + 2;
+ memcpy(pos, cdata, csize);
+ putchunk(ctx, out, "iCCP", chunk, size);
+ }
+ fz_always(ctx)
+ {
+ fz_free(ctx, cdata);
+ fz_free(ctx, chunk);
+ }
+ fz_catch(ctx)
+ {
+ /* Nothing */
+ }
+}
+
+static void
+png_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colorspace *cs)
{
png_band_writer *writer = (png_band_writer *)(void *)writer_;
fz_output *out = writer->super.out;
@@ -116,6 +168,8 @@ png_write_header(fz_context *ctx, fz_band_writer *writer_)
fz_write_data(ctx, out, pngsig, 8);
putchunk(ctx, out, "IHDR", head, 13);
+
+ png_write_icc(ctx, writer, cs);
}
static void
@@ -240,7 +294,7 @@ fz_band_writer *fz_new_png_band_writer(fz_context *ctx, fz_output *out)
* drop pix early in the case where we have to convert, potentially saving
* us having to have 2 copies of the pixmap and a buffer open at once. */
static fz_buffer *
-png_from_pixmap(fz_context *ctx, fz_pixmap *pix, int drop)
+png_from_pixmap(fz_context *ctx, fz_pixmap *pix, const fz_color_params *color_params, int drop)
{
fz_buffer *buf = NULL;
fz_output *out;
@@ -253,11 +307,14 @@ png_from_pixmap(fz_context *ctx, fz_pixmap *pix, int drop)
if (pix->w == 0 || pix->h == 0)
return NULL;
+ if (color_params == NULL)
+ color_params = fz_default_color_params(ctx);
+
fz_try(ctx)
{
if (pix->colorspace && pix->colorspace != fz_device_gray(ctx) && pix->colorspace != fz_device_rgb(ctx))
{
- pix2 = fz_convert_pixmap(ctx, pix, fz_device_rgb(ctx), 1);
+ pix2 = fz_convert_pixmap(ctx, pix, fz_device_rgb(ctx), NULL, NULL, color_params, 1);
if (drop)
fz_drop_pixmap(ctx, pix);
pix = pix2;
@@ -280,22 +337,20 @@ png_from_pixmap(fz_context *ctx, fz_pixmap *pix, int drop)
}
fz_buffer *
-fz_new_buffer_from_image_as_png(fz_context *ctx, fz_image *image)
+fz_new_buffer_from_image_as_png(fz_context *ctx, fz_image *image, const fz_color_params *color_params)
{
fz_pixmap *pix = fz_get_pixmap_from_image(ctx, image, NULL, NULL, NULL, NULL);
- fz_buffer *buf = NULL;
-
- fz_var(buf);
+ fz_buffer *buf;
fz_try(ctx)
- buf = png_from_pixmap(ctx, pix, 1);
+ buf = png_from_pixmap(ctx, pix, color_params, 1);
fz_catch(ctx)
fz_rethrow(ctx);
return buf;
}
fz_buffer *
-fz_new_buffer_from_pixmap_as_png(fz_context *ctx, fz_pixmap *pix)
+fz_new_buffer_from_pixmap_as_png(fz_context *ctx, fz_pixmap *pix, const fz_color_params *color_params)
{
- return png_from_pixmap(ctx, pix, 0);
+ return png_from_pixmap(ctx, pix, color_params, 0);
}
diff --git a/source/fitz/output-pnm.c b/source/fitz/output-pnm.c
index 455a5358..496d8ea0 100644
--- a/source/fitz/output-pnm.c
+++ b/source/fitz/output-pnm.c
@@ -4,7 +4,7 @@
* Write pixmap to PNM file (without alpha channel)
*/
static void
-pnm_write_header(fz_context *ctx, fz_band_writer *writer)
+pnm_write_header(fz_context *ctx, fz_band_writer *writer, const fz_colorspace *cs)
{
fz_output *out = writer->out;
int w = writer->w;
@@ -123,7 +123,7 @@ void
fz_write_pixmap_as_pnm(fz_context *ctx, fz_output *out, fz_pixmap *pixmap)
{
fz_band_writer *writer = fz_new_pnm_band_writer(ctx, out);
- fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, 0, 0, 0);
+ fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, 0, 0, 0, pixmap->colorspace);
fz_write_band(ctx, writer, pixmap->stride, pixmap->h, pixmap->samples);
fz_drop_band_writer(ctx, writer);
}
@@ -139,7 +139,7 @@ fz_save_pixmap_as_pnm(fz_context *ctx, fz_pixmap *pixmap, const char *filename)
fz_try(ctx)
{
writer = fz_new_pnm_band_writer(ctx, out);
- fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, 0, 0, 0);
+ fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, 0, 0, 0, pixmap->colorspace);
fz_write_band(ctx, writer, pixmap->stride, pixmap->h, pixmap->samples);
}
fz_always(ctx)
@@ -156,7 +156,7 @@ fz_save_pixmap_as_pnm(fz_context *ctx, fz_pixmap *pixmap, const char *filename)
*/
static void
-pam_write_header(fz_context *ctx, fz_band_writer *writer)
+pam_write_header(fz_context *ctx, fz_band_writer *writer, const fz_colorspace *cs)
{
fz_output *out = writer->out;
int w = writer->w;
@@ -220,7 +220,7 @@ void
fz_write_pixmap_as_pam(fz_context *ctx, fz_output *out, fz_pixmap *pixmap)
{
fz_band_writer *writer = fz_new_pam_band_writer(ctx, out);
- fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, 0, 0, 0);
+ fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, 0, 0, 0, pixmap->colorspace);
fz_write_band(ctx, writer, pixmap->stride, pixmap->h, pixmap->samples);
fz_drop_band_writer(ctx, writer);
}
@@ -236,7 +236,7 @@ fz_save_pixmap_as_pam(fz_context *ctx, fz_pixmap *pixmap, const char *filename)
fz_try(ctx)
{
writer = fz_new_pam_band_writer(ctx, out);
- fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, 0, 0, 0);
+ fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, 0, 0, 0, pixmap->colorspace);
fz_write_band(ctx, writer, pixmap->stride, pixmap->h, pixmap->samples);
}
fz_always(ctx)
diff --git a/source/fitz/output-ps.c b/source/fitz/output-ps.c
index 90be4367..a3d354ad 100644
--- a/source/fitz/output-ps.c
+++ b/source/fitz/output-ps.c
@@ -41,7 +41,7 @@ void fz_write_ps_file_trailer(fz_context *ctx, fz_output *out, int pages)
}
static void
-ps_write_header(fz_context *ctx, fz_band_writer *writer_)
+ps_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colorspace *cs)
{
ps_band_writer *writer = (ps_band_writer *)writer_;
fz_output *out = writer->super.out;
@@ -147,7 +147,7 @@ void fz_write_pixmap_as_ps(fz_context *ctx, fz_output *out, const fz_pixmap *pix
fz_try(ctx)
{
- fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0);
+ fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0, pixmap->colorspace);
fz_write_band(ctx, writer, pixmap->stride, pixmap->h, pixmap->samples);
}
fz_always(ctx)
diff --git a/source/fitz/output-pwg.c b/source/fitz/output-pwg.c
index 1b5f3812..f36c3a2b 100644
--- a/source/fitz/output-pwg.c
+++ b/source/fitz/output-pwg.c
@@ -102,7 +102,7 @@ fz_write_pixmap_as_pwg_page(fz_context *ctx, fz_output *out, const fz_pixmap *pi
fz_try(ctx)
{
- fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0);
+ fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0, pixmap->colorspace);
fz_write_band(ctx, writer, pixmap->stride, pixmap->h, pixmap->samples);
}
fz_always(ctx)
@@ -118,7 +118,7 @@ fz_write_bitmap_as_pwg_page(fz_context *ctx, fz_output *out, const fz_bitmap *bi
fz_try(ctx)
{
- fz_write_header(ctx, writer, bitmap->w, bitmap->h, bitmap->n, 0, bitmap->xres, bitmap->yres, 0);
+ fz_write_header(ctx, writer, bitmap->w, bitmap->h, bitmap->n, 0, bitmap->xres, bitmap->yres, 0, NULL);
fz_write_band(ctx, writer, bitmap->stride, bitmap->h, bitmap->samples);
}
fz_always(ctx)
@@ -174,7 +174,7 @@ fz_save_bitmap_as_pwg(fz_context *ctx, fz_bitmap *bitmap, char *filename, int ap
}
static void
-pwg_write_mono_header(fz_context *ctx, fz_band_writer *writer_)
+pwg_write_mono_header(fz_context *ctx, fz_band_writer *writer_, const fz_colorspace *cs)
{
pwg_band_writer *writer = (pwg_band_writer *)writer_;
@@ -272,7 +272,7 @@ fz_band_writer *fz_new_mono_pwg_band_writer(fz_context *ctx, fz_output *out, con
}
static void
-pwg_write_header(fz_context *ctx, fz_band_writer *writer_)
+pwg_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colorspace *cs)
{
pwg_band_writer *writer = (pwg_band_writer *)writer_;
int n = writer->super.n;
diff --git a/source/fitz/output-tga.c b/source/fitz/output-tga.c
index 712f82fe..f576dd74 100644
--- a/source/fitz/output-tga.c
+++ b/source/fitz/output-tga.c
@@ -69,7 +69,7 @@ fz_write_pixmap_as_tga(fz_context *ctx, fz_output *out, fz_pixmap *pixmap)
fz_try(ctx)
{
- fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0);
+ fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0, pixmap->colorspace);
fz_write_band(ctx, writer, -pixmap->stride, pixmap->h, pixmap->samples + pixmap->stride * (pixmap->h-1));
}
fz_always(ctx)
@@ -79,7 +79,7 @@ fz_write_pixmap_as_tga(fz_context *ctx, fz_output *out, fz_pixmap *pixmap)
}
static void
-tga_write_header(fz_context *ctx, fz_band_writer *writer_)
+tga_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colorspace *cs)
{
tga_band_writer *writer = (tga_band_writer *)writer_;
fz_output *out = writer->super.out;
diff --git a/source/fitz/output.c b/source/fitz/output.c
index cbcc4209..3240be12 100644
--- a/source/fitz/output.c
+++ b/source/fitz/output.c
@@ -392,7 +392,7 @@ fz_band_writer *fz_new_band_writer_of_size(fz_context *ctx, size_t size, fz_outp
return writer;
}
-void fz_write_header(fz_context *ctx, fz_band_writer *writer, int w, int h, int n, int alpha, int xres, int yres, int pagenum)
+void fz_write_header(fz_context *ctx, fz_band_writer *writer, int w, int h, int n, int alpha, int xres, int yres, int pagenum, const fz_colorspace *cs)
{
if (writer == NULL || writer->band == NULL)
return;
@@ -404,7 +404,7 @@ void fz_write_header(fz_context *ctx, fz_band_writer *writer, int w, int h, int
writer->yres = yres;
writer->pagenum = pagenum;
writer->line = 0;
- writer->header(ctx, writer);
+ writer->header(ctx, writer, cs);
}
void fz_write_band(fz_context *ctx, fz_band_writer *writer, int stride, int band_height, const unsigned char *samples)
diff --git a/source/fitz/pixmap.c b/source/fitz/pixmap.c
index ab7d068f..d89889fd 100644
--- a/source/fitz/pixmap.c
+++ b/source/fitz/pixmap.c
@@ -722,7 +722,7 @@ fz_ensure_pixmap_is_additive(fz_context *ctx, fz_pixmap *pix)
{
if (fz_colorspace_is_subtractive(ctx, pix->colorspace))
{
- fz_pixmap *rgb = fz_convert_pixmap(ctx, pix, fz_device_rgb(ctx), 1);
+ fz_pixmap *rgb = fz_convert_pixmap(ctx, pix, fz_device_rgb(ctx), NULL, NULL, NULL/* FIXME */, 1);
fz_drop_pixmap(ctx, pix);
return rgb;
}
@@ -881,13 +881,16 @@ fz_pixmap_size(fz_context *ctx, fz_pixmap * pix)
}
fz_pixmap *
-fz_convert_pixmap(fz_context *ctx, fz_pixmap *pix, fz_colorspace *ds, int keep_alpha)
+fz_convert_pixmap(fz_context *ctx, fz_pixmap *pix, fz_colorspace *ds, fz_colorspace *prf, fz_default_colorspaces *default_cs, const fz_color_params *color_params, int keep_alpha)
{
fz_pixmap *cvt;
if (!ds && !keep_alpha)
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot both throw away and keep alpha");
+ if (color_params == NULL)
+ color_params = fz_default_color_params(ctx);
+
cvt = fz_new_pixmap(ctx, ds, pix->w, pix->h, keep_alpha && pix->alpha);
cvt->xres = pix->xres;
@@ -899,7 +902,7 @@ fz_convert_pixmap(fz_context *ctx, fz_pixmap *pix, fz_colorspace *ds, int keep_a
fz_try(ctx)
{
fz_pixmap_converter *pc = fz_lookup_pixmap_converter(ctx, ds, pix->colorspace);
- pc(ctx, cvt, pix);
+ pc(ctx, cvt, pix, prf, default_cs, color_params);
}
fz_catch(ctx)
{
diff --git a/source/fitz/stext-device.c b/source/fitz/stext-device.c
index 0213a945..f942babe 100644
--- a/source/fitz/stext-device.c
+++ b/source/fitz/stext-device.c
@@ -867,7 +867,7 @@ fz_stext_extract(fz_context *ctx, fz_stext_device *dev, fz_text_span *span, cons
static void
fz_stext_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_stext_device *tdev = (fz_stext_device*)dev;
fz_stext_style *style;
@@ -881,7 +881,7 @@ fz_stext_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const f
static void
fz_stext_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_stext_device *tdev = (fz_stext_device*)dev;
fz_stext_style *style;
@@ -934,7 +934,7 @@ fz_stext_ignore_text(fz_context *ctx, fz_device *dev, const fz_text *text, const
static void
fz_stext_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *img, const fz_matrix *ctm,
- fz_colorspace *cspace, const float *color, float alpha)
+ fz_colorspace *cspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_stext_device *tdev = (fz_stext_device*)dev;
fz_stext_page *page = tdev->page;
@@ -969,9 +969,9 @@ fz_stext_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *img, const f
}
static void
-fz_stext_fill_image(fz_context *ctx, fz_device *dev, fz_image *img, const fz_matrix *ctm, float alpha)
+fz_stext_fill_image(fz_context *ctx, fz_device *dev, fz_image *img, const fz_matrix *ctm, float alpha, const fz_color_params *color_params)
{
- fz_stext_fill_image_mask(ctx, dev, img, ctm, NULL, NULL, alpha);
+ fz_stext_fill_image_mask(ctx, dev, img, ctm, NULL, NULL, alpha, color_params);
}
static int
diff --git a/source/fitz/stext-output.c b/source/fitz/stext-output.c
index 49ef2ea5..a247fc8d 100644
--- a/source/fitz/stext-output.c
+++ b/source/fitz/stext-output.c
@@ -240,7 +240,7 @@ fz_print_stext_page_html(fz_context *ctx, fz_output *out, fz_stext_page *page)
break;
default:
{
- fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, image->image);
+ fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, image->image, NULL);
fz_write_printf(ctx, out, "image/png;base64,");
send_data_base64_stext(ctx, out, buf);
fz_drop_buffer(ctx, buf);
diff --git a/source/fitz/svg-device.c b/source/fitz/svg-device.c
index 7c6c8826..1bd6987f 100644
--- a/source/fitz/svg-device.c
+++ b/source/fitz/svg-device.c
@@ -200,14 +200,14 @@ svg_dev_stroke_state(fz_context *ctx, svg_device *sdev, const fz_stroke_state *s
}
static unsigned int
-svg_hex_color(fz_context *ctx, fz_colorspace *colorspace, const float *color)
+svg_hex_color(fz_context *ctx, fz_colorspace *colorspace, const float *color, const fz_color_params *color_params)
{
float rgb[3];
int r, g, b;
if (colorspace != fz_device_rgb(ctx))
{
- fz_convert_color(ctx, fz_device_rgb(ctx), rgb, colorspace, color);
+ fz_convert_color(ctx, color_params, NULL, fz_device_rgb(ctx), rgb, colorspace, color);
color = rgb;
}
@@ -219,12 +219,12 @@ svg_hex_color(fz_context *ctx, fz_colorspace *colorspace, const float *color)
}
static void
-svg_dev_fill_color(fz_context *ctx, svg_device *sdev, fz_colorspace *colorspace, const float *color, float alpha)
+svg_dev_fill_color(fz_context *ctx, svg_device *sdev, fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_output *out = sdev->out;
if (colorspace)
{
- int rgb = svg_hex_color(ctx, colorspace, color);
+ int rgb = svg_hex_color(ctx, colorspace, color, color_params);
if (rgb != 0) /* black is the default value */
fz_write_printf(ctx, out, " fill=\"#%06x\"", rgb);
}
@@ -235,11 +235,11 @@ svg_dev_fill_color(fz_context *ctx, svg_device *sdev, fz_colorspace *colorspace,
}
static void
-svg_dev_stroke_color(fz_context *ctx, svg_device *sdev, fz_colorspace *colorspace, const float *color, float alpha)
+svg_dev_stroke_color(fz_context *ctx, svg_device *sdev, fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_output *out = sdev->out;
if (colorspace)
- fz_write_printf(ctx, out, " fill=\"none\" stroke=\"#%06x\"", svg_hex_color(ctx, colorspace, color));
+ fz_write_printf(ctx, out, " fill=\"none\" stroke=\"#%06x\"", svg_hex_color(ctx, colorspace, color, color_params));
else
fz_write_printf(ctx, out, " fill=\"none\" stroke=\"none\"");
if (alpha != 1)
@@ -505,7 +505,7 @@ svg_dev_text_span_as_paths_defs(fz_context *ctx, fz_device *dev, fz_text_span *s
static void
svg_dev_text_span_as_paths_fill(fz_context *ctx, fz_device *dev, const fz_text_span *span, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha, font *fnt)
+ fz_colorspace *colorspace, const float *color, float alpha, font *fnt, const fz_color_params *color_params)
{
svg_device *sdev = (svg_device*)dev;
fz_output *out = sdev->out;
@@ -538,7 +538,7 @@ svg_dev_text_span_as_paths_fill(fz_context *ctx, fz_device *dev, const fz_text_s
fz_concat(&local_trm2, &shift, &local_trm2);
fz_write_printf(ctx, out, "<use xlink:href=\"#font_%x_%x\"", fnt->id, gid);
svg_dev_ctm(ctx, sdev, &local_trm2);
- svg_dev_fill_color(ctx, sdev, colorspace, color, alpha);
+ svg_dev_fill_color(ctx, sdev, colorspace, color, alpha, color_params);
fz_write_printf(ctx, out, "/>\n");
}
}
@@ -546,7 +546,7 @@ svg_dev_text_span_as_paths_fill(fz_context *ctx, fz_device *dev, const fz_text_s
static void
svg_dev_text_span_as_paths_stroke(fz_context *ctx, fz_device *dev, const fz_text_span *span,
const fz_stroke_state *stroke, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha, font *fnt)
+ fz_colorspace *colorspace, const float *color, float alpha, font *fnt, const fz_color_params *color_params)
{
svg_device *sdev = (svg_device*)dev;
fz_output *out = sdev->out;
@@ -579,7 +579,7 @@ svg_dev_text_span_as_paths_stroke(fz_context *ctx, fz_device *dev, const fz_text
fz_write_printf(ctx, out, "<use xlink:href=\"#font_%x_%x\"", fnt->id, gid);
svg_dev_stroke_state(ctx, sdev, stroke, &local_trm2);
svg_dev_ctm(ctx, sdev, &local_trm2);
- svg_dev_stroke_color(ctx, sdev, colorspace, color, alpha);
+ svg_dev_stroke_color(ctx, sdev, colorspace, color, alpha, color_params);
fz_write_printf(ctx, out, "/>\n");
}
}
@@ -588,7 +588,7 @@ svg_dev_text_span_as_paths_stroke(fz_context *ctx, fz_device *dev, const fz_text
static void
svg_dev_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
svg_device *sdev = (svg_device*)dev;
fz_output *out = sdev->out;
@@ -596,7 +596,7 @@ svg_dev_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even
fz_write_printf(ctx, out, "<path");
svg_dev_ctm(ctx, sdev, ctm);
svg_dev_path(ctx, sdev, path);
- svg_dev_fill_color(ctx, sdev, colorspace, color, alpha);
+ svg_dev_fill_color(ctx, sdev, colorspace, color, alpha, color_params);
if (even_odd)
fz_write_printf(ctx, out, " fill-rule=\"evenodd\"");
fz_write_printf(ctx, out, "/>\n");
@@ -604,7 +604,7 @@ svg_dev_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even
static void
svg_dev_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
svg_device *sdev = (svg_device*)dev;
fz_output *out = sdev->out;
@@ -612,7 +612,7 @@ svg_dev_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const
fz_write_printf(ctx, out, "<path");
svg_dev_ctm(ctx, sdev, ctm);
svg_dev_stroke_state(ctx, sdev, stroke, &fz_identity);
- svg_dev_stroke_color(ctx, sdev, colorspace, color, alpha);
+ svg_dev_stroke_color(ctx, sdev, colorspace, color, alpha, color_params);
svg_dev_path(ctx, sdev, path);
fz_write_printf(ctx, out, "/>\n");
}
@@ -655,7 +655,7 @@ svg_dev_clip_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, c
fz_write_printf(ctx, out, "<path");
svg_dev_ctm(ctx, sdev, ctm);
svg_dev_stroke_state(ctx, sdev, stroke, &fz_identity);
- svg_dev_stroke_color(ctx, sdev, fz_device_rgb(ctx), white, 1);
+ svg_dev_stroke_color(ctx, sdev, fz_device_rgb(ctx), white, 1, NULL);
svg_dev_path(ctx, sdev, path);
fz_write_printf(ctx, out, "/>\n</mask>\n");
out = end_def(ctx, sdev);
@@ -664,7 +664,7 @@ svg_dev_clip_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, c
static void
svg_dev_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
svg_device *sdev = (svg_device*)dev;
fz_output *out = sdev->out;
@@ -676,7 +676,7 @@ svg_dev_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz
for (span = text->head; span; span = span->next)
{
fz_write_printf(ctx, out, "<text");
- svg_dev_fill_color(ctx, sdev, colorspace, color, alpha);
+ svg_dev_fill_color(ctx, sdev, colorspace, color, alpha, color_params);
svg_dev_text_span(ctx, sdev, ctm, span);
}
}
@@ -685,14 +685,14 @@ svg_dev_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz
for (span = text->head; span; span = span->next)
{
fnt = svg_dev_text_span_as_paths_defs(ctx, dev, span, ctm);
- svg_dev_text_span_as_paths_fill(ctx, dev, span, ctm, colorspace, color, alpha, fnt);
+ svg_dev_text_span_as_paths_fill(ctx, dev, span, ctm, colorspace, color, alpha, fnt, color_params);
}
}
}
static void
svg_dev_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
svg_device *sdev = (svg_device*)dev;
fz_output *out = sdev->out;
@@ -704,7 +704,7 @@ svg_dev_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const
for (span = text->head; span; span = span->next)
{
fz_write_printf(ctx, out, "<text");
- svg_dev_fill_color(ctx, sdev, colorspace, color, alpha);
+ svg_dev_fill_color(ctx, sdev, colorspace, color, alpha, color_params);
svg_dev_text_span(ctx, sdev, ctm, span);
}
}
@@ -713,7 +713,7 @@ svg_dev_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const
for (span = text->head; span; span = span->next)
{
fnt = svg_dev_text_span_as_paths_defs(ctx, dev, span, ctm);
- svg_dev_text_span_as_paths_stroke(ctx, dev, span, stroke, ctm, colorspace, color, alpha, fnt);
+ svg_dev_text_span_as_paths_stroke(ctx, dev, span, stroke, ctm, colorspace, color, alpha, fnt, color_params);
}
}
}
@@ -741,7 +741,7 @@ svg_dev_clip_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz
for (span = text->head; span; span = span->next)
{
fz_write_printf(ctx, out, "<text");
- svg_dev_fill_color(ctx, sdev, fz_device_rgb(ctx), white, 1);
+ svg_dev_fill_color(ctx, sdev, fz_device_rgb(ctx), white, 1, NULL);
svg_dev_text_span(ctx, sdev, ctm, span);
}
}
@@ -750,7 +750,7 @@ svg_dev_clip_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz
for (span = text->head; span; span = span->next)
{
fnt = svg_dev_text_span_as_paths_defs(ctx, dev, span, ctm);
- svg_dev_text_span_as_paths_fill(ctx, dev, span, ctm, fz_device_rgb(ctx), white, 1.0f, fnt);
+ svg_dev_text_span_as_paths_fill(ctx, dev, span, ctm, fz_device_rgb(ctx), white, 1.0f, fnt, NULL);
}
}
fz_write_printf(ctx, out, "</mask>\n");
@@ -782,7 +782,7 @@ svg_dev_clip_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, c
{
fz_write_printf(ctx, out, "<text");
svg_dev_stroke_state(ctx, sdev, stroke, &fz_identity);
- svg_dev_stroke_color(ctx, sdev, fz_device_rgb(ctx), white, 1);
+ svg_dev_stroke_color(ctx, sdev, fz_device_rgb(ctx), white, 1, NULL);
svg_dev_text_span(ctx, sdev, ctm, span);
}
}
@@ -791,7 +791,7 @@ svg_dev_clip_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, c
for (span = text->head; span; span = span->next)
{
fnt = svg_dev_text_span_as_paths_defs(ctx, dev, span, ctm);
- svg_dev_text_span_as_paths_stroke(ctx, dev, span, stroke, ctm, fz_device_rgb(ctx), white, 1.0f, fnt);
+ svg_dev_text_span_as_paths_stroke(ctx, dev, span, stroke, ctm, fz_device_rgb(ctx), white, 1.0f, fnt, NULL);
}
}
fz_write_printf(ctx, out, "</mask>\n");
@@ -813,7 +813,7 @@ svg_dev_ignore_text(fz_context *ctx, fz_device *dev, const fz_text *text, const
for (span = text->head; span; span = span->next)
{
fz_write_printf(ctx, out, "<text");
- svg_dev_fill_color(ctx, sdev, fz_device_rgb(ctx), black, 0.0f);
+ svg_dev_fill_color(ctx, sdev, fz_device_rgb(ctx), black, 0.0f, NULL);
svg_dev_text_span(ctx, sdev, ctm, span);
}
}
@@ -863,7 +863,7 @@ send_data_base64(fz_context *ctx, fz_output *out, fz_buffer *buffer)
* have conniptions. We therefore have an option that is
* made to avoid this (reuse-images=no). */
static void
-svg_send_image(fz_context *ctx, svg_device *sdev, fz_image *img)
+svg_send_image(fz_context *ctx, svg_device *sdev, fz_image *img, const fz_color_params *color_params)
{
fz_output *out = sdev->out;
fz_compressed_buffer *buffer;
@@ -917,7 +917,7 @@ svg_send_image(fz_context *ctx, svg_device *sdev, fz_image *img)
/*@fallthough@*/
default:
{
- fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, img);
+ fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, img, color_params);
fz_write_printf(ctx, out, "image/png;base64,");
send_data_base64(ctx, out, buf);
fz_drop_buffer(ctx, buf);
@@ -941,7 +941,7 @@ svg_send_image(fz_context *ctx, svg_device *sdev, fz_image *img)
}
static void
-svg_dev_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha)
+svg_dev_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha, const fz_color_params *color_params)
{
svg_device *sdev = (svg_device*)dev;
fz_output *out = sdev->out;
@@ -958,12 +958,12 @@ svg_dev_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_ma
fz_write_printf(ctx, out, " opacity=\"%g\"", alpha);
svg_dev_ctm(ctx, sdev, &local_ctm);
fz_write_printf(ctx, out, ">\n");
- svg_send_image(ctx, sdev, image);
+ svg_send_image(ctx, sdev, image, color_params);
fz_write_printf(ctx, out, "</g>\n");
}
static void
-svg_dev_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha)
+svg_dev_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha, const fz_color_params *color_params)
{
svg_device *sdev = (svg_device*)dev;
fz_output *out = sdev->out;
@@ -985,8 +985,8 @@ svg_dev_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_ma
fz_try(ctx)
{
- fz_paint_shade(ctx, shade, ctm, pix, &bbox);
- buf = fz_new_buffer_from_pixmap_as_png(ctx, pix);
+ fz_paint_shade(ctx, shade, ctm, pix, NULL, color_params, &bbox);
+ buf = fz_new_buffer_from_pixmap_as_png(ctx, pix, color_params);
if (alpha != 1.0f)
fz_write_printf(ctx, out, "<g opacity=\"%g\">\n", alpha);
fz_write_printf(ctx, out, "<image x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xlink:href=\"data:image/png;base64,", pix->x, pix->y, pix->w, pix->h);
@@ -1008,7 +1008,7 @@ svg_dev_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_ma
static void
svg_dev_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
svg_device *sdev = (svg_device*)dev;
fz_output *out;
@@ -1022,11 +1022,11 @@ svg_dev_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const
fz_concat(&local_ctm, &scale, ctm);
out = start_def(ctx, sdev);
fz_write_printf(ctx, out, "<mask id=\"ma%d\">\n", mask);
- svg_send_image(ctx, sdev, image);
+ svg_send_image(ctx, sdev, image, color_params);
fz_write_printf(ctx, out, "</mask>\n");
out = end_def(ctx, sdev);
fz_write_printf(ctx, out, "<rect x=\"0\" y=\"0\" width=\"%d\" height=\"%d\"", image->w, image->h);
- svg_dev_fill_color(ctx, sdev, colorspace, color, alpha);
+ svg_dev_fill_color(ctx, sdev, colorspace, color, alpha, color_params);
svg_dev_ctm(ctx, sdev, &local_ctm);
fz_write_printf(ctx, out, " mask=\"url(#ma%d)\"/>\n", mask);
}
@@ -1048,7 +1048,7 @@ svg_dev_clip_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const
fz_write_printf(ctx, out, "<mask id=\"ma%d\">\n<g", mask);
svg_dev_ctm(ctx, sdev, &local_ctm);
fz_write_printf(ctx, out, ">\n");
- svg_send_image(ctx, sdev, image);
+ svg_send_image(ctx, sdev, image, NULL/* FIXME */);
fz_write_printf(ctx, out, "</g>\n</mask>\n");
out = end_def(ctx, sdev);
fz_write_printf(ctx, out, "<g mask=\"url(#ma%d)\">\n", mask);
@@ -1065,7 +1065,7 @@ svg_dev_pop_clip(fz_context *ctx, fz_device *dev)
}
static void
-svg_dev_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *bbox, int luminosity, fz_colorspace *colorspace, const float *color)
+svg_dev_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *bbox, int luminosity, fz_colorspace *colorspace, const float *color, const fz_color_params *color_params)
{
svg_device *sdev = (svg_device*)dev;
fz_output *out;
diff --git a/source/fitz/test-device.c b/source/fitz/test-device.c
index 38dc331b..aa6631a8 100644
--- a/source/fitz/test-device.c
+++ b/source/fitz/test-device.c
@@ -29,7 +29,7 @@ is_rgb_color_u8(int threshold_u8, int r, int g, int b)
}
static void
-fz_test_color(fz_context *ctx, fz_test_device *t, fz_colorspace *colorspace, const float *color)
+fz_test_color(fz_context *ctx, fz_test_device *t, fz_colorspace *colorspace, const float *color, const fz_color_params *color_params)
{
if (!*t->is_color && colorspace && colorspace != fz_device_gray(ctx))
{
@@ -46,7 +46,7 @@ fz_test_color(fz_context *ctx, fz_test_device *t, fz_colorspace *colorspace, con
else
{
float rgb[3];
- fz_convert_color(ctx, fz_device_rgb(ctx), rgb, colorspace, color);
+ fz_convert_color(ctx, color_params, NULL, fz_device_rgb(ctx), rgb, colorspace, color);
if (is_rgb_color(t->threshold, rgb[0], rgb[1], rgb[2]))
{
*t->is_color = 2;
@@ -62,68 +62,73 @@ fz_test_color(fz_context *ctx, fz_test_device *t, fz_colorspace *colorspace, con
static void
fz_test_fill_path(fz_context *ctx, fz_device *dev_, const fz_path *path, int even_odd, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_test_device *dev = (fz_test_device*)dev_;
- if (dev->resolved == 0)
+ if (dev->resolved == 0 && alpha != 0.0f)
{
- if (alpha != 0.0f)
- fz_test_color(ctx, dev, colorspace, color);
+ if (color_params == NULL)
+ color_params = fz_default_color_params(ctx);
+ fz_test_color(ctx, dev, colorspace, color, color_params);
}
if (dev->passthrough)
- fz_fill_path(ctx, dev->passthrough, path, even_odd, ctm, colorspace, color, alpha);
+ fz_fill_path(ctx, dev->passthrough, path, even_odd, ctm, colorspace, color, alpha, color_params);
}
static void
fz_test_stroke_path(fz_context *ctx, fz_device *dev_, const fz_path *path, const fz_stroke_state *stroke,
- const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha)
+ const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_test_device *dev = (fz_test_device*)dev_;
- if (dev->resolved == 0)
+ if (dev->resolved == 0 && alpha != 0.0f)
{
- if (alpha != 0.0f)
- fz_test_color(ctx, dev, colorspace, color);
+ if (color_params == NULL)
+ color_params = fz_default_color_params(ctx);
+ fz_test_color(ctx, dev, colorspace, color, color_params);
}
if (dev->passthrough)
- fz_stroke_path(ctx, dev->passthrough, path, stroke, ctm, colorspace, color, alpha);
+ fz_stroke_path(ctx, dev->passthrough, path, stroke, ctm, colorspace, color, alpha, color_params);
}
static void
fz_test_fill_text(fz_context *ctx, fz_device *dev_, const fz_text *text, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_test_device *dev = (fz_test_device*)dev_;
- if (dev->resolved == 0)
+ if (dev->resolved == 0 && alpha != 0.0f)
{
- if (alpha != 0.0f)
- fz_test_color(ctx, dev, colorspace, color);
+ if (color_params == NULL)
+ color_params = fz_default_color_params(ctx);
+ fz_test_color(ctx, dev, colorspace, color, color_params);
}
if (dev->passthrough)
- fz_fill_text(ctx, dev->passthrough, text, ctm, colorspace, color, alpha);
+ fz_fill_text(ctx, dev->passthrough, text, ctm, colorspace, color, alpha, color_params);
}
static void
fz_test_stroke_text(fz_context *ctx, fz_device *dev_, const fz_text *text, const fz_stroke_state *stroke,
- const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha)
+ const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_test_device *dev = (fz_test_device*)dev_;
- if (dev->resolved == 0)
+ if (dev->resolved == 0 && alpha != 0.0f)
{
- if (alpha != 0.0f)
- fz_test_color(ctx, dev, colorspace, color);
+ if (color_params == NULL)
+ color_params = fz_default_color_params(ctx);
+ fz_test_color(ctx, dev, colorspace, color, color_params);
}
if (dev->passthrough)
- fz_stroke_text(ctx, dev->passthrough, text, stroke, ctm, colorspace, color, alpha);
+ fz_stroke_text(ctx, dev->passthrough, text, stroke, ctm, colorspace, color, alpha, color_params);
}
struct shadearg
{
fz_test_device *dev;
fz_shade *shade;
+ const fz_color_params *color_params;
};
static void
@@ -133,14 +138,17 @@ prepare_vertex(fz_context *ctx, void *arg_, fz_vertex *v, const float *color)
fz_test_device *dev = arg->dev;
fz_shade *shade = arg->shade;
if (!shade->use_function)
- fz_test_color(ctx, dev, shade->colorspace, color);
+ fz_test_color(ctx, dev, shade->colorspace, color, arg->color_params);
}
static void
-fz_test_fill_shade(fz_context *ctx, fz_device *dev_, fz_shade *shade, const fz_matrix *ctm, float alpha)
+fz_test_fill_shade(fz_context *ctx, fz_device *dev_, fz_shade *shade, const fz_matrix *ctm, float alpha, const fz_color_params *color_params)
{
fz_test_device *dev = (fz_test_device*)dev_;
+ if (color_params == NULL)
+ color_params = fz_default_color_params(ctx);
+
if (dev->resolved == 0)
{
if ((dev->options & FZ_TEST_OPT_SHADINGS) == 0)
@@ -161,23 +169,24 @@ fz_test_fill_shade(fz_context *ctx, fz_device *dev_, fz_shade *shade, const fz_m
{
int i;
for (i = 0; i < 256; i++)
- fz_test_color(ctx, dev, shade->colorspace, shade->function[i]);
+ fz_test_color(ctx, dev, shade->colorspace, shade->function[i], color_params);
}
else
{
struct shadearg arg;
arg.dev = dev;
arg.shade = shade;
+ arg.color_params = color_params;
fz_process_shade(ctx, shade, ctm, prepare_vertex, NULL, &arg);
}
}
}
if (dev->passthrough)
- fz_fill_shade(ctx, dev->passthrough, shade, ctm, alpha);
+ fz_fill_shade(ctx, dev->passthrough, shade, ctm, alpha, color_params);
}
static void
-fz_test_fill_image(fz_context *ctx, fz_device *dev_, fz_image *image, const fz_matrix *ctm, float alpha)
+fz_test_fill_image(fz_context *ctx, fz_device *dev_, fz_image *image, const fz_matrix *ctm, float alpha, const fz_color_params *color_params)
{
fz_test_device *dev = (fz_test_device*)dev_;
@@ -231,7 +240,7 @@ fz_test_fill_image(fz_context *ctx, fz_device *dev_, fz_image *image, const fz_m
fz_color_converter cc;
unsigned int n = (unsigned int)image->n;
- fz_init_cached_color_converter(ctx, &cc, fz_device_rgb(ctx), image->colorspace);
+ fz_init_cached_color_converter(ctx, &cc, NULL, fz_device_rgb(ctx), image->colorspace, color_params);
for (i = 0; i < count; i++)
{
float cs[FZ_MAX_COLORS];
@@ -299,7 +308,7 @@ fz_test_fill_image(fz_context *ctx, fz_device *dev_, fz_image *image, const fz_m
fz_color_converter cc;
unsigned int n = (unsigned int)pix->n-1;
- fz_init_cached_color_converter(ctx, &cc, fz_device_rgb(ctx), pix->colorspace);
+ fz_init_cached_color_converter(ctx, &cc, NULL, fz_device_rgb(ctx), pix->colorspace, color_params);
while (h--)
{
for (i = 0; i < count; i++)
@@ -336,22 +345,25 @@ fz_test_fill_image(fz_context *ctx, fz_device *dev_, fz_image *image, const fz_m
break;
}
if (dev->passthrough)
- fz_fill_image(ctx, dev->passthrough, image, ctm, alpha);
+ fz_fill_image(ctx, dev->passthrough, image, ctm, alpha, color_params);
}
static void
fz_test_fill_image_mask(fz_context *ctx, fz_device *dev_, fz_image *image, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_test_device *dev = (fz_test_device*)dev_;
+ if (color_params == NULL)
+ color_params = fz_default_color_params(ctx);
+
if (dev->resolved == 0)
{
/* We assume that at least some of the image pixels are non-zero */
- fz_test_color(ctx, dev, colorspace, color);
+ fz_test_color(ctx, dev, colorspace, color, color_params);
}
if (dev->passthrough)
- fz_fill_image_mask(ctx, dev->passthrough, image, ctm, colorspace, color, alpha);
+ fz_fill_image_mask(ctx, dev->passthrough, image, ctm, colorspace, color, alpha, color_params);
}
static void
@@ -411,11 +423,11 @@ fz_test_pop_clip(fz_context *ctx, fz_device *dev_)
}
static void
-fz_test_begin_mask(fz_context *ctx, fz_device *dev_, const fz_rect *rect, int luminosity, fz_colorspace *cs, const float *bc)
+fz_test_begin_mask(fz_context *ctx, fz_device *dev_, const fz_rect *rect, int luminosity, fz_colorspace *cs, const float *bc, const fz_color_params *color_params)
{
fz_test_device *dev = (fz_test_device*)dev_;
- fz_begin_mask(ctx, dev->passthrough, rect, luminosity, cs, bc);
+ fz_begin_mask(ctx, dev->passthrough, rect, luminosity, cs, bc, color_params);
}
static void
diff --git a/source/fitz/trace-device.c b/source/fitz/trace-device.c
index c2f8b4c2..db08aa52 100644
--- a/source/fitz/trace-device.c
+++ b/source/fitz/trace-device.c
@@ -117,7 +117,7 @@ fz_trace_path(fz_context *ctx, fz_output *out, const fz_path *path)
static void
fz_trace_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_output *out = ((fz_trace_device*)dev)->out;
fz_write_printf(ctx, out, "<fill_path");
@@ -134,7 +134,7 @@ fz_trace_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int eve
static void
fz_trace_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_output *out = ((fz_trace_device*)dev)->out;
int i;
@@ -190,7 +190,7 @@ fz_trace_clip_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path,
static void
fz_trace_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_output *out = ((fz_trace_device*)dev)->out;
fz_write_printf(ctx, out, "<fill_text");
@@ -203,7 +203,7 @@ fz_trace_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const f
static void
fz_trace_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_output *out = ((fz_trace_device*)dev)->out;
fz_write_printf(ctx, out, "<stroke_text");
@@ -248,7 +248,7 @@ fz_trace_ignore_text(fz_context *ctx, fz_device *dev, const fz_text *text, const
}
static void
-fz_trace_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha)
+fz_trace_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha, const fz_color_params *color_params)
{
fz_output *out = ((fz_trace_device*)dev)->out;
fz_write_printf(ctx, out, "<fill_image alpha=\"%g\"", alpha);
@@ -258,7 +258,7 @@ fz_trace_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_m
}
static void
-fz_trace_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha)
+fz_trace_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha, const fz_color_params *color_params)
{
fz_output *out = ((fz_trace_device*)dev)->out;
fz_write_printf(ctx, out, "<fill_shade alpha=\"%g\"", alpha);
@@ -268,7 +268,7 @@ fz_trace_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_m
static void
fz_trace_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
fz_output *out = ((fz_trace_device*)dev)->out;
fz_write_printf(ctx, out, "<fill_image_mask");
@@ -296,7 +296,7 @@ fz_trace_pop_clip(fz_context *ctx, fz_device *dev)
}
static void
-fz_trace_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *bbox, int luminosity, fz_colorspace *colorspace, const float *color)
+fz_trace_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *bbox, int luminosity, fz_colorspace *colorspace, const float *color, const fz_color_params *color_params)
{
fz_output *out = ((fz_trace_device*)dev)->out;
fz_write_printf(ctx, out, "<mask bbox=\"%g %g %g %g\" s=\"%s\"",
diff --git a/source/gprf/gprf-doc.c b/source/gprf/gprf-doc.c
index b0111fd4..34a293bd 100644
--- a/source/gprf/gprf-doc.c
+++ b/source/gprf/gprf-doc.c
@@ -827,7 +827,7 @@ gprf_run_page(fz_context *ctx, fz_page *page_, fz_device *dev, const fz_matrix *
local.e = x * scale;
local.f = y * scale;
fz_concat(&local, &local, ctm);
- fz_fill_image(ctx, dev, page->tiles[i++], &local, 1.0f);
+ fz_fill_image(ctx, dev, page->tiles[i++], &local, 1.0f, NULL);
}
}
fz_render_flags(ctx, dev, 0, FZ_DEVFLAG_GRIDFIT_AS_TILED);
diff --git a/source/html/html-layout.c b/source/html/html-layout.c
index 6c3600ca..1ad37f8f 100644
--- a/source/html/html-layout.c
+++ b/source/html/html-layout.c
@@ -1536,7 +1536,7 @@ static void draw_flow_box(fz_context *ctx, fz_html_box *box, float page_top, flo
{
if (text)
{
- fz_fill_text(ctx, dev, text, ctm, fz_device_rgb(ctx), prev_color, 1);
+ fz_fill_text(ctx, dev, text, ctm, fz_device_rgb(ctx), prev_color, 1, NULL);
fz_drop_text(ctx, text);
text = NULL;
}
@@ -1623,7 +1623,7 @@ static void draw_flow_box(fz_context *ctx, fz_html_box *box, float page_top, flo
{
if (text)
{
- fz_fill_text(ctx, dev, text, ctm, fz_device_rgb(ctx), color, 1);
+ fz_fill_text(ctx, dev, text, ctm, fz_device_rgb(ctx), color, 1, NULL);
fz_drop_text(ctx, text);
text = NULL;
}
@@ -1632,14 +1632,14 @@ static void draw_flow_box(fz_context *ctx, fz_html_box *box, float page_top, flo
fz_matrix local_ctm = *ctm;
fz_pre_translate(&local_ctm, node->x, node->y - page_top);
fz_pre_scale(&local_ctm, node->w, node->h);
- fz_fill_image(ctx, dev, node->content.image, &local_ctm, 1);
+ fz_fill_image(ctx, dev, node->content.image, &local_ctm, 1, NULL);
}
}
}
if (text)
{
- fz_fill_text(ctx, dev, text, ctm, fz_device_rgb(ctx), color, 1);
+ fz_fill_text(ctx, dev, text, ctm, fz_device_rgb(ctx), color, 1, NULL);
fz_drop_text(ctx, text);
text = NULL;
}
@@ -1663,7 +1663,7 @@ static void draw_rect(fz_context *ctx, fz_device *dev, const fz_matrix *ctm, flo
rgb[1] = color.g / 255.0f;
rgb[2] = color.b / 255.0f;
- fz_fill_path(ctx, dev, path, 0, ctm, fz_device_rgb(ctx), rgb, color.a / 255.0f);
+ fz_fill_path(ctx, dev, path, 0, ctm, fz_device_rgb(ctx), rgb, color.a / 255.0f, NULL);
fz_drop_path(ctx, path);
}
@@ -1821,7 +1821,7 @@ static void draw_list_mark(fz_context *ctx, fz_html_box *box, float page_top, fl
color[1] = box->style.color.g / 255.0f;
color[2] = box->style.color.b / 255.0f;
- fz_fill_text(ctx, dev, text, ctm, fz_device_rgb(ctx), color, 1);
+ fz_fill_text(ctx, dev, text, ctm, fz_device_rgb(ctx), color, 1, NULL);
}
fz_always(ctx)
fz_drop_text(ctx, text);
diff --git a/source/pdf/pdf-appearance.c b/source/pdf/pdf-appearance.c
index fbd50434..da351de9 100644
--- a/source/pdf/pdf-appearance.c
+++ b/source/pdf/pdf-appearance.c
@@ -1727,7 +1727,7 @@ void pdf_set_markup_appearance(fz_context *ctx, pdf_document *doc, pdf_annot *an
if (stroke)
{
// assert(path)
- fz_stroke_path(ctx, dev, path, stroke, &page_ctm, fz_device_rgb(ctx), color, alpha);
+ fz_stroke_path(ctx, dev, path, stroke, &page_ctm, fz_device_rgb(ctx), color, alpha, NULL);
fz_drop_stroke_state(ctx, stroke);
stroke = NULL;
fz_drop_path(ctx, path);
@@ -1745,7 +1745,7 @@ void pdf_set_markup_appearance(fz_context *ctx, pdf_document *doc, pdf_annot *an
if (stroke)
{
- fz_stroke_path(ctx, dev, path, stroke, &page_ctm, fz_device_rgb(ctx), color, alpha);
+ fz_stroke_path(ctx, dev, path, stroke, &page_ctm, fz_device_rgb(ctx), color, alpha, NULL);
}
fz_close_device(ctx, dev);
@@ -1860,7 +1860,7 @@ void pdf_update_ink_appearance(fz_context *ctx, pdf_document *doc, pdf_annot *an
}
cs = pdf_to_color(ctx, doc, pdf_dict_get(ctx, annot->obj, PDF_NAME_C), color);
- fz_stroke_path(ctx, dev, path, stroke, &page_ctm, cs, color, 1.0f);
+ fz_stroke_path(ctx, dev, path, stroke, &page_ctm, cs, color, 1.0f, NULL);
fz_expand_rect(&rect, width);
/*
@@ -2115,15 +2115,15 @@ void pdf_update_text_annot_appearance(fz_context *ctx, pdf_document *doc, pdf_an
center_rect_within_rect(&bounds, &rect, &tm);
fz_concat(&tm, &tm, &page_ctm);
cs = fz_device_rgb(ctx);
- fz_fill_path(ctx, dev, path, 0, &tm, cs, yellow, 1.0f);
- fz_stroke_path(ctx, dev, path, stroke, &tm, cs, black, 1.0f);
+ fz_fill_path(ctx, dev, path, 0, &tm, cs, yellow, 1.0f, NULL);
+ fz_stroke_path(ctx, dev, path, stroke, &tm, cs, black, 1.0f, NULL);
fz_drop_path(ctx, path);
path = NULL;
path = fz_new_path(ctx);
draw_speech_bubble(ctx, path);
- fz_fill_path(ctx, dev, path, 0, &tm, cs, white, 1.0f);
- fz_stroke_path(ctx, dev, path, stroke, &tm, cs, black, 1.0f);
+ fz_fill_path(ctx, dev, path, 0, &tm, cs, white, 1.0f, NULL);
+ fz_stroke_path(ctx, dev, path, stroke, &tm, cs, black, 1.0f, NULL);
fz_close_device(ctx, dev);
@@ -2198,7 +2198,7 @@ void pdf_update_free_text_annot_appearance(fz_context *ctx, pdf_document *doc, p
dlist = fz_new_display_list(ctx, NULL);
dev = fz_new_list_device(ctx, dlist);
- fz_fill_text(ctx, dev, text, &page_ctm, cs, font_rec.da_rec.col, 1.0f);
+ fz_fill_text(ctx, dev, text, &page_ctm, cs, font_rec.da_rec.col, 1.0f, NULL);
fz_close_device(ctx, dev);
fz_transform_rect(&rect, &page_ctm);
@@ -2384,7 +2384,7 @@ void pdf_set_signature_appearance(fz_context *ctx, pdf_document *doc, pdf_annot
center_rect_within_rect(&logo_bounds, &rect, &logo_tm);
fz_concat(&logo_tm, &logo_tm, &page_ctm);
cs = fz_device_rgb(ctx);
- fz_fill_path(ctx, dev, path, 0, &logo_tm, cs, logo_color, 1.0f);
+ fz_fill_path(ctx, dev, path, 0, &logo_tm, cs, logo_color, 1.0f, NULL);
fz_drop_colorspace(ctx, cs);
cs = NULL;
@@ -2400,7 +2400,7 @@ void pdf_set_signature_appearance(fz_context *ctx, pdf_document *doc, pdf_annot
/* Display the name in the left-hand half of the form field */
rect.x1 = (rect.x0 + rect.x1)/2.0f;
text = fit_text(ctx, &font_rec, name, &rect);
- fz_fill_text(ctx, dev, text, &page_ctm, cs, font_rec.da_rec.col, 1.0f);
+ fz_fill_text(ctx, dev, text, &page_ctm, cs, font_rec.da_rec.col, 1.0f, NULL);
fz_drop_text(ctx, text);
text = NULL;
@@ -2413,7 +2413,7 @@ void pdf_set_signature_appearance(fz_context *ctx, pdf_document *doc, pdf_annot
rect = annot_rect;
rect.x0 = (rect.x0 + rect.x1)/2.0f;
text = fit_text(ctx, &font_rec, fz_string_from_buffer(ctx, fzbuf), &rect);
- fz_fill_text(ctx, dev, text, &page_ctm, cs, font_rec.da_rec.col, 1.0f);
+ fz_fill_text(ctx, dev, text, &page_ctm, cs, font_rec.da_rec.col, 1.0f, NULL);
fz_close_device(ctx, dev);
diff --git a/source/pdf/pdf-colorspace.c b/source/pdf/pdf-colorspace.c
index 2a862c65..9b840cc9 100644
--- a/source/pdf/pdf-colorspace.c
+++ b/source/pdf/pdf-colorspace.c
@@ -6,52 +6,119 @@
#include <string.h>
/* ICCBased */
-
static fz_colorspace *
-load_icc_based(fz_context *ctx, pdf_obj *dict)
+load_icc_based(fz_context *ctx, pdf_obj *dict, int alt)
{
int n;
pdf_obj *obj;
+ fz_buffer *buffer = NULL;
+ fz_colorspace *cs = NULL;
+ fz_colorspace *cs_alt = NULL;
+ fz_colorspace_clamp_fn *alt_lab_clamping = NULL;
+
+ fz_var(cs);
+ fz_var(cs_alt);
+ fz_var(buffer);
+
+ /*
+ alt => "If ICC unreadable/unsupported, then return the
+ alternate instead".
+
+ Regardless of whether alt is set or not, we DO read the
+ alternate space, because we need to know whether it's a
+ LAB space or not to affect our clamping. We just might
+ not return it.
+ */
+ fz_try(ctx)
+ {
+ obj = pdf_dict_get(ctx, dict, PDF_NAME_Alternate);
+ if (obj)
+ {
+ cs_alt = pdf_load_colorspace(ctx, obj);
+ if (fz_colorspace_is_lab_icc(ctx, cs_alt))
+ alt_lab_clamping = cs_alt->clamp;
+ }
+ }
+ fz_catch(ctx)
+ {
+ fz_drop_colorspace(ctx, cs_alt);
+ cs_alt = NULL;
+ }
+
+ /* If we're not going to be allowed to return it, drop it! */
+ if (!alt)
+ {
+ fz_drop_colorspace(ctx, cs_alt);
+ cs_alt = NULL;
+ }
n = pdf_to_int(ctx, pdf_dict_get(ctx, dict, PDF_NAME_N));
- obj = pdf_dict_get(ctx, dict, PDF_NAME_Alternate);
- if (obj)
+ fz_try(ctx)
{
- fz_colorspace *cs_alt = NULL;
-
- fz_try(ctx)
+ if (fz_get_cmm_engine(ctx))
{
- cs_alt = pdf_load_colorspace(ctx, obj);
- if (cs_alt->n != n)
- {
- fz_drop_colorspace(ctx, cs_alt);
- fz_throw(ctx, FZ_ERROR_SYNTAX, "ICCBased /Alternate colorspace must have %d components", n);
- }
+ buffer = pdf_load_stream(ctx, dict);
+ cs = fz_new_icc_colorspace(ctx, 0, n, buffer, NULL);
}
- fz_catch(ctx)
+ }
+ fz_always(ctx)
+ fz_drop_buffer(ctx, buffer);
+ fz_catch(ctx)
+ {
+ if (!alt)
+ fz_rethrow(ctx);
+ }
+
+ if (cs)
+ {
+ if (n != 1 && n != 3 && n != 4)
{
- cs_alt = NULL;
+ fz_drop_colorspace(ctx, cs);
+ fz_throw(ctx, FZ_ERROR_GENERIC, "ICC Based must have 1, 3 or 4 components");
}
- if (cs_alt)
- return cs_alt;
+ /* Override the clamping if the alternate was LAB */
+ if (alt_lab_clamping)
+ cs->clamp = alt_lab_clamping;
+ fz_drop_colorspace(ctx, cs_alt);
+ return cs;
+ }
+
+ /* Failed to load the ICC profile - either because it was broken,
+ * or because we aren't in an ICC workflow. If we aren't allowed
+ * to return the alternate, then that's all she wrote. */
+ if (!alt)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Unable to read ICC workflow");
+
+ /* If we have an alternate we are allowed to use, return that. */
+ if (cs_alt)
+ {
+ if (n != 1 && n != 3 && n != 4)
+ {
+ fz_drop_colorspace(ctx, cs_alt);
+ fz_throw(ctx, FZ_ERROR_GENERIC, "ICC Based must have 1, 3 or 4 components");
+ }
+ return cs_alt;
}
switch (n)
{
- case 1: return fz_device_gray(ctx);
- case 3: return fz_device_rgb(ctx);
- case 4: return fz_device_cmyk(ctx);
+ case 1:
+ cs = fz_device_gray(ctx);
+ break;
+ case 3:
+ cs = fz_device_rgb(ctx);
+ break;
+ case 4:
+ cs = fz_device_cmyk(ctx);
+ break;
+ default: fz_throw(ctx, FZ_ERROR_SYNTAX, "ICCBased must have 1, 3 or 4 components");
}
- fz_throw(ctx, FZ_ERROR_SYNTAX, "ICCBased must have 1, 3 or 4 components");
+ return cs;
}
-/* Lab */
-
-/* Separation and DeviceN */
-
struct separation
{
fz_colorspace *base;
@@ -59,12 +126,19 @@ struct separation
};
static void
+separation_to_alt(fz_context *ctx, fz_colorspace *cs, const float *color, float *alt)
+{
+ struct separation *sep = cs->data;
+ pdf_eval_function(ctx, sep->tint, color, cs->n, alt, sep->base->n);
+}
+
+static void
separation_to_rgb(fz_context *ctx, fz_colorspace *cs, const float *color, float *rgb)
{
struct separation *sep = cs->data;
float alt[FZ_MAX_COLORS];
pdf_eval_function(ctx, sep->tint, color, cs->n, alt, sep->base->n);
- fz_convert_color(ctx, fz_device_rgb(ctx), rgb, sep->base, alt);
+ fz_convert_color(ctx, fz_default_color_params(ctx), NULL, fz_device_rgb(ctx), rgb, sep->base, alt);
}
static void
@@ -77,6 +151,14 @@ free_separation(fz_context *ctx, fz_colorspace *cs)
}
static fz_colorspace *
+base_separation(const fz_colorspace *cs)
+{
+ struct separation *sep = cs->data;
+
+ return sep->base;
+}
+
+static fz_colorspace *
load_separation(fz_context *ctx, pdf_obj *array)
{
fz_colorspace *cs;
@@ -108,10 +190,11 @@ load_separation(fz_context *ctx, pdf_obj *array)
* "cannot load tint function (%d 0 R)", pdf_to_num(ctx, tintobj) */
sep = fz_malloc_struct(ctx, struct separation);
- sep->base = base;
+ sep->base = fz_keep_colorspace(ctx, base); /* We drop it during the sep free... */
sep->tint = tint;
- cs = fz_new_colorspace(ctx, n == 1 ? "Separation" : "DeviceN", n, 1, separation_to_rgb, NULL, free_separation, sep,
+ cs = fz_new_colorspace(ctx, n == 1 ? "Separation" : "DeviceN", 0, n, 1,
+ fz_colorspace_is_icc(ctx, fz_device_rgb(ctx)) ? separation_to_alt : separation_to_rgb, NULL, base_separation, NULL, free_separation, sep,
sizeof(struct separation) + (base ? base->size : 0) + pdf_function_size(ctx, tint));
}
fz_catch(ctx)
@@ -128,7 +211,7 @@ load_separation(fz_context *ctx, pdf_obj *array)
int
pdf_is_tint_colorspace(fz_context *ctx, fz_colorspace *cs)
{
- return fz_colorspace_is(ctx, cs, separation_to_rgb);
+ return cs && cs->free_data == free_separation;
}
/* Indexed */
@@ -201,6 +284,104 @@ load_indexed(fz_context *ctx, pdf_obj *array)
return cs;
}
+static void
+pdf_load_cal_common(fz_context *ctx, pdf_obj *dict, float *wp, float *bp, float *gamma)
+{
+ pdf_obj *obj;
+ int i;
+
+ obj = pdf_dict_get(ctx, dict, PDF_NAME_WhitePoint);
+ if (pdf_array_len(ctx, obj) != 3)
+ fz_throw(ctx, FZ_ERROR_SYNTAX, "WhitePoint must be a 3-element array");
+
+ for (i = 0; i < 3; i++)
+ {
+ wp[i] = pdf_to_real(ctx, pdf_array_get(ctx, obj, i));
+ if (wp[i] < 0)
+ fz_throw(ctx, FZ_ERROR_SYNTAX, "WhitePoint numbers must be positive");
+ }
+ if (wp[1] != 1)
+ fz_throw(ctx, FZ_ERROR_SYNTAX, "WhitePoint Yw must be 1.0");
+
+ obj = pdf_dict_get(ctx, dict, PDF_NAME_BlackPoint);
+ if (pdf_array_len(ctx, obj) == 3)
+ {
+ for (i = 0; i < 3; i++)
+ {
+ bp[i] = pdf_to_real(ctx, pdf_array_get(ctx, obj, i));
+ if (bp[i] < 0)
+ fz_throw(ctx, FZ_ERROR_SYNTAX, "BlackPoint numbers must be positive");
+ }
+ }
+
+ obj = pdf_dict_get(ctx, dict, PDF_NAME_Gamma);
+ if (pdf_is_number(ctx, obj))
+ {
+ gamma[0] = pdf_to_real(ctx, obj);
+ gamma[1] = gamma[2];
+ if (gamma[0] <= 0)
+ fz_throw(ctx, FZ_ERROR_SYNTAX, "Gamma must be greater than zero");
+ }
+ else if (pdf_array_len(ctx, obj) == 3)
+ {
+ for (i = 0; i < 3; i++)
+ {
+ gamma[i] = pdf_to_real(ctx, pdf_array_get(ctx, obj, i));
+ if (gamma[i] <= 0)
+ fz_throw(ctx, FZ_ERROR_SYNTAX, "Gamma must be greater than zero");
+ }
+ }
+}
+
+static fz_colorspace *
+pdf_load_cal_gray(fz_context *ctx, pdf_obj *dict)
+{
+ float wp[3];
+ float bp[3] = { 0, 0, 0 };
+ float gamma[3] = { 1, 1, 1 };
+
+ if (dict == NULL)
+ return fz_device_gray(ctx);
+
+ fz_try(ctx)
+ {
+ pdf_load_cal_common(ctx, dict, wp, bp, gamma);
+ gamma[2] = gamma[1] = gamma[0];
+ }
+ fz_catch(ctx)
+ return fz_device_gray(ctx);
+ return fz_new_cal_colorspace(ctx, wp, bp, gamma, NULL);
+}
+
+static fz_colorspace *
+pdf_load_cal_rgb(fz_context *ctx, pdf_obj *dict)
+{
+ pdf_obj *obj;
+ float matrix[9] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 };
+ float wp[3];
+ float bp[3] = { 0, 0, 0 };
+ float gamma[3] = { 1, 1, 1 };
+ int i;
+
+ if (dict == NULL)
+ return fz_device_rgb(ctx);
+
+ fz_try(ctx)
+ {
+ pdf_load_cal_common(ctx, dict, wp, bp, gamma);
+
+ obj = pdf_dict_get(ctx, dict, PDF_NAME_Matrix);
+ if (pdf_array_len(ctx, obj) == 9)
+ {
+ for (i = 0; i < 9; i++)
+ matrix[i] = pdf_to_real(ctx, pdf_array_get(ctx, obj, i));
+ }
+ }
+ fz_catch(ctx)
+ return fz_device_rgb(ctx);
+ return fz_new_cal_colorspace(ctx, wp, bp, gamma, matrix);
+}
+
/* Parse and create colorspace from PDF object */
static fz_colorspace *
@@ -249,9 +430,19 @@ pdf_load_colorspace_imp(fz_context *ctx, pdf_obj *obj)
else if (pdf_name_eq(ctx, name, PDF_NAME_DeviceCMYK))
return fz_device_cmyk(ctx);
else if (pdf_name_eq(ctx, name, PDF_NAME_CalGray))
- return fz_device_gray(ctx);
+ {
+ if (fz_get_cmm_engine(ctx))
+ return pdf_load_cal_gray(ctx, pdf_array_get(ctx, obj, 1));
+ else
+ return fz_device_gray(ctx);
+ }
else if (pdf_name_eq(ctx, name, PDF_NAME_CalRGB))
- return fz_device_rgb(ctx);
+ {
+ if (fz_get_cmm_engine(ctx))
+ return pdf_load_cal_rgb(ctx, pdf_array_get(ctx, obj, 1));
+ else
+ return fz_device_rgb(ctx);
+ }
else if (pdf_name_eq(ctx, name, PDF_NAME_CalCMYK))
return fz_device_cmyk(ctx);
else if (pdf_name_eq(ctx, name, PDF_NAME_Lab))
@@ -264,7 +455,7 @@ pdf_load_colorspace_imp(fz_context *ctx, pdf_obj *obj)
if (pdf_mark_obj(ctx, obj))
fz_throw(ctx, FZ_ERROR_SYNTAX, "recursive colorspace");
if (pdf_name_eq(ctx, name, PDF_NAME_ICCBased))
- cs = load_icc_based(ctx, pdf_array_get(ctx, obj, 1));
+ cs = load_icc_based(ctx, pdf_array_get(ctx, obj, 1), 1);
else if (pdf_name_eq(ctx, name, PDF_NAME_Indexed))
cs = load_indexed(ctx, obj);
@@ -305,6 +496,16 @@ pdf_load_colorspace_imp(fz_context *ctx, pdf_obj *obj)
}
}
+ /* We have seen files where /DefaultRGB is specified as 1 0 R,
+ * and 1 0 obj << /Length 3144 /Alternate /DeviceRGB /N 3 >>
+ * stream ...iccprofile... endstream endobj.
+ * This *should* be [ /ICCBased 1 0 R ], but Acrobat seems to
+ * handle it, so do our best. */
+ else if (pdf_is_dict(ctx, obj))
+ {
+ return load_icc_based(ctx, obj, 1);
+ }
+
fz_throw(ctx, FZ_ERROR_SYNTAX, "could not parse color space (%d 0 R)", pdf_to_num(ctx, obj));
}
@@ -324,3 +525,48 @@ pdf_load_colorspace(fz_context *ctx, pdf_obj *obj)
return cs;
}
+
+static fz_colorspace *
+pdf_load_output_intent(fz_context *ctx, pdf_document *doc)
+{
+ pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root);
+ pdf_obj *intents = pdf_dict_get(ctx, root, PDF_NAME_OutputIntents);
+ pdf_obj *intent_dict;
+ pdf_obj *dest_profile;
+ fz_colorspace *cs = NULL;
+
+ /* An array of intents */
+ if (!intents)
+ return NULL;
+
+ /* For now, always just use the first intent. I have never even seen a file
+ * with multiple intents but it could happen */
+ intent_dict = pdf_array_get(ctx, intents, 0);
+ if (!intent_dict)
+ return NULL;
+ dest_profile = pdf_dict_get(ctx, intent_dict, PDF_NAME_DestOutputProfile);
+ if (!dest_profile)
+ return NULL;
+
+ fz_var(cs);
+
+ fz_try(ctx)
+ cs = load_icc_based(ctx, dest_profile, 0);
+ fz_catch(ctx)
+ {
+ /* Swallow the error */
+ fz_warn(ctx, "Attempt to read Output Intent failed");
+ }
+
+ return cs;
+}
+
+fz_colorspace *
+pdf_document_output_intent(fz_context *ctx, pdf_document *doc)
+{
+#ifndef NOICC
+ if (!doc->oi)
+ doc->oi = pdf_load_output_intent(ctx, doc);
+#endif
+ return doc->oi;
+}
diff --git a/source/pdf/pdf-device.c b/source/pdf/pdf-device.c
index 23fed0fd..ba51265a 100644
--- a/source/pdf/pdf-device.c
+++ b/source/pdf/pdf-device.c
@@ -214,7 +214,7 @@ pdf_dev_ctm(fz_context *ctx, pdf_device *pdev, const fz_matrix *ctm)
}
static void
-pdf_dev_color(fz_context *ctx, pdf_device *pdev, fz_colorspace *colorspace, const float *color, int stroke)
+pdf_dev_color(fz_context *ctx, pdf_device *pdev, fz_colorspace *colorspace, const float *color, int stroke, const fz_color_params *color_params)
{
int diff = 0;
int i;
@@ -232,7 +232,7 @@ pdf_dev_color(fz_context *ctx, pdf_device *pdev, fz_colorspace *colorspace, cons
if (cspace == 0)
{
/* If it's an unknown colorspace, fallback to rgb */
- fz_convert_color(ctx, fz_device_rgb(ctx), rgb, colorspace, color);
+ fz_convert_color(ctx, color_params, NULL, fz_device_rgb(ctx), rgb, colorspace, color);
color = rgb;
colorspace = fz_device_rgb(ctx);
cspace = 3;
@@ -631,14 +631,14 @@ pdf_dev_new_form(fz_context *ctx, pdf_obj **form_ref, pdf_device *pdev, const fz
static void
pdf_dev_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
pdf_device *pdev = (pdf_device*)dev;
gstate *gs = CURRENT_GSTATE(pdev);
pdf_dev_end_text(ctx, pdev);
pdf_dev_alpha(ctx, pdev, alpha, 0);
- pdf_dev_color(ctx, pdev, colorspace, color, 0);
+ pdf_dev_color(ctx, pdev, colorspace, color, 0, color_params);
pdf_dev_ctm(ctx, pdev, ctm);
pdf_dev_path(ctx, pdev, path);
fz_append_string(ctx, gs->buf, (even_odd ? "f*\n" : "f\n"));
@@ -646,14 +646,14 @@ pdf_dev_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even
static void
pdf_dev_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
pdf_device *pdev = (pdf_device*)dev;
gstate *gs = CURRENT_GSTATE(pdev);
pdf_dev_end_text(ctx, pdev);
pdf_dev_alpha(ctx, pdev, alpha, 1);
- pdf_dev_color(ctx, pdev, colorspace, color, 1);
+ pdf_dev_color(ctx, pdev, colorspace, color, 1, color_params);
pdf_dev_ctm(ctx, pdev, ctm);
pdf_dev_stroke_state(ctx, pdev, stroke);
pdf_dev_path(ctx, pdev, path);
@@ -694,7 +694,7 @@ pdf_dev_clip_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, c
static void
pdf_dev_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
pdf_device *pdev = (pdf_device*)dev;
fz_text_span *span;
@@ -706,14 +706,14 @@ pdf_dev_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz
pdf_dev_font(ctx, pdev, span->font);
pdf_dev_ctm(ctx, pdev, ctm);
pdf_dev_alpha(ctx, pdev, alpha, 0);
- pdf_dev_color(ctx, pdev, colorspace, color, 0);
+ pdf_dev_color(ctx, pdev, colorspace, color, 0, color_params);
pdf_dev_text_span(ctx, pdev, span);
}
}
static void
pdf_dev_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
pdf_device *pdev = (pdf_device*)dev;
fz_text_span *span;
@@ -724,7 +724,7 @@ pdf_dev_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const
pdf_dev_font(ctx, pdev, span->font);
pdf_dev_ctm(ctx, pdev, ctm);
pdf_dev_alpha(ctx, pdev, alpha, 1);
- pdf_dev_color(ctx, pdev, colorspace, color, 1);
+ pdf_dev_color(ctx, pdev, colorspace, color, 1, color_params);
pdf_dev_text_span(ctx, pdev, span);
}
}
@@ -804,7 +804,7 @@ pdf_dev_add_image_res(fz_context *ctx, fz_device *dev, pdf_obj *im_res)
}
static void
-pdf_dev_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha)
+pdf_dev_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha, const fz_color_params *color_params)
{
pdf_device *pdev = (pdf_device*)dev;
pdf_obj *im_res;
@@ -832,7 +832,7 @@ pdf_dev_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_ma
}
static void
-pdf_dev_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha)
+pdf_dev_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha, const fz_color_params *color_params)
{
pdf_device *pdev = (pdf_device*)dev;
@@ -842,7 +842,7 @@ pdf_dev_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_ma
static void
pdf_dev_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
pdf_device *pdev = (pdf_device*)dev;
pdf_obj *im_res = NULL;
@@ -858,7 +858,7 @@ pdf_dev_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const
}
fz_append_string(ctx, gs->buf, "q\n");
pdf_dev_alpha(ctx, pdev, alpha, 0);
- pdf_dev_color(ctx, pdev, colorspace, color, 0);
+ pdf_dev_color(ctx, pdev, colorspace, color, 0, color_params);
/* PDF images are upside down, so fiddle the ctm */
fz_pre_scale(&local_ctm, 1, -1);
@@ -892,7 +892,7 @@ pdf_dev_pop_clip(fz_context *ctx, fz_device *dev)
}
static void
-pdf_dev_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *bbox, int luminosity, fz_colorspace *colorspace, const float *color)
+pdf_dev_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *bbox, int luminosity, fz_colorspace *colorspace, const float *color, const fz_color_params *color_params)
{
pdf_device *pdev = (pdf_device*)dev;
pdf_document *doc = pdev->doc;
diff --git a/source/pdf/pdf-image.c b/source/pdf/pdf-image.c
index b19f1e39..cf82b540 100644
--- a/source/pdf/pdf-image.c
+++ b/source/pdf/pdf-image.c
@@ -18,7 +18,7 @@ pdf_load_jpx_imp(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *dict
if (tile->n != 1)
{
- fz_pixmap *gray = fz_convert_pixmap(ctx, tile, fz_device_gray(ctx), 0);
+ fz_pixmap *gray = fz_convert_pixmap(ctx, tile, fz_device_gray(ctx), NULL, NULL, fz_default_color_params(ctx), 0);
fz_drop_pixmap(ctx, tile);
tile = gray;
}
diff --git a/source/pdf/pdf-interpret.c b/source/pdf/pdf-interpret.c
index f98326e6..d9620212 100644
--- a/source/pdf/pdf-interpret.c
+++ b/source/pdf/pdf-interpret.c
@@ -200,6 +200,24 @@ pdf_process_extgstate(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, pdf_ob
fz_rethrow(ctx);
}
+ /* overprint and color management */
+
+ obj = pdf_dict_get(ctx, dict, PDF_NAME_OP);
+ if (pdf_is_name(ctx, obj) && proc->op_gs_OP)
+ proc->op_gs_OP(ctx, proc, pdf_to_bool(ctx, obj));
+
+ obj = pdf_dict_get(ctx, dict, PDF_NAME_op);
+ if (pdf_is_name(ctx, obj) && proc->op_gs_op)
+ proc->op_gs_op(ctx, proc, pdf_to_bool(ctx, obj));
+
+ obj = pdf_dict_get(ctx, dict, PDF_NAME_OPM);
+ if (pdf_is_name(ctx, obj) && proc->op_gs_OPM)
+ proc->op_gs_OPM(ctx, proc, pdf_to_int(ctx, obj));
+
+ obj = pdf_dict_get(ctx, dict, PDF_NAME_UseBlackPtComp);
+ if (pdf_is_name(ctx, obj) && proc->op_gs_UseBlackPtComp)
+ proc->op_gs_UseBlackPtComp(ctx, proc, obj);
+
/* transfer functions */
obj = pdf_dict_get(ctx, dict, PDF_NAME_TR2);
@@ -253,10 +271,7 @@ pdf_process_extgstate(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, pdf_ob
{
colorspace = pdf_xobject_colorspace(ctx, xobj);
if (colorspace)
- {
colorspace_n = fz_colorspace_n(ctx, colorspace);
- fz_drop_colorspace(ctx, colorspace);
- }
/* Default background color is black. */
for (k = 0; k < colorspace_n; k++)
@@ -266,6 +281,7 @@ pdf_process_extgstate(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, pdf_ob
* to do for now. */
if (colorspace == fz_device_cmyk(ctx))
softmask_bc[3] = 1.0f;
+ fz_drop_colorspace(ctx, colorspace);
bc = pdf_dict_get(ctx, obj, PDF_NAME_BC);
if (pdf_is_array(ctx, bc))
diff --git a/source/pdf/pdf-op-buffer.c b/source/pdf/pdf-op-buffer.c
index d5585766..6974fb00 100644
--- a/source/pdf/pdf-op-buffer.c
+++ b/source/pdf/pdf-op-buffer.c
@@ -65,6 +65,26 @@ pdf_out_ri(fz_context *ctx, pdf_processor *proc, const char *intent)
}
static void
+pdf_out_gs_OP(fz_context *ctx, pdf_processor *proc, int b)
+{
+}
+
+static void
+pdf_out_gs_op(fz_context *ctx, pdf_processor *proc, int b)
+{
+}
+
+static void
+pdf_out_gs_OPM(fz_context *ctx, pdf_processor *proc, int i)
+{
+}
+
+static void
+pdf_out_gs_UseBlackPtComp(fz_context *ctx, pdf_processor *proc, pdf_obj *name)
+{
+}
+
+static void
pdf_out_i(fz_context *ctx, pdf_processor *proc, float flatness)
{
fz_output *out = ((pdf_output_processor*)proc)->out;
@@ -891,6 +911,12 @@ pdf_new_output_processor(fz_context *ctx, fz_output *out, int ahxencode)
/* compatibility */
proc->super.op_BX = pdf_out_BX;
proc->super.op_EX = pdf_out_EX;
+
+ /* extgstate */
+ proc->super.op_gs_OP = pdf_out_gs_OP;
+ proc->super.op_gs_op = pdf_out_gs_op;
+ proc->super.op_gs_OPM = pdf_out_gs_OPM;
+ proc->super.op_gs_UseBlackPtComp = pdf_out_gs_UseBlackPtComp;
}
proc->out = out;
diff --git a/source/pdf/pdf-op-filter.c b/source/pdf/pdf-op-filter.c
index ad80d3cd..a71f2fa7 100644
--- a/source/pdf/pdf-op-filter.c
+++ b/source/pdf/pdf-op-filter.c
@@ -389,6 +389,42 @@ pdf_filter_ri(fz_context *ctx, pdf_processor *proc, const char *intent)
}
static void
+pdf_filter_gs_OP(fz_context *ctx, pdf_processor *proc, int b)
+{
+ pdf_filter_processor *p = (pdf_filter_processor*)proc;
+ filter_flush(ctx, p, 0);
+ if (p->chain->op_gs_OP)
+ p->chain->op_gs_OP(ctx, p->chain, b);
+}
+
+static void
+pdf_filter_gs_op(fz_context *ctx, pdf_processor *proc, int b)
+{
+ pdf_filter_processor *p = (pdf_filter_processor*)proc;
+ filter_flush(ctx, p, 0);
+ if (p->chain->op_gs_op)
+ p->chain->op_gs_op(ctx, p->chain, b);
+}
+
+static void
+pdf_filter_gs_OPM(fz_context *ctx, pdf_processor *proc, int i)
+{
+ pdf_filter_processor *p = (pdf_filter_processor*)proc;
+ filter_flush(ctx, p, 0);
+ if (p->chain->op_gs_OPM)
+ p->chain->op_gs_OPM(ctx, p->chain, i);
+}
+
+static void
+pdf_filter_gs_UseBlackPtComp(fz_context *ctx, pdf_processor *proc, pdf_obj *name)
+{
+ pdf_filter_processor *p = (pdf_filter_processor*)proc;
+ filter_flush(ctx, p, 0);
+ if (p->chain->op_gs_UseBlackPtComp)
+ p->chain->op_gs_UseBlackPtComp(ctx, p->chain, name);
+}
+
+static void
pdf_filter_i(fz_context *ctx, pdf_processor *proc, float flatness)
{
pdf_filter_processor *p = (pdf_filter_processor*)proc;
@@ -1238,6 +1274,12 @@ pdf_new_filter_processor(fz_context *ctx, pdf_processor *chain, pdf_obj *old_rdb
proc->super.op_BX = pdf_filter_BX;
proc->super.op_EX = pdf_filter_EX;
+ /* extgstate */
+ proc->super.op_gs_OP = pdf_filter_gs_OP;
+ proc->super.op_gs_op = pdf_filter_gs_op;
+ proc->super.op_gs_OPM = pdf_filter_gs_OPM;
+ proc->super.op_gs_UseBlackPtComp = pdf_filter_gs_UseBlackPtComp;
+
proc->super.op_END = pdf_filter_END;
}
diff --git a/source/pdf/pdf-op-run.c b/source/pdf/pdf-op-run.c
index fddc9b91..f028732e 100644
--- a/source/pdf/pdf-op-run.c
+++ b/source/pdf/pdf-op-run.c
@@ -36,6 +36,7 @@ struct pdf_material_s
pdf_pattern *pattern;
fz_shade *shade;
int gstate_num;
+ fz_color_params color_params;
float alpha;
float v[FZ_MAX_COLORS];
};
@@ -148,7 +149,7 @@ begin_softmask(fz_context *ctx, pdf_run_processor *pr, softmask_save *save)
fz_try(ctx)
{
- fz_begin_mask(ctx, pr->dev, &mask_bbox, gstate->luminosity, mask_colorspace, gstate->softmask_bc);
+ fz_begin_mask(ctx, pr->dev, &mask_bbox, gstate->luminosity, mask_colorspace, gstate->softmask_bc, &gstate->fill.color_params);
pdf_run_xobject(ctx, pr, softmask, save->page_resources, &fz_identity);
}
fz_always(ctx)
@@ -224,7 +225,7 @@ pdf_show_shade(fz_context *ctx, pdf_run_processor *pr, fz_shade *shd)
/* FIXME: The gstate->ctm in the next line may be wrong; maybe
* it should be the parent gstates ctm? */
- fz_fill_shade(ctx, pr->dev, shd, &gstate->ctm, gstate->fill.alpha);
+ fz_fill_shade(ctx, pr->dev, shd, &gstate->ctm, gstate->fill.alpha, &gstate->fill.color_params);
pdf_end_group(ctx, pr, &softmask);
}
@@ -540,7 +541,7 @@ pdf_show_image(fz_context *ctx, pdf_run_processor *pr, fz_image *image)
break;
case PDF_MAT_COLOR:
fz_fill_image_mask(ctx, pr->dev, image, &image_ctm,
- gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha);
+ gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha, &gstate->fill.color_params);
break;
case PDF_MAT_PATTERN:
if (gstate->fill.pattern)
@@ -554,7 +555,7 @@ pdf_show_image(fz_context *ctx, pdf_run_processor *pr, fz_image *image)
if (gstate->fill.shade)
{
fz_clip_image_mask(ctx, pr->dev, image, &image_ctm, &bbox);
- fz_fill_shade(ctx, pr->dev, gstate->fill.shade, &pr->gstate[gstate->fill.gstate_num].ctm, gstate->fill.alpha);
+ fz_fill_shade(ctx, pr->dev, gstate->fill.shade, &pr->gstate[gstate->fill.gstate_num].ctm, gstate->fill.alpha, &gstate->fill.color_params);
fz_pop_clip(ctx, pr->dev);
}
break;
@@ -562,7 +563,7 @@ pdf_show_image(fz_context *ctx, pdf_run_processor *pr, fz_image *image)
}
else
{
- fz_fill_image(ctx, pr->dev, image, &image_ctm, gstate->fill.alpha);
+ fz_fill_image(ctx, pr->dev, image, &image_ctm, gstate->fill.alpha, &gstate->fill.color_params);
}
if (image->mask)
@@ -646,7 +647,7 @@ pdf_show_path(fz_context *ctx, pdf_run_processor *pr, int doclose, int dofill, i
break;
case PDF_MAT_COLOR:
fz_fill_path(ctx, pr->dev, path, even_odd, &gstate->ctm,
- gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha);
+ gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha, &gstate->fill.color_params);
break;
case PDF_MAT_PATTERN:
if (gstate->fill.pattern)
@@ -661,7 +662,7 @@ pdf_show_path(fz_context *ctx, pdf_run_processor *pr, int doclose, int dofill, i
{
fz_clip_path(ctx, pr->dev, path, even_odd, &gstate->ctm, &bbox);
/* The cluster and page 2 of patterns.pdf shows that fz_fill_shade should NOT be called with gstate->ctm. */
- fz_fill_shade(ctx, pr->dev, gstate->fill.shade, &pr->gstate[gstate->fill.gstate_num].ctm, gstate->fill.alpha);
+ fz_fill_shade(ctx, pr->dev, gstate->fill.shade, &pr->gstate[gstate->fill.gstate_num].ctm, gstate->fill.alpha, &gstate->fill.color_params);
fz_pop_clip(ctx, pr->dev);
}
break;
@@ -676,7 +677,7 @@ pdf_show_path(fz_context *ctx, pdf_run_processor *pr, int doclose, int dofill, i
break;
case PDF_MAT_COLOR:
fz_stroke_path(ctx, pr->dev, path, gstate->stroke_state, &gstate->ctm,
- gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha);
+ gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha, &gstate->stroke.color_params);
break;
case PDF_MAT_PATTERN:
if (gstate->stroke.pattern)
@@ -690,7 +691,7 @@ pdf_show_path(fz_context *ctx, pdf_run_processor *pr, int doclose, int dofill, i
if (gstate->stroke.shade)
{
fz_clip_stroke_path(ctx, pr->dev, path, gstate->stroke_state, &gstate->ctm, &bbox);
- fz_fill_shade(ctx, pr->dev, gstate->stroke.shade, &pr->gstate[gstate->stroke.gstate_num].ctm, gstate->stroke.alpha);
+ fz_fill_shade(ctx, pr->dev, gstate->stroke.shade, &pr->gstate[gstate->stroke.gstate_num].ctm, gstate->stroke.alpha, &gstate->stroke.color_params);
fz_pop_clip(ctx, pr->dev);
}
break;
@@ -794,7 +795,7 @@ pdf_flush_text(fz_context *ctx, pdf_run_processor *pr)
break;
case PDF_MAT_COLOR:
fz_fill_text(ctx, pr->dev, text, &gstate->ctm,
- gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha);
+ gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha, &gstate->fill.color_params);
break;
case PDF_MAT_PATTERN:
if (gstate->fill.pattern)
@@ -809,7 +810,7 @@ pdf_flush_text(fz_context *ctx, pdf_run_processor *pr)
{
fz_clip_text(ctx, pr->dev, text, &gstate->ctm, &tb);
/* Page 2 of patterns.pdf shows that fz_fill_shade should NOT be called with gstate->ctm */
- fz_fill_shade(ctx, pr->dev, gstate->fill.shade, &pr->gstate[gstate->fill.gstate_num].ctm, gstate->fill.alpha);
+ fz_fill_shade(ctx, pr->dev, gstate->fill.shade, &pr->gstate[gstate->fill.gstate_num].ctm, gstate->fill.alpha, &gstate->fill.color_params);
fz_pop_clip(ctx, pr->dev);
}
break;
@@ -824,7 +825,7 @@ pdf_flush_text(fz_context *ctx, pdf_run_processor *pr)
break;
case PDF_MAT_COLOR:
fz_stroke_text(ctx, pr->dev, text, gstate->stroke_state, &gstate->ctm,
- gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha);
+ gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha, &gstate->stroke.color_params);
break;
case PDF_MAT_PATTERN:
if (gstate->stroke.pattern)
@@ -838,7 +839,7 @@ pdf_flush_text(fz_context *ctx, pdf_run_processor *pr)
if (gstate->stroke.shade)
{
fz_clip_stroke_text(ctx, pr->dev, text, gstate->stroke_state, &gstate->ctm, &tb);
- fz_fill_shade(ctx, pr->dev, gstate->stroke.shade, &pr->gstate[gstate->stroke.gstate_num].ctm, gstate->stroke.alpha);
+ fz_fill_shade(ctx, pr->dev, gstate->stroke.shade, &pr->gstate[gstate->stroke.gstate_num].ctm, gstate->stroke.alpha, &gstate->stroke.color_params);
fz_pop_clip(ctx, pr->dev);
}
break;
@@ -1085,6 +1086,9 @@ pdf_init_gstate(fz_context *ctx, pdf_gstate *gs, const fz_matrix *ctm)
gs->softmask_resources = NULL;
gs->softmask_ctm = fz_identity;
gs->luminosity = 0;
+
+ gs->fill.color_params = *fz_default_color_params(ctx);
+ gs->stroke.color_params = *fz_default_color_params(ctx);
}
static void
@@ -1133,7 +1137,6 @@ pdf_set_color(fz_context *ctx, pdf_run_processor *pr, int what, float *v)
{
pdf_gstate *gstate = pr->gstate + pr->gtop;
pdf_material *mat;
- int i, n;
gstate = pdf_flush_text(ctx, pr);
@@ -1143,25 +1146,7 @@ pdf_set_color(fz_context *ctx, pdf_run_processor *pr, int what, float *v)
{
case PDF_MAT_PATTERN:
case PDF_MAT_COLOR:
- /* ICC Colorspaces would be handled here too, if we handled them */
- if (fz_colorspace_is_indexed(ctx, mat->colorspace))
- {
- mat->v[0] = fz_clamp(v[0], 0, 1) / 255;
- break;
- }
- else if (fz_colorspace_is_lab(ctx, mat->colorspace))
- {
- n = fz_colorspace_n(ctx, mat->colorspace);
- /* input is in range (0..100, -128..127, -128..127) not (0..1, 0..1, 0..1) */
- for (i = 0; i < n; i++)
- mat->v[i] = fz_clamp(v[i], i ? -128 : 0, i ? 127 : 100);
- }
- else
- {
- n = fz_colorspace_n(ctx, mat->colorspace);
- for (i = 0; i < n; i++)
- mat->v[i] = fz_clamp(v[i], 0, 1);
- }
+ fz_clamp_color(ctx, mat->colorspace, v, mat->v);
break;
default:
fz_warn(ctx, "color incompatible with material");
@@ -1435,6 +1420,44 @@ static void pdf_run_d(fz_context *ctx, pdf_processor *proc, pdf_obj *array, floa
static void pdf_run_ri(fz_context *ctx, pdf_processor *proc, const char *intent)
{
+ pdf_run_processor *pr = (pdf_run_processor *)proc;
+ pdf_gstate *gstate = pdf_flush_text(ctx, pr);
+ gstate->fill.color_params.ri = fz_lookup_rendering_intent(intent);
+ gstate->stroke.color_params.ri = gstate->fill.color_params.ri;
+}
+
+static void pdf_run_gs_OP(fz_context *ctx, pdf_processor *proc, int b)
+{
+ pdf_run_processor *pr = (pdf_run_processor *)proc;
+ pdf_gstate *gstate = pdf_flush_text(ctx, pr);
+ gstate->stroke.color_params.op = b;
+ gstate->fill.color_params.op = b;
+}
+
+static void pdf_run_gs_op(fz_context *ctx, pdf_processor *proc, int b)
+{
+ pdf_run_processor *pr = (pdf_run_processor *)proc;
+ pdf_gstate *gstate = pdf_flush_text(ctx, pr);
+ gstate->fill.color_params.op = b;
+}
+
+static void pdf_run_gs_OPM(fz_context *ctx, pdf_processor *proc, int i)
+{
+ pdf_run_processor *pr = (pdf_run_processor *)proc;
+ pdf_gstate *gstate = pdf_flush_text(ctx, pr);
+ gstate->stroke.color_params.opm = i;
+ gstate->fill.color_params.opm = i;
+}
+
+static void pdf_run_gs_UseBlackPtComp(fz_context *ctx, pdf_processor *proc, pdf_obj *obj)
+{
+ pdf_run_processor *pr = (pdf_run_processor *)proc;
+ pdf_gstate *gstate = pdf_flush_text(ctx, pr);
+ int on = pdf_name_eq(ctx, obj, PDF_NAME_ON);
+ /* The spec says that "ON" means on, "OFF" means "Off", and
+ * "Default" or anything else means "Meh, do what you want." */
+ gstate->stroke.color_params.bp = on;
+ gstate->fill.color_params.bp = on;
}
static void pdf_run_i(fz_context *ctx, pdf_processor *proc, float flatness)
@@ -1491,10 +1514,7 @@ static void pdf_run_gs_SMask(fz_context *ctx, pdf_processor *proc, pdf_xobject *
fz_colorspace *cs = pdf_xobject_colorspace(ctx, smask);
int cs_n = 1;
if (cs)
- {
cs_n = fz_colorspace_n(ctx, cs);
- fz_drop_colorspace(ctx, cs);
- }
gstate->softmask_ctm = gstate->ctm;
gstate->softmask = pdf_keep_xobject(ctx, smask);
gstate->softmask_resources = pdf_keep_obj(ctx, page_resources);
@@ -2149,6 +2169,12 @@ pdf_new_run_processor(fz_context *ctx, fz_device *dev, const fz_matrix *ctm, con
proc->super.op_BX = pdf_run_BX;
proc->super.op_EX = pdf_run_EX;
+ /* extgstate */
+ proc->super.op_gs_OP = pdf_run_gs_OP;
+ proc->super.op_gs_op = pdf_run_gs_op;
+ proc->super.op_gs_OPM = pdf_run_gs_OPM;
+ proc->super.op_gs_UseBlackPtComp = pdf_run_gs_UseBlackPtComp;
+
proc->super.op_END = pdf_run_END;
}
diff --git a/source/pdf/pdf-page.c b/source/pdf/pdf-page.c
index 8f24ef91..f243bdcd 100644
--- a/source/pdf/pdf-page.c
+++ b/source/pdf/pdf-page.c
@@ -676,6 +676,61 @@ pdf_new_page(fz_context *ctx, pdf_document *doc)
return page;
}
+fz_default_colorspaces *
+pdf_load_default_colorspaces(fz_context *ctx, pdf_document *doc, pdf_page *page)
+{
+ pdf_obj *res;
+ pdf_obj *obj;
+ pdf_obj *cs_obj;
+ fz_default_colorspaces *default_cs;
+ fz_colorspace *oi;
+
+ /* If we are doing color management check for internal default color spaces. */
+ /* Photoshop is notorious for doing this in its PDF creation. */
+ if (!fz_colorspace_is_icc(ctx, fz_device_rgb(ctx)))
+ return NULL;
+
+ default_cs = fz_new_default_colorspaces(ctx);
+ res = pdf_page_resources(ctx, page);
+ obj = pdf_dict_get(ctx, res, PDF_NAME_ColorSpace);
+ if (obj)
+ {
+ /* The spec says to ignore any colors we can't understand */
+ fz_try(ctx)
+ {
+ cs_obj = pdf_dict_get(ctx, obj, PDF_NAME_DefaultGray);
+ if (cs_obj)
+ fz_set_default_gray(ctx, default_cs, pdf_load_colorspace(ctx, cs_obj));
+ }
+ fz_catch(ctx)
+ {}
+
+ fz_try(ctx)
+ {
+ cs_obj = pdf_dict_get(ctx, obj, PDF_NAME_DefaultRGB);
+ if (cs_obj)
+ fz_set_default_rgb(ctx, default_cs, pdf_load_colorspace(ctx, cs_obj));
+ }
+ fz_catch(ctx)
+ {}
+
+ fz_try(ctx)
+ {
+ cs_obj = pdf_dict_get(ctx, obj, PDF_NAME_DefaultCMYK);
+ if (cs_obj)
+ fz_set_default_cmyk(ctx, default_cs, pdf_load_colorspace(ctx, cs_obj));
+ }
+ fz_catch(ctx)
+ {}
+ }
+
+ oi = pdf_document_output_intent(ctx, doc);
+ if (oi)
+ fz_set_default_output_intent(ctx, default_cs, oi);
+
+ return default_cs;
+}
+
pdf_page *
pdf_load_page(fz_context *ctx, pdf_document *doc, int number)
{
diff --git a/source/pdf/pdf-run.c b/source/pdf/pdf-run.c
index 4fa1071f..e4a773ba 100644
--- a/source/pdf/pdf-run.c
+++ b/source/pdf/pdf-run.c
@@ -7,6 +7,11 @@ pdf_run_annot_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, pdf
fz_matrix local_ctm, page_ctm;
fz_rect mediabox;
pdf_processor *proc;
+ fz_default_colorspaces *default_cs;
+
+ default_cs = pdf_load_default_colorspaces(ctx, doc, page);
+ if (default_cs)
+ fz_set_default_colorspaces(ctx, dev, default_cs);
pdf_page_transform(ctx, page, &mediabox, &page_ctm);
fz_concat(&local_ctm, &page_ctm, ctm);
@@ -31,6 +36,11 @@ pdf_run_page_contents_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *p
pdf_obj *contents;
fz_rect mediabox;
pdf_processor *proc;
+ fz_default_colorspaces *default_cs;
+
+ default_cs = pdf_load_default_colorspaces(ctx, doc, page);
+ if (default_cs)
+ fz_set_default_colorspaces(ctx, dev, default_cs);
pdf_page_transform(ctx, page, &mediabox, &page_ctm);
fz_concat(&local_ctm, &page_ctm, ctm);
diff --git a/source/pdf/pdf-xref.c b/source/pdf/pdf-xref.c
index 256ebfec..ce62e6b7 100644
--- a/source/pdf/pdf-xref.c
+++ b/source/pdf/pdf-xref.c
@@ -1540,6 +1540,8 @@ pdf_drop_document_imp(fz_context *ctx, pdf_document *doc)
pdf_drop_resource_tables(ctx, doc);
+ fz_drop_colorspace(ctx, doc->oi);
+
for (i = 0; i < doc->orphans_count; i++)
pdf_drop_obj(ctx, doc->orphans[i]);
@@ -2230,6 +2232,7 @@ pdf_new_document(fz_context *ctx, fz_stream *file)
pdf_document *doc = fz_new_derived_document(ctx, pdf_document);
doc->super.drop_document = (fz_document_drop_fn*)pdf_drop_document_imp;
+ doc->super.get_output_intent = (fz_document_output_intent_fn*)pdf_document_output_intent;
doc->super.needs_password = (fz_document_needs_password_fn*)pdf_needs_password;
doc->super.authenticate_password = (fz_document_authenticate_password_fn*)pdf_authenticate_password;
doc->super.has_permission = (fz_document_has_permission_fn*)pdf_has_permission;
diff --git a/source/svg/svg-run.c b/source/svg/svg-run.c
index f02a8aca..f974c675 100644
--- a/source/svg/svg-run.c
+++ b/source/svg/svg-run.c
@@ -39,13 +39,13 @@ static void svg_run_element(fz_context *ctx, fz_device *dev, svg_document *doc,
static void svg_fill(fz_context *ctx, fz_device *dev, svg_document *doc, fz_path *path, svg_state *state)
{
float opacity = state->opacity * state->fill_opacity;
- fz_fill_path(ctx, dev, path, state->fill_rule, &state->transform, fz_device_rgb(ctx), state->fill_color, opacity);
+ fz_fill_path(ctx, dev, path, state->fill_rule, &state->transform, fz_device_rgb(ctx), state->fill_color, opacity, NULL);
}
static void svg_stroke(fz_context *ctx, fz_device *dev, svg_document *doc, fz_path *path, svg_state *state)
{
float opacity = state->opacity * state->stroke_opacity;
- fz_stroke_path(ctx, dev, path, &state->stroke, &state->transform, fz_device_rgb(ctx), state->stroke_color, opacity);
+ fz_stroke_path(ctx, dev, path, &state->stroke, &state->transform, fz_device_rgb(ctx), state->stroke_color, opacity, NULL);
}
static void svg_draw_path(fz_context *ctx, fz_device *dev, svg_document *doc, fz_path *path, svg_state *state)
diff --git a/source/tools/mudraw.c b/source/tools/mudraw.c
index ef95f1d3..aebe441e 100644
--- a/source/tools/mudraw.c
+++ b/source/tools/mudraw.c
@@ -254,6 +254,12 @@ static int files = 0;
static int num_workers = 0;
static worker_t *workers;
+#ifdef NO_ICC
+static fz_cmm_engine *icc_engine = NULL;
+#else
+static fz_cmm_engine *icc_engine = &fz_cmm_engine_lcms;
+#endif
+
static const char *layer_config = NULL;
static struct {
@@ -327,6 +333,7 @@ static void usage(void)
"\t-i\tignore errors\n"
"\t-L\tlow memory mode (avoid caching, clear objects after each page)\n"
"\t-P\tparallel interpretation/rendering\n"
+ "\t-N\tdisable ICC workflow (\"N\"o color management)\n"
"\n"
"\t-y l\tList the layer configs to stderr\n"
"\t-y -\tSelect layer config (by number)\n"
@@ -797,7 +804,9 @@ static void dodrawpage(fz_context *ctx, fz_page *page, fz_display_list *list, in
bander = fz_new_color_pcl_band_writer(ctx, out, NULL);
}
if (bander)
- fz_write_header(ctx, bander, pix->w, totalheight, pix->n, pix->alpha, pix->xres, pix->yres, output_pagenum++);
+ {
+ fz_write_header(ctx, bander, pix->w, totalheight, pix->n, pix->alpha, pix->xres, pix->yres, output_pagenum++, pix->colorspace);
+ }
}
for (band = 0; band < bands; band++)
@@ -1345,10 +1354,11 @@ int mudraw_main(int argc, char **argv)
fz_context *ctx;
fz_alloc_context alloc_ctx = { NULL, trace_malloc, trace_realloc, trace_free };
fz_locks_context *locks = NULL;
+ fz_colorspace *oi = NULL;
fz_var(doc);
- while ((c = fz_getopt(argc, argv, "p:o:F:R:r:w:h:fB:c:G:Is:A:DiW:H:S:T:U:XLvPl:y:")) != -1)
+ while ((c = fz_getopt(argc, argv, "p:o:F:R:r:w:h:fB:c:G:Is:A:DiW:H:S:T:U:XLvPl:y:N")) != -1)
{
switch (c)
{
@@ -1397,6 +1407,7 @@ int mudraw_main(int argc, char **argv)
case 'D': uselist = 0; break;
case 'l': min_line_width = fz_atof(fz_optarg); break;
case 'i': ignore_errors = 1; break;
+ case 'N': icc_engine = NULL; break;
case 'T':
#ifndef DISABLE_MUTHREADS
@@ -1459,6 +1470,7 @@ int mudraw_main(int argc, char **argv)
fz_set_text_aa_level(ctx, alphabits_text);
fz_set_graphics_aa_level(ctx, alphabits_graphics);
fz_set_graphics_min_line_width(ctx, min_line_width);
+ fz_set_cmm_engine(ctx, icc_engine);
#ifndef DISABLE_MUTHREADS
if (bgprint.active)
@@ -1659,6 +1671,17 @@ int mudraw_main(int argc, char **argv)
doc = fz_open_document(ctx, filename);
+ /* Once document is open check for output intent colorspace */
+ oi = fz_document_output_intent(ctx, doc);
+ if (oi)
+ {
+ if (fz_colorspace_n(ctx, oi) == fz_colorspace_n(ctx, colorspace))
+ {
+ fz_drop_colorspace(ctx, colorspace);
+ colorspace = fz_keep_colorspace(ctx, oi);
+ }
+ }
+
if (fz_needs_password(ctx, doc))
{
if (!fz_authenticate_password(ctx, doc, password))
diff --git a/source/tools/muraster.c b/source/tools/muraster.c
index 41d5e3bf..77d60b8f 100644
--- a/source/tools/muraster.c
+++ b/source/tools/muraster.c
@@ -615,7 +615,7 @@ static int dodrawpage(fz_context *ctx, int pagenum, fz_cookie *cookie, render_de
pix = fz_new_pixmap_with_bbox(ctx, colorspace, &ibounds, 0);
fz_set_pixmap_resolution(ctx, pix, x_resolution, y_resolution);
}
- fz_write_header(ctx, render->bander, pix->w, total_height, pix->n, pix->alpha, pix->xres, pix->yres, pagenum);
+ fz_write_header(ctx, render->bander, pix->w, total_height, pix->n, pix->alpha, pix->xres, pix->yres, pagenum, pix->colorspace);
for (band = 0; band < bands; band++)
{
@@ -718,7 +718,7 @@ static int try_render_page(fz_context *ctx, int pagenum, fz_cookie *cookie, int
{
int w = render->ibounds.x1 - render->ibounds.x0;
int h = render->ibounds.y1 - render->ibounds.y0;
- fz_write_header(ctx, render->bander, w, h, render->n, 0, 0, 0, 0);
+ fz_write_header(ctx, render->bander, w, h, render->n, 0, 0, 0, 0, NULL);
}
fz_catch(ctx)
{
diff --git a/source/tools/murun.c b/source/tools/murun.c
index 205e8f91..47cc1884 100644
--- a/source/tools/murun.c
+++ b/source/tools/murun.c
@@ -538,6 +538,18 @@ static struct color ffi_tocolor(js_State *J, int idx)
return c;
}
+static fz_color_params *ffi_tocolorparams(js_State *J, int idx)
+{
+ /* TODO */
+ return NULL;
+}
+
+static void ffi_pushcolorparams(js_State *J, const fz_color_params *color_params)
+{
+ /* TODO */
+ js_pushnull(J);
+}
+
static const char *string_from_cap(fz_linecap cap)
{
switch (cap) {
@@ -771,7 +783,7 @@ typedef struct js_device_s
static void
js_dev_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
js_State *J = ((js_device*)dev)->J;
if (js_try(J))
@@ -782,7 +794,8 @@ js_dev_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_
js_pushboolean(J, even_odd);
ffi_pushmatrix(J, *ctm);
ffi_pushcolor(J, colorspace, color, alpha);
- js_call(J, 6);
+ ffi_pushcolorparams(J, color_params);
+ js_call(J, 7);
js_pop(J, 1);
}
js_endtry(J);
@@ -809,7 +822,7 @@ js_dev_clip_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_
static void
js_dev_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path,
const fz_stroke_state *stroke, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
js_State *J = ((js_device*)dev)->J;
if (js_try(J))
@@ -820,7 +833,8 @@ js_dev_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path,
ffi_pushstroke(J, stroke);
ffi_pushmatrix(J, *ctm);
ffi_pushcolor(J, colorspace, color, alpha);
- js_call(J, 6);
+ ffi_pushcolorparams(J, color_params);
+ js_call(J, 7);
js_pop(J, 1);
}
js_endtry(J);
@@ -846,7 +860,7 @@ js_dev_clip_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, co
static void
js_dev_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
js_State *J = ((js_device*)dev)->J;
if (js_try(J))
@@ -856,7 +870,8 @@ js_dev_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_
ffi_pushtext(J, text);
ffi_pushmatrix(J, *ctm);
ffi_pushcolor(J, colorspace, color, alpha);
- js_call(J, 5);
+ ffi_pushcolorparams(J, color_params);
+ js_call(J, 6);
js_pop(J, 1);
}
js_endtry(J);
@@ -864,7 +879,7 @@ js_dev_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_
static void
js_dev_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke,
- const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha)
+ const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
js_State *J = ((js_device*)dev)->J;
if (js_try(J))
@@ -875,7 +890,8 @@ js_dev_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const f
ffi_pushstroke(J, stroke);
ffi_pushmatrix(J, *ctm);
ffi_pushcolor(J, colorspace, color, alpha);
- js_call(J, 6);
+ ffi_pushcolorparams(J, color_params);
+ js_call(J, 7);
js_pop(J, 1);
}
js_endtry(J);
@@ -932,7 +948,7 @@ js_dev_ignore_text(fz_context *ctx, fz_device *dev, const fz_text *text, const f
}
static void
-js_dev_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha)
+js_dev_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha, const fz_color_params *color_params)
{
js_State *J = ((js_device*)dev)->J;
if (js_try(J))
@@ -942,14 +958,15 @@ js_dev_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_mat
ffi_pushshade(J, shade);
ffi_pushmatrix(J, *ctm);
js_pushnumber(J, alpha);
- js_call(J, 3);
+ ffi_pushcolorparams(J, color_params);
+ js_call(J, 4);
js_pop(J, 1);
}
js_endtry(J);
}
static void
-js_dev_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha)
+js_dev_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha, const fz_color_params *color_params)
{
js_State *J = ((js_device*)dev)->J;
if (js_try(J))
@@ -959,7 +976,8 @@ js_dev_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_mat
ffi_pushimage(J, image);
ffi_pushmatrix(J, *ctm);
js_pushnumber(J, alpha);
- js_call(J, 3);
+ ffi_pushcolorparams(J, color_params);
+ js_call(J, 4);
js_pop(J, 1);
}
js_endtry(J);
@@ -967,7 +985,7 @@ js_dev_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_mat
static void
js_dev_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm,
- fz_colorspace *colorspace, const float *color, float alpha)
+ fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params)
{
js_State *J = ((js_device*)dev)->J;
if (js_try(J))
@@ -977,7 +995,8 @@ js_dev_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const f
ffi_pushimage(J, image);
ffi_pushmatrix(J, *ctm);
ffi_pushcolor(J, colorspace, color, alpha);
- js_call(J, 5);
+ ffi_pushcolorparams(J, color_params);
+ js_call(J, 6);
js_pop(J, 1);
}
js_endtry(J);
@@ -1015,7 +1034,7 @@ js_dev_pop_clip(fz_context *ctx, fz_device *dev)
static void
js_dev_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *bbox, int luminosity,
- fz_colorspace *colorspace, const float *color)
+ fz_colorspace *colorspace, const float *color, const fz_color_params *color_params)
{
js_State *J = ((js_device*)dev)->J;
if (js_try(J))
@@ -1024,14 +1043,9 @@ js_dev_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *bbox, int lumi
js_copy(J, -2);
ffi_pushrect(J, *bbox);
js_pushboolean(J, luminosity);
- if (colorspace) {
- ffi_pushcolorspace(J, colorspace);
- ffi_pusharray(J, color, fz_colorspace_n(ctx, colorspace));
- } else {
- js_pushnull(J);
- js_pushnull(J);
- }
- js_call(J, 4);
+ ffi_pushcolor(J, colorspace, color, 1);
+ ffi_pushcolorparams(J, color_params);
+ js_call(J, 6);
js_pop(J, 1);
}
js_endtry(J);
@@ -1178,8 +1192,9 @@ static void ffi_Device_fillPath(js_State *J)
int even_odd = js_toboolean(J, 2);
fz_matrix ctm = ffi_tomatrix(J, 3);
struct color c = ffi_tocolor(J, 4);
+ fz_color_params *color_params = ffi_tocolorparams(J, 7);
fz_try(ctx)
- fz_fill_path(ctx, dev, path, even_odd, &ctm, c.colorspace, c.color, c.alpha);
+ fz_fill_path(ctx, dev, path, even_odd, &ctm, c.colorspace, c.color, c.alpha, color_params);
fz_catch(ctx)
rethrow(J);
}
@@ -1192,8 +1207,9 @@ static void ffi_Device_strokePath(js_State *J)
fz_stroke_state stroke = ffi_tostroke(J, 2);
fz_matrix ctm = ffi_tomatrix(J, 3);
struct color c = ffi_tocolor(J, 4);
+ fz_color_params *color_params = ffi_tocolorparams(J, 7);
fz_try(ctx)
- fz_stroke_path(ctx, dev, path, &stroke, &ctm, c.colorspace, c.color, c.alpha);
+ fz_stroke_path(ctx, dev, path, &stroke, &ctm, c.colorspace, c.color, c.alpha, color_params);
fz_catch(ctx)
rethrow(J);
}
@@ -1231,8 +1247,9 @@ static void ffi_Device_fillText(js_State *J)
fz_text *text = js_touserdata(J, 1, "fz_text");
fz_matrix ctm = ffi_tomatrix(J, 2);
struct color c = ffi_tocolor(J, 3);
+ fz_color_params *color_params = ffi_tocolorparams(J, 6);
fz_try(ctx)
- fz_fill_text(ctx, dev, text, &ctm, c.colorspace, c.color, c.alpha);
+ fz_fill_text(ctx, dev, text, &ctm, c.colorspace, c.color, c.alpha, color_params);
fz_catch(ctx)
rethrow(J);
}
@@ -1245,8 +1262,9 @@ static void ffi_Device_strokeText(js_State *J)
fz_stroke_state stroke = ffi_tostroke(J, 2);
fz_matrix ctm = ffi_tomatrix(J, 3);
struct color c = ffi_tocolor(J, 4);
+ fz_color_params *color_params = ffi_tocolorparams(J, 7);
fz_try(ctx)
- fz_stroke_text(ctx, dev, text, &stroke, &ctm, c.colorspace, c.color, c.alpha);
+ fz_stroke_text(ctx, dev, text, &stroke, &ctm, c.colorspace, c.color, c.alpha, color_params);
fz_catch(ctx)
rethrow(J);
}
@@ -1295,8 +1313,9 @@ static void ffi_Device_fillShade(js_State *J)
fz_shade *shade = js_touserdata(J, 1, "fz_shade");
fz_matrix ctm = ffi_tomatrix(J, 2);
float alpha = js_tonumber(J, 3);
+ fz_color_params *color_params = ffi_tocolorparams(J, 4);
fz_try(ctx)
- fz_fill_shade(ctx, dev, shade, &ctm, alpha);
+ fz_fill_shade(ctx, dev, shade, &ctm, alpha, color_params);
fz_catch(ctx)
rethrow(J);
}
@@ -1308,8 +1327,9 @@ static void ffi_Device_fillImage(js_State *J)
fz_image *image = js_touserdata(J, 1, "fz_image");
fz_matrix ctm = ffi_tomatrix(J, 2);
float alpha = js_tonumber(J, 3);
+ fz_color_params *color_params = ffi_tocolorparams(J, 4);
fz_try(ctx)
- fz_fill_image(ctx, dev, image, &ctm, alpha);
+ fz_fill_image(ctx, dev, image, &ctm, alpha, color_params);
fz_catch(ctx)
rethrow(J);
}
@@ -1321,8 +1341,9 @@ static void ffi_Device_fillImageMask(js_State *J)
fz_image *image = js_touserdata(J, 1, "fz_image");
fz_matrix ctm = ffi_tomatrix(J, 2);
struct color c = ffi_tocolor(J, 3);
+ fz_color_params *color_params = ffi_tocolorparams(J, 6);
fz_try(ctx)
- fz_fill_image_mask(ctx, dev, image, &ctm, c.colorspace, c.color, c.alpha);
+ fz_fill_image_mask(ctx, dev, image, &ctm, c.colorspace, c.color, c.alpha, color_params);
fz_catch(ctx)
rethrow(J);
}
@@ -1356,8 +1377,9 @@ static void ffi_Device_beginMask(js_State *J)
fz_rect area = ffi_torect(J, 1);
int luminosity = js_toboolean(J, 2);
struct color c = ffi_tocolor(J, 3);
+ fz_color_params *color_params = ffi_tocolorparams(J, 6);
fz_try(ctx)
- fz_begin_mask(ctx, dev, &area, luminosity, c.colorspace, c.color);
+ fz_begin_mask(ctx, dev, &area, luminosity, c.colorspace, c.color, color_params);
fz_catch(ctx)
rethrow(J);
}
@@ -4312,25 +4334,25 @@ int murun_main(int argc, char **argv)
{
jsB_propfun(J, "Device.close", ffi_Device_close, 0);
- jsB_propfun(J, "Device.fillPath", ffi_Device_fillPath, 6);
- jsB_propfun(J, "Device.strokePath", ffi_Device_strokePath, 6);
+ jsB_propfun(J, "Device.fillPath", ffi_Device_fillPath, 7);
+ jsB_propfun(J, "Device.strokePath", ffi_Device_strokePath, 7);
jsB_propfun(J, "Device.clipPath", ffi_Device_clipPath, 3);
jsB_propfun(J, "Device.clipStrokePath", ffi_Device_clipStrokePath, 3);
- jsB_propfun(J, "Device.fillText", ffi_Device_fillText, 5);
- jsB_propfun(J, "Device.strokeText", ffi_Device_strokeText, 6);
+ jsB_propfun(J, "Device.fillText", ffi_Device_fillText, 6);
+ jsB_propfun(J, "Device.strokeText", ffi_Device_strokeText, 7);
jsB_propfun(J, "Device.clipText", ffi_Device_clipText, 2);
jsB_propfun(J, "Device.clipStrokeText", ffi_Device_clipStrokeText, 3);
jsB_propfun(J, "Device.ignoreText", ffi_Device_ignoreText, 2);
- jsB_propfun(J, "Device.fillShade", ffi_Device_fillShade, 3);
- jsB_propfun(J, "Device.fillImage", ffi_Device_fillImage, 3);
- jsB_propfun(J, "Device.fillImageMask", ffi_Device_fillImageMask, 5);
+ jsB_propfun(J, "Device.fillShade", ffi_Device_fillShade, 4);
+ jsB_propfun(J, "Device.fillImage", ffi_Device_fillImage, 4);
+ jsB_propfun(J, "Device.fillImageMask", ffi_Device_fillImageMask, 6);
jsB_propfun(J, "Device.clipImageMask", ffi_Device_clipImageMask, 2);
jsB_propfun(J, "Device.popClip", ffi_Device_popClip, 0);
- jsB_propfun(J, "Device.beginMask", ffi_Device_beginMask, 5); /* should be 4 */
+ jsB_propfun(J, "Device.beginMask", ffi_Device_beginMask, 6);
jsB_propfun(J, "Device.endMask", ffi_Device_endMask, 0);
jsB_propfun(J, "Device.beginGroup", ffi_Device_beginGroup, 5);
jsB_propfun(J, "Device.endGroup", ffi_Device_endGroup, 0);
diff --git a/source/tools/pdfextract.c b/source/tools/pdfextract.c
index 49a2747e..984cda16 100644
--- a/source/tools/pdfextract.c
+++ b/source/tools/pdfextract.c
@@ -42,7 +42,7 @@ static void writepixmap(fz_context *ctx, fz_pixmap *pix, char *file, int dorgb)
if (dorgb && pix->colorspace && pix->colorspace != fz_device_rgb(ctx))
{
- rgb = fz_convert_pixmap(ctx, pix, fz_device_rgb(ctx), 1);
+ rgb = fz_convert_pixmap(ctx, pix, fz_device_rgb(ctx), NULL, NULL, NULL /* FIXME */, 1);
pix = rgb;
}
diff --git a/source/xps/xps-common.c b/source/xps/xps-common.c
index 9e590788..cc7fed94 100644
--- a/source/xps/xps-common.c
+++ b/source/xps/xps-common.c
@@ -109,7 +109,7 @@ xps_begin_opacity(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, cons
if (opacity_mask_tag)
{
- fz_begin_mask(ctx, dev, area, 0, NULL, NULL);
+ fz_begin_mask(ctx, dev, area, 0, NULL, NULL, NULL);
xps_parse_brush(ctx, doc, ctm, area, base_uri, dict, opacity_mask_tag);
fz_end_mask(ctx, dev);
}
diff --git a/source/xps/xps-glyphs.c b/source/xps/xps-glyphs.c
index bfe38432..55a8a362 100644
--- a/source/xps/xps-glyphs.c
+++ b/source/xps/xps-glyphs.c
@@ -610,7 +610,7 @@ xps_parse_glyphs(fz_context *ctx, xps_document *doc, const fz_matrix *ctm,
xps_set_color(ctx, doc, colorspace, samples);
fz_fill_text(ctx, dev, text, &local_ctm,
- doc->colorspace, doc->color, doc->alpha);
+ doc->colorspace, doc->color, doc->alpha, NULL);
}
/* If it's a complex brush, use the charpath as a clip mask */
diff --git a/source/xps/xps-gradient.c b/source/xps/xps-gradient.c
index a7a7cf44..349132d5 100644
--- a/source/xps/xps-gradient.c
+++ b/source/xps/xps-gradient.c
@@ -68,7 +68,7 @@ xps_parse_gradient_stops(fz_context *ctx, xps_document *doc, char *base_uri, fz_
xps_parse_color(ctx, doc, base_uri, color, &colorspace, sample);
- fz_convert_color(ctx, fz_device_rgb(ctx), rgb, colorspace, sample + 1);
+ fz_convert_color(ctx, fz_default_color_params(ctx), NULL, fz_device_rgb(ctx), rgb, colorspace, sample + 1);
stops[count].r = rgb[0];
stops[count].g = rgb[1];
@@ -240,7 +240,7 @@ xps_draw_one_radial_gradient(fz_context *ctx, xps_document *doc, const fz_matrix
shade->u.l_or_r.coords[1][1] = y1;
shade->u.l_or_r.coords[1][2] = r1;
- fz_fill_shade(ctx, dev, shade, ctm, 1);
+ fz_fill_shade(ctx, dev, shade, ctm, 1, fz_default_color_params(ctx));
fz_drop_shade(ctx, shade);
}
@@ -279,7 +279,7 @@ xps_draw_one_linear_gradient(fz_context *ctx, xps_document *doc, const fz_matrix
shade->u.l_or_r.coords[1][1] = y1;
shade->u.l_or_r.coords[1][2] = 0;
- fz_fill_shade(ctx, dev, shade, ctm, doc->opacity[doc->opacity_top]);
+ fz_fill_shade(ctx, dev, shade, ctm, doc->opacity[doc->opacity_top], fz_default_color_params(ctx));
fz_drop_shade(ctx, shade);
}
diff --git a/source/xps/xps-image.c b/source/xps/xps-image.c
index 2996b4ee..9408c528 100644
--- a/source/xps/xps-image.c
+++ b/source/xps/xps-image.c
@@ -23,7 +23,7 @@ xps_paint_image_brush(fz_context *ctx, xps_document *doc, const fz_matrix *ctm,
xs = image->w * 96 / image->xres;
ys = image->h * 96 / image->yres;
fz_pre_scale(&local_ctm, xs, ys);
- fz_fill_image(ctx, doc->dev, image, &local_ctm, doc->opacity[doc->opacity_top]);
+ fz_fill_image(ctx, doc->dev, image, &local_ctm, doc->opacity[doc->opacity_top], fz_default_color_params(ctx));
}
static void
diff --git a/source/xps/xps-path.c b/source/xps/xps-path.c
index c60934a2..c9bd64e0 100644
--- a/source/xps/xps-path.c
+++ b/source/xps/xps-path.c
@@ -1002,7 +1002,7 @@ xps_parse_path(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, char *b
xps_set_color(ctx, doc, colorspace, samples);
fz_fill_path(ctx, dev, path, fill_rule == 0, &local_ctm,
- doc->colorspace, doc->color, doc->alpha);
+ doc->colorspace, doc->color, doc->alpha, NULL);
}
if (fill_tag)
@@ -1020,7 +1020,7 @@ xps_parse_path(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, char *b
xps_set_color(ctx, doc, colorspace, samples);
fz_stroke_path(ctx, dev, stroke_path, stroke, &local_ctm,
- doc->colorspace, doc->color, doc->alpha);
+ doc->colorspace, doc->color, doc->alpha, NULL);
}
if (stroke_tag)