2 implements a pdf output device (OutputDev).
4 This file is part of swftools.
6 Swftools is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 Swftools is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with swftools; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
25 #include "../config.h"
29 #ifdef HAVE_SYS_STAT_H
32 #ifdef HAVE_FONTCONFIG
33 #include <fontconfig.h>
49 #include "OutputDev.h"
52 #include "CharCodeToUnicode.h"
53 #include "NameToUnicodeTable.h"
54 #include "GlobalParams.h"
59 #include "FoFiType1C.h"
60 #include "FoFiTrueType.h"
63 #include "SWFOutputDev.h"
65 //swftools header files
66 #include "swfoutput.h"
67 #include "../lib/log.h"
68 #include "../lib/gfxdevice.h"
69 #include "../lib/gfxtools.h"
70 #include "../lib/gfxfont.h"
74 typedef struct _fontfile
80 typedef struct _parameter
84 struct _parameter*next;
87 static parameter_t* device_config = 0;
88 static parameter_t* device_config_next = 0;
91 static fontfile_t fonts[2048];
92 static int fontnum = 0;
94 static int config_use_fontconfig = 1;
97 static double caplinewidth = 3.0;
98 static double zoom = 72; /* xpdf: 86 */
99 static int forceType0Fonts = 1;
101 static void printInfoString(Dict *infoDict, char *key, char *fmt);
102 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
108 {"Times-Roman", "n021003l"},
109 {"Times-Italic", "n021023l"},
110 {"Times-Bold", "n021004l"},
111 {"Times-BoldItalic", "n021024l"},
112 {"Helvetica", "n019003l"},
113 {"Helvetica-Oblique", "n019023l"},
114 {"Helvetica-Bold", "n019004l"},
115 {"Helvetica-BoldOblique", "n019024l"},
116 {"Courier", "n022003l"},
117 {"Courier-Oblique", "n022023l"},
118 {"Courier-Bold", "n022004l"},
119 {"Courier-BoldOblique", "n022024l"},
120 {"Symbol", "s050000l"},
121 {"ZapfDingbats", "d050000l"}};
123 class SWFOutputState {
129 this->textRender = 0;
133 typedef struct _fontlist
143 class SWFOutputDev: public OutputDev {
151 virtual ~SWFOutputDev() ;
153 void setMove(int x,int y);
154 void setClip(int x1,int y1,int x2,int y2);
156 void setInfo(InfoOutputDev*info) {this->info = info;}
158 int save(char*filename);
161 void startFrame(int width, int height);
163 virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
166 void* get(char*name);
168 //----- get info about output device
170 // Does this device use upside-down coordinates?
171 // (Upside-down means (0,0) is the top left corner of the page.)
172 virtual GBool upsideDown();
174 // Does this device use drawChar() or drawString()?
175 virtual GBool useDrawChar();
177 // Can this device draw gradients?
178 virtual GBool useGradients();
180 virtual GBool interpretType3Chars() {return gTrue;}
182 //----- initialization and control
184 void setXRef(PDFDoc*doc, XRef *xref);
187 virtual void drawLink(Link *link, Catalog *catalog) ;
189 //----- save/restore graphics state
190 virtual void saveState(GfxState *state) ;
191 virtual void restoreState(GfxState *state) ;
193 //----- update graphics state
195 virtual void updateFont(GfxState *state);
196 virtual void updateFillColor(GfxState *state);
197 virtual void updateStrokeColor(GfxState *state);
198 virtual void updateLineWidth(GfxState *state);
199 virtual void updateLineJoin(GfxState *state);
200 virtual void updateLineCap(GfxState *state);
202 virtual void updateAll(GfxState *state)
205 updateFillColor(state);
206 updateStrokeColor(state);
207 updateLineWidth(state);
208 updateLineJoin(state);
209 updateLineCap(state);
212 //----- path painting
213 virtual void stroke(GfxState *state) ;
214 virtual void fill(GfxState *state) ;
215 virtual void eoFill(GfxState *state) ;
217 //----- path clipping
218 virtual void clip(GfxState *state) ;
219 virtual void eoClip(GfxState *state) ;
222 virtual void beginString(GfxState *state, GString *s) ;
223 virtual void endString(GfxState *state) ;
224 virtual void endTextObject(GfxState *state);
225 virtual void drawChar(GfxState *state, double x, double y,
226 double dx, double dy,
227 double originX, double originY,
228 CharCode code, Unicode *u, int uLen);
230 //----- image drawing
231 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
232 int width, int height, GBool invert,
234 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
235 int width, int height, GfxImageColorMap *colorMap,
236 int *maskColors, GBool inlineImg);
238 virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
239 virtual void endType3Char(GfxState *state);
241 virtual void type3D0(GfxState *state, double wx, double wy);
242 virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
245 void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
246 int width, int height, GfxImageColorMap*colorMap, GBool invert,
247 GBool inlineImg, int mask, int *maskColors);
248 int SWFOutputDev::setGfxFont(char*id, char*filename, double quality);
249 void strokeGfxline(GfxState *state, gfxline_t*line);
250 void clipToGfxLine(GfxState *state, gfxline_t*line);
251 void fillGfxLine(GfxState *state, gfxline_t*line);
255 gfxresult_t*result; //filled when complete
257 char outer_clip_box; //whether the page clip box is still on
260 SWFOutputState states[64];
268 char* searchFont(char*name);
269 char* substituteFont(GfxFont*gfxFont, char*oldname);
270 char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
272 int textmodeinfo; // did we write "Text will be rendered as polygon" yet?
273 int jpeginfo; // did we write "File contains jpegs" yet?
274 int pbminfo; // did we write "File contains jpegs" yet?
275 int linkinfo; // did we write "File contains links" yet?
276 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
277 int gradientinfo; // did we write "File contains Gradients yet?
279 int type3active; // are we between beginType3()/endType3()?
285 char* substitutetarget[256];
286 char* substitutesource[256];
289 int user_movex,user_movey;
290 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
292 gfxline_t* current_text_stroke;
293 gfxline_t* current_text_clip;
294 char* current_font_id;
295 gfxfont_t* current_gfxfont;
296 gfxmatrix_t current_font_matrix;
298 fontlist_t* fontlist;
304 friend void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage);
307 typedef struct _drawnchar
325 chars = (drawnchar_t*)malloc(sizeof(drawnchar_t)*buf_size);
326 memset(chars, 0, sizeof(drawnchar_t)*buf_size);
331 free(chars);chars = 0;
338 chars = (drawnchar_t*)realloc(chars, sizeof(drawnchar_t)*buf_size);
342 void addChar(int charid, gfxcoord_t x, gfxcoord_t y, gfxcolor_t color)
345 chars[num_chars].x = x;
346 chars[num_chars].y = y;
347 chars[num_chars].color = color;
348 chars[num_chars].charid = charid;
352 static char*getFontID(GfxFont*font);
360 class InfoOutputDev: public OutputDev
363 FontInfo* currentfont;
375 id2font = new GHash();
377 virtual ~InfoOutputDev()
381 virtual GBool upsideDown() {return gTrue;}
382 virtual GBool useDrawChar() {return gTrue;}
383 virtual GBool useGradients() {return gTrue;}
384 virtual GBool interpretType3Chars() {return gTrue;}
385 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
388 state->transform(crop_x1,crop_y1,&x1,&y1);
389 state->transform(crop_x2,crop_y2,&x2,&y2);
390 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
391 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
397 virtual void drawLink(Link *link, Catalog *catalog)
401 virtual double getMaximumFontSize(char*id)
403 FontInfo*info = (FontInfo*)id2font->lookup(id);
405 msg("<error> Unknown font id: %s", id);
408 return info->max_size;
411 virtual void updateFont(GfxState *state)
413 GfxFont*font = state->getFont();
416 char*id = getFontID(font);
418 FontInfo*info = (FontInfo*)id2font->lookup(id);
420 GString* idStr = new GString(id);
424 id2font->add(idStr, (void*)info);
430 virtual void drawChar(GfxState *state, double x, double y,
431 double dx, double dy,
432 double originX, double originY,
433 CharCode code, Unicode *u, int uLen)
435 int render = state->getRender();
438 double m11,m21,m12,m22;
439 state->getFontTransMat(&m11, &m12, &m21, &m22);
440 m11 *= state->getHorizScaling();
441 m21 *= state->getHorizScaling();
442 double lenx = sqrt(m11*m11 + m12*m12);
443 double leny = sqrt(m21*m21 + m22*m22);
444 double len = lenx>leny?lenx:leny;
445 if(currentfont && currentfont->max_size < len) {
446 currentfont->max_size = len;
449 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
450 int width, int height, GBool invert,
455 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
456 int width, int height, GfxImageColorMap *colorMap,
457 int *maskColors, GBool inlineImg)
463 SWFOutputDev::SWFOutputDev()
481 current_text_stroke = 0;
482 current_text_clip = 0;
489 output = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
490 gfxdevice_swf_init(output);
491 /* configure device */
492 parameter_t*p = device_config;
494 output->setparameter(output, p->name, p->value);
499 void SWFOutputDev::setMove(int x,int y)
501 this->user_movex = x;
502 this->user_movey = y;
505 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
507 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
508 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
510 this->user_clipx1 = x1;
511 this->user_clipy1 = y1;
512 this->user_clipx2 = x2;
513 this->user_clipy2 = y2;
516 static char*getFontID(GfxFont*font)
518 GString*gstr = font->getName();
519 char* fontname = gstr==0?0:gstr->getCString();
523 sprintf(buf, "UFONT%d", r->num);
526 return strdup(fontname);
529 static char*getFontName(GfxFont*font)
531 char*fontid = getFontID(font);
533 char* plus = strchr(fontid, '+');
534 if(plus && plus < &fontid[strlen(fontid)-1]) {
535 fontname = strdup(plus+1);
537 fontname = strdup(fontid);
543 static char mybuf[1024];
544 static char* gfxstate2str(GfxState *state)
548 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
555 if(state->getX1()!=0.0)
556 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
557 if(state->getY1()!=0.0)
558 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
559 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
560 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
561 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
562 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
563 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
564 state->getFillColor()->c[0], state->getFillColor()->c[1]);
565 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
566 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
567 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
568 state->getFillColor()->c[0], state->getFillColor()->c[1],
569 state->getFillColor()->c[2], state->getFillColor()->c[3],
570 state->getFillColor()->c[4], state->getFillColor()->c[5],
571 state->getFillColor()->c[6], state->getFillColor()->c[7]);
572 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
573 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
574 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
575 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
576 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
577 state->getFillRGB(&rgb);
578 if(rgb.r || rgb.g || rgb.b)
579 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
580 state->getStrokeRGB(&rgb);
581 if(rgb.r || rgb.g || rgb.b)
582 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
583 if(state->getFillColorSpace()->getNComps()>1)
584 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
585 if(state->getStrokeColorSpace()->getNComps()>1)
586 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
587 if(state->getFillPattern())
588 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
589 if(state->getStrokePattern())
590 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
592 if(state->getFillOpacity()!=1.0)
593 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
594 if(state->getStrokeOpacity()!=1.0)
595 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
597 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
602 state->getLineDash(&dash, &length, &start);
606 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
607 for(t=0;t<length;t++) {
608 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
610 bufpos+=sprintf(bufpos,"]");
613 if(state->getFlatness()!=1)
614 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
615 if(state->getLineJoin()!=0)
616 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
617 if(state->getLineJoin()!=0)
618 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
619 if(state->getLineJoin()!=0)
620 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
622 if(state->getFont() && getFontID(state->getFont()))
623 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
624 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
625 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
626 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
627 if(state->getCharSpace())
628 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
629 if(state->getWordSpace())
630 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
631 if(state->getHorizScaling()!=1.0)
632 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
633 if(state->getLeading())
634 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
636 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
637 if(state->getRender())
638 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
639 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
640 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
641 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
642 if(state->getLineX())
643 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
644 if(state->getLineY())
645 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
646 bufpos+=sprintf(bufpos," ");
650 static void dumpFontInfo(char*loglevel, GfxFont*font);
651 static int lastdumps[1024];
652 static int lastdumppos = 0;
657 static void showFontError(GfxFont*font, int nr)
661 for(t=0;t<lastdumppos;t++)
662 if(lastdumps[t] == r->num)
666 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
667 lastdumps[lastdumppos++] = r->num;
669 msg("<warning> The following font caused problems:");
671 msg("<warning> The following font caused problems (substituting):");
673 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
674 dumpFontInfo("<warning>", font);
677 static void dumpFontInfo(char*loglevel, GfxFont*font)
679 char* id = getFontID(font);
680 char* name = getFontName(font);
681 Ref* r=font->getID();
682 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
684 GString*gstr = font->getTag();
686 msg("%s| Tag: %s\n", loglevel, id);
688 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
690 GfxFontType type=font->getType();
692 case fontUnknownType:
693 msg("%s| Type: unknown\n",loglevel);
696 msg("%s| Type: 1\n",loglevel);
699 msg("%s| Type: 1C\n",loglevel);
702 msg("%s| Type: 3\n",loglevel);
705 msg("%s| Type: TrueType\n",loglevel);
708 msg("%s| Type: CIDType0\n",loglevel);
711 msg("%s| Type: CIDType0C\n",loglevel);
714 msg("%s| Type: CIDType2\n",loglevel);
719 GBool embedded = font->getEmbeddedFontID(&embRef);
721 if(font->getEmbeddedFontName()) {
722 embeddedName = font->getEmbeddedFontName()->getCString();
725 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
727 gstr = font->getExtFontFile();
729 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
731 // Get font descriptor flags.
732 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
733 if(font->isSerif()) msg("%s| is serif\n", loglevel);
734 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
735 if(font->isItalic()) msg("%s| is italic\n", loglevel);
736 if(font->isBold()) msg("%s| is bold\n", loglevel);
742 //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");}
743 //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");}
746 void dump_outline(gfxline_t*line)
749 if(line->type == gfx_moveTo) {
750 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
751 } else if(line->type == gfx_lineTo) {
752 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
753 } else if(line->type == gfx_splineTo) {
754 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
760 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey)
762 int num = path->getNumSubpaths();
765 double lastx=0,lasty=0,posx=0,posy=0;
768 msg("<warning> empty path");
772 gfxdrawer_target_gfxline(&draw);
774 for(t = 0; t < num; t++) {
775 GfxSubpath *subpath = path->getSubpath(t);
776 int subnum = subpath->getNumPoints();
777 double bx=0,by=0,cx=0,cy=0;
779 for(s=0;s<subnum;s++) {
782 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
787 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
788 draw.lineTo(&draw, lastx, lasty);
790 draw.moveTo(&draw, x,y);
795 } else if(subpath->getCurve(s) && cpos==0) {
799 } else if(subpath->getCurve(s) && cpos==1) {
807 draw.lineTo(&draw, x,y);
809 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y, 0.05);
816 /* fix non-closed lines */
817 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
818 draw.lineTo(&draw, lastx, lasty);
820 gfxline_t*result = (gfxline_t*)draw.result(&draw);
824 /*----------------------------------------------------------------------------
825 * Primitive Graphic routines
826 *----------------------------------------------------------------------------*/
828 void SWFOutputDev::stroke(GfxState *state)
830 GfxPath * path = state->getPath();
831 gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex, user_movey);
832 strokeGfxline(state, line);
836 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
838 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
839 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
840 double miterLimit = state->getMiterLimit();
841 double width = state->getTransformedLineWidth();
844 double opaq = state->getStrokeOpacity();
846 state->getFillRGB(&rgb);
848 state->getStrokeRGB(&rgb);
850 col.r = (unsigned char)(rgb.r*255);
851 col.g = (unsigned char)(rgb.g*255);
852 col.b = (unsigned char)(rgb.b*255);
853 col.a = (unsigned char)(opaq*255);
855 gfx_capType capType = gfx_capRound;
856 if(lineCap == 0) capType = gfx_capButt;
857 else if(lineCap == 1) capType = gfx_capRound;
858 else if(lineCap == 2) capType = gfx_capSquare;
860 gfx_joinType joinType = gfx_joinRound;
861 if(lineJoin == 0) joinType = gfx_joinMiter;
862 else if(lineJoin == 1) joinType = gfx_joinRound;
863 else if(lineJoin == 2) joinType = gfx_joinBevel;
866 double dashphase = 0;
868 state->getLineDash(&ldash, &dashnum, &dashphase);
872 if(dashnum && ldash) {
873 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
877 msg("<trace> %d dashes", dashnum);
878 msg("<trace> | phase: %f", dashphase);
879 for(t=0;t<dashnum;t++) {
881 msg("<trace> | d%-3d: %f", t, ldash[t]);
884 if(getLogLevel() >= LOGLEVEL_TRACE) {
888 line2 = gfxtool_dash_line(line, dash, dashphase);
891 msg("<trace> After dashing:");
894 if(getLogLevel() >= LOGLEVEL_TRACE) {
896 state->getStrokeGray(&gray);
897 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n",
899 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
900 lineCap==0?"butt": (lineJoin==1?"round":"square"),
902 col.r,col.g,col.b,col.a,
908 //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
909 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 = (unsigned char)(rgb.r*255);
922 col.g = (unsigned char)(rgb.g*255);
923 col.b = (unsigned char)(rgb.b*255);
924 col.a = (unsigned char)(opaq*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, 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, _u+t, 1);
1260 if(charid<0 && name) {
1261 if(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;
1437 gfxline_t points[5];
1441 link->getBorder(&x1, &y1, &x2, &y2, &w);
1443 link->getRect(&x1, &y1, &x2, &y2);
1448 cvtUserToDev(x1, y1, &x, &y);
1449 points[0].type = gfx_moveTo;
1450 points[0].x = points[4].x = x + user_movex;
1451 points[0].y = points[4].y = y + user_movey;
1452 points[0].next = &points[1];
1453 cvtUserToDev(x2, y1, &x, &y);
1454 points[1].type = gfx_lineTo;
1455 points[1].x = x + user_movex;
1456 points[1].y = y + user_movey;
1457 points[1].next = &points[2];
1458 cvtUserToDev(x2, y2, &x, &y);
1459 points[2].type = gfx_lineTo;
1460 points[2].x = x + user_movex;
1461 points[2].y = y + user_movey;
1462 points[2].next = &points[3];
1463 cvtUserToDev(x1, y2, &x, &y);
1464 points[3].type = gfx_lineTo;
1465 points[3].x = x + user_movex;
1466 points[3].y = y + user_movey;
1467 points[3].next = &points[4];
1468 cvtUserToDev(x1, y1, &x, &y);
1469 points[4].type = gfx_lineTo;
1470 points[4].x = x + user_movex;
1471 points[4].y = y + user_movey;
1474 LinkAction*action=link->getAction();
1481 switch(action->getKind())
1485 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1486 LinkDest *dest=NULL;
1487 if (ha->getDest()==NULL)
1488 dest=catalog->findDest(ha->getNamedDest());
1489 else dest=ha->getDest();
1491 if (dest->isPageRef()){
1492 Ref pageref=dest->getPageRef();
1493 page=catalog->findPage(pageref.num,pageref.gen);
1495 else page=dest->getPageNum();
1496 sprintf(buf, "%d", page);
1503 LinkGoToR*l = (LinkGoToR*)action;
1504 GString*g = l->getNamedDest();
1506 s = strdup(g->getCString());
1511 LinkNamed*l = (LinkNamed*)action;
1512 GString*name = l->getName();
1514 s = strdup(name->lowerCase()->getCString());
1515 named = name->getCString();
1518 if(strstr(s, "next") || strstr(s, "forward"))
1520 page = currentpage + 1;
1522 else if(strstr(s, "prev") || strstr(s, "back"))
1524 page = currentpage - 1;
1526 else if(strstr(s, "last") || strstr(s, "end"))
1528 if(pages && pagepos>0)
1529 page = pages[pagepos-1];
1531 else if(strstr(s, "first") || strstr(s, "top"))
1539 case actionLaunch: {
1541 LinkLaunch*l = (LinkLaunch*)action;
1542 GString * str = new GString(l->getFileName());
1543 str->append(l->getParams());
1544 s = strdup(str->getCString());
1550 LinkURI*l = (LinkURI*)action;
1551 GString*g = l->getURI();
1553 url = g->getCString();
1558 case actionUnknown: {
1560 LinkUnknown*l = (LinkUnknown*)action;
1565 msg("<error> Unknown link type!\n");
1569 if(!s) s = strdup("-?-");
1571 if(!linkinfo && (page || url))
1573 msg("<notice> File contains links");
1581 for(t=1;t<=pagepos;t++) {
1582 if(pages[t]==page) {
1589 sprintf(buf, "page%d", t);
1590 output->drawlink(output, points, buf);
1592 msg("<warning> Invalid link to page %d", page);
1597 output->drawlink(output, points, url);
1600 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1604 void SWFOutputDev::saveState(GfxState *state) {
1605 msg("<trace> saveState\n");
1608 msg("<error> Too many nested states in pdf.");
1612 states[statepos].clipping = 0; //? shouldn't this be the current value?
1613 states[statepos].textRender = states[statepos-1].textRender;
1616 void SWFOutputDev::restoreState(GfxState *state) {
1617 msg("<trace> restoreState\n");
1619 while(states[statepos].clipping) {
1620 output->endclip(output);
1621 states[statepos].clipping--;
1626 char* SWFOutputDev::searchFont(char*name)
1630 int is_standard_font = 0;
1632 msg("<verbose> SearchFont(%s)", name);
1634 /* see if it is a pdf standard font */
1635 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1637 if(!strcmp(name, pdf2t1map[i].pdffont))
1639 name = pdf2t1map[i].filename;
1640 is_standard_font = 1;
1644 /* look in all font files */
1645 for(i=0;i<fontnum;i++)
1647 if(strstr(fonts[i].filename, name))
1649 if(!fonts[i].used) {
1652 if(!is_standard_font)
1653 msg("<notice> Using %s for %s", fonts[i].filename, name);
1655 return strdup(fonts[i].filename);
1661 void SWFOutputDev::updateLineWidth(GfxState *state)
1663 double width = state->getTransformedLineWidth();
1664 //swfoutput_setlinewidth(&output, width);
1667 void SWFOutputDev::updateLineCap(GfxState *state)
1669 int c = state->getLineCap();
1672 void SWFOutputDev::updateLineJoin(GfxState *state)
1674 int j = state->getLineJoin();
1677 void SWFOutputDev::updateFillColor(GfxState *state)
1680 double opaq = state->getFillOpacity();
1681 state->getFillRGB(&rgb);
1683 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1686 void SWFOutputDev::updateStrokeColor(GfxState *state)
1689 double opaq = state->getStrokeOpacity();
1690 state->getStrokeRGB(&rgb);
1691 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1694 void FoFiWrite(void *stream, char *data, int len)
1696 fwrite(data, len, 1, (FILE*)stream);
1699 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1701 char*tmpFileName = NULL;
1707 Object refObj, strObj;
1709 tmpFileName = mktmpname(namebuf);
1712 ret = font->getEmbeddedFontID(&embRef);
1714 msg("<verbose> Didn't get embedded font id");
1715 /* not embedded- the caller should now search the font
1716 directories for this font */
1720 f = fopen(tmpFileName, "wb");
1722 msg("<error> Couldn't create temporary Type 1 font file");
1726 /*if(font->isCIDFont()) {
1727 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1728 GString c = cidFont->getCollection();
1729 msg("<notice> Collection: %s", c.getCString());
1732 //if (font->getType() == fontType1C) {
1733 if (0) { //font->getType() == fontType1C) {
1734 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1736 msg("<error> Couldn't read embedded font file");
1740 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1742 cvt->convertToType1(f);
1744 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1746 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1748 //cvt->convertToCIDType0("test", f);
1749 //cvt->convertToType0("test", f);
1752 } else if(font->getType() == fontTrueType) {
1753 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1754 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1756 msg("<error> Couldn't read embedded font file");
1760 TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1763 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1764 cvt->writeTTF(FoFiWrite, f);
1769 font->getEmbeddedFontID(&embRef);
1770 refObj.initRef(embRef.num, embRef.gen);
1771 refObj.fetch(ref, &strObj);
1773 strObj.streamReset();
1778 f4[t] = strObj.streamGetChar();
1779 f4c[t] = (char)f4[t];
1784 if(!strncmp(f4c, "true", 4)) {
1785 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1786 Change this on the fly */
1787 f4[0] = f4[2] = f4[3] = 0;
1795 while ((c = strObj.streamGetChar()) != EOF) {
1799 strObj.streamClose();
1804 return strdup(tmpFileName);
1807 char* searchForSuitableFont(GfxFont*gfxFont)
1809 char*name = getFontName(gfxFont);
1813 if(!config_use_fontconfig)
1816 #ifdef HAVE_FONTCONFIG
1817 FcPattern *pattern, *match;
1821 static int fcinitcalled = false;
1823 msg("<debug> searchForSuitableFont(%s)", name);
1825 // call init ony once
1826 if (!fcinitcalled) {
1827 msg("<debug> Initializing FontConfig...");
1828 fcinitcalled = true;
1830 msg("<debug> FontConfig Initialization failed. Disabling.");
1831 config_use_fontconfig = 0;
1834 msg("<debug> ...initialized FontConfig");
1837 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1838 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1839 if (gfxFont->isItalic()) // check for italic
1840 msg("<debug> FontConfig: Adding Italic Slant");
1841 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1842 if (gfxFont->isBold()) // check for bold
1843 msg("<debug> FontConfig: Adding Bold Weight");
1844 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1846 msg("<debug> FontConfig: Try to match...");
1847 // configure and match using the original font name
1848 FcConfigSubstitute(0, pattern, FcMatchPattern);
1849 FcDefaultSubstitute(pattern);
1850 match = FcFontMatch(0, pattern, &result);
1852 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1853 msg("<debug> FontConfig: family=%s", (char*)v);
1854 // if we get an exact match
1855 if (strcmp((char *)v, name) == 0) {
1856 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1857 filename = strdup((char*)v); // mem leak
1858 char *nfn = strrchr(filename, '/');
1859 if(nfn) fontname = strdup(nfn+1);
1860 else fontname = filename;
1862 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1864 // initialize patterns
1865 FcPatternDestroy(pattern);
1866 FcPatternDestroy(match);
1868 // now match against serif etc.
1869 if (gfxFont->isSerif()) {
1870 msg("<debug> FontConfig: Create Serif Family Pattern");
1871 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1872 } else if (gfxFont->isFixedWidth()) {
1873 msg("<debug> FontConfig: Create Monospace Family Pattern");
1874 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1876 msg("<debug> FontConfig: Create Sans Family Pattern");
1877 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1881 if (gfxFont->isItalic()) {
1882 msg("<debug> FontConfig: Adding Italic Slant");
1883 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1886 if (gfxFont->isBold()) {
1887 msg("<debug> FontConfig: Adding Bold Weight");
1888 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1891 msg("<debug> FontConfig: Try to match... (2)");
1892 // configure and match using serif etc
1893 FcConfigSubstitute (0, pattern, FcMatchPattern);
1894 FcDefaultSubstitute (pattern);
1895 match = FcFontMatch (0, pattern, &result);
1897 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1898 filename = strdup((char*)v); // mem leak
1899 char *nfn = strrchr(filename, '/');
1900 if(nfn) fontname = strdup(nfn+1);
1901 else fontname = filename;
1903 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1907 //printf("FONTCONFIG: pattern");
1908 //FcPatternPrint(pattern);
1909 //printf("FONTCONFIG: match");
1910 //FcPatternPrint(match);
1912 FcPatternDestroy(pattern);
1913 FcPatternDestroy(match);
1915 pdfswf_addfont(filename);
1922 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1924 char*fontname = 0, *filename = 0;
1925 msg("<notice> subsituteFont(%s)", oldname);
1927 if(!(fontname = searchForSuitableFont(gfxFont))) {
1928 fontname = "Times-Roman";
1930 filename = searchFont(fontname);
1932 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1936 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1937 msg("<fatal> Too many fonts in file.");
1941 substitutesource[substitutepos] = strdup(oldname); //mem leak
1942 substitutetarget[substitutepos] = fontname;
1943 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1946 return strdup(filename); //mem leak
1949 void unlinkfont(char* filename)
1956 if(!strncmp(&filename[l-4],".afm",4)) {
1957 memcpy(&filename[l-4],".pfb",4);
1959 memcpy(&filename[l-4],".pfa",4);
1961 memcpy(&filename[l-4],".afm",4);
1964 if(!strncmp(&filename[l-4],".pfa",4)) {
1965 memcpy(&filename[l-4],".afm",4);
1967 memcpy(&filename[l-4],".pfa",4);
1970 if(!strncmp(&filename[l-4],".pfb",4)) {
1971 memcpy(&filename[l-4],".afm",4);
1973 memcpy(&filename[l-4],".pfb",4);
1978 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1984 int SWFOutputDev::setGfxFont(char*id, char*filename, double maxSize)
1987 fontlist_t*last=0,*l = this->fontlist;
1989 /* TODO: should this be part of the state? */
1992 if(!strcmp(l->id, id)) {
1993 current_font_id = l->id;
1994 current_gfxfont = l->font;
1996 output->addfont(output, id, current_gfxfont);
2001 if(!filename) return 0;
2003 /* A font size of e.g. 9 means the font will be scaled down by
2004 1024 and scaled up by 9. So to have a maximum error of 1/20px,
2005 we have to divide 0.05 by (fontsize/1024)
2007 double quality = (1024 * 0.05) / maxSize;
2009 font = gfxfont_load(filename, quality);
2012 l->filename = strdup(filename);
2015 current_font_id = l->id;
2016 current_gfxfont = l->font;
2022 output->addfont(output, id, current_gfxfont);
2026 void SWFOutputDev::updateFont(GfxState *state)
2028 GfxFont*gfxFont = state->getFont();
2033 char * fontid = getFontID(gfxFont);
2034 double maxSize = 1.0;
2037 maxSize = this->info->getMaximumFontSize(fontid);
2041 /* first, look if we substituted this font before-
2042 this way, we don't initialize the T1 Fonts
2044 for(t=0;t<substitutepos;t++) {
2045 if(!strcmp(fontid, substitutesource[t])) {
2046 free(fontid);fontid=0;
2047 fontid = strdup(substitutetarget[t]);
2052 /* second, see if this is a font which was used before-
2053 if so, we are done */
2054 if(setGfxFont(fontid, 0, 0)) {
2058 /* if(swfoutput_queryfont(&output, fontid))
2059 swfoutput_setfont(&output, fontid, 0);
2061 msg("<debug> updateFont(%s) [cached]", fontid);
2065 // look for Type 3 font
2066 if (gfxFont->getType() == fontType3) {
2068 type3Warning = gTrue;
2069 showFontError(gfxFont, 2);
2075 /* now either load the font, or find a substitution */
2078 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
2083 (gfxFont->getType() == fontType1 ||
2084 gfxFont->getType() == fontType1C ||
2085 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
2086 gfxFont->getType() == fontTrueType ||
2087 gfxFont->getType() == fontCIDType2
2090 fileName = writeEmbeddedFontToFile(xref, gfxFont);
2091 if(!fileName) showFontError(gfxFont,0);
2094 char * fontname = getFontName(gfxFont);
2095 fileName = searchFont(fontname);
2096 if(!fileName) showFontError(gfxFont,0);
2100 char * fontname = getFontName(gfxFont);
2101 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
2102 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
2103 fileName = substituteFont(gfxFont, fontid);
2104 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
2105 msg("<notice> Font is now %s (%s)", fontid, fileName);
2109 msg("<error> Couldn't set font %s\n", fontid);
2114 msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
2115 dumpFontInfo("<verbose>", gfxFont);
2117 //swfoutput_setfont(&output, fontid, fileName);
2119 if(!setGfxFont(fontid, 0, 0)) {
2120 setGfxFont(fontid, fileName, maxSize);
2124 unlinkfont(fileName);
2130 #define SQR(x) ((x)*(x))
2132 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
2134 if((newwidth<2 || newheight<2) ||
2135 (width<=newwidth || height<=newheight))
2137 unsigned char*newdata;
2139 newdata= (unsigned char*)malloc(newwidth*newheight);
2141 double fx = (double)(width)/newwidth;
2142 double fy = (double)(height)/newheight;
2144 int blocksize = (int)(8192/(fx*fy));
2145 int r = 8192*256/palettesize;
2146 for(x=0;x<newwidth;x++) {
2147 double ex = px + fx;
2148 int fromx = (int)px;
2150 int xweight1 = (int)(((fromx+1)-px)*256);
2151 int xweight2 = (int)((ex-tox)*256);
2153 for(y=0;y<newheight;y++) {
2154 double ey = py + fy;
2155 int fromy = (int)py;
2157 int yweight1 = (int)(((fromy+1)-py)*256);
2158 int yweight2 = (int)((ey-toy)*256);
2161 for(xx=fromx;xx<=tox;xx++)
2162 for(yy=fromy;yy<=toy;yy++) {
2163 int b = 1-data[width*yy+xx];
2165 if(xx==fromx) weight = (weight*xweight1)/256;
2166 if(xx==tox) weight = (weight*xweight2)/256;
2167 if(yy==fromy) weight = (weight*yweight1)/256;
2168 if(yy==toy) weight = (weight*yweight2)/256;
2171 //if(a) a=(palettesize-1)*r/blocksize;
2172 newdata[y*newwidth+x] = (a*blocksize)/r;
2180 #define IMAGE_TYPE_JPEG 0
2181 #define IMAGE_TYPE_LOSSLESS 1
2183 static void drawimage(gfxdevice_t*dev, RGBA* data, int sizex,int sizey,
2184 double x1,double y1,
2185 double x2,double y2,
2186 double x3,double y3,
2187 double x4,double y4, int type)
2191 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2192 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2194 gfxline_t p1,p2,p3,p4,p5;
2195 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2196 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2197 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2198 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2199 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2201 {p1.x = (int)(p1.x*20)/20.0;
2202 p1.y = (int)(p1.y*20)/20.0;
2203 p2.x = (int)(p2.x*20)/20.0;
2204 p2.y = (int)(p2.y*20)/20.0;
2205 p3.x = (int)(p3.x*20)/20.0;
2206 p3.y = (int)(p3.y*20)/20.0;
2207 p4.x = (int)(p4.x*20)/20.0;
2208 p4.y = (int)(p4.y*20)/20.0;
2209 p5.x = (int)(p5.x*20)/20.0;
2210 p5.y = (int)(p5.y*20)/20.0;
2217 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2218 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2223 img.data = (gfxcolor_t*)data;
2227 if(type == IMAGE_TYPE_JPEG)
2228 /* TODO: pass image_dpi to device instead */
2229 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2231 dev->fillbitmap(dev, &p1, &img, &m, 0);
2234 void drawimagejpeg(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
2235 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2237 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2240 void drawimagelossless(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
2241 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2243 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2247 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2248 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2249 GBool inlineImg, int mask, int*maskColors)
2254 double x1,y1,x2,y2,x3,y3,x4,y4;
2255 ImageStream *imgStr;
2262 ncomps = colorMap->getNumPixelComps();
2263 bits = colorMap->getBits();
2265 imgStr = new ImageStream(str, width, ncomps,bits);
2268 if(!width || !height || (height<=1 && width<=1))
2270 msg("<verbose> Ignoring %d by %d image", width, height);
2271 unsigned char buf[8];
2273 for (y = 0; y < height; ++y)
2274 for (x = 0; x < width; ++x) {
2275 imgStr->getPixel(buf);
2281 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1+= user_movey;
2282 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2+= user_movey;
2283 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3+= user_movey;
2284 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4+= user_movey;
2286 if(!pbminfo && !(str->getKind()==strDCT)) {
2288 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2292 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2294 if(!jpeginfo && (str->getKind()==strDCT)) {
2295 msg("<notice> file contains jpeg pictures");
2301 unsigned char buf[8];
2303 unsigned char*pic = new unsigned char[width*height];
2306 state->getFillRGB(&rgb);
2308 memset(pal,255,sizeof(pal));
2309 pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
2310 pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
2311 pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
2312 pal[0].a = 255; pal[1].a = 0;
2315 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2316 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2317 for (y = 0; y < height; ++y)
2318 for (x = 0; x < width; ++x)
2320 imgStr->getPixel(buf);
2323 pic[width*y+x] = buf[0];
2326 /* the size of the drawn image is added to the identifier
2327 as the same image may require different bitmaps if displayed
2328 at different sizes (due to antialiasing): */
2331 unsigned char*pic2 = 0;
2334 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2343 height = realheight;
2347 /* make a black/white palette */
2352 float r = 255/(numpalette-1);
2354 for(t=0;t<numpalette;t++) {
2355 pal[t].r = (U8)(255*rgb.r);
2356 pal[t].g = (U8)(255*rgb.g);
2357 pal[t].b = (U8)(255*rgb.b);
2358 pal[t].a = (U8)(t*r);
2362 RGBA*pic2 = new RGBA[width*height];
2363 for (y = 0; y < height; ++y) {
2364 for (x = 0; x < width; ++x) {
2365 pic2[width*y+x] = pal[pic[y*width+x]];
2368 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2377 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2378 RGBA*pic=new RGBA[width*height];
2379 for (y = 0; y < height; ++y) {
2380 for (x = 0; x < width; ++x) {
2381 imgStr->getPixel(pixBuf);
2382 colorMap->getRGB(pixBuf, &rgb);
2383 pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
2384 pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
2385 pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
2386 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2389 if(str->getKind()==strDCT)
2390 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2392 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2397 RGBA*pic=new RGBA[width*height];
2400 for(t=0;t<256;t++) {
2402 colorMap->getRGB(pixBuf, &rgb);
2403 /*if(maskColors && *maskColors==t) {
2404 msg("<notice> Color %d is transparent", t);
2405 if (imgData->maskColors) {
2407 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2408 if (pix[i] < imgData->maskColors[2*i] ||
2409 pix[i] > imgData->maskColors[2*i+1]) {
2424 pal[t].r = (U8)(rgb.r * 255 + 0.5);
2425 pal[t].g = (U8)(rgb.g * 255 + 0.5);
2426 pal[t].b = (U8)(rgb.b * 255 + 0.5);
2427 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2430 for (y = 0; y < height; ++y) {
2431 for (x = 0; x < width; ++x) {
2432 imgStr->getPixel(pixBuf);
2433 pic[width*y+x] = pal[pixBuf[0]];
2436 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2444 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2445 int width, int height, GBool invert,
2448 if(states[statepos].textRender & 4) //clipped
2450 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2451 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
2454 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2455 int width, int height, GfxImageColorMap *colorMap,
2456 int *maskColors, GBool inlineImg)
2458 if(states[statepos].textRender & 4) //clipped
2461 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
2462 colorMap?"colorMap":"no colorMap",
2463 maskColors?"maskColors":"no maskColors",
2466 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2467 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2468 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
2471 //SWFOutputDev*output = 0;
2473 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2478 if (infoDict->lookup(key, &obj)->isString()) {
2479 s1 = obj.getString();
2480 if ((s1->getChar(0) & 0xff) == 0xfe &&
2481 (s1->getChar(1) & 0xff) == 0xff) {
2483 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2484 if (s1->getChar(i) == '\0') {
2485 s2->append(s1->getChar(i+1));
2488 s2 = new GString("<unicode>");
2492 printf(fmt, s2->getCString());
2495 printf(fmt, s1->getCString());
2501 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2505 if (infoDict->lookup(key, &obj)->isString()) {
2506 s = obj.getString()->getCString();
2507 if (s[0] == 'D' && s[1] == ':') {
2518 void storeDeviceParameter(char*name, char*value)
2520 parameter_t*p = new parameter_t();
2521 p->name = strdup(name);
2522 p->value = strdup(value);
2524 if(device_config_next) {
2525 device_config_next->next = p;
2526 device_config_next = p;
2529 device_config_next = p;
2533 void pdfswf_setparameter(char*name, char*value)
2535 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2536 if(!strcmp(name, "caplinewidth")) {
2537 caplinewidth = atof(value);
2538 } else if(!strcmp(name, "zoom")) {
2541 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2542 storeDeviceParameter("jpegsubpixels", buf);
2543 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2544 storeDeviceParameter("ppmsubpixels", buf);
2545 } else if(!strcmp(name, "jpegdpi")) {
2547 jpeg_dpi = atoi(value);
2548 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2549 storeDeviceParameter("jpegsubpixels", buf);
2550 } else if(!strcmp(name, "ppmdpi")) {
2552 ppm_dpi = atoi(value);
2553 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2554 storeDeviceParameter("ppmsubpixels", buf);
2555 } else if(!strcmp(name, "forceType0Fonts")) {
2556 forceType0Fonts = atoi(value);
2557 } else if(!strcmp(name, "fontdir")) {
2558 pdfswf_addfontdir(value);
2559 } else if(!strcmp(name, "languagedir")) {
2560 pdfswf_addlanguagedir(value);
2561 } else if(!strcmp(name, "fontconfig")) {
2562 config_use_fontconfig = atoi(value);
2564 storeDeviceParameter(name,value);
2567 void pdfswf_addfont(char*filename)
2570 memset(&f, 0, sizeof(fontfile_t));
2571 f.filename = filename;
2572 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2573 fonts[fontnum++] = f;
2575 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2579 static char* dirseparator()
2588 void pdfswf_addlanguagedir(char*dir)
2591 globalParams = new GlobalParams("");
2593 msg("<notice> Adding %s to language pack directories", dir);
2597 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2598 strcpy(config_file, dir);
2599 strcat(config_file, dirseparator());
2600 strcat(config_file, "add-to-xpdfrc");
2602 fi = fopen(config_file, "rb");
2604 msg("<error> Could not open %s", config_file);
2607 globalParams->parseFile(new GString(config_file), fi);
2611 void pdfswf_addfontdir(char*dirname)
2613 #ifdef HAVE_DIRENT_H
2614 msg("<notice> Adding %s to font directories", dirname);
2615 DIR*dir = opendir(dirname);
2617 msg("<warning> Couldn't open directory %s\n", dirname);
2622 ent = readdir (dir);
2626 char*name = ent->d_name;
2632 if(!strncasecmp(&name[l-4], ".pfa", 4))
2634 if(!strncasecmp(&name[l-4], ".pfb", 4))
2636 if(!strncasecmp(&name[l-4], ".ttf", 4))
2640 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2641 strcpy(fontname, dirname);
2642 strcat(fontname, dirseparator());
2643 strcat(fontname, name);
2644 msg("<verbose> Adding %s to fonts", fontname);
2645 pdfswf_addfont(fontname);
2650 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2655 typedef struct _pdf_doc_internal
2660 } pdf_doc_internal_t;
2661 typedef struct _pdf_page_internal
2663 } pdf_page_internal_t;
2664 typedef struct _swf_output_internal
2666 SWFOutputDev*outputDev;
2667 } swf_output_internal_t;
2669 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2671 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2672 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2673 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2674 memset(i, 0, sizeof(pdf_doc_internal_t));
2675 pdf_doc->internal = i;
2677 GString *fileName = new GString(filename);
2683 globalParams = new GlobalParams("");
2686 if (userPassword && userPassword[0]) {
2687 userPW = new GString(userPassword);
2691 i->doc = new PDFDoc(fileName, userPW);
2695 if (!i->doc->isOk()) {
2700 i->doc->getDocInfo(&info);
2701 if (info.isDict() &&
2702 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2703 printInfoString(info.getDict(), "Title", "Title: %s\n");
2704 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2705 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2706 printInfoString(info.getDict(), "Author", "Author: %s\n");
2707 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2708 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2709 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2710 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2711 printf("Pages: %d\n", i->doc->getNumPages());
2712 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2713 printf("Encrypted: ");
2714 if (i->doc->isEncrypted()) {
2715 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2716 i->doc->okToPrint() ? "yes" : "no",
2717 i->doc->okToCopy() ? "yes" : "no",
2718 i->doc->okToChange() ? "yes" : "no",
2719 i->doc->okToAddNotes() ? "yes" : "no");
2726 pdf_doc->num_pages = i->doc->getNumPages();
2728 if (i->doc->isEncrypted()) {
2729 if(!i->doc->okToCopy()) {
2730 printf("PDF disallows copying.\n");
2733 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2737 InfoOutputDev*io = new InfoOutputDev();
2739 for(t=1;t<=pdf_doc->num_pages;t++) {
2741 i->doc->displayPage((OutputDev*)io, t, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2743 i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2755 delete globalParams;globalParams=0;
2756 Object::memCheck(stderr);
2761 void pdf_destroy(pdf_doc_t*pdf_doc)
2763 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2765 delete i->doc; i->doc=0;
2768 delete i->info;i->info=0;
2771 free(pdf_doc->internal);pdf_doc->internal=0;
2772 free(pdf_doc);pdf_doc=0;
2775 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2777 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2779 if(page < 1 || page > pdf_doc->num_pages)
2782 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2783 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2784 memset(pi, 0, sizeof(pdf_page_internal_t));
2785 pdf_page->internal = pi;
2787 pdf_page->parent = pdf_doc;
2788 pdf_page->nr = page;
2792 void pdf_page_destroy(pdf_page_t*pdf_page)
2794 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2795 free(pdf_page->internal);pdf_page->internal = 0;
2796 free(pdf_page);pdf_page=0;
2799 swf_output_t* swf_output_init()
2801 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2802 memset(swf_output, 0, sizeof(swf_output_t));
2803 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2804 memset(i, 0, sizeof(swf_output_internal_t));
2805 swf_output->internal = i;
2807 i->outputDev = new SWFOutputDev();
2811 void swf_output_setparameter(swf_output_t*swf, char*name, char*value)
2813 pdfswf_setparameter(name, value);
2816 void swf_output_startframe(swf_output_t*swf, int width, int height)
2818 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2819 i->outputDev->startFrame(width, height);
2822 void swf_output_endframe(swf_output_t*swf)
2824 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2825 i->outputDev->endframe();
2828 void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage)
2830 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2831 SWFOutputDev*o = i->outputDev;
2837 o->pagebuflen = 1024;
2838 o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
2839 memset(o->pages, -1, o->pagebuflen*sizeof(int));
2841 while(pdfpage >= o->pagebuflen)
2843 int oldlen = o->pagebuflen;
2844 o->pagebuflen+=1024;
2845 o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
2846 memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
2849 o->pages[pdfpage] = outputpage;
2850 if(pdfpage>o->pagepos)
2851 o->pagepos = pdfpage;
2854 int swf_output_save(swf_output_t*swf, char*filename)
2856 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2857 int ret = i->outputDev->save(filename);
2861 void* swf_output_get(swf_output_t*swf,char*name)
2863 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2864 void* ret = i->outputDev->get(name);
2868 void swf_output_destroy(swf_output_t*output)
2870 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2871 delete i->outputDev; i->outputDev=0;
2872 free(output->internal);output->internal=0;
2876 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2878 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2879 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2882 msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2887 gfxdevice_t*dev = si->outputDev->output;
2888 dev->setparameter(dev, "protect", "1");
2890 si->outputDev->setInfo(pi->info);
2891 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2893 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2895 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2899 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2901 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2902 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2904 si->outputDev->setMove(x,y);
2905 if((x1|y1|x2|y2)==0) x2++;
2906 si->outputDev->setClip(x1,y1,x2,y2);
2908 pdf_page_render2(page, output);
2910 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2912 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2913 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2915 si->outputDev->setMove(0,0);
2916 si->outputDev->setClip(0,0,0,0);
2918 pdf_page_render2(page, output);
2922 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2924 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2925 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2926 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2927 memset(info, 0, sizeof(pdf_page_info_t));
2929 InfoOutputDev*output = new InfoOutputDev;
2932 pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2934 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2937 info->xMin = output->x1;
2938 info->yMin = output->y1;
2939 info->xMax = output->x2;
2940 info->yMax = output->y2;
2941 info->number_of_images = output->num_images;
2942 info->number_of_links = output->num_links;
2943 info->number_of_fonts = output->num_fonts;
2950 void pdf_page_info_destroy(pdf_page_info_t*info)