/* Copyright (C) 2000 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: gdevpdfv.c,v 1.10.2.1.2.1 2003/01/17 00:49:01 giles Exp $ */ /* Color value writing for pdfwrite driver */ #include "math_.h" #include "string_.h" #include "gx.h" #include "gscindex.h" #include "gserrors.h" #include "gsiparm3.h" /* for pattern colors */ #include "gsmatrix.h" /* for gspcolor.h */ #include "gscoord.h" /* for gs_currentmatrix, requires gsmatrix.h */ #include "gsptype2.h" #include "gxcolor2.h" /* for gxpcolor.h */ #include "gxdcolor.h" /* for gxpcolor.h */ #include "gxpcolor.h" /* for pattern device color types */ #include "gxshade.h" #include "gdevpdfx.h" #include "gdevpdfg.h" #include "gdevpdfo.h" #include "szlibx.h" /* Import the PatternType 2 Pattern device color type. */ extern const gx_device_color_type_t gx_dc_pattern2; /* ---------------- Utilities ---------------- */ /* Write a matrix parameter. */ private int cos_dict_put_matrix(cos_dict_t *pscd, const char *key, const gs_matrix *pmat) { float matrix[6]; matrix[0] = pmat->xx; matrix[1] = pmat->xy; matrix[2] = pmat->yx; matrix[3] = pmat->yy; matrix[4] = pmat->tx; matrix[5] = pmat->ty; return cos_dict_put_c_key_floats(pscd, key, matrix, 6); } /* ---------------- PatternType 1 colors ---------------- */ /* * Create a Pattern resource referencing an image (currently only an XObject). * p_tile is NULL for uncolored patterns or the NULL pattern. * m_tile is NULL for colored patterns that fill their bounding box, * including the NULL pattern. ****** WE DON'T HANDLE NULL PATTERNS YET ****** */ private uint tile_size(const gx_strip_bitmap *tile, int depth) { return (tile->rep_width * depth + 7) / 8 * tile->rep_height; } private bool tile_size_ok(const gx_device_pdf *pdev, const gx_color_tile *p_tile, const gx_color_tile *m_tile) { /* * Acrobat Reader can't handle image Patterns with more than * 64K of data. :-( */ uint p_size = (p_tile == 0 ? 0 : tile_size(&p_tile->tbits, pdev->color_info.depth)); uint m_size = (m_tile == 0 ? 0 : tile_size(&m_tile->tmask, 1)); return (max(p_size, m_size) <= 65500); } private int pdf_pattern(gx_device_pdf *pdev, const gx_drawing_color *pdc, const gx_color_tile *p_tile, const gx_color_tile *m_tile, cos_stream_t *pcs_image, pdf_resource_t **ppres) { pdf_resource_t *pres; int code = pdf_alloc_resource(pdev, resourcePattern, pdc->mask.id, ppres, 0L); cos_stream_t *pcos; cos_dict_t *pcd; cos_dict_t *pcd_Resources = cos_dict_alloc(pdev, "pdf_pattern(Resources)"); const gx_color_tile *tile = (p_tile ? p_tile : m_tile); const gx_strip_bitmap *btile = (p_tile ? &p_tile->tbits : &m_tile->tmask); bool mask = p_tile == 0; gs_point step; gs_matrix smat; if (code < 0) return code; if (!tile_size_ok(pdev, p_tile, m_tile)) return_error(gs_error_limitcheck); /* * We currently can't handle Patterns whose X/Y step isn't parallel * to the coordinate axes. */ if (is_xxyy(&tile->step_matrix)) step.x = tile->step_matrix.xx, step.y = tile->step_matrix.yy; else if (is_xyyx(&tile->step_matrix)) step.x = tile->step_matrix.yx, step.y = tile->step_matrix.xy; else return_error(gs_error_rangecheck); if (pcd_Resources == 0) return_error(gs_error_VMerror); gs_make_identity(&smat); smat.xx = btile->rep_width / (pdev->HWResolution[0] / 72.0); smat.yy = btile->rep_height / (pdev->HWResolution[1] / 72.0); pres = *ppres; { cos_dict_t *pcd_XObject = cos_dict_alloc(pdev, "pdf_pattern(XObject)"); char key[MAX_REF_CHARS + 3]; cos_value_t v; if (pcd_XObject == 0) return_error(gs_error_VMerror); sprintf(key, "/R%ld", pcs_image->id); COS_OBJECT_VALUE(&v, pcs_image); if ((code = cos_dict_put(pcd_XObject, (byte *)key, strlen(key), &v)) < 0 || (code = cos_dict_put_c_key_object(pcd_Resources, "/XObject", COS_OBJECT(pcd_XObject))) < 0 ) return code; } if ((code = cos_dict_put_c_strings(pcd_Resources, "/ProcSet", (mask ? "[/PDF/ImageB]" : "[/PDF/ImageC]"))) < 0) return code; cos_become(pres->object, cos_type_stream); pcos = (cos_stream_t *)pres->object; pcd = cos_stream_dict(pcos); if ((code = cos_dict_put_c_key_int(pcd, "/PatternType", 1)) < 0 || (code = cos_dict_put_c_key_int(pcd, "/PaintType", (mask ? 2 : 1))) < 0 || (code = cos_dict_put_c_key_int(pcd, "/TilingType", tile->tiling_type)) < 0 || (code = cos_dict_put_c_key_object(pcd, "/Resources", COS_OBJECT(pcd_Resources))) < 0 || (code = cos_dict_put_c_strings(pcd, "/BBox", "[0 0 1 1]")) < 0 || (code = cos_dict_put_matrix(pcd, "/Matrix", &smat)) < 0 || (code = cos_dict_put_c_key_real(pcd, "/XStep", step.x / btile->rep_width)) < 0 || (code = cos_dict_put_c_key_real(pcd, "/YStep", step.y / btile->rep_height)) < 0 ) { return code; } { char buf[MAX_REF_CHARS + 6 + 1]; /* +6 for /R# Do\n */ sprintf(buf, "/R%ld Do\n", pcs_image->id); cos_stream_add_bytes(pcos, (const byte *)buf, strlen(buf)); } return 0; } /* Set the ImageMatrix, Width, and Height for a Pattern image. */ private void pdf_set_pattern_image(gs_data_image_t *pic, const gx_strip_bitmap *tile) { pic->ImageMatrix.xx = pic->Width = tile->rep_width; pic->ImageMatrix.yy = pic->Height = tile->rep_height; } /* Write the mask for a Pattern (colored or uncolored). */ private int pdf_put_pattern_mask(gx_device_pdf *pdev, const gx_color_tile *m_tile, cos_stream_t **ppcs_mask) { int w = m_tile->tmask.rep_width, h = m_tile->tmask.rep_height; gs_image1_t image; pdf_image_writer writer; cos_stream_t *pcs_image; long pos; int code; gs_image_t_init_mask_adjust(&image, true, false); pdf_set_pattern_image((gs_data_image_t *)&image, &m_tile->tmask); if ((code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, false)) < 0 || (pdev->params.MonoImage.Encode && (code = psdf_CFE_binary(&writer.binary, w, h, true)) < 0) || (code = pdf_begin_image_data(pdev, &writer, (const gs_pixel_image_t *)&image, NULL)) < 0 ) return code; pcs_image = (cos_stream_t *)writer.pres->object; pos = stell(pdev->streams.strm); /* Pattern masks are specified in device coordinates, so invert Y. */ if ((code = pdf_copy_mask_bits(writer.binary.strm, m_tile->tmask.data + (h - 1) * m_tile->tmask.raster, 0, -m_tile->tmask.raster, w, h, 0)) < 0 || (code = cos_stream_add_since(pcs_image, pos)) < 0 || (code = pdf_end_image_binary(pdev, &writer, h)) < 0 || (code = pdf_end_write_image(pdev, &writer)) < 0 ) return code; *ppcs_mask = pcs_image; return 0; } /* Write an uncolored Pattern color. */ /* (Single-use procedure for readability.) */ private int pdf_put_uncolored_pattern(gx_device_pdf *pdev, const gx_drawing_color *pdc, const psdf_set_color_commands_t *ppscc, pdf_resource_t **ppres) { const gx_color_tile *m_tile = pdc->mask.m_tile; gx_drawing_color dc_pure; color_set_pure(&dc_pure, gx_dc_pure_color(pdc)); if (m_tile == 0) { /* * If m_tile == 0, this uncolored Pattern is all 1's, * equivalent to a pure color. */ *ppres = 0; return psdf_set_color((gx_device_vector *)pdev, &dc_pure, ppscc); } else { cos_value_t v; stream *s = pdev->strm; int code; cos_stream_t *pcs_image; static const psdf_set_color_commands_t no_scc = {0, 0, 0}; if (!tile_size_ok(pdev, NULL, m_tile)) return_error(gs_error_limitcheck); if ((code = pdf_cs_Pattern_uncolored(pdev, &v)) < 0 || (code = pdf_put_pattern_mask(pdev, m_tile, &pcs_image)) < 0 || (code = pdf_pattern(pdev, pdc, NULL, m_tile, pcs_image, ppres)) < 0 ) return code; cos_value_write(&v, pdev); pprints1(s, " %s ", ppscc->setcolorspace); return psdf_set_color((gx_device_vector *)pdev, &dc_pure, &no_scc); } } /* Write a colored Pattern color. */ /* (Single-use procedure for readability.) */ private int pdf_put_colored_pattern(gx_device_pdf *pdev, const gx_drawing_color *pdc, const psdf_set_color_commands_t *ppscc, pdf_resource_t **ppres) { const gx_color_tile *m_tile = pdc->mask.m_tile; const gx_color_tile *p_tile = pdc->colors.pattern.p_tile; int w = p_tile->tbits.rep_width, h = p_tile->tbits.rep_height; gs_color_space cs_Device; cos_value_t cs_value; pdf_image_writer writer; gs_image1_t image; cos_stream_t *pcs_image; cos_stream_t *pcs_mask = 0; cos_value_t v; long pos; int code; /* * NOTE: We assume here that the color space of the cached Pattern * is the same as the native color space of the device. This will * have to change in the future! */ /* * Check whether this colored pattern is actually a masked pure color, * by testing whether all the colored pixels have the same color. */ if (m_tile) { if (p_tile && !(p_tile->depth & 7) && p_tile->depth <= sizeof(gx_color_index) * 8) { int depth_bytes = p_tile->depth >> 3; int width = p_tile->tbits.rep_width; int skip = p_tile->tbits.raster - p_tile->tbits.rep_width * depth_bytes; const byte *bp; const byte *mp; int i, j, k; gx_color_index color = 0; /* init is arbitrary if not empty */ bool first = true; for (i = 0, bp = p_tile->tbits.data, mp = m_tile->tbits.data; i < p_tile->tbits.rep_height; ++i, bp += skip, mp += m_tile->tbits.raster) { for (j = 0; j < width; ++j) { if (mp[j >> 3] & (0x80 >> (j & 7))) { gx_color_index ci = 0; for (k = 0; k < depth_bytes; ++k) ci = (ci << 8) + *bp++; if (first) color = ci, first = false; else if (ci != color) goto not_pure; } else bp += depth_bytes; } } { /* Set the color, then handle as an uncolored pattern. */ gx_drawing_color dcolor; dcolor = *pdc; dcolor.colors.pure = color; return pdf_put_uncolored_pattern(pdev, &dcolor, ppscc, ppres); } not_pure: DO_NOTHING; /* required by MSVC */ } if (pdev->CompatibilityLevel < 1.3) { /* Masked images are only supported starting in PDF 1.3. */ return_error(gs_error_rangecheck); } } /* Acrobat Reader has a size limit for image Patterns. */ if (!tile_size_ok(pdev, p_tile, m_tile)) return_error(gs_error_limitcheck); code = pdf_cs_Pattern_colored(pdev, &v); if (code < 0) return code; pdf_cspace_init_Device(&cs_Device, pdev->color_info.num_components); code = pdf_color_space(pdev, &cs_value, &cs_Device, &pdf_color_space_names, true); if (code < 0) return code; gs_image_t_init_adjust(&image, &cs_Device, false); image.BitsPerComponent = 8; pdf_set_pattern_image((gs_data_image_t *)&image, &p_tile->tbits); if (m_tile) { if ((code = pdf_put_pattern_mask(pdev, m_tile, &pcs_mask)) < 0) return code; } if ((code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, false)) < 0 || (code = psdf_setup_lossless_filters((gx_device_psdf *)pdev, &writer.binary, (gs_pixel_image_t *)&image)) < 0 || (code = pdf_begin_image_data(pdev, &writer, (const gs_pixel_image_t *)&image, &cs_value)) < 0 ) return code; pcs_image = (cos_stream_t *)writer.pres->object; pos = stell(pdev->streams.strm); /* Pattern masks are specified in device coordinates, so invert Y. */ if ((code = pdf_copy_color_bits(writer.binary.strm, p_tile->tbits.data + (h - 1) * p_tile->tbits.raster, 0, -p_tile->tbits.raster, w, h, pdev->color_info.depth >> 3)) < 0 || (code = cos_stream_add_since(pcs_image, pos)) < 0 || (code = pdf_end_image_binary(pdev, &writer, h)) < 0 ) return code; pcs_image = (cos_stream_t *)writer.pres->object; if ((pcs_mask != 0 && (code = cos_dict_put_c_key_object(cos_stream_dict(pcs_image), "/Mask", COS_OBJECT(pcs_mask))) < 0) || (code = pdf_end_write_image(pdev, &writer)) < 0 ) return code; code = pdf_pattern(pdev, pdc, p_tile, m_tile, pcs_image, ppres); if (code < 0) return code; cos_value_write(&v, pdev); pprints1(pdev->strm, " %s", ppscc->setcolorspace); return 0; } /* ---------------- PatternType 2 colors ---------------- */ /* Write parameters common to all Shadings. */ private int pdf_put_shading_common(cos_dict_t *pscd, const gs_shading_t *psh) { gs_shading_type_t type = ShadingType(psh); const gs_color_space *pcs = psh->params.ColorSpace; int code = cos_dict_put_c_key_int(pscd, "/ShadingType", (int)type); cos_value_t cs_value; if (code < 0 || (psh->params.AntiAlias && (code = cos_dict_put_c_strings(pscd, "/AntiAlias", "true")) < 0) || (code = pdf_color_space(pscd->pdev, &cs_value, pcs, &pdf_color_space_names, false)) < 0 || (code = cos_dict_put_c_key(pscd, "/ColorSpace", &cs_value)) < 0 ) return code; if (psh->params.Background) { code = cos_dict_put_c_key_floats(pscd, "/Background", psh->params.Background->paint.values, gs_color_space_num_components(pcs)); if (code < 0) return code; } if (psh->params.have_BBox) { float bbox[4]; bbox[0] = psh->params.BBox.p.x; bbox[1] = psh->params.BBox.p.y; bbox[2] = psh->params.BBox.q.x; bbox[3] = psh->params.BBox.q.y; code = cos_dict_put_c_key_floats(pscd, "/BBox", bbox, 4); if (code < 0) return code; } return 0; } /* Write a linear (Axial / Radial) Shading. */ private int pdf_put_linear_shading(cos_dict_t *pscd, const float *Coords, int num_coords, const float *Domain /*[2]*/, const gs_function_t *Function, const bool *Extend /*[2]*/) { int code = cos_dict_put_c_key_floats(pscd, "/Coords", Coords, num_coords); if (code < 0 || ((Domain[0] != 0 || Domain[1] != 1) && (code = cos_dict_put_c_key_floats(pscd, "/Domain", Domain, 2)) < 0) ) return code; if (Function) { cos_value_t fn_value; if ((code = pdf_function(pscd->pdev, Function, &fn_value)) < 0 || (code = cos_dict_put_c_key(pscd, "/Function", &fn_value)) < 0 ) return code; } if (Extend[0] | Extend[1]) { char extend_str[1 + 5 + 1 + 5 + 1 + 1]; /* [bool bool] */ sprintf(extend_str, "[%s %s]", (Extend[0] ? "true" : "false"), (Extend[1] ? "true" : "false")); code = cos_dict_put_c_key_string(pscd, "/Extend", (const byte *)extend_str, strlen(extend_str)); } return code; } /* Write a scalar (non-mesh) Shading. */ /* (Single-use procedure for readability.) */ private int pdf_put_scalar_shading(cos_dict_t *pscd, const gs_shading_t *psh) { int code = pdf_put_shading_common(pscd, psh); if (code < 0) return code; switch (ShadingType(psh)) { case shading_type_Function_based: { const gs_shading_Fb_params_t *const params = (const gs_shading_Fb_params_t *)&psh->params; cos_value_t fn_value; if ((code = cos_dict_put_c_key_floats(pscd, "/Domain", params->Domain, 4)) < 0 || (code = pdf_function(pscd->pdev, params->Function, &fn_value)) < 0 || (code = cos_dict_put_c_key(pscd, "/Function", &fn_value)) < 0 || (code = cos_dict_put_matrix(pscd, "/Matrix", ¶ms->Matrix)) < 0 ) return code; return 0; } case shading_type_Axial: { const gs_shading_A_params_t *const params = (const gs_shading_A_params_t *)&psh->params; return pdf_put_linear_shading(pscd, params->Coords, 4, params->Domain, params->Function, params->Extend); } case shading_type_Radial: { const gs_shading_R_params_t *const params = (const gs_shading_R_params_t *)&psh->params; return pdf_put_linear_shading(pscd, params->Coords, 6, params->Domain, params->Function, params->Extend); } default: return_error(gs_error_rangecheck); } } /* Add an integer range to an array. */ private int pdf_array_add_int2(cos_array_t *pca, int lower, int upper) { int code = cos_array_add_int(pca, lower); if (code >= 0) code = cos_array_add_int(pca, upper); return code; } /* Put a clamped value into a data stream. num_bytes < sizeof(int). */ private void put_clamped(byte *p, floatp v, int num_bytes) { int limit = 1 << (num_bytes * 8); int i, shift; if (v <= -limit) i = -limit + 1; else if (v >= limit) i = limit - 1; else i = (int)v; for (shift = (num_bytes - 1) * 8; shift >= 0; shift -= 8) *p++ = (byte)(i >> shift); } inline private void put_clamped_coord(byte *p, floatp v, int num_bytes) { put_clamped(p, (v + 32768) * 0xffffff / 65535, num_bytes); } /* Convert floating-point mesh data to packed binary. */ /* BitsPerFlag = 8, BitsPerCoordinate = 24, BitsPerComponent = 16, */ /* scaling is as defined below. */ private int put_float_mesh_data(cos_stream_t *pscs, shade_coord_stream_t *cs, int flag, int num_pts, int num_components, bool is_indexed) { byte b[1 + (3 + 3) * 16]; /* flag + x + y or c */ gs_fixed_point pts[16]; int i; int code; b[0] = (byte)flag; /* may be -1 */ if ((code = shade_next_coords(cs, pts, num_pts)) < 0) return code; for (i = 0; i < num_pts; ++i) { put_clamped_coord(b + 1 + i * 6, fixed2float(pts[i].x), 3); put_clamped_coord(b + 4 + i * 6, fixed2float(pts[i].y), 3); } if ((code = cos_stream_add_bytes(pscs, b + (flag < 0), (flag >= 0) + num_pts * 6)) < 0) return code; for (i = 0; i < num_components; ++i) { float c; cs->get_decoded(cs, 0, NULL, &c); put_clamped(b, (is_indexed ? c + 32768 : (c + 256) * 65535 / 511), 2); if ((code = cos_stream_add_bytes(pscs, b, 2)) < 0) return code; } return 0; } /* Write a mesh Shading. */ /* (Single-use procedure for readability.) */ private int pdf_put_mesh_shading(cos_stream_t *pscs, const gs_shading_t *psh) { cos_dict_t *const pscd = cos_stream_dict(pscs); gs_color_space *pcs = psh->params.ColorSpace; const gs_shading_mesh_params_t *const pmp = (const gs_shading_mesh_params_t *)&psh->params; int code = pdf_put_shading_common(pscd, psh); int bits_per_coordinate, bits_per_component, bits_per_flag; int num_comp = (pmp->Function ? 1 : gs_color_space_num_components(pcs)); bool from_array = data_source_is_array(pmp->DataSource); bool is_indexed; shade_coord_stream_t cs; gs_matrix_fixed ctm_ident; int flag; if (code < 0) return code; /* Write parameters common to all mesh Shadings. */ shade_next_init(&cs, pmp, NULL); if (from_array) { cos_array_t *pca = cos_array_alloc(pscd->pdev, "pdf_put_mesh_shading"); int i; if (pca == 0) return_error(gs_error_VMerror); for (i = 0; i < 2; ++i) if ((code = pdf_array_add_int2(pca, -32768, 32767)) < 0) return code; if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed) { is_indexed = true; if ((code = pdf_array_add_int2(pca, -32768, 32767)) < 0) return code; } else { is_indexed = false; for (i = 0; i < num_comp; ++i) if ((code = pdf_array_add_int2(pca, -256, 255)) < 0) return code; } code = cos_dict_put_c_key_object(pscd, "/Decode", COS_OBJECT(pca)); if (code < 0) return code; bits_per_coordinate = 24; bits_per_component = 16; bits_per_flag = 8; gs_make_identity((gs_matrix *)&ctm_ident); ctm_ident.tx_fixed = ctm_ident.ty_fixed = 0; cs.pctm = &ctm_ident; } else { byte buf[100]; /* arbitrary */ uint num_read; code = cos_dict_put_c_key_floats(pscd, "/Decode", pmp->Decode, 4 + gs_color_space_num_components(pcs) * 2); while (sgets(cs.s, buf, sizeof(buf), &num_read), num_read > 0) if ((code = cos_stream_add_bytes(pscs, buf, num_read)) < 0) return code; bits_per_coordinate = pmp->BitsPerCoordinate; bits_per_component = pmp->BitsPerComponent; bits_per_flag = -1; } if (code < 0 || (code = cos_dict_put_c_key_int(pscd, "/BitsPerCoordinate", bits_per_coordinate)) < 0 || (code = cos_dict_put_c_key_int(pscd, "/BitsPerComponent", bits_per_component)) < 0 ) return code; switch (ShadingType(psh)) { case shading_type_Free_form_Gouraud_triangle: { const gs_shading_FfGt_params_t *const params = (const gs_shading_FfGt_params_t *)pmp; if (from_array) while ((flag = shade_next_flag(&cs, 0)) >= 0) if ((code = put_float_mesh_data(pscs, &cs, flag, 1, num_comp, is_indexed)) < 0) return code; if (bits_per_flag < 0) bits_per_flag = params->BitsPerFlag; break; } case shading_type_Lattice_form_Gouraud_triangle: { const gs_shading_LfGt_params_t *const params = (const gs_shading_LfGt_params_t *)pmp; if (from_array) while (!seofp(cs.s)) if ((code = put_float_mesh_data(pscs, &cs, -1, 1, num_comp, is_indexed)) < 0) return code; return cos_dict_put_c_key_int(pscd, "/VerticesPerRow", params->VerticesPerRow); } case shading_type_Coons_patch: { const gs_shading_Cp_params_t *const params = (const gs_shading_Cp_params_t *)pmp; if (from_array) while ((flag = shade_next_flag(&cs, 0)) >= 0) { int num_c = (flag == 0 ? 4 : 2); if ((code = put_float_mesh_data(pscs, &cs, flag, 4 + num_c * 2, num_comp * num_c, is_indexed)) < 0) return code; } if (bits_per_flag < 0) bits_per_flag = params->BitsPerFlag; break; } case shading_type_Tensor_product_patch: { const gs_shading_Tpp_params_t *const params = (const gs_shading_Tpp_params_t *)pmp; if (from_array) while ((flag = shade_next_flag(&cs, 0)) >= 0) { int num_c = (flag == 0 ? 4 : 2); if ((code = put_float_mesh_data(pscs, &cs, flag, 8 + num_c * 2, num_comp * num_c, is_indexed)) < 0) return code; } if (bits_per_flag < 0) bits_per_flag = params->BitsPerFlag; break; } default: return_error(gs_error_rangecheck); } return cos_dict_put_c_key_int(pscd, "/BitsPerFlag", bits_per_flag); } /* Write a PatternType 2 (shading pattern) color. */ /* (Single-use procedure for readability.) */ private int pdf_put_pattern2(gx_device_pdf *pdev, const gx_drawing_color *pdc, const psdf_set_color_commands_t *ppscc, pdf_resource_t **ppres) { const gs_pattern2_instance_t *pinst = (gs_pattern2_instance_t *)pdc->ccolor.pattern; const gs_shading_t *psh = pinst->template.Shading; cos_value_t v; pdf_resource_t *pres; pdf_resource_t *psres; cos_dict_t *pcd; cos_object_t *psco; int code = pdf_cs_Pattern_colored(pdev, &v); gs_matrix smat; if (code < 0) return code; code = pdf_alloc_resource(pdev, resourcePattern, gs_no_id, ppres, 0L); if (code < 0) return code; pres = *ppres; cos_become(pres->object, cos_type_dict); pcd = (cos_dict_t *)pres->object; code = pdf_alloc_resource(pdev, resourceShading, gs_no_id, &psres, 0L); if (code < 0) return code; psco = psres->object; if (ShadingType(psh) >= 4) { /* Shading has an associated data stream. */ cos_become(psco, cos_type_stream); code = pdf_put_mesh_shading((cos_stream_t *)psco, psh); } else { cos_become(psco, cos_type_dict); code = pdf_put_scalar_shading((cos_dict_t *)psco, psh); } /* * In PDF, the Matrix is the transformation from the pattern space to * the *default* user coordinate space, not the current space. */ gs_currentmatrix(pinst->saved, &smat); { double xscale = 72.0 / pdev->HWResolution[0], yscale = 72.0 / pdev->HWResolution[1]; smat.xx *= xscale, smat.yx *= xscale, smat.tx *= xscale; smat.xy *= yscale, smat.yy *= yscale, smat.ty *= yscale; } if (code < 0 || (code = cos_dict_put_c_key_int(pcd, "/PatternType", 2)) < 0 || (code = cos_dict_put_c_key_object(pcd, "/Shading", psco)) < 0 || (code = cos_dict_put_matrix(pcd, "/Matrix", &smat)) < 0 /****** ExtGState ******/ ) return code; cos_value_write(&v, pdev); pprints1(pdev->strm, " %s", ppscc->setcolorspace); return 0; } /* ---------------- Public procedure ---------------- */ /* Write a color value. */ int pdf_put_drawing_color(gx_device_pdf *pdev, const gx_drawing_color *pdc, const psdf_set_color_commands_t *ppscc) { if (gx_dc_is_pure(pdc)) return psdf_set_color((gx_device_vector *) pdev, pdc, ppscc); else { /* We never halftone, so this must be a Pattern. */ int code; pdf_resource_t *pres; cos_value_t v; if (pdc->type == gx_dc_type_pattern) code = pdf_put_colored_pattern(pdev, pdc, ppscc, &pres); else if (pdc->type == &gx_dc_pure_masked) code = pdf_put_uncolored_pattern(pdev, pdc, ppscc, &pres); else if (pdc->type == &gx_dc_pattern2) code = pdf_put_pattern2(pdev, pdc, ppscc, &pres); else return_error(gs_error_rangecheck); if (code < 0) return code; /* * Uncolored patterns equivalent to a solid color don't need an * associated resource, and set pres = 0. */ if (pres) { cos_value_write(cos_resource_value(&v, pres->object), pdev); pprints1(pdev->strm, " %s\n", ppscc->setcolorn); } return 0; } }