gambas-source-code/gb.pdf/src/CPdfDocument.cpp
Laurent Carlier 4a91059623 ...and another typo from #4730... sorry!!!!
git-svn-id: svn://localhost/gambas/trunk@4732 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2012-05-15 08:17:51 +00:00

1474 lines
32 KiB
C++

/***************************************************************************
CPdfDocument.cpp
(C) 2005-2007 Daniel Campos Fernández <dcamposf@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
***************************************************************************/
#define __CPDFDOCUMENT_C
#include "CPdfDocument.h"
#include "gambas.h"
#include "main.h"
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <PDFDoc.h>
#include <Stream.h>
#include <ErrorCodes.h>
#include <Page.h>
#include <Catalog.h>
#include <TextOutputDev.h>
#include <SplashOutputDev.h>
#include <splash/SplashBitmap.h>
#include <goo/GooList.h>
#include <Outline.h>
#include <Link.h>
#include <Gfx.h>
#include <GlobalParams.h>
#include <UnicodeMap.h>
/***************************************************************************/
static CPDFRECT *create_rect(void)
{
return (CPDFRECT *)GB.New(GB.FindClass("PdfRect"), NULL, NULL);
}
BEGIN_PROPERTY(PdfRect_X)
GB.ReturnFloat(THIS_RECT->x);
END_PROPERTY
BEGIN_PROPERTY(PdfRect_Y)
GB.ReturnFloat(THIS_RECT->y);
END_PROPERTY
BEGIN_PROPERTY(PdfRect_Width)
GB.ReturnFloat(THIS_RECT->w);
END_PROPERTY
BEGIN_PROPERTY(PdfRect_Height)
GB.ReturnFloat(THIS_RECT->h);
END_PROPERTY
BEGIN_PROPERTY(PdfRect_Right)
GB.ReturnFloat(THIS_RECT->x + THIS_RECT->w);
END_PROPERTY
BEGIN_PROPERTY(PdfRect_Bottom)
GB.ReturnFloat(THIS_RECT->y + THIS_RECT->h);
END_PROPERTY
/****************************************************************************
Translations from Poppler universe to Gambas universe
****************************************************************************/
static void return_unicode_string(Unicode *unicode, int len)
{
static UnicodeMap *uMap = NULL;
GooString gstr;
char buf[8]; /* 8 is enough for mapping an unicode char to a string */
int i, n;
if (uMap == NULL)
{
GooString *enc = new GooString("UTF-8");
uMap = globalParams->getUnicodeMap(enc);
uMap->incRefCnt();
delete enc;
}
for (i = 0; i < len; ++i) {
n = uMap->mapUnicode(unicode[i], buf, sizeof(buf));
gstr.append(buf, n);
}
GB.ReturnNewZeroString(gstr.getCString());
}
static void aux_return_string_info(void *_object, const char *key)
{
Object obj;
Object dst;
GooString *goo_value;
Dict *info_dict;
char *tmpstr;
THIS->doc->getDocInfo (&obj);
if (!obj.isDict()) { GB.ReturnNewZeroString(""); return; }
info_dict=obj.getDict();
info_dict->lookup ((char *)key, &dst);
if (!dst.isString ()) { GB.ReturnNewZeroString(""); }
else {
goo_value = dst.getString();
if (goo_value->hasUnicodeMarker())
{
GB.ConvString (&tmpstr,goo_value->getCString()+2,goo_value->getLength()-2,"UTF-16BE","UTF-8");
GB.ReturnNewZeroString(tmpstr);
}
else
GB.ReturnNewString(goo_value->getCString(),goo_value->getLength());
}
dst.free();
obj.free();
}
static void aux_return_date_info(void *_object, const char *key)
{
// TODO: Y2K effect
GB_DATE_SERIAL ds;
GB_DATE ret;
Object obj;
Object dst;
GooString *goo;
Dict *info_dict;
char *datestr=NULL,*tofree=NULL;
int nnum;
GB.ReturnDate(NULL);
THIS->doc->getDocInfo (&obj);
if (!obj.isDict()) return;
info_dict=obj.getDict();
info_dict->lookup ((char *)key, &dst);
if (dst.isString ())
{
goo = dst.getString();
if (goo->hasUnicodeMarker())
GB.ConvString (&datestr,goo->getCString()+2,goo->getLength()-2,"UTF-16BE","UTF-8");
else
{
datestr = GB.NewString(goo->getCString(),goo->getLength());
tofree=datestr;
}
if (datestr)
{
if (datestr[0] == 'D' && datestr[1] == ':') datestr += 2;
nnum=sscanf(datestr, "%4hd%2hd%2hd%2hd%2hd%2hd",&ds.year, &ds.month, \
&ds.day, &ds.hour, &ds.min, &ds.sec);
if (nnum == 6)
{
if (!GB.MakeDate(&ds,&ret))
GB.ReturnDate(&ret);
}
}
}
if (tofree) GB.FreeString(&tofree);
dst.free();
obj.free();
}
static LinkDest *get_dest(LinkAction *act)
{
if (!act)
return 0;
switch (act->getKind())
{
case actionGoTo: return ((LinkGoTo*)act)->getDest();
case actionGoToR: return ((LinkGoToR*)act)->getDest();
default: return 0;
}
}
static uint32_t aux_get_page_from_action(void *_object, LinkAction *act)
{
Ref pref;
LinkDest *dest = get_dest(act);
#if POPPLER_VERSION_0_6
GooString *name;
#else
UGooString *name;
#endif
if (!dest)
{
// try to use NamedDest to get dest
if (!act)
return 0;
if (act->getKind () == actionGoTo)
{
name = ((LinkGoTo*)act)->getNamedDest();
if (name)
dest = THIS->doc->findDest(name);
}
}
if (!dest)
return 0;
if (dest->isPageRef() )
{
pref= dest->getPageRef();
return THIS->doc->findPage(pref.num, pref.gen);
}
else
return dest->getPageNum();
}
static void aux_get_dimensions_from_action(LinkAction *act, CPDFRECT *rect)
{
LinkDest *dest = get_dest(act);
if (!dest)
return;
rect->x = dest->getLeft();
rect->w = dest->getRight() - rect->x;
rect->y = dest->getTop();
rect->h = dest->getBottom() - rect->y;
}
static double aux_get_zoom_from_action(LinkAction *act)
{
LinkDest *dest = get_dest(act);
if (dest)
return dest->getZoom();
else
return 1;
}
static char* aux_get_target_from_action(LinkAction *act)
{
char *vl=NULL;
char *uni=NULL;
GooString *tmp=NULL;
switch (act->getKind())
{
case actionGoToR:
tmp=((LinkGoToR*)act)->getFileName(); break;
case actionLaunch:
tmp=((LinkLaunch*)act)->getFileName(); break;
case actionURI:
tmp=((LinkURI*)act)->getURI(); break;
case actionNamed:
tmp=((LinkNamed*)act)->getName(); break;
case actionMovie:
#if POPPLER_VERSION_0_8
tmp=((LinkMovie*)act)->getAnnotTitle(); break;
#else
tmp=((LinkMovie*)act)->getTitle(); break;
#endif
default:
break;
}
if (!tmp) return NULL;
if (tmp->hasUnicodeMarker())
{
GB.ConvString (&uni,tmp->getCString()+2,tmp->getLength()-2,"UTF-16BE","UTF-8");
vl = GB.AddString(vl, uni, 0);
}
else
vl = GB.AddString(vl,tmp->getCString(),tmp->getLength());
return vl;
}
/*****************************************************************************
PDF document
******************************************************************************/
static void free_all(void *_object)
{
if (THIS->doc)
{
delete THIS->doc;
THIS->doc=NULL;
}
if (THIS->dev)
{
delete THIS->dev;
THIS->dev=NULL;
}
if (THIS->buf)
{
GB.ReleaseFile(THIS->buf,THIS->len);
THIS->buf=NULL;
}
if (THIS->Found)
{
GB.FreeArray(POINTER(&THIS->Found));
THIS->Found=NULL;
}
if (THIS->links)
{
delete THIS->links;
THIS->links=NULL;
}
if (THIS->pindex)
{
GB.FreeArray(POINTER(&THIS->pindex));
GB.FreeArray(POINTER(&THIS->oldindex));
THIS->pindex=NULL;
THIS->oldindex=NULL;
}
THIS->index=NULL;
THIS->currpage=-1;
}
BEGIN_METHOD_VOID (PDFDOCUMENT_free)
free_all(_object);
END_METHOD
BEGIN_PROPERTY(PDFDOCUMENT_scale)
if (READ_PROPERTY){ GB.ReturnFloat(THIS->scale); return; }
if (VPROP(GB_FLOAT)>0) { THIS->scale = VPROP(GB_FLOAT); return; }
GB.Error("Zoom must be a positive value");
END_PROPERTY
BEGIN_PROPERTY(PDFDOCUMENT_rotation)
int32_t rot;
if (READ_PROPERTY)
{
GB.ReturnInteger(THIS->rotation);
return;
}
rot=VPROP(GB_INTEGER);
while (rot<0) rot+=360;
while (rot>=360) rot-=360;
switch (rot)
{
case 0:
case 90:
case 180:
case 270:
THIS->rotation = VPROP(GB_INTEGER);
break;
}
END_PROPERTY
int32_t open_document (void *_object, char *sfile, int32_t lfile)
{
SplashColor white;
PDFDoc *test;
MemStream *stream;
Object obj;
Outline *outline;
char *buf=NULL;
int32_t len=0;
int32_t ret;
if ( GB.LoadFile(sfile,lfile,&buf,&len) ) return -1;
obj.initNull();
stream=new MemStream(buf,0,(Guint)len,&obj);
test=new PDFDoc (stream,0,0);
if (!test->isOk())
{
GB.ReleaseFile(buf,len);
ret=test->getErrorCode();
delete test;
test=NULL;
if (ret == errEncrypted) return -2;
return -3;
}
free_all(_object);
THIS->doc=test;
THIS->buf=buf;
THIS->len=len;
white[0] = 0xFF; white[1] = 0xFF; white[2] = 0xFF;
THIS->dev=new SplashOutputDev(splashModeRGB8, 3, gFalse, white);
#if POPPLER_VERSION_0_20
THIS->dev->startDoc(THIS->doc);
#else
THIS->dev->startDoc(THIS->doc->getXRef ());
#endif
outline=THIS->doc->getOutline();
if (outline) THIS->index=outline->getItems();
//if (THIS->index)
// if (!THIS->index->getLength()) THIS->index=NULL;
THIS->currindex=0;
THIS->currpage=-1;
return 0;
}
BEGIN_METHOD(PDFDOCUMENT_new, GB_STRING File)
THIS->scale = 1;
THIS->rotation = 0;
if (!MISSING(File))
{
switch (open_document( _object, STRING(File), LENGTH(File)) )
{
case -1: GB.Error("File not found"); return;
case -2: GB.Error("PDF is encrypted"); return;
case -3: GB.Error("Bad PDF File"); return;
}
}
END_METHOD
BEGIN_METHOD (PDFDOCUMENT_open, GB_STRING File;)
switch (open_document( _object, STRING(File), LENGTH(File)) )
{
case -1: GB.Error("File not found"); return;
case -2: GB.Error("PDF is encrypted"); return;
case -3: GB.Error("Bad PDF File"); return;
}
END_METHOD
BEGIN_METHOD_VOID(PDFDOCUMENT_close)
free_all(_object);
END_METHOD
BEGIN_METHOD(PDFDOCUMENT_get,GB_INTEGER index;)
if (!THIS->doc || (VARG(index)<1) || ( VARG(index)>THIS->doc->getNumPages() ) )
{
GB.Error("Invalid page number");
return;
}
if (THIS->currpage != (uint32_t)VARG(index) )
{
if (THIS->Found)
{
GB.FreeArray(POINTER(&THIS->Found));
THIS->Found=NULL;
}
if (THIS->links)
{
delete THIS->links;
THIS->links=NULL;
}
THIS->page=THIS->doc->getCatalog()->getPage(VARG(index));
THIS->currpage=VARG(index);
}
RETURN_SELF();
END_METHOD
BEGIN_PROPERTY(PDFDOCUMENT_ready)
GB.ReturnBoolean( (bool)THIS->doc );
END_PROPERTY
BEGIN_PROPERTY(PDFDOCUMENT_count)
GB.ReturnInteger( (int32_t) (THIS->doc ? THIS->doc->getNumPages() : 0));
END_PROPERTY
BEGIN_PROPERTY(PDFDOCUMENT_info)
if (THIS->doc) RETURN_SELF();
else GB.ReturnNull();
END_PROPERTY
/*****************************************************************************
PDF document information
******************************************************************************/
BEGIN_PROPERTY(PDFINFO_title)
aux_return_string_info(_object,"Title");
END_PROPERTY
BEGIN_PROPERTY(PDFINFO_format)
char ctx[16];
#if POPPLER_VERSION_0_11_3
snprintf(ctx, sizeof(ctx), "%.2g", THIS->doc->getPDFMajorVersion () + THIS->doc->getPDFMinorVersion() / 10.0);
#else
snprintf(ctx, sizeof(ctx), "%.2g", THIS->doc->getPDFVersion());
#endif
GB.ReturnNewZeroString(ctx);
END_PROPERTY
BEGIN_PROPERTY(PDFINFO_author)
aux_return_string_info(_object,"Author");
END_PROPERTY
BEGIN_PROPERTY(PDFINFO_subject)
aux_return_string_info(_object,"Subject");
END_PROPERTY
BEGIN_PROPERTY(PDFINFO_keywords)
aux_return_string_info(_object,"Keywords");
END_PROPERTY
BEGIN_PROPERTY(PDFINFO_creator)
aux_return_string_info(_object,"Creator");
END_PROPERTY
BEGIN_PROPERTY(PDFINFO_producer)
aux_return_string_info(_object,"Producer");
END_PROPERTY
BEGIN_PROPERTY(PDFINFO_linearized)
GB.ReturnBoolean(THIS->doc->isLinearized());
END_PROPERTY
BEGIN_PROPERTY(PDFINFO_layout)
Catalog *catalog;
catalog=THIS->doc->getCatalog();
if (!catalog) { GB.ReturnInteger(Catalog::pageLayoutNone); return; }
if (!catalog->isOk()) { GB.ReturnInteger(Catalog::pageLayoutNone); return; }
GB.ReturnInteger(catalog->getPageLayout());
END_PROPERTY
BEGIN_PROPERTY(PDFINFO_mode)
Catalog *catalog;
catalog=THIS->doc->getCatalog();
if (!catalog) { GB.ReturnInteger(Catalog::pageModeNone); return; }
if (!catalog->isOk()) { GB.ReturnInteger(Catalog::pageModeNone); return; }
GB.ReturnInteger(catalog->getPageMode());
END_PROPERTY
BEGIN_PROPERTY(PDFINFO_canprint)
GB.ReturnBoolean(THIS->doc->okToPrint());
END_PROPERTY
BEGIN_PROPERTY(PDFINFO_canmodify)
GB.ReturnBoolean(THIS->doc->okToChange());
END_PROPERTY
BEGIN_PROPERTY(PDFINFO_cancopy)
GB.ReturnBoolean(THIS->doc->okToCopy());
END_PROPERTY
BEGIN_PROPERTY(PDFINFO_canaddnotes)
GB.ReturnBoolean(THIS->doc->okToAddNotes());
END_PROPERTY
BEGIN_PROPERTY(PDFINFO_creation)
aux_return_date_info(_object,"CreationDate");
END_PROPERTY
BEGIN_PROPERTY(PDFINFO_modification)
aux_return_date_info(_object,"ModDate");
END_PROPERTY
/*****************************************************************************
PDF document index
******************************************************************************/
BEGIN_PROPERTY(PDFDOCUMENT_has_index)
GB.ReturnBoolean(THIS->index && THIS->index->getLength());
END_PROPERTY
BEGIN_PROPERTY(PDFDOCUMENT_index)
if (!THIS->index) { GB.ReturnNull(); return; }
THIS->action=((OutlineItem*)THIS->index->get(THIS->currindex))->getAction();
RETURN_SELF();
END_PROPERTY
BEGIN_PROPERTY(PDFINDEX_count)
GB.ReturnInteger(THIS->index->getLength());
END_PROPERTY
BEGIN_PROPERTY(PDFINDEX_has_children)
OutlineItem *item;
item = (OutlineItem *)THIS->index->get (THIS->currindex);
GB.ReturnBoolean(item->getKids() && item->getKids()->getLength());
END_PROPERTY
BEGIN_PROPERTY(PDFINDEX_is_open)
OutlineItem *item;
item = (OutlineItem *)THIS->index->get (THIS->currindex);
if (READ_PROPERTY)
{ GB.ReturnBoolean(item->isOpen()); return; }
if (VPROP(GB_INTEGER)) item->open();
else item->close();
END_PROPERTY
BEGIN_PROPERTY(PDFINDEX_title)
OutlineItem *item;
item = (OutlineItem *)THIS->index->get (THIS->currindex);
return_unicode_string(item->getTitle(), item->getTitleLength());
END_PROPERTY
BEGIN_METHOD_VOID(PDFINDEX_root)
Outline *outline;
outline=THIS->doc->getOutline();
if (outline) THIS->index=outline->getItems();
THIS->currindex=0;
if (THIS->pindex) { GB.FreeArray(POINTER(&THIS->pindex)); THIS->pindex=NULL; }
if (THIS->oldindex) { GB.FreeArray(POINTER(&THIS->oldindex)); THIS->oldindex=NULL; }
END_METHOD
BEGIN_METHOD_VOID(PDFINDEX_prev)
if (!THIS->currindex) { GB.ReturnBoolean(true); return; }
THIS->currindex--;
GB.ReturnBoolean(false);
END_METHOD
BEGIN_METHOD_VOID(PDFINDEX_next)
if ( (THIS->currindex+1) >= (uint32_t)THIS->index->getLength() )
{ GB.ReturnBoolean(true); return; }
THIS->currindex++;
GB.ReturnBoolean(false);
END_METHOD
BEGIN_METHOD_VOID(PDFINDEX_child)
OutlineItem *item;
item = (OutlineItem *)THIS->index->get (THIS->currindex);
if (!item->hasKids() || item->getKids()->getLength() == 0) { GB.ReturnBoolean(true); return; }
if (THIS->pindex)
{
GB.Add(POINTER(&THIS->pindex));
GB.Add(POINTER(&THIS->oldindex));
}
else
{
GB.NewArray(POINTER(&THIS->pindex),sizeof(void*),1);
GB.NewArray(POINTER(&THIS->oldindex),sizeof(uint32_t),1);
}
if (!item->isOpen()) item->open();
THIS->pindex[GB.Count(POINTER(THIS->pindex))-1]=(void*)THIS->index;
THIS->oldindex[GB.Count(POINTER(THIS->pindex))-1]=THIS->currindex;
THIS->index=item->getKids();
THIS->currindex=0;
GB.ReturnBoolean(false);
END_METHOD
BEGIN_METHOD_VOID(PDFINDEX_parent)
if (!THIS->pindex) { GB.ReturnBoolean(true); return; }
THIS->index=(GooList*)THIS->pindex[GB.Count(POINTER(THIS->pindex))-1];
THIS->currindex=THIS->oldindex[GB.Count(POINTER(THIS->pindex))-1];
if (GB.Count(POINTER(THIS->pindex))==1)
{
GB.FreeArray(POINTER(&THIS->pindex));
GB.FreeArray(POINTER(&THIS->oldindex));
THIS->oldindex=NULL;
THIS->pindex=NULL;
}
else
{
GB.Remove(POINTER(&THIS->pindex),GB.Count(POINTER(THIS->pindex))-1,1);
GB.Remove(POINTER(&THIS->oldindex),GB.Count(POINTER(THIS->oldindex))-1,1);
}
GB.ReturnBoolean(false);
END_METHOD
/*****************************************************************************
PDF pages
******************************************************************************/
BEGIN_PROPERTY (PDFPAGE_width)
if ( (THIS->rotation==90) || (THIS->rotation==270) )
GB.ReturnInteger((int32_t)(THIS->page->getMediaHeight()*THIS->scale));
else
GB.ReturnInteger((int32_t)(THIS->page->getMediaWidth()*THIS->scale));
END_PROPERTY
BEGIN_PROPERTY (PDFPAGE_height)
if ( (THIS->rotation==90) || (THIS->rotation==270) )
GB.ReturnInteger((int32_t)(THIS->page->getMediaWidth()*THIS->scale));
else
GB.ReturnInteger((int32_t)(THIS->page->getMediaHeight()*THIS->scale));
END_PROPERTY
static uint32_t *get_page_data(CPDFDOCUMENT *_object, int32_t x, int32_t y, int32_t *width, int32_t *height, double scale, int32_t rotation)
{
SplashBitmap *map;
uint32_t *data;
int32_t w, h;
int32_t rw;
int32_t rh;
if ( (THIS->rotation==90) || (THIS->rotation==270) )
{
rh=(int32_t)(THIS->page->getMediaWidth()*THIS->scale);
rw=(int32_t)(THIS->page->getMediaHeight()*THIS->scale);
}
else
{
rw=(int32_t)(THIS->page->getMediaWidth()*THIS->scale);
rh=(int32_t)(THIS->page->getMediaHeight()*THIS->scale);
}
w = *width;
h = *height;
if (w < 0) w = rw;
if (h < 0) h = rh;
if (x<0) x=0;
if (y<0) y=0;
if (w<1) w=1;
if (h<1) h=1;
if ( (x+w) > rw ) w=rw-x;
if ( (y+h) > rh ) h=rh-y;
if ( (w<0) || (h<0) ) return NULL;
#if POPPLER_VERSION_0_20
THIS->page->displaySlice(THIS->dev,72.0*scale,72.0*scale,
rotation,
gFalse,
gTrue,
x,y,w,h,
gFalse);
#else
THIS->page->displaySlice(THIS->dev,72.0*scale,72.0*scale,
rotation,
gFalse,
gTrue,
x,y,w,h,
gFalse,
THIS->doc->getCatalog ());
#endif
map=THIS->dev->getBitmap();
data=(uint32_t*)map->getDataPtr();
*width = w;
*height = h;
return data;
}
BEGIN_METHOD(PDFPAGE_image, GB_INTEGER x; GB_INTEGER y; GB_INTEGER w; GB_INTEGER h)
uint32_t *data;
int32_t x,y, w, h;
x = VARGOPT(x, 0);
y = VARGOPT(y, 0);
w = VARGOPT(w, -1);
h = VARGOPT(h, -1);
data = get_page_data(THIS, x, y, &w, &h, THIS->scale, THIS->rotation);
if (!data) { GB.ReturnNull(); return; }
/*GB.Image.Create(&img, data, w, h, GB_IMAGE_RGB);
GB.ReturnObject(img);*/
GB.ReturnObject(IMAGE.Create(w, h, GB_IMAGE_RGB, (unsigned char *)data));
END_METHOD
BEGIN_PROPERTY (PDFPAGE_property_image)
int32_t w=-1;
int32_t h=-1;
uint32_t *data;
data = get_page_data(THIS, 0, 0, &w, &h, THIS->scale, THIS->rotation);
if (!data) { GB.ReturnNull(); return; }
/*GB.Image.Create(&img, data, w, h, GB_IMAGE_RGB);
GB.ReturnObject(img);*/
GB.ReturnObject(IMAGE.Create(w, h, GB_IMAGE_RGB, (unsigned char *)data));
END_PROPERTY
BEGIN_METHOD(PDFPAGE_select, GB_INTEGER X; GB_INTEGER Y; GB_INTEGER W; GB_INTEGER H)
TextOutputDev *dev;
GooString *str;
Gfx *gfx;
int32_t x,y,w,h;
x = VARGOPT(X, 0);
y = VARGOPT(Y, 0);
w = VARGOPT(W, (int32_t)THIS->page->getMediaWidth());
h = VARGOPT(H, (int32_t)THIS->page->getMediaHeight());
#if POPPLER_VERSION_0_20
dev = new TextOutputDev (NULL, gTrue, 0, gFalse, gFalse);
gfx = THIS->page->createGfx(dev,72.0,72.0,0,gFalse,gTrue,-1, -1, -1, -1, gFalse, NULL, NULL);
#else
dev = new TextOutputDev (NULL, gTrue, gFalse, gFalse);
gfx = THIS->page->createGfx(dev,72.0,72.0,0,gFalse,gTrue,-1, -1, -1, -1, gFalse,THIS->doc->getCatalog (),NULL, NULL, NULL, NULL);
#endif
THIS->page->display(gfx);
dev->endPage();
str=dev->getText((double)x,(double)y,(double)(w+x),(double)(h+y));
delete gfx;
delete dev;
if (!str)
{
GB.ReturnNewZeroString("");
return;
}
GB.ReturnNewString(str->getCString(),str->getLength());
delete str;
END_METHOD
/*****************************************************************************
Bookmarks of a PDF page
******************************************************************************/
void aux_fill_links(void *_object)
{
#if POPPLER_VERSION_0_20
THIS->links = new Links (THIS->page->getAnnots ());
#elif POPPLER_VERSION_0_17
THIS->links = new Links (THIS->page->getAnnots (THIS->doc->getCatalog()));
#else
Object obj;
THIS->links = new Links (THIS->page->getAnnots (&obj),THIS->doc->getCatalog()->getBaseURI ());
obj.free();
#endif
}
BEGIN_PROPERTY (PDFPAGELINKS_count)
if (!THIS->links) aux_fill_links(_object);
if (!THIS->links) { GB.ReturnInteger(0); return; }
GB.ReturnInteger(THIS->links->getNumLinks());
END_PROPERTY
BEGIN_METHOD (PDFPAGELINKS_get,GB_INTEGER ind;)
bool pok=true;
if (!THIS->links) aux_fill_links(_object);
if (!THIS->links) pok=false;
else
{
if (VARG(ind)<0) pok=false;
else
{
if (VARG(ind)>=THIS->links->getNumLinks()) pok=false;
}
}
if (!pok) { GB.Error("Out of bounds"); return; }
THIS->lcurrent=VARG(ind);
THIS->action=THIS->links->getLink(THIS->lcurrent)->getAction();
RETURN_SELF();
END_METHOD
BEGIN_PROPERTY (PDFPAGELINKDATA_parameters)
if (THIS->action->getKind() != actionLaunch )
{
GB.ReturnNewZeroString("");
return;
}
GB.ReturnNewZeroString(((LinkLaunch*)THIS->action)->getParams()->getCString());
END_PROPERTY
BEGIN_PROPERTY (PDFPAGELINKDATA_uri)
char *uri;
uri=aux_get_target_from_action(THIS->action);
GB.ReturnNewZeroString(uri);
if (uri) GB.FreeString(&uri);
END_PROPERTY
BEGIN_PROPERTY(PdfPageLinkData_Rect)
CPDFRECT *rect = create_rect();
aux_get_dimensions_from_action(THIS->action, rect);
GB.ReturnObject(rect);
END_PROPERTY
BEGIN_PROPERTY(PDFPAGELINKDATA_zoom)
GB.ReturnFloat(aux_get_zoom_from_action(THIS->action));
END_PROPERTY
BEGIN_PROPERTY(PDFPAGELINKDATA_page)
GB.ReturnInteger(aux_get_page_from_action(_object,THIS->action));
END_PROPERTY
BEGIN_PROPERTY (PDFPAGELINKDATA_type)
GB.ReturnInteger ( (int32_t)THIS->action->getKind() );
END_PROPERTY
BEGIN_PROPERTY(PDFPAGELINKDATA_check)
if (THIS->action)
RETURN_SELF();
else
GB.ReturnNull();
END_PROPERTY
static void aux_get_link_dimensions(void *_object, CPDFRECT *rect)
{
double l,t,w,h;
double pw,ph;
pw=THIS->page->getMediaWidth();
ph=THIS->page->getMediaHeight();
THIS->links->getLink(THIS->lcurrent)->getRect(&l, &t, &w, &h);
w=w-l;
h=h-t;
switch (THIS->rotation)
{
case 0:
rect->x = (l*THIS->scale);
rect->y = ((ph-t-h)*THIS->scale);
rect->w = (w*THIS->scale);
rect->h = (h*THIS->scale);
break;
case 90:
rect->y = (l*THIS->scale);
rect->x = (t*THIS->scale);
rect->h = (w*THIS->scale);
rect->w = (h*THIS->scale);
break;
case 180:
rect->x = ((l-w)*THIS->scale);
rect->y = (t*THIS->scale);
rect->w = (w*THIS->scale);
rect->h = (h*THIS->scale);
break;
case 270:
rect->y = ((pw-l-w)*THIS->scale);
rect->x = ((ph-t-h)*THIS->scale);
rect->h = (w*THIS->scale);
rect->w = (h*THIS->scale);
break;
}
}
BEGIN_PROPERTY(PdfPageLink_rect)
CPDFRECT *rect = create_rect();
aux_get_link_dimensions(THIS, rect);
GB.ReturnObject(rect);
END_PROPERTY
/*****************************************************************************
Finding a text in a PDF page
******************************************************************************/
BEGIN_METHOD (PDFPAGE_find,GB_STRING Text; GB_BOOLEAN Sensitive;)
TextOutputDev *textdev;
double x0=0, y0=0;
double x1, y1;
CPDFFIND *el;
Unicode *block=NULL;
int nlen=0;
bool sensitive=false;
int count;
// TODO: Use UCS-4BE on big endian systems?
if (GB.ConvString ((char **)(void *)&block,STRING(Text),LENGTH(Text),"UTF-8",GB_SC_UNICODE))
{
GB.Error("Invalid UTF-8 string");
return;
}
nlen=GB.StringLength((char*)block)/sizeof(Unicode);
if (!MISSING(Sensitive)) sensitive=VARG(Sensitive);
#if POPPLER_VERSION_0_20
textdev = new TextOutputDev (NULL, true, 0, false, false);
THIS->page->display (textdev, 72, 72, 0, false, false, false);
#else
textdev = new TextOutputDev (NULL, true, false, false);
THIS->page->display (textdev, 72, 72, 0, false, false, false, THIS->doc->getCatalog());
#endif
if (THIS->Found) { GB.FreeArray(POINTER(&THIS->Found)); THIS->Found=NULL; }
count = 0;
#if POPPLER_VERSION_0_20
while (textdev->findText (block,nlen,gFalse,gTrue,gTrue,gFalse,sensitive,gFalse,gFalse,&x0,&y0,&x1,&y1))
#else
while (textdev->findText (block,nlen,gFalse,gTrue,gTrue,gFalse,sensitive,gFalse,&x0,&y0,&x1,&y1))
#endif
{
if (!THIS->Found)
GB.NewArray(POINTER(&THIS->Found),sizeof(CPDFFIND),1);
else
GB.Add(POINTER(&THIS->Found));
el = &(THIS->Found[count++]); //(CPDFFIND*)&((CPDFFIND*)THIS->Found)[GB.Count(POINTER(THIS->Found))-1];
switch (THIS->rotation)
{
case 0:
el->x0=(x0*THIS->scale);
el->y0=(y0*THIS->scale);
el->x1=((x1-x0)*THIS->scale);
el->y1=((y1-y0)*THIS->scale);
break;
case 90:
el->y1=((x1-x0)*THIS->scale);
el->x1=(y1-y0);
el->y0=(x0*THIS->scale);
el->x0=((THIS->page->getMediaHeight()-y0-el->x1)*THIS->scale);
el->x1=(el->x1*THIS->scale);
break;
case 180:
el->x1=(x1-x0);
el->y1=(y1-y0);
el->x0=((THIS->page->getMediaWidth()-x0-el->x1)*THIS->scale);
el->y0=((THIS->page->getMediaHeight()-y0-el->y1)*THIS->scale);
el->x1=(el->x1*THIS->scale);
el->y1=(el->y1*THIS->scale);
break;
case 270:
el->x1=((y1-y0)*THIS->scale);
el->y1=(x1-x0);
el->x0=(y0*THIS->scale);
el->y0=((THIS->page->getMediaWidth()-x0-el->y1)*THIS->scale);
el->y1=(el->y1*THIS->scale);
break;
}
}
delete textdev;
GB.ReturnBoolean(count == 0);
END_METHOD
BEGIN_METHOD(PDFPAGERESULT_get,GB_INTEGER Index)
CPDFRECT *rect;
CPDFFIND *el;
int index;
index = VARG(Index);
if (!THIS->Found || index < 0 || index >= GB.Count(THIS->Found))
{
GB.Error("Out of bounds");
return;
}
el = &(THIS->Found[index]);
rect = create_rect();
rect->x = el->x0;
rect->y = el->y0;
rect->w = el->x1;
rect->h = el->y1;
GB.ReturnObject(rect);
END_METHOD
BEGIN_PROPERTY (PDFPAGERESULT_count)
if (!THIS->Found) { GB.ReturnInteger(0); return; }
GB.ReturnInteger( GB.Count(POINTER(THIS->Found)) );
END_PROPERTY
/**********************************************************************
Gambas Interface
***********************************************************************/
GB_DESC PdfRectDesc[] =
{
GB_DECLARE("PdfRect", sizeof(CPDFRECT)), GB_NOT_CREATABLE(),
GB_PROPERTY_READ("X", "f", PdfRect_X),
GB_PROPERTY_READ("Y", "f", PdfRect_Y),
GB_PROPERTY_READ("Width", "f", PdfRect_Width),
GB_PROPERTY_READ("Height", "f", PdfRect_Height),
GB_PROPERTY_READ("W", "f", PdfRect_Width),
GB_PROPERTY_READ("H", "f", PdfRect_Height),
GB_PROPERTY_READ("Left", "f", PdfRect_X),
GB_PROPERTY_READ("Top", "f", PdfRect_Y),
GB_PROPERTY_READ("Right", "f", PdfRect_Right),
GB_PROPERTY_READ("Bottom", "f", PdfRect_Bottom),
GB_END_DECLARE
};
GB_DESC PdfResultDesc[]=
{
GB_DECLARE(".PdfDocumentPage.Result",0), GB_VIRTUAL_CLASS(),
GB_METHOD("_get","PdfRect",PDFPAGERESULT_get,"(Index)i"),
GB_PROPERTY_READ("Count","i",PDFPAGERESULT_count),
GB_END_DECLARE
};
GB_DESC PdfLinkDataDesc[]=
{
GB_DECLARE(".PdfDocumentPage.Link.Data",0), GB_VIRTUAL_CLASS(),
GB_PROPERTY_READ("Type","i",PDFPAGELINKDATA_type),
GB_PROPERTY_READ("Target","s",PDFPAGELINKDATA_uri),
GB_PROPERTY_READ("Parameters","s",PDFPAGELINKDATA_parameters),
GB_PROPERTY_READ("Page","i",PDFPAGELINKDATA_page),
GB_PROPERTY_READ("Zoom","f",PDFPAGELINKDATA_zoom),
GB_PROPERTY_READ("Rect", "PdfRect", PdfPageLinkData_Rect),
GB_END_DECLARE
};
GB_DESC PdfLinkDesc[]=
{
GB_DECLARE(".PdfDocumentPage.Link",0), GB_VIRTUAL_CLASS(),
GB_PROPERTY_READ("Rect", "PdfRect", PdfPageLink_rect),
GB_PROPERTY_READ("Data",".PdfDocumentPage.Link.Data", PDFPAGELINKDATA_check),
GB_END_DECLARE
};
GB_DESC PdfIndexDesc[]=
{
GB_DECLARE(".PdfDocument.Index",0), GB_VIRTUAL_CLASS(),
GB_PROPERTY("Expanded","b",PDFINDEX_is_open),
GB_PROPERTY_READ("Count","i",PDFINDEX_count),
GB_PROPERTY_READ("HasChildren","b",PDFINDEX_has_children),
GB_PROPERTY_READ("Title","s",PDFINDEX_title),
GB_PROPERTY_READ("Text","s",PDFINDEX_title),
GB_PROPERTY_READ("Data", ".PdfDocumentPage.Link.Data", PDFPAGELINKDATA_check),
GB_METHOD("MovePrevious","b",PDFINDEX_prev,0),
GB_METHOD("MoveNext","b",PDFINDEX_next,0),
GB_METHOD("MoveChild","b",PDFINDEX_child,0),
GB_METHOD("MoveParent","b",PDFINDEX_parent,0),
GB_METHOD("MoveRoot",0,PDFINDEX_root,0),
GB_END_DECLARE
};
GB_DESC PdfPageDesc[]=
{
GB_DECLARE(".PdfDocumentPage",0), GB_VIRTUAL_CLASS(),
GB_PROPERTY_READ("W","f",PDFPAGE_width),
GB_PROPERTY_READ("H","f",PDFPAGE_height),
GB_PROPERTY_READ("Width","f",PDFPAGE_width),
GB_PROPERTY_READ("Height","f",PDFPAGE_height),
GB_PROPERTY_READ("Image","Image",PDFPAGE_property_image),
GB_PROPERTY_SELF("Result",".PdfDocumentPage.Result"),
GB_METHOD("GetImage","Image",PDFPAGE_image,"[(X)i(Y)i(Width)i(Height)i]"),
GB_METHOD("Find","b",PDFPAGE_find,"(Text)s[(CaseSensitive)b]"),
GB_METHOD("Select","s",PDFPAGE_select,"[(X)i(Y)i(W)i(H)i]"),
GB_METHOD("_get",".PdfDocumentPage.Link",PDFPAGELINKS_get,"(Index)i"),
GB_PROPERTY_READ("Count","i",PDFPAGELINKS_count),
GB_END_DECLARE
};
GB_DESC PdfDocumentInfo[] =
{
GB_DECLARE(".PdfDocument.Info",0), GB_VIRTUAL_CLASS(),
GB_PROPERTY_READ("Title","s",PDFINFO_title),
GB_PROPERTY_READ("Format","s",PDFINFO_format),
GB_PROPERTY_READ("Author","s",PDFINFO_author),
GB_PROPERTY_READ("Subject","s",PDFINFO_subject),
GB_PROPERTY_READ("Keywords","s",PDFINFO_keywords),
GB_PROPERTY_READ("Creator","s",PDFINFO_creator),
GB_PROPERTY_READ("Producer","s",PDFINFO_producer),
GB_PROPERTY_READ("CreationDate","d",PDFINFO_creation),
GB_PROPERTY_READ("ModificationDate","d",PDFINFO_modification),
GB_PROPERTY_READ("Linearized","b",PDFINFO_linearized),
GB_PROPERTY_READ("Layout","i",PDFINFO_layout),
GB_PROPERTY_READ("Mode","i",PDFINFO_mode),
GB_PROPERTY_READ("CanCopy","b",PDFINFO_cancopy),
GB_PROPERTY_READ("CanModify","b",PDFINFO_canmodify),
GB_PROPERTY_READ("CanPrint","b",PDFINFO_canprint),
GB_PROPERTY_READ("CanAddNotes","b",PDFINFO_canaddnotes),
GB_END_DECLARE
};
GB_DESC PdfLayoutDesc[] =
{
GB_DECLARE("PdfLayout", 0), GB_NOT_CREATABLE(),
GB_CONSTANT("Unset","i",Catalog::pageLayoutNone),
GB_CONSTANT("SinglePage","i",Catalog::pageLayoutSinglePage),
GB_CONSTANT("OneColumn","i",Catalog::pageLayoutOneColumn),
GB_CONSTANT("TwoColumnLeft","i",Catalog::pageLayoutTwoColumnLeft),
GB_CONSTANT("TwoColumnRight","i",Catalog::pageLayoutTwoColumnRight),
GB_CONSTANT("TwoPageLeft","i",Catalog::pageLayoutTwoPageLeft),
GB_CONSTANT("TwoPageRight","i",Catalog::pageLayoutTwoPageRight),
GB_END_DECLARE
};
GB_DESC PdfModeDesc[] =
{
GB_DECLARE("PdfPageMode",0), GB_NOT_CREATABLE(),
GB_CONSTANT("Unset","i",Catalog::pageModeNone),
GB_CONSTANT("UseOutlines","i",Catalog::pageModeOutlines),
GB_CONSTANT("UseThumbs","i",Catalog::pageModeThumbs),
GB_CONSTANT("FullScreen","i",Catalog::pageModeFullScreen),
GB_CONSTANT("UseOC","i",Catalog::pageModeOC),
GB_CONSTANT("UseAttachments","i",Catalog::pageModeAttach),
GB_END_DECLARE
};
GB_DESC PdfDocumentDesc[] =
{
GB_DECLARE("PdfDocument", sizeof(CPDFDOCUMENT)),
GB_CONSTANT("Unknown","i",actionUnknown), /* unknown action */
GB_CONSTANT("Goto","i",actionGoTo), /* go to destination */
GB_CONSTANT("GotoRemote","i",actionGoToR), /* go to destination in new file */
GB_CONSTANT("Launch","i",actionLaunch), /* launch app or open doc. */
GB_CONSTANT("Uri","i",actionURI), /* URI */
GB_CONSTANT("Named","i",actionNamed), /* named action*/
GB_CONSTANT("Movie","i",actionMovie), /* movie action */
GB_CONSTANT("Normal","i",0),
GB_CONSTANT("Sideways","i",90),
GB_CONSTANT("Inverted","i",180),
GB_CONSTANT("SidewaysInverted","i",270),
GB_METHOD("_new", 0, PDFDOCUMENT_new, "[(File)s]"),
GB_METHOD("_free", 0, PDFDOCUMENT_free, 0),
GB_METHOD("Open",0,PDFDOCUMENT_open,"(File)s"),
GB_METHOD("Close",0,PDFDOCUMENT_close,0),
GB_METHOD("_get",".PdfDocumentPage",PDFDOCUMENT_get,"(Index)i"),
GB_PROPERTY("Zoom", "f", PDFDOCUMENT_scale),
GB_PROPERTY("Orientation", "i", PDFDOCUMENT_rotation),
GB_PROPERTY_READ("Ready","b",PDFDOCUMENT_ready),
GB_PROPERTY_READ("Count","i",PDFDOCUMENT_count),
GB_PROPERTY_READ("HasIndex","b",PDFDOCUMENT_has_index),
GB_PROPERTY_READ("Index",".PdfDocument.Index",PDFDOCUMENT_index),
GB_PROPERTY_READ("Info",".PdfDocument.Info",PDFDOCUMENT_info),
GB_END_DECLARE
};