kolibrios-gitea/contrib/media/updf/pdf/pdf_annot.c

235 lines
4.2 KiB
C
Raw Normal View History

#include "fitz.h"
#include "mupdf.h"
void
pdf_free_link(pdf_link *link)
{
if (link->next)
pdf_free_link(link->next);
if (link->dest)
fz_drop_obj(link->dest);
fz_free(link);
}
static fz_obj *
resolve_dest(pdf_xref *xref, fz_obj *dest)
{
if (fz_is_name(dest) || fz_is_string(dest))
{
dest = pdf_lookup_dest(xref, dest);
return resolve_dest(xref, dest);
}
else if (fz_is_array(dest))
{
return dest;
}
else if (fz_is_dict(dest))
{
dest = fz_dict_gets(dest, "D");
return resolve_dest(xref, dest);
}
else if (fz_is_indirect(dest))
return dest;
return NULL;
}
pdf_link *
pdf_load_link(pdf_xref *xref, fz_obj *dict)
{
fz_obj *dest;
fz_obj *action;
fz_obj *obj;
fz_rect bbox;
pdf_link_kind kind;
dest = NULL;
obj = fz_dict_gets(dict, "Rect");
if (obj)
bbox = pdf_to_rect(obj);
else
bbox = fz_empty_rect;
obj = fz_dict_gets(dict, "Dest");
if (obj)
{
kind = PDF_LINK_GOTO;
dest = resolve_dest(xref, obj);
}
action = fz_dict_gets(dict, "A");
/* fall back to additional action button's down/up action */
if (!action)
action = fz_dict_getsa(fz_dict_gets(dict, "AA"), "U", "D");
if (action)
{
obj = fz_dict_gets(action, "S");
if (fz_is_name(obj) && !strcmp(fz_to_name(obj), "GoTo"))
{
kind = PDF_LINK_GOTO;
dest = resolve_dest(xref, fz_dict_gets(action, "D"));
}
else if (fz_is_name(obj) && !strcmp(fz_to_name(obj), "URI"))
{
kind = PDF_LINK_URI;
dest = fz_dict_gets(action, "URI");
}
else if (fz_is_name(obj) && !strcmp(fz_to_name(obj), "Launch"))
{
kind = PDF_LINK_LAUNCH;
dest = fz_dict_gets(action, "F");
}
else if (fz_is_name(obj) && !strcmp(fz_to_name(obj), "Named"))
{
kind = PDF_LINK_NAMED;
dest = fz_dict_gets(action, "N");
}
else if (fz_is_name(obj) && (!strcmp(fz_to_name(obj), "GoToR")))
{
kind = PDF_LINK_ACTION;
dest = action;
}
else
{
dest = NULL;
}
}
if (dest)
{
pdf_link *link = fz_malloc(sizeof(pdf_link));
link->kind = kind;
link->rect = bbox;
link->dest = fz_keep_obj(dest);
link->next = NULL;
return link;
}
return NULL;
}
void
pdf_load_links(pdf_link **linkp, pdf_xref *xref, fz_obj *annots)
{
pdf_link *link, *head, *tail;
fz_obj *obj;
int i;
head = tail = NULL;
link = NULL;
for (i = 0; i < fz_array_len(annots); i++)
{
obj = fz_array_get(annots, i);
link = pdf_load_link(xref, obj);
if (link)
{
if (!head)
head = tail = link;
else
{
tail->next = link;
tail = link;
}
}
}
*linkp = head;
}
void
pdf_free_annot(pdf_annot *annot)
{
if (annot->next)
pdf_free_annot(annot->next);
if (annot->ap)
pdf_drop_xobject(annot->ap);
if (annot->obj)
fz_drop_obj(annot->obj);
fz_free(annot);
}
static void
pdf_transform_annot(pdf_annot *annot)
{
fz_matrix matrix = annot->ap->matrix;
fz_rect bbox = annot->ap->bbox;
fz_rect rect = annot->rect;
float w, h, x, y;
bbox = fz_transform_rect(matrix, bbox);
w = (rect.x1 - rect.x0) / (bbox.x1 - bbox.x0);
h = (rect.y1 - rect.y0) / (bbox.y1 - bbox.y0);
x = rect.x0 - bbox.x0;
y = rect.y0 - bbox.y0;
annot->matrix = fz_concat(fz_scale(w, h), fz_translate(x, y));
}
void
pdf_load_annots(pdf_annot **annotp, pdf_xref *xref, fz_obj *annots)
{
pdf_annot *annot, *head, *tail;
fz_obj *obj, *ap, *as, *n, *rect;
pdf_xobject *form;
fz_error error;
int i;
head = tail = NULL;
annot = NULL;
for (i = 0; i < fz_array_len(annots); i++)
{
obj = fz_array_get(annots, i);
rect = fz_dict_gets(obj, "Rect");
ap = fz_dict_gets(obj, "AP");
as = fz_dict_gets(obj, "AS");
if (fz_is_dict(ap))
{
n = fz_dict_gets(ap, "N"); /* normal state */
/* lookup current state in sub-dictionary */
if (!pdf_is_stream(xref, fz_to_num(n), fz_to_gen(n)))
n = fz_dict_get(n, as);
if (pdf_is_stream(xref, fz_to_num(n), fz_to_gen(n)))
{
error = pdf_load_xobject(&form, xref, n);
if (error)
{
fz_catch(error, "ignoring broken annotation");
continue;
}
annot = fz_malloc(sizeof(pdf_annot));
annot->obj = fz_keep_obj(obj);
annot->rect = pdf_to_rect(rect);
annot->ap = form;
annot->next = NULL;
pdf_transform_annot(annot);
if (annot)
{
if (!head)
head = tail = annot;
else
{
tail->next = annot;
tail = annot;
}
}
}
}
}
*annotp = head;
}