2 implements a pdf output device (OutputDev).
4 This file is part of swftools.
6 Swftools is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 Swftools is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with swftools; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
25 #include "../config.h"
29 #ifdef HAVE_SYS_STAT_H
32 #ifdef HAVE_FONTCONFIG
33 #include <fontconfig.h>
49 #include "OutputDev.h"
52 #include "CharCodeToUnicode.h"
53 #include "NameToUnicodeTable.h"
54 #include "GlobalParams.h"
59 #include "FoFiType1C.h"
60 #include "FoFiTrueType.h"
63 #include "SWFOutputDev.h"
65 //swftools header files
66 #include "swfoutput.h"
67 #include "../lib/log.h"
68 #include "../lib/gfxdevice.h"
69 #include "../lib/gfxtools.h"
70 #include "../lib/gfxfont.h"
74 typedef struct _fontfile
80 typedef struct _parameter
84 struct _parameter*next;
87 static parameter_t* device_config = 0;
88 static parameter_t* device_config_next = 0;
91 static fontfile_t fonts[2048];
92 static int fontnum = 0;
94 static int config_use_fontconfig = 1;
97 // TODO: move into pdf_doc_t
99 static int pagebuflen = 0;
100 static int pagepos = 0;
103 static double caplinewidth = 3.0;
104 static double zoom = 72; /* xpdf: 86 */
105 static int forceType0Fonts = 1;
107 static void printInfoString(Dict *infoDict, char *key, char *fmt);
108 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
114 {"Times-Roman", "n021003l"},
115 {"Times-Italic", "n021023l"},
116 {"Times-Bold", "n021004l"},
117 {"Times-BoldItalic", "n021024l"},
118 {"Helvetica", "n019003l"},
119 {"Helvetica-Oblique", "n019023l"},
120 {"Helvetica-Bold", "n019004l"},
121 {"Helvetica-BoldOblique", "n019024l"},
122 {"Courier", "n022003l"},
123 {"Courier-Oblique", "n022023l"},
124 {"Courier-Bold", "n022004l"},
125 {"Courier-BoldOblique", "n022024l"},
126 {"Symbol", "s050000l"},
127 {"ZapfDingbats", "d050000l"}};
129 class SWFOutputState {
135 this->textRender = 0;
139 typedef struct _fontlist
149 class SWFOutputDev: public OutputDev {
157 virtual ~SWFOutputDev() ;
159 void setMove(int x,int y);
160 void setClip(int x1,int y1,int x2,int y2);
162 void setInfo(InfoOutputDev*info) {this->info = info;}
164 int save(char*filename);
167 void startFrame(int width, int height);
169 virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
174 //----- get info about output device
176 // Does this device use upside-down coordinates?
177 // (Upside-down means (0,0) is the top left corner of the page.)
178 virtual GBool upsideDown();
180 // Does this device use drawChar() or drawString()?
181 virtual GBool useDrawChar();
183 // Can this device draw gradients?
184 virtual GBool useGradients();
186 virtual GBool interpretType3Chars() {return gTrue;}
188 //----- initialization and control
190 void setXRef(PDFDoc*doc, XRef *xref);
193 virtual void drawLink(Link *link, Catalog *catalog) ;
195 //----- save/restore graphics state
196 virtual void saveState(GfxState *state) ;
197 virtual void restoreState(GfxState *state) ;
199 //----- update graphics state
201 virtual void updateFont(GfxState *state);
202 virtual void updateFillColor(GfxState *state);
203 virtual void updateStrokeColor(GfxState *state);
204 virtual void updateLineWidth(GfxState *state);
205 virtual void updateLineJoin(GfxState *state);
206 virtual void updateLineCap(GfxState *state);
208 virtual void updateAll(GfxState *state)
211 updateFillColor(state);
212 updateStrokeColor(state);
213 updateLineWidth(state);
214 updateLineJoin(state);
215 updateLineCap(state);
218 //----- path painting
219 virtual void stroke(GfxState *state) ;
220 virtual void fill(GfxState *state) ;
221 virtual void eoFill(GfxState *state) ;
223 //----- path clipping
224 virtual void clip(GfxState *state) ;
225 virtual void eoClip(GfxState *state) ;
228 virtual void beginString(GfxState *state, GString *s) ;
229 virtual void endString(GfxState *state) ;
230 virtual void endTextObject(GfxState *state);
231 virtual void drawChar(GfxState *state, double x, double y,
232 double dx, double dy,
233 double originX, double originY,
234 CharCode code, Unicode *u, int uLen);
236 //----- image drawing
237 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
238 int width, int height, GBool invert,
240 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
241 int width, int height, GfxImageColorMap *colorMap,
242 int *maskColors, GBool inlineImg);
244 virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
245 virtual void endType3Char(GfxState *state);
247 virtual void type3D0(GfxState *state, double wx, double wy);
248 virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
251 void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
252 int width, int height, GfxImageColorMap*colorMap, GBool invert,
253 GBool inlineImg, int mask, int *maskColors);
254 int SWFOutputDev::setGfxFont(char*id, char*filename, double quality);
255 void strokeGfxline(GfxState *state, gfxline_t*line);
256 void clipToGfxLine(GfxState *state, gfxline_t*line);
257 void fillGfxLine(GfxState *state, gfxline_t*line);
261 gfxresult_t*result; //filled when complete
263 char outer_clip_box; //whether the page clip box is still on
266 SWFOutputState states[64];
274 char* searchFont(char*name);
275 char* substituteFont(GfxFont*gfxFont, char*oldname);
276 char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
278 int textmodeinfo; // did we write "Text will be rendered as polygon" yet?
279 int jpeginfo; // did we write "File contains jpegs" yet?
280 int pbminfo; // did we write "File contains jpegs" yet?
281 int linkinfo; // did we write "File contains links" yet?
282 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
283 int gradientinfo; // did we write "File contains Gradients yet?
285 int type3active; // are we between beginType3()/endType3()?
291 char* substitutetarget[256];
292 char* substitutesource[256];
295 int user_movex,user_movey;
296 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
298 gfxline_t* current_text_stroke;
299 gfxline_t* current_text_clip;
300 char* current_font_id;
301 gfxfont_t* current_gfxfont;
302 gfxmatrix_t current_font_matrix;
304 fontlist_t* fontlist;
307 static char*getFontID(GfxFont*font);
315 class InfoOutputDev: public OutputDev
318 FontInfo* currentfont;
330 id2font = new GHash();
332 virtual ~InfoOutputDev()
336 virtual GBool upsideDown() {return gTrue;}
337 virtual GBool useDrawChar() {return gTrue;}
338 virtual GBool useGradients() {return gTrue;}
339 virtual GBool interpretType3Chars() {return gTrue;}
340 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
343 state->transform(crop_x1,crop_y1,&x1,&y1);
344 state->transform(crop_x2,crop_y2,&x2,&y2);
345 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
346 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
352 virtual void drawLink(Link *link, Catalog *catalog)
356 virtual double getMaximumFontSize(char*id)
358 FontInfo*info = (FontInfo*)id2font->lookup(id);
360 msg("<error> Unknown font id: %s", id);
363 return info->max_size;
366 virtual void updateFont(GfxState *state)
368 GfxFont*font = state->getFont();
371 char*id = getFontID(font);
373 FontInfo*info = (FontInfo*)id2font->lookup(id);
375 GString* idStr = new GString(id);
379 id2font->add(idStr, (void*)info);
385 virtual void drawChar(GfxState *state, double x, double y,
386 double dx, double dy,
387 double originX, double originY,
388 CharCode code, Unicode *u, int uLen)
390 int render = state->getRender();
393 double m11,m21,m12,m22;
394 state->getFontTransMat(&m11, &m12, &m21, &m22);
395 m11 *= state->getHorizScaling();
396 m21 *= state->getHorizScaling();
397 double lenx = sqrt(m11*m11 + m12*m12);
398 double leny = sqrt(m21*m21 + m22*m22);
399 double len = lenx>leny?lenx:leny;
400 if(currentfont && currentfont->max_size < len) {
401 currentfont->max_size = len;
404 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
405 int width, int height, GBool invert,
410 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
411 int width, int height, GfxImageColorMap *colorMap,
412 int *maskColors, GBool inlineImg)
418 SWFOutputDev::SWFOutputDev()
436 current_text_stroke = 0;
437 current_text_clip = 0;
441 output = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
442 gfxdevice_swf_init(output);
443 /* configure device */
444 parameter_t*p = device_config;
446 output->setparameter(output, p->name, p->value);
451 void SWFOutputDev::setMove(int x,int y)
453 this->user_movex = x;
454 this->user_movey = y;
457 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
459 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
460 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
462 this->user_clipx1 = x1;
463 this->user_clipy1 = y1;
464 this->user_clipx2 = x2;
465 this->user_clipy2 = y2;
468 static char*getFontID(GfxFont*font)
470 GString*gstr = font->getName();
471 char* fontname = gstr==0?0:gstr->getCString();
475 sprintf(buf, "UFONT%d", r->num);
478 return strdup(fontname);
481 static char*getFontName(GfxFont*font)
483 char*fontid = getFontID(font);
485 char* plus = strchr(fontid, '+');
486 if(plus && plus < &fontid[strlen(fontid)-1]) {
487 fontname = strdup(plus+1);
489 fontname = strdup(fontid);
495 static char mybuf[1024];
496 static char* gfxstate2str(GfxState *state)
500 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
507 if(state->getX1()!=0.0)
508 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
509 if(state->getY1()!=0.0)
510 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
511 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
512 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
513 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
514 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
515 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
516 state->getFillColor()->c[0], state->getFillColor()->c[1]);
517 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
518 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
519 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
520 state->getFillColor()->c[0], state->getFillColor()->c[1],
521 state->getFillColor()->c[2], state->getFillColor()->c[3],
522 state->getFillColor()->c[4], state->getFillColor()->c[5],
523 state->getFillColor()->c[6], state->getFillColor()->c[7]);
524 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
525 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
526 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
527 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
528 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
529 state->getFillRGB(&rgb);
530 if(rgb.r || rgb.g || rgb.b)
531 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
532 state->getStrokeRGB(&rgb);
533 if(rgb.r || rgb.g || rgb.b)
534 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
535 if(state->getFillColorSpace()->getNComps()>1)
536 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
537 if(state->getStrokeColorSpace()->getNComps()>1)
538 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
539 if(state->getFillPattern())
540 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
541 if(state->getStrokePattern())
542 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
544 if(state->getFillOpacity()!=1.0)
545 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
546 if(state->getStrokeOpacity()!=1.0)
547 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
549 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
554 state->getLineDash(&dash, &length, &start);
558 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
559 for(t=0;t<length;t++) {
560 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
562 bufpos+=sprintf(bufpos,"]");
565 if(state->getFlatness()!=1)
566 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
567 if(state->getLineJoin()!=0)
568 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
569 if(state->getLineJoin()!=0)
570 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
571 if(state->getLineJoin()!=0)
572 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
574 if(state->getFont() && getFontID(state->getFont()))
575 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
576 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
577 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
578 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
579 if(state->getCharSpace())
580 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
581 if(state->getWordSpace())
582 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
583 if(state->getHorizScaling()!=1.0)
584 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
585 if(state->getLeading())
586 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
588 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
589 if(state->getRender())
590 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
591 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
592 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
593 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
594 if(state->getLineX())
595 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
596 if(state->getLineY())
597 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
598 bufpos+=sprintf(bufpos," ");
602 static void dumpFontInfo(char*loglevel, GfxFont*font);
603 static int lastdumps[1024];
604 static int lastdumppos = 0;
609 static void showFontError(GfxFont*font, int nr)
613 for(t=0;t<lastdumppos;t++)
614 if(lastdumps[t] == r->num)
618 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
619 lastdumps[lastdumppos++] = r->num;
621 msg("<warning> The following font caused problems:");
623 msg("<warning> The following font caused problems (substituting):");
625 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
626 dumpFontInfo("<warning>", font);
629 static void dumpFontInfo(char*loglevel, GfxFont*font)
631 char* id = getFontID(font);
632 char* name = getFontName(font);
633 Ref* r=font->getID();
634 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
636 GString*gstr = font->getTag();
638 msg("%s| Tag: %s\n", loglevel, id);
640 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
642 GfxFontType type=font->getType();
644 case fontUnknownType:
645 msg("%s| Type: unknown\n",loglevel);
648 msg("%s| Type: 1\n",loglevel);
651 msg("%s| Type: 1C\n",loglevel);
654 msg("%s| Type: 3\n",loglevel);
657 msg("%s| Type: TrueType\n",loglevel);
660 msg("%s| Type: CIDType0\n",loglevel);
663 msg("%s| Type: CIDType0C\n",loglevel);
666 msg("%s| Type: CIDType2\n",loglevel);
671 GBool embedded = font->getEmbeddedFontID(&embRef);
673 if(font->getEmbeddedFontName()) {
674 embeddedName = font->getEmbeddedFontName()->getCString();
677 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
679 gstr = font->getExtFontFile();
681 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
683 // Get font descriptor flags.
684 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
685 if(font->isSerif()) msg("%s| is serif\n", loglevel);
686 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
687 if(font->isItalic()) msg("%s| is italic\n", loglevel);
688 if(font->isBold()) msg("%s| is bold\n", loglevel);
694 //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");}
695 //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");}
698 void dump_outline(gfxline_t*line)
701 if(line->type == gfx_moveTo) {
702 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
703 } else if(line->type == gfx_lineTo) {
704 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
705 } else if(line->type == gfx_splineTo) {
706 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
712 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey)
714 int num = path->getNumSubpaths();
717 double lastx=0,lasty=0,posx=0,posy=0;
720 msg("<warning> empty path");
724 gfxdrawer_target_gfxline(&draw);
726 for(t = 0; t < num; t++) {
727 GfxSubpath *subpath = path->getSubpath(t);
728 int subnum = subpath->getNumPoints();
729 double bx=0,by=0,cx=0,cy=0;
731 for(s=0;s<subnum;s++) {
734 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
739 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
740 draw.lineTo(&draw, lastx, lasty);
742 draw.moveTo(&draw, x,y);
747 } else if(subpath->getCurve(s) && cpos==0) {
751 } else if(subpath->getCurve(s) && cpos==1) {
759 draw.lineTo(&draw, x,y);
761 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y, 0.05);
768 /* fix non-closed lines */
769 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
770 draw.lineTo(&draw, lastx, lasty);
772 gfxline_t*result = (gfxline_t*)draw.result(&draw);
776 /*----------------------------------------------------------------------------
777 * Primitive Graphic routines
778 *----------------------------------------------------------------------------*/
780 void SWFOutputDev::stroke(GfxState *state)
782 GfxPath * path = state->getPath();
783 gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex, user_movey);
784 strokeGfxline(state, line);
788 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
790 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
791 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
792 double miterLimit = state->getMiterLimit();
793 double width = state->getTransformedLineWidth();
796 double opaq = state->getStrokeOpacity();
798 state->getFillRGB(&rgb);
800 state->getStrokeRGB(&rgb);
802 col.r = (unsigned char)(rgb.r*255);
803 col.g = (unsigned char)(rgb.g*255);
804 col.b = (unsigned char)(rgb.b*255);
805 col.a = (unsigned char)(opaq*255);
807 gfx_capType capType = gfx_capRound;
808 if(lineCap == 0) capType = gfx_capButt;
809 else if(lineCap == 1) capType = gfx_capRound;
810 else if(lineCap == 2) capType = gfx_capSquare;
812 gfx_joinType joinType = gfx_joinRound;
813 if(lineJoin == 0) joinType = gfx_joinMiter;
814 else if(lineJoin == 1) joinType = gfx_joinRound;
815 else if(lineJoin == 2) joinType = gfx_joinBevel;
818 double dashphase = 0;
820 state->getLineDash(&ldash, &dashnum, &dashphase);
824 if(dashnum && ldash) {
825 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
829 msg("<trace> %d dashes", dashnum);
830 msg("<trace> | phase: %f", dashphase);
831 for(t=0;t<dashnum;t++) {
833 msg("<trace> | d%-3d: %f", t, ldash[t]);
836 if(getLogLevel() >= LOGLEVEL_TRACE) {
840 line2 = gfxtool_dash_line(line, dash, dashphase);
843 msg("<trace> After dashing:");
846 if(getLogLevel() >= LOGLEVEL_TRACE) {
848 state->getStrokeGray(&gray);
849 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n",
851 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
852 lineCap==0?"butt": (lineJoin==1?"round":"square"),
854 col.r,col.g,col.b,col.a,
860 //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
861 output->stroke(output, line, width, &col, capType, joinType, miterLimit);
867 gfxcolor_t getFillColor(GfxState * state)
870 double opaq = state->getFillOpacity();
871 state->getFillRGB(&rgb);
873 col.r = (unsigned char)(rgb.r*255);
874 col.g = (unsigned char)(rgb.g*255);
875 col.b = (unsigned char)(rgb.b*255);
876 col.a = (unsigned char)(opaq*255);
880 void SWFOutputDev::fillGfxLine(GfxState *state, gfxline_t*line)
882 gfxcolor_t col = getFillColor(state);
884 if(getLogLevel() >= LOGLEVEL_TRACE) {
885 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
888 output->fill(output, line, &col);
890 void SWFOutputDev::fill(GfxState *state)
892 GfxPath * path = state->getPath();
893 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
894 fillGfxLine(state, line);
897 void SWFOutputDev::eoFill(GfxState *state)
899 GfxPath * path = state->getPath();
900 gfxcolor_t col = getFillColor(state);
902 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
904 if(getLogLevel() >= LOGLEVEL_TRACE) {
905 msg("<trace> eofill\n");
909 output->fill(output, line, &col);
913 void SWFOutputDev::clip(GfxState *state)
915 GfxPath * path = state->getPath();
916 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
917 clipToGfxLine(state, line);
921 void SWFOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line)
923 if(getLogLevel() >= LOGLEVEL_TRACE) {
924 msg("<trace> clip\n");
928 output->startclip(output, line);
929 states[statepos].clipping++;
931 void SWFOutputDev::eoClip(GfxState *state)
933 GfxPath * path = state->getPath();
934 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
936 if(getLogLevel() >= LOGLEVEL_TRACE) {
937 msg("<trace> eoclip\n");
941 output->startclip(output, line);
942 states[statepos].clipping++;
946 void SWFOutputDev::endframe()
949 output->endclip(output);
953 output->endpage(output);
956 void SWFOutputDev::finish()
960 output->endclip(output);
965 this->result = output->finish(output);
966 free(output);output=0;
970 int SWFOutputDev::save(char*filename)
973 return result->save(result, filename);
975 void* SWFOutputDev::getSWF()
978 return result->get(result, "swf");
981 SWFOutputDev::~SWFOutputDev()
986 this->result->destroy(this->result);
990 fontlist_t*l = this->fontlist;
992 fontlist_t*next = l->next;
994 gfxfont_free(l->font);
1002 GBool SWFOutputDev::upsideDown()
1006 GBool SWFOutputDev::useDrawChar()
1010 GBool SWFOutputDev::useGradients()
1014 msg("<notice> File contains gradients");
1020 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
1021 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
1023 #define RENDER_FILL 0
1024 #define RENDER_STROKE 1
1025 #define RENDER_FILLSTROKE 2
1026 #define RENDER_INVISIBLE 3
1027 #define RENDER_CLIP 4
1029 static char tmp_printstr[4096];
1030 char* makeStringPrintable(char*str)
1032 int len = strlen(str);
1039 for(t=0;t<len;t++) {
1044 tmp_printstr[t] = c;
1047 tmp_printstr[len++] = '.';
1048 tmp_printstr[len++] = '.';
1049 tmp_printstr[len++] = '.';
1051 tmp_printstr[len] = 0;
1052 return tmp_printstr;
1056 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
1060 for(t=0;t<font->num_glyphs;t++) {
1061 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
1062 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1066 /* if we didn't find the character, maybe
1067 we can find the capitalized version */
1068 for(t=0;t<font->num_glyphs;t++) {
1069 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
1070 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1076 /* try to use the unicode id */
1077 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
1078 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
1079 return font->unicode2glyph[u];
1082 /* we don't need to "draw" space characters, so don't overdo the search
1083 for a matching glyph */
1084 if(charname && !strcasecmp(charname, "space"))
1087 if(charnr>=0 && charnr<font->num_glyphs) {
1088 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1096 void SWFOutputDev::beginString(GfxState *state, GString *s)
1098 int render = state->getRender();
1099 if(current_text_stroke) {
1100 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
1103 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
1104 double m11,m21,m12,m22;
1105 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
1106 state->getFontTransMat(&m11, &m12, &m21, &m22);
1107 m11 *= state->getHorizScaling();
1108 m21 *= state->getHorizScaling();
1110 this->current_font_matrix.m00 = m11 / 1024.0;
1111 this->current_font_matrix.m01 = m12 / 1024.0;
1112 this->current_font_matrix.m10 = -m21 / 1024.0;
1113 this->current_font_matrix.m11 = -m22 / 1024.0;
1114 this->current_font_matrix.tx = 0;
1115 this->current_font_matrix.ty = 0;
1117 gfxmatrix_t m = this->current_font_matrix;
1119 /*if(render != 3 && render != 0)
1120 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1121 states[statepos].textRender = render;
1124 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1125 double dx, double dy,
1126 double originX, double originY,
1127 CharCode c, Unicode *_u, int uLen)
1129 int render = state->getRender();
1130 // check for invisible text -- this is used by Acrobat Capture
1134 if(states[statepos].textRender != render)
1135 msg("<error> Internal error: drawChar.render!=beginString.render");
1137 gfxcolor_t col = getFillColor(state);
1139 Gushort *CIDToGIDMap = 0;
1140 GfxFont*font = state->getFont();
1142 if(font->getType() == fontType3) {
1143 /* type 3 chars are passed as graphics */
1144 msg("<debug> type3 char at %f/%f", x, y);
1155 /* find out char name from unicode index
1156 TODO: should be precomputed
1158 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1159 if(nameToUnicodeTab[t].u == u) {
1160 name = nameToUnicodeTab[t].name;
1167 if(font->isCIDFont()) {
1168 GfxCIDFont*cfont = (GfxCIDFont*)font;
1170 if(font->getType() == fontCIDType2)
1171 CIDToGIDMap = cfont->getCIDToGID();
1174 font8 = (Gfx8BitFont*)font;
1175 char**enc=font8->getEncoding();
1180 msg("<debug> 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);
1183 msg("<debug> 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);
1186 int charid = getGfxCharID(current_gfxfont, c, name, u);
1188 if(strcasecmp(name, "space")) {
1189 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1190 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1195 gfxmatrix_t m = this->current_font_matrix;
1196 state->transform(x, y, &m.tx, &m.ty);
1200 if(render == RENDER_FILL) {
1201 output->drawchar(output, current_font_id, charid, &col, &m);
1203 msg("<debug> Drawing glyph %d as shape", charid);
1205 msg("<notice> Some texts will be rendered as shape");
1208 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1209 gfxline_t*tglyph = gfxline_clone(glyph);
1210 gfxline_transform(tglyph, &m);
1211 if((render&3) != RENDER_INVISIBLE) {
1212 gfxline_t*add = gfxline_clone(tglyph);
1213 current_text_stroke = gfxline_append(current_text_stroke, add);
1215 if(render&RENDER_CLIP) {
1216 gfxline_t*add = gfxline_clone(tglyph);
1217 current_text_clip = gfxline_append(current_text_clip, add);
1219 gfxline_free(tglyph);
1223 void SWFOutputDev::endString(GfxState *state)
1225 int render = state->getRender();
1226 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1227 if(states[statepos].textRender != render)
1228 msg("<error> Internal error: drawChar.render!=beginString.render");
1230 if(current_text_stroke) {
1231 /* fillstroke and stroke text rendering objects we can process right
1232 now (as there may be texts of other rendering modes in this
1233 text object)- clipping objects have to wait until endTextObject,
1235 if((render&3) == RENDER_FILL) {
1236 fillGfxLine(state, current_text_stroke);
1237 gfxline_free(current_text_stroke);
1238 current_text_stroke = 0;
1239 } else if((render&3) == RENDER_FILLSTROKE) {
1240 fillGfxLine(state, current_text_stroke);
1241 strokeGfxline(state, current_text_stroke);
1242 gfxline_free(current_text_stroke);
1243 current_text_stroke = 0;
1244 } else if((render&3) == RENDER_STROKE) {
1245 strokeGfxline(state, current_text_stroke);
1246 gfxline_free(current_text_stroke);
1247 current_text_stroke = 0;
1252 void SWFOutputDev::endTextObject(GfxState *state)
1254 int render = state->getRender();
1255 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1256 if(states[statepos].textRender != render)
1257 msg("<error> Internal error: drawChar.render!=beginString.render");
1259 if(current_text_clip) {
1260 clipToGfxLine(state, current_text_clip);
1261 gfxline_free(current_text_clip);
1262 current_text_clip = 0;
1266 /* the logic seems to be as following:
1267 first, beginType3Char is called, with the charcode and the coordinates.
1268 if this function returns true, it already knew about the char and has now drawn it.
1269 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1270 the all draw operations until endType3Char are part of the char (which in this moment is
1271 at the position first passed to beginType3Char). the char ends with endType3Char.
1273 The drawing operations between beginType3Char and endType3Char are somewhat different to
1274 the normal ones. For example, the fillcolor equals the stroke color.
1277 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1279 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1281 /* the character itself is going to be passed using the draw functions */
1282 return gFalse; /* gTrue= is_in_cache? */
1285 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1286 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1288 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1289 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1293 void SWFOutputDev::endType3Char(GfxState *state)
1296 msg("<debug> endType3Char");
1299 void SWFOutputDev::startFrame(int width, int height)
1301 output->startpage(output, width, height);
1304 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1306 this->currentpage = pageNum;
1308 int rot = doc->getPageRotate(1);
1311 gfxline_t clippath[5];
1313 white.r = white.g = white.b = white.a = 255;
1315 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1316 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1317 Use CropBox, not MediaBox, as page size
1324 state->transform(crop_x1,crop_y1,&x1,&y1); //x1 += user_movex; y1 += user_movey;
1325 state->transform(crop_x2,crop_y2,&x2,&y2); //x2 += user_movex; y2 += user_movey;
1327 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1328 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1331 /* apply user clip box */
1332 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1333 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1334 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1335 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1336 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1339 //msg("<verbose> Bounding box is (%f,%f)-(%f,%f) [shifted by %d/%d]", x1,y1,x2,y2, user_movex, user_movey);
1341 if(outer_clip_box) {
1342 output->endclip(output);
1346 msg("<notice> 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, user_movey);
1348 msg("<verbose> page is rotated %d degrees\n", rot);
1350 clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1351 clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1352 clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1353 clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1354 clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1355 output->startclip(output, clippath); outer_clip_box = 1;
1356 output->fill(output, clippath, &white);
1359 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1361 msg("<debug> drawlink\n");
1362 double x1, y1, x2, y2, w;
1364 gfxline_t points[5];
1368 link->getBorder(&x1, &y1, &x2, &y2, &w);
1370 link->getRect(&x1, &y1, &x2, &y2);
1375 cvtUserToDev(x1, y1, &x, &y);
1376 points[0].type = gfx_moveTo;
1377 points[0].x = points[4].x = x + user_movex;
1378 points[0].y = points[4].y = y + user_movey;
1379 points[0].next = &points[1];
1380 cvtUserToDev(x2, y1, &x, &y);
1381 points[1].type = gfx_lineTo;
1382 points[1].x = x + user_movex;
1383 points[1].y = y + user_movey;
1384 points[1].next = &points[2];
1385 cvtUserToDev(x2, y2, &x, &y);
1386 points[2].type = gfx_lineTo;
1387 points[2].x = x + user_movex;
1388 points[2].y = y + user_movey;
1389 points[2].next = &points[3];
1390 cvtUserToDev(x1, y2, &x, &y);
1391 points[3].type = gfx_lineTo;
1392 points[3].x = x + user_movex;
1393 points[3].y = y + user_movey;
1394 points[3].next = &points[4];
1395 cvtUserToDev(x1, y1, &x, &y);
1396 points[4].type = gfx_lineTo;
1397 points[4].x = x + user_movex;
1398 points[4].y = y + user_movey;
1401 LinkAction*action=link->getAction();
1408 switch(action->getKind())
1412 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1413 LinkDest *dest=NULL;
1414 if (ha->getDest()==NULL)
1415 dest=catalog->findDest(ha->getNamedDest());
1416 else dest=ha->getDest();
1418 if (dest->isPageRef()){
1419 Ref pageref=dest->getPageRef();
1420 page=catalog->findPage(pageref.num,pageref.gen);
1422 else page=dest->getPageNum();
1423 sprintf(buf, "%d", page);
1430 LinkGoToR*l = (LinkGoToR*)action;
1431 GString*g = l->getNamedDest();
1433 s = strdup(g->getCString());
1438 LinkNamed*l = (LinkNamed*)action;
1439 GString*name = l->getName();
1441 s = strdup(name->lowerCase()->getCString());
1442 named = name->getCString();
1445 if(strstr(s, "next") || strstr(s, "forward"))
1447 page = currentpage + 1;
1449 else if(strstr(s, "prev") || strstr(s, "back"))
1451 page = currentpage - 1;
1453 else if(strstr(s, "last") || strstr(s, "end"))
1455 page = pagepos>0?pages[pagepos-1]:0;
1457 else if(strstr(s, "first") || strstr(s, "top"))
1465 case actionLaunch: {
1467 LinkLaunch*l = (LinkLaunch*)action;
1468 GString * str = new GString(l->getFileName());
1469 str->append(l->getParams());
1470 s = strdup(str->getCString());
1476 LinkURI*l = (LinkURI*)action;
1477 GString*g = l->getURI();
1479 url = g->getCString();
1484 case actionUnknown: {
1486 LinkUnknown*l = (LinkUnknown*)action;
1491 msg("<error> Unknown link type!\n");
1495 if(!s) s = strdup("-?-");
1497 if(!linkinfo && (page || url))
1499 msg("<notice> File contains links");
1506 for(t=0;t<pagepos;t++)
1511 sprintf(buf, "page%d", t);
1512 output->drawlink(output, points, buf);
1517 output->drawlink(output, points, url);
1520 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1524 void SWFOutputDev::saveState(GfxState *state) {
1525 msg("<trace> saveState\n");
1528 msg("<error> Too many nested states in pdf.");
1532 states[statepos].clipping = 0; //? shouldn't this be the current value?
1533 states[statepos].textRender = states[statepos-1].textRender;
1536 void SWFOutputDev::restoreState(GfxState *state) {
1537 msg("<trace> restoreState\n");
1539 while(states[statepos].clipping) {
1540 output->endclip(output);
1541 states[statepos].clipping--;
1546 char* SWFOutputDev::searchFont(char*name)
1550 int is_standard_font = 0;
1552 msg("<verbose> SearchFont(%s)", name);
1554 /* see if it is a pdf standard font */
1555 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1557 if(!strcmp(name, pdf2t1map[i].pdffont))
1559 name = pdf2t1map[i].filename;
1560 is_standard_font = 1;
1564 /* look in all font files */
1565 for(i=0;i<fontnum;i++)
1567 if(strstr(fonts[i].filename, name))
1569 if(!fonts[i].used) {
1572 if(!is_standard_font)
1573 msg("<notice> Using %s for %s", fonts[i].filename, name);
1575 return strdup(fonts[i].filename);
1581 void SWFOutputDev::updateLineWidth(GfxState *state)
1583 double width = state->getTransformedLineWidth();
1584 //swfoutput_setlinewidth(&output, width);
1587 void SWFOutputDev::updateLineCap(GfxState *state)
1589 int c = state->getLineCap();
1592 void SWFOutputDev::updateLineJoin(GfxState *state)
1594 int j = state->getLineJoin();
1597 void SWFOutputDev::updateFillColor(GfxState *state)
1600 double opaq = state->getFillOpacity();
1601 state->getFillRGB(&rgb);
1603 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1606 void SWFOutputDev::updateStrokeColor(GfxState *state)
1609 double opaq = state->getStrokeOpacity();
1610 state->getStrokeRGB(&rgb);
1611 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1614 void FoFiWrite(void *stream, char *data, int len)
1616 fwrite(data, len, 1, (FILE*)stream);
1619 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1621 char*tmpFileName = NULL;
1627 Object refObj, strObj;
1629 tmpFileName = mktmpname(namebuf);
1632 ret = font->getEmbeddedFontID(&embRef);
1634 msg("<verbose> Didn't get embedded font id");
1635 /* not embedded- the caller should now search the font
1636 directories for this font */
1640 f = fopen(tmpFileName, "wb");
1642 msg("<error> Couldn't create temporary Type 1 font file");
1646 /*if(font->isCIDFont()) {
1647 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1648 GString c = cidFont->getCollection();
1649 msg("<notice> Collection: %s", c.getCString());
1652 //if (font->getType() == fontType1C) {
1653 if (0) { //font->getType() == fontType1C) {
1654 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1656 msg("<error> Couldn't read embedded font file");
1660 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1662 cvt->convertToType1(f);
1664 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1666 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1668 //cvt->convertToCIDType0("test", f);
1669 //cvt->convertToType0("test", f);
1672 } else if(font->getType() == fontTrueType) {
1673 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1674 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1676 msg("<error> Couldn't read embedded font file");
1680 TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1683 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1684 cvt->writeTTF(FoFiWrite, f);
1689 font->getEmbeddedFontID(&embRef);
1690 refObj.initRef(embRef.num, embRef.gen);
1691 refObj.fetch(ref, &strObj);
1693 strObj.streamReset();
1698 f4[t] = strObj.streamGetChar();
1699 f4c[t] = (char)f4[t];
1704 if(!strncmp(f4c, "true", 4)) {
1705 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1706 Change this on the fly */
1707 f4[0] = f4[2] = f4[3] = 0;
1715 while ((c = strObj.streamGetChar()) != EOF) {
1719 strObj.streamClose();
1724 return strdup(tmpFileName);
1727 char* searchForSuitableFont(GfxFont*gfxFont)
1729 char*name = getFontName(gfxFont);
1733 if(!config_use_fontconfig)
1736 #ifdef HAVE_FONTCONFIG
1737 FcPattern *pattern, *match;
1741 static int fcinitcalled = false;
1743 msg("<debug> searchForSuitableFont(%s)", name);
1745 // call init ony once
1746 if (!fcinitcalled) {
1747 msg("<debug> Initializing FontConfig...");
1748 fcinitcalled = true;
1750 msg("<debug> FontConfig Initialization failed. Disabling.");
1751 config_use_fontconfig = 0;
1754 msg("<debug> ...initialized FontConfig");
1757 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1758 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1759 if (gfxFont->isItalic()) // check for italic
1760 msg("<debug> FontConfig: Adding Italic Slant");
1761 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1762 if (gfxFont->isBold()) // check for bold
1763 msg("<debug> FontConfig: Adding Bold Weight");
1764 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1766 msg("<debug> FontConfig: Try to match...");
1767 // configure and match using the original font name
1768 FcConfigSubstitute(0, pattern, FcMatchPattern);
1769 FcDefaultSubstitute(pattern);
1770 match = FcFontMatch(0, pattern, &result);
1772 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1773 msg("<debug> FontConfig: family=%s", (char*)v);
1774 // if we get an exact match
1775 if (strcmp((char *)v, name) == 0) {
1776 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1777 filename = strdup((char*)v); // mem leak
1778 char *nfn = strrchr(filename, '/');
1779 if(nfn) fontname = strdup(nfn+1);
1780 else fontname = filename;
1782 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1784 // initialize patterns
1785 FcPatternDestroy(pattern);
1786 FcPatternDestroy(match);
1788 // now match against serif etc.
1789 if (gfxFont->isSerif()) {
1790 msg("<debug> FontConfig: Create Serif Family Pattern");
1791 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1792 } else if (gfxFont->isFixedWidth()) {
1793 msg("<debug> FontConfig: Create Monospace Family Pattern");
1794 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1796 msg("<debug> FontConfig: Create Sans Family Pattern");
1797 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1801 if (gfxFont->isItalic()) {
1802 msg("<debug> FontConfig: Adding Italic Slant");
1803 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1806 if (gfxFont->isBold()) {
1807 msg("<debug> FontConfig: Adding Bold Weight");
1808 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1811 msg("<debug> FontConfig: Try to match... (2)");
1812 // configure and match using serif etc
1813 FcConfigSubstitute (0, pattern, FcMatchPattern);
1814 FcDefaultSubstitute (pattern);
1815 match = FcFontMatch (0, pattern, &result);
1817 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1818 filename = strdup((char*)v); // mem leak
1819 char *nfn = strrchr(filename, '/');
1820 if(nfn) fontname = strdup(nfn+1);
1821 else fontname = filename;
1823 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1827 //printf("FONTCONFIG: pattern");
1828 //FcPatternPrint(pattern);
1829 //printf("FONTCONFIG: match");
1830 //FcPatternPrint(match);
1832 FcPatternDestroy(pattern);
1833 FcPatternDestroy(match);
1835 pdfswf_addfont(filename);
1842 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1844 char*fontname = 0, *filename = 0;
1845 msg("<notice> subsituteFont(%s)", oldname);
1847 if(!(fontname = searchForSuitableFont(gfxFont))) {
1848 fontname = "Times-Roman";
1850 filename = searchFont(fontname);
1852 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1856 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1857 msg("<fatal> Too many fonts in file.");
1861 substitutesource[substitutepos] = strdup(oldname); //mem leak
1862 substitutetarget[substitutepos] = fontname;
1863 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1866 return strdup(filename); //mem leak
1869 void unlinkfont(char* filename)
1876 if(!strncmp(&filename[l-4],".afm",4)) {
1877 memcpy(&filename[l-4],".pfb",4);
1879 memcpy(&filename[l-4],".pfa",4);
1881 memcpy(&filename[l-4],".afm",4);
1884 if(!strncmp(&filename[l-4],".pfa",4)) {
1885 memcpy(&filename[l-4],".afm",4);
1887 memcpy(&filename[l-4],".pfa",4);
1890 if(!strncmp(&filename[l-4],".pfb",4)) {
1891 memcpy(&filename[l-4],".afm",4);
1893 memcpy(&filename[l-4],".pfb",4);
1898 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1904 int SWFOutputDev::setGfxFont(char*id, char*filename, double maxSize)
1907 fontlist_t*last=0,*l = this->fontlist;
1909 /* TODO: should this be part of the state? */
1912 if(!strcmp(l->id, id)) {
1913 current_font_id = l->id;
1914 current_gfxfont = l->font;
1916 output->addfont(output, id, current_gfxfont);
1921 if(!filename) return 0;
1923 /* A font size of e.g. 9 means the font will be scaled down by
1924 1024 and scaled up by 9. So to have a maximum error of 1/20px,
1925 we have to divide 0.05 by (fontsize/1024)
1927 double quality = (1024 * 0.05) / maxSize;
1929 font = gfxfont_load(filename, quality);
1932 l->filename = strdup(filename);
1935 current_font_id = l->id;
1936 current_gfxfont = l->font;
1942 output->addfont(output, id, current_gfxfont);
1946 void SWFOutputDev::updateFont(GfxState *state)
1948 GfxFont*gfxFont = state->getFont();
1953 char * fontid = getFontID(gfxFont);
1954 double maxSize = 1.0;
1957 maxSize = this->info->getMaximumFontSize(fontid);
1961 /* first, look if we substituted this font before-
1962 this way, we don't initialize the T1 Fonts
1964 for(t=0;t<substitutepos;t++) {
1965 if(!strcmp(fontid, substitutesource[t])) {
1966 free(fontid);fontid=0;
1967 fontid = strdup(substitutetarget[t]);
1972 /* second, see if this is a font which was used before-
1973 if so, we are done */
1974 if(setGfxFont(fontid, 0, 0)) {
1978 /* if(swfoutput_queryfont(&output, fontid))
1979 swfoutput_setfont(&output, fontid, 0);
1981 msg("<debug> updateFont(%s) [cached]", fontid);
1985 // look for Type 3 font
1986 if (gfxFont->getType() == fontType3) {
1988 type3Warning = gTrue;
1989 showFontError(gfxFont, 2);
1995 /* now either load the font, or find a substitution */
1998 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
2003 (gfxFont->getType() == fontType1 ||
2004 gfxFont->getType() == fontType1C ||
2005 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
2006 gfxFont->getType() == fontTrueType ||
2007 gfxFont->getType() == fontCIDType2
2010 fileName = writeEmbeddedFontToFile(xref, gfxFont);
2011 if(!fileName) showFontError(gfxFont,0);
2014 char * fontname = getFontName(gfxFont);
2015 fileName = searchFont(fontname);
2016 if(!fileName) showFontError(gfxFont,0);
2020 char * fontname = getFontName(gfxFont);
2021 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
2022 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
2023 fileName = substituteFont(gfxFont, fontid);
2024 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
2025 msg("<notice> Font is now %s (%s)", fontid, fileName);
2029 msg("<error> Couldn't set font %s\n", fontid);
2034 msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
2035 dumpFontInfo("<verbose>", gfxFont);
2037 //swfoutput_setfont(&output, fontid, fileName);
2039 if(!setGfxFont(fontid, 0, 0)) {
2040 setGfxFont(fontid, fileName, maxSize);
2044 unlinkfont(fileName);
2050 #define SQR(x) ((x)*(x))
2052 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
2054 if((newwidth<2 || newheight<2) ||
2055 (width<=newwidth || height<=newheight))
2057 unsigned char*newdata;
2059 newdata= (unsigned char*)malloc(newwidth*newheight);
2061 double fx = (double)(width)/newwidth;
2062 double fy = (double)(height)/newheight;
2064 int blocksize = (int)(8192/(fx*fy));
2065 int r = 8192*256/palettesize;
2066 for(x=0;x<newwidth;x++) {
2067 double ex = px + fx;
2068 int fromx = (int)px;
2070 int xweight1 = (int)(((fromx+1)-px)*256);
2071 int xweight2 = (int)((ex-tox)*256);
2073 for(y=0;y<newheight;y++) {
2074 double ey = py + fy;
2075 int fromy = (int)py;
2077 int yweight1 = (int)(((fromy+1)-py)*256);
2078 int yweight2 = (int)((ey-toy)*256);
2081 for(xx=fromx;xx<=tox;xx++)
2082 for(yy=fromy;yy<=toy;yy++) {
2083 int b = 1-data[width*yy+xx];
2085 if(xx==fromx) weight = (weight*xweight1)/256;
2086 if(xx==tox) weight = (weight*xweight2)/256;
2087 if(yy==fromy) weight = (weight*yweight1)/256;
2088 if(yy==toy) weight = (weight*yweight2)/256;
2091 //if(a) a=(palettesize-1)*r/blocksize;
2092 newdata[y*newwidth+x] = (a*blocksize)/r;
2100 #define IMAGE_TYPE_JPEG 0
2101 #define IMAGE_TYPE_LOSSLESS 1
2103 static void drawimage(gfxdevice_t*dev, RGBA* data, int sizex,int sizey,
2104 double x1,double y1,
2105 double x2,double y2,
2106 double x3,double y3,
2107 double x4,double y4, int type)
2111 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2112 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2114 gfxline_t p1,p2,p3,p4,p5;
2115 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2116 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2117 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2118 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2119 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2121 {p1.x = (int)(p1.x*20)/20.0;
2122 p1.y = (int)(p1.y*20)/20.0;
2123 p2.x = (int)(p2.x*20)/20.0;
2124 p2.y = (int)(p2.y*20)/20.0;
2125 p3.x = (int)(p3.x*20)/20.0;
2126 p3.y = (int)(p3.y*20)/20.0;
2127 p4.x = (int)(p4.x*20)/20.0;
2128 p4.y = (int)(p4.y*20)/20.0;
2129 p5.x = (int)(p5.x*20)/20.0;
2130 p5.y = (int)(p5.y*20)/20.0;
2137 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2138 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2143 img.data = (gfxcolor_t*)data;
2147 if(type == IMAGE_TYPE_JPEG)
2148 /* TODO: pass image_dpi to device instead */
2149 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2151 dev->fillbitmap(dev, &p1, &img, &m, 0);
2154 void drawimagejpeg(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
2155 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2157 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2160 void drawimagelossless(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
2161 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2163 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2167 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2168 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2169 GBool inlineImg, int mask, int*maskColors)
2174 double x1,y1,x2,y2,x3,y3,x4,y4;
2175 ImageStream *imgStr;
2182 ncomps = colorMap->getNumPixelComps();
2183 bits = colorMap->getBits();
2185 imgStr = new ImageStream(str, width, ncomps,bits);
2188 if(!width || !height || (height<=1 && width<=1))
2190 msg("<verbose> Ignoring %d by %d image", width, height);
2191 unsigned char buf[8];
2193 for (y = 0; y < height; ++y)
2194 for (x = 0; x < width; ++x) {
2195 imgStr->getPixel(buf);
2201 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1+= user_movey;
2202 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2+= user_movey;
2203 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3+= user_movey;
2204 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4+= user_movey;
2206 if(!pbminfo && !(str->getKind()==strDCT)) {
2208 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2212 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2214 if(!jpeginfo && (str->getKind()==strDCT)) {
2215 msg("<notice> file contains jpeg pictures");
2221 unsigned char buf[8];
2223 unsigned char*pic = new unsigned char[width*height];
2226 state->getFillRGB(&rgb);
2228 memset(pal,255,sizeof(pal));
2229 pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
2230 pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
2231 pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
2232 pal[0].a = 255; pal[1].a = 0;
2235 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2236 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2237 for (y = 0; y < height; ++y)
2238 for (x = 0; x < width; ++x)
2240 imgStr->getPixel(buf);
2243 pic[width*y+x] = buf[0];
2246 /* the size of the drawn image is added to the identifier
2247 as the same image may require different bitmaps if displayed
2248 at different sizes (due to antialiasing): */
2251 unsigned char*pic2 = 0;
2254 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2263 height = realheight;
2267 /* make a black/white palette */
2272 float r = 255/(numpalette-1);
2274 for(t=0;t<numpalette;t++) {
2275 pal[t].r = (U8)(255*rgb.r);
2276 pal[t].g = (U8)(255*rgb.g);
2277 pal[t].b = (U8)(255*rgb.b);
2278 pal[t].a = (U8)(t*r);
2282 RGBA*pic2 = new RGBA[width*height];
2283 for (y = 0; y < height; ++y) {
2284 for (x = 0; x < width; ++x) {
2285 pic2[width*y+x] = pal[pic[y*width+x]];
2288 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2297 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2298 RGBA*pic=new RGBA[width*height];
2299 for (y = 0; y < height; ++y) {
2300 for (x = 0; x < width; ++x) {
2301 imgStr->getPixel(pixBuf);
2302 colorMap->getRGB(pixBuf, &rgb);
2303 pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
2304 pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
2305 pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
2306 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2309 if(str->getKind()==strDCT)
2310 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2312 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2317 RGBA*pic=new RGBA[width*height];
2320 for(t=0;t<256;t++) {
2322 colorMap->getRGB(pixBuf, &rgb);
2323 /*if(maskColors && *maskColors==t) {
2324 msg("<notice> Color %d is transparent", t);
2325 if (imgData->maskColors) {
2327 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2328 if (pix[i] < imgData->maskColors[2*i] ||
2329 pix[i] > imgData->maskColors[2*i+1]) {
2344 pal[t].r = (U8)(rgb.r * 255 + 0.5);
2345 pal[t].g = (U8)(rgb.g * 255 + 0.5);
2346 pal[t].b = (U8)(rgb.b * 255 + 0.5);
2347 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2350 for (y = 0; y < height; ++y) {
2351 for (x = 0; x < width; ++x) {
2352 imgStr->getPixel(pixBuf);
2353 pic[width*y+x] = pal[pixBuf[0]];
2356 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2364 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2365 int width, int height, GBool invert,
2368 if(states[statepos].textRender & 4) //clipped
2370 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2371 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
2374 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2375 int width, int height, GfxImageColorMap *colorMap,
2376 int *maskColors, GBool inlineImg)
2378 if(states[statepos].textRender & 4) //clipped
2381 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
2382 colorMap?"colorMap":"no colorMap",
2383 maskColors?"maskColors":"no maskColors",
2386 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2387 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2388 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
2391 //SWFOutputDev*output = 0;
2393 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2398 if (infoDict->lookup(key, &obj)->isString()) {
2399 s1 = obj.getString();
2400 if ((s1->getChar(0) & 0xff) == 0xfe &&
2401 (s1->getChar(1) & 0xff) == 0xff) {
2403 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2404 if (s1->getChar(i) == '\0') {
2405 s2->append(s1->getChar(i+1));
2408 s2 = new GString("<unicode>");
2412 printf(fmt, s2->getCString());
2415 printf(fmt, s1->getCString());
2421 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2425 if (infoDict->lookup(key, &obj)->isString()) {
2426 s = obj.getString()->getCString();
2427 if (s[0] == 'D' && s[1] == ':') {
2438 void storeDeviceParameter(char*name, char*value)
2440 parameter_t*p = new parameter_t();
2441 p->name = strdup(name);
2442 p->value = strdup(value);
2444 if(device_config_next) {
2445 device_config_next->next = p;
2446 device_config_next = p;
2449 device_config_next = p;
2453 void pdfswf_setparameter(char*name, char*value)
2455 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2456 if(!strcmp(name, "caplinewidth")) {
2457 caplinewidth = atof(value);
2458 } else if(!strcmp(name, "zoom")) {
2461 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2462 storeDeviceParameter("jpegsubpixels", buf);
2463 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2464 storeDeviceParameter("ppmsubpixels", buf);
2465 } else if(!strcmp(name, "jpegdpi")) {
2467 jpeg_dpi = atoi(value);
2468 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2469 storeDeviceParameter("jpegsubpixels", buf);
2470 } else if(!strcmp(name, "ppmdpi")) {
2472 ppm_dpi = atoi(value);
2473 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2474 storeDeviceParameter("ppmsubpixels", buf);
2475 } else if(!strcmp(name, "forceType0Fonts")) {
2476 forceType0Fonts = atoi(value);
2477 } else if(!strcmp(name, "fontdir")) {
2478 pdfswf_addfontdir(value);
2479 } else if(!strcmp(name, "languagedir")) {
2480 pdfswf_addlanguagedir(value);
2481 } else if(!strcmp(name, "fontconfig")) {
2482 config_use_fontconfig = atoi(value);
2484 storeDeviceParameter(name,value);
2487 void pdfswf_addfont(char*filename)
2490 memset(&f, 0, sizeof(fontfile_t));
2491 f.filename = filename;
2492 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2493 fonts[fontnum++] = f;
2495 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2499 static char* dirseparator()
2508 void pdfswf_addlanguagedir(char*dir)
2511 globalParams = new GlobalParams("");
2513 msg("<notice> Adding %s to language pack directories", dir);
2517 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2518 strcpy(config_file, dir);
2519 strcat(config_file, dirseparator());
2520 strcat(config_file, "add-to-xpdfrc");
2522 fi = fopen(config_file, "rb");
2524 msg("<error> Could not open %s", config_file);
2527 globalParams->parseFile(new GString(config_file), fi);
2531 void pdfswf_addfontdir(char*dirname)
2533 #ifdef HAVE_DIRENT_H
2534 msg("<notice> Adding %s to font directories", dirname);
2535 DIR*dir = opendir(dirname);
2537 msg("<warning> Couldn't open directory %s\n", dirname);
2542 ent = readdir (dir);
2546 char*name = ent->d_name;
2552 if(!strncasecmp(&name[l-4], ".pfa", 4))
2554 if(!strncasecmp(&name[l-4], ".pfb", 4))
2556 if(!strncasecmp(&name[l-4], ".ttf", 4))
2560 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2561 strcpy(fontname, dirname);
2562 strcat(fontname, dirseparator());
2563 strcat(fontname, name);
2564 msg("<verbose> Adding %s to fonts", fontname);
2565 pdfswf_addfont(fontname);
2570 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2575 typedef struct _pdf_doc_internal
2580 } pdf_doc_internal_t;
2581 typedef struct _pdf_page_internal
2583 } pdf_page_internal_t;
2584 typedef struct _swf_output_internal
2586 SWFOutputDev*outputDev;
2587 } swf_output_internal_t;
2589 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2591 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2592 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2593 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2594 memset(i, 0, sizeof(pdf_doc_internal_t));
2595 pdf_doc->internal = i;
2597 GString *fileName = new GString(filename);
2603 globalParams = new GlobalParams("");
2606 if (userPassword && userPassword[0]) {
2607 userPW = new GString(userPassword);
2611 i->doc = new PDFDoc(fileName, userPW);
2615 if (!i->doc->isOk()) {
2620 i->doc->getDocInfo(&info);
2621 if (info.isDict() &&
2622 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2623 printInfoString(info.getDict(), "Title", "Title: %s\n");
2624 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2625 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2626 printInfoString(info.getDict(), "Author", "Author: %s\n");
2627 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2628 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2629 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2630 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2631 printf("Pages: %d\n", i->doc->getNumPages());
2632 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2633 printf("Encrypted: ");
2634 if (i->doc->isEncrypted()) {
2635 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2636 i->doc->okToPrint() ? "yes" : "no",
2637 i->doc->okToCopy() ? "yes" : "no",
2638 i->doc->okToChange() ? "yes" : "no",
2639 i->doc->okToAddNotes() ? "yes" : "no");
2646 pdf_doc->num_pages = i->doc->getNumPages();
2648 if (i->doc->isEncrypted()) {
2649 if(!i->doc->okToCopy()) {
2650 printf("PDF disallows copying.\n");
2653 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2657 InfoOutputDev*io = new InfoOutputDev();
2659 for(t=1;t<=pdf_doc->num_pages;t++) {
2661 i->doc->displayPage((OutputDev*)io, t, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2663 i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2671 static void pdfswf_preparepage(int page)
2675 pages = (int*)malloc(1024*sizeof(int));
2678 if(pagepos == pagebuflen)
2681 pages = (int*)realloc(pages, pagebuflen);
2684 pages[pagepos++] = page;
2691 delete globalParams;globalParams=0;
2692 Object::memCheck(stderr);
2697 void pdf_destroy(pdf_doc_t*pdf_doc)
2699 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2701 delete i->doc; i->doc=0;
2703 free(pages); pages = 0; //FIXME
2706 delete i->info;i->info=0;
2709 free(pdf_doc->internal);pdf_doc->internal=0;
2710 free(pdf_doc);pdf_doc=0;
2713 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2715 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2717 if(page < 1 || page > pdf_doc->num_pages)
2720 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2721 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2722 memset(pi, 0, sizeof(pdf_page_internal_t));
2723 pdf_page->internal = pi;
2725 pdf_page->parent = pdf_doc;
2726 pdf_page->nr = page;
2730 void pdf_page_destroy(pdf_page_t*pdf_page)
2732 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2733 free(pdf_page->internal);pdf_page->internal = 0;
2734 free(pdf_page);pdf_page=0;
2737 swf_output_t* swf_output_init()
2739 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2740 memset(swf_output, 0, sizeof(swf_output_t));
2741 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2742 memset(i, 0, sizeof(swf_output_internal_t));
2743 swf_output->internal = i;
2745 i->outputDev = new SWFOutputDev();
2749 void swf_output_setparameter(swf_output_t*swf, char*name, char*value)
2751 pdfswf_setparameter(name, value);
2754 void swf_output_startframe(swf_output_t*swf, int width, int height)
2756 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2757 i->outputDev->startFrame(width, height);
2760 void swf_output_endframe(swf_output_t*swf)
2762 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2763 i->outputDev->endframe();
2766 int swf_output_save(swf_output_t*swf, char*filename)
2768 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2769 int ret = i->outputDev->save(filename);
2773 void* swf_output_get(swf_output_t*swf)
2775 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2776 void* ret = i->outputDev->getSWF();
2780 void swf_output_destroy(swf_output_t*output)
2782 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2783 delete i->outputDev; i->outputDev=0;
2784 free(output->internal);output->internal=0;
2788 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2790 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2791 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2794 msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2799 gfxdevice_t*dev = si->outputDev->output;
2800 dev->setparameter(dev, "protect", "1");
2802 si->outputDev->setInfo(pi->info);
2803 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2805 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2807 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2811 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2813 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2814 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2816 si->outputDev->setMove(x,y);
2817 if((x1|y1|x2|y2)==0) x2++;
2818 si->outputDev->setClip(x1,y1,x2,y2);
2820 pdf_page_render2(page, output);
2822 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2824 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2825 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2827 si->outputDev->setMove(0,0);
2828 si->outputDev->setClip(0,0,0,0);
2830 pdf_page_render2(page, output);
2834 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2836 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2837 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2838 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2839 memset(info, 0, sizeof(pdf_page_info_t));
2841 InfoOutputDev*output = new InfoOutputDev;
2844 pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2846 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2849 info->xMin = output->x1;
2850 info->yMin = output->y1;
2851 info->xMax = output->x2;
2852 info->yMax = output->y2;
2853 info->number_of_images = output->num_images;
2854 info->number_of_links = output->num_links;
2855 info->number_of_fonts = output->num_fonts;
2862 void pdf_page_info_destroy(pdf_page_info_t*info)