I've reworked my SWIG wrapper into a patch (attached). I'm no expert on automake and pretty new to SWIG - I've copy-n-pasted most of the SWIG stuff from Xapian.
All the best, Tim.
>From 5ced7d08029f30a69506c42a08d0581c251052d4 Mon Sep 17 00:00:00 2001 From: Tim Brody <[email protected]> Date: Wed, 3 Nov 2010 12:13:23 +0000 Subject: [PATCH] Very basic SWIG Perl wrapper and supporting automake/autoconf scripts --- 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...@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 <[email protected] + * + * 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
_______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
