mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-31 14:33:54 -04:00
Add code to create a PDF outline using PoDoFo
This commit is contained in:
parent
6c5d581218
commit
7d0fcd9484
@ -140,6 +140,7 @@ extensions = [
|
|||||||
[
|
[
|
||||||
'calibre/utils/podofo/utils.cpp',
|
'calibre/utils/podofo/utils.cpp',
|
||||||
'calibre/utils/podofo/doc.cpp',
|
'calibre/utils/podofo/doc.cpp',
|
||||||
|
'calibre/utils/podofo/outline.cpp',
|
||||||
'calibre/utils/podofo/podofo.cpp',
|
'calibre/utils/podofo/podofo.cpp',
|
||||||
],
|
],
|
||||||
headers=[
|
headers=[
|
||||||
|
@ -98,7 +98,23 @@ def delete_all_but(path, pages):
|
|||||||
with open(path, 'wb') as f:
|
with open(path, 'wb') as f:
|
||||||
f.write(raw)
|
f.write(raw)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def test_outline(src):
|
||||||
f = u'/tmp/t.pdf'
|
podofo = get_podofo()
|
||||||
delete_all_but(f, [0, 1, -2, -1])
|
p = podofo.PDFDoc()
|
||||||
|
with open(src, 'rb') as f:
|
||||||
|
raw = f.read()
|
||||||
|
p.load(raw)
|
||||||
|
total = p.page_count()
|
||||||
|
root = p.create_outline(u'Table of Contents')
|
||||||
|
for i in xrange(0, total):
|
||||||
|
root.create(u'Page %d'%i, i, True)
|
||||||
|
raw = p.write()
|
||||||
|
out = '/tmp/outlined.pdf'
|
||||||
|
with open(out, 'wb') as f:
|
||||||
|
f.write(raw)
|
||||||
|
print 'Outlined PDF:', out
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import sys
|
||||||
|
test_outline(sys.argv[-1])
|
||||||
|
|
||||||
|
@ -194,6 +194,41 @@ PDFDoc_set_box(PDFDoc *self, PyObject *args) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
} // }}}
|
} // }}}
|
||||||
|
|
||||||
|
// create_outline() {{{
|
||||||
|
static PyObject *
|
||||||
|
PDFDoc_create_outline(PDFDoc *self, PyObject *args) {
|
||||||
|
PyObject *p;
|
||||||
|
PDFOutlineItem *ans;
|
||||||
|
PdfString *title;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "U", &p)) return NULL;
|
||||||
|
title = podofo_convert_pystring(p);
|
||||||
|
if (title == NULL) return NULL;
|
||||||
|
|
||||||
|
ans = PyObject_New(PDFOutlineItem, &PDFOutlineItemType);
|
||||||
|
if (ans == NULL) goto error;
|
||||||
|
|
||||||
|
try {
|
||||||
|
PdfOutlines *outlines = self->doc->GetOutlines();
|
||||||
|
if (outlines == NULL) {PyErr_NoMemory(); goto error;}
|
||||||
|
ans->item = outlines->CreateRoot(*title);
|
||||||
|
if (ans->item == NULL) {PyErr_NoMemory(); goto error;}
|
||||||
|
ans->doc = self->doc;
|
||||||
|
} catch(const PdfError & err) {
|
||||||
|
podofo_set_exception(err); goto error;
|
||||||
|
} catch (...) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, "An unknown error occurred while trying to create the outline");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete title;
|
||||||
|
return (PyObject*)ans;
|
||||||
|
error:
|
||||||
|
Py_XDECREF(ans); delete title;
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
} // }}}
|
||||||
|
|
||||||
// Properties {{{
|
// Properties {{{
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
@ -430,7 +465,9 @@ static PyMethodDef PDFDoc_methods[] = {
|
|||||||
{"set_box", (PyCFunction)PDFDoc_set_box, METH_VARARGS,
|
{"set_box", (PyCFunction)PDFDoc_set_box, METH_VARARGS,
|
||||||
"set_box(page_num, box, left, bottom, width, height) -> Set the PDF bounding box for the page numbered nu, box must be one of: MediaBox, CropBox, TrimBox, BleedBox, ArtBox. The numbers are interpreted as pts."
|
"set_box(page_num, box, left, bottom, width, height) -> Set the PDF bounding box for the page numbered nu, box must be one of: MediaBox, CropBox, TrimBox, BleedBox, ArtBox. The numbers are interpreted as pts."
|
||||||
},
|
},
|
||||||
|
{"create_outline", (PyCFunction)PDFDoc_create_outline, METH_VARARGS,
|
||||||
|
"create_outline(title) -> Create an outline, return the root outline item."
|
||||||
|
},
|
||||||
|
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
@ -26,7 +26,14 @@ typedef struct {
|
|||||||
|
|
||||||
} PDFDoc;
|
} PDFDoc;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
PdfMemDocument *doc;
|
||||||
|
PdfOutlineItem *item;
|
||||||
|
} PDFOutlineItem;
|
||||||
|
|
||||||
extern PyTypeObject PDFDocType;
|
extern PyTypeObject PDFDocType;
|
||||||
|
extern PyTypeObject PDFOutlineItemType;
|
||||||
extern PyObject *Error;
|
extern PyObject *Error;
|
||||||
|
|
||||||
// Utilities
|
// Utilities
|
||||||
|
142
src/calibre/utils/podofo/outline.cpp
Normal file
142
src/calibre/utils/podofo/outline.cpp
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* outline.cpp
|
||||||
|
* Copyright (C) 2012 Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the GPL3 license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
using namespace pdf;
|
||||||
|
|
||||||
|
// Constructor/destructor {{{
|
||||||
|
static void
|
||||||
|
dealloc(PDFOutlineItem* self)
|
||||||
|
{
|
||||||
|
self->ob_type->tp_free((PyObject*)self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
new_item(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
|
{
|
||||||
|
PDFOutlineItem *self;
|
||||||
|
|
||||||
|
self = (PDFOutlineItem *)type->tp_alloc(type, 0);
|
||||||
|
if (self != NULL) {
|
||||||
|
self->item = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (PyObject *)self;
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// erase() {{{
|
||||||
|
static PyObject *
|
||||||
|
erase(PDFOutlineItem *self, PyObject *args) {
|
||||||
|
try {
|
||||||
|
self->item->Erase();
|
||||||
|
} catch(const PdfError & err) {
|
||||||
|
podofo_set_exception(err);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
} // }}}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
create(PDFOutlineItem *self, PyObject *args) {
|
||||||
|
PyObject *ptitle, *as_child = NULL;
|
||||||
|
PDFOutlineItem *ans;
|
||||||
|
int num;
|
||||||
|
PdfString *title;
|
||||||
|
PdfPage *page;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "Ui|O", &ptitle, &num, &as_child)) return NULL;
|
||||||
|
title = podofo_convert_pystring(ptitle);
|
||||||
|
if (title == NULL) return NULL;
|
||||||
|
|
||||||
|
ans = PyObject_New(PDFOutlineItem, &PDFOutlineItemType);
|
||||||
|
if (ans == NULL) goto error;
|
||||||
|
ans->doc = self->doc;
|
||||||
|
|
||||||
|
try {
|
||||||
|
page = self->doc->GetPage(num);
|
||||||
|
if (page == NULL) { PyErr_Format(PyExc_ValueError, "Invalid page number: %d", num); goto error; }
|
||||||
|
PdfDestination dest(page);
|
||||||
|
if (as_child != NULL && PyObject_IsTrue(as_child)) {
|
||||||
|
ans->item = self->item->CreateChild(*title, dest);
|
||||||
|
} else
|
||||||
|
ans->item = self->item->CreateNext(*title, dest);
|
||||||
|
} catch (const PdfError &err) {
|
||||||
|
podofo_set_exception(err); goto error;
|
||||||
|
} catch (...) {
|
||||||
|
PyErr_SetString(PyExc_Exception, "An unknown error occurred while trying to create the outline item");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete title;
|
||||||
|
return (PyObject*) ans;
|
||||||
|
error:
|
||||||
|
Py_XDECREF(ans); delete title;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef methods[] = {
|
||||||
|
|
||||||
|
{"create", (PyCFunction)create, METH_VARARGS,
|
||||||
|
"create(title, pagenum, as_child=False) -> Create a new outline item with title 'title', pointing to page number pagenum. If as_child is True the new item will be a child of this item otherwise it will be a sibling. Returns the newly created item."
|
||||||
|
},
|
||||||
|
|
||||||
|
{"erase", (PyCFunction)erase, METH_VARARGS,
|
||||||
|
"erase() -> Delete this item and all its children, removing it from the outline tree completely."
|
||||||
|
},
|
||||||
|
|
||||||
|
{NULL} /* Sentinel */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Type definition {{{
|
||||||
|
PyTypeObject pdf::PDFOutlineItemType = {
|
||||||
|
PyObject_HEAD_INIT(NULL)
|
||||||
|
0, /*ob_size*/
|
||||||
|
"podofo.PDFOutlineItem", /*tp_name*/
|
||||||
|
sizeof(PDFOutlineItem), /*tp_basicsize*/
|
||||||
|
0, /*tp_itemsize*/
|
||||||
|
(destructor)dealloc, /*tp_dealloc*/
|
||||||
|
0, /*tp_print*/
|
||||||
|
0, /*tp_getattr*/
|
||||||
|
0, /*tp_setattr*/
|
||||||
|
0, /*tp_compare*/
|
||||||
|
0, /*tp_repr*/
|
||||||
|
0, /*tp_as_number*/
|
||||||
|
0, /*tp_as_sequence*/
|
||||||
|
0, /*tp_as_mapping*/
|
||||||
|
0, /*tp_hash */
|
||||||
|
0, /*tp_call*/
|
||||||
|
0, /*tp_str*/
|
||||||
|
0, /*tp_getattro*/
|
||||||
|
0, /*tp_setattro*/
|
||||||
|
0, /*tp_as_buffer*/
|
||||||
|
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
||||||
|
"PDF Outline items", /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
0, /* tp_iter */
|
||||||
|
0, /* tp_iternext */
|
||||||
|
methods, /* tp_methods */
|
||||||
|
0, /* tp_members */
|
||||||
|
0, /* tp_getset */
|
||||||
|
0, /* tp_base */
|
||||||
|
0, /* tp_dict */
|
||||||
|
0, /* tp_descr_get */
|
||||||
|
0, /* tp_descr_set */
|
||||||
|
0, /* tp_dictoffset */
|
||||||
|
0, /* tp_init */
|
||||||
|
0, /* tp_alloc */
|
||||||
|
new_item, /* tp_new */
|
||||||
|
|
||||||
|
};
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
|
@ -46,6 +46,9 @@ initpodofo(void)
|
|||||||
if (PyType_Ready(&pdf::PDFDocType) < 0)
|
if (PyType_Ready(&pdf::PDFDocType) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (PyType_Ready(&pdf::PDFOutlineItemType) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
pdf::Error = PyErr_NewException((char*)"podofo.Error", NULL, NULL);
|
pdf::Error = PyErr_NewException((char*)"podofo.Error", NULL, NULL);
|
||||||
if (pdf::Error == NULL) return;
|
if (pdf::Error == NULL) return;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user