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) {
1583 sprintf(buf, "page%d", lpage);
1584 output->drawlink(output, points, buf);
1588 output->drawlink(output, points, url);
1591 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1595 void SWFOutputDev::saveState(GfxState *state) {
1596 msg("<trace> saveState\n");
1599 msg("<error> Too many nested states in pdf.");
1603 states[statepos].clipping = 0; //? shouldn't this be the current value?
1604 states[statepos].textRender = states[statepos-1].textRender;
1607 void SWFOutputDev::restoreState(GfxState *state) {
1608 msg("<trace> restoreState\n");
1610 while(states[statepos].clipping) {
1611 output->endclip(output);
1612 states[statepos].clipping--;
1617 char* SWFOutputDev::searchFont(char*name)
1621 int is_standard_font = 0;
1623 msg("<verbose> SearchFont(%s)", name);
1625 /* see if it is a pdf standard font */
1626 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1628 if(!strcmp(name, pdf2t1map[i].pdffont))
1630 name = pdf2t1map[i].filename;
1631 is_standard_font = 1;
1635 /* look in all font files */
1636 for(i=0;i<fontnum;i++)
1638 if(strstr(fonts[i].filename, name))
1640 if(!fonts[i].used) {
1643 if(!is_standard_font)
1644 msg("<notice> Using %s for %s", fonts[i].filename, name);
1646 return strdup(fonts[i].filename);
1652 void SWFOutputDev::updateLineWidth(GfxState *state)
1654 double width = state->getTransformedLineWidth();
1655 //swfoutput_setlinewidth(&output, width);
1658 void SWFOutputDev::updateLineCap(GfxState *state)
1660 int c = state->getLineCap();
1663 void SWFOutputDev::updateLineJoin(GfxState *state)
1665 int j = state->getLineJoin();
1668 void SWFOutputDev::updateFillColor(GfxState *state)
1671 double opaq = state->getFillOpacity();
1672 state->getFillRGB(&rgb);
1674 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1677 void SWFOutputDev::updateStrokeColor(GfxState *state)
1680 double opaq = state->getStrokeOpacity();
1681 state->getStrokeRGB(&rgb);
1682 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1685 void FoFiWrite(void *stream, char *data, int len)
1687 fwrite(data, len, 1, (FILE*)stream);
1690 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1692 char*tmpFileName = NULL;
1698 Object refObj, strObj;
1700 tmpFileName = mktmpname(namebuf);
1703 ret = font->getEmbeddedFontID(&embRef);
1705 msg("<verbose> Didn't get embedded font id");
1706 /* not embedded- the caller should now search the font
1707 directories for this font */
1711 f = fopen(tmpFileName, "wb");
1713 msg("<error> Couldn't create temporary Type 1 font file");
1717 /*if(font->isCIDFont()) {
1718 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1719 GString c = cidFont->getCollection();
1720 msg("<notice> Collection: %s", c.getCString());
1723 //if (font->getType() == fontType1C) {
1724 if (0) { //font->getType() == fontType1C) {
1725 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1727 msg("<error> Couldn't read embedded font file");
1730 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1732 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1733 //cvt->convertToCIDType0("test", f);
1734 //cvt->convertToType0("test", f);
1737 } else if(font->getType() == fontTrueType) {
1738 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1739 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1741 msg("<error> Couldn't read embedded font file");
1744 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1745 cvt->writeTTF(FoFiWrite, f);
1749 font->getEmbeddedFontID(&embRef);
1750 refObj.initRef(embRef.num, embRef.gen);
1751 refObj.fetch(ref, &strObj);
1753 strObj.streamReset();
1758 f4[t] = strObj.streamGetChar();
1759 f4c[t] = (char)f4[t];
1764 if(!strncmp(f4c, "true", 4)) {
1765 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1766 Change this on the fly */
1767 f4[0] = f4[2] = f4[3] = 0;
1775 while ((c = strObj.streamGetChar()) != EOF) {
1779 strObj.streamClose();
1784 return strdup(tmpFileName);
1787 char* searchForSuitableFont(GfxFont*gfxFont)
1789 char*name = getFontName(gfxFont);
1793 if(!config_use_fontconfig)
1796 #ifdef HAVE_FONTCONFIG
1797 FcPattern *pattern, *match;
1801 static int fcinitcalled = false;
1803 msg("<debug> searchForSuitableFont(%s)", name);
1805 // call init ony once
1806 if (!fcinitcalled) {
1807 msg("<debug> Initializing FontConfig...");
1808 fcinitcalled = true;
1810 msg("<debug> FontConfig Initialization failed. Disabling.");
1811 config_use_fontconfig = 0;
1814 msg("<debug> ...initialized FontConfig");
1817 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1818 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1819 if (gfxFont->isItalic()) // check for italic
1820 msg("<debug> FontConfig: Adding Italic Slant");
1821 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1822 if (gfxFont->isBold()) // check for bold
1823 msg("<debug> FontConfig: Adding Bold Weight");
1824 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1826 msg("<debug> FontConfig: Try to match...");
1827 // configure and match using the original font name
1828 FcConfigSubstitute(0, pattern, FcMatchPattern);
1829 FcDefaultSubstitute(pattern);
1830 match = FcFontMatch(0, pattern, &result);
1832 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1833 msg("<debug> FontConfig: family=%s", (char*)v);
1834 // if we get an exact match
1835 if (strcmp((char *)v, name) == 0) {
1836 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1837 filename = strdup((char*)v); // mem leak
1838 char *nfn = strrchr(filename, '/');
1839 if(nfn) fontname = strdup(nfn+1);
1840 else fontname = filename;
1842 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1844 // initialize patterns
1845 FcPatternDestroy(pattern);
1846 FcPatternDestroy(match);
1848 // now match against serif etc.
1849 if (gfxFont->isSerif()) {
1850 msg("<debug> FontConfig: Create Serif Family Pattern");
1851 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1852 } else if (gfxFont->isFixedWidth()) {
1853 msg("<debug> FontConfig: Create Monospace Family Pattern");
1854 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1856 msg("<debug> FontConfig: Create Sans Family Pattern");
1857 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1861 if (gfxFont->isItalic()) {
1862 msg("<debug> FontConfig: Adding Italic Slant");
1863 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1866 if (gfxFont->isBold()) {
1867 msg("<debug> FontConfig: Adding Bold Weight");
1868 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1871 msg("<debug> FontConfig: Try to match... (2)");
1872 // configure and match using serif etc
1873 FcConfigSubstitute (0, pattern, FcMatchPattern);
1874 FcDefaultSubstitute (pattern);
1875 match = FcFontMatch (0, pattern, &result);
1877 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1878 filename = strdup((char*)v); // mem leak
1879 char *nfn = strrchr(filename, '/');
1880 if(nfn) fontname = strdup(nfn+1);
1881 else fontname = filename;
1883 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1887 //printf("FONTCONFIG: pattern");
1888 //FcPatternPrint(pattern);
1889 //printf("FONTCONFIG: match");
1890 //FcPatternPrint(match);
1892 FcPatternDestroy(pattern);
1893 FcPatternDestroy(match);
1895 pdfswf_addfont(filename);
1902 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1904 char*fontname = 0, *filename = 0;
1905 msg("<notice> substituteFont(%s)", oldname);
1907 if(!(fontname = searchForSuitableFont(gfxFont))) {
1908 fontname = "Times-Roman";
1910 filename = searchFont(fontname);
1912 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1916 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1917 msg("<fatal> Too many fonts in file.");
1921 substitutesource[substitutepos] = strdup(oldname); //mem leak
1922 substitutetarget[substitutepos] = fontname;
1923 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1926 return strdup(filename); //mem leak
1929 void unlinkfont(char* filename)
1936 if(!strncmp(&filename[l-4],".afm",4)) {
1937 memcpy(&filename[l-4],".pfb",4);
1939 memcpy(&filename[l-4],".pfa",4);
1941 memcpy(&filename[l-4],".afm",4);
1944 if(!strncmp(&filename[l-4],".pfa",4)) {
1945 memcpy(&filename[l-4],".afm",4);
1947 memcpy(&filename[l-4],".pfa",4);
1950 if(!strncmp(&filename[l-4],".pfb",4)) {
1951 memcpy(&filename[l-4],".afm",4);
1953 memcpy(&filename[l-4],".pfb",4);
1958 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1964 int SWFOutputDev::setGfxFont(char*id, char*filename, double maxSize)
1967 fontlist_t*last=0,*l = this->fontlist;
1969 /* TODO: should this be part of the state? */
1972 if(!strcmp(l->id, id)) {
1973 current_font_id = l->id;
1974 current_gfxfont = l->font;
1976 output->addfont(output, id, current_gfxfont);
1981 if(!filename) return 0;
1983 /* A font size of e.g. 9 means the font will be scaled down by
1984 1024 and scaled up by 9. So to have a maximum error of 1/20px,
1985 we have to divide 0.05 by (fontsize/1024)
1987 double quality = (1024 * 0.05) / maxSize;
1989 msg("<verbose> Loading %s...", filename);
1990 font = gfxfont_load(filename, quality);
1991 msg("<verbose> Font %s loaded successfully", filename);
1995 l->filename = strdup(filename);
1998 current_font_id = l->id;
1999 current_gfxfont = l->font;
2005 output->addfont(output, id, current_gfxfont);
2009 void SWFOutputDev::updateFont(GfxState *state)
2011 GfxFont*gfxFont = state->getFont();
2016 char * fontid = getFontID(gfxFont);
2017 double maxSize = 1.0;
2020 maxSize = this->info->getMaximumFontSize(fontid);
2024 /* first, look if we substituted this font before-
2025 this way, we don't initialize the T1 Fonts
2027 for(t=0;t<substitutepos;t++) {
2028 if(!strcmp(fontid, substitutesource[t])) {
2029 free(fontid);fontid=0;
2030 fontid = strdup(substitutetarget[t]);
2035 /* second, see if this is a font which was used before-
2036 if so, we are done */
2037 if(setGfxFont(fontid, 0, 0)) {
2041 /* if(swfoutput_queryfont(&output, fontid))
2042 swfoutput_setfont(&output, fontid, 0);
2044 msg("<debug> updateFont(%s) [cached]", fontid);
2048 // look for Type 3 font
2049 if (gfxFont->getType() == fontType3) {
2051 type3Warning = gTrue;
2052 showFontError(gfxFont, 2);
2058 /* now either load the font, or find a substitution */
2061 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
2066 (gfxFont->getType() == fontType1 ||
2067 gfxFont->getType() == fontType1C ||
2068 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
2069 gfxFont->getType() == fontTrueType ||
2070 gfxFont->getType() == fontCIDType2
2073 fileName = writeEmbeddedFontToFile(xref, gfxFont);
2074 if(!fileName) showFontError(gfxFont,0);
2077 char * fontname = getFontName(gfxFont);
2078 fileName = searchFont(fontname);
2079 if(!fileName) showFontError(gfxFont,0);
2083 char * fontname = getFontName(gfxFont);
2084 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
2087 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into %s", fontname, lastfontdir);
2089 msg("<warning> Try specifying one or more font directories");
2091 fileName = substituteFont(gfxFont, fontid);
2092 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
2093 msg("<notice> Font is now %s (%s)", fontid, fileName);
2097 msg("<error> Couldn't set font %s\n", fontid);
2102 msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
2103 dumpFontInfo("<verbose>", gfxFont);
2105 //swfoutput_setfont(&output, fontid, fileName);
2107 if(!setGfxFont(fontid, 0, 0)) {
2108 setGfxFont(fontid, fileName, maxSize);
2112 unlinkfont(fileName);
2120 #define SQR(x) ((x)*(x))
2122 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
2124 if((newwidth<2 || newheight<2) ||
2125 (width<=newwidth || height<=newheight))
2127 unsigned char*newdata;
2129 newdata= (unsigned char*)malloc(newwidth*newheight);
2131 double fx = (double)(width)/newwidth;
2132 double fy = (double)(height)/newheight;
2134 int blocksize = (int)(8192/(fx*fy));
2135 int r = 8192*256/palettesize;
2136 for(x=0;x<newwidth;x++) {
2137 double ex = px + fx;
2138 int fromx = (int)px;
2140 int xweight1 = (int)(((fromx+1)-px)*256);
2141 int xweight2 = (int)((ex-tox)*256);
2143 for(y=0;y<newheight;y++) {
2144 double ey = py + fy;
2145 int fromy = (int)py;
2147 int yweight1 = (int)(((fromy+1)-py)*256);
2148 int yweight2 = (int)((ey-toy)*256);
2151 for(xx=fromx;xx<=tox;xx++)
2152 for(yy=fromy;yy<=toy;yy++) {
2153 int b = 1-data[width*yy+xx];
2155 if(xx==fromx) weight = (weight*xweight1)/256;
2156 if(xx==tox) weight = (weight*xweight2)/256;
2157 if(yy==fromy) weight = (weight*yweight1)/256;
2158 if(yy==toy) weight = (weight*yweight2)/256;
2161 //if(a) a=(palettesize-1)*r/blocksize;
2162 newdata[y*newwidth+x] = (a*blocksize)/r;
2170 #define IMAGE_TYPE_JPEG 0
2171 #define IMAGE_TYPE_LOSSLESS 1
2173 static void drawimage(gfxdevice_t*dev, gfxcolor_t* data, int sizex,int sizey,
2174 double x1,double y1,
2175 double x2,double y2,
2176 double x3,double y3,
2177 double x4,double y4, int type)
2179 gfxcolor_t*newpic=0;
2181 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2182 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2184 gfxline_t p1,p2,p3,p4,p5;
2185 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2186 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2187 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2188 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2189 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2191 {p1.x = (int)(p1.x*20)/20.0;
2192 p1.y = (int)(p1.y*20)/20.0;
2193 p2.x = (int)(p2.x*20)/20.0;
2194 p2.y = (int)(p2.y*20)/20.0;
2195 p3.x = (int)(p3.x*20)/20.0;
2196 p3.y = (int)(p3.y*20)/20.0;
2197 p4.x = (int)(p4.x*20)/20.0;
2198 p4.y = (int)(p4.y*20)/20.0;
2199 p5.x = (int)(p5.x*20)/20.0;
2200 p5.y = (int)(p5.y*20)/20.0;
2207 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2208 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2213 img.data = (gfxcolor_t*)data;
2217 if(type == IMAGE_TYPE_JPEG)
2218 /* TODO: pass image_dpi to device instead */
2219 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2221 dev->fillbitmap(dev, &p1, &img, &m, 0);
2224 void drawimagejpeg(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2225 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2227 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2230 void drawimagelossless(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2231 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2233 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2237 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2238 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2239 GBool inlineImg, int mask, int*maskColors)
2244 double x1,y1,x2,y2,x3,y3,x4,y4;
2245 ImageStream *imgStr;
2252 ncomps = colorMap->getNumPixelComps();
2253 bits = colorMap->getBits();
2255 imgStr = new ImageStream(str, width, ncomps,bits);
2258 if(!width || !height || (height<=1 && width<=1))
2260 msg("<verbose> Ignoring %d by %d image", width, height);
2261 unsigned char buf[8];
2263 for (y = 0; y < height; ++y)
2264 for (x = 0; x < width; ++x) {
2265 imgStr->getPixel(buf);
2271 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1+= user_movey;
2272 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2+= user_movey;
2273 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3+= user_movey;
2274 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4+= user_movey;
2276 if(!pbminfo && !(str->getKind()==strDCT)) {
2278 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2282 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2284 if(!jpeginfo && (str->getKind()==strDCT)) {
2285 msg("<notice> file contains jpeg pictures");
2291 unsigned char buf[8];
2293 unsigned char*pic = new unsigned char[width*height];
2294 gfxcolor_t pal[256];
2296 state->getFillRGB(&rgb);
2298 memset(pal,255,sizeof(pal));
2299 pal[0].r = (int)(colToByte(rgb.r)); pal[1].r = 0;
2300 pal[0].g = (int)(colToByte(rgb.g)); pal[1].g = 0;
2301 pal[0].b = (int)(colToByte(rgb.b)); pal[1].b = 0;
2302 pal[0].a = 255; pal[1].a = 0;
2305 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2306 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2307 for (y = 0; y < height; ++y)
2308 for (x = 0; x < width; ++x)
2310 imgStr->getPixel(buf);
2313 pic[width*y+x] = buf[0];
2316 /* the size of the drawn image is added to the identifier
2317 as the same image may require different bitmaps if displayed
2318 at different sizes (due to antialiasing): */
2321 unsigned char*pic2 = 0;
2324 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2333 height = realheight;
2337 /* make a black/white palette */
2339 float r = 255/(numpalette-1);
2341 for(t=0;t<numpalette;t++) {
2342 pal[t].r = colToByte(rgb.r);
2343 pal[t].g = colToByte(rgb.g);
2344 pal[t].b = colToByte(rgb.b);
2345 pal[t].a = (unsigned char)(t*r);
2349 gfxcolor_t*pic2 = new gfxcolor_t[width*height];
2350 for (y = 0; y < height; ++y) {
2351 for (x = 0; x < width; ++x) {
2352 pic2[width*y+x] = pal[pic[y*width+x]];
2355 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2364 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2365 gfxcolor_t*pic=new gfxcolor_t[width*height];
2366 for (y = 0; y < height; ++y) {
2367 for (x = 0; x < width; ++x) {
2368 imgStr->getPixel(pixBuf);
2369 colorMap->getRGB(pixBuf, &rgb);
2370 pic[width*y+x].r = (unsigned char)(colToByte(rgb.r));
2371 pic[width*y+x].g = (unsigned char)(colToByte(rgb.g));
2372 pic[width*y+x].b = (unsigned char)(colToByte(rgb.b));
2373 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2376 if(str->getKind()==strDCT)
2377 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2379 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2384 gfxcolor_t*pic=new gfxcolor_t[width*height];
2385 gfxcolor_t pal[256];
2387 for(t=0;t<256;t++) {
2389 colorMap->getRGB(pixBuf, &rgb);
2390 /*if(maskColors && *maskColors==t) {
2391 msg("<notice> Color %d is transparent", t);
2392 if (imgData->maskColors) {
2394 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2395 if (pix[i] < imgData->maskColors[2*i] ||
2396 pix[i] > imgData->maskColors[2*i+1]) {
2411 pal[t].r = (unsigned char)(rgb.r * 255 + 0.5);
2412 pal[t].g = (unsigned char)(rgb.g * 255 + 0.5);
2413 pal[t].b = (unsigned char)(rgb.b * 255 + 0.5);
2414 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2417 for (y = 0; y < height; ++y) {
2418 for (x = 0; x < width; ++x) {
2419 imgStr->getPixel(pixBuf);
2420 pic[width*y+x] = pal[pixBuf[0]];
2423 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2431 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2432 int width, int height, GBool invert,
2435 if(states[statepos].textRender & 4) //clipped
2437 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2438 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
2441 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2442 int width, int height, GfxImageColorMap *colorMap,
2443 int *maskColors, GBool inlineImg)
2445 if(states[statepos].textRender & 4) //clipped
2448 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
2449 colorMap?"colorMap":"no colorMap",
2450 maskColors?"maskColors":"no maskColors",
2453 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2454 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2455 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
2458 //SWFOutputDev*output = 0;
2460 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2465 if (infoDict->lookup(key, &obj)->isString()) {
2466 s1 = obj.getString();
2467 if ((s1->getChar(0) & 0xff) == 0xfe &&
2468 (s1->getChar(1) & 0xff) == 0xff) {
2470 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2471 if (s1->getChar(i) == '\0') {
2472 s2->append(s1->getChar(i+1));
2475 s2 = new GString("<unicode>");
2479 printf(fmt, s2->getCString());
2482 printf(fmt, s1->getCString());
2488 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2492 if (infoDict->lookup(key, &obj)->isString()) {
2493 s = obj.getString()->getCString();
2494 if (s[0] == 'D' && s[1] == ':') {
2505 void storeDeviceParameter(char*name, char*value)
2507 parameter_t*p = new parameter_t();
2508 p->name = strdup(name);
2509 p->value = strdup(value);
2511 if(device_config_next) {
2512 device_config_next->next = p;
2513 device_config_next = p;
2516 device_config_next = p;
2520 void pdfswf_setparameter(char*name, char*value)
2522 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2523 if(!strcmp(name, "caplinewidth")) {
2524 caplinewidth = atof(value);
2525 } else if(!strcmp(name, "zoom")) {
2528 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2529 storeDeviceParameter("jpegsubpixels", buf);
2530 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2531 storeDeviceParameter("ppmsubpixels", buf);
2532 } else if(!strcmp(name, "jpegdpi")) {
2534 jpeg_dpi = atoi(value);
2535 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2536 storeDeviceParameter("jpegsubpixels", buf);
2537 } else if(!strcmp(name, "ppmdpi")) {
2539 ppm_dpi = atoi(value);
2540 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2541 storeDeviceParameter("ppmsubpixels", buf);
2542 } else if(!strcmp(name, "forceType0Fonts")) {
2543 forceType0Fonts = atoi(value);
2544 } else if(!strncmp(name, "fontdir", strlen("fontdir"))) {
2545 pdfswf_addfontdir(value);
2546 } else if(!strncmp(name, "languagedir", strlen("languagedir"))) {
2547 pdfswf_addlanguagedir(value);
2548 } else if(!strcmp(name, "fontconfig")) {
2549 config_use_fontconfig = atoi(value);
2551 storeDeviceParameter(name,value);
2554 void pdfswf_addfont(char*filename)
2557 memset(&f, 0, sizeof(fontfile_t));
2558 f.filename = filename;
2559 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2560 fonts[fontnum++] = f;
2562 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2566 static char* dirseparator()
2575 void pdfswf_addlanguagedir(char*dir)
2578 globalParams = new GlobalParams("");
2580 msg("<notice> Adding %s to language pack directories", dir);
2584 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2585 strcpy(config_file, dir);
2586 strcat(config_file, dirseparator());
2587 strcat(config_file, "add-to-xpdfrc");
2589 fi = fopen(config_file, "rb");
2591 msg("<error> Could not open %s", config_file);
2594 globalParams->parseFile(new GString(config_file), fi);
2598 void pdfswf_addfontdir(char*dirname)
2600 #ifdef HAVE_DIRENT_H
2601 msg("<notice> Adding %s to font directories", dirname);
2602 lastfontdir = strdup(dirname);
2603 DIR*dir = opendir(dirname);
2605 msg("<warning> Couldn't open directory %s\n", dirname);
2610 ent = readdir (dir);
2614 char*name = ent->d_name;
2620 if(!strncasecmp(&name[l-4], ".pfa", 4))
2622 if(!strncasecmp(&name[l-4], ".pfb", 4))
2624 if(!strncasecmp(&name[l-4], ".ttf", 4))
2628 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2629 strcpy(fontname, dirname);
2630 strcat(fontname, dirseparator());
2631 strcat(fontname, name);
2632 msg("<verbose> Adding %s to fonts", fontname);
2633 pdfswf_addfont(fontname);
2638 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2643 typedef struct _pdf_doc_internal
2648 } pdf_doc_internal_t;
2649 typedef struct _pdf_page_internal
2651 } pdf_page_internal_t;
2652 typedef struct _swf_output_internal
2654 SWFOutputDev*outputDev;
2655 } swf_output_internal_t;
2657 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2659 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2660 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2661 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2662 memset(i, 0, sizeof(pdf_doc_internal_t));
2663 pdf_doc->internal = i;
2665 GString *fileName = new GString(filename);
2671 globalParams = new GlobalParams("");
2674 if (userPassword && userPassword[0]) {
2675 userPW = new GString(userPassword);
2679 i->doc = new PDFDoc(fileName, userPW);
2683 if (!i->doc->isOk()) {
2688 i->doc->getDocInfo(&info);
2689 if (info.isDict() &&
2690 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2691 printInfoString(info.getDict(), "Title", "Title: %s\n");
2692 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2693 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2694 printInfoString(info.getDict(), "Author", "Author: %s\n");
2695 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2696 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2697 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2698 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2699 printf("Pages: %d\n", i->doc->getNumPages());
2700 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2701 printf("Encrypted: ");
2702 if (i->doc->isEncrypted()) {
2703 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2704 i->doc->okToPrint() ? "yes" : "no",
2705 i->doc->okToCopy() ? "yes" : "no",
2706 i->doc->okToChange() ? "yes" : "no",
2707 i->doc->okToAddNotes() ? "yes" : "no");
2714 pdf_doc->num_pages = i->doc->getNumPages();
2716 if (i->doc->isEncrypted()) {
2717 if(!i->doc->okToCopy()) {
2718 printf("PDF disallows copying.\n");
2721 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2725 InfoOutputDev*io = new InfoOutputDev();
2727 for(t=1;t<=pdf_doc->num_pages;t++) {
2728 i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, /*usemediabox*/true, /*crop*/true, /*doLinks*/(int)1);
2739 delete globalParams;globalParams=0;
2740 Object::memCheck(stderr);
2745 void pdf_destroy(pdf_doc_t*pdf_doc)
2747 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2749 delete i->doc; i->doc=0;
2752 delete i->info;i->info=0;
2755 free(pdf_doc->internal);pdf_doc->internal=0;
2756 free(pdf_doc);pdf_doc=0;
2759 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2761 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2763 if(page < 1 || page > pdf_doc->num_pages)
2766 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2767 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2768 memset(pi, 0, sizeof(pdf_page_internal_t));
2769 pdf_page->internal = pi;
2771 pdf_page->parent = pdf_doc;
2772 pdf_page->nr = page;
2776 void pdf_page_destroy(pdf_page_t*pdf_page)
2778 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2779 free(pdf_page->internal);pdf_page->internal = 0;
2780 free(pdf_page);pdf_page=0;
2783 swf_output_t* swf_output_init()
2785 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2786 memset(swf_output, 0, sizeof(swf_output_t));
2787 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2788 memset(i, 0, sizeof(swf_output_internal_t));
2789 swf_output->internal = i;
2791 i->outputDev = new SWFOutputDev();
2795 void swf_output_setparameter(swf_output_t*swf, char*name, char*value)
2797 pdfswf_setparameter(name, value);
2800 void swf_output_startframe(swf_output_t*swf, int width, int height)
2802 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2803 i->outputDev->startFrame(width, height);
2806 void swf_output_endframe(swf_output_t*swf)
2808 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2809 i->outputDev->endframe();
2812 void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage)
2814 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2815 SWFOutputDev*o = i->outputDev;
2821 o->pagebuflen = 1024;
2822 o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
2823 memset(o->pages, -1, o->pagebuflen*sizeof(int));
2825 while(pdfpage >= o->pagebuflen)
2827 int oldlen = o->pagebuflen;
2828 o->pagebuflen+=1024;
2829 o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
2830 memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
2833 o->pages[pdfpage] = outputpage;
2834 if(pdfpage>o->pagepos)
2835 o->pagepos = pdfpage;
2838 int swf_output_save(swf_output_t*swf, char*filename)
2840 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2841 int ret = i->outputDev->save(filename);
2845 void* swf_output_get(swf_output_t*swf,char*name)
2847 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2848 void* ret = i->outputDev->get(name);
2852 void swf_output_destroy(swf_output_t*output)
2854 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2855 delete i->outputDev; i->outputDev=0;
2856 free(output->internal);output->internal=0;
2860 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2862 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2863 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2866 msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2871 gfxdevice_t*dev = si->outputDev->output;
2872 dev->setparameter(dev, "protect", "1");
2874 si->outputDev->setInfo(pi->info);
2875 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2876 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
2879 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2881 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2882 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2884 si->outputDev->setMove(x,y);
2885 if((x1|y1|x2|y2)==0) x2++;
2886 si->outputDev->setClip(x1,y1,x2,y2);
2888 pdf_page_render2(page, output);
2890 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2892 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2893 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2895 si->outputDev->setMove(0,0);
2896 si->outputDev->setClip(0,0,0,0);
2898 pdf_page_render2(page, output);
2902 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2904 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2905 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2906 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2907 memset(info, 0, sizeof(pdf_page_info_t));
2909 InfoOutputDev*output = new InfoOutputDev;
2911 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
2913 info->xMin = output->x1;
2914 info->yMin = output->y1;
2915 info->xMax = output->x2;
2916 info->yMax = output->y2;
2917 info->number_of_images = output->num_images;
2918 info->number_of_links = output->num_links;
2919 info->number_of_fonts = output->num_fonts;
2926 void pdf_page_info_destroy(pdf_page_info_t*info)