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:
Carl Worth 2006-05-15 10:04:53 -07:00
parent 6f417fed51
commit bf2ab0de92
2 changed files with 231 additions and 11 deletions

View file

@ -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