Files correlati : pdflib Ricompilazione Demo : [ ] Commento : Aggiornata PDFlib git-svn-id: svn://10.65.10.50/trunk@17433 c028cbd2-c16b-5b4b-a496-9718f37d4682
2290 lines
55 KiB
C
Executable File
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;
|
|
}
|
|
|
|
|