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 "../lib/devices/swf.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 static double caplinewidth = 3.0;
98 static double zoom = 72; /* xpdf: 86 */
99 static int forceType0Fonts = 1;
101 static void printInfoString(Dict *infoDict, char *key, char *fmt);
102 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
104 static char* lastfontdir = 0;
110 {"Times-Roman", "n021003l"},
111 {"Times-Italic", "n021023l"},
112 {"Times-Bold", "n021004l"},
113 {"Times-BoldItalic", "n021024l"},
114 {"Helvetica", "n019003l"},
115 {"Helvetica-Oblique", "n019023l"},
116 {"Helvetica-Bold", "n019004l"},
117 {"Helvetica-BoldOblique", "n019024l"},
118 {"Courier", "n022003l"},
119 {"Courier-Oblique", "n022023l"},
120 {"Courier-Bold", "n022004l"},
121 {"Courier-BoldOblique", "n022024l"},
122 {"Symbol", "s050000l"},
123 {"ZapfDingbats", "d050000l"}};
125 class SWFOutputState {
131 this->textRender = 0;
135 typedef struct _fontlist
145 class SWFOutputDev: public OutputDev {
153 virtual ~SWFOutputDev() ;
155 void setMove(int x,int y);
156 void setClip(int x1,int y1,int x2,int y2);
158 void setInfo(InfoOutputDev*info) {this->info = info;}
160 int save(char*filename);
163 void startFrame(int width, int height);
165 virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
168 void* get(char*name);
170 //----- get info about output device
172 // Does this device use upside-down coordinates?
173 // (Upside-down means (0,0) is the top left corner of the page.)
174 virtual GBool upsideDown();
176 // Does this device use drawChar() or drawString()?
177 virtual GBool useDrawChar();
179 // Can this device draw gradients?
180 virtual GBool useGradients();
182 virtual GBool interpretType3Chars() {return gTrue;}
184 //----- initialization and control
186 void setXRef(PDFDoc*doc, XRef *xref);
189 virtual void drawLink(Link *link, Catalog *catalog) ;
191 //----- save/restore graphics state
192 virtual void saveState(GfxState *state) ;
193 virtual void restoreState(GfxState *state) ;
195 //----- update graphics state
197 virtual void updateFont(GfxState *state);
198 virtual void updateFillColor(GfxState *state);
199 virtual void updateStrokeColor(GfxState *state);
200 virtual void updateLineWidth(GfxState *state);
201 virtual void updateLineJoin(GfxState *state);
202 virtual void updateLineCap(GfxState *state);
204 virtual void updateAll(GfxState *state)
207 updateFillColor(state);
208 updateStrokeColor(state);
209 updateLineWidth(state);
210 updateLineJoin(state);
211 updateLineCap(state);
214 //----- path painting
215 virtual void stroke(GfxState *state) ;
216 virtual void fill(GfxState *state) ;
217 virtual void eoFill(GfxState *state) ;
219 //----- path clipping
220 virtual void clip(GfxState *state) ;
221 virtual void eoClip(GfxState *state) ;
224 virtual void beginString(GfxState *state, GString *s) ;
225 virtual void endString(GfxState *state) ;
226 virtual void endTextObject(GfxState *state);
227 virtual void drawChar(GfxState *state, double x, double y,
228 double dx, double dy,
229 double originX, double originY,
230 CharCode code, Unicode *u, int uLen);
232 //----- image drawing
233 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
234 int width, int height, GBool invert,
236 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
237 int width, int height, GfxImageColorMap *colorMap,
238 int *maskColors, GBool inlineImg);
240 virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
241 virtual void endType3Char(GfxState *state);
243 virtual void type3D0(GfxState *state, double wx, double wy);
244 virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
247 void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
248 int width, int height, GfxImageColorMap*colorMap, GBool invert,
249 GBool inlineImg, int mask, int *maskColors);
250 int SWFOutputDev::setGfxFont(char*id, char*filename, double quality);
251 void strokeGfxline(GfxState *state, gfxline_t*line);
252 void clipToGfxLine(GfxState *state, gfxline_t*line);
253 void fillGfxLine(GfxState *state, gfxline_t*line);
257 gfxresult_t*result; //filled when complete
259 char outer_clip_box; //whether the page clip box is still on
262 SWFOutputState states[64];
270 char* searchFont(char*name);
271 char* substituteFont(GfxFont*gfxFont, char*oldname);
272 char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
274 int textmodeinfo; // did we write "Text will be rendered as polygon" yet?
275 int jpeginfo; // did we write "File contains jpegs" yet?
276 int pbminfo; // did we write "File contains jpegs" yet?
277 int linkinfo; // did we write "File contains links" yet?
278 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
279 int gradientinfo; // did we write "File contains Gradients yet?
281 int type3active; // are we between beginType3()/endType3()?
287 char* substitutetarget[256];
288 char* substitutesource[256];
291 int user_movex,user_movey;
292 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
294 gfxline_t* current_text_stroke;
295 gfxline_t* current_text_clip;
296 char* current_font_id;
297 gfxfont_t* current_gfxfont;
298 gfxmatrix_t current_font_matrix;
300 fontlist_t* fontlist;
306 friend void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage);
309 typedef struct _drawnchar
327 chars = (drawnchar_t*)malloc(sizeof(drawnchar_t)*buf_size);
328 memset(chars, 0, sizeof(drawnchar_t)*buf_size);
333 free(chars);chars = 0;
340 chars = (drawnchar_t*)realloc(chars, sizeof(drawnchar_t)*buf_size);
344 void addChar(int charid, gfxcoord_t x, gfxcoord_t y, gfxcolor_t color)
347 chars[num_chars].x = x;
348 chars[num_chars].y = y;
349 chars[num_chars].color = color;
350 chars[num_chars].charid = charid;
354 static char*getFontID(GfxFont*font);
362 class InfoOutputDev: public OutputDev
365 FontInfo* currentfont;
377 id2font = new GHash();
379 virtual ~InfoOutputDev()
383 virtual GBool upsideDown() {return gTrue;}
384 virtual GBool useDrawChar() {return gTrue;}
385 virtual GBool useGradients() {return gTrue;}
386 virtual GBool interpretType3Chars() {return gTrue;}
387 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
390 state->transform(crop_x1,crop_y1,&x1,&y1);
391 state->transform(crop_x2,crop_y2,&x2,&y2);
392 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
393 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
399 virtual void drawLink(Link *link, Catalog *catalog)
403 virtual double getMaximumFontSize(char*id)
405 FontInfo*info = (FontInfo*)id2font->lookup(id);
407 msg("<error> Unknown font id: %s", id);
410 return info->max_size;
413 virtual void updateFont(GfxState *state)
415 GfxFont*font = state->getFont();
418 char*id = getFontID(font);
420 FontInfo*info = (FontInfo*)id2font->lookup(id);
422 GString* idStr = new GString(id);
426 id2font->add(idStr, (void*)info);
432 virtual void drawChar(GfxState *state, double x, double y,
433 double dx, double dy,
434 double originX, double originY,
435 CharCode code, Unicode *u, int uLen)
437 int render = state->getRender();
440 double m11,m21,m12,m22;
441 state->getFontTransMat(&m11, &m12, &m21, &m22);
442 m11 *= state->getHorizScaling();
443 m21 *= state->getHorizScaling();
444 double lenx = sqrt(m11*m11 + m12*m12);
445 double leny = sqrt(m21*m21 + m22*m22);
446 double len = lenx>leny?lenx:leny;
447 if(currentfont && currentfont->max_size < len) {
448 currentfont->max_size = len;
451 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
452 int width, int height, GBool invert,
457 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
458 int width, int height, GfxImageColorMap *colorMap,
459 int *maskColors, GBool inlineImg)
465 SWFOutputDev::SWFOutputDev()
483 current_text_stroke = 0;
484 current_text_clip = 0;
491 output = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
492 gfxdevice_swf_init(output);
493 /* configure device */
494 parameter_t*p = device_config;
496 output->setparameter(output, p->name, p->value);
501 void SWFOutputDev::setMove(int x,int y)
503 this->user_movex = x;
504 this->user_movey = y;
507 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
509 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
510 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
512 this->user_clipx1 = x1;
513 this->user_clipy1 = y1;
514 this->user_clipx2 = x2;
515 this->user_clipy2 = y2;
518 static char*getFontID(GfxFont*font)
520 GString*gstr = font->getName();
521 char* fontname = gstr==0?0:gstr->getCString();
525 sprintf(buf, "UFONT%d", r->num);
528 return strdup(fontname);
531 static char*getFontName(GfxFont*font)
533 char*fontid = getFontID(font);
535 char* plus = strchr(fontid, '+');
536 if(plus && plus < &fontid[strlen(fontid)-1]) {
537 fontname = strdup(plus+1);
539 fontname = strdup(fontid);
545 static char mybuf[1024];
546 static char* gfxstate2str(GfxState *state)
550 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
557 if(state->getX1()!=0.0)
558 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
559 if(state->getY1()!=0.0)
560 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
561 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
562 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
563 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
564 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
565 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
566 state->getFillColor()->c[0], state->getFillColor()->c[1]);
567 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
568 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
569 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
570 state->getFillColor()->c[0], state->getFillColor()->c[1],
571 state->getFillColor()->c[2], state->getFillColor()->c[3],
572 state->getFillColor()->c[4], state->getFillColor()->c[5],
573 state->getFillColor()->c[6], state->getFillColor()->c[7]);
574 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
575 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
576 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
577 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
578 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
579 state->getFillRGB(&rgb);
580 if(rgb.r || rgb.g || rgb.b)
581 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
582 state->getStrokeRGB(&rgb);
583 if(rgb.r || rgb.g || rgb.b)
584 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
585 if(state->getFillColorSpace()->getNComps()>1)
586 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
587 if(state->getStrokeColorSpace()->getNComps()>1)
588 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
589 if(state->getFillPattern())
590 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
591 if(state->getStrokePattern())
592 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
594 if(state->getFillOpacity()!=1.0)
595 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
596 if(state->getStrokeOpacity()!=1.0)
597 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
599 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
604 state->getLineDash(&dash, &length, &start);
608 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
609 for(t=0;t<length;t++) {
610 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
612 bufpos+=sprintf(bufpos,"]");
615 if(state->getFlatness()!=1)
616 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
617 if(state->getLineJoin()!=0)
618 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
619 if(state->getLineJoin()!=0)
620 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
621 if(state->getLineJoin()!=0)
622 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
624 if(state->getFont() && getFontID(state->getFont()))
625 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
626 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
627 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
628 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
629 if(state->getCharSpace())
630 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
631 if(state->getWordSpace())
632 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
633 if(state->getHorizScaling()!=1.0)
634 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
635 if(state->getLeading())
636 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
638 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
639 if(state->getRender())
640 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
641 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
642 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
643 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
644 if(state->getLineX())
645 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
646 if(state->getLineY())
647 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
648 bufpos+=sprintf(bufpos," ");
652 static void dumpFontInfo(char*loglevel, GfxFont*font);
653 static int lastdumps[1024];
654 static int lastdumppos = 0;
659 static void showFontError(GfxFont*font, int nr)
663 for(t=0;t<lastdumppos;t++)
664 if(lastdumps[t] == r->num)
668 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
669 lastdumps[lastdumppos++] = r->num;
671 msg("<warning> The following font caused problems:");
673 msg("<warning> The following font caused problems (substituting):");
675 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
676 dumpFontInfo("<warning>", font);
679 static void dumpFontInfo(char*loglevel, GfxFont*font)
681 char* id = getFontID(font);
682 char* name = getFontName(font);
683 Ref* r=font->getID();
684 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
686 GString*gstr = font->getTag();
688 msg("%s| Tag: %s\n", loglevel, id);
690 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
692 GfxFontType type=font->getType();
694 case fontUnknownType:
695 msg("%s| Type: unknown\n",loglevel);
698 msg("%s| Type: 1\n",loglevel);
701 msg("%s| Type: 1C\n",loglevel);
704 msg("%s| Type: 3\n",loglevel);
707 msg("%s| Type: TrueType\n",loglevel);
710 msg("%s| Type: CIDType0\n",loglevel);
713 msg("%s| Type: CIDType0C\n",loglevel);
716 msg("%s| Type: CIDType2\n",loglevel);
721 GBool embedded = font->getEmbeddedFontID(&embRef);
723 if(font->getEmbeddedFontName()) {
724 embeddedName = font->getEmbeddedFontName()->getCString();
727 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
729 gstr = font->getExtFontFile();
731 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
733 // Get font descriptor flags.
734 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
735 if(font->isSerif()) msg("%s| is serif\n", loglevel);
736 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
737 if(font->isItalic()) msg("%s| is italic\n", loglevel);
738 if(font->isBold()) msg("%s| is bold\n", loglevel);
744 //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");}
745 //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");}
748 void dump_outline(gfxline_t*line)
751 if(line->type == gfx_moveTo) {
752 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
753 } else if(line->type == gfx_lineTo) {
754 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
755 } else if(line->type == gfx_splineTo) {
756 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
762 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey)
764 int num = path->getNumSubpaths();
767 double lastx=0,lasty=0,posx=0,posy=0;
770 msg("<warning> empty path");
774 gfxdrawer_target_gfxline(&draw);
776 for(t = 0; t < num; t++) {
777 GfxSubpath *subpath = path->getSubpath(t);
778 int subnum = subpath->getNumPoints();
779 double bx=0,by=0,cx=0,cy=0;
781 for(s=0;s<subnum;s++) {
784 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
789 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
790 draw.lineTo(&draw, lastx, lasty);
792 draw.moveTo(&draw, x,y);
797 } else if(subpath->getCurve(s) && cpos==0) {
801 } else if(subpath->getCurve(s) && cpos==1) {
809 draw.lineTo(&draw, x,y);
811 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y, 0.05);
818 /* fix non-closed lines */
819 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
820 draw.lineTo(&draw, lastx, lasty);
822 gfxline_t*result = (gfxline_t*)draw.result(&draw);
826 /*----------------------------------------------------------------------------
827 * Primitive Graphic routines
828 *----------------------------------------------------------------------------*/
830 void SWFOutputDev::stroke(GfxState *state)
832 GfxPath * path = state->getPath();
833 gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex, user_movey);
834 strokeGfxline(state, line);
838 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
840 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
841 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
842 double miterLimit = state->getMiterLimit();
843 double width = state->getTransformedLineWidth();
846 double opaq = state->getStrokeOpacity();
848 state->getFillRGB(&rgb);
850 state->getStrokeRGB(&rgb);
852 col.r = (unsigned char)(rgb.r*255);
853 col.g = (unsigned char)(rgb.g*255);
854 col.b = (unsigned char)(rgb.b*255);
855 col.a = (unsigned char)(opaq*255);
857 gfx_capType capType = gfx_capRound;
858 if(lineCap == 0) capType = gfx_capButt;
859 else if(lineCap == 1) capType = gfx_capRound;
860 else if(lineCap == 2) capType = gfx_capSquare;
862 gfx_joinType joinType = gfx_joinRound;
863 if(lineJoin == 0) joinType = gfx_joinMiter;
864 else if(lineJoin == 1) joinType = gfx_joinRound;
865 else if(lineJoin == 2) joinType = gfx_joinBevel;
868 double dashphase = 0;
870 state->getLineDash(&ldash, &dashnum, &dashphase);
874 if(dashnum && ldash) {
875 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
879 msg("<trace> %d dashes", dashnum);
880 msg("<trace> | phase: %f", dashphase);
881 for(t=0;t<dashnum;t++) {
883 msg("<trace> | d%-3d: %f", t, ldash[t]);
886 if(getLogLevel() >= LOGLEVEL_TRACE) {
890 line2 = gfxtool_dash_line(line, dash, dashphase);
893 msg("<trace> After dashing:");
896 if(getLogLevel() >= LOGLEVEL_TRACE) {
898 state->getStrokeGray(&gray);
899 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n",
901 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
902 lineCap==0?"butt": (lineJoin==1?"round":"square"),
904 col.r,col.g,col.b,col.a,
910 //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
911 output->stroke(output, line, width, &col, capType, joinType, miterLimit);
917 gfxcolor_t getFillColor(GfxState * state)
920 double opaq = state->getFillOpacity();
921 state->getFillRGB(&rgb);
923 col.r = (unsigned char)(rgb.r*255);
924 col.g = (unsigned char)(rgb.g*255);
925 col.b = (unsigned char)(rgb.b*255);
926 col.a = (unsigned char)(opaq*255);
930 void SWFOutputDev::fillGfxLine(GfxState *state, gfxline_t*line)
932 gfxcolor_t col = getFillColor(state);
934 if(getLogLevel() >= LOGLEVEL_TRACE) {
935 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
938 output->fill(output, line, &col);
940 void SWFOutputDev::fill(GfxState *state)
942 GfxPath * path = state->getPath();
943 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
944 fillGfxLine(state, line);
947 void SWFOutputDev::eoFill(GfxState *state)
949 GfxPath * path = state->getPath();
950 gfxcolor_t col = getFillColor(state);
952 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
954 if(getLogLevel() >= LOGLEVEL_TRACE) {
955 msg("<trace> eofill\n");
959 output->fill(output, line, &col);
963 void SWFOutputDev::clip(GfxState *state)
965 GfxPath * path = state->getPath();
966 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
967 clipToGfxLine(state, line);
971 void SWFOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line)
973 if(getLogLevel() >= LOGLEVEL_TRACE) {
974 msg("<trace> clip\n");
978 output->startclip(output, line);
979 states[statepos].clipping++;
981 void SWFOutputDev::eoClip(GfxState *state)
983 GfxPath * path = state->getPath();
984 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
986 if(getLogLevel() >= LOGLEVEL_TRACE) {
987 msg("<trace> eoclip\n");
991 output->startclip(output, line);
992 states[statepos].clipping++;
996 void SWFOutputDev::endframe()
999 output->endclip(output);
1003 output->endpage(output);
1006 void SWFOutputDev::finish()
1008 if(outer_clip_box) {
1010 output->endclip(output);
1015 this->result = output->finish(output);
1016 free(output);output=0;
1020 int SWFOutputDev::save(char*filename)
1023 return result->save(result, filename);
1025 void* SWFOutputDev::get(char*name)
1028 return result->get(result, name);
1031 SWFOutputDev::~SWFOutputDev()
1036 this->result->destroy(this->result);
1041 free(this->pages); this->pages = 0;
1044 fontlist_t*l = this->fontlist;
1046 fontlist_t*next = l->next;
1048 gfxfont_free(l->font);
1056 GBool SWFOutputDev::upsideDown()
1060 GBool SWFOutputDev::useDrawChar()
1064 GBool SWFOutputDev::useGradients()
1068 msg("<notice> File contains gradients");
1074 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
1075 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
1077 #define RENDER_FILL 0
1078 #define RENDER_STROKE 1
1079 #define RENDER_FILLSTROKE 2
1080 #define RENDER_INVISIBLE 3
1081 #define RENDER_CLIP 4
1083 static char tmp_printstr[4096];
1084 char* makeStringPrintable(char*str)
1086 int len = strlen(str);
1093 for(t=0;t<len;t++) {
1098 tmp_printstr[t] = c;
1101 tmp_printstr[len++] = '.';
1102 tmp_printstr[len++] = '.';
1103 tmp_printstr[len++] = '.';
1105 tmp_printstr[len] = 0;
1106 return tmp_printstr;
1110 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
1114 for(t=0;t<font->num_glyphs;t++) {
1115 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
1116 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1120 /* if we didn't find the character, maybe
1121 we can find the capitalized version */
1122 for(t=0;t<font->num_glyphs;t++) {
1123 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
1124 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1130 /* try to use the unicode id */
1131 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
1132 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
1133 return font->unicode2glyph[u];
1136 /* we don't need to "draw" space characters, so don't overdo the search
1137 for a matching glyph */
1138 if(charname && !strcasecmp(charname, "space"))
1141 if(charnr>=0 && charnr<font->num_glyphs) {
1142 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1150 void SWFOutputDev::beginString(GfxState *state, GString *s)
1152 int render = state->getRender();
1153 if(current_text_stroke) {
1154 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
1157 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
1158 double m11,m21,m12,m22;
1159 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
1160 state->getFontTransMat(&m11, &m12, &m21, &m22);
1161 m11 *= state->getHorizScaling();
1162 m21 *= state->getHorizScaling();
1164 this->current_font_matrix.m00 = m11 / 1024.0;
1165 this->current_font_matrix.m01 = m12 / 1024.0;
1166 this->current_font_matrix.m10 = -m21 / 1024.0;
1167 this->current_font_matrix.m11 = -m22 / 1024.0;
1168 this->current_font_matrix.tx = 0;
1169 this->current_font_matrix.ty = 0;
1171 gfxmatrix_t m = this->current_font_matrix;
1173 /*if(render != 3 && render != 0)
1174 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1175 states[statepos].textRender = render;
1178 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1179 double dx, double dy,
1180 double originX, double originY,
1181 CharCode c, Unicode *_u, int uLen)
1183 int render = state->getRender();
1184 // check for invisible text -- this is used by Acrobat Capture
1186 msg("<debug> Ignoring invisible text: char %d at %f,%f", c, x, y);
1190 if(states[statepos].textRender != render)
1191 msg("<error> Internal error: drawChar.render!=beginString.render");
1193 gfxcolor_t col = getFillColor(state);
1195 Gushort *CIDToGIDMap = 0;
1196 GfxFont*font = state->getFont();
1198 if(font->getType() == fontType3) {
1199 /* type 3 chars are passed as graphics */
1200 msg("<debug> type3 char at %f/%f", x, y);
1211 /* find out char name from unicode index
1212 TODO: should be precomputed
1214 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1215 if(nameToUnicodeTab[t].u == u) {
1216 name = nameToUnicodeTab[t].name;
1223 if(font->isCIDFont()) {
1224 GfxCIDFont*cfont = (GfxCIDFont*)font;
1226 if(font->getType() == fontCIDType2)
1227 CIDToGIDMap = cfont->getCIDToGID();
1230 font8 = (Gfx8BitFont*)font;
1231 char**enc=font8->getEncoding();
1232 if(enc && enc[c] && strcasecmp(enc[c], "space")) {
1237 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);
1240 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);
1246 charid = getGfxCharID(current_gfxfont, c, name, u);
1248 charid = getGfxCharID(current_gfxfont, c, 0, -1);
1250 /* multiple unicodes- should usually map to a ligature.
1251 if the ligature doesn't exist, we need to draw
1252 the characters one-by-one. */
1254 msg("<warning> ligature %d missing in font %s\n", c, current_font_id);
1255 for(t=0;t<uLen;t++) {
1256 drawChar(state, x, y, dx, dy, originX, originY, c, _u+t, 1);
1263 if(!name || strcasecmp(name, "space")) {
1264 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1265 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1270 gfxmatrix_t m = this->current_font_matrix;
1271 state->transform(x, y, &m.tx, &m.ty);
1275 if(render == RENDER_FILL) {
1276 output->drawchar(output, current_font_id, charid, &col, &m);
1278 msg("<debug> Drawing glyph %d as shape", charid);
1280 msg("<notice> Some texts will be rendered as shape");
1283 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1284 gfxline_t*tglyph = gfxline_clone(glyph);
1285 gfxline_transform(tglyph, &m);
1286 if((render&3) != RENDER_INVISIBLE) {
1287 gfxline_t*add = gfxline_clone(tglyph);
1288 current_text_stroke = gfxline_append(current_text_stroke, add);
1290 if(render&RENDER_CLIP) {
1291 gfxline_t*add = gfxline_clone(tglyph);
1292 current_text_clip = gfxline_append(current_text_clip, add);
1294 gfxline_free(tglyph);
1298 void SWFOutputDev::endString(GfxState *state)
1300 int render = state->getRender();
1301 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1302 if(states[statepos].textRender != render)
1303 msg("<error> Internal error: drawChar.render!=beginString.render");
1305 if(current_text_stroke) {
1306 /* fillstroke and stroke text rendering objects we can process right
1307 now (as there may be texts of other rendering modes in this
1308 text object)- clipping objects have to wait until endTextObject,
1310 if((render&3) == RENDER_FILL) {
1311 fillGfxLine(state, current_text_stroke);
1312 gfxline_free(current_text_stroke);
1313 current_text_stroke = 0;
1314 } else if((render&3) == RENDER_FILLSTROKE) {
1315 fillGfxLine(state, current_text_stroke);
1316 strokeGfxline(state, current_text_stroke);
1317 gfxline_free(current_text_stroke);
1318 current_text_stroke = 0;
1319 } else if((render&3) == RENDER_STROKE) {
1320 strokeGfxline(state, current_text_stroke);
1321 gfxline_free(current_text_stroke);
1322 current_text_stroke = 0;
1327 void SWFOutputDev::endTextObject(GfxState *state)
1329 int render = state->getRender();
1330 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1331 if(states[statepos].textRender != render)
1332 msg("<error> Internal error: drawChar.render!=beginString.render");
1334 if(current_text_clip) {
1335 clipToGfxLine(state, current_text_clip);
1336 gfxline_free(current_text_clip);
1337 current_text_clip = 0;
1341 /* the logic seems to be as following:
1342 first, beginType3Char is called, with the charcode and the coordinates.
1343 if this function returns true, it already knew about the char and has now drawn it.
1344 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1345 the all draw operations until endType3Char are part of the char (which in this moment is
1346 at the position first passed to beginType3Char). the char ends with endType3Char.
1348 The drawing operations between beginType3Char and endType3Char are somewhat different to
1349 the normal ones. For example, the fillcolor equals the stroke color.
1352 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1354 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1356 /* the character itself is going to be passed using the draw functions */
1357 return gFalse; /* gTrue= is_in_cache? */
1360 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1361 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1363 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1364 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1368 void SWFOutputDev::endType3Char(GfxState *state)
1371 msg("<debug> endType3Char");
1374 void SWFOutputDev::startFrame(int width, int height)
1376 output->startpage(output, width, height);
1379 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1381 this->currentpage = pageNum;
1383 int rot = doc->getPageRotate(1);
1386 gfxline_t clippath[5];
1388 white.r = white.g = white.b = white.a = 255;
1390 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1391 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1392 Use CropBox, not MediaBox, as page size
1399 state->transform(crop_x1,crop_y1,&x1,&y1); //x1 += user_movex; y1 += user_movey;
1400 state->transform(crop_x2,crop_y2,&x2,&y2); //x2 += user_movex; y2 += user_movey;
1402 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1403 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1406 /* apply user clip box */
1407 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1408 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1409 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1410 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1411 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1414 //msg("<verbose> Bounding box is (%f,%f)-(%f,%f) [shifted by %d/%d]", x1,y1,x2,y2, user_movex, user_movey);
1416 if(outer_clip_box) {
1417 output->endclip(output);
1421 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);
1423 msg("<verbose> page is rotated %d degrees\n", rot);
1425 clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1426 clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1427 clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1428 clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1429 clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1430 output->startclip(output, clippath); outer_clip_box = 1;
1431 output->fill(output, clippath, &white);
1434 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1436 msg("<debug> drawlink\n");
1437 double x1, y1, x2, y2, w;
1439 gfxline_t points[5];
1443 link->getBorder(&x1, &y1, &x2, &y2, &w);
1445 link->getRect(&x1, &y1, &x2, &y2);
1450 cvtUserToDev(x1, y1, &x, &y);
1451 points[0].type = gfx_moveTo;
1452 points[0].x = points[4].x = x + user_movex;
1453 points[0].y = points[4].y = y + user_movey;
1454 points[0].next = &points[1];
1455 cvtUserToDev(x2, y1, &x, &y);
1456 points[1].type = gfx_lineTo;
1457 points[1].x = x + user_movex;
1458 points[1].y = y + user_movey;
1459 points[1].next = &points[2];
1460 cvtUserToDev(x2, y2, &x, &y);
1461 points[2].type = gfx_lineTo;
1462 points[2].x = x + user_movex;
1463 points[2].y = y + user_movey;
1464 points[2].next = &points[3];
1465 cvtUserToDev(x1, y2, &x, &y);
1466 points[3].type = gfx_lineTo;
1467 points[3].x = x + user_movex;
1468 points[3].y = y + user_movey;
1469 points[3].next = &points[4];
1470 cvtUserToDev(x1, y1, &x, &y);
1471 points[4].type = gfx_lineTo;
1472 points[4].x = x + user_movex;
1473 points[4].y = y + user_movey;
1476 LinkAction*action=link->getAction();
1483 switch(action->getKind())
1487 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1488 LinkDest *dest=NULL;
1489 if (ha->getDest()==NULL)
1490 dest=catalog->findDest(ha->getNamedDest());
1491 else dest=ha->getDest();
1493 if (dest->isPageRef()){
1494 Ref pageref=dest->getPageRef();
1495 page=catalog->findPage(pageref.num,pageref.gen);
1497 else page=dest->getPageNum();
1498 sprintf(buf, "%d", page);
1505 LinkGoToR*l = (LinkGoToR*)action;
1506 GString*g = l->getNamedDest();
1508 s = strdup(g->getCString());
1513 LinkNamed*l = (LinkNamed*)action;
1514 GString*name = l->getName();
1516 s = strdup(name->lowerCase()->getCString());
1517 named = name->getCString();
1520 if(strstr(s, "next") || strstr(s, "forward"))
1522 page = currentpage + 1;
1524 else if(strstr(s, "prev") || strstr(s, "back"))
1526 page = currentpage - 1;
1528 else if(strstr(s, "last") || strstr(s, "end"))
1530 if(pages && pagepos>0)
1531 page = pages[pagepos-1];
1533 else if(strstr(s, "first") || strstr(s, "top"))
1541 case actionLaunch: {
1543 LinkLaunch*l = (LinkLaunch*)action;
1544 GString * str = new GString(l->getFileName());
1545 str->append(l->getParams());
1546 s = strdup(str->getCString());
1552 LinkURI*l = (LinkURI*)action;
1553 GString*g = l->getURI();
1555 url = g->getCString();
1560 case actionUnknown: {
1562 LinkUnknown*l = (LinkUnknown*)action;
1567 msg("<error> Unknown link type!\n");
1571 if(!s) s = strdup("-?-");
1573 if(!linkinfo && (page || url))
1575 msg("<notice> File contains links");
1583 for(t=1;t<=pagepos;t++) {
1584 if(pages[t]==page) {
1591 sprintf(buf, "page%d", t);
1592 output->drawlink(output, points, buf);
1594 msg("<warning> Invalid link to page %d", page);
1599 output->drawlink(output, points, url);
1602 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1606 void SWFOutputDev::saveState(GfxState *state) {
1607 msg("<trace> saveState\n");
1610 msg("<error> Too many nested states in pdf.");
1614 states[statepos].clipping = 0; //? shouldn't this be the current value?
1615 states[statepos].textRender = states[statepos-1].textRender;
1618 void SWFOutputDev::restoreState(GfxState *state) {
1619 msg("<trace> restoreState\n");
1621 while(states[statepos].clipping) {
1622 output->endclip(output);
1623 states[statepos].clipping--;
1628 char* SWFOutputDev::searchFont(char*name)
1632 int is_standard_font = 0;
1634 msg("<verbose> SearchFont(%s)", name);
1636 /* see if it is a pdf standard font */
1637 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1639 if(!strcmp(name, pdf2t1map[i].pdffont))
1641 name = pdf2t1map[i].filename;
1642 is_standard_font = 1;
1646 /* look in all font files */
1647 for(i=0;i<fontnum;i++)
1649 if(strstr(fonts[i].filename, name))
1651 if(!fonts[i].used) {
1654 if(!is_standard_font)
1655 msg("<notice> Using %s for %s", fonts[i].filename, name);
1657 return strdup(fonts[i].filename);
1663 void SWFOutputDev::updateLineWidth(GfxState *state)
1665 double width = state->getTransformedLineWidth();
1666 //swfoutput_setlinewidth(&output, width);
1669 void SWFOutputDev::updateLineCap(GfxState *state)
1671 int c = state->getLineCap();
1674 void SWFOutputDev::updateLineJoin(GfxState *state)
1676 int j = state->getLineJoin();
1679 void SWFOutputDev::updateFillColor(GfxState *state)
1682 double opaq = state->getFillOpacity();
1683 state->getFillRGB(&rgb);
1685 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1688 void SWFOutputDev::updateStrokeColor(GfxState *state)
1691 double opaq = state->getStrokeOpacity();
1692 state->getStrokeRGB(&rgb);
1693 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1696 void FoFiWrite(void *stream, char *data, int len)
1698 fwrite(data, len, 1, (FILE*)stream);
1701 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1703 char*tmpFileName = NULL;
1709 Object refObj, strObj;
1711 tmpFileName = mktmpname(namebuf);
1714 ret = font->getEmbeddedFontID(&embRef);
1716 msg("<verbose> Didn't get embedded font id");
1717 /* not embedded- the caller should now search the font
1718 directories for this font */
1722 f = fopen(tmpFileName, "wb");
1724 msg("<error> Couldn't create temporary Type 1 font file");
1728 /*if(font->isCIDFont()) {
1729 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1730 GString c = cidFont->getCollection();
1731 msg("<notice> Collection: %s", c.getCString());
1734 //if (font->getType() == fontType1C) {
1735 if (0) { //font->getType() == fontType1C) {
1736 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1738 msg("<error> Couldn't read embedded font file");
1742 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1744 cvt->convertToType1(f);
1746 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1748 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1750 //cvt->convertToCIDType0("test", f);
1751 //cvt->convertToType0("test", f);
1754 } else if(font->getType() == fontTrueType) {
1755 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1756 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1758 msg("<error> Couldn't read embedded font file");
1762 TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1765 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1766 cvt->writeTTF(FoFiWrite, f);
1771 font->getEmbeddedFontID(&embRef);
1772 refObj.initRef(embRef.num, embRef.gen);
1773 refObj.fetch(ref, &strObj);
1775 strObj.streamReset();
1780 f4[t] = strObj.streamGetChar();
1781 f4c[t] = (char)f4[t];
1786 if(!strncmp(f4c, "true", 4)) {
1787 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1788 Change this on the fly */
1789 f4[0] = f4[2] = f4[3] = 0;
1797 while ((c = strObj.streamGetChar()) != EOF) {
1801 strObj.streamClose();
1806 return strdup(tmpFileName);
1809 char* searchForSuitableFont(GfxFont*gfxFont)
1811 char*name = getFontName(gfxFont);
1815 if(!config_use_fontconfig)
1818 #ifdef HAVE_FONTCONFIG
1819 FcPattern *pattern, *match;
1823 static int fcinitcalled = false;
1825 msg("<debug> searchForSuitableFont(%s)", name);
1827 // call init ony once
1828 if (!fcinitcalled) {
1829 msg("<debug> Initializing FontConfig...");
1830 fcinitcalled = true;
1832 msg("<debug> FontConfig Initialization failed. Disabling.");
1833 config_use_fontconfig = 0;
1836 msg("<debug> ...initialized FontConfig");
1839 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1840 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1841 if (gfxFont->isItalic()) // check for italic
1842 msg("<debug> FontConfig: Adding Italic Slant");
1843 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1844 if (gfxFont->isBold()) // check for bold
1845 msg("<debug> FontConfig: Adding Bold Weight");
1846 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1848 msg("<debug> FontConfig: Try to match...");
1849 // configure and match using the original font name
1850 FcConfigSubstitute(0, pattern, FcMatchPattern);
1851 FcDefaultSubstitute(pattern);
1852 match = FcFontMatch(0, pattern, &result);
1854 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1855 msg("<debug> FontConfig: family=%s", (char*)v);
1856 // if we get an exact match
1857 if (strcmp((char *)v, name) == 0) {
1858 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1859 filename = strdup((char*)v); // mem leak
1860 char *nfn = strrchr(filename, '/');
1861 if(nfn) fontname = strdup(nfn+1);
1862 else fontname = filename;
1864 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1866 // initialize patterns
1867 FcPatternDestroy(pattern);
1868 FcPatternDestroy(match);
1870 // now match against serif etc.
1871 if (gfxFont->isSerif()) {
1872 msg("<debug> FontConfig: Create Serif Family Pattern");
1873 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1874 } else if (gfxFont->isFixedWidth()) {
1875 msg("<debug> FontConfig: Create Monospace Family Pattern");
1876 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1878 msg("<debug> FontConfig: Create Sans Family Pattern");
1879 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1883 if (gfxFont->isItalic()) {
1884 msg("<debug> FontConfig: Adding Italic Slant");
1885 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1888 if (gfxFont->isBold()) {
1889 msg("<debug> FontConfig: Adding Bold Weight");
1890 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1893 msg("<debug> FontConfig: Try to match... (2)");
1894 // configure and match using serif etc
1895 FcConfigSubstitute (0, pattern, FcMatchPattern);
1896 FcDefaultSubstitute (pattern);
1897 match = FcFontMatch (0, pattern, &result);
1899 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1900 filename = strdup((char*)v); // mem leak
1901 char *nfn = strrchr(filename, '/');
1902 if(nfn) fontname = strdup(nfn+1);
1903 else fontname = filename;
1905 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1909 //printf("FONTCONFIG: pattern");
1910 //FcPatternPrint(pattern);
1911 //printf("FONTCONFIG: match");
1912 //FcPatternPrint(match);
1914 FcPatternDestroy(pattern);
1915 FcPatternDestroy(match);
1917 pdfswf_addfont(filename);
1924 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1926 char*fontname = 0, *filename = 0;
1927 msg("<notice> substituteFont(%s)", oldname);
1929 if(!(fontname = searchForSuitableFont(gfxFont))) {
1930 fontname = "Times-Roman";
1932 filename = searchFont(fontname);
1934 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1938 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1939 msg("<fatal> Too many fonts in file.");
1943 substitutesource[substitutepos] = strdup(oldname); //mem leak
1944 substitutetarget[substitutepos] = fontname;
1945 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1948 return strdup(filename); //mem leak
1951 void unlinkfont(char* filename)
1958 if(!strncmp(&filename[l-4],".afm",4)) {
1959 memcpy(&filename[l-4],".pfb",4);
1961 memcpy(&filename[l-4],".pfa",4);
1963 memcpy(&filename[l-4],".afm",4);
1966 if(!strncmp(&filename[l-4],".pfa",4)) {
1967 memcpy(&filename[l-4],".afm",4);
1969 memcpy(&filename[l-4],".pfa",4);
1972 if(!strncmp(&filename[l-4],".pfb",4)) {
1973 memcpy(&filename[l-4],".afm",4);
1975 memcpy(&filename[l-4],".pfb",4);
1980 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1986 int SWFOutputDev::setGfxFont(char*id, char*filename, double maxSize)
1989 fontlist_t*last=0,*l = this->fontlist;
1991 /* TODO: should this be part of the state? */
1994 if(!strcmp(l->id, id)) {
1995 current_font_id = l->id;
1996 current_gfxfont = l->font;
1998 output->addfont(output, id, current_gfxfont);
2003 if(!filename) return 0;
2005 /* A font size of e.g. 9 means the font will be scaled down by
2006 1024 and scaled up by 9. So to have a maximum error of 1/20px,
2007 we have to divide 0.05 by (fontsize/1024)
2009 double quality = (1024 * 0.05) / maxSize;
2011 msg("<verbose> Loading %s...", filename);
2012 font = gfxfont_load(filename, quality);
2013 msg("<verbose> Font %s loaded successfully", filename);
2017 l->filename = strdup(filename);
2020 current_font_id = l->id;
2021 current_gfxfont = l->font;
2027 output->addfont(output, id, current_gfxfont);
2031 void SWFOutputDev::updateFont(GfxState *state)
2033 GfxFont*gfxFont = state->getFont();
2038 char * fontid = getFontID(gfxFont);
2039 double maxSize = 1.0;
2042 maxSize = this->info->getMaximumFontSize(fontid);
2046 /* first, look if we substituted this font before-
2047 this way, we don't initialize the T1 Fonts
2049 for(t=0;t<substitutepos;t++) {
2050 if(!strcmp(fontid, substitutesource[t])) {
2051 free(fontid);fontid=0;
2052 fontid = strdup(substitutetarget[t]);
2057 /* second, see if this is a font which was used before-
2058 if so, we are done */
2059 if(setGfxFont(fontid, 0, 0)) {
2063 /* if(swfoutput_queryfont(&output, fontid))
2064 swfoutput_setfont(&output, fontid, 0);
2066 msg("<debug> updateFont(%s) [cached]", fontid);
2070 // look for Type 3 font
2071 if (gfxFont->getType() == fontType3) {
2073 type3Warning = gTrue;
2074 showFontError(gfxFont, 2);
2080 /* now either load the font, or find a substitution */
2083 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
2088 (gfxFont->getType() == fontType1 ||
2089 gfxFont->getType() == fontType1C ||
2090 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
2091 gfxFont->getType() == fontTrueType ||
2092 gfxFont->getType() == fontCIDType2
2095 fileName = writeEmbeddedFontToFile(xref, gfxFont);
2096 if(!fileName) showFontError(gfxFont,0);
2099 char * fontname = getFontName(gfxFont);
2100 fileName = searchFont(fontname);
2101 if(!fileName) showFontError(gfxFont,0);
2105 char * fontname = getFontName(gfxFont);
2106 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
2109 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into %s", fontname, lastfontdir);
2111 msg("<warning> Try specifying one or more font directories");
2113 fileName = substituteFont(gfxFont, fontid);
2114 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
2115 msg("<notice> Font is now %s (%s)", fontid, fileName);
2119 msg("<error> Couldn't set font %s\n", fontid);
2124 msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
2125 dumpFontInfo("<verbose>", gfxFont);
2127 //swfoutput_setfont(&output, fontid, fileName);
2129 if(!setGfxFont(fontid, 0, 0)) {
2130 setGfxFont(fontid, fileName, maxSize);
2134 unlinkfont(fileName);
2142 #define SQR(x) ((x)*(x))
2144 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
2146 if((newwidth<2 || newheight<2) ||
2147 (width<=newwidth || height<=newheight))
2149 unsigned char*newdata;
2151 newdata= (unsigned char*)malloc(newwidth*newheight);
2153 double fx = (double)(width)/newwidth;
2154 double fy = (double)(height)/newheight;
2156 int blocksize = (int)(8192/(fx*fy));
2157 int r = 8192*256/palettesize;
2158 for(x=0;x<newwidth;x++) {
2159 double ex = px + fx;
2160 int fromx = (int)px;
2162 int xweight1 = (int)(((fromx+1)-px)*256);
2163 int xweight2 = (int)((ex-tox)*256);
2165 for(y=0;y<newheight;y++) {
2166 double ey = py + fy;
2167 int fromy = (int)py;
2169 int yweight1 = (int)(((fromy+1)-py)*256);
2170 int yweight2 = (int)((ey-toy)*256);
2173 for(xx=fromx;xx<=tox;xx++)
2174 for(yy=fromy;yy<=toy;yy++) {
2175 int b = 1-data[width*yy+xx];
2177 if(xx==fromx) weight = (weight*xweight1)/256;
2178 if(xx==tox) weight = (weight*xweight2)/256;
2179 if(yy==fromy) weight = (weight*yweight1)/256;
2180 if(yy==toy) weight = (weight*yweight2)/256;
2183 //if(a) a=(palettesize-1)*r/blocksize;
2184 newdata[y*newwidth+x] = (a*blocksize)/r;
2192 #define IMAGE_TYPE_JPEG 0
2193 #define IMAGE_TYPE_LOSSLESS 1
2195 static void drawimage(gfxdevice_t*dev, gfxcolor_t* data, int sizex,int sizey,
2196 double x1,double y1,
2197 double x2,double y2,
2198 double x3,double y3,
2199 double x4,double y4, int type)
2201 gfxcolor_t*newpic=0;
2203 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2204 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2206 gfxline_t p1,p2,p3,p4,p5;
2207 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2208 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2209 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2210 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2211 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2213 {p1.x = (int)(p1.x*20)/20.0;
2214 p1.y = (int)(p1.y*20)/20.0;
2215 p2.x = (int)(p2.x*20)/20.0;
2216 p2.y = (int)(p2.y*20)/20.0;
2217 p3.x = (int)(p3.x*20)/20.0;
2218 p3.y = (int)(p3.y*20)/20.0;
2219 p4.x = (int)(p4.x*20)/20.0;
2220 p4.y = (int)(p4.y*20)/20.0;
2221 p5.x = (int)(p5.x*20)/20.0;
2222 p5.y = (int)(p5.y*20)/20.0;
2229 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2230 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2235 img.data = (gfxcolor_t*)data;
2239 if(type == IMAGE_TYPE_JPEG)
2240 /* TODO: pass image_dpi to device instead */
2241 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2243 dev->fillbitmap(dev, &p1, &img, &m, 0);
2246 void drawimagejpeg(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2247 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2249 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2252 void drawimagelossless(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2253 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2255 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2259 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2260 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2261 GBool inlineImg, int mask, int*maskColors)
2266 double x1,y1,x2,y2,x3,y3,x4,y4;
2267 ImageStream *imgStr;
2274 ncomps = colorMap->getNumPixelComps();
2275 bits = colorMap->getBits();
2277 imgStr = new ImageStream(str, width, ncomps,bits);
2280 if(!width || !height || (height<=1 && width<=1))
2282 msg("<verbose> Ignoring %d by %d image", width, height);
2283 unsigned char buf[8];
2285 for (y = 0; y < height; ++y)
2286 for (x = 0; x < width; ++x) {
2287 imgStr->getPixel(buf);
2293 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1+= user_movey;
2294 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2+= user_movey;
2295 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3+= user_movey;
2296 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4+= user_movey;
2298 if(!pbminfo && !(str->getKind()==strDCT)) {
2300 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2304 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2306 if(!jpeginfo && (str->getKind()==strDCT)) {
2307 msg("<notice> file contains jpeg pictures");
2313 unsigned char buf[8];
2315 unsigned char*pic = new unsigned char[width*height];
2316 gfxcolor_t pal[256];
2318 state->getFillRGB(&rgb);
2320 memset(pal,255,sizeof(pal));
2321 pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
2322 pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
2323 pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
2324 pal[0].a = 255; pal[1].a = 0;
2327 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2328 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2329 for (y = 0; y < height; ++y)
2330 for (x = 0; x < width; ++x)
2332 imgStr->getPixel(buf);
2335 pic[width*y+x] = buf[0];
2338 /* the size of the drawn image is added to the identifier
2339 as the same image may require different bitmaps if displayed
2340 at different sizes (due to antialiasing): */
2343 unsigned char*pic2 = 0;
2346 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2355 height = realheight;
2359 /* make a black/white palette */
2364 float r = 255/(numpalette-1);
2366 for(t=0;t<numpalette;t++) {
2367 pal[t].r = (unsigned char)(255*rgb.r);
2368 pal[t].g = (unsigned char)(255*rgb.g);
2369 pal[t].b = (unsigned char)(255*rgb.b);
2370 pal[t].a = (unsigned char)(t*r);
2374 gfxcolor_t*pic2 = new gfxcolor_t[width*height];
2375 for (y = 0; y < height; ++y) {
2376 for (x = 0; x < width; ++x) {
2377 pic2[width*y+x] = pal[pic[y*width+x]];
2380 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2389 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2390 gfxcolor_t*pic=new gfxcolor_t[width*height];
2391 for (y = 0; y < height; ++y) {
2392 for (x = 0; x < width; ++x) {
2393 imgStr->getPixel(pixBuf);
2394 colorMap->getRGB(pixBuf, &rgb);
2395 pic[width*y+x].r = (unsigned char)(rgb.r * 255 + 0.5);
2396 pic[width*y+x].g = (unsigned char)(rgb.g * 255 + 0.5);
2397 pic[width*y+x].b = (unsigned char)(rgb.b * 255 + 0.5);
2398 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2401 if(str->getKind()==strDCT)
2402 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2404 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2409 gfxcolor_t*pic=new gfxcolor_t[width*height];
2410 gfxcolor_t pal[256];
2412 for(t=0;t<256;t++) {
2414 colorMap->getRGB(pixBuf, &rgb);
2415 /*if(maskColors && *maskColors==t) {
2416 msg("<notice> Color %d is transparent", t);
2417 if (imgData->maskColors) {
2419 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2420 if (pix[i] < imgData->maskColors[2*i] ||
2421 pix[i] > imgData->maskColors[2*i+1]) {
2436 pal[t].r = (unsigned char)(rgb.r * 255 + 0.5);
2437 pal[t].g = (unsigned char)(rgb.g * 255 + 0.5);
2438 pal[t].b = (unsigned char)(rgb.b * 255 + 0.5);
2439 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2442 for (y = 0; y < height; ++y) {
2443 for (x = 0; x < width; ++x) {
2444 imgStr->getPixel(pixBuf);
2445 pic[width*y+x] = pal[pixBuf[0]];
2448 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2456 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2457 int width, int height, GBool invert,
2460 if(states[statepos].textRender & 4) //clipped
2462 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2463 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
2466 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2467 int width, int height, GfxImageColorMap *colorMap,
2468 int *maskColors, GBool inlineImg)
2470 if(states[statepos].textRender & 4) //clipped
2473 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
2474 colorMap?"colorMap":"no colorMap",
2475 maskColors?"maskColors":"no maskColors",
2478 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2479 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2480 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
2483 //SWFOutputDev*output = 0;
2485 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2490 if (infoDict->lookup(key, &obj)->isString()) {
2491 s1 = obj.getString();
2492 if ((s1->getChar(0) & 0xff) == 0xfe &&
2493 (s1->getChar(1) & 0xff) == 0xff) {
2495 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2496 if (s1->getChar(i) == '\0') {
2497 s2->append(s1->getChar(i+1));
2500 s2 = new GString("<unicode>");
2504 printf(fmt, s2->getCString());
2507 printf(fmt, s1->getCString());
2513 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2517 if (infoDict->lookup(key, &obj)->isString()) {
2518 s = obj.getString()->getCString();
2519 if (s[0] == 'D' && s[1] == ':') {
2530 void storeDeviceParameter(char*name, char*value)
2532 parameter_t*p = new parameter_t();
2533 p->name = strdup(name);
2534 p->value = strdup(value);
2536 if(device_config_next) {
2537 device_config_next->next = p;
2538 device_config_next = p;
2541 device_config_next = p;
2545 void pdfswf_setparameter(char*name, char*value)
2547 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2548 if(!strcmp(name, "caplinewidth")) {
2549 caplinewidth = atof(value);
2550 } else if(!strcmp(name, "zoom")) {
2553 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2554 storeDeviceParameter("jpegsubpixels", buf);
2555 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2556 storeDeviceParameter("ppmsubpixels", buf);
2557 } else if(!strcmp(name, "jpegdpi")) {
2559 jpeg_dpi = atoi(value);
2560 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2561 storeDeviceParameter("jpegsubpixels", buf);
2562 } else if(!strcmp(name, "ppmdpi")) {
2564 ppm_dpi = atoi(value);
2565 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2566 storeDeviceParameter("ppmsubpixels", buf);
2567 } else if(!strcmp(name, "forceType0Fonts")) {
2568 forceType0Fonts = atoi(value);
2569 } else if(!strcmp(name, "fontdir")) {
2570 pdfswf_addfontdir(value);
2571 } else if(!strcmp(name, "languagedir")) {
2572 pdfswf_addlanguagedir(value);
2573 } else if(!strcmp(name, "fontconfig")) {
2574 config_use_fontconfig = atoi(value);
2576 storeDeviceParameter(name,value);
2579 void pdfswf_addfont(char*filename)
2582 memset(&f, 0, sizeof(fontfile_t));
2583 f.filename = filename;
2584 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2585 fonts[fontnum++] = f;
2587 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2591 static char* dirseparator()
2600 void pdfswf_addlanguagedir(char*dir)
2603 globalParams = new GlobalParams("");
2605 msg("<notice> Adding %s to language pack directories", dir);
2609 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2610 strcpy(config_file, dir);
2611 strcat(config_file, dirseparator());
2612 strcat(config_file, "add-to-xpdfrc");
2614 fi = fopen(config_file, "rb");
2616 msg("<error> Could not open %s", config_file);
2619 globalParams->parseFile(new GString(config_file), fi);
2623 void pdfswf_addfontdir(char*dirname)
2625 #ifdef HAVE_DIRENT_H
2626 msg("<notice> Adding %s to font directories", dirname);
2627 lastfontdir = strdup(dirname);
2628 DIR*dir = opendir(dirname);
2630 msg("<warning> Couldn't open directory %s\n", dirname);
2635 ent = readdir (dir);
2639 char*name = ent->d_name;
2645 if(!strncasecmp(&name[l-4], ".pfa", 4))
2647 if(!strncasecmp(&name[l-4], ".pfb", 4))
2649 if(!strncasecmp(&name[l-4], ".ttf", 4))
2653 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2654 strcpy(fontname, dirname);
2655 strcat(fontname, dirseparator());
2656 strcat(fontname, name);
2657 msg("<verbose> Adding %s to fonts", fontname);
2658 pdfswf_addfont(fontname);
2663 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2668 typedef struct _pdf_doc_internal
2673 } pdf_doc_internal_t;
2674 typedef struct _pdf_page_internal
2676 } pdf_page_internal_t;
2677 typedef struct _swf_output_internal
2679 SWFOutputDev*outputDev;
2680 } swf_output_internal_t;
2682 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2684 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2685 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2686 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2687 memset(i, 0, sizeof(pdf_doc_internal_t));
2688 pdf_doc->internal = i;
2690 GString *fileName = new GString(filename);
2696 globalParams = new GlobalParams("");
2699 if (userPassword && userPassword[0]) {
2700 userPW = new GString(userPassword);
2704 i->doc = new PDFDoc(fileName, userPW);
2708 if (!i->doc->isOk()) {
2713 i->doc->getDocInfo(&info);
2714 if (info.isDict() &&
2715 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2716 printInfoString(info.getDict(), "Title", "Title: %s\n");
2717 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2718 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2719 printInfoString(info.getDict(), "Author", "Author: %s\n");
2720 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2721 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2722 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2723 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2724 printf("Pages: %d\n", i->doc->getNumPages());
2725 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2726 printf("Encrypted: ");
2727 if (i->doc->isEncrypted()) {
2728 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2729 i->doc->okToPrint() ? "yes" : "no",
2730 i->doc->okToCopy() ? "yes" : "no",
2731 i->doc->okToChange() ? "yes" : "no",
2732 i->doc->okToAddNotes() ? "yes" : "no");
2739 pdf_doc->num_pages = i->doc->getNumPages();
2741 if (i->doc->isEncrypted()) {
2742 if(!i->doc->okToCopy()) {
2743 printf("PDF disallows copying.\n");
2746 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2750 InfoOutputDev*io = new InfoOutputDev();
2752 for(t=1;t<=pdf_doc->num_pages;t++) {
2754 i->doc->displayPage((OutputDev*)io, t, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2756 i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2768 delete globalParams;globalParams=0;
2769 Object::memCheck(stderr);
2774 void pdf_destroy(pdf_doc_t*pdf_doc)
2776 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2778 delete i->doc; i->doc=0;
2781 delete i->info;i->info=0;
2784 free(pdf_doc->internal);pdf_doc->internal=0;
2785 free(pdf_doc);pdf_doc=0;
2788 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2790 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2792 if(page < 1 || page > pdf_doc->num_pages)
2795 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2796 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2797 memset(pi, 0, sizeof(pdf_page_internal_t));
2798 pdf_page->internal = pi;
2800 pdf_page->parent = pdf_doc;
2801 pdf_page->nr = page;
2805 void pdf_page_destroy(pdf_page_t*pdf_page)
2807 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2808 free(pdf_page->internal);pdf_page->internal = 0;
2809 free(pdf_page);pdf_page=0;
2812 swf_output_t* swf_output_init()
2814 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2815 memset(swf_output, 0, sizeof(swf_output_t));
2816 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2817 memset(i, 0, sizeof(swf_output_internal_t));
2818 swf_output->internal = i;
2820 i->outputDev = new SWFOutputDev();
2824 void swf_output_setparameter(swf_output_t*swf, char*name, char*value)
2826 pdfswf_setparameter(name, value);
2829 void swf_output_startframe(swf_output_t*swf, int width, int height)
2831 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2832 i->outputDev->startFrame(width, height);
2835 void swf_output_endframe(swf_output_t*swf)
2837 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2838 i->outputDev->endframe();
2841 void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage)
2843 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2844 SWFOutputDev*o = i->outputDev;
2850 o->pagebuflen = 1024;
2851 o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
2852 memset(o->pages, -1, o->pagebuflen*sizeof(int));
2854 while(pdfpage >= o->pagebuflen)
2856 int oldlen = o->pagebuflen;
2857 o->pagebuflen+=1024;
2858 o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
2859 memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
2862 o->pages[pdfpage] = outputpage;
2863 if(pdfpage>o->pagepos)
2864 o->pagepos = pdfpage;
2867 int swf_output_save(swf_output_t*swf, char*filename)
2869 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2870 int ret = i->outputDev->save(filename);
2874 void* swf_output_get(swf_output_t*swf,char*name)
2876 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2877 void* ret = i->outputDev->get(name);
2881 void swf_output_destroy(swf_output_t*output)
2883 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2884 delete i->outputDev; i->outputDev=0;
2885 free(output->internal);output->internal=0;
2889 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2891 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2892 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2895 msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2900 gfxdevice_t*dev = si->outputDev->output;
2901 dev->setparameter(dev, "protect", "1");
2903 si->outputDev->setInfo(pi->info);
2904 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2906 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2908 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2912 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2914 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2915 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2917 si->outputDev->setMove(x,y);
2918 if((x1|y1|x2|y2)==0) x2++;
2919 si->outputDev->setClip(x1,y1,x2,y2);
2921 pdf_page_render2(page, output);
2923 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2925 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2926 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2928 si->outputDev->setMove(0,0);
2929 si->outputDev->setClip(0,0,0,0);
2931 pdf_page_render2(page, output);
2935 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2937 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2938 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2939 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2940 memset(info, 0, sizeof(pdf_page_info_t));
2942 InfoOutputDev*output = new InfoOutputDev;
2945 pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2947 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2950 info->xMin = output->x1;
2951 info->yMin = output->y1;
2952 info->xMax = output->x2;
2953 info->yMax = output->y2;
2954 info->number_of_images = output->num_images;
2955 info->number_of_links = output->num_links;
2956 info->number_of_fonts = output->num_fonts;
2963 void pdf_page_info_destroy(pdf_page_info_t*info)