/* * Set the text matrix for writing text. The translation component of the * matrix is the text origin. If the non-translation components of the * matrix differ from the current ones, write a Tm command; if there is only * a Y translation, set use_leading so the next text string will be written * with ' rather than Tj; otherwise, write a Td command. */ static int pdf_set_text_matrix(gx_device_pdf * pdev) { pdf_text_state_t *pts = pdev->text->text_state; stream *s = pdev->strm; pts->use_leading = false; if (matrix_is_compatible(&pts->out.matrix, &pts->in.matrix)) { gs_point dist; int code; code = set_text_distance(&dist, pts->start.x - pts->line_start.x, pts->start.y - pts->line_start.y, &pts->in.matrix); if (code < 0) return code; if (dist.x == 0 && dist.y < 0) { /* Use TL, if needed, and T* or '. */ float dist_y = (float)-dist.y; if (fabs(pts->leading - dist_y) > 0.0005) { pprintg1(s, "%g TL\n", dist_y); pts->leading = dist_y; } pts->use_leading = true; } else { /* Use Td. */ pprintg2(s, "%g %g Td\n", dist.x, dist.y); } } else { /* Use Tm. */ /* * See stream_to_text in gdevpdfu.c for why we need the following * matrix adjustments. */ double sx = 72.0 / pdev->HWResolution[0], sy = 72.0 / pdev->HWResolution[1]; pprintg6(s, "%g %g %g %g %g %g Tm\n", pts->in.matrix.xx * sx, pts->in.matrix.xy * sy, pts->in.matrix.yx * sx, pts->in.matrix.yy * sy, pts->start.x * sx, pts->start.y * sy); } pts->line_start.x = pts->start.x; pts->line_start.y = pts->start.y; pts->out.matrix = pts->in.matrix; return 0; }
/* * Flush text from buffer. */ static int flush_text_buffer(gx_device_pdf *pdev) { pdf_text_state_t *pts = pdev->text->text_state; stream *s = pdev->strm; if (pts->buffer.count_chars != 0) { pdf_font_resource_t *pdfont = pts->in.pdfont; int code = pdf_assign_font_object_id(pdev, pdfont); if (code < 0) return code; code = pdf_add_resource(pdev, pdev->substream_Resources, "/Font", (pdf_resource_t *)pdfont); if (code < 0) return code; } if (pts->buffer.count_moves > 0) { int i, cur = 0; if (pts->use_leading) stream_puts(s, "T*"); stream_puts(s, "["); for (i = 0; i < pts->buffer.count_moves; ++i) { int next = pts->buffer.moves[i].index; pdf_put_string(pdev, pts->buffer.chars + cur, next - cur); pprintg1(s, "%g", pts->buffer.moves[i].amount); cur = next; } if (pts->buffer.count_chars > cur) pdf_put_string(pdev, pts->buffer.chars + cur, pts->buffer.count_chars - cur); stream_puts(s, "]TJ\n"); } else { pdf_put_string(pdev, pts->buffer.chars, pts->buffer.count_chars); stream_puts(s, (pts->use_leading ? "'\n" : "Tj\n")); } pts->buffer.count_chars = 0; pts->buffer.count_moves = 0; pts->use_leading = false; return 0; }
/* Write a CMap in its standard (source) format. */ int psf_write_cmap(const gs_memory_t *mem, stream *s, const gs_cmap_t *pcmap, psf_put_name_chars_proc_t put_name_chars, const gs_const_string *alt_cmap_name, int font_index_only) { const gs_const_string *const cmap_name = (alt_cmap_name ? alt_cmap_name : &pcmap->CMapName); const gs_cid_system_info_t *const pcidsi = pcmap->CIDSystemInfo; switch (pcmap->CMapType) { case 0: case 1: case 2: break; default: return_error(gs_error_rangecheck); } /* Write the header. */ if (!pcmap->ToUnicode) { stream_puts(s, "%!PS-Adobe-3.0 Resource-CMap\n"); stream_puts(s, "%%DocumentNeededResources: ProcSet (CIDInit)\n"); stream_puts(s, "%%IncludeResource: ProcSet (CIDInit)\n"); pput_string_entry(s, "%%BeginResource: CMap (", cmap_name); pput_string_entry(s, ")\n%%Title: (", cmap_name); pput_string_entry(s, " ", &pcidsi->Registry); pput_string_entry(s, " ", &pcidsi->Ordering); pprintd1(s, " %d)\n", pcidsi->Supplement); pprintg1(s, "%%%%Version: %g\n", pcmap->CMapVersion); } stream_puts(s, "/CIDInit /ProcSet findresource begin\n"); stream_puts(s, "12 dict begin\nbegincmap\n"); /* Write the fixed entries. */ pprintd1(s, "/CMapType %d def\n", pcmap->CMapType); stream_puts(s, "/CMapName/"); put_name_chars(s, cmap_name->data, cmap_name->size); stream_puts(s, " def\n"); if (!pcmap->ToUnicode) { pprintg1(s, "/CMapVersion %g def\n", pcmap->CMapVersion); stream_puts(s, "/CIDSystemInfo"); if (font_index_only >= 0 && font_index_only < pcmap->num_fonts) { cmap_put_system_info(s, pcidsi + font_index_only); } else if (pcmap->num_fonts == 1) { cmap_put_system_info(s, pcidsi); } else { int i; pprintd1(s, " %d array\n", pcmap->num_fonts); for (i = 0; i < pcmap->num_fonts; ++i) { pprintd1(s, "dup %d", i); cmap_put_system_info(s, pcidsi + i); stream_puts(s, "put\n"); } } stream_puts(s, " def\n"); if (uid_is_XUID(&pcmap->uid)) { uint i, n = uid_XUID_size(&pcmap->uid); const long *values = uid_XUID_values(&pcmap->uid); stream_puts(s, "/XUID ["); for (i = 0; i < n; ++i) pprintld1(s, " %ld", values[i]); stream_puts(s, "] def\n"); } pprintld1(s, "/UIDOffset %ld def\n", pcmap->UIDOffset); pprintd1(s, "/WMode %d def\n", pcmap->WMode); } /* Write the code space ranges. */ { gs_cmap_ranges_enum_t renum; #define MAX_RANGES 100 gx_code_space_range_t ranges[MAX_RANGES]; int code, count = 0; for (gs_cmap_ranges_enum_init(pcmap, &renum); (code = gs_cmap_enum_next_range(&renum)) == 0; ) { if (count == MAX_RANGES) { cmap_put_ranges(s, ranges, count); count = 0; } ranges[count++] = renum.range; } if (code < 0) return code; if (count) cmap_put_ranges(s, ranges, count); #undef MAX_RANGES } /* Write the code and notdef data. */ { int code; code = cmap_put_code_map(mem, s, 1, pcmap, &cmap_notdef_operators, put_name_chars, font_index_only); if (code < 0) return code; code = cmap_put_code_map(mem, s, 0, pcmap, &cmap_cid_operators, put_name_chars, font_index_only); if (code < 0) return code; } /* Write the trailer. */ stream_puts(s, "endcmap\n"); stream_puts(s, "CMapName currentdict /CMap defineresource pop\nend end\n"); if (!pcmap->ToUnicode) { stream_puts(s, "%%EndResource\n"); stream_puts(s, "%%EOF\n"); } return 0; }
/* * Transition from string context to text context. */ static int sync_text_state(gx_device_pdf *pdev) { pdf_text_state_t *pts = pdev->text->text_state; stream *s = pdev->strm; int code; if (pts->buffer.count_chars == 0) return 0; /* nothing to output */ if (pts->continue_line) return flush_text_buffer(pdev); /* Bring text state parameters up to date. */ if (pts->out.character_spacing != pts->in.character_spacing) { pprintg1(s, "%g Tc\n", pts->in.character_spacing); pts->out.character_spacing = pts->in.character_spacing; } if (pts->out.pdfont != pts->in.pdfont || pts->out.size != pts->in.size) { pdf_font_resource_t *pdfont = pts->in.pdfont; code = pdf_assign_font_object_id(pdev, pdfont); if (code < 0) return code; pprints1(s, "/%s ", pdfont->rname); pprintg1(s, "%g Tf\n", pts->in.size); pts->out.pdfont = pdfont; pts->out.size = pts->in.size; /* * In PDF, the only place to specify WMode is in the CMap * (a.k.a. Encoding) of a Type 0 font. */ pts->wmode = (pdfont->FontType == ft_composite ? pdfont->u.type0.WMode : 0); code = pdf_used_charproc_resources(pdev, pdfont); if (code < 0) return code; } if (memcmp(&pts->in.matrix, &pts->out.matrix, sizeof(pts->in.matrix)) || ((pts->start.x != pts->out_pos.x || pts->start.y != pts->out_pos.y) && (pts->buffer.count_chars != 0 || pts->buffer.count_moves != 0))) { /* pdf_set_text_matrix sets out.matrix = in.matrix */ code = pdf_set_text_matrix(pdev); if (code < 0) return code; } if (pts->out.render_mode != pts->in.render_mode) { pprintg1(s, "%g Tr\n", pts->in.render_mode); pts->out.render_mode = pts->in.render_mode; } if (pts->out.word_spacing != pts->in.word_spacing) { if (memchr(pts->buffer.chars, 32, pts->buffer.count_chars)) { pprintg1(s, "%g Tw\n", pts->in.word_spacing); pts->out.word_spacing = pts->in.word_spacing; } } return flush_text_buffer(pdev); }
static int param_print_typed(gs_param_list * plist, gs_param_name pkey, gs_param_typed_value * pvalue) { printer_param_list_t *const prlist = (printer_param_list_t *)plist; stream *s = prlist->strm; if (!prlist->any) { if (prlist->params.prefix) stream_puts(s, prlist->params.prefix); prlist->any = true; } if (prlist->params.item_prefix) stream_puts(s, prlist->params.item_prefix); pprints1(s, "/%s", pkey); switch (pvalue->type) { case gs_param_type_null: stream_puts(s, " null"); break; case gs_param_type_bool: stream_puts(s, (pvalue->value.b ? " true" : " false")); break; case gs_param_type_int: pprintd1(s, " %d", pvalue->value.i); break; case gs_param_type_long: pprintld1(s, " %l", pvalue->value.l); break; case gs_param_type_float: pprintg1(s, " %g", pvalue->value.f); break; case gs_param_type_string: s_write_ps_string(s, pvalue->value.s.data, pvalue->value.s.size, prlist->params.print_ok); break; case gs_param_type_name: /****** SHOULD USE #-ESCAPES FOR PDF ******/ stream_putc(s, '/'); stream_write(s, pvalue->value.n.data, pvalue->value.n.size); break; case gs_param_type_int_array: { uint i; char sepr = (pvalue->value.ia.size <= 10 ? ' ' : '\n'); stream_putc(s, '['); for (i = 0; i < pvalue->value.ia.size; ++i) { pprintd1(s, "%d", pvalue->value.ia.data[i]); stream_putc(s, sepr); } stream_putc(s, ']'); } break; case gs_param_type_float_array: { uint i; char sepr = (pvalue->value.fa.size <= 10 ? ' ' : '\n'); stream_putc(s, '['); for (i = 0; i < pvalue->value.fa.size; ++i) { pprintg1(s, "%g", pvalue->value.fa.data[i]); stream_putc(s, sepr); } stream_putc(s, ']'); } break; /*case gs_param_type_string_array: */ /*case gs_param_type_name_array: */ default: return_error(gs_error_typecheck); } if (prlist->params.item_suffix) stream_puts(s, prlist->params.item_suffix); return 0; }
const char * pprintg3(stream * s, const char *format, floatp v1, floatp v2, floatp v3) { return pprintg2(s, pprintg1(s, format, v1), v2, v3); }