guy 429faed747 Patch level : 10.0
Files correlati     : pdflib
Ricompilazione Demo : [ ]
Commento            :
Aggiornata PDFlib


git-svn-id: svn://10.65.10.50/trunk@17433 c028cbd2-c16b-5b4b-a496-9718f37d4682
2008-10-20 14:35:00 +00:00

2290 lines
55 KiB
C
Executable File

/*---------------------------------------------------------------------------*
| PDFlib - A library for generating PDF on the fly |
+---------------------------------------------------------------------------+
| Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. |
+---------------------------------------------------------------------------+
| |
| This software is subject to the PDFlib license. It is NOT in the |
| public domain. Extended versions and commercial licenses are |
| available, please check http://www.pdflib.com. |
| |
*---------------------------------------------------------------------------*/
/* $Id: p_page.c,v 1.3 2008-10-20 14:34:16 guy Exp $
*
* PDFlib page related routines
*
*/
#define P_PAGE_C
#include "p_intern.h"
#include "p_color.h"
#include "p_font.h"
#include "p_image.h"
#include "p_layer.h"
#include "p_page.h"
#include "p_tagged.h"
#define PDF_N_PAGE_BOXES 5
static const pdc_keyconn pdf_labelstyle_pdfkeylist[] =
{
{"none", label_none},
{"D", label_123},
{"R", label_IVX},
{"r", label_ivx},
{"A", label_ABC},
{"a", label_abc},
{NULL, 0}
};
typedef enum
{
tabo_none,
tabo_row,
tabo_column,
tabo_structure
}
pdf_taborder;
static const pdc_keyconn pdf_taborder_keylist[] =
{
{"none", tabo_none},
{"row", tabo_row},
{"column", tabo_column},
{"structure", tabo_structure},
{NULL, 0}
};
static const pdc_keyconn pdf_taborder_pdfkeylist[] =
{
{"R", tabo_row},
{"C", tabo_column},
{"S", tabo_structure},
{NULL, 0}
};
static const pdc_keyconn pdf_colorspace_pdfkeylist[] =
{
{"DeviceGray", color_gray},
{"DeviceRGB", color_rgb},
{"DeviceCMYK", color_cmyk},
{NULL, 0}
};
typedef struct
{
pdf_colortype colorspace; /* color space */
pdc_bool isolated; /* isolated flag I */
pdc_bool knockout; /* knockout flag K */
} pg_transgroup;
typedef struct
{
pdf_labelstyle style; /* page label style */
char * prefix; /* page label prefix */
int start; /* page label numbering start */
/* 0 means "no label" */
} pg_label;
typedef struct
{
char * name; /* group name */
int n_pages; /* # of pages in this group */
int capacity; /* # of pages reserved */
int start; /* 1-based physical page number */
pg_label label;
} pg_group;
/* per page resource list
*/
struct pdf_reslist_s
{
int * list; /* resource numbers */
int capacity;
int length;
};
/* current, or suspended page.
*/
typedef struct
{
pdf_ppt ppt;
/* list of content stream IDs.
*/
pdc_id * contents_ids;
int contents_ids_capacity;
int next_content;
pdc_vtr * annots; /* annotation chain */
/* local values of global parameters.
*/
pdc_scalar ydir; /* p->ydirection */
/* resource lists.
*/
pdf_reslist rl_colorspaces;
pdf_reslist rl_extgstates;
pdf_reslist rl_fonts;
pdf_reslist rl_layers;
pdf_reslist rl_patterns;
pdf_reslist rl_shadings;
pdf_reslist rl_xobjects;
} pdf_page;
/* PDF page object.
*/
typedef struct
{
pg_label label;
pdc_id id; /* object id for this page */
pdf_page * pg; /* NULL if this page is not suspended */
/* object ids (PDC_BAD_ID if not present).
*/
pdc_id annots_id; /* id of page's /Annots entry */
pdc_id contents_id; /* id of page's /Contents entry */
pdc_id res_id; /* id of page's /Resources entry */
pdc_id thumb_id; /* id of page's /Thumb entry */
int rotate; /* page's /Rotate entry */
int transition; /* page transition type, or -1 */
int taborder; /* page taborder type */
double duration; /* page display duration, or -1 */
pdc_scalar userunit; /* page user unit */
char * action; /* "action" option string */
pg_transgroup tgroup; /* transparency group definition */
pdc_bool autotgroup; /* create transp. group automatically */
pdc_id * act_idlist; /* action object ids */
pdc_rectangle * boxes[PDF_N_PAGE_BOXES]; /* MediaBox etc. */
} page_obj;
struct pdf_pages_s
{
pdf_page *curr_pg;
pdc_bool have_labels;
pdc_bool have_groups;
pdc_bool in_csect; /* currently in contents section */
int last_suspended; /* 1-based page number or -1 */
pdf_ppt default_ppt; /* pseudo-ppt (for document scope) */
/* as long as we support the old global parameters in addition to
** the new options, we have to save their values on entry to
** begin/resume_page(), and restore them during end/suspend_page().
*/
pdc_scalar old_ydir; /* p->ydirection */
/* deprecated parameters.
*/
int transition; /* page transition type */
double duration; /* page display duration */
/* page descriptors in physical page order.
*/
page_obj * pages; /* page ids and suspended page descr */
int pages_capacity;
int current_page; /* current page number (1-based) */
int last_page; /* last page number allocated yet */
int max_page; /* highest page number pre-allocated yet */
/* page groups.
*/
pg_group * groups;
int groups_capacity;
int n_groups;
pdc_id *pnodes; /* page tree node ids */
int pnodes_capacity; /* current # of entries in pnodes */
int current_pnode; /* current node number (0-based) */
int current_pnode_kids; /* current # of kids in current node */
};
static const pdc_rectangle pdf_null_rect =
{
0, 0, 0, 0
};
/*********************** initialization & cleanup ***********************/
static void
pdf_init_ppt(PDF *p, pdc_bool new_ppt)
{
pdf_ppt *ppt = p->curr_ppt;
if (new_ppt)
{
ppt->cstate = 0;
ppt->tstate = 0;
ppt->mboxes = (pdc_vtr *) 0;
ppt->cs_bias = 0;
ppt->eg_bias = 0;
ppt->fn_bias = 0;
ppt->pt_bias = 0;
ppt->sh_bias = 0;
ppt->xo_bias = 0;
}
ppt->sl = 0;
pdf_init_tstate(p);
pdf_init_gstate(p);
pdf_init_cstate(p);
} /* pdf_init_ppt */
static void
pdf_reset_ppt(pdf_ppt *ppt)
{
if (ppt->mboxes)
{
pdc_vtr_delete(ppt->mboxes);
ppt->mboxes = (pdc_vtr *) 0;
}
}
static void
pdf_delete_page(PDF *p, pdf_page *pg)
{
if (pg != 0)
{
pdf_cleanup_page_cstate(p, &pg->ppt);
pdf_cleanup_page_tstate(p, &pg->ppt);
pdf_reset_ppt(&pg->ppt);
if (pg->contents_ids)
pdc_free(p->pdc, pg->contents_ids);
if (pg->annots)
{
pdc_vtr_delete(pg->annots);
pg->annots = (pdc_vtr *) 0;
}
if (pg->rl_colorspaces.list)
pdc_free(p->pdc, pg->rl_colorspaces.list);
if (pg->rl_extgstates.list)
pdc_free(p->pdc, pg->rl_extgstates.list);
if (pg->rl_fonts.list)
pdc_free(p->pdc, pg->rl_fonts.list);
if (pg->rl_layers.list)
pdc_free(p->pdc, pg->rl_layers.list);
if (pg->rl_patterns.list)
pdc_free(p->pdc, pg->rl_patterns.list);
if (pg->rl_shadings.list)
pdc_free(p->pdc, pg->rl_shadings.list);
if (pg->rl_xobjects.list)
pdc_free(p->pdc, pg->rl_xobjects.list);
pdc_free(p->pdc, pg);
}
} /* pdf_delete_page */
static void
pdf_init_page_obj(page_obj *po)
{
int i;
po->id = PDC_BAD_ID;
po->pg = (pdf_page *) 0;
po->label.start = 0;
po->label.prefix = (char *) 0;
po->tgroup.colorspace = color_none;
po->tgroup.isolated = pdc_false;
po->tgroup.knockout = pdc_false;
po->autotgroup = pdc_false;
po->annots_id = PDC_BAD_ID;
po->contents_id = PDC_BAD_ID;
po->res_id = PDC_BAD_ID;
po->thumb_id = PDC_BAD_ID;
po->transition = -1;
po->duration = -1;
po->taborder = (int) tabo_none;
po->userunit = 1.0;
po->action = (char *) 0;
po->rotate = 0;
po->act_idlist = (pdc_id *) 0;
for (i = 0; i < PDF_N_PAGE_BOXES; ++i)
po->boxes[i] = (pdc_rectangle *) 0;
} /* pdf_init_page_obj */
static void
pdf_grow_pages(PDF *p)
{
static const char fn[] = "pdf_grow_pages";
pdf_pages *dp = p->doc_pages;
int i;
dp->pages = (page_obj *) pdc_realloc(p->pdc, dp->pages,
2 * sizeof (page_obj) * dp->pages_capacity, fn);
for (i = dp->pages_capacity; i < dp->pages_capacity * 2; i++)
pdf_init_page_obj(&dp->pages[i]);
dp->pages_capacity *= 2;
} /* pdf_grow_pages */
void
pdf_init_pages(PDF *p, const char **groups, int n_groups)
{
static const char fn[] = "pdf_init_pages";
int i, k;
pdf_pages * dp = (pdf_pages *) pdc_malloc(p->pdc, sizeof (pdf_pages), fn);
p->doc_pages = dp;
dp->have_labels = pdc_false;
dp->have_groups = (n_groups != 0);
dp->n_groups = 0;
dp->last_suspended = 0;
dp->in_csect = pdc_false;
dp->transition = (int) trans_none;
dp->duration = 0;
dp->pages = (page_obj *) 0;
dp->pnodes = (pdc_id *) 0;
dp->pages_capacity = PAGES_CHUNKSIZE;
dp->pages = (page_obj *)
pdc_malloc(p->pdc, sizeof (page_obj) * dp->pages_capacity, fn);
/* mark ids to allow for pre-allocation of page ids */
for (i = 0; i < dp->pages_capacity; i++)
pdf_init_page_obj(&dp->pages[i]);
dp->current_page = 0;
dp->last_page = 0;
dp->max_page = 0;
dp->curr_pg = (pdf_page *) 0;
dp->pnodes_capacity = PNODES_CHUNKSIZE;
dp->pnodes = (pdc_id *)
pdc_malloc(p->pdc, sizeof (pdc_id) * dp->pnodes_capacity, fn);
dp->current_pnode = 0;
dp->current_pnode_kids = 0;
/* clients may set char/word spacing and horizontal scaling outside pages
** for PDF_stringwidth() calculations, and they may set a color for use
** in PDF_makespotcolor(). that's what default_ppt is good for.
*/
p->curr_ppt = &dp->default_ppt;
pdf_init_ppt(p, pdc_true);
for (i = 0; i < n_groups - 1; ++i)
for (k = i + 1; k < n_groups; ++k)
if (strcmp(groups[i], groups[k]) == 0)
{
pdc_error(p->pdc, PDF_E_DOC_DUPLGROUP, groups[i], 0, 0, 0);
}
dp->n_groups = n_groups;
dp->groups = (pg_group *) (n_groups ?
pdc_malloc(p->pdc, sizeof (pg_group) * n_groups, fn) : 0);
for (i = 0; i < n_groups; ++i)
{
dp->groups[i].name = pdc_strdup(p->pdc, groups[i]);
dp->groups[i].n_pages = 0;
dp->groups[i].capacity = 0;
dp->groups[i].start = 1;
dp->groups[i].label.prefix = (char *) 0;
dp->groups[i].label.start = 0;
}
} /* pdf_init_pages */
void pdf_check_suspended_pages(PDF *p)
{
int i;
pdf_pages * dp = p->doc_pages;
for (i = 0; i <= dp->last_page; ++i)
{
if (dp->pages[i].pg != (pdf_page *) 0)
{
pdc_error(p->pdc, PDF_E_PAGE_SUSPENDED,
pdc_errprintf(p->pdc, "%d", i), 0, 0, 0);
}
}
} /* pdf_check_suspended_pages */
void
pdf_cleanup_pages(PDF *p)
{
if (p->doc_pages != (pdf_pages *) 0)
{
int i;
pdf_pages * dp = p->doc_pages;
if (dp->groups)
{
for (i = 0; i < dp->n_groups; ++i)
{
if (dp->groups[i].name)
pdc_free(p->pdc, dp->groups[i].name);
if (dp->groups[i].label.prefix)
pdc_free(p->pdc, dp->groups[i].label.prefix);
}
pdc_free(p->pdc, dp->groups);
}
if (dp->curr_pg)
pdf_delete_page(p, dp->curr_pg);
if (dp->pages)
{
for (i = 0; i <= dp->last_page; ++i)
{
int k;
page_obj *po = &dp->pages[i];
if (po->label.prefix)
pdc_free(p->pdc, po->label.prefix);
if (po->action)
pdc_free(p->pdc, po->action);
if (po->pg != (pdf_page *) 0)
pdf_delete_page(p, po->pg);
if (po->act_idlist != (pdc_id *) 0)
pdc_free(p->pdc, po->act_idlist);
for (k = 0; k < PDF_N_PAGE_BOXES; ++k)
{
if (po->boxes[k] != (pdc_rectangle *) 0)
pdc_free(p->pdc, po->boxes[k]);
}
}
pdc_free(p->pdc, dp->pages);
}
if (dp->pnodes)
{
pdc_free(p->pdc, dp->pnodes);
}
if (p->curr_ppt != 0)
{
pdf_cleanup_page_cstate(p, &dp->default_ppt);
pdf_cleanup_page_tstate(p, &dp->default_ppt);
}
pdc_free(p->pdc, p->doc_pages);
p->doc_pages = (pdf_pages *) 0;
}
} /* pdf_cleanup_pages */
/******************** page group & labels management ********************/
static pg_group *
find_group(pdf_pages *dp, const char *name)
{
int i;
for (i = 0; i < dp->n_groups; ++i)
if (strcmp(dp->groups[i].name, name) == 0)
return &dp->groups[i];
return (pg_group *) 0;
} /* find_group */
static void
grow_group(PDF *p, pg_group *group, int pageno, int n)
{
pdf_pages * dp = p->doc_pages;
int i;
while (dp->max_page + n >= dp->pages_capacity)
pdf_grow_pages(p);
if (dp->max_page >= pageno)
{
memmove(&dp->pages[pageno + n], &dp->pages[pageno],
(dp->max_page - pageno + 1) * sizeof (page_obj));
for (i = pageno; i < pageno + n; ++i)
pdf_init_page_obj(&dp->pages[i]);
}
dp->max_page += n;
if (dp->last_page >= pageno)
dp->last_page += n;
if (dp->current_page >= pageno)
dp->current_page += n;
group->capacity += n;
for (i = group - dp->groups + 1; i < dp->n_groups; ++i)
dp->groups[i].start += n;
}
/* translate the group-relative pageno to an absolute page number.
** as a side effect, the group gets enlarged as needed if pageno
** exceeds the current number of pages in the group.
*/
int
pdf_xlat_pageno(PDF *p, int pageno, const char *groupname)
{
pdf_pages * dp = p->doc_pages;
pg_group * group = (pg_group *) 0;
if (groupname && *groupname)
{
if ((group = find_group(dp, groupname)) == (pg_group *) 0)
pdc_error(p->pdc, PDF_E_DOC_UNKNOWNGROUP, groupname, 0, 0, 0);
}
if (group)
{
if (pageno < 1)
pdc_error(p->pdc, PDF_E_PAGE_NOTEXIST2,
pdc_errprintf(p->pdc, "%d", pageno), group->name, 0, 0);
if (pageno > group->capacity)
grow_group(p, group, group->start + group->capacity,
pageno - group->capacity);
pageno = group->start + pageno - 1;
}
else
{
if (dp->have_groups && pageno != 0)
pdc_error(p->pdc, PDF_E_PAGE_NEEDGROUP, 0, 0, 0, 0);
}
return pageno;
}
/* TODO (york): get rid of this function.
*/
void
pdf_init_pages2(PDF *p)
{
pdf_pages * dp = p->doc_pages;
dp->pnodes[0] = pdc_alloc_id(p->out);
} /* pdf_init_pages2 */
static const pdc_defopt pdf_pagelabel_options[] =
{
{"pagenumber", pdc_integerlist, PDC_OPT_NONE, 1, 1,
1.0, PDC_INT_MAX, NULL},
{"group", pdc_stringlist, PDC_OPT_NONE, 1, 1,
1.0, PDF_MAX_NAMESTRING, NULL},
{"style", pdc_keywordlist, PDC_OPT_CASESENS, 1, 1,
0.0, 0.0, pdf_labelstyle_pdfkeylist},
{"hypertextencoding", pdc_stringlist, PDC_OPT_NONE, 1, 1,
0.0, PDF_MAX_NAMESTRING, NULL},
{"prefix", pdc_stringlist, PDC_OPT_NONE, 1, 1,
0.0, PDF_MAX_NAMESTRING, NULL},
{"start", pdc_integerlist, PDC_OPT_NONE, 1, 1,
1.0, PDC_INT_MAX, NULL},
PDC_OPT_TERMINATE
};
void
pdf_set_pagelabel(PDF *p, const char *optlist, int pageno)
{
pdf_pages * dp = p->doc_pages;
pg_label * lp;
pdc_resopt *resopts = NULL;
char ** strlist;
int inum;
int page = 0;
char * groupname = NULL;
pdf_labelstyle style = label_none;
pdc_encoding htenc;
int htcp;
char * prefix = NULL;
int start = 1;
resopts = pdc_parse_optionlist(p->pdc, optlist, pdf_pagelabel_options,
NULL, pdc_true);
switch (pageno)
{
case PDF_FC_BEGIN_DOCUMENT:
if (pdc_get_optvalues("group", resopts, NULL, &strlist))
groupname = strlist[0];
else
pdc_error(p->pdc, PDF_E_DOC_NEED_LABELOPT, "group", 0, 0, 0);
if (pdc_get_optvalues("pagenumber", resopts, &page, NULL))
pdc_error(p->pdc, PDF_E_DOC_ILL_LABELOPT,
"pagenumber", 0, 0, 0);
break;
case PDF_FC_END_DOCUMENT:
if (pdc_get_optvalues("group", resopts, NULL, &strlist))
pdc_error(p->pdc, PDF_E_DOC_ILL_LABELOPT, "group", 0, 0, 0);
if (!pdc_get_optvalues("pagenumber", resopts, &page, NULL))
pdc_error(p->pdc, PDF_E_DOC_NEED_LABELOPT,
"pagenumber", 0, 0, 0);
break;
default:
if (pdc_get_optvalues("group", resopts, NULL, &strlist))
pdc_error(p->pdc, PDF_E_DOC_ILL_LABELOPT, "group", 0, 0, 0);
if (pdc_get_optvalues("pagenumber", resopts, &page, NULL))
pdc_error(p->pdc, PDF_E_DOC_ILL_LABELOPT,
"pagenumber", 0, 0, 0);
page = pageno;
break;
}
if (pdc_get_optvalues("style", resopts, &inum, NULL))
style = (pdf_labelstyle) inum;
htenc = pdf_get_hypertextencoding_opt(p, resopts, &htcp, pdc_true);
pdf_get_opt_textlist(p, "prefix", resopts, htenc, htcp,
pdc_true, NULL, &prefix, NULL);
pdc_get_optvalues("start", resopts, &start, NULL);
dp->have_labels = pdc_true;
if (groupname)
{
pg_group *group;
if ((group = find_group(dp, groupname)) == (pg_group *) 0)
pdc_error(p->pdc, PDF_E_DOC_UNKNOWNGROUP, groupname, 0, 0, 0);
lp = &group->label;
}
else
{
if (dp->last_page < page)
pdc_error(p->pdc, PDF_E_PAGE_NOTEXIST,
pdc_errprintf(p->pdc, "%d", page), 0, 0, 0);
lp = &dp->pages[page].label;
}
lp->style = style;
lp->start = start;
if (prefix)
{
if (lp->prefix)
pdc_free(p->pdc, lp->prefix);
lp->prefix = pdc_strdup(p->pdc, prefix);
}
} /* pdf_set_pagelabel */
static void
write_label(PDF *p, pg_label *label, int pageno)
{
pdc_printf(p->out, "%d", pageno);
pdc_begin_dict(p->out);
if (label->style != label_none)
{
pdc_printf(p->out, "/S/%s",
pdc_get_keyword(label->style, pdf_labelstyle_pdfkeylist));
}
if (label->prefix)
{
pdc_printf(p->out, "/P");
pdf_put_hypertext(p, label->prefix);
}
if (label->start != 1)
pdc_printf(p->out, "/St %d", label->start);
pdc_end_dict(p->out);
} /* write_label */
pdc_id
pdf_write_pagelabels(PDF *p)
{
pdf_pages * dp = p->doc_pages;
pdc_id result;
int i, k;
if (!dp->have_labels || dp->last_page == 0)
return PDC_BAD_ID;
result = pdc_begin_obj(p->out, PDC_NEW_ID);
pdc_begin_dict(p->out);
pdc_printf(p->out, "/Nums");
pdc_begin_array(p->out);
/* generate default label if page 1 doesn't have one:
*/
if (dp->pages[1].label.start == 0 &&
(dp->n_groups == 0 || dp->groups[0].label.start == 0))
{
pdc_puts(p->out, "0");
pdc_begin_dict(p->out);
pdc_puts(p->out, "/S/D"); /* 1-based decimal w/o prefix */
pdc_end_dict(p->out);
}
if (dp->n_groups == 0)
{
for (i = 1; i <= dp->last_page; ++i)
if (dp->pages[i].label.start != 0)
write_label(p, &dp->pages[i].label, i - 1);
}
else
{
for (i = 0; i < dp->n_groups; ++i)
{
pg_group *gp = &dp->groups[i];
if (gp->label.start != 0 && gp->n_pages != 0)
{
/* if present, the page label beats the group label.
*/
if (dp->pages[gp->start].label.start == 0)
write_label(p, &gp->label, gp->start - 1);
}
for (k = gp->start; k < gp->start + gp->n_pages; ++k)
if (dp->pages[k].label.start != 0)
write_label(p, &dp->pages[k].label, k - 1);
}
}
pdc_end_array_c(p->out);
pdc_end_dict(p->out);
pdc_end_obj(p->out);
return result;
} /* pdf_write_pagelabels */
static const pdc_defopt pdf_transgroup_options[] =
{
{"CS", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
1.0, PDC_INT_MAX, pdf_colorspace_pdfkeylist},
{"I", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
0.0, 0.0, NULL},
{"K", pdc_booleanlist, PDC_OPT_NONE, 1, 1, \
0.0, 0.0, NULL}, \
PDC_OPT_TERMINATE
};
static void
pdf_set_transgroup(PDF *p, const char *optlist, int pageno)
{
pdf_pages * dp = p->doc_pages;
page_obj * po = &dp->pages[pageno];
pdc_resopt *resopts = NULL;
int inum;
resopts = pdc_parse_optionlist(p->pdc, optlist, pdf_transgroup_options,
NULL, pdc_true);
if (pdc_get_optvalues("CS", resopts, &inum, NULL))
po->tgroup.colorspace = (pdf_colortype) inum;
pdc_get_optvalues("I", resopts, &po->tgroup.isolated, NULL);
pdc_get_optvalues("K", resopts, &po->tgroup.knockout, NULL);
}
static void
write_transgroup(PDF *p, int pageno)
{
pdf_pages * dp = p->doc_pages;
page_obj *po = &dp->pages[pageno];
pdc_puts(p->out, "/Group");
pdc_begin_dict(p->out);
pdc_puts(p->out, "/S/Transparency/CS/");
if (po->tgroup.colorspace != color_none)
{
pdc_printf(p->out, "%s", pdc_get_keyword(po->tgroup.colorspace,
pdf_colorspace_pdfkeylist));
if (po->tgroup.isolated)
pdc_puts(p->out, "/I true");
if (po->tgroup.knockout)
pdc_puts(p->out, "/K true");
}
else
{
pdc_puts(p->out, "DeviceRGB");
}
pdc_end_dict(p->out);
}
/************************** utility functions ***************************/
/* get the id of an existing or future page.
** pageno == 0 means current page. note that pdf_get_page_id(0) returns
** PDC_BAD_ID if no page has been opened yet, whereas pdf_current_page_id()
** returns a pre-allocated id for page 1 in this case.
*/
pdc_id
pdf_get_page_id(PDF *p, int pageno)
{
pdf_pages *dp = p->doc_pages;
if (pageno == 0)
{
return dp->pages[dp->current_page].id;
}
else
{
while (pageno >= dp->pages_capacity)
pdf_grow_pages(p);
/* preallocate page object id for a later page
*/
if (dp->pages[pageno].id == PDC_BAD_ID)
dp->pages[pageno].id = pdc_alloc_id(p->out);
return dp->pages[pageno].id;
}
} /* pdf_get_page_id */
int
pdf_current_page(PDF *p)
{
pdf_pages *dp = p->doc_pages;
return dp ? dp->current_page : 0;
} /* pdf_current_page */
/* get the id of the current page. if there are no pages in the
** document yet, an id will be pre-allocated for page 1.
*/
int
pdf_current_page_id(PDF *p)
{
pdf_pages *dp = p->doc_pages;
if (dp->current_page != 0)
return dp->pages[dp->current_page].id;
else
return pdf_get_page_id(p, 1);
} /* pdf_current_page_id */
int
pdf_last_page(PDF *p)
{
return p->doc_pages->last_page;
} /* pdf_last_page */
int
pdf_search_page_fwd(PDF *p, int start_page, pdc_id id)
{
pdf_pages * dp = p->doc_pages;
int i;
for (i = start_page; i <= dp->last_page; ++i)
{
if (dp->pages[i].id == id)
return i;
}
return -1;
} /* pdf_search_page_fwd */
int
pdf_search_page_bwd(PDF *p, int start_page, pdc_id id)
{
pdf_pages * dp = p->doc_pages;
int i;
if (start_page == -1)
start_page = dp->last_page;
for (i = start_page; i > 0; --i)
{
if (dp->pages[i].id == id)
return i;
}
return -1;
} /* pdf_search_page_bwd */
double
pdf_get_pageheight(PDF *p)
{
pdf_pages * dp = p->doc_pages;
page_obj * po = &dp->pages[dp->current_page];
return po->boxes[pdf_mediabox]->ury - po->boxes[pdf_mediabox]->lly;
} /* pdf_get_pageheight */
void
pdf_set_pagebox(
PDF * p,
pdf_pagebox box,
pdc_scalar llx,
pdc_scalar lly,
pdc_scalar urx,
pdc_scalar ury)
{
static const char fn[] = "pdf_set_pagebox";
pdf_pages * dp = p->doc_pages;
page_obj * po = &dp->pages[dp->current_page];
if (po->boxes[box] == (pdc_rectangle *) 0)
{
po->boxes[box] = (pdc_rectangle *)
pdc_malloc(p->pdc, sizeof (pdc_rectangle), fn);
}
pdc_rect_init(po->boxes[box], llx, lly, urx, ury);
} /* pdf_set_pagebox */
void
pdf_set_pagebox_llx(PDF *p, pdf_pagebox box, pdc_scalar llx)
{
static const char fn[] = "pdf_set_pagebox_llx";
pdf_pages * dp = p->doc_pages;
page_obj * po = &dp->pages[dp->current_page];
if (po->boxes[box] == (pdc_rectangle *) 0)
{
po->boxes[box] = (pdc_rectangle *)
pdc_malloc(p->pdc, sizeof (pdc_rectangle), fn);
pdc_rect_init(po->boxes[box], 0, 0, 0, 0);
}
po->boxes[box]->llx = llx;
} /* pdf_set_pagebox_llx */
void
pdf_set_pagebox_lly(PDF *p, pdf_pagebox box, pdc_scalar lly)
{
static const char fn[] = "pdf_set_pagebox_lly";
pdf_pages * dp = p->doc_pages;
page_obj * po = &dp->pages[dp->current_page];
if (po->boxes[box] == (pdc_rectangle *) 0)
{
po->boxes[box] = (pdc_rectangle *)
pdc_malloc(p->pdc, sizeof (pdc_rectangle), fn);
pdc_rect_init(po->boxes[box], 0, 0, 0, 0);
}
po->boxes[box]->lly = lly;
} /* pdf_set_pagebox_lly */
void
pdf_set_pagebox_urx(PDF *p, pdf_pagebox box, pdc_scalar urx)
{
static const char fn[] = "pdf_set_pagebox_urx";
pdf_pages * dp = p->doc_pages;
page_obj * po = &dp->pages[dp->current_page];
if (po->boxes[box] == (pdc_rectangle *) 0)
{
po->boxes[box] = (pdc_rectangle *)
pdc_malloc(p->pdc, sizeof (pdc_rectangle), fn);
pdc_rect_init(po->boxes[box], 0, 0, 0, 0);
}
po->boxes[box]->urx = urx;
} /* pdf_set_pagebox_urx */
void
pdf_set_pagebox_ury(PDF *p, pdf_pagebox box, pdc_scalar ury)
{
static const char fn[] = "pdf_set_pagebox_ury";
pdf_pages * dp = p->doc_pages;
page_obj * po = &dp->pages[dp->current_page];
if (po->boxes[box] == (pdc_rectangle *) 0)
{
po->boxes[box] = (pdc_rectangle *)
pdc_malloc(p->pdc, sizeof (pdc_rectangle), fn);
pdc_rect_init(po->boxes[box], 0, 0, 0, 0);
}
po->boxes[box]->ury = ury;
} /* pdf_set_pagebox_ury */
const pdc_rectangle *
pdf_get_pagebox(PDF *p, pdf_pagebox box)
{
pdf_pages * dp = p->doc_pages;
page_obj * po = &dp->pages[dp->current_page];
if (po->boxes[box])
return po->boxes[box];
else
return &pdf_null_rect;
} /* pdf_get_pagebox */
pdc_vtr *
pdf_get_annots_list(PDF *p)
{
pdf_pages * dp = p->doc_pages;
return dp->curr_pg->annots;
} /* pdf_get_annots_list */
void
pdf_set_annots_list(PDF *p, pdc_vtr *annots)
{
pdf_pages * dp = p->doc_pages;
if (dp->curr_pg)
dp->curr_pg->annots = annots;
} /* pdf_set_annots_list */
pdc_id
pdf_get_thumb_id(PDF *p)
{
pdf_pages * dp = p->doc_pages;
page_obj * po = &dp->pages[dp->current_page];
return po->thumb_id;
} /* pdf_get_thumb_id */
void
pdf_set_thumb_id(PDF *p, pdc_id id)
{
pdf_pages * dp = p->doc_pages;
page_obj * po = &dp->pages[dp->current_page];
po->thumb_id = id;
} /* pdf_set_thumb_id */
void
pdf_set_autotgroup(PDF *p, pdc_bool autotgroup)
{
pdf_pages * dp = p->doc_pages;
page_obj * po = &dp->pages[dp->current_page];
po->autotgroup = autotgroup;
} /* pdf_set_thumb_id */
/************************* contents sections ***************************/
void
pdf_begin_contents_section(PDF *p)
{
pdf_page *pg = p->doc_pages->curr_pg;
if (PDF_GET_STATE(p) != pdf_state_page || p->doc_pages->in_csect)
return;
p->doc_pages->in_csect = pdc_true;
if (pg->next_content >= pg->contents_ids_capacity) {
pg->contents_ids_capacity *= 2;
pg->contents_ids = (pdc_id *) pdc_realloc(p->pdc, pg->contents_ids,
sizeof(pdc_id) * pg->contents_ids_capacity,
"pdf_begin_contents_section");
}
pg->contents_ids[pg->next_content] = pdc_begin_obj(p->out, PDC_NEW_ID);
pdc_begin_dict(p->out);
p->length_id = pdc_alloc_id(p->out);
pdc_objref(p->out, "/Length", p->length_id);
if (pdc_get_compresslevel(p->out))
pdc_puts(p->out, "/Filter/FlateDecode\n");
pdc_end_dict(p->out);
pdc_begin_pdfstream(p->out);
pg->next_content++;
} /* pdf_begin_contents_section */
void
pdf_end_contents_section(PDF *p)
{
if (!p->doc_pages->in_csect)
return;
p->doc_pages->in_csect = pdc_false;
pdf_end_text(p);
pdc_end_pdfstream(p->out);
pdc_end_obj(p->out);
pdc_put_pdfstreamlength(p->out, p->length_id);
} /* pdf_end_contents_section */
/************************* page tree generation *************************/
static void
pdf_write_pnode(PDF *p,
pdc_id node_id,
pdc_id parent_id,
page_obj *kids,
int n_kids,
int n_pages)
{
pdc_begin_obj(p->out, node_id);
pdc_begin_dict(p->out);
pdc_puts(p->out, "/Type/Pages\n");
pdc_printf(p->out, "/Count %d\n", n_pages);
if (parent_id != PDC_BAD_ID)
pdc_objref(p->out, "/Parent", parent_id);
pdc_puts(p->out, "/Kids");
pdc_begin_array(p->out);
do
{
pdc_objref_c(p->out, kids->id);
++kids;
} while (--n_kids > 0);
pdc_end_array_c(p->out);
pdc_end_dict(p->out);
pdc_end_obj(p->out);
} /* pdf_write_pnode */
#define N_KIDS 10
static pdc_id
pdf_get_pnode_id(PDF *p)
{
static const char fn[] = "pdf_get_pnode_id";
pdf_pages *dp = p->doc_pages;
if (dp->current_pnode_kids == N_KIDS)
{
if (++dp->current_pnode == dp->pnodes_capacity)
{
dp->pnodes_capacity *= 2;
dp->pnodes = (pdc_id *) pdc_realloc(p->pdc, dp->pnodes,
sizeof (pdc_id) * dp->pnodes_capacity, fn);
}
dp->pnodes[dp->current_pnode] = pdc_alloc_id(p->out);
dp->current_pnode_kids = 1;
}
else
++dp->current_pnode_kids;
return dp->pnodes[dp->current_pnode];
} /* pdf_get_pnode_id */
static pdc_id
write_pages_tree(PDF *p,
pdc_id parent_id,
pdc_id *pnodes,
page_obj *pages,
int n_pages)
{
if (n_pages <= N_KIDS)
{
/* this is a near-to-leaf node. use the pre-allocated id
** from dp->pnodes.
*/
pdf_write_pnode(p, *pnodes, parent_id, pages, n_pages, n_pages);
return *pnodes;
}
else
{
pdc_id node_id = pdc_alloc_id(p->out);
page_obj kids[N_KIDS];
int n_kids, rest;
int tpow = N_KIDS;
int i;
/* tpow < n_pages <= tpow*N_KIDS
*/
while (tpow * N_KIDS < n_pages)
tpow *= N_KIDS;
n_kids = n_pages / tpow;
rest = n_pages % tpow;
for (i = 0; i < n_kids; ++i, pnodes += tpow / N_KIDS, pages += tpow)
{
kids[i].id = write_pages_tree(p, node_id, pnodes, pages, tpow);
}
if (rest)
{
kids[i].id = write_pages_tree(p, node_id, pnodes, pages, rest);
++n_kids;
}
pdf_write_pnode(p, node_id, parent_id, kids, n_kids, n_pages);
return node_id;
}
} /* write_pages_tree */
static void
pdf_write_box(PDF *p, pdc_rectangle *box, const char *name)
{
if (!box || pdc_rect_isnull(box))
return;
if (box->urx <= box->llx || box->ury <= box->lly)
{
pdc_error(p->pdc, PDF_E_PAGE_BADBOX, name,
pdc_errprintf(p->pdc, "%f %f %f %f",
box->llx, box->lly, box->urx, box->ury), 0, 0);
}
pdc_printf(p->out, "/%s[%f %f %f %f]\n",
name, box->llx, box->lly, box->urx, box->ury);
} /* pdf_write_box */
pdc_id
pdf_write_pages_tree(PDF *p)
{
int i;
pdf_pages * dp = p->doc_pages;
for (i = dp->last_page + 1; i < dp->pages_capacity; ++i)
{
if (dp->pages[i].id != PDC_BAD_ID)
{
pdc_error(p->pdc, PDF_E_PAGE_ILLREF,
pdc_errprintf(p->pdc, "%d", i), 0, 0, 0);
}
}
for (i = 1; i <= dp->last_page; ++i)
{
page_obj *po = &dp->pages[i];
pdc_begin_obj(p->out, po->id);
pdc_begin_dict(p->out);
pdc_puts(p->out, "/Type/Page\n");
pdc_objref(p->out, "/Parent", pdf_get_pnode_id(p));
if (po->annots_id != PDC_BAD_ID)
pdc_objref(p->out, "/Annots", po->annots_id);
if (po->contents_id != PDC_BAD_ID)
pdc_objref(p->out, "/Contents", po->contents_id);
if (po->res_id != PDC_BAD_ID)
pdc_objref(p->out, "/Resources", po->res_id);
if (po->thumb_id != PDC_BAD_ID)
pdc_objref(p->out, "/Thumb", po->thumb_id);
if (po->duration > 0)
pdc_printf(p->out, "/Dur %f\n", po->duration);
if (po->taborder != (int) tabo_none)
pdc_printf(p->out, "/Tabs/%s\n",
pdc_get_keyword(po->taborder, pdf_taborder_pdfkeylist));
if (po->userunit != 1.0)
pdc_printf(p->out, "/UserUnit %f\n", po->userunit);
if (po->rotate > 0)
pdc_printf(p->out, "/Rotate %d\n", po->rotate);
if (po->action)
pdf_write_action_entries(p, event_page, po->act_idlist);
if (po->transition != trans_none)
{
pdc_puts(p->out, "/Trans");
pdc_begin_dict(p->out);
pdc_printf(p->out, "/S/%s",
pdc_get_keyword(po->transition, pdf_transition_pdfkeylist));
pdc_end_dict(p->out);
}
if (po->tgroup.colorspace != color_none || po->autotgroup)
write_transgroup(p, i);
pdf_write_box(p, po->boxes[pdf_artbox], "ArtBox");
pdf_write_box(p, po->boxes[pdf_bleedbox], "BleedBox");
pdf_write_box(p, po->boxes[pdf_cropbox], "CropBox");
pdf_write_box(p, po->boxes[pdf_mediabox], "MediaBox");
pdf_write_box(p, po->boxes[pdf_trimbox], "TrimBox");
pdc_end_dict(p->out);
pdc_end_obj(p->out);
}
return write_pages_tree(p, PDC_BAD_ID, dp->pnodes, dp->pages + 1,
dp->last_page);
} /* pdf_write_pages_tree */
/**************************** resource lists ****************************/
static void
pdf_init_reslist(pdf_reslist *rl)
{
rl->length = 0;
rl->capacity = 0;
rl->list = (int *) 0;
} /* pdf_init_reslist */
void
pdf_add_reslist(PDF *p, pdf_reslist *rl, int num)
{
static const char fn[] = "pdf_add_reslist";
if (rl->length == rl->capacity)
{
if (rl->capacity == 0)
{
rl->capacity = RESLIST_CHUNKSIZE;
rl->list = (int *)
pdc_malloc(p->pdc, rl->capacity * sizeof (pdf_reslist), fn);
}
else
{
rl->capacity *= 2;
rl->list = (int *) pdc_realloc(p->pdc,
rl->list, rl->capacity * sizeof (pdf_reslist), fn);
}
}
rl->list[rl->length++] = num;
} /* pdf_add_reslist */
/****************************** begin_page ******************************/
/* begin_page_ext() only:
*/
#define PDF_ICC_FLAG PDC_OPT_UNSUPP
#define PDF_SPOT_FLAG PDC_OPT_UNSUPP
#define PDF_METADATA_FLAG PDC_OPT_UNSUPP
static const pdc_defopt pdf_sepinfo_options[] =
{
{"pages", pdc_integerlist, PDC_OPT_NONE, 1, 1,
1.0, PDC_INT_MAX, NULL},
{"spotname", pdc_stringlist, PDC_OPT_NONE, 1, 1,
1.0, PDF_MAX_NAMESTRING, NULL},
{"spotcolor", pdc_colorhandle, PDC_OPT_NONE, 1, 1,
1.0, PDC_INT_MAX, NULL},
PDC_OPT_TERMINATE
};
#define PDF_PAGE_OPTIONS1 \
\
{"topdown", pdc_booleanlist, PDC_OPT_NONE, 1, 1, \
0.0, 0.0, NULL}, \
\
{"defaultgray", pdc_iccprofilehandle, PDF_ICC_FLAG, 1, 1, \
0.0, PDC_INT_MAX, NULL}, \
\
{"defaultrgb", pdc_iccprofilehandle, PDF_ICC_FLAG, 1, 1, \
0.0, PDC_INT_MAX, NULL}, \
\
{"defaultcmyk", pdc_iccprofilehandle, PDF_ICC_FLAG, 1, 1, \
0.0, PDC_INT_MAX, NULL}, \
\
{"separationinfo", pdc_stringlist, PDF_SPOT_FLAG, 1, 1, \
0.0, PDC_USHRT_MAX, NULL}, \
/* begin_page_ext() and resume_page():
*/
#define PDF_PAGE_OPTIONS2 \
\
{"group", pdc_stringlist, PDC_OPT_NONE, 1, 1, \
1.0, PDF_MAX_NAMESTRING, NULL}, \
\
{"pagenumber", pdc_integerlist, PDC_OPT_NONE, 1, 1, \
1.0, PDC_INT_MAX, NULL}, \
/* begin_page_ext() and end_page_ext():
*/
static const pdc_keyconn pdf_pagedim_keylist[] =
{
{ "a0.width", (int) a0_width },
{ "a0.height", (int) a0_height },
{ "a1.width", (int) a1_width },
{ "a1.height", (int) a1_height },
{ "a2.width", (int) a2_width },
{ "a2.height", (int) a2_height },
{ "a3.width", (int) a3_width },
{ "a3.height", (int) a3_height },
{ "a4.width", (int) a4_width },
{ "a4.height", (int) a4_height },
{ "a5.width", (int) a5_width },
{ "a5.height", (int) a5_height },
{ "a6.width", (int) a6_width },
{ "a6.height", (int) a6_height },
{ "b5.width", (int) b5_width },
{ "b5.height", (int) b5_height },
{ "letter.width", (int) letter_width },
{ "letter.height", (int) letter_height },
{ "legal.width", (int) legal_width },
{ "legal.height", (int) legal_height },
{ "ledger.width", (int) ledger_width },
{ "ledger.height", (int) ledger_height },
{ "11x17.width", (int) p11x17_width },
{ "11x17.height", (int) p11x17_height },
{ NULL, 0 }
};
typedef enum
{
pdf_unit_mm = -1000,
pdf_unit_cm = -100,
pdf_unit_m = -1
}
pdf_page_unit;
static const pdc_keyconn pdf_userunit_keylist[] =
{
{ "mm", pdf_unit_mm },
{ "cm", pdf_unit_cm },
{ "m", pdf_unit_m },
{ NULL, 0 }
};
#define PDF_PAGE_OPTIONS3 \
\
{"action", pdc_stringlist, PDC_OPT_NONE, 1, 1, \
1.0, PDF_MAX_NAMESTRING, NULL}, \
\
{"artbox", pdc_scalarlist, PDC_OPT_NONE, 4, 4,\
PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL},\
\
{"bleedbox", pdc_scalarlist, PDC_OPT_NONE, 4, 4,\
PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL},\
\
{"cropbox", pdc_scalarlist, PDC_OPT_NONE, 4, 4,\
PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL},\
\
{"duration", pdc_scalarlist, PDC_OPT_NONE, 1, 1,\
0.0, PDC_FLOAT_MAX, NULL},\
\
{"height", pdc_scalarlist, PDC_OPT_NONE, 1, 1,\
0.0, PDC_FLOAT_MAX, pdf_pagedim_keylist},\
\
{"label", pdc_stringlist, PDC_OPT_NONE, 1, 1, \
0.0, PDC_USHRT_MAX, NULL}, \
\
{"mediabox", pdc_scalarlist, PDC_OPT_NONE, 4, 4,\
PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL},\
\
{"metadata", pdc_stringlist, PDF_METADATA_FLAG, 1, 1, \
0.0, PDC_INT_MAX, NULL}, \
\
{"rotate", pdc_integerlist, PDC_OPT_NONE, 1, 1, \
0.0, 270, NULL}, \
\
{"transition", pdc_keywordlist, PDC_OPT_NONE, 1, 1, \
0.0, 0.0, pdf_transition_keylist}, \
\
{"transparencygroup", pdc_stringlist, PDC_OPT_PDC_1_4, 1, 1, \
1.0, PDF_MAX_NAMESTRING, NULL}, \
\
{"taborder", pdc_keywordlist, PDC_OPT_PDC_1_5, 1, 1, \
0.0, 0.0, pdf_taborder_keylist}, \
\
{"trimbox", pdc_scalarlist, PDC_OPT_NONE, 4, 4,\
PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL},\
\
{"userunit", pdc_scalarlist, PDC_OPT_PDC_1_6, 1, 1,\
1.0, 75000, pdf_userunit_keylist},\
\
{"width", pdc_scalarlist, PDC_OPT_NONE, 1, 1,\
0.0, PDC_FLOAT_MAX, pdf_pagedim_keylist},\
/* common helper function for pdf__begin_page_ext() and pdf__resume_page().
** returns the target group (if any) and the target page number. the
** page number is relative to the group (if available). page number -1
** means "no page number".
*/
static pg_group *
get_page_options2(PDF *p, pdc_resopt *resopts, int *pageno)
{
pdf_pages * dp = p->doc_pages;
pg_group * group = (pg_group *) 0;
char ** strlist;
*pageno = -1;
if (pdc_get_optvalues("pagenumber", resopts, pageno, NULL))
{
if (*pageno <= 0)
pdc_error(p->pdc, PDF_E_PAGE_ILLNUMBER,
pdc_errprintf(p->pdc, "%d", *pageno), 0, 0, 0);
}
if (pdc_get_optvalues("group", resopts, NULL, &strlist))
{
if ((group = find_group(dp, strlist[0])) == (pg_group *) 0)
pdc_error(p->pdc, PDF_E_DOC_UNKNOWNGROUP, strlist[0], 0, 0, 0);
}
if (group)
{
if (*pageno > group->n_pages)
pdc_error(p->pdc, PDF_E_PAGE_NOTEXIST2,
pdc_errprintf(p->pdc, "%d", *pageno), group->name, 0, 0);
}
else
{
if (dp->have_groups)
pdc_error(p->pdc, PDF_E_PAGE_NEEDGROUP, 0, 0, 0, 0);
if (*pageno > dp->last_page)
pdc_error(p->pdc, PDF_E_PAGE_NOTEXIST,
pdc_errprintf(p->pdc, "%d", *pageno), 0, 0, 0);
}
return group;
} /* get_page_options2 */
static pdc_rectangle *
pdf_new_box(PDF *p, const pdc_rectangle *box)
{
static const char fn[] = "pdf_new_box";
pdc_rectangle *result = (pdc_rectangle *)
pdc_malloc(p->pdc, sizeof (pdc_rectangle), fn);
if (box)
*result = *box;
else
pdc_rect_init(result, 0, 0, 0, 0);
return result;
} /* pdf_new_box */
/* common helper function for pdf__begin_page_ext() and pdf__end_page_ext().
*/
static void
get_page_options3(PDF *p, pdc_resopt *resopts, pdc_bool end_page)
{
pdf_pages * dp = p->doc_pages;
int pageno = dp->current_page;
page_obj * po = &dp->pages[pageno];
pdc_scalar width;
pdc_scalar height;
pdc_bool has_width;
pdc_bool has_height;
pdc_bool has_mediabox;
pdc_rectangle box;
char **slist;
if (pdc_get_optvalues("action", resopts, NULL, NULL))
{
po->action = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
pdf_parse_and_write_actionlist(p, event_page, NULL,
(char *) po->action);
}
if (pdc_get_optvalues("artbox", resopts, &box, NULL))
po->boxes[pdf_artbox] = pdf_new_box(p, &box);
if (pdc_get_optvalues("bleedbox", resopts, &box, NULL))
po->boxes[pdf_bleedbox] = pdf_new_box(p, &box);
if (pdc_get_optvalues("cropbox", resopts, &box, NULL))
po->boxes[pdf_cropbox] = pdf_new_box(p, &box);
if (pdc_get_optvalues("trimbox", resopts, &box, NULL))
po->boxes[pdf_trimbox] = pdf_new_box(p, &box);
pdc_get_optvalues("taborder", resopts, &po->taborder, NULL);
pdc_get_optvalues("duration", resopts, &po->duration, NULL);
pdc_get_optvalues("userunit", resopts, &po->userunit, NULL);
if (po->userunit < 0.0)
po->userunit = 72.0 / (PDC_INCH2METER * -po->userunit);
if (pdc_get_optvalues("label", resopts, NULL, NULL))
{
char *pagelabel = pdf_get_opt_utf8name(p, "label", resopts);
pdf_set_pagelabel(p, pagelabel, pageno);
pdc_free(p->pdc, pagelabel);
}
if (pdc_get_optvalues("transparencygroup", resopts, NULL, &slist))
pdf_set_transgroup(p, slist[0], pageno);
/* the "width" and "height" options must be processed BEFORE the
** "mediabox" option, since the latter dominates over the formers.
*/
has_width = pdc_get_optvalues("width", resopts, &width, NULL);
has_height = pdc_get_optvalues("height", resopts, &height, NULL);
if (has_width)
po->boxes[pdf_mediabox]->urx = po->boxes[pdf_mediabox]->llx + width;
if (has_height)
po->boxes[pdf_mediabox]->ury = po->boxes[pdf_mediabox]->lly + height;
has_mediabox =
pdc_get_optvalues("mediabox", resopts, po->boxes[pdf_mediabox], NULL);
width = po->boxes[pdf_mediabox]->urx - po->boxes[pdf_mediabox]->llx;
height = po->boxes[pdf_mediabox]->ury - po->boxes[pdf_mediabox]->lly;
if (p->ydirection == -1)
{
if (end_page)
{
if (has_mediabox || has_width || has_height)
pdc_error(p->pdc, PDF_E_PAGE_ILLCHGSIZE, 0, 0, 0, 0);
}
else
{
if (width == 0 || height == 0)
pdc_error(p->pdc, PDF_E_PAGE_TOPDOWN_NODIMS, 0, 0, 0, 0);
if ((height < PDF_ACRO_MINPAGE || width < PDF_ACRO_MINPAGE ||
height > PDF_ACRO_MAXPAGE || width > PDF_ACRO_MAXPAGE))
pdc_warning(p->pdc, PDF_E_PAGE_SIZE_ACRO, 0, 0, 0, 0);
}
}
pdc_get_optvalues("rotate", resopts, &po->rotate, NULL);
switch (po->rotate)
{
case 0: case 90: case 180: case 270:
break;
default:
pdc_error(p->pdc, PDF_E_PAGE_ILLROTATE,
pdc_errprintf(p->pdc, "%d", po->rotate), 0, 0, 0);
}
pdc_get_optvalues("transition", resopts, &po->transition, NULL);
if (po->transition >= (int) TRANS_1_5 && p->compatibility < PDC_1_5)
pdc_error(p->pdc, PDF_E_PAGE_TRANS_COMPAT,
pdc_get_keyword(po->transition, pdf_transition_keylist), 0, 0, 0);
} /* get_page_options3 */
#if 0
#endif
static const pdc_defopt pdf_begin_page_ext_options[] =
{
PDF_PAGE_OPTIONS1
PDF_PAGE_OPTIONS2
PDF_PAGE_OPTIONS3
PDC_OPT_TERMINATE
};
void
pdf__begin_page_ext(
PDF * p,
pdc_scalar width,
pdc_scalar height,
const char *optlist)
{
static const char fn[] = "pdf__begin_page_ext";
pdf_pages * dp = p->doc_pages;
pdf_page * pg;
page_obj * po;
pdc_resopt *resopts = NULL;
pg_group * group = (pg_group *) 0;
int pageno = -1;
pdc_check_number_limits(p->pdc, "width", width, 0.0, PDC_FLOAT_MAX);
pdc_check_number_limits(p->pdc, "height", height, 0.0, PDC_FLOAT_MAX);
if (optlist && *optlist)
{
pdc_clientdata cdata;
pdf_set_clientdata(p, &cdata);
resopts = pdc_parse_optionlist(p->pdc,
optlist, pdf_begin_page_ext_options, &cdata, pdc_true);
group = get_page_options2(p, resopts, &pageno);
}
if (group)
{
if (pageno == -1)
pageno = group->start + group->n_pages;
else
pageno = group->start + pageno - 1;
if (++group->n_pages > group->capacity)
{
grow_group(p, group, pageno, 1);
}
else if (pageno < group->start + group->n_pages - 1)
{
memmove(&dp->pages[pageno + 1], &dp->pages[pageno],
(group->start + group->n_pages - pageno) * sizeof (page_obj));
pdf_init_page_obj(&dp->pages[pageno]);
}
if (dp->last_page < group->start + group->n_pages - 1)
dp->last_page = group->start + group->n_pages - 1;
}
else
{
if (dp->last_page + 1 >= dp->pages_capacity)
pdf_grow_pages(p);
++dp->last_page;
if (dp->last_page > dp->max_page)
++dp->max_page;
if (pageno == -1)
pageno = dp->last_page;
if (pageno != dp->last_page)
{
memmove(&dp->pages[pageno + 1], &dp->pages[pageno],
(dp->max_page - pageno) * sizeof (page_obj));
pdf_init_page_obj(&dp->pages[pageno]);
}
}
po = &dp->pages[pageno];
dp->current_page = pageno;
/* no id has been preallocated */
if (po->id == PDC_BAD_ID)
po->id = pdc_alloc_id(p->out);
pg = dp->curr_pg = (pdf_page *) pdc_malloc(p->pdc, sizeof (pdf_page), fn);
p->curr_ppt = &pg->ppt;
pg->contents_ids = (pdc_id *) 0;
pg->annots = (pdc_vtr *) 0;
/* save and take over global parameters.
*/
pg->ydir = dp->old_ydir = p->ydirection;
pg->rl_colorspaces.list = (int *) 0;
pg->rl_extgstates.list = (int *) 0;
pg->rl_fonts.list = (int *) 0;
pg->rl_layers.list = (int *) 0;
pg->rl_patterns.list = (int *) 0;
pg->rl_shadings.list = (int *) 0;
pg->rl_xobjects.list = (int *) 0;
pg->contents_ids_capacity = CONTENTS_CHUNKSIZE;
pg->contents_ids = (pdc_id *) pdc_malloc(p->pdc,
sizeof(pdc_id) * pg->contents_ids_capacity, fn);
/* might be overwritten by options */
po->boxes[pdf_mediabox] = pdf_new_box(p, 0);
pdc_rect_init(po->boxes[pdf_mediabox], 0, 0, width, height);
if (resopts)
{
pdc_bool topdown = pdc_false;
if (pdc_get_optvalues("topdown", resopts, &topdown, NULL))
p->ydirection = pg->ydir = topdown ? -1 : 1;
get_page_options3(p, resopts, pdc_false);
}
/* initialize the current ppt descriptor. p->ydirection
** must be set before pdf_init_ppt()!
*/
pdf_init_ppt(p, pdc_true);
pg->next_content = 0;
pdf_init_reslist(&pg->rl_colorspaces);
pdf_init_reslist(&pg->rl_extgstates);
pdf_init_reslist(&pg->rl_fonts);
pdf_init_reslist(&pg->rl_layers);
pdf_init_reslist(&pg->rl_patterns);
pdf_init_reslist(&pg->rl_shadings);
pdf_init_reslist(&pg->rl_xobjects);
PDF_SET_STATE(p, pdf_state_page);
pdf_begin_contents_section(p);
/* top-down y coordinates */
pdf_set_topdownsystem(p, pdf_get_pageheight(p));
/* set color differing from PDF default */
pdf_set_default_color(p, pdc_false);
#if 0
#endif
if (!p->pdc->smokerun)
pdc_logg_cond(p->pdc, 1, trc_api, "[Begin page #%d]\n",
dp->current_page);
} /* pdf__begin_page_ext */
void
pdf__begin_page(
PDF * p,
pdc_scalar width,
pdc_scalar height)
{
if (p->doc_pages->have_groups)
pdc_error(p->pdc, PDF_E_PAGE_NEEDGROUP2, 0, 0, 0, 0);
pdf__begin_page_ext(p, width, height, 0);
} /* pdf__begin_page */
/*************************** suspend & resume ***************************/
void
pdf_pg_suspend(PDF *p)
{
pdf_pages *dp = p->doc_pages;
if (PDF_GET_STATE(p) != pdf_state_page)
{
dp->last_suspended = -1;
}
else
{
pdf_page *pg = dp->curr_pg;
pdf_end_contents_section(p);
/* restore global parms.
*/
p->ydirection = dp->old_ydir;
pdf_get_page_colorspaces(p, &pg->rl_colorspaces);
pdf_get_page_extgstates(p, &pg->rl_extgstates);
pdf_get_page_fonts(p, &pg->rl_fonts);
pdf_get_page_patterns(p, &pg->rl_patterns);
pdf_get_page_shadings(p, &pg->rl_shadings);
pdf_get_page_xobjects(p, &pg->rl_xobjects);
dp->pages[dp->current_page].pg = pg;
dp->curr_pg = (pdf_page *) 0;
dp->last_suspended = dp->current_page;
/* restore the default ppt for out-of-page usage.
*/
p->curr_ppt = &dp->default_ppt;
}
pdf_init_ppt(p, pdc_false);
} /* pdf_pg_suspend */
static const pdc_defopt pdf_suspend_page_options[] =
{
PDC_OPT_TERMINATE
};
void
pdf__suspend_page(PDF *p, const char *optlist)
{
if (optlist && *optlist)
{
pdc_resopt *resopts = pdc_parse_optionlist(p->pdc,
optlist, pdf_suspend_page_options, NULL, pdc_true);
(void) resopts;
}
pdf_pg_suspend(p);
PDF_SET_STATE(p, pdf_state_document);
if (!p->pdc->smokerun)
pdc_logg_cond(p->pdc, 1, trc_api, "[Suspend page #%d]\n",
p->doc_pages->current_page);
} /* pdf__suspend_page */
void
pdf_pg_resume(PDF *p, int pageno)
{
pdf_pages *dp = p->doc_pages;
pdf_reset_ppt(p->curr_ppt);
if (pageno == -1)
{
pageno = dp->last_suspended;
dp->last_suspended = -1;
}
if (pageno == -1)
{
PDF_SET_STATE(p, pdf_state_document);
}
else
{
pdf_page *pg;
int i;
/* prevent error cleanup from killing the same page twice.
*/
pg = dp->curr_pg = dp->pages[pageno].pg;
dp->pages[pageno].pg = (pdf_page *) 0;
dp->current_page = pageno;
p->curr_ppt = &pg->ppt;
PDF_SET_STATE(p, pdf_state_page);
/* save global parameters and replace them
** with the page specific ones.
*/
dp->old_ydir = p->ydirection;
p->ydirection = pg->ydir;
pdf_begin_contents_section(p);
/* mark global resources as "used on current page".
*/
for (i = 0; i < pg->rl_colorspaces.length; ++i)
pdf_mark_page_colorspace(p, pg->rl_colorspaces.list[i]);
for (i = 0; i < pg->rl_extgstates.length; ++i)
pdf_mark_page_extgstate(p, pg->rl_extgstates.list[i]);
for (i = 0; i < pg->rl_fonts.length; ++i)
pdf_mark_page_font(p, pg->rl_fonts.list[i]);
for (i = 0; i < pg->rl_patterns.length; ++i)
pdf_mark_page_pattern(p, pg->rl_patterns.list[i]);
for (i = 0; i < pg->rl_shadings.length; ++i)
pdf_mark_page_shading(p, pg->rl_shadings.list[i]);
for (i = 0; i < pg->rl_xobjects.length; ++i)
pdf_mark_page_xobject(p, pg->rl_xobjects.list[i]);
}
} /* pdf_pg_resume */
static const pdc_defopt pdf_resume_page_options[] =
{
PDF_PAGE_OPTIONS2
PDC_OPT_TERMINATE
};
void
pdf__resume_page(PDF *p, const char *optlist)
{
pdf_pages * dp = p->doc_pages;
pg_group * group = (pg_group *) 0;
int pageno = -1; /* logical page number */
int physno; /* physical page number */
if (optlist && *optlist)
{
pdc_resopt *resopts = pdc_parse_optionlist(p->pdc,
optlist, pdf_resume_page_options, NULL, pdc_true);
group = get_page_options2(p, resopts, &pageno);
}
if (group)
{
if (pageno == -1)
pageno = group->n_pages;
physno = group->start + pageno - 1;
}
else
{
if (pageno == -1)
pageno = dp->last_page;
physno = pageno;
}
if (dp->pages[physno].pg == (pdf_page *) 0)
{
if (group)
{
pdc_error(p->pdc, PDF_E_PAGE_NOSUSPEND2,
pdc_errprintf(p->pdc, "%d", pageno), group->name, 0, 0);
}
else
{
pdc_error(p->pdc, PDF_E_PAGE_NOSUSPEND,
pdc_errprintf(p->pdc, "%d", pageno), 0, 0, 0);
}
}
pdf_pg_resume(p, physno);
if (!p->pdc->smokerun)
pdc_logg_cond(p->pdc, 1, trc_api, "[Resume page #%d]\n", physno);
} /* pdf__resume_page */
/******************************* end_page *******************************/
static const pdc_defopt pdf_end_page_ext_options[] =
{
PDF_PAGE_OPTIONS3
PDC_OPT_TERMINATE
};
void
pdf__end_page_ext(PDF *p, const char *optlist)
{
static const char fn[] = "pdf__end_page_ext";
pdf_pages * dp = p->doc_pages;
page_obj * po = &dp->pages[dp->current_page];
pdc_scalar width;
pdc_scalar height;
pdf_page * pg;
pdf_ppt * ppt = p->curr_ppt;
int i;
if (optlist && *optlist)
{
pdc_resopt *resopts = pdc_parse_optionlist(p->pdc,
optlist, pdf_end_page_ext_options, NULL, pdc_true);
get_page_options3(p, resopts, pdc_true);
}
width = po->boxes[pdf_mediabox]->urx - po->boxes[pdf_mediabox]->llx;
height = po->boxes[pdf_mediabox]->ury - po->boxes[pdf_mediabox]->lly;
if (width == 0 || height == 0)
pdc_error(p->pdc, PDF_E_PAGE_NODIMS, 0, 0, 0, 0);
if ((height < PDF_ACRO_MINPAGE || width < PDF_ACRO_MINPAGE ||
height > PDF_ACRO_MAXPAGE || width > PDF_ACRO_MAXPAGE))
pdc_warning(p->pdc, PDF_E_PAGE_SIZE_ACRO, 0, 0, 0, 0);
/* check whether PDF_save() and PDF_restore() calls are balanced */
if (ppt->sl > 0)
pdc_error(p->pdc, PDF_E_GSTATE_UNMATCHEDSAVE, 0, 0, 0, 0);
/* TODO (york): avoid memory leak in error case. */
pg = dp->curr_pg;
#if 0
#endif
pdf_end_contents_section(p);
/* if no "duration" or "transition" options have been specified
** for this page, fall back on the (deprecated) global parameters.
*/
if (po->duration == -1)
po->duration = dp->duration;
if (po->transition == -1)
po->transition = dp->transition;
if (pg->next_content > 0)
{
if (pg->next_content == 1)
{
po->contents_id = pg->contents_ids[0];
}
else
{
po->contents_id = pdc_begin_obj(p->out, PDC_NEW_ID);
pdc_begin_array(p->out);
for (i = 0; i < pg->next_content; ++i)
{
pdc_objref_c(p->out, pg->contents_ids[i]);
}
pdc_end_array(p->out);
pdc_end_obj(p->out);
}
}
if (po->action)
{
po->act_idlist = (pdc_id *)
pdc_malloc(p->pdc, PDF_MAX_EVENTS * sizeof (pdc_id), fn);
pdf_parse_and_write_actionlist(p, event_page, po->act_idlist,
po->action);
}
po->annots_id = pdf_write_annots_root(p, pg->annots, NULL);
/* resources dictionary
*/
po->res_id = pdc_begin_obj(p->out, PDC_NEW_ID);
pdc_begin_dict(p->out);
pdf_write_page_fonts(p); /* Font resources */
pdf_write_page_colorspaces(p); /* ColorSpace resources */
pdf_write_page_pattern(p); /* Pattern resources */
pdf_write_page_shadings(p); /* Shading resources */
pdf_write_xobjects(p); /* XObject resources */
pdf_write_page_extgstates(p); /* ExtGState resources */
pdc_end_dict(p->out);
pdc_end_obj(p->out);
if (pg->annots != (pdc_vtr *) 0)
pdf_write_page_annots(p, pg->annots); /* Annotation dicts */
/* restore global parms.
*/
p->ydirection = dp->old_ydir;
/* restore the default ppt for out-of-page usage.
*/
p->curr_ppt = &dp->default_ppt;
pdf_init_ppt(p, pdc_false);
PDF_SET_STATE(p, pdf_state_document);
pdf_delete_page(p, pg);
dp->curr_pg = (pdf_page *) 0;
if (p->flush & (pdc_flush_page | pdc_flush_content))
pdc_flush_stream(p->out);
if (!p->pdc->smokerun)
pdc_logg_cond(p->pdc, 1, trc_api, "[End page #%d]\n",
dp->current_page);
} /* pdf__end_page_ext */
/*****************************************************************************/
/** deprecated historical page functions **/
/*****************************************************************************/
/* set page display duration for current and future pages */
void
pdf_set_duration(PDF *p, double t)
{
p->doc_pages->duration = t;
}
/* set transition mode for current and future pages */
void
pdf_set_transition(PDF *p, const char *transition)
{
int i;
if (transition == NULL || !*transition)
transition = "none";
i = pdc_get_keycode_ci(transition, pdf_transition_keylist);
if (i == PDC_KEY_NOTFOUND)
pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, transition, "transition", 0, 0);
if (i >= (int) TRANS_1_5 && p->compatibility < PDC_1_5)
pdc_error(p->pdc, PDF_E_PAGE_TRANS_COMPAT,
pdc_get_keyword(i, pdf_transition_keylist), 0, 0, 0);
p->doc_pages->transition = i;
}