[PATCH] Very basic SWIG Perl wrapper and supporting automake/autoconf scripts
Tim Brody
tdb2 at ecs.soton.ac.uk
Wed Nov 3 05:13:23 PDT 2010
---
configure.ac | 53 ++++++++
swig/Makefile.am | 6 +
swig/generic.mk | 7 +
swig/perl/Makefile.am | 33 +++++
swig/perl/util.i.in | 338 +++++++++++++++++++++++++++++++++++++++++++++++++
swig/poppler.i | 105 +++++++++++++++
6 files changed, 542 insertions(+), 0 deletions(-)
create mode 100644 swig/Makefile.am
create mode 100644 swig/generic.mk
create mode 100644 swig/perl/Makefile.am
create mode 100644 swig/perl/util.i.in
create mode 100644 swig/poppler.i
diff --git a/configure.ac b/configure.ac
index 8e3c5ac..3eac3d9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -540,6 +540,56 @@ fi
AM_CONDITIONAL(BUILD_POPPLER_CPP, test "x$enable_poppler_cpp" = "xyes")
+dnl
+dnl SWIG bindings
+dnl
+
+BINDINGS=
+
+AC_ARG_ENABLE(poppler-swig,
+ AC_HELP_STRING([--disable-poppler-swig],
+ [Don't compile poppler swig bindings.]),
+ enable_poppler_swig=$enableval,
+ enable_poppler_swig="yes")
+if test x$enable_poppler_swig = xyes; then
+ AC_PATH_PROGS(SWIG, ["${SWIG-swig}"], [])
+ if test -z "$SWIG" ; then
+ enable_poppler_swig=no
+ else
+ AC_PATH_PROGS(PERL, ["${PERL-perl}"], [])
+ if test -n "$PERL" ; then
+ AC_ARG_VAR(PERL_INC, [Directory to include XS headers])
+ if test -z "$PERL_INC" ; then
+ PERL_INC=`$PERL -MConfig -e 'print $Config{archlibexp}, "/CORE";'`
+ fi
+ AC_SUBST(PERL_INC)
+
+ AC_ARG_VAR(PERL_LIB, [Directory to install perl files into])
+ if test -z "$PERL_LIB" ; then
+ [PERL_LIB=`$PERL -MConfig -e 'print $Config{sitearch};'`];
+ fi
+ AC_SUBST(PERL_LIB)
+
+ AC_ARG_VAR(PERL_SO, [for perl module extension])
+ if test -z "$PERL_SO" ; then
+ [PERL_SO=`$PERL -MConfig -e 'print ".", $Config{'dlext'};'`];
+ fi
+ AC_SUBST(PERL_SO)
+
+ if test -z "$PERL_POPPLER_VERSION" ; then
+ [PERL_POPPLER_VERSION=$POPPLER_VERSION];
+ fi
+ AC_SUBST(PERL_POPPLER_VERSION)
+
+ BINDINGS="$BINDINGS perl"
+ fi
+ fi
+fi
+
+AC_SUBST(BINDINGS)
+
+AM_CONDITIONAL(BUILD_POPPLER_SWIG, test "x$enable_poppler_swig" = "xyes")
+
AC_ARG_ENABLE(gtk-test,
AC_HELP_STRING([--disable-gtk-test],
@@ -654,6 +704,8 @@ qt4/demos/Makefile
cpp/Makefile
cpp/poppler-version.h
cpp/tests/Makefile
+swig/Makefile
+swig/perl/Makefile swig/perl/util.i
poppler.pc
poppler-uninstalled.pc
poppler-cairo.pc
@@ -689,6 +741,7 @@ echo " use zlib: $enable_zlib"
echo " use libcurl: $enable_libcurl"
echo " use libopenjpeg: $enable_libopenjpeg"
echo " use cms: $enable_cms"
+echo " swig bindings: $BINDINGS"
echo " command line utils: $enable_utils"
echo ""
diff --git a/swig/Makefile.am b/swig/Makefile.am
new file mode 100644
index 0000000..7d71150
--- /dev/null
+++ b/swig/Makefile.am
@@ -0,0 +1,6 @@
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/goo \
+ -I$(top_srcdir)/poppler
+
+SUBDIRS = @BINDINGS@
diff --git a/swig/generic.mk b/swig/generic.mk
new file mode 100644
index 0000000..0a7c191
--- /dev/null
+++ b/swig/generic.mk
@@ -0,0 +1,7 @@
+# General Makefile settings for all language-bindings
+
+SWIG_mainsource = \
+ $(srcdir)/../poppler.i
+
+SWIG_sources = \
+ $(SWIG_mainsource)
diff --git a/swig/perl/Makefile.am b/swig/perl/Makefile.am
new file mode 100644
index 0000000..f983613
--- /dev/null
+++ b/swig/perl/Makefile.am
@@ -0,0 +1,33 @@
+
+
+include ../generic.mk
+
+BUILT_SOURCES = poppler_wrap.cc
+
+EXTRA_DIST = util.i $(BUILT_SOURCES)
+
+perllibdir = $(PERL_LIB)/auto/Poppler
+perllib_LTLIBRARIES = Poppler.la
+
+perlmoddir = $(PERL_LIB)
+perlmod_DATA = Poppler.pm
+
+#perlPODdir = $(PERL_LIB)
+#perlPOD_DATA = lib/*
+
+AM_CPPFLAGS = -I$(PERL_INC)
+Poppler_la_SOURCES = poppler_wrap.cc
+Poppler_la_LIBADD = \
+ $(top_builddir)/poppler/libpoppler.la \
+ $(PERL_LIBS)
+Poppler_la_LDFLAGS = \
+ @create_shared_lib@ \
+ -avoid-version \
+ -module \
+ -shrext $(PERL_SO) \
+ $(NO_UNDEFINED)
+
+poppler_wrap.cc Poppler.pm:
+ $(SWIG) $(INCLUDES) $(SWIG_FLAGS) -c++ \
+ -perl -module Poppler -proxy -const \
+ -o poppler_wrap.cc $(SWIG_mainsource)
diff --git a/swig/perl/util.i.in b/swig/perl/util.i.in
new file mode 100644
index 0000000..7059f22
--- /dev/null
+++ b/swig/perl/util.i.in
@@ -0,0 +1,338 @@
+/* type-checking for overloaded methods */
+%typecheck(SWIG_TYPECHECK_POINTER) BaseStream *, OutStream * {
+ $1 = sv_isio(aTHX_ $input);
+}
+%typecheck(SWIG_TYPECHECK_POINTER) PDFRectangle * {
+ $1 = SvTYPE(SvRV($input)) == SVt_PVHV;
+}
+%typecheck(SWIG_TYPECHECK_POINTER) AnnotColor * {
+ $1 = SvTYPE(SvRV($input)) == SVt_PVAV;
+}
+/* any scalar can be stringified or true/false */
+%typecheck(SWIG_TYPECHECK_STRING) GooString *, GBool {
+ $1 = 1;
+}
+
+/* GooStrings look like a duplication of std::string to me */
+%typemap(in) GooString * {
+ STRLEN len;
+ $1 = $input != &PL_sv_undef ?
+ new GooString(SvPV($input,len),len) :
+ NULL;
+}
+%typemap(out) GooString * {
+ if (argvi >= items) {
+ EXTEND(sp,1);
+ }
+ $result = sv_newmortal();
+ if( $1 != NULL )
+ {
+ sv_setpvn($result, $1->getCString(), $1->getLength());
+ gfree($1);
+ }
+ argvi++;
+}
+
+/* should've used std::bool */
+%typemap(in) GBool {
+ $1 = SvTRUE($input);
+}
+%typemap(out) GBool {
+ if (argvi >= items) {
+ EXTEND(sp,1);
+ }
+ $result = sv_newmortal();
+ sv_setiv($result, $1);
+ argvi++;
+}
+%typemap(in) Unicode, CID, CharCode {
+ const char *pat = "W";
+ STRLEN len;
+ const char *s = SvPV($input,len);
+ dSP;
+ unpackstring(pat,pat+1,s,s+len,0);
+ $1 = SvUV(ST(0));
+ PUTBACK;
+ SPAGAIN;
+}
+%typemap(out) Unicode, CID, CharCode {
+ if (argvi >= items) {
+ EXTEND(sp,1);
+ }
+ const char *pat = "U";
+ SV *svp[1];
+ svp[0] = sv_2mortal(newSVUV($1));
+ $result = sv_newmortal();
+ packlist($result,pat,pat+1,svp,svp+1);
+ argvi++;
+}
+
+%typemap(in) PDFRectangle * {
+ HV *hv = (HV *) SvRV($input);
+
+ double rect[4];
+ const char *idx[4] = {
+ "x1", "y1", "x2", "y2"
+ };
+
+ for(int i = 0; i < 4; ++i)
+ {
+ SV **sv = hv_fetch(hv,idx[i],strlen(idx[i]),NULL);
+ if( sv == NULL )
+ {
+ croak("Expected '%s' in hash reference", idx[i]);
+ }
+ rect[i] = SvNV(*sv);
+ }
+
+ $1 = new PDFRectangle(rect[0],rect[1],rect[2],rect[3]);
+}
+%typemap(out) PDFRectangle * {
+ if (argvi >= items) {
+ EXTEND(sp,1);
+ }
+ HV *hv = newHV();
+ hv_stores(hv, "x1", newSVnv($1->x1));
+ hv_stores(hv, "y1", newSVnv($1->y1));
+ hv_stores(hv, "x2", newSVnv($1->x2));
+ hv_stores(hv, "y2", newSVnv($1->y2));
+ $result = sv_2mortal(newRV_noinc((SV *) hv));
+ argvi++;
+}
+%typemap(in) AnnotColor * {
+ AV *av = (AV *) SvRV($input);
+ double color[4];
+
+ for(int i = 0; i <= av_len(av) && i < 4; ++i)
+ {
+ SV **svp = av_fetch(av,i,NULL);
+ color[i] = svp != NULL ? SvNV(*svp) : 0;
+ }
+
+ switch(av_len(av)+1)
+ {
+ case 0:
+ $1 = new AnnotColor();
+ break;
+ case 1:
+ $1 = new AnnotColor(color[0]);
+ break;
+ case 3:
+ $1 = new AnnotColor(color[0],color[1],color[2]);
+ break;
+ case 4:
+ $1 = new AnnotColor(color[0],color[1],color[2],color[3]);
+ break;
+ default:
+ croak("Expected 0, 1, 3 or 4 elements in array");
+ }
+}
+%typemap(out) AnnotColor * {
+ if (argvi >= items) {
+ EXTEND(sp,1);
+ }
+ AV *av = newAV();
+ const double *values = $1->getValues();
+ for(int i = 0; i < $1->getSpace(); ++i)
+ {
+ av_push(av, newSVnv(values[i]));
+ }
+ $result = sv_2mortal(newRV_noinc((SV *) av));
+ argvi++;
+}
+/* when reading PDFDoc stores the stream and frees it */
+%typemap(in) BaseStream * (Object obj) {
+ PerlIO *fh = IoIFP(sv_2io($input));
+
+ obj.initNull();
+ $1 = new PerlInStream(fh, 0, gFalse, 0, &obj);
+}
+/* when writing we need to free the output stream */
+%typemap(in) OutStream * {
+ PerlIO *fh = IoOFP(sv_2io($input));
+
+ $1 = new PerlOutStream(fh);
+}
+%typemap(freearg) OutStream * {
+ free($1);
+}
+
+%{
+/* Copied from Win32::Job */
+static int sv_isio(pTHX_ SV *sv)
+{
+ IO *io;
+ GV *gv;
+ STRLEN n_a;
+
+ switch (SvTYPE(sv)) {
+ case SVt_PVIO:
+ io = (IO*)sv;
+ return 1;
+ case SVt_PVGV:
+ gv = (GV*)sv;
+ io = GvIO(gv);
+ if (!io)
+ return 0;
+ return 1;
+ default:
+ if (!SvOK(sv))
+ return 0;
+ if (SvROK(sv))
+ return sv_isio(aTHX_ SvRV(sv));
+ gv = gv_fetchpv(SvPV(sv,n_a), FALSE, SVt_PVIO);
+ if (gv)
+ return 1;
+ else
+ return 0;
+ }
+ return 0;
+}
+
+class PerlOutStream: public OutStream {
+ public:
+ PerlOutStream(PerlIO *f): OutStream() {
+ f_ = f;
+ };
+ void close() {};
+ int getPos() { return PerlIO_tell(f_); };
+ void put(char c) { PerlIO_putc(f_, c); };
+ void printf(const char *format, ...) {
+ va_list argptr;
+ va_start(argptr, format);
+ PerlIO_vprintf(f_, format, argptr);
+ va_end(argptr);
+ };
+ private:
+ PerlIO *f_;
+};
+
+class PerlInStream: public BaseStream {
+ public:
+ PerlInStream(PerlIO *f, Guint start, GBool limited, Guint length, Object *dict): BaseStream(dict) {
+ f_ = f;
+ start_ = static_cast<Off_t>(start);
+ limited_ = limited;
+ length_ = static_cast<Off_t>(length);
+ savePos_ = 0;
+ saved_ = false;
+ total_ = 0;
+ };
+ ~PerlInStream() {
+ close();
+ };
+ StreamKind getKind() { return strFile; };
+ void reset() {
+ savePos_ = PerlIO_tell(f_);
+ PerlIO_seek(f_, start_, SEEK_SET);
+ saved_ = true;
+ };
+ void close() {
+ if(saved_) {
+ PerlIO_seek(f_, savePos_, SEEK_SET);
+ saved_ = false;
+ }
+ };
+ int getChar() {
+ if(limited_ && PerlIO_tell(f_) >= start_ + length_)
+ return EOF;
+ ++total_;
+ return PerlIO_getc(f_);
+ };
+ int lookChar() {
+ int c = getChar();
+ PerlIO_ungetc(f_, c);
+ return c == EOF ? EOF : c & 0xff;
+ };
+ int getPos() {
+ return (int)PerlIO_tell(f_);
+ };
+ void setPos(Guint pos, int dir = 0) {
+ Off_t size;
+ if( dir >= 0 ) {
+ if(PerlIO_seek(f_, pos, SEEK_SET) != 0)
+ croak("Error in file seek");
+ }
+ else {
+ if(PerlIO_seek(f_, 0, SEEK_END) != 0)
+ croak("Error in file seek");
+ size = static_cast<Guint>(PerlIO_tell(f_));
+ if( pos > size )
+ pos = static_cast<Guint>(size);
+ if(PerlIO_seek(f_, -(Off_t)pos, SEEK_END) != 0)
+ croak("Error in file seek");
+ }
+ };
+ Stream *makeSubStream(Guint start, GBool limited, Guint length, Object *dict) {
+ return new PerlInStream(f_, start, limited, length, dict);
+ };
+ int getUnfilteredChar() { return getChar(); };
+ void unfilteredReset() { reset(); };
+ Guint getStart() { return static_cast<Guint>(start_); };
+ void moveStart(int delta) {
+ start_ += delta;
+ };
+ private:
+ virtual GBool hasGetChars() { return true; }
+ virtual int getChars(int nchars, Guchar *buffer) {
+ return PerlIO_read(f_, buffer, nchars);
+ }
+
+ PerlIO *f_;
+ Off_t start_;
+ GBool limited_;
+ Off_t length_;
+ bool saved_;
+ Off_t savePos_;
+ Off_t total_;
+};
+%}
+
+%perlcode %{
+
+package Poppler;
+
+our $VERSION = v at POPPLER_VERSION@;
+
+=pod
+
+=head1 NAME
+
+Poppler - poppler PDF API
+
+=head1 SYNOPSIS
+
+ use Poppler;
+
+ $doc = Poppler::PDFDoc->new( "foo.pdf" );
+
+ print $doc->getNumPages(), "\n";
+
+ $txtdev = Poppler::TextOutputDev->new( "foo.txt",
+ 1, # physical layout
+ 0, # raw order
+ 0, # append
+ );
+
+ $doc->displayPages( $txtdev,
+ 1, # from
+ $doc->getNumPages, # to
+ 72, # h-DPI
+ 72, # v-DPI
+ 0, # rotation
+ 1, # use media box
+ 0, # crop
+ 0, # printing
+ );
+
+=head1 DESCRIPTION
+
+These bindings are for the 'libpoppler' library.
+
+=head1 SEE ALSO
+
+L<Poppler>, http://poppler.freedesktop.org/
+
+=cut
+
+%}
diff --git a/swig/poppler.i b/swig/poppler.i
new file mode 100644
index 0000000..4cd4fb2
--- /dev/null
+++ b/swig/poppler.i
@@ -0,0 +1,105 @@
+/*
+ * Poppler SWIG wrapper
+ *
+ * Copyright 2010 Tim Brody <tdb2 at ecs.soton.ac.uk
+ *
+ * Released under the same license as Poppler (GPL 2 or later as of writing).
+ *
+ */
+
+%module "poppler"
+%{
+#include <poppler/GlobalParams.h>
+#include <poppler/OutputDev.h>
+#include <poppler/PDFDoc.h>
+#include <poppler/TextOutputDev.h>
+#include <poppler/DateInfo.h>
+%}
+
+/* these symbols seem to be missing on FC13, according to PERL_DL_NOLAZY */
+%ignore TextWord::primaryCmp(TextWord *word);
+%ignore AnnotAppearance;
+
+/* PDFRectangle are turned into hashes */
+%ignore PDFRectangle;
+/* SWIG can't cope with the weird const Time struct */
+%ignore AnnotMovie;
+/* AnnotColor are turned into arrays */
+%ignore AnnotColor;
+
+/* Ignore 'Unicode' character methods */
+%ignore Unicode;
+%ignore TextWord::getChar(int idx);
+%ignore TextPage::findText(Unicode *s, int len,
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
+ GBool caseSensitive, GBool backward,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax);
+%ignore TextOutputDev::findText(Unicode *s, int len,
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
+ GBool caseSensitive, GBool backward,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax);
+
+/* objects and methods only used by higher-level methods */
+%ignore TextPage::addChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode c, int nBytes, Unicode *u, int uLen);
+%ignore TextOutputDev::drawChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ double originX, double originY,
+ CharCode c, int nBytes, Unicode *u, int uLen);
+%ignore ActualText;
+%ignore TextPage::coalesce;
+%ignore TextBlock::coalesce;
+%ignore TextLine::coalesce;
+%ignore NameTree;
+%ignore OutputDev::dump();
+%ignore TextOutputDev::dump();
+%ignore TextPage::dump(void *outputStream, TextOutputFunc outputFunc,
+ GBool physLayout);
+%ignore TextPool;
+
+/* we can't support overloaded constructors with the same number of args */
+%rename("with_callback") TextOutputDev::TextOutputDev(TextOutputFunc,void *,GBool,GBool);
+
+%contract Catalog::getPage(int i) {
+require:
+ i >= 1;
+}
+%contract PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage,
+ double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool crop, GBool printing,
+ GBool (*abortCheckCbk)(void *data) = NULL,
+ void *abortCheckCbkData = NULL,
+ GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
+ void *annotDisplayDecideCbkData = NULL) {
+require:
+ firstPage >= 1;
+ lastPage >= 1;
+ hDPI > 0;
+ vDPI > 0;
+}
+
+%include <poppler-config.h>;
+%include <Catalog.h>;
+%include <Dict.h>;
+%include <Object.h>;
+%include <Page.h>;
+%include <XRef.h>;
+%include <PDFDoc.h>;
+%include <Annot.h>
+%include <OutputDev.h>;
+%apply double *OUTPUT { double *r, double *g, double *b, double *xMinA, double *yMinA, double *xMaxA, double *yMaxA };
+%include <TextOutputDev.h>;
+%clear double *r, double *g, double *b, double *xMinA, double *yMinA, double *xMaxA, double *yMaxA;
+
+%include "util.i"
+
+/* poppler has GlobalParams that must exist before we do anything */
+%init %{
+ globalParams = new GlobalParams();
+%}
+
--
1.7.2.3
--=-owvJKzHF+/8E/IQpZ/Tu--
More information about the poppler
mailing list