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>
50 #include "OutputDev.h"
53 #include "CharCodeToUnicode.h"
54 #include "NameToUnicodeTable.h"
55 #include "GlobalParams.h"
56 #include "FoFiType1C.h"
57 #include "FoFiTrueType.h"
59 #include "SWFOutputDev.h"
61 //swftools header files
62 #include "../lib/devices/swf.h"
63 #include "../lib/log.h"
64 #include "../lib/gfxdevice.h"
65 #include "../lib/gfxtools.h"
66 #include "../lib/gfxfont.h"
70 typedef struct _fontfile
76 typedef struct _parameter
80 struct _parameter*next;
83 static parameter_t* device_config = 0;
84 static parameter_t* device_config_next = 0;
87 static fontfile_t fonts[2048];
88 static int fontnum = 0;
90 static int config_use_fontconfig = 1;
93 static double caplinewidth = 3.0;
94 static double zoom = 72; /* xpdf: 86 */
95 static int forceType0Fonts = 1;
97 static void printInfoString(Dict *infoDict, char *key, char *fmt);
98 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
100 static char* lastfontdir = 0;
106 {"Times-Roman", "n021003l"},
107 {"Times-Italic", "n021023l"},
108 {"Times-Bold", "n021004l"},
109 {"Times-BoldItalic", "n021024l"},
110 {"Helvetica", "n019003l"},
111 {"Helvetica-Oblique", "n019023l"},
112 {"Helvetica-Bold", "n019004l"},
113 {"Helvetica-BoldOblique", "n019024l"},
114 {"Courier", "n022003l"},
115 {"Courier-Oblique", "n022023l"},
116 {"Courier-Bold", "n022004l"},
117 {"Courier-BoldOblique", "n022024l"},
118 {"Symbol", "s050000l"},
119 {"ZapfDingbats", "d050000l"}};
121 class SWFOutputState {
127 this->textRender = 0;
131 typedef struct _fontlist
141 class SWFOutputDev: public OutputDev {
149 virtual ~SWFOutputDev() ;
151 void setMove(int x,int y);
152 void setClip(int x1,int y1,int x2,int y2);
154 void setInfo(InfoOutputDev*info) {this->info = info;}
156 int save(char*filename);
159 void startFrame(int width, int height);
161 virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
164 void* get(char*name);
166 //----- get info about output device
168 // Does this device use upside-down coordinates?
169 // (Upside-down means (0,0) is the top left corner of the page.)
170 virtual GBool upsideDown();
172 // Does this device use drawChar() or drawString()?
173 virtual GBool useDrawChar();
175 // Can this device draw gradients?
176 virtual GBool useGradients();
178 virtual GBool interpretType3Chars() {return gTrue;}
180 //----- initialization and control
182 void setXRef(PDFDoc*doc, XRef *xref);
185 virtual void drawLink(Link *link, Catalog *catalog) ;
187 //----- save/restore graphics state
188 virtual void saveState(GfxState *state) ;
189 virtual void restoreState(GfxState *state) ;
191 //----- update graphics state
193 virtual void updateFont(GfxState *state);
194 virtual void updateFillColor(GfxState *state);
195 virtual void updateStrokeColor(GfxState *state);
196 virtual void updateLineWidth(GfxState *state);
197 virtual void updateLineJoin(GfxState *state);
198 virtual void updateLineCap(GfxState *state);
200 virtual void updateAll(GfxState *state)
203 updateFillColor(state);
204 updateStrokeColor(state);
205 updateLineWidth(state);
206 updateLineJoin(state);
207 updateLineCap(state);
210 //----- path painting
211 virtual void stroke(GfxState *state) ;
212 virtual void fill(GfxState *state) ;
213 virtual void eoFill(GfxState *state) ;
215 //----- path clipping
216 virtual void clip(GfxState *state) ;
217 virtual void eoClip(GfxState *state) ;
220 virtual void beginString(GfxState *state, GString *s) ;
221 virtual void endString(GfxState *state) ;
222 virtual void endTextObject(GfxState *state);
223 virtual void drawChar(GfxState *state, double x, double y,
224 double dx, double dy,
225 double originX, double originY,
226 CharCode code, int nBytes, Unicode *u, int uLen);
228 //----- image drawing
229 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
230 int width, int height, GBool invert,
232 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
233 int width, int height, GfxImageColorMap *colorMap,
234 int *maskColors, GBool inlineImg);
236 virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
237 virtual void endType3Char(GfxState *state);
239 virtual void type3D0(GfxState *state, double wx, double wy);
240 virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
243 void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
244 int width, int height, GfxImageColorMap*colorMap, GBool invert,
245 GBool inlineImg, int mask, int *maskColors);
246 int SWFOutputDev::setGfxFont(char*id, char*filename, double quality);
247 void strokeGfxline(GfxState *state, gfxline_t*line);
248 void clipToGfxLine(GfxState *state, gfxline_t*line);
249 void fillGfxLine(GfxState *state, gfxline_t*line);
253 gfxresult_t*result; //filled when complete
255 char outer_clip_box; //whether the page clip box is still on
258 SWFOutputState states[64];
266 char* searchFont(char*name);
267 char* substituteFont(GfxFont*gfxFont, char*oldname);
268 char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
270 int textmodeinfo; // did we write "Text will be rendered as polygon" yet?
271 int jpeginfo; // did we write "File contains jpegs" yet?
272 int pbminfo; // did we write "File contains jpegs" yet?
273 int linkinfo; // did we write "File contains links" yet?
274 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
275 int gradientinfo; // did we write "File contains Gradients yet?
277 int type3active; // are we between beginType3()/endType3()?
283 char* substitutetarget[256];
284 char* substitutesource[256];
287 int user_movex,user_movey;
288 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
290 gfxline_t* current_text_stroke;
291 gfxline_t* current_text_clip;
292 char* current_font_id;
293 gfxfont_t* current_gfxfont;
294 gfxmatrix_t current_font_matrix;
296 fontlist_t* fontlist;
302 friend void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage);
305 typedef struct _drawnchar
323 chars = (drawnchar_t*)malloc(sizeof(drawnchar_t)*buf_size);
324 memset(chars, 0, sizeof(drawnchar_t)*buf_size);
329 free(chars);chars = 0;
336 chars = (drawnchar_t*)realloc(chars, sizeof(drawnchar_t)*buf_size);
340 void addChar(int charid, gfxcoord_t x, gfxcoord_t y, gfxcolor_t color)
343 chars[num_chars].x = x;
344 chars[num_chars].y = y;
345 chars[num_chars].color = color;
346 chars[num_chars].charid = charid;
350 static char*getFontID(GfxFont*font);
358 class InfoOutputDev: public OutputDev
361 FontInfo* currentfont;
373 id2font = new GHash();
375 virtual ~InfoOutputDev()
379 virtual GBool upsideDown() {return gTrue;}
380 virtual GBool useDrawChar() {return gTrue;}
381 virtual GBool useGradients() {return gTrue;}
382 virtual GBool interpretType3Chars() {return gTrue;}
383 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
386 state->transform(crop_x1,crop_y1,&x1,&y1);
387 state->transform(crop_x2,crop_y2,&x2,&y2);
388 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
389 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
395 virtual void drawLink(Link *link, Catalog *catalog)
399 virtual double getMaximumFontSize(char*id)
401 FontInfo*info = (FontInfo*)id2font->lookup(id);
403 msg("<error> Unknown font id: %s", id);
406 return info->max_size;
409 virtual void updateFont(GfxState *state)
411 GfxFont*font = state->getFont();
414 char*id = getFontID(font);
416 FontInfo*info = (FontInfo*)id2font->lookup(id);
418 GString* idStr = new GString(id);
422 id2font->add(idStr, (void*)info);
429 virtual void drawChar(GfxState *state, double x, double y,
430 double dx, double dy,
431 double originX, double originY,
432 CharCode code, int nBytes, Unicode *u, int uLen)
434 int render = state->getRender();
437 double m11,m21,m12,m22;
438 state->getFontTransMat(&m11, &m12, &m21, &m22);
439 m11 *= state->getHorizScaling();
440 m21 *= state->getHorizScaling();
441 double lenx = sqrt(m11*m11 + m12*m12);
442 double leny = sqrt(m21*m21 + m22*m22);
443 double len = lenx>leny?lenx:leny;
444 if(currentfont && currentfont->max_size < len) {
445 currentfont->max_size = len;
448 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
449 int width, int height, GBool invert,
454 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
455 int width, int height, GfxImageColorMap *colorMap,
456 int *maskColors, GBool inlineImg)
462 SWFOutputDev::SWFOutputDev()
480 current_text_stroke = 0;
481 current_text_clip = 0;
488 output = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
489 gfxdevice_swf_init(output);
490 /* configure device */
491 parameter_t*p = device_config;
493 output->setparameter(output, p->name, p->value);
498 void SWFOutputDev::setMove(int x,int y)
500 this->user_movex = x;
501 this->user_movey = y;
504 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
506 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
507 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
509 this->user_clipx1 = x1;
510 this->user_clipy1 = y1;
511 this->user_clipx2 = x2;
512 this->user_clipy2 = y2;
515 static char*getFontID(GfxFont*font)
517 GString*gstr = font->getName();
518 char* fontname = gstr==0?0:gstr->getCString();
522 sprintf(buf, "UFONT%d", r->num);
525 return strdup(fontname);
528 static char*getFontName(GfxFont*font)
530 char*fontid = getFontID(font);
532 char* plus = strchr(fontid, '+');
533 if(plus && plus < &fontid[strlen(fontid)-1]) {
534 fontname = strdup(plus+1);
536 fontname = strdup(fontid);
542 static char mybuf[1024];
543 static char* gfxstate2str(GfxState *state)
547 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
554 if(state->getX1()!=0.0)
555 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
556 if(state->getY1()!=0.0)
557 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
558 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
559 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
560 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
561 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
562 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
563 state->getFillColor()->c[0], state->getFillColor()->c[1]);
564 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
565 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
566 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
567 state->getFillColor()->c[0], state->getFillColor()->c[1],
568 state->getFillColor()->c[2], state->getFillColor()->c[3],
569 state->getFillColor()->c[4], state->getFillColor()->c[5],
570 state->getFillColor()->c[6], state->getFillColor()->c[7]);
571 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
572 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
573 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
574 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
575 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
576 state->getFillRGB(&rgb);
577 if(rgb.r || rgb.g || rgb.b)
578 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
579 state->getStrokeRGB(&rgb);
580 if(rgb.r || rgb.g || rgb.b)
581 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
582 if(state->getFillColorSpace()->getNComps()>1)
583 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
584 if(state->getStrokeColorSpace()->getNComps()>1)
585 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
586 if(state->getFillPattern())
587 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
588 if(state->getStrokePattern())
589 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
591 if(state->getFillOpacity()!=1.0)
592 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
593 if(state->getStrokeOpacity()!=1.0)
594 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
596 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
601 state->getLineDash(&dash, &length, &start);
605 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
606 for(t=0;t<length;t++) {
607 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
609 bufpos+=sprintf(bufpos,"]");
612 if(state->getFlatness()!=1)
613 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
614 if(state->getLineJoin()!=0)
615 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
616 if(state->getLineJoin()!=0)
617 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
618 if(state->getLineJoin()!=0)
619 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
621 if(state->getFont() && getFontID(state->getFont()))
622 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
623 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
624 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
625 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
626 if(state->getCharSpace())
627 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
628 if(state->getWordSpace())
629 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
630 if(state->getHorizScaling()!=1.0)
631 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
632 if(state->getLeading())
633 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
635 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
636 if(state->getRender())
637 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
638 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
639 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
640 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
641 if(state->getLineX())
642 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
643 if(state->getLineY())
644 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
645 bufpos+=sprintf(bufpos," ");
649 static void dumpFontInfo(char*loglevel, GfxFont*font);
650 static int lastdumps[1024];
651 static int lastdumppos = 0;
656 static void showFontError(GfxFont*font, int nr)
660 for(t=0;t<lastdumppos;t++)
661 if(lastdumps[t] == r->num)
665 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
666 lastdumps[lastdumppos++] = r->num;
668 msg("<warning> The following font caused problems:");
670 msg("<warning> The following font caused problems (substituting):");
672 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
673 dumpFontInfo("<warning>", font);
676 static void dumpFontInfo(char*loglevel, GfxFont*font)
678 char* id = getFontID(font);
679 char* name = getFontName(font);
680 Ref* r=font->getID();
681 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
683 GString*gstr = font->getTag();
685 msg("%s| Tag: %s\n", loglevel, id);
687 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
689 GfxFontType type=font->getType();
691 case fontUnknownType:
692 msg("%s| Type: unknown\n",loglevel);
695 msg("%s| Type: 1\n",loglevel);
698 msg("%s| Type: 1C\n",loglevel);
701 msg("%s| Type: 3\n",loglevel);
704 msg("%s| Type: TrueType\n",loglevel);
707 msg("%s| Type: CIDType0\n",loglevel);
710 msg("%s| Type: CIDType0C\n",loglevel);
713 msg("%s| Type: CIDType2\n",loglevel);
718 GBool embedded = font->getEmbeddedFontID(&embRef);
720 if(font->getEmbeddedFontName()) {
721 embeddedName = font->getEmbeddedFontName()->getCString();
724 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
726 gstr = font->getExtFontFile();
728 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
730 // Get font descriptor flags.
731 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
732 if(font->isSerif()) msg("%s| is serif\n", loglevel);
733 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
734 if(font->isItalic()) msg("%s| is italic\n", loglevel);
735 if(font->isBold()) msg("%s| is bold\n", loglevel);
741 //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");}
742 //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");}
745 void dump_outline(gfxline_t*line)
748 if(line->type == gfx_moveTo) {
749 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
750 } else if(line->type == gfx_lineTo) {
751 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
752 } else if(line->type == gfx_splineTo) {
753 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
759 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey)
761 int num = path->getNumSubpaths();
764 double lastx=0,lasty=0,posx=0,posy=0;
767 msg("<warning> empty path");
771 gfxdrawer_target_gfxline(&draw);
773 for(t = 0; t < num; t++) {
774 GfxSubpath *subpath = path->getSubpath(t);
775 int subnum = subpath->getNumPoints();
776 double bx=0,by=0,cx=0,cy=0;
778 for(s=0;s<subnum;s++) {
781 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
786 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
787 draw.lineTo(&draw, lastx, lasty);
789 draw.moveTo(&draw, x,y);
794 } else if(subpath->getCurve(s) && cpos==0) {
798 } else if(subpath->getCurve(s) && cpos==1) {
806 draw.lineTo(&draw, x,y);
808 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y, 0.05);
815 /* fix non-closed lines */
816 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
817 draw.lineTo(&draw, lastx, lasty);
819 gfxline_t*result = (gfxline_t*)draw.result(&draw);
823 /*----------------------------------------------------------------------------
824 * Primitive Graphic routines
825 *----------------------------------------------------------------------------*/
827 void SWFOutputDev::stroke(GfxState *state)
829 GfxPath * path = state->getPath();
830 gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex, user_movey);
831 strokeGfxline(state, line);
835 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
837 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
838 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
839 double miterLimit = state->getMiterLimit();
840 double width = state->getTransformedLineWidth();
843 double opaq = state->getStrokeOpacity();
845 state->getFillRGB(&rgb);
847 state->getStrokeRGB(&rgb);
849 col.r = colToByte(rgb.r);
850 col.g = colToByte(rgb.g);
851 col.b = colToByte(rgb.b);
852 col.a = (unsigned char)(opaq*255);
854 gfx_capType capType = gfx_capRound;
855 if(lineCap == 0) capType = gfx_capButt;
856 else if(lineCap == 1) capType = gfx_capRound;
857 else if(lineCap == 2) capType = gfx_capSquare;
859 gfx_joinType joinType = gfx_joinRound;
860 if(lineJoin == 0) joinType = gfx_joinMiter;
861 else if(lineJoin == 1) joinType = gfx_joinRound;
862 else if(lineJoin == 2) joinType = gfx_joinBevel;
865 double dashphase = 0;
867 state->getLineDash(&ldash, &dashnum, &dashphase);
871 if(dashnum && ldash) {
872 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
876 msg("<trace> %d dashes", dashnum);
877 msg("<trace> | phase: %f", dashphase);
878 for(t=0;t<dashnum;t++) {
880 msg("<trace> | d%-3d: %f", t, ldash[t]);
883 if(getLogLevel() >= LOGLEVEL_TRACE) {
887 line2 = gfxtool_dash_line(line, dash, dashphase);
890 msg("<trace> After dashing:");
893 if(getLogLevel() >= LOGLEVEL_TRACE) {
894 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x\n",
896 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
897 lineCap==0?"butt": (lineJoin==1?"round":"square"),
899 col.r,col.g,col.b,col.a
904 //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
905 output->stroke(output, line, width, &col, capType, joinType, miterLimit);
915 gfxcolor_t getFillColor(GfxState * state)
918 double opaq = state->getFillOpacity();
919 state->getFillRGB(&rgb);
921 col.r = colToByte(rgb.r);
922 col.g = colToByte(rgb.g);
923 col.b = colToByte(rgb.b);
924 col.a = (unsigned char)(rgb.r*255);
928 void SWFOutputDev::fillGfxLine(GfxState *state, gfxline_t*line)
930 gfxcolor_t col = getFillColor(state);
932 if(getLogLevel() >= LOGLEVEL_TRACE) {
933 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
936 output->fill(output, line, &col);
938 void SWFOutputDev::fill(GfxState *state)
940 GfxPath * path = state->getPath();
941 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
942 fillGfxLine(state, line);
945 void SWFOutputDev::eoFill(GfxState *state)
947 GfxPath * path = state->getPath();
948 gfxcolor_t col = getFillColor(state);
950 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
952 if(getLogLevel() >= LOGLEVEL_TRACE) {
953 msg("<trace> eofill\n");
957 output->fill(output, line, &col);
961 void SWFOutputDev::clip(GfxState *state)
963 GfxPath * path = state->getPath();
964 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
965 clipToGfxLine(state, line);
969 void SWFOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line)
971 if(getLogLevel() >= LOGLEVEL_TRACE) {
972 msg("<trace> clip\n");
976 output->startclip(output, line);
977 states[statepos].clipping++;
979 void SWFOutputDev::eoClip(GfxState *state)
981 GfxPath * path = state->getPath();
982 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
984 if(getLogLevel() >= LOGLEVEL_TRACE) {
985 msg("<trace> eoclip\n");
989 output->startclip(output, line);
990 states[statepos].clipping++;
994 void SWFOutputDev::endframe()
997 output->endclip(output);
1001 output->endpage(output);
1004 void SWFOutputDev::finish()
1006 if(outer_clip_box) {
1008 output->endclip(output);
1013 this->result = output->finish(output);
1014 free(output);output=0;
1018 int SWFOutputDev::save(char*filename)
1021 return result->save(result, filename);
1023 void* SWFOutputDev::get(char*name)
1026 return result->get(result, name);
1029 SWFOutputDev::~SWFOutputDev()
1034 this->result->destroy(this->result);
1039 free(this->pages); this->pages = 0;
1042 fontlist_t*l = this->fontlist;
1044 fontlist_t*next = l->next;
1046 gfxfont_free(l->font);
1054 GBool SWFOutputDev::upsideDown()
1058 GBool SWFOutputDev::useDrawChar()
1062 GBool SWFOutputDev::useGradients()
1066 msg("<notice> File contains gradients");
1072 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
1073 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
1075 #define RENDER_FILL 0
1076 #define RENDER_STROKE 1
1077 #define RENDER_FILLSTROKE 2
1078 #define RENDER_INVISIBLE 3
1079 #define RENDER_CLIP 4
1081 static char tmp_printstr[4096];
1082 char* makeStringPrintable(char*str)
1084 int len = strlen(str);
1091 for(t=0;t<len;t++) {
1096 tmp_printstr[t] = c;
1099 tmp_printstr[len++] = '.';
1100 tmp_printstr[len++] = '.';
1101 tmp_printstr[len++] = '.';
1103 tmp_printstr[len] = 0;
1104 return tmp_printstr;
1108 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
1112 for(t=0;t<font->num_glyphs;t++) {
1113 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
1114 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1118 /* if we didn't find the character, maybe
1119 we can find the capitalized version */
1120 for(t=0;t<font->num_glyphs;t++) {
1121 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
1122 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1128 /* try to use the unicode id */
1129 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
1130 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
1131 return font->unicode2glyph[u];
1134 /* we don't need to "draw" space characters, so don't overdo the search
1135 for a matching glyph */
1136 if(charname && !strcasecmp(charname, "space"))
1139 if(charnr>=0 && charnr<font->num_glyphs) {
1140 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1148 void SWFOutputDev::beginString(GfxState *state, GString *s)
1150 int render = state->getRender();
1151 if(current_text_stroke) {
1152 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
1155 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
1156 double m11,m21,m12,m22;
1157 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
1158 state->getFontTransMat(&m11, &m12, &m21, &m22);
1159 m11 *= state->getHorizScaling();
1160 m21 *= state->getHorizScaling();
1162 this->current_font_matrix.m00 = m11 / 1024.0;
1163 this->current_font_matrix.m01 = m12 / 1024.0;
1164 this->current_font_matrix.m10 = -m21 / 1024.0;
1165 this->current_font_matrix.m11 = -m22 / 1024.0;
1166 this->current_font_matrix.tx = 0;
1167 this->current_font_matrix.ty = 0;
1169 gfxmatrix_t m = this->current_font_matrix;
1171 /*if(render != 3 && render != 0)
1172 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1173 states[statepos].textRender = render;
1176 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1177 double dx, double dy,
1178 double originX, double originY,
1179 CharCode c, int nBytes, Unicode *_u, int uLen)
1181 int render = state->getRender();
1182 // check for invisible text -- this is used by Acrobat Capture
1184 msg("<debug> Ignoring invisible text: char %d at %f,%f", c, x, y);
1188 if(states[statepos].textRender != render)
1189 msg("<error> Internal error: drawChar.render!=beginString.render");
1191 gfxcolor_t col = getFillColor(state);
1193 Gushort *CIDToGIDMap = 0;
1194 GfxFont*font = state->getFont();
1196 if(font->getType() == fontType3) {
1197 /* type 3 chars are passed as graphics */
1198 msg("<debug> type3 char at %f/%f", x, y);
1209 /* find out char name from unicode index
1210 TODO: should be precomputed
1212 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1213 if(nameToUnicodeTab[t].u == u) {
1214 name = nameToUnicodeTab[t].name;
1221 if(font->isCIDFont()) {
1222 GfxCIDFont*cfont = (GfxCIDFont*)font;
1224 if(font->getType() == fontCIDType2)
1225 CIDToGIDMap = cfont->getCIDToGID();
1228 font8 = (Gfx8BitFont*)font;
1229 char**enc=font8->getEncoding();
1230 if(enc && enc[c] && strcasecmp(enc[c], "space")) {
1235 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);
1238 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);
1244 charid = getGfxCharID(current_gfxfont, c, name, u);
1246 charid = getGfxCharID(current_gfxfont, c, 0, -1);
1248 /* multiple unicodes- should usually map to a ligature.
1249 if the ligature doesn't exist, we need to draw
1250 the characters one-by-one. */
1252 msg("<warning> ligature %d missing in font %s\n", c, current_font_id);
1253 for(t=0;t<uLen;t++) {
1254 drawChar(state, x, y, dx, dy, originX, originY, c, nBytes, _u+t, 1);
1261 if(!name || strcasecmp(name, "space")) {
1262 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1263 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1268 gfxmatrix_t m = this->current_font_matrix;
1269 state->transform(x, y, &m.tx, &m.ty);
1273 if(render == RENDER_FILL) {
1274 output->drawchar(output, current_font_id, charid, &col, &m);
1276 msg("<debug> Drawing glyph %d as shape", charid);
1278 msg("<notice> Some texts will be rendered as shape");
1281 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1282 gfxline_t*tglyph = gfxline_clone(glyph);
1283 gfxline_transform(tglyph, &m);
1284 if((render&3) != RENDER_INVISIBLE) {
1285 gfxline_t*add = gfxline_clone(tglyph);
1286 current_text_stroke = gfxline_append(current_text_stroke, add);
1288 if(render&RENDER_CLIP) {
1289 gfxline_t*add = gfxline_clone(tglyph);
1290 current_text_clip = gfxline_append(current_text_clip, add);
1292 gfxline_free(tglyph);
1296 void SWFOutputDev::endString(GfxState *state)
1298 int render = state->getRender();
1299 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1300 if(states[statepos].textRender != render)
1301 msg("<error> Internal error: drawChar.render!=beginString.render");
1303 if(current_text_stroke) {
1304 /* fillstroke and stroke text rendering objects we can process right
1305 now (as there may be texts of other rendering modes in this
1306 text object)- clipping objects have to wait until endTextObject,
1308 if((render&3) == RENDER_FILL) {
1309 fillGfxLine(state, current_text_stroke);
1310 gfxline_free(current_text_stroke);
1311 current_text_stroke = 0;
1312 } else if((render&3) == RENDER_FILLSTROKE) {
1313 fillGfxLine(state, current_text_stroke);
1314 strokeGfxline(state, current_text_stroke);
1315 gfxline_free(current_text_stroke);
1316 current_text_stroke = 0;
1317 } else if((render&3) == RENDER_STROKE) {
1318 strokeGfxline(state, current_text_stroke);
1319 gfxline_free(current_text_stroke);
1320 current_text_stroke = 0;
1325 void SWFOutputDev::endTextObject(GfxState *state)
1327 int render = state->getRender();
1328 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1329 if(states[statepos].textRender != render)
1330 msg("<error> Internal error: drawChar.render!=beginString.render");
1332 if(current_text_clip) {
1333 clipToGfxLine(state, current_text_clip);
1334 gfxline_free(current_text_clip);
1335 current_text_clip = 0;
1339 /* the logic seems to be as following:
1340 first, beginType3Char is called, with the charcode and the coordinates.
1341 if this function returns true, it already knew about the char and has now drawn it.
1342 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1343 the all draw operations until endType3Char are part of the char (which in this moment is
1344 at the position first passed to beginType3Char). the char ends with endType3Char.
1346 The drawing operations between beginType3Char and endType3Char are somewhat different to
1347 the normal ones. For example, the fillcolor equals the stroke color.
1350 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1352 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1354 /* the character itself is going to be passed using the draw functions */
1355 return gFalse; /* gTrue= is_in_cache? */
1358 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1359 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1361 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1362 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1366 void SWFOutputDev::endType3Char(GfxState *state)
1369 msg("<debug> endType3Char");
1372 void SWFOutputDev::startFrame(int width, int height)
1374 output->startpage(output, width, height);
1377 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1379 this->currentpage = pageNum;
1381 int rot = doc->getPageRotate(1);
1384 gfxline_t clippath[5];
1386 white.r = white.g = white.b = white.a = 255;
1388 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1389 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1390 Use CropBox, not MediaBox, as page size
1397 state->transform(crop_x1,crop_y1,&x1,&y1); //x1 += user_movex; y1 += user_movey;
1398 state->transform(crop_x2,crop_y2,&x2,&y2); //x2 += user_movex; y2 += user_movey;
1400 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1401 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1404 /* apply user clip box */
1405 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1406 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1407 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1408 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1409 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1412 //msg("<verbose> Bounding box is (%f,%f)-(%f,%f) [shifted by %d/%d]", x1,y1,x2,y2, user_movex, user_movey);
1414 if(outer_clip_box) {
1415 output->endclip(output);
1419 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);
1421 msg("<verbose> page is rotated %d degrees\n", rot);
1423 clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1424 clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1425 clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1426 clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1427 clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1428 output->startclip(output, clippath); outer_clip_box = 1;
1429 output->fill(output, clippath, &white);
1432 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1434 msg("<debug> drawlink\n");
1435 double x1, y1, x2, y2, w;
1436 gfxline_t points[5];
1439 link->getRect(&x1, &y1, &x2, &y2);
1440 cvtUserToDev(x1, y1, &x, &y);
1441 points[0].type = gfx_moveTo;
1442 points[0].x = points[4].x = x + user_movex;
1443 points[0].y = points[4].y = y + user_movey;
1444 points[0].next = &points[1];
1445 cvtUserToDev(x2, y1, &x, &y);
1446 points[1].type = gfx_lineTo;
1447 points[1].x = x + user_movex;
1448 points[1].y = y + user_movey;
1449 points[1].next = &points[2];
1450 cvtUserToDev(x2, y2, &x, &y);
1451 points[2].type = gfx_lineTo;
1452 points[2].x = x + user_movex;
1453 points[2].y = y + user_movey;
1454 points[2].next = &points[3];
1455 cvtUserToDev(x1, y2, &x, &y);
1456 points[3].type = gfx_lineTo;
1457 points[3].x = x + user_movex;
1458 points[3].y = y + user_movey;
1459 points[3].next = &points[4];
1460 cvtUserToDev(x1, y1, &x, &y);
1461 points[4].type = gfx_lineTo;
1462 points[4].x = x + user_movex;
1463 points[4].y = y + user_movey;
1466 LinkAction*action=link->getAction();
1473 switch(action->getKind())
1477 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1478 LinkDest *dest=NULL;
1479 if (ha->getDest()==NULL)
1480 dest=catalog->findDest(ha->getNamedDest());
1481 else dest=ha->getDest();
1483 if (dest->isPageRef()){
1484 Ref pageref=dest->getPageRef();
1485 page=catalog->findPage(pageref.num,pageref.gen);
1487 else page=dest->getPageNum();
1488 sprintf(buf, "%d", page);
1495 LinkGoToR*l = (LinkGoToR*)action;
1496 GString*g = l->getNamedDest();
1498 s = strdup(g->getCString());
1503 LinkNamed*l = (LinkNamed*)action;
1504 GString*name = l->getName();
1506 s = strdup(name->lowerCase()->getCString());
1507 named = name->getCString();
1510 if(strstr(s, "next") || strstr(s, "forward"))
1512 page = currentpage + 1;
1514 else if(strstr(s, "prev") || strstr(s, "back"))
1516 page = currentpage - 1;
1518 else if(strstr(s, "last") || strstr(s, "end"))
1520 if(pages && pagepos>0)
1521 page = pages[pagepos-1];
1523 else if(strstr(s, "first") || strstr(s, "top"))
1531 case actionLaunch: {
1533 LinkLaunch*l = (LinkLaunch*)action;
1534 GString * str = new GString(l->getFileName());
1535 str->append(l->getParams());
1536 s = strdup(str->getCString());
1542 LinkURI*l = (LinkURI*)action;
1543 GString*g = l->getURI();
1545 url = g->getCString();
1550 case actionUnknown: {
1552 LinkUnknown*l = (LinkUnknown*)action;
1557 msg("<error> Unknown link type!\n");
1561 if(!s) s = strdup("-?-");
1563 if(!linkinfo && (page || url))
1565 msg("<notice> File contains links");
1573 for(t=1;t<=pagepos;t++) {
1574 if(pages[t]==page) {
1581 sprintf(buf, "page%d", t);
1582 output->drawlink(output, points, buf);
1584 msg("<warning> Invalid link to page %d", page);
1589 output->drawlink(output, points, url);
1592 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1596 void SWFOutputDev::saveState(GfxState *state) {
1597 msg("<trace> saveState\n");
1600 msg("<error> Too many nested states in pdf.");
1604 states[statepos].clipping = 0; //? shouldn't this be the current value?
1605 states[statepos].textRender = states[statepos-1].textRender;
1608 void SWFOutputDev::restoreState(GfxState *state) {
1609 msg("<trace> restoreState\n");
1611 while(states[statepos].clipping) {
1612 output->endclip(output);
1613 states[statepos].clipping--;
1618 char* SWFOutputDev::searchFont(char*name)
1622 int is_standard_font = 0;
1624 msg("<verbose> SearchFont(%s)", name);
1626 /* see if it is a pdf standard font */
1627 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1629 if(!strcmp(name, pdf2t1map[i].pdffont))
1631 name = pdf2t1map[i].filename;
1632 is_standard_font = 1;
1636 /* look in all font files */
1637 for(i=0;i<fontnum;i++)
1639 if(strstr(fonts[i].filename, name))
1641 if(!fonts[i].used) {
1644 if(!is_standard_font)
1645 msg("<notice> Using %s for %s", fonts[i].filename, name);
1647 return strdup(fonts[i].filename);
1653 void SWFOutputDev::updateLineWidth(GfxState *state)
1655 double width = state->getTransformedLineWidth();
1656 //swfoutput_setlinewidth(&output, width);
1659 void SWFOutputDev::updateLineCap(GfxState *state)
1661 int c = state->getLineCap();
1664 void SWFOutputDev::updateLineJoin(GfxState *state)
1666 int j = state->getLineJoin();
1669 void SWFOutputDev::updateFillColor(GfxState *state)
1672 double opaq = state->getFillOpacity();
1673 state->getFillRGB(&rgb);
1675 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1678 void SWFOutputDev::updateStrokeColor(GfxState *state)
1681 double opaq = state->getStrokeOpacity();
1682 state->getStrokeRGB(&rgb);
1683 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1686 void FoFiWrite(void *stream, char *data, int len)
1688 fwrite(data, len, 1, (FILE*)stream);
1691 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1693 char*tmpFileName = NULL;
1699 Object refObj, strObj;
1701 tmpFileName = mktmpname(namebuf);
1704 ret = font->getEmbeddedFontID(&embRef);
1706 msg("<verbose> Didn't get embedded font id");
1707 /* not embedded- the caller should now search the font
1708 directories for this font */
1712 f = fopen(tmpFileName, "wb");
1714 msg("<error> Couldn't create temporary Type 1 font file");
1718 /*if(font->isCIDFont()) {
1719 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1720 GString c = cidFont->getCollection();
1721 msg("<notice> Collection: %s", c.getCString());
1724 //if (font->getType() == fontType1C) {
1725 if (0) { //font->getType() == fontType1C) {
1726 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1728 msg("<error> Couldn't read embedded font file");
1731 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1733 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1734 //cvt->convertToCIDType0("test", f);
1735 //cvt->convertToType0("test", f);
1738 } else if(font->getType() == fontTrueType) {
1739 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1740 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1742 msg("<error> Couldn't read embedded font file");
1745 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1746 cvt->writeTTF(FoFiWrite, f);
1750 font->getEmbeddedFontID(&embRef);
1751 refObj.initRef(embRef.num, embRef.gen);
1752 refObj.fetch(ref, &strObj);
1754 strObj.streamReset();
1759 f4[t] = strObj.streamGetChar();
1760 f4c[t] = (char)f4[t];
1765 if(!strncmp(f4c, "true", 4)) {
1766 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1767 Change this on the fly */
1768 f4[0] = f4[2] = f4[3] = 0;
1776 while ((c = strObj.streamGetChar()) != EOF) {
1780 strObj.streamClose();
1785 return strdup(tmpFileName);
1788 char* searchForSuitableFont(GfxFont*gfxFont)
1790 char*name = getFontName(gfxFont);
1794 if(!config_use_fontconfig)
1797 #ifdef HAVE_FONTCONFIG
1798 FcPattern *pattern, *match;
1802 static int fcinitcalled = false;
1804 msg("<debug> searchForSuitableFont(%s)", name);
1806 // call init ony once
1807 if (!fcinitcalled) {
1808 msg("<debug> Initializing FontConfig...");
1809 fcinitcalled = true;
1811 msg("<debug> FontConfig Initialization failed. Disabling.");
1812 config_use_fontconfig = 0;
1815 msg("<debug> ...initialized FontConfig");
1818 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1819 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1820 if (gfxFont->isItalic()) // check for italic
1821 msg("<debug> FontConfig: Adding Italic Slant");
1822 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1823 if (gfxFont->isBold()) // check for bold
1824 msg("<debug> FontConfig: Adding Bold Weight");
1825 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1827 msg("<debug> FontConfig: Try to match...");
1828 // configure and match using the original font name
1829 FcConfigSubstitute(0, pattern, FcMatchPattern);
1830 FcDefaultSubstitute(pattern);
1831 match = FcFontMatch(0, pattern, &result);
1833 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1834 msg("<debug> FontConfig: family=%s", (char*)v);
1835 // if we get an exact match
1836 if (strcmp((char *)v, name) == 0) {
1837 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1838 filename = strdup((char*)v); // mem leak
1839 char *nfn = strrchr(filename, '/');
1840 if(nfn) fontname = strdup(nfn+1);
1841 else fontname = filename;
1843 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1845 // initialize patterns
1846 FcPatternDestroy(pattern);
1847 FcPatternDestroy(match);
1849 // now match against serif etc.
1850 if (gfxFont->isSerif()) {
1851 msg("<debug> FontConfig: Create Serif Family Pattern");
1852 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1853 } else if (gfxFont->isFixedWidth()) {
1854 msg("<debug> FontConfig: Create Monospace Family Pattern");
1855 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1857 msg("<debug> FontConfig: Create Sans Family Pattern");
1858 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1862 if (gfxFont->isItalic()) {
1863 msg("<debug> FontConfig: Adding Italic Slant");
1864 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1867 if (gfxFont->isBold()) {
1868 msg("<debug> FontConfig: Adding Bold Weight");
1869 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1872 msg("<debug> FontConfig: Try to match... (2)");
1873 // configure and match using serif etc
1874 FcConfigSubstitute (0, pattern, FcMatchPattern);
1875 FcDefaultSubstitute (pattern);
1876 match = FcFontMatch (0, pattern, &result);
1878 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1879 filename = strdup((char*)v); // mem leak
1880 char *nfn = strrchr(filename, '/');
1881 if(nfn) fontname = strdup(nfn+1);
1882 else fontname = filename;
1884 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1888 //printf("FONTCONFIG: pattern");
1889 //FcPatternPrint(pattern);
1890 //printf("FONTCONFIG: match");
1891 //FcPatternPrint(match);
1893 FcPatternDestroy(pattern);
1894 FcPatternDestroy(match);
1896 pdfswf_addfont(filename);
1903 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1905 char*fontname = 0, *filename = 0;
1906 msg("<notice> substituteFont(%s)", oldname);
1908 if(!(fontname = searchForSuitableFont(gfxFont))) {
1909 fontname = "Times-Roman";
1911 filename = searchFont(fontname);
1913 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1917 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1918 msg("<fatal> Too many fonts in file.");
1922 substitutesource[substitutepos] = strdup(oldname); //mem leak
1923 substitutetarget[substitutepos] = fontname;
1924 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1927 return strdup(filename); //mem leak
1930 void unlinkfont(char* filename)
1937 if(!strncmp(&filename[l-4],".afm",4)) {
1938 memcpy(&filename[l-4],".pfb",4);
1940 memcpy(&filename[l-4],".pfa",4);
1942 memcpy(&filename[l-4],".afm",4);
1945 if(!strncmp(&filename[l-4],".pfa",4)) {
1946 memcpy(&filename[l-4],".afm",4);
1948 memcpy(&filename[l-4],".pfa",4);
1951 if(!strncmp(&filename[l-4],".pfb",4)) {
1952 memcpy(&filename[l-4],".afm",4);
1954 memcpy(&filename[l-4],".pfb",4);
1959 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1965 int SWFOutputDev::setGfxFont(char*id, char*filename, double maxSize)
1968 fontlist_t*last=0,*l = this->fontlist;
1970 /* TODO: should this be part of the state? */
1973 if(!strcmp(l->id, id)) {
1974 current_font_id = l->id;
1975 current_gfxfont = l->font;
1977 output->addfont(output, id, current_gfxfont);
1982 if(!filename) return 0;
1984 /* A font size of e.g. 9 means the font will be scaled down by
1985 1024 and scaled up by 9. So to have a maximum error of 1/20px,
1986 we have to divide 0.05 by (fontsize/1024)
1988 double quality = (1024 * 0.05) / maxSize;
1990 msg("<verbose> Loading %s...", filename);
1991 font = gfxfont_load(filename, quality);
1992 msg("<verbose> Font %s loaded successfully", filename);
1996 l->filename = strdup(filename);
1999 current_font_id = l->id;
2000 current_gfxfont = l->font;
2006 output->addfont(output, id, current_gfxfont);
2010 void SWFOutputDev::updateFont(GfxState *state)
2012 GfxFont*gfxFont = state->getFont();
2017 char * fontid = getFontID(gfxFont);
2018 double maxSize = 1.0;
2021 maxSize = this->info->getMaximumFontSize(fontid);
2025 /* first, look if we substituted this font before-
2026 this way, we don't initialize the T1 Fonts
2028 for(t=0;t<substitutepos;t++) {
2029 if(!strcmp(fontid, substitutesource[t])) {
2030 free(fontid);fontid=0;
2031 fontid = strdup(substitutetarget[t]);
2036 /* second, see if this is a font which was used before-
2037 if so, we are done */
2038 if(setGfxFont(fontid, 0, 0)) {
2042 /* if(swfoutput_queryfont(&output, fontid))
2043 swfoutput_setfont(&output, fontid, 0);
2045 msg("<debug> updateFont(%s) [cached]", fontid);
2049 // look for Type 3 font
2050 if (gfxFont->getType() == fontType3) {
2052 type3Warning = gTrue;
2053 showFontError(gfxFont, 2);
2059 /* now either load the font, or find a substitution */
2062 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
2067 (gfxFont->getType() == fontType1 ||
2068 gfxFont->getType() == fontType1C ||
2069 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
2070 gfxFont->getType() == fontTrueType ||
2071 gfxFont->getType() == fontCIDType2
2074 fileName = writeEmbeddedFontToFile(xref, gfxFont);
2075 if(!fileName) showFontError(gfxFont,0);
2078 char * fontname = getFontName(gfxFont);
2079 fileName = searchFont(fontname);
2080 if(!fileName) showFontError(gfxFont,0);
2084 char * fontname = getFontName(gfxFont);
2085 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
2088 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into %s", fontname, lastfontdir);
2090 msg("<warning> Try specifying one or more font directories");
2092 fileName = substituteFont(gfxFont, fontid);
2093 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
2094 msg("<notice> Font is now %s (%s)", fontid, fileName);
2098 msg("<error> Couldn't set font %s\n", fontid);
2103 msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
2104 dumpFontInfo("<verbose>", gfxFont);
2106 //swfoutput_setfont(&output, fontid, fileName);
2108 if(!setGfxFont(fontid, 0, 0)) {
2109 setGfxFont(fontid, fileName, maxSize);
2113 unlinkfont(fileName);
2121 #define SQR(x) ((x)*(x))
2123 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
2125 if((newwidth<2 || newheight<2) ||
2126 (width<=newwidth || height<=newheight))
2128 unsigned char*newdata;
2130 newdata= (unsigned char*)malloc(newwidth*newheight);
2132 double fx = (double)(width)/newwidth;
2133 double fy = (double)(height)/newheight;
2135 int blocksize = (int)(8192/(fx*fy));
2136 int r = 8192*256/palettesize;
2137 for(x=0;x<newwidth;x++) {
2138 double ex = px + fx;
2139 int fromx = (int)px;
2141 int xweight1 = (int)(((fromx+1)-px)*256);
2142 int xweight2 = (int)((ex-tox)*256);
2144 for(y=0;y<newheight;y++) {
2145 double ey = py + fy;
2146 int fromy = (int)py;
2148 int yweight1 = (int)(((fromy+1)-py)*256);
2149 int yweight2 = (int)((ey-toy)*256);
2152 for(xx=fromx;xx<=tox;xx++)
2153 for(yy=fromy;yy<=toy;yy++) {
2154 int b = 1-data[width*yy+xx];
2156 if(xx==fromx) weight = (weight*xweight1)/256;
2157 if(xx==tox) weight = (weight*xweight2)/256;
2158 if(yy==fromy) weight = (weight*yweight1)/256;
2159 if(yy==toy) weight = (weight*yweight2)/256;
2162 //if(a) a=(palettesize-1)*r/blocksize;
2163 newdata[y*newwidth+x] = (a*blocksize)/r;
2171 #define IMAGE_TYPE_JPEG 0
2172 #define IMAGE_TYPE_LOSSLESS 1
2174 static void drawimage(gfxdevice_t*dev, gfxcolor_t* data, int sizex,int sizey,
2175 double x1,double y1,
2176 double x2,double y2,
2177 double x3,double y3,
2178 double x4,double y4, int type)
2180 gfxcolor_t*newpic=0;
2182 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2183 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2185 gfxline_t p1,p2,p3,p4,p5;
2186 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2187 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2188 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2189 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2190 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2192 {p1.x = (int)(p1.x*20)/20.0;
2193 p1.y = (int)(p1.y*20)/20.0;
2194 p2.x = (int)(p2.x*20)/20.0;
2195 p2.y = (int)(p2.y*20)/20.0;
2196 p3.x = (int)(p3.x*20)/20.0;
2197 p3.y = (int)(p3.y*20)/20.0;
2198 p4.x = (int)(p4.x*20)/20.0;
2199 p4.y = (int)(p4.y*20)/20.0;
2200 p5.x = (int)(p5.x*20)/20.0;
2201 p5.y = (int)(p5.y*20)/20.0;
2208 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2209 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2214 img.data = (gfxcolor_t*)data;
2218 if(type == IMAGE_TYPE_JPEG)
2219 /* TODO: pass image_dpi to device instead */
2220 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2222 dev->fillbitmap(dev, &p1, &img, &m, 0);
2225 void drawimagejpeg(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2226 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2228 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2231 void drawimagelossless(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2232 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2234 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2238 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2239 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2240 GBool inlineImg, int mask, int*maskColors)
2245 double x1,y1,x2,y2,x3,y3,x4,y4;
2246 ImageStream *imgStr;
2253 ncomps = colorMap->getNumPixelComps();
2254 bits = colorMap->getBits();
2256 imgStr = new ImageStream(str, width, ncomps,bits);
2259 if(!width || !height || (height<=1 && width<=1))
2261 msg("<verbose> Ignoring %d by %d image", width, height);
2262 unsigned char buf[8];
2264 for (y = 0; y < height; ++y)
2265 for (x = 0; x < width; ++x) {
2266 imgStr->getPixel(buf);
2272 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1+= user_movey;
2273 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2+= user_movey;
2274 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3+= user_movey;
2275 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4+= user_movey;
2277 if(!pbminfo && !(str->getKind()==strDCT)) {
2279 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2283 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2285 if(!jpeginfo && (str->getKind()==strDCT)) {
2286 msg("<notice> file contains jpeg pictures");
2292 unsigned char buf[8];
2294 unsigned char*pic = new unsigned char[width*height];
2295 gfxcolor_t pal[256];
2297 state->getFillRGB(&rgb);
2299 memset(pal,255,sizeof(pal));
2300 pal[0].r = (int)(colToByte(rgb.r)); pal[1].r = 0;
2301 pal[0].g = (int)(colToByte(rgb.g)); pal[1].g = 0;
2302 pal[0].b = (int)(colToByte(rgb.b)); pal[1].b = 0;
2303 pal[0].a = 255; pal[1].a = 0;
2306 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2307 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2308 for (y = 0; y < height; ++y)
2309 for (x = 0; x < width; ++x)
2311 imgStr->getPixel(buf);
2314 pic[width*y+x] = buf[0];
2317 /* the size of the drawn image is added to the identifier
2318 as the same image may require different bitmaps if displayed
2319 at different sizes (due to antialiasing): */
2322 unsigned char*pic2 = 0;
2325 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2334 height = realheight;
2338 /* make a black/white palette */
2340 float r = 255/(numpalette-1);
2342 for(t=0;t<numpalette;t++) {
2343 pal[t].r = colToByte(rgb.r);
2344 pal[t].g = colToByte(rgb.g);
2345 pal[t].b = colToByte(rgb.b);
2346 pal[t].a = (unsigned char)(t*r);
2350 gfxcolor_t*pic2 = new gfxcolor_t[width*height];
2351 for (y = 0; y < height; ++y) {
2352 for (x = 0; x < width; ++x) {
2353 pic2[width*y+x] = pal[pic[y*width+x]];
2356 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2365 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2366 gfxcolor_t*pic=new gfxcolor_t[width*height];
2367 for (y = 0; y < height; ++y) {
2368 for (x = 0; x < width; ++x) {
2369 imgStr->getPixel(pixBuf);
2370 colorMap->getRGB(pixBuf, &rgb);
2371 pic[width*y+x].r = (unsigned char)(colToByte(rgb.r));
2372 pic[width*y+x].g = (unsigned char)(colToByte(rgb.g));
2373 pic[width*y+x].b = (unsigned char)(colToByte(rgb.b));
2374 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2377 if(str->getKind()==strDCT)
2378 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2380 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2385 gfxcolor_t*pic=new gfxcolor_t[width*height];
2386 gfxcolor_t pal[256];
2388 for(t=0;t<256;t++) {
2390 colorMap->getRGB(pixBuf, &rgb);
2391 /*if(maskColors && *maskColors==t) {
2392 msg("<notice> Color %d is transparent", t);
2393 if (imgData->maskColors) {
2395 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2396 if (pix[i] < imgData->maskColors[2*i] ||
2397 pix[i] > imgData->maskColors[2*i+1]) {
2412 pal[t].r = (unsigned char)(rgb.r * 255 + 0.5);
2413 pal[t].g = (unsigned char)(rgb.g * 255 + 0.5);
2414 pal[t].b = (unsigned char)(rgb.b * 255 + 0.5);
2415 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2418 for (y = 0; y < height; ++y) {
2419 for (x = 0; x < width; ++x) {
2420 imgStr->getPixel(pixBuf);
2421 pic[width*y+x] = pal[pixBuf[0]];
2424 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2432 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2433 int width, int height, GBool invert,
2436 if(states[statepos].textRender & 4) //clipped
2438 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2439 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
2442 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2443 int width, int height, GfxImageColorMap *colorMap,
2444 int *maskColors, GBool inlineImg)
2446 if(states[statepos].textRender & 4) //clipped
2449 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
2450 colorMap?"colorMap":"no colorMap",
2451 maskColors?"maskColors":"no maskColors",
2454 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2455 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2456 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
2459 //SWFOutputDev*output = 0;
2461 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2466 if (infoDict->lookup(key, &obj)->isString()) {
2467 s1 = obj.getString();
2468 if ((s1->getChar(0) & 0xff) == 0xfe &&
2469 (s1->getChar(1) & 0xff) == 0xff) {
2471 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2472 if (s1->getChar(i) == '\0') {
2473 s2->append(s1->getChar(i+1));
2476 s2 = new GString("<unicode>");
2480 printf(fmt, s2->getCString());
2483 printf(fmt, s1->getCString());
2489 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2493 if (infoDict->lookup(key, &obj)->isString()) {
2494 s = obj.getString()->getCString();
2495 if (s[0] == 'D' && s[1] == ':') {
2506 void storeDeviceParameter(char*name, char*value)
2508 parameter_t*p = new parameter_t();
2509 p->name = strdup(name);
2510 p->value = strdup(value);
2512 if(device_config_next) {
2513 device_config_next->next = p;
2514 device_config_next = p;
2517 device_config_next = p;
2521 void pdfswf_setparameter(char*name, char*value)
2523 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2524 if(!strcmp(name, "caplinewidth")) {
2525 caplinewidth = atof(value);
2526 } else if(!strcmp(name, "zoom")) {
2529 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2530 storeDeviceParameter("jpegsubpixels", buf);
2531 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2532 storeDeviceParameter("ppmsubpixels", buf);
2533 } else if(!strcmp(name, "jpegdpi")) {
2535 jpeg_dpi = atoi(value);
2536 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2537 storeDeviceParameter("jpegsubpixels", buf);
2538 } else if(!strcmp(name, "ppmdpi")) {
2540 ppm_dpi = atoi(value);
2541 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2542 storeDeviceParameter("ppmsubpixels", buf);
2543 } else if(!strcmp(name, "forceType0Fonts")) {
2544 forceType0Fonts = atoi(value);
2545 } else if(!strcmp(name, "fontdir")) {
2546 pdfswf_addfontdir(value);
2547 } else if(!strcmp(name, "languagedir")) {
2548 pdfswf_addlanguagedir(value);
2549 } else if(!strcmp(name, "fontconfig")) {
2550 config_use_fontconfig = atoi(value);
2552 storeDeviceParameter(name,value);
2555 void pdfswf_addfont(char*filename)
2558 memset(&f, 0, sizeof(fontfile_t));
2559 f.filename = filename;
2560 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2561 fonts[fontnum++] = f;
2563 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2567 static char* dirseparator()
2576 void pdfswf_addlanguagedir(char*dir)
2579 globalParams = new GlobalParams("");
2581 msg("<notice> Adding %s to language pack directories", dir);
2585 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2586 strcpy(config_file, dir);
2587 strcat(config_file, dirseparator());
2588 strcat(config_file, "add-to-xpdfrc");
2590 fi = fopen(config_file, "rb");
2592 msg("<error> Could not open %s", config_file);
2595 globalParams->parseFile(new GString(config_file), fi);
2599 void pdfswf_addfontdir(char*dirname)
2601 #ifdef HAVE_DIRENT_H
2602 msg("<notice> Adding %s to font directories", dirname);
2603 lastfontdir = strdup(dirname);
2604 DIR*dir = opendir(dirname);
2606 msg("<warning> Couldn't open directory %s\n", dirname);
2611 ent = readdir (dir);
2615 char*name = ent->d_name;
2621 if(!strncasecmp(&name[l-4], ".pfa", 4))
2623 if(!strncasecmp(&name[l-4], ".pfb", 4))
2625 if(!strncasecmp(&name[l-4], ".ttf", 4))
2629 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2630 strcpy(fontname, dirname);
2631 strcat(fontname, dirseparator());
2632 strcat(fontname, name);
2633 msg("<verbose> Adding %s to fonts", fontname);
2634 pdfswf_addfont(fontname);
2639 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2644 typedef struct _pdf_doc_internal
2649 } pdf_doc_internal_t;
2650 typedef struct _pdf_page_internal
2652 } pdf_page_internal_t;
2653 typedef struct _swf_output_internal
2655 SWFOutputDev*outputDev;
2656 } swf_output_internal_t;
2658 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2660 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2661 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2662 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2663 memset(i, 0, sizeof(pdf_doc_internal_t));
2664 pdf_doc->internal = i;
2666 GString *fileName = new GString(filename);
2672 globalParams = new GlobalParams("");
2675 if (userPassword && userPassword[0]) {
2676 userPW = new GString(userPassword);
2680 i->doc = new PDFDoc(fileName, userPW);
2684 if (!i->doc->isOk()) {
2689 i->doc->getDocInfo(&info);
2690 if (info.isDict() &&
2691 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2692 printInfoString(info.getDict(), "Title", "Title: %s\n");
2693 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2694 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2695 printInfoString(info.getDict(), "Author", "Author: %s\n");
2696 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2697 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2698 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2699 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2700 printf("Pages: %d\n", i->doc->getNumPages());
2701 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2702 printf("Encrypted: ");
2703 if (i->doc->isEncrypted()) {
2704 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2705 i->doc->okToPrint() ? "yes" : "no",
2706 i->doc->okToCopy() ? "yes" : "no",
2707 i->doc->okToChange() ? "yes" : "no",
2708 i->doc->okToAddNotes() ? "yes" : "no");
2715 pdf_doc->num_pages = i->doc->getNumPages();
2717 if (i->doc->isEncrypted()) {
2718 if(!i->doc->okToCopy()) {
2719 printf("PDF disallows copying.\n");
2722 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2726 InfoOutputDev*io = new InfoOutputDev();
2728 for(t=1;t<=pdf_doc->num_pages;t++) {
2729 i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, /*usemediabox*/true, /*crop*/true, /*doLinks*/(int)1);
2740 delete globalParams;globalParams=0;
2741 Object::memCheck(stderr);
2746 void pdf_destroy(pdf_doc_t*pdf_doc)
2748 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2750 delete i->doc; i->doc=0;
2753 delete i->info;i->info=0;
2756 free(pdf_doc->internal);pdf_doc->internal=0;
2757 free(pdf_doc);pdf_doc=0;
2760 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2762 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2764 if(page < 1 || page > pdf_doc->num_pages)
2767 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2768 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2769 memset(pi, 0, sizeof(pdf_page_internal_t));
2770 pdf_page->internal = pi;
2772 pdf_page->parent = pdf_doc;
2773 pdf_page->nr = page;
2777 void pdf_page_destroy(pdf_page_t*pdf_page)
2779 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2780 free(pdf_page->internal);pdf_page->internal = 0;
2781 free(pdf_page);pdf_page=0;
2784 swf_output_t* swf_output_init()
2786 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2787 memset(swf_output, 0, sizeof(swf_output_t));
2788 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2789 memset(i, 0, sizeof(swf_output_internal_t));
2790 swf_output->internal = i;
2792 i->outputDev = new SWFOutputDev();
2796 void swf_output_setparameter(swf_output_t*swf, char*name, char*value)
2798 pdfswf_setparameter(name, value);
2801 void swf_output_startframe(swf_output_t*swf, int width, int height)
2803 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2804 i->outputDev->startFrame(width, height);
2807 void swf_output_endframe(swf_output_t*swf)
2809 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2810 i->outputDev->endframe();
2813 void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage)
2815 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2816 SWFOutputDev*o = i->outputDev;
2822 o->pagebuflen = 1024;
2823 o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
2824 memset(o->pages, -1, o->pagebuflen*sizeof(int));
2826 while(pdfpage >= o->pagebuflen)
2828 int oldlen = o->pagebuflen;
2829 o->pagebuflen+=1024;
2830 o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
2831 memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
2834 o->pages[pdfpage] = outputpage;
2835 if(pdfpage>o->pagepos)
2836 o->pagepos = pdfpage;
2839 int swf_output_save(swf_output_t*swf, char*filename)
2841 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2842 int ret = i->outputDev->save(filename);
2846 void* swf_output_get(swf_output_t*swf,char*name)
2848 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2849 void* ret = i->outputDev->get(name);
2853 void swf_output_destroy(swf_output_t*output)
2855 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2856 delete i->outputDev; i->outputDev=0;
2857 free(output->internal);output->internal=0;
2861 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2863 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2864 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2867 msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2872 gfxdevice_t*dev = si->outputDev->output;
2873 dev->setparameter(dev, "protect", "1");
2875 si->outputDev->setInfo(pi->info);
2876 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2877 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
2880 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2882 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2883 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2885 si->outputDev->setMove(x,y);
2886 if((x1|y1|x2|y2)==0) x2++;
2887 si->outputDev->setClip(x1,y1,x2,y2);
2889 pdf_page_render2(page, output);
2891 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2893 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2894 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2896 si->outputDev->setMove(0,0);
2897 si->outputDev->setClip(0,0,0,0);
2899 pdf_page_render2(page, output);
2903 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2905 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2906 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2907 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2908 memset(info, 0, sizeof(pdf_page_info_t));
2910 InfoOutputDev*output = new InfoOutputDev;
2912 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
2914 info->xMin = output->x1;
2915 info->yMin = output->y1;
2916 info->xMax = output->x2;
2917 info->yMax = output->y2;
2918 info->number_of_images = output->num_images;
2919 info->number_of_links = output->num_links;
2920 info->number_of_fonts = output->num_fonts;
2927 void pdf_page_info_destroy(pdf_page_info_t*info)