X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=pdf2swf%2FSWFOutputDev.cc;h=2728dcb24d87889f252dc3e0a713b89bdbfbef2e;hb=3223ebf85298888a0bda5a489e78584baafa151f;hp=8e93f5de6ae4c45789dd60ebaf43614fdf2302ea;hpb=377ede4ea24974fde5de2a44bd060e6d87dd8bd5;p=swftools.git diff --git a/pdf2swf/SWFOutputDev.cc b/pdf2swf/SWFOutputDev.cc index 8e93f5d..2728dcb 100644 --- a/pdf2swf/SWFOutputDev.cc +++ b/pdf2swf/SWFOutputDev.cc @@ -23,6 +23,12 @@ #include #include #include "../config.h" +#ifdef HAVE_DIRENT_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif #ifdef HAVE_FONTCONFIG_H #include #endif @@ -61,63 +67,35 @@ #include -static PDFDoc*doc = 0; -static char* swffilename = 0; -static int numpages; -static int currentpage; - typedef struct _fontfile { char*filename; int used; } fontfile_t; +// for pdfswf_addfont static fontfile_t fonts[2048]; static int fontnum = 0; +static int config_use_fontconfig = 1; + // swf <-> pdf pages +// TODO: move into pdf_doc_t static int*pages = 0; static int pagebuflen = 0; static int pagepos = 0; +/* config */ static double caplinewidth = 3.0; static int zoom = 72; /* xpdf: 86 */ +static int forceType0Fonts = 0; static void printInfoString(Dict *infoDict, char *key, char *fmt); static void printInfoDate(Dict *infoDict, char *key, char *fmt); -static double fontsizes[] = -{ - 0.833,0.833,0.889,0.889, - 0.788,0.722,0.833,0.778, - 0.600,0.600,0.600,0.600, - 0.576,0.576,0.576,0.576, - 0.733 //? -}; -static char*fontnames[]={ -"Helvetica", -"Helvetica-Bold", -"Helvetica-BoldOblique", -"Helvetica-Oblique", -"Times-Roman", -"Times-Bold", -"Times-BoldItalic", -"Times-Italic", -"Courier", -"Courier-Bold", -"Courier-BoldOblique", -"Courier-Oblique", -"Symbol", -"Symbol", -"Symbol", -"Symbol", -"ZapfDingBats" -}; - struct mapping { char*pdffont; char*filename; - int id; } pdf2t1map[] ={ {"Times-Roman", "n021003l"}, {"Times-Italic", "n021023l"}, @@ -134,12 +112,9 @@ struct mapping { {"Symbol", "s050000l"}, {"ZapfDingbats", "d050000l"}}; -class GfxState; -class GfxImageColorMap; - class SWFOutputDev: public OutputDev { - struct swfoutput output; int outputstarted; + struct swfoutput output; public: // Constructor. @@ -148,6 +123,15 @@ public: // Destructor. virtual ~SWFOutputDev() ; + void setMove(int x,int y); + void setClip(int x1,int y1,int x2,int y2); + + int save(char*filename); + void pagefeed(); + void* getSWF(); + + void getDimensions(int*x1,int*y1,int*x2,int*y2); + //----- get info about output device // Does this device use upside-down coordinates? @@ -157,11 +141,14 @@ public: // Does this device use drawChar() or drawString()? virtual GBool useDrawChar(); + // Can this device draw gradients? + virtual GBool useGradients(); + virtual GBool interpretType3Chars() {return gTrue;} //----- initialization and control - void startDoc(XRef *xref); + void setXRef(PDFDoc*doc, XRef *xref); // Start a page. virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ; @@ -228,6 +215,9 @@ public: int clipping[64]; int clippos; + int currentpage; + + PDFDoc*doc; XRef*xref; char* searchFont(char*name); @@ -238,12 +228,137 @@ public: int pbminfo; // did we write "File contains jpegs" yet? int linkinfo; // did we write "File contains links" yet? int ttfinfo; // did we write "File contains TrueType Fonts" yet? + int gradientinfo; // did we write "File contains Gradients yet? int type3active; // are we between beginType3()/endType3()? GfxState *laststate; + + int pic_xids[1024]; + int pic_yids[1024]; + int pic_ids[1024]; + int pic_width[1024]; + int pic_height[1024]; + int picpos; + int pic_id; + char type3Warning; + + char* substitutetarget[256]; + char* substitutesource[256]; + int substitutepos; + + int user_movex,user_movey; + int user_clipx1,user_clipx2,user_clipy1,user_clipy2; +}; + +static char*getFontID(GfxFont*font); + +class InfoOutputDev: public OutputDev +{ + public: + int x1,y1,x2,y2; + int num_links; + int num_images; + int num_fonts; + + InfoOutputDev() + { + num_links = 0; + num_images = 0; + num_fonts = 0; + } + virtual ~InfoOutputDev() + { + } + virtual GBool upsideDown() {return gTrue;} + virtual GBool useDrawChar() {return gTrue;} + virtual GBool useGradients() {return gTrue;} + virtual GBool interpretType3Chars() {return gTrue;} + virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2) + { + double x1,y1,x2,y2; + state->transform(crop_x1,crop_y1,&x1,&y1); + state->transform(crop_x2,crop_y2,&x2,&y2); + if(x2x1 = (int)x1; + this->y1 = (int)y1; + this->x2 = (int)x2; + this->y2 = (int)y2; + } + virtual void drawLink(Link *link, Catalog *catalog) + { + num_links++; + } + virtual void updateFont(GfxState *state) + { + GfxFont*font = state->getFont(); + if(!font) + return; + char*id = getFontID(font); + /* FIXME*/ + num_fonts++; + } + virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, + int width, int height, GBool invert, + GBool inlineImg) + { + num_images++; + } + virtual void drawImage(GfxState *state, Object *ref, Stream *str, + int width, int height, GfxImageColorMap *colorMap, + int *maskColors, GBool inlineImg) + { + num_images++; + } }; +SWFOutputDev::SWFOutputDev() +{ + jpeginfo = 0; + ttfinfo = 0; + linkinfo = 0; + pbminfo = 0; + type3active = 0; + clippos = 0; + clipping[clippos] = 0; + outputstarted = 0; + xref = 0; + picpos = 0; + pic_id = 0; + substitutepos = 0; + type3Warning = 0; + user_movex = 0; + user_movey = 0; + user_clipx1 = 0; + user_clipy1 = 0; + user_clipx2 = 0; + user_clipy2 = 0; + memset(&output, 0, sizeof(output)); +// printf("SWFOutputDev::SWFOutputDev() \n"); +}; + +void SWFOutputDev::setMove(int x,int y) +{ + this->user_movex = x; + this->user_movey = y; +} + +void SWFOutputDev::setClip(int x1,int y1,int x2,int y2) +{ + if(x2user_clipx1 = x1; + this->user_clipy1 = y1; + this->user_clipx2 = x2; + this->user_clipy2 = y2; +} +void SWFOutputDev::getDimensions(int*x1,int*y1,int*x2,int*y2) +{ + return swfoutput_getdimensions(&output, x1,y1,x2,y2); +} + static char*getFontID(GfxFont*font) { GString*gstr = font->getName(); @@ -254,20 +369,25 @@ static char*getFontID(GfxFont*font) sprintf(buf, "UFONT%d", r->num); return strdup(buf); } - return fontname; + return strdup(fontname); } static char*getFontName(GfxFont*font) { - char*fontname = getFontID(font); - char* plus = strchr(fontname, '+'); - if(plus && plus < &fontname[strlen(fontname)-1]) - fontname = plus+1; + char*fontid = getFontID(font); + char*fontname= 0; + char* plus = strchr(fontid, '+'); + if(plus && plus < &fontid[strlen(fontid)-1]) { + fontname = strdup(plus+1); + } else { + fontname = strdup(fontid); + } + free(fontid); return fontname; } -char mybuf[1024]; -char* gfxstate2str(GfxState *state) +static char mybuf[1024]; +static char* gfxstate2str(GfxState *state) { char*bufpos = mybuf; GfxRGB rgb; @@ -373,16 +493,14 @@ char* gfxstate2str(GfxState *state) return mybuf; } - - -void dumpFontInfo(char*loglevel, GfxFont*font); -int lastdumps[1024]; -int lastdumppos = 0; +static void dumpFontInfo(char*loglevel, GfxFont*font); +static int lastdumps[1024]; +static int lastdumppos = 0; /* nr = 0 unknown nr = 1 substituting nr = 2 type 3 */ -void showFontError(GfxFont*font, int nr) +static void showFontError(GfxFont*font, int nr) { Ref*r=font->getID(); int t; @@ -402,7 +520,7 @@ void showFontError(GfxFont*font, int nr) dumpFontInfo("", font); } -void dumpFontInfo(char*loglevel, GfxFont*font) +static void dumpFontInfo(char*loglevel, GfxFont*font) { char* name = getFontID(font); Ref* r=font->getID(); @@ -464,26 +582,44 @@ void dumpFontInfo(char*loglevel, GfxFont*font) //void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) {printf("void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) \n");} //void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) {printf("void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) \n");} -SWFOutputDev::SWFOutputDev() +static void free_outline(SWF_OUTLINE*outline) { - jpeginfo = 0; - ttfinfo = 0; - linkinfo = 0; - pbminfo = 0; - type3active = 0; - clippos = 0; - clipping[clippos] = 0; - outputstarted = 0; - xref = 0; -// printf("SWFOutputDev::SWFOutputDev() \n"); -}; + while(outline) { + SWF_OUTLINE*next = outline->link; + free(outline); + outline = next; + } +} + +static void dump_outline(SWF_OUTLINE*outline) +{ + double x=0,y=0; + while(outline) { + double lastx=x,lasty=y; + x += (outline->dest.x/(float)0xffff); + y += (outline->dest.y/(float)0xffff); + if(outline->type == SWF_PATHTYPE_MOVE) { + msg(" | moveto %f,%f", x,y); + } else if(outline->type == SWF_PATHTYPE_LINE) { + msg(" | lineto: %f,%f\n",x,y); + } else if(outline->type == SWF_PATHTYPE_BEZIER) { + SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline; + float x1 = o2->C.x/(float)0xffff+lastx; + float y1 = o2->C.y/(float)0xffff+lasty; + float x2 = o2->B.x/(float)0xffff+lastx; + float y2 = o2->B.y/(float)0xffff+lasty; + msg(" | spline: %f,%f -> %f,%f -> %f,%f\n",x1,y1,x2,y2,x,y); + } + outline = outline->link; + } +} SWF_OUTLINE* gfxPath_to_SWF_OUTLINE(GfxState*state, GfxPath*path) { int num = path->getNumSubpaths(); int s,t; bezierpathsegment*start,*last=0; - bezierpathsegment*outline = start = new bezierpathsegment(); + bezierpathsegment*outline = start = (bezierpathsegment*)malloc(sizeof(bezierpathsegment)); int cpos = 0; double lastx=0,lasty=0; if(!num) { @@ -509,7 +645,7 @@ SWF_OUTLINE* gfxPath_to_SWF_OUTLINE(GfxState*state, GfxPath*path) outline->type = SWF_PATHTYPE_MOVE; outline->dest.x = x; outline->dest.y = y; - outline->link = (SWF_OUTLINE*)new bezierpathsegment(); + outline->link = (SWF_OUTLINE*)malloc(sizeof(bezierpathsegment)); outline = (bezierpathsegment*)outline->link; cpos = 0; lastx = nx; @@ -533,8 +669,7 @@ SWF_OUTLINE* gfxPath_to_SWF_OUTLINE(GfxState*state, GfxPath*path) outline->dest.x = x; outline->dest.y = y; outline->type = cpos?SWF_PATHTYPE_BEZIER:SWF_PATHTYPE_LINE; - outline->link = 0; - outline->link = (SWF_OUTLINE*)new bezierpathsegment(); + outline->link = (SWF_OUTLINE*)malloc(sizeof(bezierpathsegment)); outline = (bezierpathsegment*)outline->link; cpos = 0; lastx = nx; @@ -542,7 +677,9 @@ SWF_OUTLINE* gfxPath_to_SWF_OUTLINE(GfxState*state, GfxPath*path) } } } + if(last->link) {free(last->link);} last->link = 0; + return (SWF_OUTLINE*)start; } /*---------------------------------------------------------------------------- @@ -551,7 +688,6 @@ SWF_OUTLINE* gfxPath_to_SWF_OUTLINE(GfxState*state, GfxPath*path) void SWFOutputDev::stroke(GfxState *state) { - msg(" stroke\n"); GfxPath * path = state->getPath(); int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel @@ -565,6 +701,11 @@ void SWFOutputDev::stroke(GfxState *state) m.m11 = 1; m.m21 = 0; m.m22 = 1; m.m12 = 0; m.m13 = 0; m.m23 = 0; SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path); + + if(getLogLevel() >= LOGLEVEL_TRACE) { + msg(" stroke\n"); + dump_outline(outline); + } lineJoin = 1; // other line joins are not yet supported by the swf encoder // TODO: support bevel joints @@ -587,51 +728,90 @@ void SWFOutputDev::stroke(GfxState *state) updateStrokeColor(state); //reset updateFillColor(state); //reset } + free_outline(outline); } void SWFOutputDev::fill(GfxState *state) { - msg(" fill\n"); GfxPath * path = state->getPath(); struct swfmatrix m; m.m11 = 1; m.m21 = 0; m.m22 = 1; m.m12 = 0; m.m13 = 0; m.m23 = 0; SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path); + + if(getLogLevel() >= LOGLEVEL_TRACE) { + msg(" fill\n"); + dump_outline(outline); + } + swfoutput_setdrawmode(&output, DRAWMODE_FILL); swfoutput_drawpath(&output, outline, &m); + free_outline(outline); } void SWFOutputDev::eoFill(GfxState *state) { - msg(" eofill\n"); GfxPath * path = state->getPath(); struct swfmatrix m; m.m11 = 1; m.m21 = 0; m.m22 = 1; m.m12 = 0; m.m13 = 0; m.m23 = 0; SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path); + + if(getLogLevel() >= LOGLEVEL_TRACE) { + msg(" eofill\n"); + dump_outline(outline); + } + swfoutput_setdrawmode(&output, DRAWMODE_EOFILL); swfoutput_drawpath(&output, outline, &m); + free_outline(outline); } void SWFOutputDev::clip(GfxState *state) { - msg(" clip\n"); GfxPath * path = state->getPath(); struct swfmatrix m; m.m11 = 1; m.m22 = 1; m.m12 = 0; m.m21 = 0; m.m13 = 0; m.m23 = 0; SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path); + + if(getLogLevel() >= LOGLEVEL_TRACE) { + msg(" clip\n"); + dump_outline(outline); + } + swfoutput_startclip(&output, outline, &m); clipping[clippos] ++; + free_outline(outline); } void SWFOutputDev::eoClip(GfxState *state) { - msg(" eoclip\n"); GfxPath * path = state->getPath(); struct swfmatrix m; m.m11 = 1; m.m21 = 0; m.m22 = 1; m.m12 = 0; m.m13 = 0; m.m23 = 0; SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path); + + if(getLogLevel() >= LOGLEVEL_TRACE) { + msg(" eoclip\n"); + dump_outline(outline); + } + swfoutput_startclip(&output, outline, &m); clipping[clippos] ++; + free_outline(outline); +} + +/* pass through functions for swf_output */ +int SWFOutputDev::save(char*filename) +{ + return swfoutput_save(&output, filename); +} +void SWFOutputDev::pagefeed() +{ + swfoutput_pagefeed(&output); +} +void* SWFOutputDev::getSWF() +{ + return (void*)swfoutput_get(&output); } SWFOutputDev::~SWFOutputDev() @@ -648,6 +828,15 @@ GBool SWFOutputDev::useDrawChar() { return gTrue; } +GBool SWFOutputDev::useGradients() +{ + if(!gradientinfo) + { + msg(" File contains gradients"); + gradientinfo = 1; + } + return gTrue; +} void SWFOutputDev::beginString(GfxState *state, GString *s) { @@ -657,9 +846,6 @@ void SWFOutputDev::beginString(GfxState *state, GString *s) m11 *= state->getHorizScaling(); m21 *= state->getHorizScaling(); swfoutput_setfontmatrix(&output, m11, -m21, m12, -m22); - - msg(" fontmatrix %7.3f %7.3f\n", m11,-m21); - msg(" fontmatrix %7.3f %7.3f\n", m12,-m22); } void SWFOutputDev::drawChar(GfxState *state, double x, double y, @@ -670,7 +856,7 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y, // check for invisible text -- this is used by Acrobat Capture if ((state->getRender() & 3) == 3) return; - + Gushort *CIDToGIDMap = 0; GfxFont*font = state->getFont(); if(font->getType() == fontType3) { @@ -683,21 +869,30 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y, state->transform(x, y, &x1, &y1); Unicode u=0; - if(_u) - u = *_u; - - /* find out the character name */ char*name=0; - if(font->isCIDFont() && u) { - GfxCIDFont*cfont = (GfxCIDFont*)font; - int t; - for(t=0;tisCIDFont()) { + GfxCIDFont*cfont = (GfxCIDFont*)font; + + if(font->getType() == fontCIDType2) { + CIDToGIDMap = cfont->getCIDToGID(); + } } else { Gfx8BitFont*font8; font8 = (Gfx8BitFont*)font; @@ -705,13 +900,14 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y, if(enc && enc[c]) name = enc[c]; } - - msg(" drawChar(%f,%f,c='%c' (%d),u=%d <%d>) CID=%d name=\"%s\"\n",x,y,(c&127)>=32?c:'?',c,u, uLen, font->isCIDFont(), FIXNULL(name)); - - /*x1 = (int)(x1+0.5); - y1 = (int)(y1+0.5);*/ - - int ret = swfoutput_drawchar(&output, x1, y1, name, c, u); + + if (CIDToGIDMap) { + msg(" drawChar(%f, %f, c='%c' (%d), GID=%d, u=%d <%d>) CID=%d name=\"%s\"\n", x, y, (c&127)>=32?c:'?', c, CIDToGIDMap[c], u, uLen, font->isCIDFont(), FIXNULL(name)); + swfoutput_drawchar(&output, x1, y1, name, CIDToGIDMap[c], u); + } else { + msg(" drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d name=\"%s\"\n",x,y,(c&127)>=32?c:'?',c,u, uLen, font->isCIDFont(), FIXNULL(name)); + swfoutput_drawchar(&output, x1, y1, name, c, u); + } } void SWFOutputDev::endString(GfxState *state) { @@ -736,54 +932,59 @@ void SWFOutputDev::endType3Char(GfxState *state) void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2) { - double x1,y1,x2,y2; - int rot = doc->getPageRotate(1); - laststate = state; - msg(" startPage %d (%f,%f,%f,%f)\n", pageNum, crop_x1, crop_y1, crop_x2, crop_y2); - if(rot!=0) - msg(" page is rotated %d degrees\n", rot); - - msg(" processing page %d", pageNum); + this->currentpage = pageNum; + double x1,y1,x2,y2; + int rot = doc->getPageRotate(1); + laststate = state; + msg(" startPage %d (%f,%f,%f,%f)\n", pageNum, crop_x1, crop_y1, crop_x2, crop_y2); + if(rot!=0) + msg(" page is rotated %d degrees\n", rot); + + /* state->transform(state->getX1(),state->getY1(),&x1,&y1); + state->transform(state->getX2(),state->getY2(),&x2,&y2); + Use CropBox, not MediaBox, as page size + */ + + /*x1 = crop_x1; + y1 = crop_y1; + x2 = crop_x2; + y2 = crop_y2;*/ + state->transform(crop_x1,crop_y1,&x1,&y1); + state->transform(crop_x2,crop_y2,&x2,&y2); + + if(x2 x1)*/ x1 = user_clipx1; + /*if(user_clipx2 < x2)*/ x2 = user_clipx2; + /*if(user_clipy1 > y1)*/ y1 = user_clipy1; + /*if(user_clipy2 < y2)*/ y2 = user_clipy2; + } - /* state->transform(state->getX1(),state->getY1(),&x1,&y1); - state->transform(state->getX2(),state->getY2(),&x2,&y2); - Use CropBox, not MediaBox, as page size - */ - - /*x1 = crop_x1; - y1 = crop_y1; - x2 = crop_x2; - y2 = crop_y2;*/ - state->transform(crop_x1,crop_y1,&x1,&y1); - state->transform(crop_x2,crop_y2,&x2,&y2); - - if(x2 Bounding box is (%f,%f)-(%f,%f)", x1,y1,x2,y2); - swfoutput_init(&output, swffilename,(int)x1,(int)y1,(int)x2,(int)y2); - outputstarted = 1; - } - else - swfoutput_newpage(&output); + if(!outputstarted) { + msg(" Bounding box is (%f,%f)-(%f,%f)", x1,y1,x2,y2); + swfoutput_init(&output); + outputstarted = 1; + } + + swfoutput_newpage(&output, pageNum, user_movex, user_movey, (int)x1, (int)y1, (int)x2, (int)y2); } void SWFOutputDev::drawLink(Link *link, Catalog *catalog) { - msg(" drawlink\n"); - double x1, y1, x2, y2, w; - GfxRGB rgb; - swfcoord points[5]; - int x, y; + msg(" drawlink\n"); + double x1, y1, x2, y2, w; + GfxRGB rgb; + swfcoord points[5]; + int x, y; #ifdef XPDF_101 - link->getBorder(&x1, &y1, &x2, &y2, &w); + link->getBorder(&x1, &y1, &x2, &y2, &w); #else - link->getRect(&x1, &y1, &x2, &y2); + link->getRect(&x1, &y1, &x2, &y2); #endif -// if (w > 0) - { rgb.r = 0; rgb.g = 0; rgb.b = 1; @@ -802,121 +1003,124 @@ void SWFOutputDev::drawLink(Link *link, Catalog *catalog) LinkAction*action=link->getAction(); char buf[128]; - char*s = "-?-"; + char*s = 0; char*type = "-?-"; char*url = 0; char*named = 0; int page = -1; switch(action->getKind()) { - case actionGoTo: { - type = "GoTo"; - LinkGoTo *ha=(LinkGoTo *)link->getAction(); - LinkDest *dest=NULL; - if (ha->getDest()==NULL) - dest=catalog->findDest(ha->getNamedDest()); - else dest=ha->getDest(); - if (dest){ - if (dest->isPageRef()){ - Ref pageref=dest->getPageRef(); - page=catalog->findPage(pageref.num,pageref.gen); - } - else page=dest->getPageNum(); - sprintf(buf, "%d", page); - s = buf; - } - } + case actionGoTo: { + type = "GoTo"; + LinkGoTo *ha=(LinkGoTo *)link->getAction(); + LinkDest *dest=NULL; + if (ha->getDest()==NULL) + dest=catalog->findDest(ha->getNamedDest()); + else dest=ha->getDest(); + if (dest){ + if (dest->isPageRef()){ + Ref pageref=dest->getPageRef(); + page=catalog->findPage(pageref.num,pageref.gen); + } + else page=dest->getPageNum(); + sprintf(buf, "%d", page); + s = strdup(buf); + } + } break; - case actionGoToR: { - type = "GoToR"; - LinkGoToR*l = (LinkGoToR*)action; - GString*g = l->getNamedDest(); - if(g) - s = g->getCString(); - } + case actionGoToR: { + type = "GoToR"; + LinkGoToR*l = (LinkGoToR*)action; + GString*g = l->getNamedDest(); + if(g) + s = strdup(g->getCString()); + } break; - case actionNamed: { - type = "Named"; - LinkNamed*l = (LinkNamed*)action; - GString*name = l->getName(); - if(name) { - s = name->lowerCase()->getCString(); - named = name->getCString(); - if(!strchr(s,':')) - { - if(strstr(s, "next") || strstr(s, "forward")) - { - page = currentpage + 1; - } - else if(strstr(s, "prev") || strstr(s, "back")) - { - page = currentpage - 1; - } - else if(strstr(s, "last") || strstr(s, "end")) - { - page = pages[pagepos-1]; //:) - } - else if(strstr(s, "first") || strstr(s, "top")) - { - page = 1; - } - } - } - } + case actionNamed: { + type = "Named"; + LinkNamed*l = (LinkNamed*)action; + GString*name = l->getName(); + if(name) { + s = strdup(name->lowerCase()->getCString()); + named = name->getCString(); + if(!strchr(s,':')) + { + if(strstr(s, "next") || strstr(s, "forward")) + { + page = currentpage + 1; + } + else if(strstr(s, "prev") || strstr(s, "back")) + { + page = currentpage - 1; + } + else if(strstr(s, "last") || strstr(s, "end")) + { + page = pagepos>0?pages[pagepos-1]:0; + } + else if(strstr(s, "first") || strstr(s, "top")) + { + page = 1; + } + } + } + } break; - case actionLaunch: { - type = "Launch"; - LinkLaunch*l = (LinkLaunch*)action; - GString * str = new GString(l->getFileName()); - str->append(l->getParams()); - s = str->getCString(); - } + case actionLaunch: { + type = "Launch"; + LinkLaunch*l = (LinkLaunch*)action; + GString * str = new GString(l->getFileName()); + str->append(l->getParams()); + s = strdup(str->getCString()); + delete str; + } break; - case actionURI: { - type = "URI"; - LinkURI*l = (LinkURI*)action; - GString*g = l->getURI(); - if(g) { - url = g->getCString(); - s = url; - } - } + case actionURI: { + type = "URI"; + LinkURI*l = (LinkURI*)action; + GString*g = l->getURI(); + if(g) { + url = g->getCString(); + s = strdup(url); + } + } break; - case actionUnknown: { - type = "Unknown"; - LinkUnknown*l = (LinkUnknown*)action; - s = ""; - } + case actionUnknown: { + type = "Unknown"; + LinkUnknown*l = (LinkUnknown*)action; + s = strdup(""); + } break; - default: { - msg(" Unknown link type!\n"); - break; - } + default: { + msg(" Unknown link type!\n"); + break; + } } + if(!s) s = strdup("-?-"); + if(!linkinfo && (page || url)) { - msg(" File contains links"); - linkinfo = 1; + msg(" File contains links"); + linkinfo = 1; } if(page>0) { - int t; - for(t=0;t \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page); - } + free(s);s=0; } void SWFOutputDev::saveState(GfxState *state) { @@ -939,8 +1143,6 @@ void SWFOutputDev::restoreState(GfxState *state) { clippos--; } -char type3Warning=0; - char* SWFOutputDev::searchFont(char*name) { int i; @@ -970,7 +1172,7 @@ char* SWFOutputDev::searchFont(char*name) if(!is_standard_font) msg(" Using %s for %s", fonts[i].filename, name); } - return fonts[i].filename; + return strdup(fonts[i].filename); } } return 0; @@ -1059,9 +1261,11 @@ char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font) } #ifdef XPDF_101 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen); + if(!cvt) return 0; cvt->convertToType1(f); #else FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen); + if(!cvt) return 0; cvt->convertToType1(NULL, gTrue, FoFiWrite, f); #endif //cvt->convertToCIDType0("test", f); @@ -1122,42 +1326,54 @@ char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font) return strdup(tmpFileName); } - - -char* substitutetarget[256]; -char* substitutesource[256]; -int substitutepos = 0; - + char* searchForSuitableFont(GfxFont*gfxFont) { char*name = getFontName(gfxFont); char*fontname = 0; char*filename = 0; + + if(!config_use_fontconfig) + return 0; #ifdef HAVE_FONTCONFIG FcPattern *pattern, *match; FcResult result; FcChar8 *v; - // call init ony once static int fcinitcalled = false; + + msg(" searchForSuitableFont(%s)", name); + + // call init ony once if (!fcinitcalled) { + msg(" Initializing FontConfig..."); fcinitcalled = true; - FcInit(); + if(FcInit()) { + msg(" FontConfig Initialization failed. Disabling."); + config_use_fontconfig = 0; + return 0; + } + msg(" ...initialized FontConfig"); } + msg(" FontConfig: Create \"%s\" Family Pattern", name); pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL); if (gfxFont->isItalic()) // check for italic + msg(" FontConfig: Adding Italic Slant"); FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); if (gfxFont->isBold()) // check for bold + msg(" FontConfig: Adding Bold Weight"); FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); + msg(" FontConfig: Try to match..."); // configure and match using the original font name FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); match = FcFontMatch(0, pattern, &result); if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) { + msg(" FontConfig: family=%s", (char*)v); // if we get an exact match if (strcmp((char *)v, name) == 0) { if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) { @@ -1166,6 +1382,7 @@ char* searchForSuitableFont(GfxFont*gfxFont) if(nfn) fontname = strdup(nfn+1); else fontname = filename; } + msg(" FontConfig: Returning \"%s\"", fontname); } else { // initialize patterns FcPatternDestroy(pattern); @@ -1173,22 +1390,28 @@ char* searchForSuitableFont(GfxFont*gfxFont) // now match against serif etc. if (gfxFont->isSerif()) { + msg(" FontConfig: Create Serif Family Pattern"); pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL); } else if (gfxFont->isFixedWidth()) { + msg(" FontConfig: Create Monospace Family Pattern"); pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL); } else { + msg(" FontConfig: Create Sans Family Pattern"); pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL); } // check for italic if (gfxFont->isItalic()) { + msg(" FontConfig: Adding Italic Slant"); int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); } // check for bold if (gfxFont->isBold()) { + msg(" FontConfig: Adding Bold Weight"); int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); } + msg(" FontConfig: Try to match... (2)"); // configure and match using serif etc FcConfigSubstitute (0, pattern, FcMatchPattern); FcDefaultSubstitute (pattern); @@ -1200,6 +1423,7 @@ char* searchForSuitableFont(GfxFont*gfxFont) if(nfn) fontname = strdup(nfn+1); else fontname = filename; } + msg(" FontConfig: Returning \"%s\"", fontname); } } @@ -1227,6 +1451,10 @@ char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname) fontname = "Times-Roman"; } filename = searchFont(fontname); + if(!filename) { + msg(" Couldn't find font %s- did you install the default fonts?"); + return 0; + } if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) { msg(" Too many fonts in file."); @@ -1238,7 +1466,7 @@ char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname) msg(" substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname)); substitutepos ++; } - return filename; + return strdup(filename); } void unlinkfont(char* filename) @@ -1270,8 +1498,9 @@ void unlinkfont(char* filename) } } -void SWFOutputDev::startDoc(XRef *xref) +void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref) { + this->doc = doc; this->xref = xref; } @@ -1325,7 +1554,7 @@ void SWFOutputDev::updateFont(GfxState *state) if(embedded && (gfxFont->getType() == fontType1 || gfxFont->getType() == fontType1C || - //gfxFont->getType() == fontCIDType0C || + (gfxFont->getType() == fontCIDType0C && forceType0Fonts) || gfxFont->getType() == fontTrueType || gfxFont->getType() == fontCIDType2 )) @@ -1359,16 +1588,10 @@ void SWFOutputDev::updateFont(GfxState *state) if(fileName && del) unlinkfont(fileName); + if(fileName) + free(fileName); } -int pic_xids[1024]; -int pic_yids[1024]; -int pic_ids[1024]; -int pic_width[1024]; -int pic_height[1024]; -int picpos = 0; -int pic_id = 0; - #define SQR(x) ((x)*(x)) unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize) @@ -1736,97 +1959,201 @@ static void printInfoDate(Dict *infoDict, char *key, char *fmt) { obj.free(); } -void pdfswf_init(char*filename, char*userPassword) -{ - GString *fileName = new GString(filename); - GString *userPW; - Object info; - - // read config file - globalParams = new GlobalParams(""); - - // open PDF file - if (userPassword && userPassword[0]) { - userPW = new GString(userPassword); - } else { - userPW = NULL; - } - doc = new PDFDoc(fileName, userPW); - if (userPW) { - delete userPW; - } - if (!doc->isOk()) { - exit(1); - } - - // print doc info - doc->getDocInfo(&info); - if (info.isDict() && - (screenloglevel>=LOGLEVEL_NOTICE)) { - printInfoString(info.getDict(), "Title", "Title: %s\n"); - printInfoString(info.getDict(), "Subject", "Subject: %s\n"); - printInfoString(info.getDict(), "Keywords", "Keywords: %s\n"); - printInfoString(info.getDict(), "Author", "Author: %s\n"); - printInfoString(info.getDict(), "Creator", "Creator: %s\n"); - printInfoString(info.getDict(), "Producer", "Producer: %s\n"); - printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n"); - printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n"); - printf("Pages: %d\n", doc->getNumPages()); - printf("Linearized: %s\n", doc->isLinearized() ? "yes" : "no"); - printf("Encrypted: "); - if (doc->isEncrypted()) { - printf("yes (print:%s copy:%s change:%s addNotes:%s)\n", - doc->okToPrint() ? "yes" : "no", - doc->okToCopy() ? "yes" : "no", - doc->okToChange() ? "yes" : "no", - doc->okToAddNotes() ? "yes" : "no"); - } else { - printf("no\n"); - } - } - info.free(); - - numpages = doc->getNumPages(); - if (doc->isEncrypted()) { - if(!doc->okToCopy()) { - printf("PDF disallows copying. Bailing out.\n"); - exit(1); //bail out - } - if(!doc->okToChange() || !doc->okToAddNotes()) - swfoutput_setprotected(); - } - - output = new SWFOutputDev(); - output->startDoc(doc->getXRef()); -} - void pdfswf_setparameter(char*name, char*value) { - if(!strcmp(name, "outputfilename")) { - swffilename = value; - } else if(!strcmp(name, "caplinewidth")) { + msg(" setting parameter %s to \"%s\"", name, value); + if(!strcmp(name, "caplinewidth")) { caplinewidth = atof(value); } else if(!strcmp(name, "zoom")) { zoom = atoi(value); + } else if(!strcmp(name, "forceType0Fonts")) { + forceType0Fonts = atoi(value); + } else if(!strcmp(name, "fontdir")) { + pdfswf_addfontdir(value); + } else if(!strcmp(name, "languagedir")) { + pdfswf_addlanguagedir(value); + } else if(!strcmp(name, "fontconfig")) { + config_use_fontconfig = atoi(value); } else { swfoutput_setparameter(name, value); } } - void pdfswf_addfont(char*filename) { fontfile_t f; memset(&f, 0, sizeof(fontfile_t)); f.filename = filename; - fonts[fontnum++] = f; + if(fontnum < sizeof(fonts)/sizeof(fonts[0])) { + fonts[fontnum++] = f; + } else { + msg(" Too many external fonts. Not adding font file \"%s\".", filename); + } } -void pdfswf_setoutputfilename(char*_filename) { swffilename = _filename; } +static char* dirseparator() +{ +#ifdef WIN32 + return "\\"; +#else + return "/"; +#endif +} -void pdfswf_convertpage(int page) +void pdfswf_addlanguagedir(char*dir) { - if(!pages) - { + if(!globalParams) + globalParams = new GlobalParams(""); + + msg(" Adding %s to language pack directories", dir); + + int l; + FILE*fi = 0; + char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc")); + strcpy(config_file, dir); + strcat(config_file, dirseparator()); + strcat(config_file, "add-to-xpdfrc"); + + fi = fopen(config_file, "rb"); + if(!fi) { + msg(" Could not open %s", config_file); + return; + } + globalParams->parseFile(new GString(config_file), fi); + fclose(fi); +} + +void pdfswf_addfontdir(char*dirname) +{ +#ifdef HAVE_DIRENT_H + msg(" Adding %s to font directories", dirname); + DIR*dir = opendir(dirname); + if(!dir) { + msg(" Couldn't open directory %s\n", dirname); + return; + } + struct dirent*ent; + while(1) { + ent = readdir (dir); + if (!ent) + break; + int l; + char*name = ent->d_name; + char type = 0; + if(!name) continue; + l=strlen(name); + if(l<4) + continue; + if(!strncasecmp(&name[l-4], ".pfa", 4)) + type=1; + if(!strncasecmp(&name[l-4], ".pfb", 4)) + type=3; + if(!strncasecmp(&name[l-4], ".ttf", 4)) + type=2; + if(type) + { + char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2); + strcpy(fontname, dirname); + strcat(fontname, dirseparator()); + strcat(fontname, name); + msg(" Adding %s to fonts", fontname); + pdfswf_addfont(fontname); + } + } + closedir(dir); +#else + msg(" No dirent.h- unable to add font dir %s", dir); +#endif +} + + +typedef struct _pdf_doc_internal +{ + int protect; + PDFDoc*doc; +} pdf_doc_internal_t; +typedef struct _pdf_page_internal +{ +} pdf_page_internal_t; +typedef struct _swf_output_internal +{ + SWFOutputDev*outputDev; +} swf_output_internal_t; + +pdf_doc_t* pdf_init(char*filename, char*userPassword) +{ + pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t)); + memset(pdf_doc, 0, sizeof(pdf_doc_t)); + pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t)); + memset(i, 0, sizeof(pdf_doc_internal_t)); + pdf_doc->internal = i; + + GString *fileName = new GString(filename); + GString *userPW; + Object info; + + // read config file + if(!globalParams) + globalParams = new GlobalParams(""); + + // open PDF file + if (userPassword && userPassword[0]) { + userPW = new GString(userPassword); + } else { + userPW = NULL; + } + i->doc = new PDFDoc(fileName, userPW); + if (userPW) { + delete userPW; + } + if (!i->doc->isOk()) { + return 0; + } + + // print doc info + i->doc->getDocInfo(&info); + if (info.isDict() && + (getScreenLogLevel()>=LOGLEVEL_NOTICE)) { + printInfoString(info.getDict(), "Title", "Title: %s\n"); + printInfoString(info.getDict(), "Subject", "Subject: %s\n"); + printInfoString(info.getDict(), "Keywords", "Keywords: %s\n"); + printInfoString(info.getDict(), "Author", "Author: %s\n"); + printInfoString(info.getDict(), "Creator", "Creator: %s\n"); + printInfoString(info.getDict(), "Producer", "Producer: %s\n"); + printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n"); + printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n"); + printf("Pages: %d\n", i->doc->getNumPages()); + printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no"); + printf("Encrypted: "); + if (i->doc->isEncrypted()) { + printf("yes (print:%s copy:%s change:%s addNotes:%s)\n", + i->doc->okToPrint() ? "yes" : "no", + i->doc->okToCopy() ? "yes" : "no", + i->doc->okToChange() ? "yes" : "no", + i->doc->okToAddNotes() ? "yes" : "no"); + } else { + printf("no\n"); + } + } + info.free(); + + pdf_doc->num_pages = i->doc->getNumPages(); + i->protect = 0; + if (i->doc->isEncrypted()) { + if(!i->doc->okToCopy()) { + printf("PDF disallows copying.\n"); + return 0; + } + if(!i->doc->okToChange() || !i->doc->okToAddNotes()) + i->protect = 1; + } + + return pdf_doc; +} + +void pdfswf_preparepage(int page) +{ + /*FIXME*/ + if(!pages) { pages = (int*)malloc(1024*sizeof(int)); pagebuflen = 1024; } else { @@ -1839,33 +2166,171 @@ void pdfswf_convertpage(int page) pages[pagepos++] = page; } -void pdfswf_performconversion() +class MemCheck { - int t; - for(t=0;tinternal; + + msg(" pdfswf.cc: pdfswf_close()"); + delete i->doc; i->doc=0; + + free(pages); pages = 0; //FIXME + + free(pdf_doc->internal);pdf_doc->internal=0; + free(pdf_doc);pdf_doc=0; +} + +pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page) +{ + pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal; + + if(page < 1 || page > pdf_doc->num_pages) + return 0; + + pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t)); + pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t)); + memset(pi, 0, sizeof(pdf_page_internal_t)); + pdf_page->internal = pi; + + pdf_page->parent = pdf_doc; + pdf_page->nr = page; + return pdf_page; +} + +void pdf_page_destroy(pdf_page_t*pdf_page) +{ + pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal; + free(pdf_page->internal);pdf_page->internal = 0; + free(pdf_page);pdf_page=0; +} + +swf_output_t* swf_output_init() +{ + swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t)); + memset(swf_output, 0, sizeof(swf_output_t)); + swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t)); + memset(i, 0, sizeof(swf_output_internal_t)); + swf_output->internal = i; + + i->outputDev = new SWFOutputDev(); + return swf_output; +} + +void swf_output_setparameter(swf_output_t*swf_output, char*name, char*value) +{ + /* FIXME */ + pdfswf_setparameter(name, value); +} + +void swf_output_pagefeed(swf_output_t*swf) +{ + swf_output_internal_t*i= (swf_output_internal_t*)swf->internal; + i->outputDev->pagefeed(); + i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2); +} + +int swf_output_save(swf_output_t*swf, char*filename) +{ + swf_output_internal_t*i= (swf_output_internal_t*)swf->internal; + int ret = i->outputDev->save(filename); + i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2); + return ret; +} + +void* swf_output_get(swf_output_t*swf) +{ + swf_output_internal_t*i= (swf_output_internal_t*)swf->internal; + void* ret = i->outputDev->getSWF(); + i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2); + return ret; +} + +void swf_output_destroy(swf_output_t*output) +{ + swf_output_internal_t*i = (swf_output_internal_t*)output->internal; + delete i->outputDev; i->outputDev=0; + free(output->internal);output->internal=0; + free(output); +} + +void pdf_page_render2(pdf_page_t*page, swf_output_t*swf) +{ + pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal; + swf_output_internal_t*si = (swf_output_internal_t*)swf->internal; + + if(pi->protect) { + swfoutput_setparameter("protect", "1"); + } + si->outputDev->setXRef(pi->doc, pi->doc->getXRef()); #ifdef XPDF_101 - doc->displayPage((OutputDev*)output, currentpage, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1); + pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1); #else - doc->displayPage((OutputDev*)output, currentpage, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1); + pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1); #endif - } + si->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2); } -int pdfswf_numpages() + +void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2) { - return doc->getNumPages(); + pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal; + swf_output_internal_t*si = (swf_output_internal_t*)output->internal; + + si->outputDev->setMove(x,y); + if((x1|y1|x2|y2)==0) x2++; + si->outputDev->setClip(x1,y1,x2,y2); + + pdf_page_render2(page, output); } -int closed=0; -void pdfswf_close() +void pdf_page_render(pdf_page_t*page, swf_output_t*output) { - msg(" pdfswf.cc: pdfswf_close()"); - delete output; - delete doc; - //freeParams(); - // check for memory leaks - Object::memCheck(stderr); - gMemReport(stderr); + pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal; + swf_output_internal_t*si = (swf_output_internal_t*)output->internal; + + si->outputDev->setMove(0,0); + si->outputDev->setClip(0,0,0,0); + + pdf_page_render2(page, output); } +pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page) +{ + pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal; + pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal; + pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t)); + memset(info, 0, sizeof(pdf_page_info_t)); + + InfoOutputDev*output = new InfoOutputDev; + +#ifdef XPDF_101 + pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1); +#else + pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1); +#endif + + info->xMin = output->x1; + info->yMin = output->y1; + info->xMax = output->x2; + info->yMax = output->y2; + info->number_of_images = output->num_images; + info->number_of_links = output->num_links; + info->number_of_fonts = output->num_fonts; + + delete output; + + return info; +} + +void pdf_page_info_destroy(pdf_page_info_t*info) +{ + free(info); +}