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) ;
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 static char*getFontID(GfxFont*font);
315 class InfoOutputDev: public OutputDev
318 FontInfo* currentfont;
330 id2font = new GHash();
332 virtual ~InfoOutputDev()
336 virtual GBool upsideDown() {return gTrue;}
337 virtual GBool useDrawChar() {return gTrue;}
338 virtual GBool useGradients() {return gTrue;}
339 virtual GBool interpretType3Chars() {return gTrue;}
340 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
343 state->transform(crop_x1,crop_y1,&x1,&y1);
344 state->transform(crop_x2,crop_y2,&x2,&y2);
345 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
346 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
352 virtual void drawLink(Link *link, Catalog *catalog)
356 virtual double getMaximumFontSize(char*id)
358 FontInfo*info = (FontInfo*)id2font->lookup(id);
360 msg("<error> Unknown font id: %s", id);
363 return info->max_size;
366 virtual void updateFont(GfxState *state)
368 GfxFont*font = state->getFont();
371 char*id = getFontID(font);
373 FontInfo*info = (FontInfo*)id2font->lookup(id);
375 GString* idStr = new GString(id);
379 id2font->add(idStr, (void*)info);
385 virtual void drawChar(GfxState *state, double x, double y,
386 double dx, double dy,
387 double originX, double originY,
388 CharCode code, Unicode *u, int uLen)
390 int render = state->getRender();
393 double m11,m21,m12,m22;
394 state->getFontTransMat(&m11, &m12, &m21, &m22);
395 m11 *= state->getHorizScaling();
396 m21 *= state->getHorizScaling();
397 double lenx = sqrt(m11*m11 + m12*m12);
398 double leny = sqrt(m21*m21 + m22*m22);
399 double len = lenx>leny?lenx:leny;
400 if(currentfont && currentfont->max_size < len) {
401 currentfont->max_size = len;
404 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
405 int width, int height, GBool invert,
410 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
411 int width, int height, GfxImageColorMap *colorMap,
412 int *maskColors, GBool inlineImg)
418 SWFOutputDev::SWFOutputDev()
436 current_text_stroke = 0;
437 current_text_clip = 0;
444 output = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
445 gfxdevice_swf_init(output);
446 /* configure device */
447 parameter_t*p = device_config;
449 output->setparameter(output, p->name, p->value);
454 void SWFOutputDev::setMove(int x,int y)
456 this->user_movex = x;
457 this->user_movey = y;
460 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
462 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
463 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
465 this->user_clipx1 = x1;
466 this->user_clipy1 = y1;
467 this->user_clipx2 = x2;
468 this->user_clipy2 = y2;
471 static char*getFontID(GfxFont*font)
473 GString*gstr = font->getName();
474 char* fontname = gstr==0?0:gstr->getCString();
478 sprintf(buf, "UFONT%d", r->num);
481 return strdup(fontname);
484 static char*getFontName(GfxFont*font)
486 char*fontid = getFontID(font);
488 char* plus = strchr(fontid, '+');
489 if(plus && plus < &fontid[strlen(fontid)-1]) {
490 fontname = strdup(plus+1);
492 fontname = strdup(fontid);
498 static char mybuf[1024];
499 static char* gfxstate2str(GfxState *state)
503 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
510 if(state->getX1()!=0.0)
511 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
512 if(state->getY1()!=0.0)
513 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
514 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
515 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
516 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
517 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
518 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
519 state->getFillColor()->c[0], state->getFillColor()->c[1]);
520 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
521 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
522 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
523 state->getFillColor()->c[0], state->getFillColor()->c[1],
524 state->getFillColor()->c[2], state->getFillColor()->c[3],
525 state->getFillColor()->c[4], state->getFillColor()->c[5],
526 state->getFillColor()->c[6], state->getFillColor()->c[7]);
527 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
528 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
529 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
530 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
531 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
532 state->getFillRGB(&rgb);
533 if(rgb.r || rgb.g || rgb.b)
534 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
535 state->getStrokeRGB(&rgb);
536 if(rgb.r || rgb.g || rgb.b)
537 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
538 if(state->getFillColorSpace()->getNComps()>1)
539 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
540 if(state->getStrokeColorSpace()->getNComps()>1)
541 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
542 if(state->getFillPattern())
543 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
544 if(state->getStrokePattern())
545 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
547 if(state->getFillOpacity()!=1.0)
548 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
549 if(state->getStrokeOpacity()!=1.0)
550 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
552 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
557 state->getLineDash(&dash, &length, &start);
561 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
562 for(t=0;t<length;t++) {
563 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
565 bufpos+=sprintf(bufpos,"]");
568 if(state->getFlatness()!=1)
569 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
570 if(state->getLineJoin()!=0)
571 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
572 if(state->getLineJoin()!=0)
573 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
574 if(state->getLineJoin()!=0)
575 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
577 if(state->getFont() && getFontID(state->getFont()))
578 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
579 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
580 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
581 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
582 if(state->getCharSpace())
583 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
584 if(state->getWordSpace())
585 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
586 if(state->getHorizScaling()!=1.0)
587 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
588 if(state->getLeading())
589 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
591 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
592 if(state->getRender())
593 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
594 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
595 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
596 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
597 if(state->getLineX())
598 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
599 if(state->getLineY())
600 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
601 bufpos+=sprintf(bufpos," ");
605 static void dumpFontInfo(char*loglevel, GfxFont*font);
606 static int lastdumps[1024];
607 static int lastdumppos = 0;
612 static void showFontError(GfxFont*font, int nr)
616 for(t=0;t<lastdumppos;t++)
617 if(lastdumps[t] == r->num)
621 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
622 lastdumps[lastdumppos++] = r->num;
624 msg("<warning> The following font caused problems:");
626 msg("<warning> The following font caused problems (substituting):");
628 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
629 dumpFontInfo("<warning>", font);
632 static void dumpFontInfo(char*loglevel, GfxFont*font)
634 char* id = getFontID(font);
635 char* name = getFontName(font);
636 Ref* r=font->getID();
637 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
639 GString*gstr = font->getTag();
641 msg("%s| Tag: %s\n", loglevel, id);
643 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
645 GfxFontType type=font->getType();
647 case fontUnknownType:
648 msg("%s| Type: unknown\n",loglevel);
651 msg("%s| Type: 1\n",loglevel);
654 msg("%s| Type: 1C\n",loglevel);
657 msg("%s| Type: 3\n",loglevel);
660 msg("%s| Type: TrueType\n",loglevel);
663 msg("%s| Type: CIDType0\n",loglevel);
666 msg("%s| Type: CIDType0C\n",loglevel);
669 msg("%s| Type: CIDType2\n",loglevel);
674 GBool embedded = font->getEmbeddedFontID(&embRef);
676 if(font->getEmbeddedFontName()) {
677 embeddedName = font->getEmbeddedFontName()->getCString();
680 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
682 gstr = font->getExtFontFile();
684 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
686 // Get font descriptor flags.
687 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
688 if(font->isSerif()) msg("%s| is serif\n", loglevel);
689 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
690 if(font->isItalic()) msg("%s| is italic\n", loglevel);
691 if(font->isBold()) msg("%s| is bold\n", loglevel);
697 //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");}
698 //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");}
701 void dump_outline(gfxline_t*line)
704 if(line->type == gfx_moveTo) {
705 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
706 } else if(line->type == gfx_lineTo) {
707 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
708 } else if(line->type == gfx_splineTo) {
709 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
715 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey)
717 int num = path->getNumSubpaths();
720 double lastx=0,lasty=0,posx=0,posy=0;
723 msg("<warning> empty path");
727 gfxdrawer_target_gfxline(&draw);
729 for(t = 0; t < num; t++) {
730 GfxSubpath *subpath = path->getSubpath(t);
731 int subnum = subpath->getNumPoints();
732 double bx=0,by=0,cx=0,cy=0;
734 for(s=0;s<subnum;s++) {
737 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
742 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
743 draw.lineTo(&draw, lastx, lasty);
745 draw.moveTo(&draw, x,y);
750 } else if(subpath->getCurve(s) && cpos==0) {
754 } else if(subpath->getCurve(s) && cpos==1) {
762 draw.lineTo(&draw, x,y);
764 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y, 0.05);
771 /* fix non-closed lines */
772 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
773 draw.lineTo(&draw, lastx, lasty);
775 gfxline_t*result = (gfxline_t*)draw.result(&draw);
779 /*----------------------------------------------------------------------------
780 * Primitive Graphic routines
781 *----------------------------------------------------------------------------*/
783 void SWFOutputDev::stroke(GfxState *state)
785 GfxPath * path = state->getPath();
786 gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex, user_movey);
787 strokeGfxline(state, line);
791 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
793 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
794 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
795 double miterLimit = state->getMiterLimit();
796 double width = state->getTransformedLineWidth();
799 double opaq = state->getStrokeOpacity();
801 state->getFillRGB(&rgb);
803 state->getStrokeRGB(&rgb);
805 col.r = (unsigned char)(rgb.r*255);
806 col.g = (unsigned char)(rgb.g*255);
807 col.b = (unsigned char)(rgb.b*255);
808 col.a = (unsigned char)(opaq*255);
810 gfx_capType capType = gfx_capRound;
811 if(lineCap == 0) capType = gfx_capButt;
812 else if(lineCap == 1) capType = gfx_capRound;
813 else if(lineCap == 2) capType = gfx_capSquare;
815 gfx_joinType joinType = gfx_joinRound;
816 if(lineJoin == 0) joinType = gfx_joinMiter;
817 else if(lineJoin == 1) joinType = gfx_joinRound;
818 else if(lineJoin == 2) joinType = gfx_joinBevel;
821 double dashphase = 0;
823 state->getLineDash(&ldash, &dashnum, &dashphase);
827 if(dashnum && ldash) {
828 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
832 msg("<trace> %d dashes", dashnum);
833 msg("<trace> | phase: %f", dashphase);
834 for(t=0;t<dashnum;t++) {
836 msg("<trace> | d%-3d: %f", t, ldash[t]);
839 if(getLogLevel() >= LOGLEVEL_TRACE) {
843 line2 = gfxtool_dash_line(line, dash, dashphase);
846 msg("<trace> After dashing:");
849 if(getLogLevel() >= LOGLEVEL_TRACE) {
851 state->getStrokeGray(&gray);
852 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n",
854 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
855 lineCap==0?"butt": (lineJoin==1?"round":"square"),
857 col.r,col.g,col.b,col.a,
863 //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
864 output->stroke(output, line, width, &col, capType, joinType, miterLimit);
870 gfxcolor_t getFillColor(GfxState * state)
873 double opaq = state->getFillOpacity();
874 state->getFillRGB(&rgb);
876 col.r = (unsigned char)(rgb.r*255);
877 col.g = (unsigned char)(rgb.g*255);
878 col.b = (unsigned char)(rgb.b*255);
879 col.a = (unsigned char)(opaq*255);
883 void SWFOutputDev::fillGfxLine(GfxState *state, gfxline_t*line)
885 gfxcolor_t col = getFillColor(state);
887 if(getLogLevel() >= LOGLEVEL_TRACE) {
888 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
891 output->fill(output, line, &col);
893 void SWFOutputDev::fill(GfxState *state)
895 GfxPath * path = state->getPath();
896 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
897 fillGfxLine(state, line);
900 void SWFOutputDev::eoFill(GfxState *state)
902 GfxPath * path = state->getPath();
903 gfxcolor_t col = getFillColor(state);
905 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
907 if(getLogLevel() >= LOGLEVEL_TRACE) {
908 msg("<trace> eofill\n");
912 output->fill(output, line, &col);
916 void SWFOutputDev::clip(GfxState *state)
918 GfxPath * path = state->getPath();
919 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
920 clipToGfxLine(state, line);
924 void SWFOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line)
926 if(getLogLevel() >= LOGLEVEL_TRACE) {
927 msg("<trace> clip\n");
931 output->startclip(output, line);
932 states[statepos].clipping++;
934 void SWFOutputDev::eoClip(GfxState *state)
936 GfxPath * path = state->getPath();
937 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
939 if(getLogLevel() >= LOGLEVEL_TRACE) {
940 msg("<trace> eoclip\n");
944 output->startclip(output, line);
945 states[statepos].clipping++;
949 void SWFOutputDev::endframe()
952 output->endclip(output);
956 output->endpage(output);
959 void SWFOutputDev::finish()
963 output->endclip(output);
968 this->result = output->finish(output);
969 free(output);output=0;
973 int SWFOutputDev::save(char*filename)
976 return result->save(result, filename);
978 void* SWFOutputDev::getSWF()
981 return result->get(result, "swf");
984 SWFOutputDev::~SWFOutputDev()
989 this->result->destroy(this->result);
994 free(this->pages); this->pages = 0;
997 fontlist_t*l = this->fontlist;
999 fontlist_t*next = l->next;
1001 gfxfont_free(l->font);
1009 GBool SWFOutputDev::upsideDown()
1013 GBool SWFOutputDev::useDrawChar()
1017 GBool SWFOutputDev::useGradients()
1021 msg("<notice> File contains gradients");
1027 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
1028 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
1030 #define RENDER_FILL 0
1031 #define RENDER_STROKE 1
1032 #define RENDER_FILLSTROKE 2
1033 #define RENDER_INVISIBLE 3
1034 #define RENDER_CLIP 4
1036 static char tmp_printstr[4096];
1037 char* makeStringPrintable(char*str)
1039 int len = strlen(str);
1046 for(t=0;t<len;t++) {
1051 tmp_printstr[t] = c;
1054 tmp_printstr[len++] = '.';
1055 tmp_printstr[len++] = '.';
1056 tmp_printstr[len++] = '.';
1058 tmp_printstr[len] = 0;
1059 return tmp_printstr;
1063 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
1067 for(t=0;t<font->num_glyphs;t++) {
1068 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
1069 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1073 /* if we didn't find the character, maybe
1074 we can find the capitalized version */
1075 for(t=0;t<font->num_glyphs;t++) {
1076 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
1077 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1083 /* try to use the unicode id */
1084 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
1085 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
1086 return font->unicode2glyph[u];
1089 /* we don't need to "draw" space characters, so don't overdo the search
1090 for a matching glyph */
1091 if(charname && !strcasecmp(charname, "space"))
1094 if(charnr>=0 && charnr<font->num_glyphs) {
1095 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1103 void SWFOutputDev::beginString(GfxState *state, GString *s)
1105 int render = state->getRender();
1106 if(current_text_stroke) {
1107 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
1110 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
1111 double m11,m21,m12,m22;
1112 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
1113 state->getFontTransMat(&m11, &m12, &m21, &m22);
1114 m11 *= state->getHorizScaling();
1115 m21 *= state->getHorizScaling();
1117 this->current_font_matrix.m00 = m11 / 1024.0;
1118 this->current_font_matrix.m01 = m12 / 1024.0;
1119 this->current_font_matrix.m10 = -m21 / 1024.0;
1120 this->current_font_matrix.m11 = -m22 / 1024.0;
1121 this->current_font_matrix.tx = 0;
1122 this->current_font_matrix.ty = 0;
1124 gfxmatrix_t m = this->current_font_matrix;
1126 /*if(render != 3 && render != 0)
1127 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1128 states[statepos].textRender = render;
1131 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1132 double dx, double dy,
1133 double originX, double originY,
1134 CharCode c, Unicode *_u, int uLen)
1136 int render = state->getRender();
1137 // check for invisible text -- this is used by Acrobat Capture
1141 if(states[statepos].textRender != render)
1142 msg("<error> Internal error: drawChar.render!=beginString.render");
1144 gfxcolor_t col = getFillColor(state);
1146 Gushort *CIDToGIDMap = 0;
1147 GfxFont*font = state->getFont();
1149 if(font->getType() == fontType3) {
1150 /* type 3 chars are passed as graphics */
1151 msg("<debug> type3 char at %f/%f", x, y);
1162 /* find out char name from unicode index
1163 TODO: should be precomputed
1165 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1166 if(nameToUnicodeTab[t].u == u) {
1167 name = nameToUnicodeTab[t].name;
1174 if(font->isCIDFont()) {
1175 GfxCIDFont*cfont = (GfxCIDFont*)font;
1177 if(font->getType() == fontCIDType2)
1178 CIDToGIDMap = cfont->getCIDToGID();
1181 font8 = (Gfx8BitFont*)font;
1182 char**enc=font8->getEncoding();
1187 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);
1190 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);
1193 int charid = getGfxCharID(current_gfxfont, c, name, u);
1195 if(strcasecmp(name, "space")) {
1196 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1197 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1202 gfxmatrix_t m = this->current_font_matrix;
1203 state->transform(x, y, &m.tx, &m.ty);
1207 if(render == RENDER_FILL) {
1208 output->drawchar(output, current_font_id, charid, &col, &m);
1210 msg("<debug> Drawing glyph %d as shape", charid);
1212 msg("<notice> Some texts will be rendered as shape");
1215 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1216 gfxline_t*tglyph = gfxline_clone(glyph);
1217 gfxline_transform(tglyph, &m);
1218 if((render&3) != RENDER_INVISIBLE) {
1219 gfxline_t*add = gfxline_clone(tglyph);
1220 current_text_stroke = gfxline_append(current_text_stroke, add);
1222 if(render&RENDER_CLIP) {
1223 gfxline_t*add = gfxline_clone(tglyph);
1224 current_text_clip = gfxline_append(current_text_clip, add);
1226 gfxline_free(tglyph);
1230 void SWFOutputDev::endString(GfxState *state)
1232 int render = state->getRender();
1233 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1234 if(states[statepos].textRender != render)
1235 msg("<error> Internal error: drawChar.render!=beginString.render");
1237 if(current_text_stroke) {
1238 /* fillstroke and stroke text rendering objects we can process right
1239 now (as there may be texts of other rendering modes in this
1240 text object)- clipping objects have to wait until endTextObject,
1242 if((render&3) == RENDER_FILL) {
1243 fillGfxLine(state, current_text_stroke);
1244 gfxline_free(current_text_stroke);
1245 current_text_stroke = 0;
1246 } else if((render&3) == RENDER_FILLSTROKE) {
1247 fillGfxLine(state, current_text_stroke);
1248 strokeGfxline(state, current_text_stroke);
1249 gfxline_free(current_text_stroke);
1250 current_text_stroke = 0;
1251 } else if((render&3) == RENDER_STROKE) {
1252 strokeGfxline(state, current_text_stroke);
1253 gfxline_free(current_text_stroke);
1254 current_text_stroke = 0;
1259 void SWFOutputDev::endTextObject(GfxState *state)
1261 int render = state->getRender();
1262 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1263 if(states[statepos].textRender != render)
1264 msg("<error> Internal error: drawChar.render!=beginString.render");
1266 if(current_text_clip) {
1267 clipToGfxLine(state, current_text_clip);
1268 gfxline_free(current_text_clip);
1269 current_text_clip = 0;
1273 /* the logic seems to be as following:
1274 first, beginType3Char is called, with the charcode and the coordinates.
1275 if this function returns true, it already knew about the char and has now drawn it.
1276 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1277 the all draw operations until endType3Char are part of the char (which in this moment is
1278 at the position first passed to beginType3Char). the char ends with endType3Char.
1280 The drawing operations between beginType3Char and endType3Char are somewhat different to
1281 the normal ones. For example, the fillcolor equals the stroke color.
1284 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1286 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1288 /* the character itself is going to be passed using the draw functions */
1289 return gFalse; /* gTrue= is_in_cache? */
1292 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1293 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1295 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1296 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1300 void SWFOutputDev::endType3Char(GfxState *state)
1303 msg("<debug> endType3Char");
1306 void SWFOutputDev::startFrame(int width, int height)
1308 output->startpage(output, width, height);
1311 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1313 this->currentpage = pageNum;
1315 int rot = doc->getPageRotate(1);
1318 gfxline_t clippath[5];
1320 white.r = white.g = white.b = white.a = 255;
1322 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1323 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1324 Use CropBox, not MediaBox, as page size
1331 state->transform(crop_x1,crop_y1,&x1,&y1); //x1 += user_movex; y1 += user_movey;
1332 state->transform(crop_x2,crop_y2,&x2,&y2); //x2 += user_movex; y2 += user_movey;
1334 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1335 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1338 /* apply user clip box */
1339 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1340 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1341 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1342 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1343 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1346 //msg("<verbose> Bounding box is (%f,%f)-(%f,%f) [shifted by %d/%d]", x1,y1,x2,y2, user_movex, user_movey);
1348 if(outer_clip_box) {
1349 output->endclip(output);
1353 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);
1355 msg("<verbose> page is rotated %d degrees\n", rot);
1357 clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1358 clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1359 clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1360 clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1361 clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1362 output->startclip(output, clippath); outer_clip_box = 1;
1363 output->fill(output, clippath, &white);
1366 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1368 msg("<debug> drawlink\n");
1369 double x1, y1, x2, y2, w;
1371 gfxline_t points[5];
1375 link->getBorder(&x1, &y1, &x2, &y2, &w);
1377 link->getRect(&x1, &y1, &x2, &y2);
1382 cvtUserToDev(x1, y1, &x, &y);
1383 points[0].type = gfx_moveTo;
1384 points[0].x = points[4].x = x + user_movex;
1385 points[0].y = points[4].y = y + user_movey;
1386 points[0].next = &points[1];
1387 cvtUserToDev(x2, y1, &x, &y);
1388 points[1].type = gfx_lineTo;
1389 points[1].x = x + user_movex;
1390 points[1].y = y + user_movey;
1391 points[1].next = &points[2];
1392 cvtUserToDev(x2, y2, &x, &y);
1393 points[2].type = gfx_lineTo;
1394 points[2].x = x + user_movex;
1395 points[2].y = y + user_movey;
1396 points[2].next = &points[3];
1397 cvtUserToDev(x1, y2, &x, &y);
1398 points[3].type = gfx_lineTo;
1399 points[3].x = x + user_movex;
1400 points[3].y = y + user_movey;
1401 points[3].next = &points[4];
1402 cvtUserToDev(x1, y1, &x, &y);
1403 points[4].type = gfx_lineTo;
1404 points[4].x = x + user_movex;
1405 points[4].y = y + user_movey;
1408 LinkAction*action=link->getAction();
1415 switch(action->getKind())
1419 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1420 LinkDest *dest=NULL;
1421 if (ha->getDest()==NULL)
1422 dest=catalog->findDest(ha->getNamedDest());
1423 else dest=ha->getDest();
1425 if (dest->isPageRef()){
1426 Ref pageref=dest->getPageRef();
1427 page=catalog->findPage(pageref.num,pageref.gen);
1429 else page=dest->getPageNum();
1430 sprintf(buf, "%d", page);
1437 LinkGoToR*l = (LinkGoToR*)action;
1438 GString*g = l->getNamedDest();
1440 s = strdup(g->getCString());
1445 LinkNamed*l = (LinkNamed*)action;
1446 GString*name = l->getName();
1448 s = strdup(name->lowerCase()->getCString());
1449 named = name->getCString();
1452 if(strstr(s, "next") || strstr(s, "forward"))
1454 page = currentpage + 1;
1456 else if(strstr(s, "prev") || strstr(s, "back"))
1458 page = currentpage - 1;
1460 else if(strstr(s, "last") || strstr(s, "end"))
1462 if(pages && pagepos>0)
1463 page = pages[pagepos-1];
1465 else if(strstr(s, "first") || strstr(s, "top"))
1473 case actionLaunch: {
1475 LinkLaunch*l = (LinkLaunch*)action;
1476 GString * str = new GString(l->getFileName());
1477 str->append(l->getParams());
1478 s = strdup(str->getCString());
1484 LinkURI*l = (LinkURI*)action;
1485 GString*g = l->getURI();
1487 url = g->getCString();
1492 case actionUnknown: {
1494 LinkUnknown*l = (LinkUnknown*)action;
1499 msg("<error> Unknown link type!\n");
1503 if(!s) s = strdup("-?-");
1505 if(!linkinfo && (page || url))
1507 msg("<notice> File contains links");
1515 for(t=1;t<=pagepos;t++) {
1516 printf("%d) %d (%d?)\n", t, pages[t], page);
1517 if(pages[t]==page) {
1524 sprintf(buf, "page%d", t);
1525 output->drawlink(output, points, buf);
1527 msg("<warning> Invalid link to page %d", page);
1532 output->drawlink(output, points, url);
1535 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1539 void SWFOutputDev::saveState(GfxState *state) {
1540 msg("<trace> saveState\n");
1543 msg("<error> Too many nested states in pdf.");
1547 states[statepos].clipping = 0; //? shouldn't this be the current value?
1548 states[statepos].textRender = states[statepos-1].textRender;
1551 void SWFOutputDev::restoreState(GfxState *state) {
1552 msg("<trace> restoreState\n");
1554 while(states[statepos].clipping) {
1555 output->endclip(output);
1556 states[statepos].clipping--;
1561 char* SWFOutputDev::searchFont(char*name)
1565 int is_standard_font = 0;
1567 msg("<verbose> SearchFont(%s)", name);
1569 /* see if it is a pdf standard font */
1570 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1572 if(!strcmp(name, pdf2t1map[i].pdffont))
1574 name = pdf2t1map[i].filename;
1575 is_standard_font = 1;
1579 /* look in all font files */
1580 for(i=0;i<fontnum;i++)
1582 if(strstr(fonts[i].filename, name))
1584 if(!fonts[i].used) {
1587 if(!is_standard_font)
1588 msg("<notice> Using %s for %s", fonts[i].filename, name);
1590 return strdup(fonts[i].filename);
1596 void SWFOutputDev::updateLineWidth(GfxState *state)
1598 double width = state->getTransformedLineWidth();
1599 //swfoutput_setlinewidth(&output, width);
1602 void SWFOutputDev::updateLineCap(GfxState *state)
1604 int c = state->getLineCap();
1607 void SWFOutputDev::updateLineJoin(GfxState *state)
1609 int j = state->getLineJoin();
1612 void SWFOutputDev::updateFillColor(GfxState *state)
1615 double opaq = state->getFillOpacity();
1616 state->getFillRGB(&rgb);
1618 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1621 void SWFOutputDev::updateStrokeColor(GfxState *state)
1624 double opaq = state->getStrokeOpacity();
1625 state->getStrokeRGB(&rgb);
1626 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1629 void FoFiWrite(void *stream, char *data, int len)
1631 fwrite(data, len, 1, (FILE*)stream);
1634 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1636 char*tmpFileName = NULL;
1642 Object refObj, strObj;
1644 tmpFileName = mktmpname(namebuf);
1647 ret = font->getEmbeddedFontID(&embRef);
1649 msg("<verbose> Didn't get embedded font id");
1650 /* not embedded- the caller should now search the font
1651 directories for this font */
1655 f = fopen(tmpFileName, "wb");
1657 msg("<error> Couldn't create temporary Type 1 font file");
1661 /*if(font->isCIDFont()) {
1662 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1663 GString c = cidFont->getCollection();
1664 msg("<notice> Collection: %s", c.getCString());
1667 //if (font->getType() == fontType1C) {
1668 if (0) { //font->getType() == fontType1C) {
1669 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1671 msg("<error> Couldn't read embedded font file");
1675 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1677 cvt->convertToType1(f);
1679 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1681 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1683 //cvt->convertToCIDType0("test", f);
1684 //cvt->convertToType0("test", f);
1687 } else if(font->getType() == fontTrueType) {
1688 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1689 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1691 msg("<error> Couldn't read embedded font file");
1695 TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1698 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1699 cvt->writeTTF(FoFiWrite, f);
1704 font->getEmbeddedFontID(&embRef);
1705 refObj.initRef(embRef.num, embRef.gen);
1706 refObj.fetch(ref, &strObj);
1708 strObj.streamReset();
1713 f4[t] = strObj.streamGetChar();
1714 f4c[t] = (char)f4[t];
1719 if(!strncmp(f4c, "true", 4)) {
1720 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1721 Change this on the fly */
1722 f4[0] = f4[2] = f4[3] = 0;
1730 while ((c = strObj.streamGetChar()) != EOF) {
1734 strObj.streamClose();
1739 return strdup(tmpFileName);
1742 char* searchForSuitableFont(GfxFont*gfxFont)
1744 char*name = getFontName(gfxFont);
1748 if(!config_use_fontconfig)
1751 #ifdef HAVE_FONTCONFIG
1752 FcPattern *pattern, *match;
1756 static int fcinitcalled = false;
1758 msg("<debug> searchForSuitableFont(%s)", name);
1760 // call init ony once
1761 if (!fcinitcalled) {
1762 msg("<debug> Initializing FontConfig...");
1763 fcinitcalled = true;
1765 msg("<debug> FontConfig Initialization failed. Disabling.");
1766 config_use_fontconfig = 0;
1769 msg("<debug> ...initialized FontConfig");
1772 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1773 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1774 if (gfxFont->isItalic()) // check for italic
1775 msg("<debug> FontConfig: Adding Italic Slant");
1776 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1777 if (gfxFont->isBold()) // check for bold
1778 msg("<debug> FontConfig: Adding Bold Weight");
1779 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1781 msg("<debug> FontConfig: Try to match...");
1782 // configure and match using the original font name
1783 FcConfigSubstitute(0, pattern, FcMatchPattern);
1784 FcDefaultSubstitute(pattern);
1785 match = FcFontMatch(0, pattern, &result);
1787 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1788 msg("<debug> FontConfig: family=%s", (char*)v);
1789 // if we get an exact match
1790 if (strcmp((char *)v, name) == 0) {
1791 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1792 filename = strdup((char*)v); // mem leak
1793 char *nfn = strrchr(filename, '/');
1794 if(nfn) fontname = strdup(nfn+1);
1795 else fontname = filename;
1797 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1799 // initialize patterns
1800 FcPatternDestroy(pattern);
1801 FcPatternDestroy(match);
1803 // now match against serif etc.
1804 if (gfxFont->isSerif()) {
1805 msg("<debug> FontConfig: Create Serif Family Pattern");
1806 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1807 } else if (gfxFont->isFixedWidth()) {
1808 msg("<debug> FontConfig: Create Monospace Family Pattern");
1809 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1811 msg("<debug> FontConfig: Create Sans Family Pattern");
1812 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1816 if (gfxFont->isItalic()) {
1817 msg("<debug> FontConfig: Adding Italic Slant");
1818 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1821 if (gfxFont->isBold()) {
1822 msg("<debug> FontConfig: Adding Bold Weight");
1823 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1826 msg("<debug> FontConfig: Try to match... (2)");
1827 // configure and match using serif etc
1828 FcConfigSubstitute (0, pattern, FcMatchPattern);
1829 FcDefaultSubstitute (pattern);
1830 match = FcFontMatch (0, pattern, &result);
1832 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1833 filename = strdup((char*)v); // mem leak
1834 char *nfn = strrchr(filename, '/');
1835 if(nfn) fontname = strdup(nfn+1);
1836 else fontname = filename;
1838 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1842 //printf("FONTCONFIG: pattern");
1843 //FcPatternPrint(pattern);
1844 //printf("FONTCONFIG: match");
1845 //FcPatternPrint(match);
1847 FcPatternDestroy(pattern);
1848 FcPatternDestroy(match);
1850 pdfswf_addfont(filename);
1857 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1859 char*fontname = 0, *filename = 0;
1860 msg("<notice> subsituteFont(%s)", oldname);
1862 if(!(fontname = searchForSuitableFont(gfxFont))) {
1863 fontname = "Times-Roman";
1865 filename = searchFont(fontname);
1867 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1871 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1872 msg("<fatal> Too many fonts in file.");
1876 substitutesource[substitutepos] = strdup(oldname); //mem leak
1877 substitutetarget[substitutepos] = fontname;
1878 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1881 return strdup(filename); //mem leak
1884 void unlinkfont(char* filename)
1891 if(!strncmp(&filename[l-4],".afm",4)) {
1892 memcpy(&filename[l-4],".pfb",4);
1894 memcpy(&filename[l-4],".pfa",4);
1896 memcpy(&filename[l-4],".afm",4);
1899 if(!strncmp(&filename[l-4],".pfa",4)) {
1900 memcpy(&filename[l-4],".afm",4);
1902 memcpy(&filename[l-4],".pfa",4);
1905 if(!strncmp(&filename[l-4],".pfb",4)) {
1906 memcpy(&filename[l-4],".afm",4);
1908 memcpy(&filename[l-4],".pfb",4);
1913 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1919 int SWFOutputDev::setGfxFont(char*id, char*filename, double maxSize)
1922 fontlist_t*last=0,*l = this->fontlist;
1924 /* TODO: should this be part of the state? */
1927 if(!strcmp(l->id, id)) {
1928 current_font_id = l->id;
1929 current_gfxfont = l->font;
1931 output->addfont(output, id, current_gfxfont);
1936 if(!filename) return 0;
1938 /* A font size of e.g. 9 means the font will be scaled down by
1939 1024 and scaled up by 9. So to have a maximum error of 1/20px,
1940 we have to divide 0.05 by (fontsize/1024)
1942 double quality = (1024 * 0.05) / maxSize;
1944 font = gfxfont_load(filename, quality);
1947 l->filename = strdup(filename);
1950 current_font_id = l->id;
1951 current_gfxfont = l->font;
1957 output->addfont(output, id, current_gfxfont);
1961 void SWFOutputDev::updateFont(GfxState *state)
1963 GfxFont*gfxFont = state->getFont();
1968 char * fontid = getFontID(gfxFont);
1969 double maxSize = 1.0;
1972 maxSize = this->info->getMaximumFontSize(fontid);
1976 /* first, look if we substituted this font before-
1977 this way, we don't initialize the T1 Fonts
1979 for(t=0;t<substitutepos;t++) {
1980 if(!strcmp(fontid, substitutesource[t])) {
1981 free(fontid);fontid=0;
1982 fontid = strdup(substitutetarget[t]);
1987 /* second, see if this is a font which was used before-
1988 if so, we are done */
1989 if(setGfxFont(fontid, 0, 0)) {
1993 /* if(swfoutput_queryfont(&output, fontid))
1994 swfoutput_setfont(&output, fontid, 0);
1996 msg("<debug> updateFont(%s) [cached]", fontid);
2000 // look for Type 3 font
2001 if (gfxFont->getType() == fontType3) {
2003 type3Warning = gTrue;
2004 showFontError(gfxFont, 2);
2010 /* now either load the font, or find a substitution */
2013 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
2018 (gfxFont->getType() == fontType1 ||
2019 gfxFont->getType() == fontType1C ||
2020 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
2021 gfxFont->getType() == fontTrueType ||
2022 gfxFont->getType() == fontCIDType2
2025 fileName = writeEmbeddedFontToFile(xref, gfxFont);
2026 if(!fileName) showFontError(gfxFont,0);
2029 char * fontname = getFontName(gfxFont);
2030 fileName = searchFont(fontname);
2031 if(!fileName) showFontError(gfxFont,0);
2035 char * fontname = getFontName(gfxFont);
2036 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
2037 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
2038 fileName = substituteFont(gfxFont, fontid);
2039 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
2040 msg("<notice> Font is now %s (%s)", fontid, fileName);
2044 msg("<error> Couldn't set font %s\n", fontid);
2049 msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
2050 dumpFontInfo("<verbose>", gfxFont);
2052 //swfoutput_setfont(&output, fontid, fileName);
2054 if(!setGfxFont(fontid, 0, 0)) {
2055 setGfxFont(fontid, fileName, maxSize);
2059 unlinkfont(fileName);
2065 #define SQR(x) ((x)*(x))
2067 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
2069 if((newwidth<2 || newheight<2) ||
2070 (width<=newwidth || height<=newheight))
2072 unsigned char*newdata;
2074 newdata= (unsigned char*)malloc(newwidth*newheight);
2076 double fx = (double)(width)/newwidth;
2077 double fy = (double)(height)/newheight;
2079 int blocksize = (int)(8192/(fx*fy));
2080 int r = 8192*256/palettesize;
2081 for(x=0;x<newwidth;x++) {
2082 double ex = px + fx;
2083 int fromx = (int)px;
2085 int xweight1 = (int)(((fromx+1)-px)*256);
2086 int xweight2 = (int)((ex-tox)*256);
2088 for(y=0;y<newheight;y++) {
2089 double ey = py + fy;
2090 int fromy = (int)py;
2092 int yweight1 = (int)(((fromy+1)-py)*256);
2093 int yweight2 = (int)((ey-toy)*256);
2096 for(xx=fromx;xx<=tox;xx++)
2097 for(yy=fromy;yy<=toy;yy++) {
2098 int b = 1-data[width*yy+xx];
2100 if(xx==fromx) weight = (weight*xweight1)/256;
2101 if(xx==tox) weight = (weight*xweight2)/256;
2102 if(yy==fromy) weight = (weight*yweight1)/256;
2103 if(yy==toy) weight = (weight*yweight2)/256;
2106 //if(a) a=(palettesize-1)*r/blocksize;
2107 newdata[y*newwidth+x] = (a*blocksize)/r;
2115 #define IMAGE_TYPE_JPEG 0
2116 #define IMAGE_TYPE_LOSSLESS 1
2118 static void drawimage(gfxdevice_t*dev, RGBA* data, int sizex,int sizey,
2119 double x1,double y1,
2120 double x2,double y2,
2121 double x3,double y3,
2122 double x4,double y4, int type)
2126 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2127 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2129 gfxline_t p1,p2,p3,p4,p5;
2130 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2131 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2132 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2133 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2134 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2136 {p1.x = (int)(p1.x*20)/20.0;
2137 p1.y = (int)(p1.y*20)/20.0;
2138 p2.x = (int)(p2.x*20)/20.0;
2139 p2.y = (int)(p2.y*20)/20.0;
2140 p3.x = (int)(p3.x*20)/20.0;
2141 p3.y = (int)(p3.y*20)/20.0;
2142 p4.x = (int)(p4.x*20)/20.0;
2143 p4.y = (int)(p4.y*20)/20.0;
2144 p5.x = (int)(p5.x*20)/20.0;
2145 p5.y = (int)(p5.y*20)/20.0;
2152 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2153 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2158 img.data = (gfxcolor_t*)data;
2162 if(type == IMAGE_TYPE_JPEG)
2163 /* TODO: pass image_dpi to device instead */
2164 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2166 dev->fillbitmap(dev, &p1, &img, &m, 0);
2169 void drawimagejpeg(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
2170 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2172 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2175 void drawimagelossless(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
2176 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2178 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2182 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2183 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2184 GBool inlineImg, int mask, int*maskColors)
2189 double x1,y1,x2,y2,x3,y3,x4,y4;
2190 ImageStream *imgStr;
2197 ncomps = colorMap->getNumPixelComps();
2198 bits = colorMap->getBits();
2200 imgStr = new ImageStream(str, width, ncomps,bits);
2203 if(!width || !height || (height<=1 && width<=1))
2205 msg("<verbose> Ignoring %d by %d image", width, height);
2206 unsigned char buf[8];
2208 for (y = 0; y < height; ++y)
2209 for (x = 0; x < width; ++x) {
2210 imgStr->getPixel(buf);
2216 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1+= user_movey;
2217 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2+= user_movey;
2218 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3+= user_movey;
2219 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4+= user_movey;
2221 if(!pbminfo && !(str->getKind()==strDCT)) {
2223 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2227 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2229 if(!jpeginfo && (str->getKind()==strDCT)) {
2230 msg("<notice> file contains jpeg pictures");
2236 unsigned char buf[8];
2238 unsigned char*pic = new unsigned char[width*height];
2241 state->getFillRGB(&rgb);
2243 memset(pal,255,sizeof(pal));
2244 pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
2245 pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
2246 pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
2247 pal[0].a = 255; pal[1].a = 0;
2250 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2251 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2252 for (y = 0; y < height; ++y)
2253 for (x = 0; x < width; ++x)
2255 imgStr->getPixel(buf);
2258 pic[width*y+x] = buf[0];
2261 /* the size of the drawn image is added to the identifier
2262 as the same image may require different bitmaps if displayed
2263 at different sizes (due to antialiasing): */
2266 unsigned char*pic2 = 0;
2269 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2278 height = realheight;
2282 /* make a black/white palette */
2287 float r = 255/(numpalette-1);
2289 for(t=0;t<numpalette;t++) {
2290 pal[t].r = (U8)(255*rgb.r);
2291 pal[t].g = (U8)(255*rgb.g);
2292 pal[t].b = (U8)(255*rgb.b);
2293 pal[t].a = (U8)(t*r);
2297 RGBA*pic2 = new RGBA[width*height];
2298 for (y = 0; y < height; ++y) {
2299 for (x = 0; x < width; ++x) {
2300 pic2[width*y+x] = pal[pic[y*width+x]];
2303 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2312 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2313 RGBA*pic=new RGBA[width*height];
2314 for (y = 0; y < height; ++y) {
2315 for (x = 0; x < width; ++x) {
2316 imgStr->getPixel(pixBuf);
2317 colorMap->getRGB(pixBuf, &rgb);
2318 pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
2319 pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
2320 pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
2321 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2324 if(str->getKind()==strDCT)
2325 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2327 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2332 RGBA*pic=new RGBA[width*height];
2335 for(t=0;t<256;t++) {
2337 colorMap->getRGB(pixBuf, &rgb);
2338 /*if(maskColors && *maskColors==t) {
2339 msg("<notice> Color %d is transparent", t);
2340 if (imgData->maskColors) {
2342 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2343 if (pix[i] < imgData->maskColors[2*i] ||
2344 pix[i] > imgData->maskColors[2*i+1]) {
2359 pal[t].r = (U8)(rgb.r * 255 + 0.5);
2360 pal[t].g = (U8)(rgb.g * 255 + 0.5);
2361 pal[t].b = (U8)(rgb.b * 255 + 0.5);
2362 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2365 for (y = 0; y < height; ++y) {
2366 for (x = 0; x < width; ++x) {
2367 imgStr->getPixel(pixBuf);
2368 pic[width*y+x] = pal[pixBuf[0]];
2371 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2379 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2380 int width, int height, GBool invert,
2383 if(states[statepos].textRender & 4) //clipped
2385 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2386 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
2389 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2390 int width, int height, GfxImageColorMap *colorMap,
2391 int *maskColors, GBool inlineImg)
2393 if(states[statepos].textRender & 4) //clipped
2396 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
2397 colorMap?"colorMap":"no colorMap",
2398 maskColors?"maskColors":"no maskColors",
2401 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2402 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2403 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
2406 //SWFOutputDev*output = 0;
2408 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2413 if (infoDict->lookup(key, &obj)->isString()) {
2414 s1 = obj.getString();
2415 if ((s1->getChar(0) & 0xff) == 0xfe &&
2416 (s1->getChar(1) & 0xff) == 0xff) {
2418 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2419 if (s1->getChar(i) == '\0') {
2420 s2->append(s1->getChar(i+1));
2423 s2 = new GString("<unicode>");
2427 printf(fmt, s2->getCString());
2430 printf(fmt, s1->getCString());
2436 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2440 if (infoDict->lookup(key, &obj)->isString()) {
2441 s = obj.getString()->getCString();
2442 if (s[0] == 'D' && s[1] == ':') {
2453 void storeDeviceParameter(char*name, char*value)
2455 parameter_t*p = new parameter_t();
2456 p->name = strdup(name);
2457 p->value = strdup(value);
2459 if(device_config_next) {
2460 device_config_next->next = p;
2461 device_config_next = p;
2464 device_config_next = p;
2468 void pdfswf_setparameter(char*name, char*value)
2470 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2471 if(!strcmp(name, "caplinewidth")) {
2472 caplinewidth = atof(value);
2473 } else if(!strcmp(name, "zoom")) {
2476 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2477 storeDeviceParameter("jpegsubpixels", buf);
2478 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2479 storeDeviceParameter("ppmsubpixels", buf);
2480 } else if(!strcmp(name, "jpegdpi")) {
2482 jpeg_dpi = atoi(value);
2483 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2484 storeDeviceParameter("jpegsubpixels", buf);
2485 } else if(!strcmp(name, "ppmdpi")) {
2487 ppm_dpi = atoi(value);
2488 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2489 storeDeviceParameter("ppmsubpixels", buf);
2490 } else if(!strcmp(name, "forceType0Fonts")) {
2491 forceType0Fonts = atoi(value);
2492 } else if(!strcmp(name, "fontdir")) {
2493 pdfswf_addfontdir(value);
2494 } else if(!strcmp(name, "languagedir")) {
2495 pdfswf_addlanguagedir(value);
2496 } else if(!strcmp(name, "fontconfig")) {
2497 config_use_fontconfig = atoi(value);
2499 storeDeviceParameter(name,value);
2502 void pdfswf_addfont(char*filename)
2505 memset(&f, 0, sizeof(fontfile_t));
2506 f.filename = filename;
2507 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2508 fonts[fontnum++] = f;
2510 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2514 static char* dirseparator()
2523 void pdfswf_addlanguagedir(char*dir)
2526 globalParams = new GlobalParams("");
2528 msg("<notice> Adding %s to language pack directories", dir);
2532 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2533 strcpy(config_file, dir);
2534 strcat(config_file, dirseparator());
2535 strcat(config_file, "add-to-xpdfrc");
2537 fi = fopen(config_file, "rb");
2539 msg("<error> Could not open %s", config_file);
2542 globalParams->parseFile(new GString(config_file), fi);
2546 void pdfswf_addfontdir(char*dirname)
2548 #ifdef HAVE_DIRENT_H
2549 msg("<notice> Adding %s to font directories", dirname);
2550 DIR*dir = opendir(dirname);
2552 msg("<warning> Couldn't open directory %s\n", dirname);
2557 ent = readdir (dir);
2561 char*name = ent->d_name;
2567 if(!strncasecmp(&name[l-4], ".pfa", 4))
2569 if(!strncasecmp(&name[l-4], ".pfb", 4))
2571 if(!strncasecmp(&name[l-4], ".ttf", 4))
2575 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2576 strcpy(fontname, dirname);
2577 strcat(fontname, dirseparator());
2578 strcat(fontname, name);
2579 msg("<verbose> Adding %s to fonts", fontname);
2580 pdfswf_addfont(fontname);
2585 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2590 typedef struct _pdf_doc_internal
2595 } pdf_doc_internal_t;
2596 typedef struct _pdf_page_internal
2598 } pdf_page_internal_t;
2599 typedef struct _swf_output_internal
2601 SWFOutputDev*outputDev;
2602 } swf_output_internal_t;
2604 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2606 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2607 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2608 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2609 memset(i, 0, sizeof(pdf_doc_internal_t));
2610 pdf_doc->internal = i;
2612 GString *fileName = new GString(filename);
2618 globalParams = new GlobalParams("");
2621 if (userPassword && userPassword[0]) {
2622 userPW = new GString(userPassword);
2626 i->doc = new PDFDoc(fileName, userPW);
2630 if (!i->doc->isOk()) {
2635 i->doc->getDocInfo(&info);
2636 if (info.isDict() &&
2637 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2638 printInfoString(info.getDict(), "Title", "Title: %s\n");
2639 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2640 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2641 printInfoString(info.getDict(), "Author", "Author: %s\n");
2642 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2643 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2644 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2645 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2646 printf("Pages: %d\n", i->doc->getNumPages());
2647 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2648 printf("Encrypted: ");
2649 if (i->doc->isEncrypted()) {
2650 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2651 i->doc->okToPrint() ? "yes" : "no",
2652 i->doc->okToCopy() ? "yes" : "no",
2653 i->doc->okToChange() ? "yes" : "no",
2654 i->doc->okToAddNotes() ? "yes" : "no");
2661 pdf_doc->num_pages = i->doc->getNumPages();
2663 if (i->doc->isEncrypted()) {
2664 if(!i->doc->okToCopy()) {
2665 printf("PDF disallows copying.\n");
2668 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2672 InfoOutputDev*io = new InfoOutputDev();
2674 for(t=1;t<=pdf_doc->num_pages;t++) {
2676 i->doc->displayPage((OutputDev*)io, t, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2678 i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2690 delete globalParams;globalParams=0;
2691 Object::memCheck(stderr);
2696 void pdf_destroy(pdf_doc_t*pdf_doc)
2698 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2700 delete i->doc; i->doc=0;
2703 delete i->info;i->info=0;
2706 free(pdf_doc->internal);pdf_doc->internal=0;
2707 free(pdf_doc);pdf_doc=0;
2710 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2712 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2714 if(page < 1 || page > pdf_doc->num_pages)
2717 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2718 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2719 memset(pi, 0, sizeof(pdf_page_internal_t));
2720 pdf_page->internal = pi;
2722 pdf_page->parent = pdf_doc;
2723 pdf_page->nr = page;
2727 void pdf_page_destroy(pdf_page_t*pdf_page)
2729 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2730 free(pdf_page->internal);pdf_page->internal = 0;
2731 free(pdf_page);pdf_page=0;
2734 swf_output_t* swf_output_init()
2736 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2737 memset(swf_output, 0, sizeof(swf_output_t));
2738 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2739 memset(i, 0, sizeof(swf_output_internal_t));
2740 swf_output->internal = i;
2742 i->outputDev = new SWFOutputDev();
2746 void swf_output_setparameter(swf_output_t*swf, char*name, char*value)
2748 pdfswf_setparameter(name, value);
2751 void swf_output_startframe(swf_output_t*swf, int width, int height)
2753 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2754 i->outputDev->startFrame(width, height);
2757 void swf_output_endframe(swf_output_t*swf)
2759 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2760 i->outputDev->endframe();
2763 void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage)
2765 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2766 SWFOutputDev*o = i->outputDev;
2772 o->pagebuflen = 1024;
2773 o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
2774 memset(o->pages, -1, o->pagebuflen*sizeof(int));
2776 while(pdfpage >= o->pagebuflen)
2778 int oldlen = o->pagebuflen;
2779 o->pagebuflen+=1024;
2780 o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
2781 memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
2784 o->pages[pdfpage] = outputpage;
2785 if(pdfpage>o->pagepos)
2786 o->pagepos = pdfpage;
2789 int swf_output_save(swf_output_t*swf, char*filename)
2791 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2792 int ret = i->outputDev->save(filename);
2796 void* swf_output_get(swf_output_t*swf)
2798 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2799 void* ret = i->outputDev->getSWF();
2803 void swf_output_destroy(swf_output_t*output)
2805 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2806 delete i->outputDev; i->outputDev=0;
2807 free(output->internal);output->internal=0;
2811 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2813 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2814 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2817 msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2822 gfxdevice_t*dev = si->outputDev->output;
2823 dev->setparameter(dev, "protect", "1");
2825 si->outputDev->setInfo(pi->info);
2826 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2828 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2830 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2834 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2836 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2837 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2839 si->outputDev->setMove(x,y);
2840 if((x1|y1|x2|y2)==0) x2++;
2841 si->outputDev->setClip(x1,y1,x2,y2);
2843 pdf_page_render2(page, output);
2845 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2847 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2848 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2850 si->outputDev->setMove(0,0);
2851 si->outputDev->setClip(0,0,0,0);
2853 pdf_page_render2(page, output);
2857 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2859 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2860 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2861 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2862 memset(info, 0, sizeof(pdf_page_info_t));
2864 InfoOutputDev*output = new InfoOutputDev;
2867 pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2869 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2872 info->xMin = output->x1;
2873 info->yMin = output->y1;
2874 info->xMax = output->x2;
2875 info->yMax = output->y2;
2876 info->number_of_images = output->num_images;
2877 info->number_of_links = output->num_links;
2878 info->number_of_fonts = output->num_fonts;
2885 void pdf_page_info_destroy(pdf_page_info_t*info)