1
/* Copyright (C) 2001-2012 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied,
8
modified or distributed except as expressly authorized under the terms
9
of the license contained in the file LICENSE in this distribution.
11
Refer to licensing information at http://www.artifex.com or contact
12
Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13
CA 94903, U.S.A., +1(415)492-9861, for further information.
17
/* Color value writing for pdfwrite driver */
23
#include "gsiparm3.h" /* for pattern colors */
24
#include "gsmatrix.h" /* for gspcolor.h */
25
#include "gscoord.h" /* for gs_currentmatrix, requires gsmatrix.h */
27
#include "gxcolor2.h" /* for gxpcolor.h */
28
#include "gxdcolor.h" /* for gxpcolor.h */
29
#include "gxpcolor.h" /* for pattern device color types */
35
/* Import the PatternType 2 Pattern device color type. */
36
extern const gx_device_color_type_t gx_dc_pattern2;
39
* Define the scaling and range of values written for mesh shadings.
40
* BitsPerCoordinate is always 24; BitsPerComponent (for colors) is
43
#define ENCODE_VALUE(v, emax, vmin, vmax)\
44
( ((v) - (vmin)) * ((double)(emax) / ((vmax) - (vmin))) )
46
* Because of the Acrobat Reader limitation noted in gdevpdfx.h,
47
* we must limit coordinate values to 14 bits.
49
#define MIN_MESH_COORDINATE (-0x400000 / 256.0)
50
#define MAX_MESH_COORDINATE ( 0x3fffff / 256.0)
51
#define ENCODE_MESH_COORDINATE(v)\
52
ENCODE_VALUE(v, 0xffffff, MIN_MESH_COORDINATE, MAX_MESH_COORDINATE)
54
#define MIN_MESH_COLOR_INDEX 0
55
#define MAX_MESH_COLOR_INDEX 0xffff
56
#define ENCODE_MESH_COLOR_INDEX(v) ((v) + MIN_MESH_COLOR_INDEX)
58
#define ENCODE_MESH_COMPONENT(v, vmin, vmax)\
59
ENCODE_VALUE(v, 0xffff, vmin, vmax)
61
/* ---------------- Utilities ---------------- */
63
/* Write a matrix parameter. */
65
cos_dict_put_matrix(cos_dict_t *pscd, const char *key, const gs_matrix *pmat)
75
return cos_dict_put_c_key_floats(pscd, key, matrix, 6);
78
/* ---------------- PatternType 1 colors ---------------- */
81
* Create a Pattern resource referencing an image (currently only an XObject).
82
* p_tile is NULL for uncolored patterns or the NULL pattern.
83
* m_tile is NULL for colored patterns that fill their bounding box,
84
* including the NULL pattern.
85
****** WE DON'T HANDLE NULL PATTERNS YET ******
88
tile_size(const gx_strip_bitmap *tile, int depth)
90
return (tile->rep_width * depth + 7) / 8 * tile->rep_height;
93
tile_size_ok(const gx_device_pdf *pdev, const gx_color_tile *p_tile,
94
const gx_color_tile *m_tile)
97
* Acrobat Reader can't handle image Patterns with more than
101
(p_tile == 0 ? 0 : tile_size(&p_tile->tbits, p_tile->depth));
103
(m_tile == 0 ? 0 : tile_size(&m_tile->tmask, 1));
104
/* The image limit only applies to Acrobat versions less than 5
107
if (pdev->CompatibilityLevel < 1.4)
108
return (max(p_size, m_size) <= 65500);
114
pdf_pattern(gx_device_pdf *pdev, const gx_drawing_color *pdc,
115
const gx_color_tile *p_tile, const gx_color_tile *m_tile,
116
cos_stream_t *pcs_image, pdf_resource_t **ppres)
118
pdf_resource_t *pres;
119
int code = pdf_alloc_resource(pdev, resourcePattern, pdc->mask.id, ppres,
123
cos_dict_t *pcd_Resources = cos_dict_alloc(pdev, "pdf_pattern(Resources)");
124
const gx_color_tile *tile = (p_tile ? p_tile : m_tile);
125
const gx_strip_bitmap *btile = (p_tile ? &p_tile->tbits : &m_tile->tmask);
126
bool mask = p_tile == 0;
132
if (!tile_size_ok(pdev, p_tile, m_tile))
133
return_error(gs_error_limitcheck);
135
* We currently can't handle Patterns whose X/Y step isn't parallel
136
* to the coordinate axes.
138
if (is_xxyy(&tile->step_matrix))
139
step.x = tile->step_matrix.xx, step.y = tile->step_matrix.yy;
140
else if (is_xyyx(&tile->step_matrix))
141
step.x = tile->step_matrix.yx, step.y = tile->step_matrix.xy;
143
return_error(gs_error_rangecheck);
144
if (pcd_Resources == 0)
145
return_error(gs_error_VMerror);
146
gs_make_identity(&smat);
147
smat.xx = btile->rep_width / (pdev->HWResolution[0] / 72.0);
148
smat.yy = btile->rep_height / (pdev->HWResolution[1] / 72.0);
149
smat.tx = tile->step_matrix.tx / (pdev->HWResolution[0] / 72.0);
150
smat.ty = tile->step_matrix.ty / (pdev->HWResolution[1] / 72.0);
153
cos_dict_t *pcd_XObject = cos_dict_alloc(pdev, "pdf_pattern(XObject)");
154
char key[MAX_REF_CHARS + 3];
156
cos_object_t *object;
158
if (pcd_XObject == 0)
159
return_error(gs_error_VMerror);
160
sprintf(key, "/R%ld", pcs_image->id);
161
/* This is non-obvious code. Previously we would put the image object (pcs_image)
162
* into the Resources dit. When we come to write out the Resources dict
163
* that code writes a reference (index 0 R) using the ID from the object.
164
* However that means we have two pointers to the XObject. One in the chain
165
* of resoruces (which we need in order to write teh XObject) and one from
166
* the pattern here. That seriously messes up memory handling. So instead
167
* we now make a new object, and copy the id from the pcs_image. Since that's
168
* all that the writing code will use, we cna avoid the double pointers.
170
object = cos_reference_alloc(pdev, "pdf_pattern(reference copy of XObject)");
171
object->id = pcs_image->id;
172
COS_OBJECT_VALUE(&v, object);
173
if ((code = cos_dict_put(pcd_XObject, (byte *)key, strlen(key), &v)) < 0 ||
174
(code = cos_dict_put_c_key_object(pcd_Resources, "/XObject",
175
COS_OBJECT(pcd_XObject))) < 0
179
if ((code = cos_dict_put_c_strings(pcd_Resources, "/ProcSet",
180
(mask ? "[/PDF/ImageB]" :
181
"[/PDF/ImageC]"))) < 0)
183
cos_become(pres->object, cos_type_stream);
184
pcos = (cos_stream_t *)pres->object;
185
pcd = cos_stream_dict(pcos);
186
if ((code = cos_dict_put_c_key_int(pcd, "/PatternType", 1)) < 0 ||
187
(code = cos_dict_put_c_key_int(pcd, "/PaintType",
188
(mask ? 2 : 1))) < 0 ||
189
(code = cos_dict_put_c_key_int(pcd, "/TilingType",
190
tile->tiling_type)) < 0 ||
191
(code = cos_dict_put_c_key_object(pcd, "/Resources",
192
COS_OBJECT(pcd_Resources))) < 0 ||
193
(code = cos_dict_put_c_strings(pcd, "/BBox", "[0 0 1 1]")) < 0 ||
194
(code = cos_dict_put_matrix(pcd, "/Matrix", &smat)) < 0 ||
195
(code = cos_dict_put_c_key_real(pcd, "/XStep", step.x / btile->rep_width)) < 0 ||
196
(code = cos_dict_put_c_key_real(pcd, "/YStep", step.y / btile->rep_height)) < 0
202
char buf[MAX_REF_CHARS + 6 + 1]; /* +6 for /R# Do\n */
204
sprintf(buf, "/R%ld Do\n", pcs_image->id);
205
cos_stream_add_bytes(pcos, (const byte *)buf, strlen(buf));
211
/* Store pattern 1 parameters to cos dictionary. */
213
pdf_store_pattern1_params(gx_device_pdf *pdev, pdf_resource_t *pres,
214
gs_pattern1_instance_t *pinst)
216
gs_pattern1_template_t *t = &pinst->templat;
217
gs_matrix smat2 = ctm_only((gs_imager_state *)pinst->saved), smat;
218
double scale_x = pdev->HWResolution[0] / 72.0;
219
double scale_y = pdev->HWResolution[1] / 72.0;
220
cos_dict_t *pcd = cos_stream_dict((cos_stream_t *)pres->object);
221
cos_dict_t *pcd_Resources = cos_dict_alloc(pdev, "pdf_pattern(Resources)");
225
if (pcd == NULL || pcd_Resources == NULL)
226
return_error(gs_error_VMerror);
227
pdev->substream_Resources = pcd_Resources;
228
bbox[0] = t->BBox.p.x;
229
bbox[1] = t->BBox.p.y;
230
bbox[2] = t->BBox.q.x;
231
bbox[3] = t->BBox.q.y;
232
/* The graphics library assumes a shifted origin to provide
233
positive bitmap pixel indices. Compensate it now. */
234
smat2.tx += pinst->step_matrix.tx;
235
smat2.ty += pinst->step_matrix.ty;
237
* In PDF, the Matrix is the transformation from the pattern space to
238
* the *default* user coordinate space, not the current space.
239
* NB. For a form the default space is the parent. This means that when a
240
* form is nested inside a form, the default space is the space of the
241
* first form, and therefore we do *not* remove the resolution scaling.
243
if (pdev->FormDepth == 0) {
246
gs_make_scaling(1 / scale_x, 1 / scale_y, &scaled);
247
gs_matrix_multiply(&smat2, &scaled, &smat);
251
if (pdev->ForOPDFRead) {
252
if (pdev->PatternDepth) {
253
gs_matrix_multiply(&smat, &pdev->AccumulatedPatternMatrix, &smat2);
254
gs_matrix_multiply(&pdev->AccumulatedPatternMatrix, &smat, &pdev->AccumulatedPatternMatrix);
257
gs_make_identity(&pdev->AccumulatedPatternMatrix);
258
gs_matrix_multiply(&pdev->AccumulatedPatternMatrix, &smat, &pdev->AccumulatedPatternMatrix);
261
if (any_abs(smat.tx) < 0.0001) /* Noise. */
263
if (any_abs(smat.ty) < 0.0001)
265
code = cos_dict_put_c_strings(pcd, "/Type", "/Pattern");
267
code = cos_dict_put_c_key_int(pcd, "/PatternType", 1);
269
code = cos_dict_put_c_key_int(pcd, "/PaintType", t->PaintType);
271
code = cos_dict_put_c_key_int(pcd, "/TilingType", t->TilingType);
273
code = cos_dict_put_c_key_floats(pcd, "/BBox", bbox, 4);
275
code = cos_dict_put_matrix(pcd, "/Matrix", &smat);
277
code = cos_dict_put_c_key_real(pcd, "/XStep", t->XStep);
279
code = cos_dict_put_c_key_real(pcd, "/YStep", t->YStep);
281
code = cos_dict_put_c_key_object(pcd, "/Resources", COS_OBJECT(pcd_Resources));
282
pdev->skip_colors = (t->PaintType == 2);
286
/* Set the ImageMatrix, Width, and Height for a Pattern image. */
288
pdf_set_pattern_image(gs_data_image_t *pic, const gx_strip_bitmap *tile)
290
pic->ImageMatrix.xx = (float)(pic->Width = tile->rep_width);
291
pic->ImageMatrix.yy = (float)(pic->Height = tile->rep_height);
294
/* Write the mask for a Pattern (colored or uncolored). */
296
pdf_put_pattern_mask(gx_device_pdf *pdev, const gx_color_tile *m_tile,
297
cos_stream_t **ppcs_mask)
299
int w = m_tile->tmask.rep_width, h = m_tile->tmask.rep_height;
301
pdf_image_writer writer;
304
gs_image_t_init_mask_adjust(&image, true, false);
305
pdf_set_pattern_image((gs_data_image_t *)&image, &m_tile->tmask);
306
pdf_image_writer_init(&writer);
307
if ((code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, false)) < 0 ||
308
(pdev->params.MonoImage.Encode &&
309
(code = psdf_CFE_binary(&writer.binary[0], w, h, true)) < 0) ||
310
(code = pdf_begin_image_data(pdev, &writer, (const gs_pixel_image_t *)&image, NULL, 0)) < 0
313
/* Pattern masks are specified in device coordinates, so invert Y. */
314
if ((code = pdf_copy_mask_bits(writer.binary[0].strm, m_tile->tmask.data + (h - 1) * m_tile->tmask.raster, 0, -m_tile->tmask.raster, w, h, 0)) < 0 ||
315
(code = pdf_end_image_binary(pdev, &writer, h)) < 0 ||
316
(code = pdf_end_write_image(pdev, &writer)) < 0
319
*ppcs_mask = (cos_stream_t *)writer.pres->object;
323
/* Write an uncolored Pattern color. */
325
pdf_put_uncolored_pattern(gx_device_pdf *pdev, const gx_drawing_color *pdc,
326
const gs_color_space *pcs,
327
const psdf_set_color_commands_t *ppscc,
328
bool have_pattern_streams, pdf_resource_t **ppres)
330
const gx_color_tile *m_tile = pdc->mask.m_tile;
331
gx_drawing_color dc_pure;
333
if (!have_pattern_streams && m_tile == 0) {
335
* If m_tile == 0, this uncolored Pattern is all 1's,
336
* equivalent to a pure color.
339
set_nonclient_dev_color(&dc_pure, gx_dc_pure_color(pdc));
340
return psdf_set_color((gx_device_vector *)pdev, &dc_pure, ppscc);
343
stream *s = pdev->strm;
345
cos_stream_t *pcs_image;
346
static const psdf_set_color_commands_t no_scc = {0, 0, 0};
348
if (!tile_size_ok(pdev, NULL, m_tile))
349
return_error(gs_error_limitcheck);
350
if (!have_pattern_streams) {
351
if ((code = pdf_cs_Pattern_uncolored(pdev, &v)) < 0 ||
352
(code = pdf_put_pattern_mask(pdev, m_tile, &pcs_image)) < 0 ||
353
(code = pdf_pattern(pdev, pdc, NULL, m_tile, pcs_image, ppres)) < 0
357
code = pdf_cs_Pattern_uncolored_hl(pdev, pcs, &v);
360
*ppres = pdf_find_resource_by_gs_id(pdev, resourcePattern, pdc->mask.id);
361
*ppres = pdf_substitute_pattern(*ppres);
362
if (!pdev->AR4_save_bug && pdev->CompatibilityLevel <= 1.3) {
363
/* We reconnized AR4 behavior as reserving "q Q" stack elements
364
* on demand. It looks as processing a pattern stream
365
* with PaintType 1 AR4 replaces the topmost stack element
366
* instead allocating a new one, if it was not previousely allocated.
367
* AR 5 doesn't have this bug. Working around the AR4 bug here.
369
stream_puts(pdev->strm, "q q Q Q\n");
370
pdev->AR4_save_bug = true;
372
(*ppres)->where_used |= pdev->used_mask;
374
cos_value_write(&v, pdev);
375
pprints1(s, " %s ", ppscc->setcolorspace);
376
if (have_pattern_streams)
378
set_nonclient_dev_color(&dc_pure, gx_dc_pure_color(pdc));
379
return psdf_set_color((gx_device_vector *)pdev, &dc_pure, &no_scc);
384
pdf_put_colored_pattern(gx_device_pdf *pdev, const gx_drawing_color *pdc,
385
const gs_color_space *pcs,
386
const psdf_set_color_commands_t *ppscc,
387
bool have_pattern_streams, pdf_resource_t **ppres)
389
const gx_color_tile *p_tile = pdc->colors.pattern.p_tile;
390
gs_color_space *pcs_Device;
391
cos_value_t cs_value;
395
const gx_color_tile *m_tile = NULL;
396
pdf_image_writer writer;
397
int w = p_tile->tbits.rep_width, h = p_tile->tbits.rep_height;
399
if (!have_pattern_streams) {
401
* NOTE: We assume here that the color space of the cached Pattern
402
* is the same as the native color space of the device. This will
403
* have to change in the future!
406
* Check whether this colored pattern is actually a masked pure color,
407
* by testing whether all the colored pixels have the same color.
409
m_tile = pdc->mask.m_tile;
411
if (p_tile && !(p_tile->depth & 7) && p_tile->depth <= arch_sizeof_color_index * 8) {
412
int depth_bytes = p_tile->depth >> 3;
413
int width = p_tile->tbits.rep_width;
414
int skip = p_tile->tbits.raster -
415
p_tile->tbits.rep_width * depth_bytes;
419
gx_color_index color = 0; /* init is arbitrary if not empty */
422
for (i = 0, bp = p_tile->tbits.data, mp = p_tile->tmask.data;
423
i < p_tile->tbits.rep_height;
424
++i, bp += skip, mp += p_tile->tmask.raster) {
426
for (j = 0; j < width; ++j) {
427
if (mp[j >> 3] & (0x80 >> (j & 7))) {
428
gx_color_index ci = 0;
430
for (k = 0; k < depth_bytes; ++k)
431
ci = (ci << 8) + *bp++;
433
color = ci, first = false;
434
else if (ci != color)
441
/* Set the color, then handle as an uncolored pattern. */
442
gx_drawing_color dcolor;
445
dcolor.colors.pure = color;
446
return pdf_put_uncolored_pattern(pdev, &dcolor, pcs, ppscc,
447
have_pattern_streams, ppres);
450
DO_NOTHING; /* required by MSVC */
452
if (pdev->CompatibilityLevel < 1.3) {
453
/* Masked images are only supported starting in PDF 1.3. */
454
return_error(gs_error_rangecheck);
457
/* Acrobat Reader has a size limit for image Patterns. */
458
if (!tile_size_ok(pdev, p_tile, m_tile))
459
return_error(gs_error_limitcheck);
461
code = pdf_cs_Pattern_colored(pdev, &v);
464
pdf_cspace_init_Device(pdev->memory, &pcs_Device, pdev->color_info.num_components);
466
* We don't have to worry about color space scaling: the color
467
* space is always a Device space.
469
code = pdf_color_space_named(pdev, &cs_value, NULL, pcs_Device,
470
&pdf_color_space_names, true, NULL, 0);
473
if (!have_pattern_streams) {
474
cos_stream_t *pcs_mask = 0;
475
cos_stream_t *pcs_image;
477
gs_image_t_init_adjust(&image, pcs_Device, false);
478
image.BitsPerComponent = 8;
479
pdf_set_pattern_image((gs_data_image_t *)&image, &p_tile->tbits);
481
if ((code = pdf_put_pattern_mask(pdev, m_tile, &pcs_mask)) < 0)
484
pdf_image_writer_init(&writer);
485
pdev->ParamCompatibilityLevel = pdev->CompatibilityLevel;
486
if ((code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, false)) < 0 ||
487
(code = psdf_setup_lossless_filters((gx_device_psdf *)pdev,
489
(gs_pixel_image_t *)&image, false)) < 0 ||
490
(code = pdf_begin_image_data(pdev, &writer, (const gs_pixel_image_t *)&image, &cs_value, 0)) < 0
493
/* Pattern masks are specified in device coordinates, so invert Y. */
494
if ((code = pdf_copy_color_bits(writer.binary[0].strm, p_tile->tbits.data + (h - 1) * p_tile->tbits.raster, 0, -p_tile->tbits.raster, w, h, pdev->color_info.depth >> 3)) < 0 ||
495
(code = pdf_end_image_binary(pdev, &writer, h)) < 0
498
pcs_image = (cos_stream_t *)writer.pres->object;
499
if ((pcs_mask != 0 &&
500
(code = cos_dict_put_c_key_object(cos_stream_dict(pcs_image), "/Mask",
501
COS_OBJECT(pcs_mask))) < 0) ||
502
(code = pdf_end_write_image(pdev, &writer)) < 0
505
pcs_image = (cos_stream_t *)writer.pres->object; /* pdf_end_write_image may change it. */
506
code = pdf_pattern(pdev, pdc, p_tile, m_tile, pcs_image, ppres);
510
*ppres = pdf_find_resource_by_gs_id(pdev, resourcePattern, p_tile->id);
511
*ppres = pdf_substitute_pattern(*ppres);
512
(*ppres)->where_used |= pdev->used_mask;
514
/* pcs_Device will leak (picked up by GC in PS) on error, but we'll
515
tolerate that for now. */
516
rc_decrement_cs(pcs_Device, "pdf_put_colored_pattern");
517
cos_value_write(&v, pdev);
518
pprints1(pdev->strm, " %s", ppscc->setcolorspace);
522
/* ---------------- PatternType 2 colors ---------------- */
524
/* Write parameters common to all Shadings. */
526
pdf_put_shading_common(cos_dict_t *pscd, const gs_shading_t *psh,
527
bool shfill, const gs_range_t **ppranges)
529
gs_shading_type_t type = ShadingType(psh);
530
const gs_color_space *pcs = psh->params.ColorSpace;
531
int code = cos_dict_put_c_key_int(pscd, "/ShadingType", (int)type);
532
cos_value_t cs_value;
535
(psh->params.AntiAlias &&
536
(code = cos_dict_put_c_strings(pscd, "/AntiAlias", "true")) < 0) ||
537
(code = pdf_color_space_named(pscd->pdev, &cs_value, ppranges, pcs,
538
&pdf_color_space_names, false, NULL, 0)) < 0 ||
539
(code = cos_dict_put_c_key(pscd, "/ColorSpace", &cs_value)) < 0
542
if (psh->params.Background && !shfill) {
543
/****** SCALE Background ******/
544
code = cos_dict_put_c_key_floats(pscd, "/Background",
545
psh->params.Background->paint.values,
546
gs_color_space_num_components(pcs));
550
if (psh->params.have_BBox) {
553
bbox[0] = psh->params.BBox.p.x;
554
bbox[1] = psh->params.BBox.p.y;
555
bbox[2] = psh->params.BBox.q.x;
556
bbox[3] = psh->params.BBox.q.y;
557
code = cos_dict_put_c_key_floats(pscd, "/BBox", bbox, 4);
564
/* Write an optional Function parameter. */
566
pdf_put_shading_Function(cos_dict_t *pscd, const gs_function_t *pfn,
567
const gs_range_t *pranges)
572
cos_value_t fn_value;
574
if ((code = pdf_function_scaled(pscd->pdev, pfn, pranges, &fn_value)) >= 0)
575
code = cos_dict_put_c_key(pscd, "/Function", &fn_value);
580
/* Write a linear (Axial / Radial) Shading. */
582
pdf_put_linear_shading(cos_dict_t *pscd, const float *Coords,
583
int num_coords, const float *Domain /*[2]*/,
584
const gs_function_t *Function,
585
const bool *Extend /*[2]*/,
586
const gs_range_t *pranges)
588
int code = cos_dict_put_c_key_floats(pscd, "/Coords", Coords, num_coords);
591
((Domain[0] != 0 || Domain[1] != 1) &&
592
(code = cos_dict_put_c_key_floats(pscd, "/Domain", Domain, 2)) < 0) ||
593
(code = pdf_put_shading_Function(pscd, Function, pranges)) < 0
596
if (Extend[0] | Extend[1]) {
597
char extend_str[1 + 5 + 1 + 5 + 1 + 1]; /* [bool bool] */
599
sprintf(extend_str, "[%s %s]",
600
(Extend[0] ? "true" : "false"),
601
(Extend[1] ? "true" : "false"));
602
code = cos_dict_put_c_key_string(pscd, "/Extend",
603
(const byte *)extend_str,
609
/* Write a scalar (non-mesh) Shading. */
610
/* (Single-use procedure for readability.) */
612
pdf_put_scalar_shading(cos_dict_t *pscd, const gs_shading_t *psh,
613
const gs_range_t *pranges)
617
switch (ShadingType(psh)) {
618
case shading_type_Function_based: {
619
const gs_shading_Fb_params_t *const params =
620
(const gs_shading_Fb_params_t *)&psh->params;
622
if ((code = cos_dict_put_c_key_floats(pscd, "/Domain", params->Domain, 4)) < 0 ||
623
(code = pdf_put_shading_Function(pscd, params->Function, pranges)) < 0 ||
624
(code = cos_dict_put_matrix(pscd, "/Matrix", ¶ms->Matrix)) < 0
629
case shading_type_Axial: {
630
const gs_shading_A_params_t *const params =
631
(const gs_shading_A_params_t *)&psh->params;
633
return pdf_put_linear_shading(pscd, params->Coords, 4,
634
params->Domain, params->Function,
635
params->Extend, pranges);
637
case shading_type_Radial: {
638
const gs_shading_R_params_t *const params =
639
(const gs_shading_R_params_t *)&psh->params;
641
return pdf_put_linear_shading(pscd, params->Coords, 6,
642
params->Domain, params->Function,
643
params->Extend, pranges);
646
return_error(gs_error_rangecheck);
650
/* Add a floating point range to an array. */
652
pdf_array_add_real2(cos_array_t *pca, floatp lower, floatp upper)
654
int code = cos_array_add_real(pca, lower);
657
code = cos_array_add_real(pca, upper);
661
/* Define a parameter structure for mesh data. */
662
typedef struct pdf_mesh_data_params_s {
666
const float *Domain; /* iff Function */
667
const gs_range_t *ranges;
668
} pdf_mesh_data_params_t;
670
/* Put a clamped value into a data stream. num_bytes < sizeof(int). */
672
put_clamped(byte *p, floatp v, int num_bytes)
674
int limit = 1 << (num_bytes * 8);
683
for (shift = (num_bytes - 1) * 8; shift >= 0; shift -= 8)
684
*p++ = (byte)(i >> shift);
687
put_clamped_coord(byte *p, floatp v, int num_bytes)
689
put_clamped(p, ENCODE_MESH_COORDINATE(v), num_bytes);
692
/* Convert floating-point mesh data to packed binary. */
693
/* BitsPerFlag = 8, BitsPerCoordinate = 24, BitsPerComponent = 16, */
694
/* scaling is as defined below. */
696
put_float_mesh_data(cos_stream_t *pscs, shade_coord_stream_t *cs,
697
int flag, const pdf_mesh_data_params_t *pmdp)
699
int num_points = pmdp->num_points;
700
byte b[1 + (3 + 3) * 16]; /* flag + x + y or c */
701
gs_fixed_point pts[16];
702
const float *domain = pmdp->Domain;
703
const gs_range_t *pranges = pmdp->ranges;
706
b[0] = (byte)flag; /* may be -1 */
707
if ((code = shade_next_coords(cs, pts, num_points)) < 0)
709
for (i = 0; i < num_points; ++i) {
710
put_clamped_coord(b + 1 + i * 6, fixed2float(pts[i].x), 3);
711
put_clamped_coord(b + 4 + i * 6, fixed2float(pts[i].y), 3);
713
if ((code = cos_stream_add_bytes(pscs, b + (flag < 0),
714
(flag >= 0) + num_points * 6)) < 0)
716
for (i = 0; i < pmdp->num_components; ++i) {
720
cs->get_decoded(cs, 0, NULL, &c);
721
if (pmdp->is_indexed)
722
v = ENCODE_MESH_COLOR_INDEX(c);
725
* We don't rescale stream data values, only the Decode ranges.
726
* (We do have to rescale data values from an array, unless
727
* they are the input parameter for a Function.)
728
* This makes everything come out as it should.
733
vmin = domain[2 * i], vmax = domain[2 * i + 1];
735
vmin = 0.0, vmax = 1.0;
737
double base = pranges[i].rmin, factor = pranges[i].rmax - base;
739
vmin = vmin * factor + base;
740
vmax = vmax * factor + base;
742
v = ENCODE_MESH_COMPONENT(c, vmin, vmax);
744
put_clamped(b, v, 2);
745
if ((code = cos_stream_add_bytes(pscs, b, 2)) < 0)
751
/* Write a mesh Shading. */
753
pdf_put_mesh_shading(cos_stream_t *pscs, const gs_shading_t *psh,
754
const gs_range_t *pranges)
756
cos_dict_t *const pscd = cos_stream_dict(pscs);
757
gs_color_space *pcs = psh->params.ColorSpace;
758
const gs_shading_mesh_params_t *const pmp =
759
(const gs_shading_mesh_params_t *)&psh->params;
761
int bits_per_coordinate, bits_per_component, bits_per_flag;
763
bool from_array = data_source_is_array(pmp->DataSource);
764
pdf_mesh_data_params_t data_params;
765
shade_coord_stream_t cs;
766
gs_matrix_fixed ctm_ident;
770
data_params.Domain = 0;
773
data_params.Domain = (pmp->Decode != 0 ? pmp->Decode + 4 : NULL);
774
num_comp = gs_color_space_num_components(pcs);
776
data_params.ranges = pranges;
778
/* Write parameters common to all mesh Shadings. */
779
shade_next_init(&cs, pmp, NULL);
781
cos_array_t *pca = cos_array_alloc(pscd->pdev, "pdf_put_mesh_shading");
785
return_error(gs_error_VMerror);
786
for (i = 0; i < 2; ++i)
787
if ((code = pdf_array_add_real2(pca, MIN_MESH_COORDINATE,
788
MAX_MESH_COORDINATE)) < 0)
790
data_params.is_indexed = false;
791
if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed) {
792
data_params.is_indexed = true;
793
if ((code = pdf_array_add_real2(pca, MIN_MESH_COLOR_INDEX,
794
MAX_MESH_COLOR_INDEX)) < 0)
797
for (i = 0; i < num_comp; ++i) {
800
if (pmp->Function || pranges || data_params.Domain == 0)
801
rmin = 0.0, rmax = 1.0;
803
rmin = data_params.Domain[2 * i],
804
rmax = data_params.Domain[2 * i + 1];
806
pdf_array_add_real2(pca, rmin, rmax)) < 0)
810
code = cos_dict_put_c_key_object(pscd, "/Decode", COS_OBJECT(pca));
813
bits_per_coordinate = 24;
814
bits_per_component = 16;
816
gs_make_identity((gs_matrix *)&ctm_ident);
817
ctm_ident.tx_fixed = ctm_ident.ty_fixed = 0;
818
ctm_ident.txy_fixed_valid = true;
819
cs.pctm = &ctm_ident;
821
data_params.ranges = 0; /* don't scale function parameter */
823
/****** SCALE Decode ******/
824
code = cos_dict_put_c_key_floats(pscd, "/Decode", pmp->Decode,
827
code = cos_stream_add_stream_contents(pscs, cs.s);
828
bits_per_coordinate = pmp->BitsPerCoordinate;
829
bits_per_component = pmp->BitsPerComponent;
833
(code = pdf_put_shading_Function(pscd, pmp->Function, pranges)) < 0 ||
834
(code = cos_dict_put_c_key_int(pscd, "/BitsPerCoordinate",
835
bits_per_coordinate)) < 0 ||
836
(code = cos_dict_put_c_key_int(pscd, "/BitsPerComponent",
837
bits_per_component)) < 0
841
switch (ShadingType(psh)) {
842
case shading_type_Free_form_Gouraud_triangle: {
843
const gs_shading_FfGt_params_t *const params =
844
(const gs_shading_FfGt_params_t *)pmp;
846
data_params.num_points = 1;
847
data_params.num_components = num_comp;
849
while ((flag = shade_next_flag(&cs, 0)) >= 0)
850
if ((code = put_float_mesh_data(pscs, &cs, flag,
854
code = gs_note_error(gs_error_rangecheck);
856
if (bits_per_flag < 0)
857
bits_per_flag = params->BitsPerFlag;
860
case shading_type_Lattice_form_Gouraud_triangle: {
861
const gs_shading_LfGt_params_t *const params =
862
(const gs_shading_LfGt_params_t *)pmp;
864
data_params.num_points = 1;
865
data_params.num_components = num_comp;
868
if ((code = put_float_mesh_data(pscs, &cs, -1,
871
code = cos_dict_put_c_key_int(pscd, "/VerticesPerRow",
872
params->VerticesPerRow);
875
case shading_type_Coons_patch: {
876
const gs_shading_Cp_params_t *const params =
877
(const gs_shading_Cp_params_t *)pmp;
880
while ((flag = shade_next_flag(&cs, 0)) >= 0) {
881
data_params.num_points = (flag == 0 ? 12 : 8);
882
data_params.num_components = num_comp * (flag == 0 ? 4 : 2);
883
if ((code = put_float_mesh_data(pscs, &cs, flag,
888
code = gs_note_error(gs_error_rangecheck);
890
if (bits_per_flag < 0)
891
bits_per_flag = params->BitsPerFlag;
894
case shading_type_Tensor_product_patch: {
895
const gs_shading_Tpp_params_t *const params =
896
(const gs_shading_Tpp_params_t *)pmp;
899
while ((flag = shade_next_flag(&cs, 0)) >= 0) {
900
data_params.num_points = (flag == 0 ? 16 : 12);
901
data_params.num_components = num_comp * (flag == 0 ? 4 : 2);
902
if ((code = put_float_mesh_data(pscs, &cs, flag,
907
code = gs_note_error(gs_error_rangecheck);
909
if (bits_per_flag < 0)
910
bits_per_flag = params->BitsPerFlag;
914
return_error(gs_error_rangecheck);
916
code1 = cos_dict_put_c_key_int(pscd, "/BitsPerFlag", bits_per_flag);
922
/* Write a PatternType 2 (shading pattern) color. */
924
pdf_put_pattern2(gx_device_pdf *pdev, const gx_drawing_color *pdc,
925
const psdf_set_color_commands_t *ppscc,
926
pdf_resource_t **ppres)
928
const gs_pattern2_instance_t *pinst =
929
(gs_pattern2_instance_t *)pdc->ccolor.pattern;
930
const gs_shading_t *psh = pinst->templat.Shading;
932
pdf_resource_t *pres;
933
pdf_resource_t *psres;
936
const gs_range_t *pranges;
937
int code = pdf_cs_Pattern_colored(pdev, &v);
943
code = pdf_alloc_resource(pdev, resourcePattern, gs_no_id, ppres, 0L);
947
cos_become(pres->object, cos_type_dict);
948
pcd = (cos_dict_t *)pres->object;
949
code = pdf_alloc_resource(pdev, resourceShading, gs_no_id, &psres, 0L);
952
psco = psres->object;
953
if (ShadingType(psh) >= 4) {
954
/* Shading has an associated data stream. */
955
cos_become(psco, cos_type_stream);
956
code = pdf_put_shading_common(cos_stream_dict((cos_stream_t *)psco),
957
psh, pinst->shfill, &pranges);
959
code1 = pdf_put_mesh_shading((cos_stream_t *)psco, psh, pranges);
961
/* We won't use this shading, we fall back because we couldn't write it */
962
psres->where_used = 0;
964
cos_become(psco, cos_type_dict);
965
code = pdf_put_shading_common((cos_dict_t *)psco, psh, pinst->shfill, &pranges);
967
code = pdf_put_scalar_shading((cos_dict_t *)psco, psh, pranges);
969
/* We won't use this shading, we fall back because we couldn't write it */
970
psres->where_used = 0;
973
* In PDF, the Matrix is the transformation from the pattern space to
974
* the *default* user coordinate space, not the current space.
975
* NB. For a form the default space is the parent. This means that when a
976
* form is nested inside a form, the default space is the space of the
977
* first form, and therefore we do *not* remove the resolution scaling.
979
gs_currentmatrix(pinst->saved, &smat);
981
double xscale = 1.0, yscale = 1.0;
982
if (pdev->FormDepth == 0) {
983
xscale = 72.0 / pdev->HWResolution[0];
984
yscale = 72.0 / pdev->HWResolution[1];
987
smat.xx *= xscale, smat.yx *= xscale, smat.tx *= xscale;
988
smat.xy *= yscale, smat.yy *= yscale, smat.ty *= yscale;
991
(code = cos_dict_put_c_key_int(pcd, "/PatternType", 2)) < 0 ||
992
(code = cos_dict_put_c_key_object(pcd, "/Shading", psco)) < 0 ||
993
(code = cos_dict_put_matrix(pcd, "/Matrix", &smat)) < 0
994
/****** ExtGState ******/
997
cos_value_write(&v, pdev);
998
pprints1(pdev->strm, " %s\n", ppscc->setcolorspace);
1003
Include color space.
1006
gdev_pdf_include_color_space(gx_device *dev, gs_color_space *cspace, const byte *res_name, int name_length)
1008
gx_device_pdf * pdev = (gx_device_pdf *)dev;
1009
cos_value_t cs_value;
1011
return pdf_color_space_named(pdev, &cs_value, NULL, cspace,
1012
&pdf_color_space_names, true, res_name, name_length);