From 191439ab6ffe1cad91825ae84286bf720370f863 Mon Sep 17 00:00:00 2001 From: kramm Date: Sun, 19 Nov 2006 21:32:53 +0000 Subject: [PATCH] moved from ../xpdf/ --- lib/pdf/GFXOutputDev.cc | 2465 +++++++++++++++++++++++++++++++++++++++++++++++ lib/pdf/GFXOutputDev.h | 236 +++++ lib/pdf/Makefile.in | 136 +++ 3 files changed, 2837 insertions(+) create mode 100644 lib/pdf/GFXOutputDev.cc create mode 100644 lib/pdf/GFXOutputDev.h create mode 100644 lib/pdf/Makefile.in diff --git a/lib/pdf/GFXOutputDev.cc b/lib/pdf/GFXOutputDev.cc new file mode 100644 index 0000000..2878d5a --- /dev/null +++ b/lib/pdf/GFXOutputDev.cc @@ -0,0 +1,2465 @@ +/* pdfswf.cc + implements a pdf output device (OutputDev). + + This file is part of swftools. + + Swftools 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 of the License, or + (at your option) any later version. + + Swftools 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 swftools; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include +#include +#include +#include +#include "../../config.h" +#include "../os.h" +#ifdef HAVE_DIRENT_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_FONTCONFIG +#include +#endif +//xpdf header files +#include "config.h" +#include "gfile.h" +#include "GString.h" +#include "gmem.h" +#include "Object.h" +#include "Stream.h" +#include "Array.h" +#include "Dict.h" +#include "XRef.h" +#include "Catalog.h" +#include "Page.h" +#include "PDFDoc.h" +#include "Error.h" +#include "Link.h" +#include "OutputDev.h" +#include "GfxFont.h" +#include "GfxState.h" +#include "CharCodeToUnicode.h" +#include "NameToUnicodeTable.h" +#include "GlobalParams.h" +#include "FoFiType1C.h" +#include "FoFiTrueType.h" +#include "GHash.h" +#include "GFXOutputDev.h" + +//swftools header files +#include "../log.h" +#include "../gfxdevice.h" +#include "../gfxtools.h" +#include "../gfxfont.h" + +#include + +typedef struct _fontfile +{ + char*filename; + int used; +} fontfile_t; + +// for pdfswf_addfont +static fontfile_t fonts[2048]; +static int fontnum = 0; + +/* config */ + +static char* lastfontdir = 0; + +struct mapping { + char*pdffont; + char*filename; +} pdf2t1map[] ={ +{"Times-Roman", "n021003l"}, +{"Times-Italic", "n021023l"}, +{"Times-Bold", "n021004l"}, +{"Times-BoldItalic", "n021024l"}, +{"Helvetica", "n019003l"}, +{"Helvetica-Oblique", "n019023l"}, +{"Helvetica-Bold", "n019004l"}, +{"Helvetica-BoldOblique", "n019024l"}, +{"Courier", "n022003l"}, +{"Courier-Oblique", "n022023l"}, +{"Courier-Bold", "n022004l"}, +{"Courier-BoldOblique", "n022024l"}, +{"Symbol", "s050000l"}, +{"ZapfDingbats", "d050000l"}}; + +GFXOutputState::GFXOutputState() { + this->clipping = 0; + this->textRender = 0; +} + +GBool GFXOutputDev::interpretType3Chars() +{ + return gTrue; +} + +typedef struct _drawnchar +{ + gfxcoord_t x,y; + int charid; + gfxcolor_t color; +} drawnchar_t; + +class CharBuffer +{ + drawnchar_t * chars; + int buf_size; + int num_chars; + +public: + + CharBuffer() + { + buf_size = 32; + chars = (drawnchar_t*)malloc(sizeof(drawnchar_t)*buf_size); + memset(chars, 0, sizeof(drawnchar_t)*buf_size); + num_chars = 0; + } + ~CharBuffer() + { + free(chars);chars = 0; + } + + void grow(int size) + { + if(size>=buf_size) { + buf_size += 32; + chars = (drawnchar_t*)realloc(chars, sizeof(drawnchar_t)*buf_size); + } + } + + void addChar(int charid, gfxcoord_t x, gfxcoord_t y, gfxcolor_t color) + { + grow(num_chars); + chars[num_chars].x = x; + chars[num_chars].y = y; + chars[num_chars].color = color; + chars[num_chars].charid = charid; + } +}; + +static char*getFontID(GfxFont*font); + +GFXOutputDev::GFXOutputDev(parameter_t*p) +{ + this->jpeginfo = 0; + this->textmodeinfo = 0; + this->ttfinfo = 0; + this->linkinfo = 0; + this->pbminfo = 0; + this->type3active = 0; + this->statepos = 0; + this->xref = 0; + this->substitutepos = 0; + this->type3Warning = 0; + this->user_movex = 0; + this->user_movey = 0; + this->clipmovex = 0; + this->clipmovey = 0; + this->user_clipx1 = 0; + this->user_clipy1 = 0; + this->user_clipx2 = 0; + this->user_clipy2 = 0; + this->current_text_stroke = 0; + this->current_text_clip = 0; + this->fontlist = 0; + this->outer_clip_box = 0; + this->pages = 0; + this->pagebuflen = 0; + this->pagepos = 0; + this->transparencyGroup = 0; + + this->forceType0Fonts=1; + this->config_use_fontconfig=1; + + this->parameters = p; + + /* configure device */ + while(p) { + if(!strcmp(p->name,"forceType0Fonts")) { + this->forceType0Fonts = atoi(p->value); + } else if(!strcmp(p->name,"fontconfig")) { + this->config_use_fontconfig = atoi(p->value); + } + p = p->next; + } +}; + +void GFXOutputDev::setDevice(gfxdevice_t*dev) +{ + parameter_t*p = this->parameters; + + /* TODO: get rid of this */ + this->device = dev; + if(this->device) { + while(p) { + this->device->setparameter(this->device, p->name, p->value); + p = p->next; + } + } +} + +void GFXOutputDev::setMove(int x,int y) +{ + this->user_movex = x; + this->user_movey = y; +} + +void GFXOutputDev::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; +} + +static char*getFontID(GfxFont*font) +{ + Ref*ref = font->getID(); + GString*gstr = font->getName(); + char* fname = gstr==0?0:gstr->getCString(); + char buf[128]; + if(fname==0) { + sprintf(buf, "font-%d-%d", ref->num, ref->gen); + } else { + sprintf(buf, "%s-%d-%d", fname, ref->num, ref->gen); + } + return strdup(buf); +} + +static char*getFontName(GfxFont*font) +{ + char*fontid; + GString*gstr = font->getName(); + char* fname = gstr==0?0:gstr->getCString(); + if(fname==0) { + char buf[32]; + Ref*r=font->getID(); + sprintf(buf, "UFONT%d", r->num); + fontid = strdup(buf); + } else { + fontid = strdup(fname); + } + + 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; +} + +static char mybuf[1024]; +static char* gfxstate2str(GfxState *state) +{ + char*bufpos = mybuf; + GfxRGB rgb; + bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ", + state->getCTM()[0], + state->getCTM()[1], + state->getCTM()[2], + state->getCTM()[3], + state->getCTM()[4], + state->getCTM()[5]); + if(state->getX1()!=0.0) + bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1()); + if(state->getY1()!=0.0) + bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1()); + bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2()); + bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2()); + bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth()); + bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight()); + /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ", + state->getFillColor()->c[0], state->getFillColor()->c[1]); + bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ", + state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/ +/* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]", + state->getFillColor()->c[0], state->getFillColor()->c[1], + state->getFillColor()->c[2], state->getFillColor()->c[3], + state->getFillColor()->c[4], state->getFillColor()->c[5], + state->getFillColor()->c[6], state->getFillColor()->c[7]); + bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]", + state->getStrokeColor()->c[0], state->getFillColor()->c[1], + state->getStrokeColor()->c[2], state->getFillColor()->c[3], + state->getStrokeColor()->c[4], state->getFillColor()->c[5], + state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/ + state->getFillRGB(&rgb); + if(rgb.r || rgb.g || rgb.b) + bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b); + state->getStrokeRGB(&rgb); + if(rgb.r || rgb.g || rgb.b) + bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b); + if(state->getFillColorSpace()->getNComps()>1) + bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps()); + if(state->getStrokeColorSpace()->getNComps()>1) + bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps()); + if(state->getFillPattern()) + bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern()); + if(state->getStrokePattern()) + bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern()); + + if(state->getFillOpacity()!=1.0) + bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity()); + if(state->getStrokeOpacity()!=1.0) + bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity()); + + bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth()); + + double * dash; + int length; + double start; + state->getLineDash(&dash, &length, &start); + int t; + if(length) + { + bufpos+=sprintf(bufpos,"DASH%.1f[",start); + for(t=0;tgetFlatness()!=1) + bufpos+=sprintf(bufpos,"F%d ", state->getFlatness()); + if(state->getLineJoin()!=0) + bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin()); + if(state->getLineJoin()!=0) + bufpos+=sprintf(bufpos,"C%d ", state->getLineCap()); + if(state->getLineJoin()!=0) + bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit()); + + if(state->getFont() && getFontID(state->getFont())) + bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont())); + bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize()); + bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2], + state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]); + if(state->getCharSpace()) + bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace()); + if(state->getWordSpace()) + bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace()); + if(state->getHorizScaling()!=1.0) + bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling()); + if(state->getLeading()) + bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading()); + if(state->getRise()) + bufpos+=sprintf(bufpos,"R%.1f ", state->getRise()); + if(state->getRender()) + bufpos+=sprintf(bufpos,"R%d ", state->getRender()); + bufpos+=sprintf(bufpos,"P%08x ", state->getPath()); + bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX()); + bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY()); + if(state->getLineX()) + bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX()); + if(state->getLineY()) + bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY()); + bufpos+=sprintf(bufpos," "); + return mybuf; +} + +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 + */ +static void showFontError(GfxFont*font, int nr) +{ + Ref*r=font->getID(); + int t; + for(t=0;tnum) + break; + if(t < lastdumppos) + return; + if(lastdumpposnum; + if(nr == 0) + msg(" The following font caused problems:"); + else if(nr == 1) + msg(" The following font caused problems (substituting):"); + else if(nr == 2) + msg(" The following Type 3 Font will be rendered as bitmap:"); + dumpFontInfo("", font); +} + +static void dumpFontInfo(char*loglevel, GfxFont*font) +{ + char* id = getFontID(font); + char* name = getFontName(font); + Ref* r=font->getID(); + msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen); + + GString*gstr = font->getTag(); + + msg("%s| Tag: %s\n", loglevel, id); + + if(font->isCIDFont()) msg("%s| is CID font\n", loglevel); + + GfxFontType type=font->getType(); + switch(type) { + case fontUnknownType: + msg("%s| Type: unknown\n",loglevel); + break; + case fontType1: + msg("%s| Type: 1\n",loglevel); + break; + case fontType1C: + msg("%s| Type: 1C\n",loglevel); + break; + case fontType3: + msg("%s| Type: 3\n",loglevel); + break; + case fontTrueType: + msg("%s| Type: TrueType\n",loglevel); + break; + case fontCIDType0: + msg("%s| Type: CIDType0\n",loglevel); + break; + case fontCIDType0C: + msg("%s| Type: CIDType0C\n",loglevel); + break; + case fontCIDType2: + msg("%s| Type: CIDType2\n",loglevel); + break; + } + + Ref embRef; + GBool embedded = font->getEmbeddedFontID(&embRef); + char*embeddedName=0; + if(font->getEmbeddedFontName()) { + embeddedName = font->getEmbeddedFontName()->getCString(); + } + if(embedded) + msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num); + + gstr = font->getExtFontFile(); + if(gstr) + msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString())); + + // Get font descriptor flags. + if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel); + if(font->isSerif()) msg("%s| is serif\n", loglevel); + if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel); + if(font->isItalic()) msg("%s| is italic\n", loglevel); + if(font->isBold()) msg("%s| is bold\n", loglevel); + + free(id); + free(name); +} + +//void GFXOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) {printf("void GFXOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) \n");} +//void GFXOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) {printf("void GFXOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) \n");} + + +void dump_outline(gfxline_t*line) +{ + while(line) { + if(line->type == gfx_moveTo) { + msg(" | moveTo %.2f %.2f", line->x,line->y); + } else if(line->type == gfx_lineTo) { + msg(" | lineTo %.2f %.2f", line->x,line->y); + } else if(line->type == gfx_splineTo) { + msg(" | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y); + } + line = line->next; + } +} + +gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey) +{ + int num = path->getNumSubpaths(); + int s,t; + int cpos = 0; + double lastx=0,lasty=0,posx=0,posy=0; + int needsfix=0; + if(!num) { + msg(" empty path"); + return 0; + } + gfxdrawer_t draw; + gfxdrawer_target_gfxline(&draw); + + for(t = 0; t < num; t++) { + GfxSubpath *subpath = path->getSubpath(t); + int subnum = subpath->getNumPoints(); + double bx=0,by=0,cx=0,cy=0; + + for(s=0;stransform(subpath->getX(s),subpath->getY(s),&x,&y); + x += user_movex; + y += user_movey; + + if(s==0) { + if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) { + draw.lineTo(&draw, lastx, lasty); + } + draw.moveTo(&draw, x,y); + posx = lastx = x; + posy = lasty = y; + cpos = 0; + needsfix = 0; + } else if(subpath->getCurve(s) && cpos==0) { + bx = x; + by = y; + cpos = 1; + } else if(subpath->getCurve(s) && cpos==1) { + cx = x; + cy = y; + cpos = 2; + } else { + posx = x; + posy = y; + if(cpos==0) { + draw.lineTo(&draw, x,y); + } else { + gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y, 0.05); + } + needsfix = 1; + cpos = 0; + } + } + } + /* fix non-closed lines */ + if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) { + draw.lineTo(&draw, lastx, lasty); + } + gfxline_t*result = (gfxline_t*)draw.result(&draw); + return result; +} + +/*---------------------------------------------------------------------------- + * Primitive Graphic routines + *----------------------------------------------------------------------------*/ + +void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line) +{ + int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square + int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel + double miterLimit = state->getMiterLimit(); + double width = state->getTransformedLineWidth(); + + GfxRGB rgb; + double opaq = state->getStrokeOpacity(); + if(type3active) + state->getFillRGB(&rgb); + else + state->getStrokeRGB(&rgb); + gfxcolor_t col; + col.r = colToByte(rgb.r); + col.g = colToByte(rgb.g); + col.b = colToByte(rgb.b); + col.a = (unsigned char)(opaq*255); + + gfx_capType capType = gfx_capRound; + if(lineCap == 0) capType = gfx_capButt; + else if(lineCap == 1) capType = gfx_capRound; + else if(lineCap == 2) capType = gfx_capSquare; + + gfx_joinType joinType = gfx_joinRound; + if(lineJoin == 0) joinType = gfx_joinMiter; + else if(lineJoin == 1) joinType = gfx_joinRound; + else if(lineJoin == 2) joinType = gfx_joinBevel; + + int dashnum = 0; + double dashphase = 0; + double * ldash = 0; + state->getLineDash(&ldash, &dashnum, &dashphase); + + gfxline_t*line2 = 0; + + if(dashnum && ldash) { + float * dash = (float*)malloc(sizeof(float)*(dashnum+1)); + int t; + double cut = 0; + int fixzero = 0; + msg(" %d dashes", dashnum); + msg(" | phase: %f", dashphase); + for(t=0;t | d%-3d: %f", t, ldash[t]); + } + dash[dashnum] = -1; + if(getLogLevel() >= LOGLEVEL_TRACE) { + dump_outline(line); + } + + line2 = gfxtool_dash_line(line, dash, dashphase); + line = line2; + free(dash); + msg(" After dashing:"); + } + + if(getLogLevel() >= LOGLEVEL_TRACE) { + msg(" stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x\n", + width, + lineJoin==0?"miter": (lineJoin==1?"round":"bevel"), + lineCap==0?"butt": (lineJoin==1?"round":"square"), + dashnum, + col.r,col.g,col.b,col.a + ); + dump_outline(line); + } + + //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit); + device->stroke(device, line, width, &col, capType, joinType, miterLimit); + + if(line2) + gfxline_free(line2); +} + +gfxcolor_t getFillColor(GfxState * state) +{ + GfxRGB rgb; + double opaq = state->getFillOpacity(); + state->getFillRGB(&rgb); + gfxcolor_t col; + col.r = colToByte(rgb.r); + col.g = colToByte(rgb.g); + col.b = colToByte(rgb.b); + col.a = (unsigned char)(opaq*255); + return col; +} + +void GFXOutputDev::fillGfxLine(GfxState *state, gfxline_t*line) +{ + gfxcolor_t col = getFillColor(state); + + if(getLogLevel() >= LOGLEVEL_TRACE) { + msg(" fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a); + dump_outline(line); + } + + device->fill(device, line, &col); +} + +void GFXOutputDev::clip(GfxState *state) +{ + GfxPath * path = state->getPath(); + gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey); + clipToGfxLine(state, line); + gfxline_free(line); +} + +void GFXOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line) +{ + if(getLogLevel() >= LOGLEVEL_TRACE) { + msg(" clip\n"); + dump_outline(line); + } + + device->startclip(device, line); + states[statepos].clipping++; +} +void GFXOutputDev::eoClip(GfxState *state) +{ + GfxPath * path = state->getPath(); + gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey); + + if(getLogLevel() >= LOGLEVEL_TRACE) { + msg(" eoclip\n"); + dump_outline(line); + } + + device->startclip(device, line); + states[statepos].clipping++; + gfxline_free(line); +} + +void GFXOutputDev::endframe() +{ + if(outer_clip_box) { + device->endclip(device); + outer_clip_box = 0; + } + + device->endpage(device); +} + +void GFXOutputDev::finish() +{ + if(outer_clip_box) { + if(device) { + device->endclip(device); + } + outer_clip_box = 0; + } +} + +GFXOutputDev::~GFXOutputDev() +{ + finish(); + + if(this->pages) { + free(this->pages); this->pages = 0; + } + + fontlist_t*l = this->fontlist; + while(l) { + fontlist_t*next = l->next; + l->next = 0; + gfxfont_free(l->font); + free(l->filename);l->filename=0; + free(l); + l = next; + } + this->fontlist = 0; +}; +GBool GFXOutputDev::upsideDown() +{ + return gTrue; +}; +GBool GFXOutputDev::useDrawChar() +{ + return gTrue; +} + +char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible", + "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"}; + +#define RENDER_FILL 0 +#define RENDER_STROKE 1 +#define RENDER_FILLSTROKE 2 +#define RENDER_INVISIBLE 3 +#define RENDER_CLIP 4 + +static char tmp_printstr[4096]; +char* makeStringPrintable(char*str) +{ + int len = strlen(str); + int dots = 0; + if(len>=80) { + len = 80; + dots = 1; + } + int t; + for(t=0;t124) { + c = '.'; + } + tmp_printstr[t] = c; + } + if(dots) { + tmp_printstr[len++] = '.'; + tmp_printstr[len++] = '.'; + tmp_printstr[len++] = '.'; + } + tmp_printstr[len] = 0; + return tmp_printstr; +} + + +int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u) +{ + char*uniname = 0; + if(u>0) { + int t; + /* find out char name from unicode index + TODO: should be precomputed + */ + for(t=0;tnum_glyphs;t++) { + if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) { + msg(" Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t); + return t; + } + } + /* if we didn't find the character, maybe + we can find the capitalized version */ + for(t=0;tnum_glyphs;t++) { + if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) { + msg(" Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t); + return t; + } + } + } + + if(uniname) { + int t; + for(t=0;tnum_glyphs;t++) { + if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,uniname)) { + msg(" Char [%d,%s,>%d(%s)<] maps to %d\n", charnr, charname, u, uniname, t); + return t; + } + } + /* if we didn't find the character, maybe + we can find the capitalized version */ + for(t=0;tnum_glyphs;t++) { + if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,uniname)) { + msg(" Char [%d,%s,>>%d(%s)<<] maps to %d\n", charnr, charname, u, uniname, t); + return t; + } + } + } + + /* try to use the unicode id */ + if(u>=0 && umax_unicode && font->unicode2glyph[u]>=0) { + msg(" Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]); + return font->unicode2glyph[u]; + } + + if(charnr>=0 && charnrnum_glyphs) { + msg(" Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr); + return charnr; + } + + return -1; +} + + +void GFXOutputDev::beginString(GfxState *state, GString *s) +{ + int render = state->getRender(); + if(current_text_stroke) { + msg(" Error: Incompatible change of text rendering to %d while inside cliptext", render); + } + + msg(" beginString(%s) render=%d", makeStringPrintable(s->getCString()), render); + double m11,m21,m12,m22; +// msg(" %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString()); + state->getFontTransMat(&m11, &m12, &m21, &m22); + m11 *= state->getHorizScaling(); + m21 *= state->getHorizScaling(); + + this->current_font_matrix.m00 = m11 / 1024.0; + this->current_font_matrix.m01 = m12 / 1024.0; + this->current_font_matrix.m10 = -m21 / 1024.0; + this->current_font_matrix.m11 = -m22 / 1024.0; + this->current_font_matrix.tx = 0; + this->current_font_matrix.ty = 0; + + gfxmatrix_t m = this->current_font_matrix; + + /*if(render != 3 && render != 0) + msg(" Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/ + states[statepos].textRender = render; +} + +void GFXOutputDev::drawChar(GfxState *state, double x, double y, + double dx, double dy, + double originX, double originY, + CharCode c, int nBytes, Unicode *_u, int uLen) +{ + if(createsoftmask) + return; + int render = state->getRender(); + // check for invisible text -- this is used by Acrobat Capture + if (render == 3) { + msg(" Ignoring invisible text: char %d at %f,%f", c, x, y); + return; + } + + if(states[statepos].textRender != render) + msg(" Internal error: drawChar.render!=beginString.render"); + + gfxcolor_t col = getFillColor(state); + + Gushort *CIDToGIDMap = 0; + GfxFont*font = state->getFont(); + + if(font->getType() == fontType3) { + /* type 3 chars are passed as graphics */ + msg(" type3 char at %f/%f", x, y); + return; + } + + Unicode u=0; + char*name=0; + + if(uLen) + u = _u[0]; + + if(font->isCIDFont()) { + GfxCIDFont*cfont = (GfxCIDFont*)font; + + if(font->getType() == fontCIDType2) + CIDToGIDMap = cfont->getCIDToGID(); + } else { + Gfx8BitFont*font8; + font8 = (Gfx8BitFont*)font; + char**enc=font8->getEncoding(); + name = enc[c]; + } + if (CIDToGIDMap) { + msg(" drawChar(%f, %f, c='%c' (%d), GID=%d, u=%d <%d>) CID=%d name=\"%s\" render=%d\n", x, y, (c&127)>=32?c:'?', c, CIDToGIDMap[c], u, uLen, font->isCIDFont(), FIXNULL(name), render); + c = CIDToGIDMap[c]; + } else { + msg(" drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d name=\"%s\" render=%d\n",x,y,(c&127)>=32?c:'?',c,u, uLen, font->isCIDFont(), FIXNULL(name), render); + } + + int charid = -1; + + if(uLen<=1) { + charid = getGfxCharID(current_gfxfont, c, name, u); + } else { + charid = getGfxCharID(current_gfxfont, c, name, -1); + + if(charid < 0) { + /* multiple unicodes- should usually map to a ligature. + if the ligature doesn't exist, we need to draw + the characters one-by-one. */ + int t; + msg(" ligature %d missing in font %s\n", c, current_gfxfont->id); + for(t=0;t Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)", + FIXNULL(name),c, u, FIXNULL((char*)current_gfxfont->id), current_gfxfont->num_glyphs); + return; + } + + gfxmatrix_t m = this->current_font_matrix; + state->transform(x, y, &m.tx, &m.ty); + m.tx += user_movex + clipmovex; + m.ty += user_movey + clipmovey; + + if(render == RENDER_FILL) { + device->drawchar(device, current_gfxfont, charid, &col, &m); + } else { + msg(" Drawing glyph %d as shape", charid); + if(!textmodeinfo) { + msg(" Some texts will be rendered as shape"); + textmodeinfo = 1; + } + gfxline_t*glyph = current_gfxfont->glyphs[charid].line; + gfxline_t*tglyph = gfxline_clone(glyph); + gfxline_transform(tglyph, &m); + if((render&3) != RENDER_INVISIBLE) { + gfxline_t*add = gfxline_clone(tglyph); + current_text_stroke = gfxline_append(current_text_stroke, add); + } + if(render&RENDER_CLIP) { + gfxline_t*add = gfxline_clone(tglyph); + current_text_clip = gfxline_append(current_text_clip, add); + } + gfxline_free(tglyph); + } +} + +void GFXOutputDev::endString(GfxState *state) +{ + int render = state->getRender(); + msg(" endString() render=%d textstroke=%08x", render, current_text_stroke); + if(states[statepos].textRender != render) + msg(" Internal error: drawChar.render!=beginString.render"); + + if(current_text_stroke) { + /* fillstroke and stroke text rendering objects we can process right + now (as there may be texts of other rendering modes in this + text object)- clipping objects have to wait until endTextObject, + however */ + device->setparameter(device, "mark","TXT"); + if((render&3) == RENDER_FILL) { + fillGfxLine(state, current_text_stroke); + gfxline_free(current_text_stroke); + current_text_stroke = 0; + } else if((render&3) == RENDER_FILLSTROKE) { + fillGfxLine(state, current_text_stroke); + strokeGfxline(state, current_text_stroke); + gfxline_free(current_text_stroke); + current_text_stroke = 0; + } else if((render&3) == RENDER_STROKE) { + strokeGfxline(state, current_text_stroke); + gfxline_free(current_text_stroke); + current_text_stroke = 0; + } + device->setparameter(device, "mark",""); + } +} + +void GFXOutputDev::endTextObject(GfxState *state) +{ + int render = state->getRender(); + msg(" endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip); + if(states[statepos].textRender != render) + msg(" Internal error: drawChar.render!=beginString.render"); + + if(current_text_clip) { + device->setparameter(device, "mark","TXT"); + clipToGfxLine(state, current_text_clip); + device->setparameter(device, "mark",""); + gfxline_free(current_text_clip); + current_text_clip = 0; + } +} + +/* the logic seems to be as following: + first, beginType3Char is called, with the charcode and the coordinates. + if this function returns true, it already knew about the char and has now drawn it. + if the function returns false, it's a new char, and type3D1 is called with some parameters- + the all draw operations until endType3Char are part of the char (which in this moment is + at the position first passed to beginType3Char). the char ends with endType3Char. + + The drawing operations between beginType3Char and endType3Char are somewhat different to + the normal ones. For example, the fillcolor equals the stroke color. +*/ + +GBool GFXOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen) +{ + msg(" beginType3Char %d, %08x, %d", code, *u, uLen); + type3active = 1; + /* the character itself is going to be passed using the draw functions */ + return gFalse; /* gTrue= is_in_cache? */ +} + +void GFXOutputDev::type3D0(GfxState *state, double wx, double wy) { + msg(" type3D0 width=%f height=%f", wx, wy); +} +void GFXOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) { + msg(" type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy, + llx,lly,urx,ury); +} + +void GFXOutputDev::endType3Char(GfxState *state) +{ + type3active = 0; + msg(" endType3Char"); +} + +void GFXOutputDev::startFrame(int width, int height) +{ + if(outer_clip_box) { + device->endclip(device); + outer_clip_box = 0; + } + + device->startpage(device, width, height); +} + +void GFXOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2) +{ + this->currentpage = pageNum; + double x1,y1,x2,y2; + int rot = doc->getPageRotate(1); + gfxcolor_t white; + laststate = state; + gfxline_t clippath[5]; + + white.r = white.g = white.b = white.a = 255; + + /* 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); //x1 += user_movex; y1 += user_movey; + state->transform(crop_x2,crop_y2,&x2,&y2); //x2 += user_movex; y2 += user_movey; + + if(x2clipmovex = -(int)x1; + this->clipmovey = -(int)y1; + + /* apply user clip box */ + if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) { + /*if(user_clipx1 > 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; + msg(" Using user clip box %f/%f/%f/%f",x1,y1,x2,y2); + } + + //msg(" Bounding box is (%f,%f)-(%f,%f) [shifted by %d/%d]", x1,y1,x2,y2, user_movex, user_movey); + + msg(" processing PDF page %d (%dx%d:%d:%d) (move:%d:%d)", pageNum, (int)x2-(int)x1,(int)y2-(int)y1, (int)x1, (int)y1, user_movex + clipmovex, user_movey + clipmovey); + if(rot!=0) + msg(" page is rotated %d degrees\n", rot); + + clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1]; + clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2]; + clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3]; + clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4]; + clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0; + device->startclip(device, clippath); outer_clip_box = 1; + device->fill(device, clippath, &white); +} + +void GFXOutputDev::drawLink(Link *link, Catalog *catalog) +{ + double x1, y1, x2, y2, w; + gfxline_t points[5]; + int x, y; + + msg(" drawlink\n"); + + link->getRect(&x1, &y1, &x2, &y2); + cvtUserToDev(x1, y1, &x, &y); + points[0].type = gfx_moveTo; + points[0].x = points[4].x = x + user_movex + clipmovex; + points[0].y = points[4].y = y + user_movey + clipmovey; + points[0].next = &points[1]; + cvtUserToDev(x2, y1, &x, &y); + points[1].type = gfx_lineTo; + points[1].x = x + user_movex + clipmovex; + points[1].y = y + user_movey + clipmovey; + points[1].next = &points[2]; + cvtUserToDev(x2, y2, &x, &y); + points[2].type = gfx_lineTo; + points[2].x = x + user_movex + clipmovex; + points[2].y = y + user_movey + clipmovey; + points[2].next = &points[3]; + cvtUserToDev(x1, y2, &x, &y); + points[3].type = gfx_lineTo; + points[3].x = x + user_movex + clipmovex; + points[3].y = y + user_movey + clipmovey; + points[3].next = &points[4]; + cvtUserToDev(x1, y1, &x, &y); + points[4].type = gfx_lineTo; + points[4].x = x + user_movex + clipmovex; + points[4].y = y + user_movey + clipmovey; + points[4].next = 0; + + msg(" drawlink %.2f/%.2f %.2f/%.2f %.2f/%.2f %.2f/%.2f\n", + points[0].x, points[0].y, + points[1].x, points[1].y, + points[2].x, points[2].y, + points[3].x, points[3].y); + + LinkAction*action=link->getAction(); + char buf[128]; + char*s = 0; + char*type = "-?-"; + char*named = 0; + int page = -1; + msg(" drawlink action=%d\n", action->getKind()); + 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 = strdup(buf); + } + } + break; + case actionGoToR: { + type = "GoToR"; + LinkGoToR*l = (LinkGoToR*)action; + GString*g = l->getFileName(); + if(g) + s = strdup(g->getCString()); + if(!s) { + /* if the GoToR link has no filename, then + try to find a refernce in the *local* + file */ + 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 = 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")) + { + if(pages && pagepos>0) + page = pages[pagepos-1]; + } + 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()); + GString * params = l->getParams(); + if(params) + str->append(params); + s = strdup(str->getCString()); + delete str; + } + break; + case actionURI: { + char*url = 0; + 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 = strdup(""); + } + break; + default: { + msg(" Unknown link type!\n"); + break; + } + } + + if(!s) s = strdup("-?-"); + + msg(" drawlink s=%s\n", s); + + if(!linkinfo && (page || s)) + { + msg(" File contains links"); + linkinfo = 1; + } + + if(page>0) + { + int t; + int lpage = -1; + for(t=1;t<=pagepos;t++) { + if(pages[t]==page) { + lpage = t; + break; + } + } + if(lpage<0) { + lpage = page; + } + char buf[80]; + sprintf(buf, "page%d", lpage); + device->drawlink(device, points, buf); + } + else if(s) + { + device->drawlink(device, points, s); + } + + msg(" \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page); + free(s);s=0; +} + +void GFXOutputDev::saveState(GfxState *state) { + msg(" saveState\n"); + updateAll(state); + if(statepos>=64) { + msg(" Too many nested states in pdf."); + return; + } + statepos ++; + states[statepos].clipping = 0; //? shouldn't this be the current value? + states[statepos].textRender = states[statepos-1].textRender; +}; + +void GFXOutputDev::restoreState(GfxState *state) { + msg(" restoreState\n"); + updateAll(state); + while(states[statepos].clipping) { + device->endclip(device); + states[statepos].clipping--; + } + statepos--; +} + +char* GFXOutputDev::searchFont(char*name) +{ + int i; + char*filename=0; + int is_standard_font = 0; + + msg(" SearchFont(%s)", name); + + /* see if it is a pdf standard font */ + for(i=0;i Using %s for %s", fonts[i].filename, name); + } + return strdup(fonts[i].filename); + } + } + return 0; +} + +void GFXOutputDev::updateLineWidth(GfxState *state) +{ + double width = state->getTransformedLineWidth(); + //swfoutput_setlinewidth(&device, width); +} + +void GFXOutputDev::updateLineCap(GfxState *state) +{ + int c = state->getLineCap(); +} + +void GFXOutputDev::updateLineJoin(GfxState *state) +{ + int j = state->getLineJoin(); +} + +void GFXOutputDev::updateFillColor(GfxState *state) +{ + GfxRGB rgb; + double opaq = state->getFillOpacity(); + state->getFillRGB(&rgb); +} +void GFXOutputDev::updateFillOpacity(GfxState *state) +{ + GfxRGB rgb; + double opaq = state->getFillOpacity(); + state->getFillRGB(&rgb); +} + +void GFXOutputDev::updateStrokeColor(GfxState *state) +{ + GfxRGB rgb; + double opaq = state->getStrokeOpacity(); + state->getStrokeRGB(&rgb); +} + +void FoFiWrite(void *stream, char *data, int len) +{ + int ret = fwrite(data, len, 1, (FILE*)stream); +} + +char*GFXOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font) +{ + char*tmpFileName = NULL; + FILE *f; + int c; + char *fontBuf; + int fontLen; + Ref embRef; + Object refObj, strObj; + char namebuf[512]; + tmpFileName = mktmpname(namebuf); + int ret; + + ret = font->getEmbeddedFontID(&embRef); + if(!ret) { + msg(" Didn't get embedded font id"); + /* not embedded- the caller should now search the font + directories for this font */ + return 0; + } + + f = fopen(tmpFileName, "wb"); + if (!f) { + msg(" Couldn't create temporary Type 1 font file"); + return 0; + } + + /*if(font->isCIDFont()) { + GfxCIDFont* cidFont = (GfxCIDFont *)font; + GString c = cidFont->getCollection(); + msg(" Collection: %s", c.getCString()); + }*/ + + //if (font->getType() == fontType1C) { + if (0) { //font->getType() == fontType1C) { + if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) { + fclose(f); + msg(" Couldn't read embedded font file"); + return 0; + } + FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen); + if(!cvt) return 0; + cvt->convertToType1(NULL, gTrue, FoFiWrite, f); + //cvt->convertToCIDType0("test", f); + //cvt->convertToType0("test", f); + delete cvt; + gfree(fontBuf); + } else if(font->getType() == fontTrueType) { + msg(" writing font using TrueTypeFontFile::writeTTF"); + if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) { + fclose(f); + msg(" Couldn't read embedded font file"); + return 0; + } + FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen); + cvt->writeTTF(FoFiWrite, f); + delete cvt; + gfree(fontBuf); + } else { + font->getEmbeddedFontID(&embRef); + refObj.initRef(embRef.num, embRef.gen); + refObj.fetch(ref, &strObj); + refObj.free(); + strObj.streamReset(); + int f4[4]; + char f4c[4]; + int t; + for(t=0;t<4;t++) { + f4[t] = strObj.streamGetChar(); + f4c[t] = (char)f4[t]; + if(f4[t] == EOF) + break; + } + if(t==4) { + if(!strncmp(f4c, "true", 4)) { + /* some weird TTF fonts don't start with 0,1,0,0 but with "true". + Change this on the fly */ + f4[0] = f4[2] = f4[3] = 0; + f4[1] = 1; + } + fputc(f4[0], f); + fputc(f4[1], f); + fputc(f4[2], f); + fputc(f4[3], f); + + while ((c = strObj.streamGetChar()) != EOF) { + fputc(c, f); + } + } + strObj.streamClose(); + strObj.free(); + } + fclose(f); + + return strdup(tmpFileName); +} + +char* GFXOutputDev::searchForSuitableFont(GfxFont*gfxFont) +{ + char*name = getFontName(gfxFont); + char*fontname = 0; + char*filename = 0; + + if(!this->config_use_fontconfig) + return 0; + +#ifdef HAVE_FONTCONFIG + FcPattern *pattern, *match; + FcResult result; + FcChar8 *v; + + static int fcinitcalled = false; + + msg(" searchForSuitableFont(%s)", name); + + // call init ony once + if (!fcinitcalled) { + msg(" Initializing FontConfig..."); + fcinitcalled = true; + 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) { + filename = strdup((char*)v); // mem leak + char *nfn = strrchr(filename, '/'); + if(nfn) fontname = strdup(nfn+1); + else fontname = filename; + } + msg(" FontConfig: Returning \"%s\"", fontname); + } else { + // initialize patterns + FcPatternDestroy(pattern); + FcPatternDestroy(match); + + // 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); + match = FcFontMatch (0, pattern, &result); + + if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) { + filename = strdup((char*)v); // mem leak + char *nfn = strrchr(filename, '/'); + if(nfn) fontname = strdup(nfn+1); + else fontname = filename; + } + msg(" FontConfig: Returning \"%s\"", fontname); + } + } + + //printf("FONTCONFIG: pattern"); + //FcPatternPrint(pattern); + //printf("FONTCONFIG: match"); + //FcPatternPrint(match); + + FcPatternDestroy(pattern); + FcPatternDestroy(match); + + pdfswf_addfont(filename); + return fontname; +#else + return 0; +#endif +} + +char* GFXOutputDev::substituteFont(GfxFont*gfxFont, char* oldname) +{ + char*fontname = 0, *filename = 0; + msg(" substituteFont(%s)", oldname); + + if(!(fontname = searchForSuitableFont(gfxFont))) { + fontname = "Times-Roman"; + } + filename = searchFont(fontname); + if(!filename) { + msg(" Couldn't find font %s- did you install the default fonts?", fontname); + return 0; + } + + if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) { + msg(" Too many fonts in file."); + exit(1); + } + if(oldname) { + substitutesource[substitutepos] = strdup(oldname); //mem leak + substitutetarget[substitutepos] = fontname; + msg(" substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname)); + substitutepos ++; + } + return strdup(filename); //mem leak +} + +void unlinkfont(char* filename) +{ + int l; + if(!filename) + return; + l=strlen(filename); + unlink(filename); + if(!strncmp(&filename[l-4],".afm",4)) { + memcpy(&filename[l-4],".pfb",4); + unlink(filename); + memcpy(&filename[l-4],".pfa",4); + unlink(filename); + memcpy(&filename[l-4],".afm",4); + return; + } else + if(!strncmp(&filename[l-4],".pfa",4)) { + memcpy(&filename[l-4],".afm",4); + unlink(filename); + memcpy(&filename[l-4],".pfa",4); + return; + } else + if(!strncmp(&filename[l-4],".pfb",4)) { + memcpy(&filename[l-4],".afm",4); + unlink(filename); + memcpy(&filename[l-4],".pfb",4); + return; + } +} + +void GFXOutputDev::setXRef(PDFDoc*doc, XRef *xref) +{ + this->doc = doc; + this->xref = xref; +} + +int GFXOutputDev::setGfxFont(char*id, char*name, char*filename, double maxSize) +{ + gfxfont_t*font = 0; + fontlist_t*last=0,*l = this->fontlist; + + if(!id) + msg(" Internal Error: FontID is null"); + + /* TODO: should this be part of the state? */ + while(l) { + last = l; + if(!strcmp(l->font->id, id)) { + current_gfxfont = l->font; + font = l->font; + device->addfont(device, current_gfxfont); + return 1; + } + l = l->next; + } + if(!filename) return 0; + + /* A font size of e.g. 9 means the font will be scaled down by + 1024 and scaled up by 9. So to have a maximum error of 1/20px, + we have to divide 0.05 by (fontsize/1024) + */ + double quality = (1024 * 0.05) / maxSize; + + msg(" Loading %s...", filename); + font = gfxfont_load(id, filename, quality); + if(!font) { + msg(" Couldn't load Font %s (%s)", filename, id); + return 0; + } + msg(" Font %s (%s) loaded successfully", filename, id); + + l = new fontlist_t; + l->font = font; + l->filename = strdup(filename); + l->next = 0; + current_gfxfont = l->font; + if(last) { + last->next = l; + } else { + this->fontlist = l; + } + device->addfont(device, current_gfxfont); + return 1; +} + +void GFXOutputDev::updateFont(GfxState *state) +{ + GfxFont*gfxFont = state->getFont(); + + if (!gfxFont) { + return; + } + + char * fontid = getFontID(gfxFont); + char * fontname = getFontName(gfxFont); + + double maxSize = 1.0; + + if(this->info) { + maxSize = this->info->getMaximumFontSize(fontid); + } + + int t; + /* first, look if we substituted this font before- + this way, we don't initialize the T1 Fonts + too often */ + for(t=0;t updateFont(%s) [cached]", fontid); + return; + }*/ + + // look for Type 3 font + if (gfxFont->getType() == fontType3) { + if(!type3Warning) { + type3Warning = gTrue; + showFontError(gfxFont, 2); + } + free(fontid); + free(fontname); + return; + } + + /* now either load the font, or find a substitution */ + + Ref embRef; + GBool embedded = gfxFont->getEmbeddedFontID(&embRef); + + char*fileName = 0; + int del = 0; + if(embedded && + (gfxFont->getType() == fontType1 || + gfxFont->getType() == fontType1C || + (gfxFont->getType() == fontCIDType0C && forceType0Fonts) || + gfxFont->getType() == fontTrueType || + gfxFont->getType() == fontCIDType2 + )) + { + fileName = writeEmbeddedFontToFile(xref, gfxFont); + if(!fileName) showFontError(gfxFont,0); + else del = 1; + } else { + fileName = searchFont(fontname); + if(!fileName) showFontError(gfxFont,0); + } + if(!fileName) { + char * fontname = getFontName(gfxFont); + msg(" Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) "); + + if(lastfontdir) + msg(" Try putting a TTF version of that font (named \"%s.ttf\") into %s", fontname, lastfontdir); + else + msg(" Try specifying one or more font directories"); + + fileName = substituteFont(gfxFont, fontid); + if(!fileName) + exit(1); + if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/}; + msg(" Font is now %s (%s)", fontid, fileName); + } + + if(!fileName) { + msg(" Couldn't set font %s\n", fontid); + free(fontid); + free(fontname); + return; + } + + msg(" updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize); + dumpFontInfo("", gfxFont); + + //swfoutput_setfont(&device, fontid, fileName); + + if(!setGfxFont(fontid, fontname, 0, 0)) { + setGfxFont(fontid, fontname, fileName, maxSize); + } + + if(fileName && del) + unlinkfont(fileName); + + if(fileName) + free(fileName); + free(fontid); + free(fontname); + + msg(" |"); +} + +#define SQR(x) ((x)*(x)) + +unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize) +{ + if((newwidth<2 || newheight<2) || + (width<=newwidth || height<=newheight)) + return 0; + unsigned char*newdata; + int x,y; + newdata= (unsigned char*)malloc(newwidth*newheight); + int t; + double fx = (double)(width)/newwidth; + double fy = (double)(height)/newheight; + double px = 0; + int blocksize = (int)(8192/(fx*fy)); + int r = 8192*256/palettesize; + for(x=0;xsetparameter(dev, "next_bitmap_is_jpeg", "1"); + + dev->fillbitmap(dev, &p1, &img, &m, 0); +} + +void drawimagejpeg(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey, + double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4) +{ + drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG); +} + +void drawimagelossless(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey, + double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4) +{ + drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS); +} + + +void GFXOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, + int width, int height, GfxImageColorMap*colorMap, GBool invert, + GBool inlineImg, int mask, int*maskColors, + Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GfxImageColorMap*maskColorMap) +{ + double x1,y1,x2,y2,x3,y3,x4,y4; + ImageStream *imgStr; + Guchar pixBuf[4]; + GfxRGB rgb; + int ncomps = 1; + int bits = 1; + unsigned char* maskbitmap = 0; + + if(colorMap) { + ncomps = colorMap->getNumPixelComps(); + bits = colorMap->getBits(); + } + + if(maskStr) { + int x,y; + unsigned char buf[8]; + maskbitmap = (unsigned char*)malloc(maskHeight*maskWidth); + if(maskColorMap) { + ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, maskColorMap->getNumPixelComps(), maskColorMap->getBits()); + imgMaskStr->reset(); + unsigned char pal[256]; + int n = 1 << colorMap->getBits(); + int t; + for(t=0;tgetGray(pixBuf, &gray); + pal[t] = colToByte(gray); + } + for (y = 0; y < maskHeight; y++) { + for (x = 0; x < maskWidth; x++) { + imgMaskStr->getPixel(buf); + maskbitmap[y*maskWidth+x] = pal[buf[0]]; + } + } + delete imgMaskStr; + } else { + ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, 1, 1); + imgMaskStr->reset(); + for (y = 0; y < maskHeight; y++) { + for (x = 0; x < maskWidth; x++) { + imgMaskStr->getPixel(buf); + buf[0]^=maskInvert; + maskbitmap[y*maskWidth+x] = (buf[0]^1)*255; + } + } + delete imgMaskStr; + } + maskStr->close(); + } + + imgStr = new ImageStream(str, width, ncomps,bits); + imgStr->reset(); + + if(!width || !height || (height<=1 && width<=1)) + { + msg(" Ignoring %d by %d image", width, height); + unsigned char buf[8]; + int x,y; + for (y = 0; y < height; ++y) + for (x = 0; x < width; ++x) { + imgStr->getPixel(buf); + } + delete imgStr; + if(maskbitmap) + free(maskbitmap); + return; + } + + state->transform(0, 1, &x1, &y1); x1 += user_movex + clipmovex; y1 += user_movey + clipmovey; + state->transform(0, 0, &x2, &y2); x2 += user_movex + clipmovex; y2 += user_movey + clipmovey; + state->transform(1, 0, &x3, &y3); x3 += user_movex + clipmovex; y3 += user_movey + clipmovey; + state->transform(1, 1, &x4, &y4); x4 += user_movex + clipmovex; y4 += user_movey + clipmovey; + + + if(!pbminfo && !(str->getKind()==strDCT)) { + if(!type3active) { + msg(" file contains pbm pictures %s",mask?"(masked)":""); + pbminfo = 1; + } + if(mask) + msg(" drawing %d by %d masked picture\n", width, height); + } + if(!jpeginfo && (str->getKind()==strDCT)) { + msg(" file contains jpeg pictures"); + jpeginfo = 1; + } + + if(mask) { + int i,j; + unsigned char buf[8]; + int x,y; + unsigned char*pic = new unsigned char[width*height]; + gfxcolor_t pal[256]; + GfxRGB rgb; + state->getFillRGB(&rgb); + + memset(pal,255,sizeof(pal)); + pal[0].r = (int)(colToByte(rgb.r)); pal[1].r = 0; + pal[0].g = (int)(colToByte(rgb.g)); pal[1].g = 0; + pal[0].b = (int)(colToByte(rgb.b)); pal[1].b = 0; + pal[0].a = 255; pal[1].a = 0; + + int numpalette = 2; + int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3)); + int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2)); + for (y = 0; y < height; ++y) + for (x = 0; x < width; ++x) + { + imgStr->getPixel(buf); + if(invert) + buf[0]=1-buf[0]; + pic[width*y+x] = buf[0]; + } + + /* the size of the drawn image is added to the identifier + as the same image may require different bitmaps if displayed + at different sizes (due to antialiasing): */ + int t,found = -1; + if(type3active) { + unsigned char*pic2 = 0; + numpalette = 16; + + pic2 = antialize(pic,width,height,realwidth,realheight,numpalette); + + if(!pic2) { + delete pic; + delete imgStr; + return; + } + + width = realwidth; + height = realheight; + free(pic); + pic = pic2; + + /* make a black/white palette */ + + float r = 255/(numpalette-1); + int t; + for(t=0;tgetNumPixelComps()!=1 || str->getKind()==strDCT) { + gfxcolor_t*pic=new gfxcolor_t[width*height]; + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + imgStr->getPixel(pixBuf); + colorMap->getRGB(pixBuf, &rgb); + pic[width*y+x].r = (unsigned char)(colToByte(rgb.r)); + pic[width*y+x].g = (unsigned char)(colToByte(rgb.g)); + pic[width*y+x].b = (unsigned char)(colToByte(rgb.b)); + pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5); + if(maskbitmap) { + pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)]; + } + } + } + if(str->getKind()==strDCT) + drawimagejpeg(device, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4); + else + drawimagelossless(device, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4); + delete pic; + delete imgStr; + if(maskbitmap) free(maskbitmap); + return; + } else { + gfxcolor_t*pic=new gfxcolor_t[width*height]; + gfxcolor_t pal[256]; + int n = 1 << colorMap->getBits(); + int t; + for(t=0;t<256;t++) { + pixBuf[0] = t; + colorMap->getRGB(pixBuf, &rgb); + + {/*if(maskColors && *maskColors==t) { + msg(" Color %d is transparent", t); + if (imgData->maskColors) { + *alpha = 0; + for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) { + if (pix[i] < imgData->maskColors[2*i] || + pix[i] > imgData->maskColors[2*i+1]) { + *alpha = 1; + break; + } + } + } else { + *alpha = 1; + } + if(!*alpha) { + pal[t].r = 0; + pal[t].g = 0; + pal[t].b = 0; + pal[t].a = 0; + } + } else {*/ + pal[t].r = (unsigned char)(colToByte(rgb.r)); + pal[t].g = (unsigned char)(colToByte(rgb.g)); + pal[t].b = (unsigned char)(colToByte(rgb.b)); + pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5); + } + } + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + imgStr->getPixel(pixBuf); + pic[width*y+x] = pal[pixBuf[0]]; + if(maskbitmap) { + pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)]; + } + } + } + drawimagelossless(device, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4); + + delete pic; + delete imgStr; + if(maskbitmap) free(maskbitmap); + return; + } +} + +void GFXOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, + int width, int height, GBool invert, + GBool inlineImg) +{ + if(createsoftmask) + return; + msg(" drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg); + drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0, 0,0,0,0, 0); +} + +void GFXOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, + int width, int height, GfxImageColorMap *colorMap, + int *maskColors, GBool inlineImg) +{ + if(createsoftmask) + return; + msg(" drawImage %dx%d, %s, %s, inline=%d", width, height, + colorMap?"colorMap":"no colorMap", + maskColors?"maskColors":"no maskColors", + inlineImg); + if(colorMap) + msg(" colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(), + colorMap->getBits(),colorMap->getColorSpace()->getMode()); + drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors, 0,0,0,0, 0); +} + +void GFXOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, int maskWidth, int maskHeight, + GBool maskInvert) +{ + if(createsoftmask) + return; + msg(" drawMaskedImage %dx%d, %s, %dx%d mask", width, height, + colorMap?"colorMap":"no colorMap", + maskWidth, maskHeight); + if(colorMap) + msg(" colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(), + colorMap->getBits(),colorMap->getColorSpace()->getMode()); + drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, maskInvert, 0); +} + +void GFXOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap *maskColorMap) +{ + if(createsoftmask) + return; + msg(" drawSoftMaskedImage %dx%d, %s, %dx%d mask", width, height, + colorMap?"colorMap":"no colorMap", + maskWidth, maskHeight); + if(colorMap) + msg(" colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(), + colorMap->getBits(),colorMap->getColorSpace()->getMode()); + drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, 0, maskColorMap); +} + +void GFXOutputDev::stroke(GfxState *state) +{ + if(createsoftmask) + return; + + GfxPath * path = state->getPath(); + gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex + clipmovex, user_movey + clipmovey); + strokeGfxline(state, line); + gfxline_free(line); +} + +void GFXOutputDev::fill(GfxState *state) +{ + GfxPath * path = state->getPath(); + gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey); + fillGfxLine(state, line); + gfxline_free(line); +} + +void GFXOutputDev::eoFill(GfxState *state) +{ + GfxPath * path = state->getPath(); + gfxcolor_t col = getFillColor(state); + + gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey); + + if(getLogLevel() >= LOGLEVEL_TRACE) { + msg(" eofill\n"); + dump_outline(line); + } + + device->fill(device, line, &col); + gfxline_free(line); +} + + +static char* dirseparator() +{ +#ifdef WIN32 + return "\\"; +#else + return "/"; +#endif +} + +void addGlobalFont(char*filename) +{ + fontfile_t f; + memset(&f, 0, sizeof(fontfile_t)); + f.filename = filename; + if(fontnum < sizeof(fonts)/sizeof(fonts[0])) { + msg(" Adding font \"%s\".", filename); + fonts[fontnum++] = f; + } else { + msg(" Too many external fonts. Not adding font file \"%s\".", filename); + } +} + +void addGlobalLanguageDir(char*dir) +{ + 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") + 1); + 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 addGlobalFontDir(char*dirname) +{ +#ifdef HAVE_DIRENT_H + msg(" Adding %s to font directories", dirname); + lastfontdir = strdup(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); + addGlobalFont(fontname); + } + } + closedir(dir); +#else + msg(" No dirent.h- unable to add font dir %s", dir); +#endif +} + +void GFXOutputDev::preparePage(int pdfpage, int outputpage) +{ + if(pdfpage < 0) + return; + + if(!this->pages) { + this->pagebuflen = 1024; + this->pages = (int*)malloc(this->pagebuflen*sizeof(int)); + memset(this->pages, -1, this->pagebuflen*sizeof(int)); + } else { + while(pdfpage >= this->pagebuflen) + { + int oldlen = this->pagebuflen; + this->pagebuflen+=1024; + this->pages = (int*)realloc(this->pages, this->pagebuflen*sizeof(int)); + memset(&this->pages[oldlen], -1, (this->pagebuflen-oldlen)*sizeof(int)); + } + } + this->pages[pdfpage] = outputpage; + if(pdfpage>this->pagepos) + this->pagepos = pdfpage; +} + +void GFXOutputDev::beginTransparencyGroup(GfxState *state, double *bbox, + GfxColorSpace *blendingColorSpace, + GBool isolated, GBool knockout, + GBool forSoftMask) +{ + char*colormodename = GfxColorSpace::getColorSpaceModeName(blendingColorSpace->getMode()); + msg(" beginTransparencyGroup %f/%f/%f/%f %s isolated=%d knockout=%d forsoftmask=%d", bbox[0],bbox[1],bbox[2],bbox[3], colormodename, isolated, knockout, forSoftMask); + createsoftmask = forSoftMask; + transparencyGroup = !forSoftMask; + + if(transparencyGroup) { + state->setFillOpacity(0.0); + clip(state); + } +} + +void GFXOutputDev::endTransparencyGroup(GfxState *state) +{ + msg(" endTransparencyGroup"); + createsoftmask = 0; + transparencyGroup = 0; +} + +void GFXOutputDev::paintTransparencyGroup(GfxState *state, double *bbox) +{ + msg(" paintTransparencyGroup"); + createsoftmask = 0; +} + +void GFXOutputDev::setSoftMask(GfxState *state, double *bbox, GBool alpha, Function *transferFunc, GfxColor *rgb) +{ + msg(" setSoftMask %f/%f/%f/%f alpha=%d backdrop=%02x%02x%02x", + bbox[0], bbox[1], bbox[2], bbox[3], alpha, colToByte(rgb->c[0]), colToByte(rgb->c[1]), colToByte(rgb->c[2])); +} + +void GFXOutputDev::clearSoftMask(GfxState *state) +{ + msg(" clearSoftMask"); +} + +/*class MemCheck +{ + public: ~MemCheck() + { + delete globalParams;globalParams=0; + Object::memCheck(stderr); + gMemReport(stderr); + } +} myMemCheck;*/ + diff --git a/lib/pdf/GFXOutputDev.h b/lib/pdf/GFXOutputDev.h new file mode 100644 index 0000000..227e82a --- /dev/null +++ b/lib/pdf/GFXOutputDev.h @@ -0,0 +1,236 @@ +#ifndef __gfxoutputdev_h__ +#define __gfxoutputdev_h__ + +#include "../gfxdevice.h" +#include "../gfxsource.h" + +#include "InfoOutputDev.h" +#include "PDFDoc.h" + +typedef struct _fontlist +{ + char*filename; + gfxfont_t*font; + _fontlist*next; +} fontlist_t; + +class GFXOutputState { + public: + int clipping; + int textRender; + GFXOutputState(); +}; + +typedef struct _parameter +{ + char*name; + char*value; + struct _parameter*next; +} parameter_t; + +void addGlobalFont(char*filename); +void addGlobalLanguageDir(char*dir); +void addGlobalFontDir(char*dirname); + +class GFXOutputDev: public OutputDev { +public: + gfxdevice_t* device; + + // Constructor. + GFXOutputDev(parameter_t*p); + void setDevice(gfxdevice_t*dev); + + // Destructor. + virtual ~GFXOutputDev() ; + + void setMove(int x,int y); + void setClip(int x1,int y1,int x2,int y2); + + void setInfo(InfoOutputDev*info) {this->info = info;} + + // Start a page. + void startFrame(int width, int height); + + virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ; + + void endframe(); + + //----- get info about output device + + // Does this device use upside-down coordinates? + // (Upside-down means (0,0) is the top left corner of the page.) + virtual GBool upsideDown(); + + // Does this device use drawChar() or drawString()? + virtual GBool useDrawChar(); + + virtual GBool interpretType3Chars(); + + //virtual GBool useShadedFills() { return gTrue; } + + //----- initialization and control + + void setXRef(PDFDoc*doc, XRef *xref); + + //----- link borders + virtual void drawLink(Link *link, Catalog *catalog) ; + + //----- save/restore graphics state + virtual void saveState(GfxState *state) ; + virtual void restoreState(GfxState *state) ; + + //----- update graphics state + + virtual void updateFont(GfxState *state); + virtual void updateFillColor(GfxState *state); + virtual void updateStrokeColor(GfxState *state); + virtual void updateLineWidth(GfxState *state); + virtual void updateLineJoin(GfxState *state); + virtual void updateLineCap(GfxState *state); + virtual void updateFillOpacity(GfxState *state); + + + virtual void updateAll(GfxState *state) + { + updateFont(state); + updateFillColor(state); + updateStrokeColor(state); + updateLineWidth(state); + updateLineJoin(state); + updateLineCap(state); + }; + + //----- path painting + virtual void stroke(GfxState *state) ; + virtual void fill(GfxState *state) ; + virtual void eoFill(GfxState *state) ; + + //----- path clipping + virtual void clip(GfxState *state) ; + virtual void eoClip(GfxState *state) ; + + //----- text drawing + virtual void beginString(GfxState *state, GString *s) ; + virtual void endString(GfxState *state) ; + virtual void endTextObject(GfxState *state); + virtual void drawChar(GfxState *state, double x, double y, + double dx, double dy, + double originX, double originY, + CharCode code, int nBytes, Unicode *u, int uLen); + + //----- image drawing + virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, + int width, int height, GBool invert, + GBool inlineImg); + virtual void drawImage(GfxState *state, Object *ref, Stream *str, + int width, int height, GfxImageColorMap *colorMap, + int *maskColors, GBool inlineImg); + virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, int maskWidth, int maskHeight, + GBool maskInvert); + virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap *maskColorMap); + + //----- transparency groups and soft masks (xpdf > ~ 3.01.16) + virtual void beginTransparencyGroup(GfxState *state, double *bbox, + GfxColorSpace *blendingColorSpace, + GBool isolated, GBool knockout, + GBool forSoftMask); + virtual void endTransparencyGroup(GfxState *state); + virtual void paintTransparencyGroup(GfxState *state, double *bbox); + virtual void setSoftMask(GfxState *state, double *bbox, GBool alpha, Function *transferFunc, GfxColor *backdropColor); + virtual void clearSoftMask(GfxState *state); + + + //----- type 3 chars + virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen); + virtual void endType3Char(GfxState *state); + + virtual void type3D0(GfxState *state, double wx, double wy); + virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury); + + void preparePage(int pdfpage, int outputpage); + + char* searchForSuitableFont(GfxFont*gfxFont); + + void finish(); + + private: + void drawGeneralImage(GfxState *state, Object *ref, Stream *str, + int width, int height, GfxImageColorMap*colorMap, GBool invert, + GBool inlineImg, int mask, int *maskColors, + Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GfxImageColorMap*maskColorMap); + int setGfxFont(char*id, char*name, char*filename, double quality); + void strokeGfxline(GfxState *state, gfxline_t*line); + void clipToGfxLine(GfxState *state, gfxline_t*line); + void fillGfxLine(GfxState *state, gfxline_t*line); + + char outer_clip_box; //whether the page clip box is still on + + InfoOutputDev*info; + GFXOutputState states[64]; + int statepos; + + int currentpage; + + PDFDoc*doc; + XRef*xref; + + char* searchFont(char*name); + char* substituteFont(GfxFont*gfxFont, char*oldname); + char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font); + int t1id; + int textmodeinfo; // did we write "Text will be rendered as polygon" yet? + int jpeginfo; // did we write "File contains jpegs" yet? + 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; + + char type3Warning; + + char* substitutetarget[256]; + char* substitutesource[256]; + int substitutepos; + + /* upper left corner of clipping rectangle (cropbox)- needs to be + added to all drawing coordinates to give the impression that all + pages start at (0,0)*/ + int clipmovex,clipmovey; + + int user_movex,user_movey; + int user_clipx1,user_clipx2,user_clipy1,user_clipy2; + + gfxline_t* current_text_stroke; + gfxline_t* current_text_clip; + char* current_font_id; + gfxfont_t* current_gfxfont; + gfxmatrix_t current_font_matrix; + + fontlist_t* fontlist; + + int*pages; + int pagebuflen; + int pagepos; + + /* config */ + int forceType0Fonts; + int config_use_fontconfig; + + int transparencyGroup; + int createsoftmask; + + parameter_t*parameters; +}; + +#endif //__gfxoutputdev_h__ diff --git a/lib/pdf/Makefile.in b/lib/pdf/Makefile.in new file mode 100644 index 0000000..fea30b7 --- /dev/null +++ b/lib/pdf/Makefile.in @@ -0,0 +1,136 @@ +# Generated automatically from Makefile.in by configure. +top_builddir = ../.. +srcdir = . +top_srcdir = ../.. +include ../../Makefile.common + +all: ../libpdf$(A) pdf2swf + +libpdf_objects = GFXOutputDev.$(O) InfoOutputDev.$(O) pdf.$(O) + +xpdf_objects = xpdf/GHash.$(O) xpdf/GList.$(O) xpdf/GString.$(O) xpdf/gmem.$(O) xpdf/gfile.$(O) \ + xpdf/FoFiTrueType.$(O) xpdf/FoFiType1.$(O) xpdf/FoFiType1C.$(O) xpdf/FoFiBase.$(O) xpdf/FoFiEncodings.$(O) \ + xpdf/OutputDev.$(O) xpdf/PDFDoc.$(O) xpdf/Error.$(O) xpdf/Stream.$(O) xpdf/Object.$(O) \ + xpdf/Decrypt.$(O) xpdf/Array.$(O) xpdf/XRef.$(O) xpdf/Dict.$(O) xpdf/Parser.$(O) \ + xpdf/Lexer.$(O) xpdf/Outline.$(O) xpdf/PDFDocEncoding.$(O) xpdf/Catalog.$(O) \ + xpdf/Link.$(O) xpdf/GlobalParams.$(O) xpdf/JBIG2Stream.$(O) xpdf/Page.$(O) xpdf/JPXStream.$(O) \ + xpdf/JArithmeticDecoder.$(O) xpdf/Gfx.$(O) xpdf/GfxFont.$(O) xpdf/CMap.$(O) xpdf/CharCodeToUnicode.$(O) \ + xpdf/PSTokenizer.$(O) xpdf/FontEncodingTables.$(O) xpdf/BuiltinFont.$(O) xpdf/BuiltinFontTables.$(O) \ + xpdf/GfxState.$(O) xpdf/Function.$(O) xpdf/Annot.$(O) xpdf/NameToCharCode.$(O) xpdf/UnicodeMap.$(O) \ + xpdf/SecurityHandler.$(O) + +cmyk.$(O): cmyk.cc + $(CC) -I ./ -I xpdf cmyk.cc -o $@ +GFXOutputDev.$(O): GFXOutputDev.cc GFXOutputDev.h + $(CC) -I ./ -I xpdf GFXOutputDev.cc -o $@ +InfoOutputDev.$(O): InfoOutputDev.cc InfoOutputDev.h + $(CC) -I ./ -I xpdf InfoOutputDev.cc -o $@ +pdf.$(O): pdf.cc + $(CC) -I ./ -I xpdf pdf.cc -o $@ + +xpdf/UnicodeMap.$(O): xpdf/UnicodeMap.cc + $(CC) -I ./ -I xpdf xpdf/UnicodeMap.cc -o $@ +xpdf/NameToCharCode.$(O): xpdf/NameToCharCode.cc + $(CC) -I ./ -I xpdf xpdf/NameToCharCode.cc -o $@ +xpdf/Annot.$(O): xpdf/Annot.cc + $(CC) -I ./ -I xpdf xpdf/Annot.cc -o $@ +xpdf/Function.$(O): xpdf/Function.cc + $(CC) -I ./ -I xpdf xpdf/Function.cc -o $@ +xpdf/BuiltinFontTables.$(O): xpdf/BuiltinFontTables.cc + $(CC) -I ./ -I xpdf xpdf/BuiltinFontTables.cc -o $@ +xpdf/BuiltinFont.$(O): xpdf/BuiltinFont.cc + $(CC) -I ./ -I xpdf xpdf/BuiltinFont.cc -o $@ +xpdf/FontEncodingTables.$(O): xpdf/FontEncodingTables.cc + $(CC) -I ./ -I xpdf xpdf/FontEncodingTables.cc -o $@ +xpdf/PSTokenizer.$(O): xpdf/PSTokenizer.cc + $(CC) -I ./ -I xpdf xpdf/PSTokenizer.cc -o $@ +xpdf/CharCodeToUnicode.$(O): xpdf/CharCodeToUnicode.cc + $(CC) -I ./ -I xpdf xpdf/CharCodeToUnicode.cc -o $@ +xpdf/CMap.$(O): xpdf/CMap.cc + $(CC) -I ./ -I xpdf xpdf/CMap.cc -o $@ +xpdf/GfxFont.$(O): xpdf/GfxFont.cc + $(CC) -I ./ -I xpdf xpdf/GfxFont.cc -o $@ +xpdf/Gfx.$(O): xpdf/Gfx.cc + $(CC) -I ./ -I xpdf xpdf/Gfx.cc -o $@ +xpdf/GfxState.$(O): xpdf/GfxState.cc + $(CC) -I ./ -I xpdf xpdf/GfxState.cc -o $@ +xpdf/JArithmeticDecoder.$(O): xpdf/JArithmeticDecoder.cc + $(CC) -I ./ -I xpdf xpdf/JArithmeticDecoder.cc -o $@ +xpdf/JPXStream.$(O): xpdf/JPXStream.cc + $(CC) -I ./ -I xpdf xpdf/JPXStream.cc -o $@ +xpdf/GlobalParams.$(O): xpdf/GlobalParams.cc xpdf/GlobalParams.h + $(CC) -I ./ -I xpdf xpdf/GlobalParams.cc -o $@ +xpdf/JBIG2Stream.$(O): xpdf/JBIG2Stream.cc + $(CC) -I ./ -I xpdf xpdf/JBIG2Stream.cc -o $@ +xpdf/Page.$(O): xpdf/Page.cc + $(CC) -I ./ -I xpdf xpdf/Page.cc -o $@ +xpdf/Link.$(O): xpdf/Link.cc + $(CC) -I ./ -I xpdf xpdf/Link.cc -o $@ +xpdf/Catalog.$(O): xpdf/Catalog.cc + $(CC) -I ./ -I xpdf xpdf/Catalog.cc -o $@ +xpdf/PDFDocEncoding.$(O): xpdf/PDFDocEncoding.cc + $(CC) -I ./ -I xpdf xpdf/PDFDocEncoding.cc -o $@ +xpdf/Outline.$(O): xpdf/Outline.cc + $(CC) -I ./ -I xpdf xpdf/Outline.cc -o $@ +xpdf/Lexer.$(O): xpdf/Lexer.cc + $(CC) -I ./ -I xpdf xpdf/Lexer.cc -o $@ +xpdf/Parser.$(O): xpdf/Parser.cc + $(CC) -I ./ -I xpdf xpdf/Parser.cc -o $@ +xpdf/XRef.$(O): xpdf/XRef.cc + $(CC) -I ./ -I xpdf xpdf/XRef.cc -o $@ +xpdf/Array.$(O): xpdf/Array.cc + $(CC) -I ./ -I xpdf xpdf/Array.cc -o $@ +xpdf/Dict.$(O): xpdf/Dict.cc + $(CC) -I ./ -I xpdf xpdf/Dict.cc -o $@ +xpdf/Decrypt.$(O): xpdf/Decrypt.cc + $(CC) -I ./ -I xpdf xpdf/Decrypt.cc -o $@ +xpdf/Object.$(O): xpdf/Object.cc + $(CC) -I ./ -I xpdf xpdf/Object.cc -o $@ +xpdf/Error.$(O): xpdf/Error.cc aconf.h + $(CC) -I ./ -I xpdf xpdf/Error.cc -o $@ +xpdf/Stream.$(O): xpdf/Stream.cc + $(CC) -I ./ -I xpdf xpdf/Stream.cc -o $@ +xpdf/PDFDoc.$(O): xpdf/PDFDoc.cc + $(CC) -I ./ -I xpdf xpdf/PDFDoc.cc -o $@ +xpdf/SecurityHandler.$(O): xpdf/SecurityHandler.cc xpdf/SecurityHandler.h + $(CC) -I ./ -I xpdf xpdf/SecurityHandler.cc -o $@ +xpdf/OutputDev.$(O): xpdf/OutputDev.cc xpdf/GfxState.h xpdf/Stream.h xpdf/Object.h xpdf/OutputDev.h xpdf/gtypes.h xpdf/CharTypes.h + $(CC) -I ./ -I xpdf xpdf/OutputDev.cc -o $@ +xpdf/FoFiBase.$(O): xpdf/FoFiBase.cc + $(CC) -I ./ -I xpdf xpdf/FoFiBase.cc -o $@ +xpdf/FoFiTrueType.$(O): xpdf/FoFiTrueType.cc xpdf/FoFiBase.h + $(CC) -I ./ -I xpdf xpdf/FoFiTrueType.cc -o $@ +xpdf/FoFiEncodings.$(O): xpdf/FoFiEncodings.cc xpdf/FoFiEncodings.h + $(CC) -I ./ -I xpdf xpdf/FoFiEncodings.cc -o $@ +xpdf/FoFiType1C.$(O): xpdf/FoFiType1C.cc xpdf/FoFiBase.h + $(CC) -I ./ -I xpdf xpdf/FoFiType1C.cc -o $@ +xpdf/FoFiType1.$(O): xpdf/FoFiType1.cc xpdf/FoFiBase.h + $(CC) -I ./ -I xpdf xpdf/FoFiType1.cc -o $@ +xpdf/GList.$(O): xpdf/GList.cc + $(CC) -I ./ -I xpdf xpdf/GList.cc -o $@ +xpdf/GString.$(O): xpdf/GString.cc + $(CC) -I ./ -I xpdf xpdf/GString.cc -o $@ +xpdf/GHash.$(O): xpdf/GHash.cc + $(CC) -I ./ -I xpdf xpdf/GHash.cc -o $@ +xpdf/gfile.$(O): xpdf/gfile.cc + $(CC) -I ./ -I xpdf xpdf/gfile.cc -o $@ +xpdf/gmem.$(O): xpdf/gmem.c + $(C) -I ./ -I xpdf xpdf/gmem.c -o $@ + +../libpdf$(A): $(libpdf_objects) $(xpdf_objects) + $(AR) r ../libpdf$(A) $(libpdf_objects) $(xpdf_objects) + $(RANLIB) ../libpdf$(A) + +pdftoppm$(E): $(xpdf_objects) xpdf/Splash*.cc + $(LL) $(CPPFLAGS) -DXPDFEXE -g -I xpdf -I . xpdf/pdftoppm.cc $(xpdf_objects) xpdf/Splash*.cc xpdf/parseargs.c -o pdftoppm$(E) $(LIBS) -lt1 +pdftotext$(E): $(xpdf_objects) + $(LL) $(CPPFLAGS) -DXPDFEXE -g -I xpdf -I . xpdf/pdftotext.cc $(xpdf_objects) xpdf/TextOutput*.cc xpdf/UnicodeType*.cc xpdf/parseargs.c -o pdftotext$(E) $(LIBS) -lt1 +pdf2swf$(E): $(xpdf_objects) $(libpdf_objects) ../../src/pdf2swf.c + $(LL) $(CPPFLAGS) ../../src/pdf2swf.c $(libpdf_objects) $(xpdf_objects) ../devices/swf.$(O) ../devices/arts.$(O) ../librfxswf$(A) ../art/libart.a ../os.$(O) ../gfxtools.$(O) ../gfxfont.$(O) -o pdf2swf$(E) $(LIBS) + +install: +uninstall: + +clean: + rm -f xpdf/*.o xpdf/*.obj *.o pdf2swf pdftoppm pdftotext pdf2swf.exe pdftoppm.exe pdftotext.exe *.obj *.lo *.a *.lib *.la gmon.out + -- 1.7.10.4