mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-02-07 02:50:37 +01:00
PDF: Add Type3 font support to PDF output.
This uses the recently added cairo-scaled-font-subsets interface in a style very similar to what the PS surface does.
This commit is contained in:
parent
6f417fed51
commit
bf2ab0de92
2 changed files with 231 additions and 11 deletions
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
#include "cairoint.h"
|
||||
#include "cairo-pdf.h"
|
||||
#include "cairo-font-subset-private.h"
|
||||
#include "cairo-scaled-font-subsets-private.h"
|
||||
#include "cairo-ft-private.h"
|
||||
#include "cairo-paginated-surface-private.h"
|
||||
#include "cairo-path-fixed-private.h"
|
||||
|
|
@ -94,6 +94,12 @@ typedef struct _cairo_pdf_resource {
|
|||
unsigned int id;
|
||||
} cairo_pdf_resource_t;
|
||||
|
||||
typedef struct _cairo_pdf_font {
|
||||
unsigned int font_id;
|
||||
unsigned int subset_id;
|
||||
cairo_pdf_resource_t subset_resource;
|
||||
} cairo_pdf_font_t;
|
||||
|
||||
typedef struct _cairo_pdf_surface {
|
||||
cairo_surface_t base;
|
||||
|
||||
|
|
@ -113,6 +119,9 @@ typedef struct _cairo_pdf_surface {
|
|||
cairo_array_t streams;
|
||||
cairo_array_t alphas;
|
||||
|
||||
cairo_scaled_font_subsets_t *font_subsets;
|
||||
cairo_array_t fonts;
|
||||
|
||||
cairo_pdf_resource_t next_available_resource;
|
||||
cairo_pdf_resource_t pages_resource;
|
||||
|
||||
|
|
@ -128,7 +137,8 @@ typedef struct _cairo_pdf_surface {
|
|||
cairo_paginated_mode_t paginated_mode;
|
||||
} cairo_pdf_surface_t;
|
||||
|
||||
#define PDF_SURFACE_DPI_DEFAULT 300
|
||||
#define PDF_SURFACE_DPI_DEFAULT 300
|
||||
#define PDF_SURFACE_MAX_GLYPHS_PER_FONT 256
|
||||
|
||||
static cairo_pdf_resource_t
|
||||
_cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface);
|
||||
|
|
@ -162,6 +172,9 @@ _cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface);
|
|||
static cairo_status_t
|
||||
_cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface);
|
||||
|
||||
static const cairo_surface_backend_t cairo_pdf_surface_backend;
|
||||
static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend;
|
||||
|
||||
|
|
@ -264,6 +277,15 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
|
|||
_cairo_array_init (&surface->streams, sizeof (cairo_pdf_resource_t));
|
||||
_cairo_array_init (&surface->alphas, sizeof (double));
|
||||
|
||||
surface->font_subsets = _cairo_scaled_font_subsets_create (PDF_SURFACE_MAX_GLYPHS_PER_FONT);
|
||||
if (! surface->font_subsets) {
|
||||
_cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
free (surface);
|
||||
return (cairo_surface_t*) &_cairo_surface_nil;
|
||||
}
|
||||
|
||||
_cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t));
|
||||
|
||||
surface->next_available_resource.id = 1;
|
||||
surface->pages_resource = _cairo_pdf_surface_new_object (surface);
|
||||
|
||||
|
|
@ -538,6 +560,8 @@ _cairo_pdf_surface_finish (void *abstract_surface)
|
|||
|
||||
_cairo_pdf_surface_close_stream (surface);
|
||||
|
||||
_cairo_pdf_surface_emit_font_subsets (surface);
|
||||
|
||||
_cairo_pdf_surface_write_pages (surface);
|
||||
|
||||
info = _cairo_pdf_surface_write_info (surface);
|
||||
|
|
@ -570,6 +594,13 @@ _cairo_pdf_surface_finish (void *abstract_surface)
|
|||
_cairo_array_fini (&surface->streams);
|
||||
_cairo_array_fini (&surface->alphas);
|
||||
|
||||
if (surface->font_subsets) {
|
||||
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
|
||||
surface->font_subsets = NULL;
|
||||
}
|
||||
|
||||
_cairo_array_fini (&surface->fonts);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -1541,7 +1572,8 @@ static void
|
|||
_cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface)
|
||||
{
|
||||
cairo_pdf_resource_t page, *res;
|
||||
int num_pages, i;
|
||||
cairo_pdf_font_t font;
|
||||
int num_pages, num_fonts, i;
|
||||
int num_alphas, num_resources;
|
||||
double alpha;
|
||||
|
||||
|
|
@ -1612,6 +1644,15 @@ _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface)
|
|||
" >>\r\n");
|
||||
}
|
||||
|
||||
_cairo_output_stream_printf (surface->output," /Font <<\r\n");
|
||||
num_fonts = _cairo_array_num_elements (&surface->fonts);
|
||||
for (i = 0; i < num_fonts; i++) {
|
||||
_cairo_array_copy_element (&surface->fonts, i, &font);
|
||||
_cairo_output_stream_printf (surface->output, " /CairoFont-%d-%d %d 0 R\r\n",
|
||||
font.font_id, font.subset_id, font.subset_resource.id);
|
||||
}
|
||||
_cairo_output_stream_printf (surface->output, " >>\r\n");
|
||||
|
||||
_cairo_output_stream_printf (surface->output,
|
||||
" >>\r\n");
|
||||
|
||||
|
|
@ -1625,6 +1666,162 @@ _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface)
|
|||
surface->height);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_pdf_surface_emit_glyph (cairo_pdf_surface_t *surface,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
unsigned long scaled_font_glyph_index,
|
||||
unsigned int subset_glyph_index,
|
||||
cairo_pdf_resource_t *glyph_ret)
|
||||
{
|
||||
cairo_scaled_glyph_t *scaled_glyph;
|
||||
cairo_status_t status;
|
||||
|
||||
status = _cairo_scaled_glyph_lookup (scaled_font,
|
||||
scaled_font_glyph_index,
|
||||
CAIRO_SCALED_GLYPH_INFO_METRICS|
|
||||
CAIRO_SCALED_GLYPH_INFO_PATH,
|
||||
&scaled_glyph);
|
||||
/*
|
||||
* If that fails, try again but ask for an image instead
|
||||
*/
|
||||
if (status)
|
||||
status = _cairo_scaled_glyph_lookup (scaled_font,
|
||||
scaled_font_glyph_index,
|
||||
CAIRO_SCALED_GLYPH_INFO_METRICS|
|
||||
CAIRO_SCALED_GLYPH_INFO_SURFACE,
|
||||
&scaled_glyph);
|
||||
if (status) {
|
||||
_cairo_surface_set_error (&surface->base, status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* XXX: Need to actually use the image not the path if that's all
|
||||
* we could get... */
|
||||
|
||||
*glyph_ret = _cairo_pdf_surface_open_stream (surface, NULL);
|
||||
|
||||
_cairo_output_stream_printf (surface->output,
|
||||
"0 0 %f %f %f %f d1\r\n"
|
||||
" \r\n",
|
||||
_cairo_fixed_to_double (scaled_glyph->bbox.p1.x),
|
||||
-_cairo_fixed_to_double (scaled_glyph->bbox.p2.y),
|
||||
_cairo_fixed_to_double (scaled_glyph->bbox.p2.x),
|
||||
-_cairo_fixed_to_double (scaled_glyph->bbox.p1.y));
|
||||
|
||||
status = _cairo_path_fixed_interpret (scaled_glyph->path,
|
||||
CAIRO_DIRECTION_FORWARD,
|
||||
_cairo_pdf_path_move_to,
|
||||
_cairo_pdf_path_line_to,
|
||||
_cairo_pdf_path_curve_to,
|
||||
_cairo_pdf_path_close_path,
|
||||
surface->output);
|
||||
|
||||
_cairo_output_stream_printf (surface->output,
|
||||
" f");
|
||||
|
||||
_cairo_pdf_surface_close_stream (surface);
|
||||
|
||||
if (status)
|
||||
_cairo_surface_set_error (&surface->base, status);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_pdf_surface_emit_font_subset (cairo_scaled_font_subset_t *font_subset,
|
||||
void *closure)
|
||||
{
|
||||
cairo_pdf_surface_t *surface = closure;
|
||||
cairo_pdf_resource_t *glyphs, encoding, char_procs, subset_resource;
|
||||
cairo_pdf_font_t font;
|
||||
int i;
|
||||
|
||||
glyphs = malloc (font_subset->num_glyphs * sizeof (cairo_pdf_resource_t));
|
||||
if (glyphs == NULL) {
|
||||
_cairo_surface_set_error (&surface->base, CAIRO_STATUS_NO_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < font_subset->num_glyphs; i++) {
|
||||
_cairo_pdf_surface_emit_glyph (surface,
|
||||
font_subset->scaled_font,
|
||||
font_subset->glyphs[i], i,
|
||||
&glyphs[i]);
|
||||
}
|
||||
|
||||
encoding = _cairo_pdf_surface_new_object (surface);
|
||||
_cairo_output_stream_printf (surface->output,
|
||||
"%d 0 obj\r\n"
|
||||
"<< /Type /Encoding\r\n"
|
||||
" /Differences [0", encoding.id);
|
||||
for (i = 0; i < font_subset->num_glyphs; i++)
|
||||
_cairo_output_stream_printf (surface->output,
|
||||
" /%d", i);
|
||||
_cairo_output_stream_printf (surface->output,
|
||||
"]\r\n"
|
||||
">>\r\n"
|
||||
"endobj\r\n");
|
||||
|
||||
char_procs = _cairo_pdf_surface_new_object (surface);
|
||||
_cairo_output_stream_printf (surface->output,
|
||||
"%d 0 obj\r\n"
|
||||
"<<\r\n", char_procs.id);
|
||||
for (i = 0; i < font_subset->num_glyphs; i++)
|
||||
_cairo_output_stream_printf (surface->output,
|
||||
" /%d %d 0 R\r\n",
|
||||
i, glyphs[i].id);
|
||||
_cairo_output_stream_printf (surface->output,
|
||||
">>\r\n"
|
||||
"endobj\r\n");
|
||||
|
||||
subset_resource = _cairo_pdf_surface_new_object (surface);
|
||||
_cairo_output_stream_printf (surface->output,
|
||||
"%d 0 obj\r\n"
|
||||
"<< /Type /Font\r\n"
|
||||
" /Subtype /Type3\r\n"
|
||||
" /FontBBox [0 0 0 0]\r\n"
|
||||
" /FontMatrix\t[1 0 0 1 0 0]\r\n"
|
||||
" /Encoding %d 0 R\r\n"
|
||||
" /CharProcs %d 0 R\r\n"
|
||||
" /FirstChar 0\r\n"
|
||||
" /LastChar %d\r\n",
|
||||
subset_resource.id,
|
||||
encoding.id,
|
||||
char_procs.id,
|
||||
font_subset->num_glyphs - 1);
|
||||
|
||||
_cairo_output_stream_printf (surface->output,
|
||||
" /Widths [");
|
||||
for (i = 0; i < font_subset->num_glyphs; i++)
|
||||
_cairo_output_stream_printf (surface->output, " 0");
|
||||
_cairo_output_stream_printf (surface->output,
|
||||
"]\r\n");
|
||||
|
||||
_cairo_output_stream_printf (surface->output,
|
||||
">>\r\n"
|
||||
"endobj\r\n");
|
||||
|
||||
font.font_id = font_subset->font_id;
|
||||
font.subset_id = font_subset->subset_id;
|
||||
font.subset_resource = subset_resource;
|
||||
_cairo_array_append (&surface->fonts, &font);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface)
|
||||
{
|
||||
cairo_status_t status;
|
||||
|
||||
status = _cairo_scaled_font_subsets_foreach (surface->font_subsets,
|
||||
_cairo_pdf_surface_emit_font_subset,
|
||||
surface);
|
||||
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
|
||||
surface->font_subsets = NULL;
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static cairo_status_t
|
||||
_cairo_pdf_surface_write_fonts (cairo_pdf_surface_t *surface)
|
||||
|
|
@ -2125,6 +2322,14 @@ _cairo_pdf_surface_fill (void *abstract_surface,
|
|||
return status;
|
||||
}
|
||||
|
||||
static char
|
||||
hex_digit (int i)
|
||||
{
|
||||
i &= 0xf;
|
||||
if (i < 10) return '0' + i;
|
||||
return 'a' + (i - 10);
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_pdf_surface_show_glyphs (void *abstract_surface,
|
||||
cairo_operator_t op,
|
||||
|
|
@ -2134,8 +2339,10 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface,
|
|||
cairo_scaled_font_t *scaled_font)
|
||||
{
|
||||
cairo_pdf_surface_t *surface = abstract_surface;
|
||||
cairo_path_fixed_t path;
|
||||
int current_subset_id = -1;
|
||||
unsigned int font_id, subset_id, subset_glyph_index;
|
||||
cairo_status_t status;
|
||||
int i;
|
||||
|
||||
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
|
||||
return _analyze_operation (surface, op, source);
|
||||
|
|
@ -2146,14 +2353,27 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface,
|
|||
if (status)
|
||||
return status;
|
||||
|
||||
_cairo_path_fixed_init (&path);
|
||||
_cairo_scaled_font_glyph_path (scaled_font, glyphs, num_glyphs, &path);
|
||||
status = _cairo_pdf_surface_fill (surface, op, source,
|
||||
&path, CAIRO_FILL_RULE_WINDING,
|
||||
0.1, scaled_font->options.antialias);
|
||||
_cairo_path_fixed_fini (&path);
|
||||
for (i = 0; i < num_glyphs; i++) {
|
||||
status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
|
||||
scaled_font, glyphs[i].index,
|
||||
&font_id, &subset_id, &subset_glyph_index);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return status;
|
||||
if (subset_id != current_subset_id) {
|
||||
_cairo_output_stream_printf (surface->output,
|
||||
"/CairoFont-%d-%d 1 Tf\r\n",
|
||||
font_id, subset_id);
|
||||
current_subset_id = subset_id;
|
||||
}
|
||||
_cairo_output_stream_printf (surface->output,
|
||||
"BT %f %f Td <%c%c> Tj ET\r\n",
|
||||
glyphs[i].x, glyphs[i].y,
|
||||
hex_digit (subset_glyph_index >> 4),
|
||||
hex_digit (subset_glyph_index));
|
||||
}
|
||||
|
||||
return _cairo_output_stream_get_status (surface->output);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Loading…
Add table
Reference in a new issue