Commit 9887679c authored by Kristian Høgsberg's avatar Kristian Høgsberg

2005-03-21 Kristian Høgsberg <krh@redhat.com>

        * glib/poppler-document.cc:

        * glib/poppler-document.h: Expose the documenttitle as a GObject
        property.

        * glib/poppler-page.cc: Expose the page label as a GObject
        property.

        * glib/poppler-private.h: Add the page index to PopplerPage.

        * glib/test-poppler-glib.c: Print out page label and document
        title.

        * poppler/Catalog.cc:
        * poppler/Catalog.h: Add page label accessors.

        * poppler/PageLabelInfo.cc:
        * poppler/PageLabelInfo.h: New files.

        * poppler/Makefile.am: Add new files to sources.
parent 2cfe917d
2005-03-21 Kristian Høgsberg <krh@redhat.com>
* glib/poppler-document.cc:
* glib/poppler-document.h: Expose the documenttitle as a GObject
property.
* glib/poppler-page.cc: Expose the page label as a GObject
property.
* glib/poppler-private.h: Add the page index to PopplerPage.
* glib/test-poppler-glib.c: Print out page label and document
title.
* poppler/Catalog.cc:
* poppler/Catalog.h: Add page label accessors.
* poppler/PageLabelInfo.cc:
* poppler/PageLabelInfo.h: New files.
* poppler/Makefile.am: Add new files to sources.
2005-03-20 Kristian Høgsberg <krh@redhat.com>
* glib/poppler-document.cc:
......
......@@ -25,13 +25,15 @@
#include <UnicodeMap.h>
#include <GfxState.h>
#include <SplashOutputDev.h>
#include <Stream.h>
#include "poppler.h"
#include "poppler-private.h"
#define POPPLER_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), POPPLER_TYPE_DOCUMENT, PopplerDocumentClass))
#define POPPLER_IS_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), POPPLER_TYPE_DOCUMENT))
#define POPPLER_DOCUMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), POPPLER_TYPE_DOCUMENT, PopplerDocumentClass))
enum {
PROP_0,
PROP_TITLE
};
typedef struct _PopplerDocumentClass PopplerDocumentClass;
struct _PopplerDocumentClass
......@@ -71,6 +73,7 @@ poppler_document_new_from_file (const char *uri,
password_g = NULL;
if (password != NULL)
password_g = new GooString (password);
newDoc = new PDFDoc(filename_g, password_g, password_g);
if (password_g)
delete password_g;
......@@ -148,15 +151,99 @@ poppler_document_get_page (PopplerDocument *document,
catalog = document->doc->getCatalog();
page = catalog->getPage (index + 1);
return _poppler_page_new (document, page);
return _poppler_page_new (document, page, index);
}
PopplerPage *
poppler_document_get_page_by_label (PopplerDocument *document,
const char *label)
{
Catalog *catalog;
GooString label_g(label);
int index;
catalog = document->doc->getCatalog();
if (!catalog->labelToIndex (&label_g, &index))
return NULL;
return poppler_document_get_page (document, index);
}
static gboolean
has_unicode_marker (GooString *string)
{
return ((string->getChar (0) & 0xff) == 0xfe &&
(string->getChar (1) & 0xff) == 0xff);
}
static void
info_dict_get_string (Dict *info_dict, const gchar *key, GValue *value)
{
Object obj;
GooString *goo_value;
gchar *result;
if (!info_dict->lookup ((gchar *)key, &obj)->isString ()) {
obj.free ();
return;
}
goo_value = obj.getString ();
if (has_unicode_marker (goo_value)) {
result = g_convert (goo_value->getCString () + 2,
goo_value->getLength () - 2,
"UTF-8", "UTF-16BE", NULL, NULL, NULL);
} else {
result = g_strndup (goo_value->getCString (), goo_value->getLength ());
}
obj.free ();
g_value_set_string (value, result);
g_free (result);
}
static void
poppler_document_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
PopplerDocument *document = POPPLER_DOCUMENT (object);
Object info;
char *title;
document->doc->getDocInfo (&info);
if (!info.isDict ())
return;
switch (prop_id)
{
case PROP_TITLE:
info_dict_get_string (info.getDict(), "Title", value);
break;
}
}
static void
poppler_document_class_init (PopplerDocumentClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
gobject_class->finalize = poppler_document_finalize;
gobject_class->get_property = poppler_document_get_property;
pspec = g_param_spec_string ("title",
"Document Title",
"The title of the document",
NULL,
G_PARAM_READABLE);
g_object_class_install_property (G_OBJECT_CLASS (klass),
PROP_TITLE,
pspec);
}
static void
......
......@@ -47,6 +47,9 @@ int poppler_document_get_n_pages (PopplerDocument *document);
PopplerPage *poppler_document_get_page (PopplerDocument *document,
int page);
PopplerPage *poppler_document_get_page_by_label (PopplerDocument *document,
const char *label);
G_END_DECLS
#endif /* __POPPLER_DOCUMENT_H__ */
......@@ -29,6 +29,11 @@
#include "poppler.h"
#include "poppler-private.h"
enum {
PROP_0,
PROP_LABEL
};
typedef struct _PopplerPageClass PopplerPageClass;
struct _PopplerPageClass
{
......@@ -38,13 +43,14 @@ struct _PopplerPageClass
G_DEFINE_TYPE (PopplerPage, poppler_page, G_TYPE_OBJECT);
PopplerPage *
_poppler_page_new (PopplerDocument *document, Page *page)
_poppler_page_new (PopplerDocument *document, Page *page, int index)
{
PopplerPage *poppler_page;
poppler_page = (PopplerPage *) g_object_new (POPPLER_TYPE_PAGE, NULL);
poppler_page->document = document;
poppler_page->page = page;
poppler_page->index = index;
return poppler_page;
}
......@@ -144,12 +150,41 @@ poppler_page_render_to_pixbuf (PopplerPage *page,
delete output_dev;
}
static void
poppler_page_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
PopplerPage *page = POPPLER_PAGE (object);
GooString label;
switch (prop_id)
{
case PROP_LABEL:
page->document->doc->getCatalog ()->indexToLabel (page->index, &label);
g_value_set_string (value, label.getCString());
break;
}
}
static void
poppler_page_class_init (PopplerPageClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
gobject_class->finalize = poppler_page_finalize;
gobject_class->get_property = poppler_page_get_property;
pspec = g_param_spec_string ("label",
"Page Label",
"The label of the page",
NULL,
G_PARAM_READABLE);
g_object_class_install_property (G_OBJECT_CLASS (klass),
PROP_LABEL,
pspec);
}
static void
......
......@@ -12,9 +12,10 @@ struct _PopplerPage
GObject parent_instance;
PopplerDocument *document;
Page *page;
int index;
};
PopplerPage *
_poppler_page_new (PopplerDocument *document, Page *page);
_poppler_page_new (PopplerDocument *document, Page *page, int index);
#endif
......@@ -9,7 +9,7 @@ int main (int argc, char *argv[])
{
PopplerDocument *document;
PopplerPage *page;
char *filename;
char *filename, *title, *label;
GError *error;
GdkPixbuf *pixbuf;
double width, height;
......@@ -25,13 +25,22 @@ int main (int argc, char *argv[])
if (document == NULL)
FAIL (error->message);
g_object_get (document, "title", &title, NULL);
printf ("document title: %s\n", title);
g_free (title);
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 100, 100);
gdk_pixbuf_fill (pixbuf, 0x00106000);
page = poppler_document_get_page (document, 5);
page = poppler_document_get_page_by_label (document, "vi");
poppler_page_get_dimensions (page, &width, &height);
printf ("page dimensions: %f inches by %f inches\n",
width / 72, height / 72);
g_object_get (page, "label", &label, NULL);
printf ("page label: %s\n", label);
g_free (label);
poppler_page_render_to_pixbuf (page, 100, 100, 50, 50, 1, pixbuf, 10, 10);
g_object_unref (G_OBJECT (page));
......
......@@ -21,6 +21,7 @@
#include "Page.h"
#include "Error.h"
#include "Link.h"
#include "PageLabelInfo.h"
#include "Catalog.h"
//------------------------------------------------------------------------
......@@ -96,6 +97,10 @@ Catalog::Catalog(XRef *xrefA) {
nameTree.initNull();
obj.free();
if (catDict.dictLookup("PageLabels", &obj)->isDict())
pageLabelInfo = new PageLabelInfo(&obj, numPages);
obj.free();
// read base URI
if (catDict.dictLookup("URI", &obj)->isDict()) {
if (obj.dictLookup("Base", &obj2)->isString()) {
......@@ -362,3 +367,13 @@ Object *Catalog::findDestInTree(Object *tree, GooString *name, Object *obj) {
return obj;
}
GBool Catalog::labelToIndex(GooString *label, int *index)
{
return pageLabelInfo->labelToIndex(label, index);
}
GBool Catalog::indexToLabel(int index, GooString *label)
{
return pageLabelInfo->indexToLabel(index, label);
}
......@@ -19,6 +19,7 @@ class Page;
class PageAttrs;
struct Ref;
class LinkDest;
class PageLabelInfo;
//------------------------------------------------------------------------
// Catalog
......@@ -63,6 +64,10 @@ public:
// NULL if <name> is not a destination.
LinkDest *findDest(GooString *name);
// Convert between page indices and page labels.
GBool labelToIndex(GooString *label, int *index);
GBool indexToLabel(int index, GooString *label);
Object *getOutline() { return &outline; }
private:
......@@ -79,6 +84,7 @@ private:
Object structTreeRoot; // structure tree root dictionary
Object outline; // outline dictionary
GBool ok; // true if catalog is valid
PageLabelInfo *pageLabelInfo; // info about page labels
int readPageTree(Dict *pages, PageAttrs *attrs, int start);
Object *findDestInTree(Object *tree, GooString *name, Object *obj);
......
......@@ -149,4 +149,6 @@ libpoppler_la_SOURCES = \
UnicodeTypeTable.cc \
XRef.cc \
PSOutputDev.cc \
TextOutputDev.cc
TextOutputDev.cc \
PageLabelInfo.h \
PageLabelInfo.cc
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "PageLabelInfo.h"
/* http://mathworld.wolfram.com/RomanNumerals.html */
static int fromRoman(const char *buffer) {
int digit_value, prev_digit_value, value;
int i;
prev_digit_value = INT_MAX;
value = 0;
for (i = 0; buffer[i] != '\0'; i++) {
switch (buffer[i]) {
case 'm':
case 'M':
digit_value = 1000;
break;
case 'd':
case 'D':
digit_value = 500;
break;
case 'c':
case 'C':
digit_value = 100;
break;
case 'l':
case 'L':
digit_value = 50;
break;
case 'x':
case 'X':
digit_value = 10;
break;
case 'v':
case 'V':
digit_value = 5;
break;
case 'i':
case 'I':
digit_value = 1;
break;
default:
return -1;
}
if (digit_value <= prev_digit_value)
value += digit_value;
else
value += digit_value - prev_digit_value * 2;
prev_digit_value = digit_value;
}
return value;
}
static void toRoman(int number, GooString *str, GBool uppercase) {
static const char uppercaseNumerals[] = "IVXLCDM";
static const char lowercaseNumerals[] = "ivxlcdm";
int divisor;
int i, j, k;
const char *wh;
if (uppercase)
wh = uppercaseNumerals;
else
wh = lowercaseNumerals;
divisor = 1000;
for (k = 3; k >= 0; k--) {
i = number / divisor;
number = number % divisor;
switch (i) {
case 0:
break;
case 5:
str->append(wh[2 * k + 1]);
break;
case 9:
str->append(wh[2 * k + 0]);
str->append(wh[ 2 * k + 2]);
break;
case 4:
str->append(wh[2 * k + 0]);
str->append(wh[2 * k + 1]);
break;
default:
if (i > 5) {
str->append(wh[2 * k + 1]);
i -= 5;
}
for (j = 0; j < i; j++) {
str->append(wh[2 * k + 0]);
}
}
divisor = divisor / 10;
}
}
static int fromLatin(const char *buffer)
{
int count;
const char *p;
for (p = buffer; *p; p++) {
if (*p != buffer[0])
return -1;
}
count = p - buffer;
if (buffer[0] >= 'a' && buffer[0] <= 'z')
return 26 * (count - 1) + buffer[0] - 'a' + 1;
if (buffer[0] >= 'A' && buffer[0] <= 'Z')
return 26 * (count - 1) + buffer[0] - 'A' + 1;
return -1;
}
static void toLatin(int number, GooString *str, GBool uppercase) {
char base, letter;
int i, count;
if (uppercase)
base = 'A';
else
base = 'a';
count = (number - 1) / 26 + 1;
letter = base + (number - 1) % 26;
for (i = 0; i < count; i++)
str->append(letter);
}
PageLabelInfo::Interval::Interval(Object *dict, int baseA) {
Object obj;
style = None;
if (dict->dictLookup("S", &obj)->isName()) {
if (obj.isName("D")) {
style = Arabic;
} else if (obj.isName("R")) {
style = UppercaseRoman;
} else if (obj.isName("r")) {
style = LowercaseRoman;
} else if (obj.isName("A")) {
style = UppercaseLatin;
} else if (obj.isName("a")) {
style = LowercaseLatin;
}
}
obj.free();
if (dict->dictLookup("P", &obj)->isString())
prefix = copyString(obj.getString()->getCString());
else
prefix = copyString("");
obj.free();
if (dict->dictLookup("St", &obj)->isInt())
first = obj.getInt();
else
first = 1;
obj.free();
base = baseA;
}
PageLabelInfo::PageLabelInfo(Object *tree, int numPages) {
int i;
Interval *interval, *next;
parse(tree);
for (i = 0; i < intervals.getLength(); i++) {
interval = (Interval *) intervals.get(i);
if (i + 1 < intervals.getLength()) {
next = (Interval *) intervals.get(i + 1);
interval->length = next->base - interval->base;
} else {
interval->length = numPages - interval->base;
}
}
}
void PageLabelInfo::parse(Object *tree) {
Object nums, obj;
Object kids, kid, limits, low, high;
int i, base;
Interval *interval;
// leaf node
if (tree->dictLookup("Nums", &nums)->isArray()) {
for (i = 0; i < nums.arrayGetLength(); i += 2) {
if (!nums.arrayGet(i, &obj)->isInt()) {
obj.free();
continue;
}
base = obj.getInt();
obj.free();
if (!nums.arrayGet(i + 1, &obj)->isDict()) {
obj.free();
continue;
}
interval = new Interval(&obj, base);
obj.free();
intervals.append(interval);
}
}
nums.free();
if (tree->dictLookup("Kids", &kids)->isArray()) {
for (i = 0; i < kids.arrayGetLength(); ++i) {
if (kids.arrayGet(i, &kid)->isDict())
parse(&kid);
kid.free();
}
}
kids.free();
}
GBool PageLabelInfo::labelToIndex(GooString *label, int *index)
{
Interval *interval;
char *str = label->getCString(), *end;
int prefixLength;
int i, base, number;
base = 0;
for (i = 0; i < intervals.getLength(); i++) {
interval = (Interval *) intervals.get(i);
prefixLength = strlen(interval->prefix);
if (strncmp(str, interval->prefix, prefixLength) != 0)
continue;
switch (interval->style) {
case Interval::Arabic:
number = strtol(str + prefixLength, &end, 10);
if (*end == '\0' && number - interval->first < interval->length) {
*index = base + number - interval->first;
return gTrue;
}
break;
case Interval::LowercaseRoman:
case Interval::UppercaseRoman:
number = fromRoman(str + prefixLength);
if (number >= 0 && number - interval->first < interval->length) {
*index = base + number - interval->first;
return gTrue;
}
break;
case Interval::UppercaseLatin:
case Interval::LowercaseLatin:
number = fromLatin(str + prefixLength);
if (number >= 0 && number - interval->first < interval->length) {
*index = base + number - interval->first;
return gTrue;
}
break;
case Interval::None:
break;
}
base += interval->length;
}
return gFalse;
}
GBool PageLabelInfo::indexToLabel(int index, GooString *label)
{
char buffer[32];
int i, base, number;
Interval *interval;
base = 0;
label->clear();
interval = NULL;
for (i = 0; i < intervals.getLength(); i++) {
interval = (Interval *) intervals.get(i);
if (base <= index && index < base + interval->length)
break;
base += interval->length;
}
if (i == intervals.getLength())
return gFalse;
label->append(interval->prefix);
number = index - base + interval->first;
switch (interval->style) {
case Interval::Arabic: