Commit f5ff2578 authored by Nelson Benítez León's avatar Nelson Benítez León Committed by Albert Astals Cid

glib: automatic handle of page's cropbox on annots

Core poppler annot (Annot.cc) has cropbox offsets included
in the coordinates of the relevant fields (rect and
quadrilaterals fields).

This commit makes poppler-glib API _not_ include cropbox
offsets when providing annot info to clients (by substracting
cropbox offsets from the read core Annot info) and in the same
way, assumes no cropbox offsets are included in the info
received from clients to create new annots (cropbox offsets will
be automatically added to the corresponding core poppler Annot).

As a result of this, existent clients (like Evince) now automatically
work right for annotations placed in pages that have a cropbox.

Poppler issue: poppler/poppler#129
Evince issue: https://gitlab.gnome.org/GNOME/evince/issues/1280
parent 8ed4623c
......@@ -264,30 +264,49 @@ _poppler_annot_text_markup_new (Annot *annot)
return _poppler_create_annot (POPPLER_TYPE_ANNOT_TEXT_MARKUP, annot);
}
/* If @crop_box parameter is non null, it will add the crop_box offset
* to the coordinates of the returned quads */
static AnnotQuadrilaterals *
create_annot_quads_from_poppler_quads (GArray *quads)
create_annot_quads_from_poppler_quads (GArray *quads,
const PDFRectangle *crop_box)
{
PDFRectangle zerobox;
g_assert (quads->len > 0);
if (!crop_box) {
zerobox = PDFRectangle();
crop_box = &zerobox;
}
auto quads_array = std::make_unique<AnnotQuadrilaterals::AnnotQuadrilateral[]>(quads->len);
for (guint i = 0; i < quads->len; i++) {
PopplerQuadrilateral *quadrilateral = &g_array_index (quads, PopplerQuadrilateral, i);
quads_array[i] = AnnotQuadrilaterals::AnnotQuadrilateral (
quadrilateral->p1.x, quadrilateral->p1.y,
quadrilateral->p2.x, quadrilateral->p2.y,
quadrilateral->p3.x, quadrilateral->p3.y,
quadrilateral->p4.x, quadrilateral->p4.y);
quadrilateral->p1.x + crop_box->x1, quadrilateral->p1.y + crop_box->y1,
quadrilateral->p2.x + crop_box->x1, quadrilateral->p2.y + crop_box->y1,
quadrilateral->p3.x + crop_box->x1, quadrilateral->p3.y + crop_box->y1,
quadrilateral->p4.x + crop_box->x1, quadrilateral->p4.y + crop_box->y1);
}
return new AnnotQuadrilaterals (std::move(quads_array), quads->len);
}
/* If @crop_box parameter is non null, it will substract the crop_box offset
* from the coordinates of the returned #PopplerQuadrilateral array */
static GArray *
create_poppler_quads_from_annot_quads (AnnotQuadrilaterals *quads_array)
create_poppler_quads_from_annot_quads (AnnotQuadrilaterals *quads_array,
const PDFRectangle *crop_box)
{
GArray *quads;
guint quads_len;
PDFRectangle zerobox;
if (!crop_box) {
zerobox = PDFRectangle();
crop_box = &zerobox;
}
quads_len = quads_array->getQuadrilateralsLength();
quads = g_array_sized_new (FALSE, FALSE,
......@@ -298,14 +317,14 @@ create_poppler_quads_from_annot_quads (AnnotQuadrilaterals *quads_array)
for (guint i = 0; i < quads_len; ++i) {
PopplerQuadrilateral *quadrilateral = &g_array_index (quads, PopplerQuadrilateral, i);
quadrilateral->p1.x = quads_array->getX1(i);
quadrilateral->p1.y = quads_array->getY1(i);
quadrilateral->p2.x = quads_array->getX2(i);
quadrilateral->p2.y = quads_array->getY2(i);
quadrilateral->p3.x = quads_array->getX3(i);
quadrilateral->p3.y = quads_array->getY3(i);
quadrilateral->p4.x = quads_array->getX4(i);
quadrilateral->p4.y = quads_array->getY4(i);
quadrilateral->p1.x = quads_array->getX1(i) - crop_box->x1;
quadrilateral->p1.y = quads_array->getY1(i) - crop_box->y1;
quadrilateral->p2.x = quads_array->getX2(i) - crop_box->x1;
quadrilateral->p2.y = quads_array->getY2(i) - crop_box->y1;
quadrilateral->p3.x = quads_array->getX3(i) - crop_box->x1;
quadrilateral->p3.y = quads_array->getY3(i) - crop_box->y1;
quadrilateral->p4.x = quads_array->getX4(i) - crop_box->x1;
quadrilateral->p4.y = quads_array->getY4(i) - crop_box->y1;
}
return quads;
......@@ -1007,6 +1026,28 @@ poppler_annot_get_page_index (PopplerAnnot *poppler_annot)
return page_num <= 0 ? -1 : page_num - 1;
}
/* Returns cropbox rect for the page where the passed in @poppler_annot is in,
* or NULL when could not retrieve the cropbox */
const PDFRectangle *
_poppler_annot_get_cropbox (PopplerAnnot *poppler_annot)
{
int page_index;
/* A returned zero means annot is not added to any page yet */
page_index = poppler_annot->annot->getPageNum();
if (page_index) {
Page *page;
page = poppler_annot->annot->getDoc()->getPage(page_index);
if (page) {
return page->getCropBox ();
}
}
return nullptr;
}
/**
* poppler_annot_get_rectangle:
* @poppler_annot: a #PopplerAnnot
......@@ -1022,15 +1063,23 @@ poppler_annot_get_rectangle (PopplerAnnot *poppler_annot,
PopplerRectangle *poppler_rect)
{
PDFRectangle *annot_rect;
const PDFRectangle *crop_box;
PDFRectangle zerobox;
g_return_if_fail (POPPLER_IS_ANNOT (poppler_annot));
g_return_if_fail (poppler_rect != nullptr);
crop_box = _poppler_annot_get_cropbox (poppler_annot);
if (!crop_box) {
zerobox = PDFRectangle();
crop_box = &zerobox;
}
annot_rect = poppler_annot->annot->getRect ();
poppler_rect->x1 = annot_rect->x1;
poppler_rect->x2 = annot_rect->x2;
poppler_rect->y1 = annot_rect->y1;
poppler_rect->y2 = annot_rect->y2;
poppler_rect->x1 = annot_rect->x1 - crop_box->x1;
poppler_rect->x2 = annot_rect->x2 - crop_box->x1;
poppler_rect->y1 = annot_rect->y1 - crop_box->y1;
poppler_rect->y2 = annot_rect->y2 - crop_box->y1;
}
/**
......@@ -1047,11 +1096,22 @@ void
poppler_annot_set_rectangle (PopplerAnnot *poppler_annot,
PopplerRectangle *poppler_rect)
{
const PDFRectangle *crop_box;
PDFRectangle zerobox;
g_return_if_fail (POPPLER_IS_ANNOT (poppler_annot));
g_return_if_fail (poppler_rect != nullptr);
poppler_annot->annot->setRect (poppler_rect->x1, poppler_rect->y1,
poppler_rect->x2, poppler_rect->y2);
crop_box = _poppler_annot_get_cropbox (poppler_annot);
if (!crop_box) {
zerobox = PDFRectangle();
crop_box = &zerobox;
}
poppler_annot->annot->setRect (poppler_rect->x1 + crop_box->x1,
poppler_rect->y1 + crop_box->y1,
poppler_rect->x2 + crop_box->x1,
poppler_rect->y2 + crop_box->y1 );
}
/* PopplerAnnotMarkup */
......@@ -1614,12 +1674,14 @@ poppler_annot_text_markup_set_quadrilaterals (PopplerAnnotTextMarkup *poppler_an
GArray *quadrilaterals)
{
AnnotTextMarkup *annot;
const PDFRectangle* crop_box;
g_return_if_fail (POPPLER_IS_ANNOT_TEXT_MARKUP (poppler_annot));
g_return_if_fail (quadrilaterals != nullptr && quadrilaterals->len > 0);
annot = static_cast<AnnotTextMarkup *>(POPPLER_ANNOT (poppler_annot)->annot);
AnnotQuadrilaterals *quads = create_annot_quads_from_poppler_quads (quadrilaterals);
crop_box = _poppler_annot_get_cropbox (POPPLER_ANNOT (poppler_annot));
AnnotQuadrilaterals *quads = create_annot_quads_from_poppler_quads (quadrilaterals, crop_box);
annot->setQuadrilaterals (quads);
delete quads;
}
......@@ -1639,13 +1701,16 @@ poppler_annot_text_markup_set_quadrilaterals (PopplerAnnotTextMarkup *poppler_an
GArray *
poppler_annot_text_markup_get_quadrilaterals (PopplerAnnotTextMarkup *poppler_annot)
{
const PDFRectangle* crop_box;
AnnotTextMarkup *annot;
g_return_val_if_fail (POPPLER_IS_ANNOT_TEXT_MARKUP (poppler_annot), NULL);
annot = static_cast<AnnotTextMarkup *>(POPPLER_ANNOT (poppler_annot)->annot);
crop_box = _poppler_annot_get_cropbox (POPPLER_ANNOT (poppler_annot));
AnnotQuadrilaterals *quads = annot->getQuadrilaterals();
return create_poppler_quads_from_annot_quads (annot->getQuadrilaterals());
return create_poppler_quads_from_annot_quads (quads, crop_box);
}
/* PopplerAnnotFreeText */
......
......@@ -1502,6 +1502,34 @@ poppler_page_free_annot_mapping (GList *list)
g_list_free_full (list, (GDestroyNotify)poppler_annot_mapping_free);
}
/* Adds or removes (according to @add parameter) the passed in @crop_box from the
* passed in @quads and returns it as a new #AnnotQuadrilaterals object */
static AnnotQuadrilaterals *
new_quads_from_offset_cropbox (const PDFRectangle* crop_box,
AnnotQuadrilaterals *quads,
gboolean add)
{
int len = quads->getQuadrilateralsLength();
auto quads_array = std::make_unique<AnnotQuadrilaterals::AnnotQuadrilateral[]>(len);
for (int i = 0; i < len; i++) {
if (add) {
quads_array[i] = AnnotQuadrilaterals::AnnotQuadrilateral (
quads->getX1(i) + crop_box->x1, quads->getY1(i) + crop_box->y1,
quads->getX2(i) + crop_box->x1, quads->getY2(i) + crop_box->y1,
quads->getX3(i) + crop_box->x1, quads->getY3(i) + crop_box->y1,
quads->getX4(i) + crop_box->x1, quads->getY4(i) + crop_box->y1);
} else {
quads_array[i] = AnnotQuadrilaterals::AnnotQuadrilateral (
quads->getX1(i) - crop_box->x1, quads->getY1(i) - crop_box->y1,
quads->getX2(i) - crop_box->x1, quads->getY2(i) - crop_box->y1,
quads->getX3(i) - crop_box->x1, quads->getY3(i) - crop_box->y1,
quads->getX4(i) - crop_box->x1, quads->getY4(i) - crop_box->y1);
}
}
return new AnnotQuadrilaterals (std::move(quads_array), len);
}
/**
* poppler_page_add_annot:
* @page: a #PopplerPage
......@@ -1515,9 +1543,36 @@ void
poppler_page_add_annot (PopplerPage *page,
PopplerAnnot *annot)
{
double x1, y1, x2, y2;
const PDFRectangle *crop_box;
const PDFRectangle *page_crop_box;
g_return_if_fail (POPPLER_IS_PAGE (page));
g_return_if_fail (POPPLER_IS_ANNOT (annot));
/* Add the page's cropBox to the coordinates of rect field of annot */
page_crop_box = page->page->getCropBox ();
annot->annot->getRect(&x1, &y1, &x2, &y2);
annot->annot->setRect(x1 + page_crop_box->x1,
y1 + page_crop_box->y1,
x2 + page_crop_box->x1,
y2 + page_crop_box->y1);
AnnotTextMarkup *annot_markup = dynamic_cast<AnnotTextMarkup*>(annot->annot);
if (annot_markup) {
AnnotQuadrilaterals *quads;
crop_box = _poppler_annot_get_cropbox (annot);
if (crop_box) {
/* Handle hypothetical case of annot being added is already existing on a prior page, so
* first remove cropbox of the prior page before adding cropbox of the new page later */
quads = new_quads_from_offset_cropbox (crop_box, annot_markup->getQuadrilaterals(), FALSE);
annot_markup->setQuadrilaterals( quads );
}
/* Add to annot's quadrilaterals the offset for the cropbox of the new page */
quads = new_quads_from_offset_cropbox (page_crop_box, annot_markup->getQuadrilaterals(), TRUE);
annot_markup->setQuadrilaterals( quads );
}
page->page->addAnnot (annot->annot);
}
......
......@@ -140,6 +140,8 @@ PopplerAnnot *_poppler_annot_line_new (Annot *annot);
PopplerAnnot *_poppler_annot_circle_new (Annot *annot);
PopplerAnnot *_poppler_annot_square_new (Annot *annot);
const PDFRectangle *_poppler_annot_get_cropbox (PopplerAnnot *poppler_annot);
char *_poppler_goo_string_to_utf8(const GooString *s);
gboolean _poppler_convert_pdf_date_to_gtime (const GooString *date,
time_t *gdate);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment