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 if(pages[t]==page) {
1523 sprintf(buf, "page%d", t);
1524 output->drawlink(output, points, buf);
1526 msg("<warning> Invalid link to page %d", page);
1531 output->drawlink(output, points, url);
1534 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1538 void SWFOutputDev::saveState(GfxState *state) {
1539 msg("<trace> saveState\n");
1542 msg("<error> Too many nested states in pdf.");
1546 states[statepos].clipping = 0; //? shouldn't this be the current value?
1547 states[statepos].textRender = states[statepos-1].textRender;
1550 void SWFOutputDev::restoreState(GfxState *state) {
1551 msg("<trace> restoreState\n");
1553 while(states[statepos].clipping) {
1554 output->endclip(output);
1555 states[statepos].clipping--;
1560 char* SWFOutputDev::searchFont(char*name)
1564 int is_standard_font = 0;
1566 msg("<verbose> SearchFont(%s)", name);
1568 /* see if it is a pdf standard font */
1569 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1571 if(!strcmp(name, pdf2t1map[i].pdffont))
1573 name = pdf2t1map[i].filename;
1574 is_standard_font = 1;
1578 /* look in all font files */
1579 for(i=0;i<fontnum;i++)
1581 if(strstr(fonts[i].filename, name))
1583 if(!fonts[i].used) {
1586 if(!is_standard_font)
1587 msg("<notice> Using %s for %s", fonts[i].filename, name);
1589 return strdup(fonts[i].filename);
1595 void SWFOutputDev::updateLineWidth(GfxState *state)
1597 double width = state->getTransformedLineWidth();
1598 //swfoutput_setlinewidth(&output, width);
1601 void SWFOutputDev::updateLineCap(GfxState *state)
1603 int c = state->getLineCap();
1606 void SWFOutputDev::updateLineJoin(GfxState *state)
1608 int j = state->getLineJoin();
1611 void SWFOutputDev::updateFillColor(GfxState *state)
1614 double opaq = state->getFillOpacity();
1615 state->getFillRGB(&rgb);
1617 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1620 void SWFOutputDev::updateStrokeColor(GfxState *state)
1623 double opaq = state->getStrokeOpacity();
1624 state->getStrokeRGB(&rgb);
1625 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1628 void FoFiWrite(void *stream, char *data, int len)
1630 fwrite(data, len, 1, (FILE*)stream);
1633 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1635 char*tmpFileName = NULL;
1641 Object refObj, strObj;
1643 tmpFileName = mktmpname(namebuf);
1646 ret = font->getEmbeddedFontID(&embRef);
1648 msg("<verbose> Didn't get embedded font id");
1649 /* not embedded- the caller should now search the font
1650 directories for this font */
1654 f = fopen(tmpFileName, "wb");
1656 msg("<error> Couldn't create temporary Type 1 font file");
1660 /*if(font->isCIDFont()) {
1661 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1662 GString c = cidFont->getCollection();
1663 msg("<notice> Collection: %s", c.getCString());
1666 //if (font->getType() == fontType1C) {
1667 if (0) { //font->getType() == fontType1C) {
1668 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1670 msg("<error> Couldn't read embedded font file");
1674 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1676 cvt->convertToType1(f);
1678 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1680 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1682 //cvt->convertToCIDType0("test", f);
1683 //cvt->convertToType0("test", f);
1686 } else if(font->getType() == fontTrueType) {
1687 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1688 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1690 msg("<error> Couldn't read embedded font file");
1694 TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1697 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1698 cvt->writeTTF(FoFiWrite, f);
1703 font->getEmbeddedFontID(&embRef);
1704 refObj.initRef(embRef.num, embRef.gen);
1705 refObj.fetch(ref, &strObj);
1707 strObj.streamReset();
1712 f4[t] = strObj.streamGetChar();
1713 f4c[t] = (char)f4[t];
1718 if(!strncmp(f4c, "true", 4)) {
1719 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1720 Change this on the fly */
1721 f4[0] = f4[2] = f4[3] = 0;
1729 while ((c = strObj.streamGetChar()) != EOF) {
1733 strObj.streamClose();
1738 return strdup(tmpFileName);
1741 char* searchForSuitableFont(GfxFont*gfxFont)
1743 char*name = getFontName(gfxFont);
1747 if(!config_use_fontconfig)
1750 #ifdef HAVE_FONTCONFIG
1751 FcPattern *pattern, *match;
1755 static int fcinitcalled = false;
1757 msg("<debug> searchForSuitableFont(%s)", name);
1759 // call init ony once
1760 if (!fcinitcalled) {
1761 msg("<debug> Initializing FontConfig...");
1762 fcinitcalled = true;
1764 msg("<debug> FontConfig Initialization failed. Disabling.");
1765 config_use_fontconfig = 0;
1768 msg("<debug> ...initialized FontConfig");
1771 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1772 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1773 if (gfxFont->isItalic()) // check for italic
1774 msg("<debug> FontConfig: Adding Italic Slant");
1775 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1776 if (gfxFont->isBold()) // check for bold
1777 msg("<debug> FontConfig: Adding Bold Weight");
1778 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1780 msg("<debug> FontConfig: Try to match...");
1781 // configure and match using the original font name
1782 FcConfigSubstitute(0, pattern, FcMatchPattern);
1783 FcDefaultSubstitute(pattern);
1784 match = FcFontMatch(0, pattern, &result);
1786 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1787 msg("<debug> FontConfig: family=%s", (char*)v);
1788 // if we get an exact match
1789 if (strcmp((char *)v, name) == 0) {
1790 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1791 filename = strdup((char*)v); // mem leak
1792 char *nfn = strrchr(filename, '/');
1793 if(nfn) fontname = strdup(nfn+1);
1794 else fontname = filename;
1796 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1798 // initialize patterns
1799 FcPatternDestroy(pattern);
1800 FcPatternDestroy(match);
1802 // now match against serif etc.
1803 if (gfxFont->isSerif()) {
1804 msg("<debug> FontConfig: Create Serif Family Pattern");
1805 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1806 } else if (gfxFont->isFixedWidth()) {
1807 msg("<debug> FontConfig: Create Monospace Family Pattern");
1808 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1810 msg("<debug> FontConfig: Create Sans Family Pattern");
1811 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1815 if (gfxFont->isItalic()) {
1816 msg("<debug> FontConfig: Adding Italic Slant");
1817 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1820 if (gfxFont->isBold()) {
1821 msg("<debug> FontConfig: Adding Bold Weight");
1822 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1825 msg("<debug> FontConfig: Try to match... (2)");
1826 // configure and match using serif etc
1827 FcConfigSubstitute (0, pattern, FcMatchPattern);
1828 FcDefaultSubstitute (pattern);
1829 match = FcFontMatch (0, pattern, &result);
1831 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1832 filename = strdup((char*)v); // mem leak
1833 char *nfn = strrchr(filename, '/');
1834 if(nfn) fontname = strdup(nfn+1);
1835 else fontname = filename;
1837 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1841 //printf("FONTCONFIG: pattern");
1842 //FcPatternPrint(pattern);
1843 //printf("FONTCONFIG: match");
1844 //FcPatternPrint(match);
1846 FcPatternDestroy(pattern);
1847 FcPatternDestroy(match);
1849 pdfswf_addfont(filename);
1856 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1858 char*fontname = 0, *filename = 0;
1859 msg("<notice> subsituteFont(%s)", oldname);
1861 if(!(fontname = searchForSuitableFont(gfxFont))) {
1862 fontname = "Times-Roman";
1864 filename = searchFont(fontname);
1866 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1870 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1871 msg("<fatal> Too many fonts in file.");
1875 substitutesource[substitutepos] = strdup(oldname); //mem leak
1876 substitutetarget[substitutepos] = fontname;
1877 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1880 return strdup(filename); //mem leak
1883 void unlinkfont(char* filename)
1890 if(!strncmp(&filename[l-4],".afm",4)) {
1891 memcpy(&filename[l-4],".pfb",4);
1893 memcpy(&filename[l-4],".pfa",4);
1895 memcpy(&filename[l-4],".afm",4);
1898 if(!strncmp(&filename[l-4],".pfa",4)) {
1899 memcpy(&filename[l-4],".afm",4);
1901 memcpy(&filename[l-4],".pfa",4);
1904 if(!strncmp(&filename[l-4],".pfb",4)) {
1905 memcpy(&filename[l-4],".afm",4);
1907 memcpy(&filename[l-4],".pfb",4);
1912 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1918 int SWFOutputDev::setGfxFont(char*id, char*filename, double maxSize)
1921 fontlist_t*last=0,*l = this->fontlist;
1923 /* TODO: should this be part of the state? */
1926 if(!strcmp(l->id, id)) {
1927 current_font_id = l->id;
1928 current_gfxfont = l->font;
1930 output->addfont(output, id, current_gfxfont);
1935 if(!filename) return 0;
1937 /* A font size of e.g. 9 means the font will be scaled down by
1938 1024 and scaled up by 9. So to have a maximum error of 1/20px,
1939 we have to divide 0.05 by (fontsize/1024)
1941 double quality = (1024 * 0.05) / maxSize;
1943 font = gfxfont_load(filename, quality);
1946 l->filename = strdup(filename);
1949 current_font_id = l->id;
1950 current_gfxfont = l->font;
1956 output->addfont(output, id, current_gfxfont);
1960 void SWFOutputDev::updateFont(GfxState *state)
1962 GfxFont*gfxFont = state->getFont();
1967 char * fontid = getFontID(gfxFont);
1968 double maxSize = 1.0;
1971 maxSize = this->info->getMaximumFontSize(fontid);
1975 /* first, look if we substituted this font before-
1976 this way, we don't initialize the T1 Fonts
1978 for(t=0;t<substitutepos;t++) {
1979 if(!strcmp(fontid, substitutesource[t])) {
1980 free(fontid);fontid=0;
1981 fontid = strdup(substitutetarget[t]);
1986 /* second, see if this is a font which was used before-
1987 if so, we are done */
1988 if(setGfxFont(fontid, 0, 0)) {
1992 /* if(swfoutput_queryfont(&output, fontid))
1993 swfoutput_setfont(&output, fontid, 0);
1995 msg("<debug> updateFont(%s) [cached]", fontid);
1999 // look for Type 3 font
2000 if (gfxFont->getType() == fontType3) {
2002 type3Warning = gTrue;
2003 showFontError(gfxFont, 2);
2009 /* now either load the font, or find a substitution */
2012 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
2017 (gfxFont->getType() == fontType1 ||
2018 gfxFont->getType() == fontType1C ||
2019 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
2020 gfxFont->getType() == fontTrueType ||
2021 gfxFont->getType() == fontCIDType2
2024 fileName = writeEmbeddedFontToFile(xref, gfxFont);
2025 if(!fileName) showFontError(gfxFont,0);
2028 char * fontname = getFontName(gfxFont);
2029 fileName = searchFont(fontname);
2030 if(!fileName) showFontError(gfxFont,0);
2034 char * fontname = getFontName(gfxFont);
2035 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
2036 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
2037 fileName = substituteFont(gfxFont, fontid);
2038 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
2039 msg("<notice> Font is now %s (%s)", fontid, fileName);
2043 msg("<error> Couldn't set font %s\n", fontid);
2048 msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
2049 dumpFontInfo("<verbose>", gfxFont);
2051 //swfoutput_setfont(&output, fontid, fileName);
2053 if(!setGfxFont(fontid, 0, 0)) {
2054 setGfxFont(fontid, fileName, maxSize);
2058 unlinkfont(fileName);
2064 #define SQR(x) ((x)*(x))
2066 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
2068 if((newwidth<2 || newheight<2) ||
2069 (width<=newwidth || height<=newheight))
2071 unsigned char*newdata;
2073 newdata= (unsigned char*)malloc(newwidth*newheight);
2075 double fx = (double)(width)/newwidth;
2076 double fy = (double)(height)/newheight;
2078 int blocksize = (int)(8192/(fx*fy));
2079 int r = 8192*256/palettesize;
2080 for(x=0;x<newwidth;x++) {
2081 double ex = px + fx;
2082 int fromx = (int)px;
2084 int xweight1 = (int)(((fromx+1)-px)*256);
2085 int xweight2 = (int)((ex-tox)*256);
2087 for(y=0;y<newheight;y++) {
2088 double ey = py + fy;
2089 int fromy = (int)py;
2091 int yweight1 = (int)(((fromy+1)-py)*256);
2092 int yweight2 = (int)((ey-toy)*256);
2095 for(xx=fromx;xx<=tox;xx++)
2096 for(yy=fromy;yy<=toy;yy++) {
2097 int b = 1-data[width*yy+xx];
2099 if(xx==fromx) weight = (weight*xweight1)/256;
2100 if(xx==tox) weight = (weight*xweight2)/256;
2101 if(yy==fromy) weight = (weight*yweight1)/256;
2102 if(yy==toy) weight = (weight*yweight2)/256;
2105 //if(a) a=(palettesize-1)*r/blocksize;
2106 newdata[y*newwidth+x] = (a*blocksize)/r;
2114 #define IMAGE_TYPE_JPEG 0
2115 #define IMAGE_TYPE_LOSSLESS 1
2117 static void drawimage(gfxdevice_t*dev, RGBA* data, int sizex,int sizey,
2118 double x1,double y1,
2119 double x2,double y2,
2120 double x3,double y3,
2121 double x4,double y4, int type)
2125 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2126 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2128 gfxline_t p1,p2,p3,p4,p5;
2129 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2130 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2131 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2132 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2133 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2135 {p1.x = (int)(p1.x*20)/20.0;
2136 p1.y = (int)(p1.y*20)/20.0;
2137 p2.x = (int)(p2.x*20)/20.0;
2138 p2.y = (int)(p2.y*20)/20.0;
2139 p3.x = (int)(p3.x*20)/20.0;
2140 p3.y = (int)(p3.y*20)/20.0;
2141 p4.x = (int)(p4.x*20)/20.0;
2142 p4.y = (int)(p4.y*20)/20.0;
2143 p5.x = (int)(p5.x*20)/20.0;
2144 p5.y = (int)(p5.y*20)/20.0;
2151 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2152 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2157 img.data = (gfxcolor_t*)data;
2161 if(type == IMAGE_TYPE_JPEG)
2162 /* TODO: pass image_dpi to device instead */
2163 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2165 dev->fillbitmap(dev, &p1, &img, &m, 0);
2168 void drawimagejpeg(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
2169 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2171 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2174 void drawimagelossless(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
2175 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2177 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2181 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2182 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2183 GBool inlineImg, int mask, int*maskColors)
2188 double x1,y1,x2,y2,x3,y3,x4,y4;
2189 ImageStream *imgStr;
2196 ncomps = colorMap->getNumPixelComps();
2197 bits = colorMap->getBits();
2199 imgStr = new ImageStream(str, width, ncomps,bits);
2202 if(!width || !height || (height<=1 && width<=1))
2204 msg("<verbose> Ignoring %d by %d image", width, height);
2205 unsigned char buf[8];
2207 for (y = 0; y < height; ++y)
2208 for (x = 0; x < width; ++x) {
2209 imgStr->getPixel(buf);
2215 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1+= user_movey;
2216 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2+= user_movey;
2217 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3+= user_movey;
2218 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4+= user_movey;
2220 if(!pbminfo && !(str->getKind()==strDCT)) {
2222 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2226 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2228 if(!jpeginfo && (str->getKind()==strDCT)) {
2229 msg("<notice> file contains jpeg pictures");
2235 unsigned char buf[8];
2237 unsigned char*pic = new unsigned char[width*height];
2240 state->getFillRGB(&rgb);
2242 memset(pal,255,sizeof(pal));
2243 pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
2244 pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
2245 pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
2246 pal[0].a = 255; pal[1].a = 0;
2249 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2250 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2251 for (y = 0; y < height; ++y)
2252 for (x = 0; x < width; ++x)
2254 imgStr->getPixel(buf);
2257 pic[width*y+x] = buf[0];
2260 /* the size of the drawn image is added to the identifier
2261 as the same image may require different bitmaps if displayed
2262 at different sizes (due to antialiasing): */
2265 unsigned char*pic2 = 0;
2268 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2277 height = realheight;
2281 /* make a black/white palette */
2286 float r = 255/(numpalette-1);
2288 for(t=0;t<numpalette;t++) {
2289 pal[t].r = (U8)(255*rgb.r);
2290 pal[t].g = (U8)(255*rgb.g);
2291 pal[t].b = (U8)(255*rgb.b);
2292 pal[t].a = (U8)(t*r);
2296 RGBA*pic2 = new RGBA[width*height];
2297 for (y = 0; y < height; ++y) {
2298 for (x = 0; x < width; ++x) {
2299 pic2[width*y+x] = pal[pic[y*width+x]];
2302 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2311 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2312 RGBA*pic=new RGBA[width*height];
2313 for (y = 0; y < height; ++y) {
2314 for (x = 0; x < width; ++x) {
2315 imgStr->getPixel(pixBuf);
2316 colorMap->getRGB(pixBuf, &rgb);
2317 pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
2318 pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
2319 pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
2320 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2323 if(str->getKind()==strDCT)
2324 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2326 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2331 RGBA*pic=new RGBA[width*height];
2334 for(t=0;t<256;t++) {
2336 colorMap->getRGB(pixBuf, &rgb);
2337 /*if(maskColors && *maskColors==t) {
2338 msg("<notice> Color %d is transparent", t);
2339 if (imgData->maskColors) {
2341 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2342 if (pix[i] < imgData->maskColors[2*i] ||
2343 pix[i] > imgData->maskColors[2*i+1]) {
2358 pal[t].r = (U8)(rgb.r * 255 + 0.5);
2359 pal[t].g = (U8)(rgb.g * 255 + 0.5);
2360 pal[t].b = (U8)(rgb.b * 255 + 0.5);
2361 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2364 for (y = 0; y < height; ++y) {
2365 for (x = 0; x < width; ++x) {
2366 imgStr->getPixel(pixBuf);
2367 pic[width*y+x] = pal[pixBuf[0]];
2370 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2378 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2379 int width, int height, GBool invert,
2382 if(states[statepos].textRender & 4) //clipped
2384 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2385 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
2388 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2389 int width, int height, GfxImageColorMap *colorMap,
2390 int *maskColors, GBool inlineImg)
2392 if(states[statepos].textRender & 4) //clipped
2395 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
2396 colorMap?"colorMap":"no colorMap",
2397 maskColors?"maskColors":"no maskColors",
2400 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2401 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2402 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
2405 //SWFOutputDev*output = 0;
2407 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2412 if (infoDict->lookup(key, &obj)->isString()) {
2413 s1 = obj.getString();
2414 if ((s1->getChar(0) & 0xff) == 0xfe &&
2415 (s1->getChar(1) & 0xff) == 0xff) {
2417 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2418 if (s1->getChar(i) == '\0') {
2419 s2->append(s1->getChar(i+1));
2422 s2 = new GString("<unicode>");
2426 printf(fmt, s2->getCString());
2429 printf(fmt, s1->getCString());
2435 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2439 if (infoDict->lookup(key, &obj)->isString()) {
2440 s = obj.getString()->getCString();
2441 if (s[0] == 'D' && s[1] == ':') {
2452 void storeDeviceParameter(char*name, char*value)
2454 parameter_t*p = new parameter_t();
2455 p->name = strdup(name);
2456 p->value = strdup(value);
2458 if(device_config_next) {
2459 device_config_next->next = p;
2460 device_config_next = p;
2463 device_config_next = p;
2467 void pdfswf_setparameter(char*name, char*value)
2469 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2470 if(!strcmp(name, "caplinewidth")) {
2471 caplinewidth = atof(value);
2472 } else if(!strcmp(name, "zoom")) {
2475 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2476 storeDeviceParameter("jpegsubpixels", buf);
2477 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2478 storeDeviceParameter("ppmsubpixels", buf);
2479 } else if(!strcmp(name, "jpegdpi")) {
2481 jpeg_dpi = atoi(value);
2482 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2483 storeDeviceParameter("jpegsubpixels", buf);
2484 } else if(!strcmp(name, "ppmdpi")) {
2486 ppm_dpi = atoi(value);
2487 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2488 storeDeviceParameter("ppmsubpixels", buf);
2489 } else if(!strcmp(name, "forceType0Fonts")) {
2490 forceType0Fonts = atoi(value);
2491 } else if(!strcmp(name, "fontdir")) {
2492 pdfswf_addfontdir(value);
2493 } else if(!strcmp(name, "languagedir")) {
2494 pdfswf_addlanguagedir(value);
2495 } else if(!strcmp(name, "fontconfig")) {
2496 config_use_fontconfig = atoi(value);
2498 storeDeviceParameter(name,value);
2501 void pdfswf_addfont(char*filename)
2504 memset(&f, 0, sizeof(fontfile_t));
2505 f.filename = filename;
2506 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2507 fonts[fontnum++] = f;
2509 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2513 static char* dirseparator()
2522 void pdfswf_addlanguagedir(char*dir)
2525 globalParams = new GlobalParams("");
2527 msg("<notice> Adding %s to language pack directories", dir);
2531 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2532 strcpy(config_file, dir);
2533 strcat(config_file, dirseparator());
2534 strcat(config_file, "add-to-xpdfrc");
2536 fi = fopen(config_file, "rb");
2538 msg("<error> Could not open %s", config_file);
2541 globalParams->parseFile(new GString(config_file), fi);
2545 void pdfswf_addfontdir(char*dirname)
2547 #ifdef HAVE_DIRENT_H
2548 msg("<notice> Adding %s to font directories", dirname);
2549 DIR*dir = opendir(dirname);
2551 msg("<warning> Couldn't open directory %s\n", dirname);
2556 ent = readdir (dir);
2560 char*name = ent->d_name;
2566 if(!strncasecmp(&name[l-4], ".pfa", 4))
2568 if(!strncasecmp(&name[l-4], ".pfb", 4))
2570 if(!strncasecmp(&name[l-4], ".ttf", 4))
2574 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2575 strcpy(fontname, dirname);
2576 strcat(fontname, dirseparator());
2577 strcat(fontname, name);
2578 msg("<verbose> Adding %s to fonts", fontname);
2579 pdfswf_addfont(fontname);
2584 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2589 typedef struct _pdf_doc_internal
2594 } pdf_doc_internal_t;
2595 typedef struct _pdf_page_internal
2597 } pdf_page_internal_t;
2598 typedef struct _swf_output_internal
2600 SWFOutputDev*outputDev;
2601 } swf_output_internal_t;
2603 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2605 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2606 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2607 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2608 memset(i, 0, sizeof(pdf_doc_internal_t));
2609 pdf_doc->internal = i;
2611 GString *fileName = new GString(filename);
2617 globalParams = new GlobalParams("");
2620 if (userPassword && userPassword[0]) {
2621 userPW = new GString(userPassword);
2625 i->doc = new PDFDoc(fileName, userPW);
2629 if (!i->doc->isOk()) {
2634 i->doc->getDocInfo(&info);
2635 if (info.isDict() &&
2636 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2637 printInfoString(info.getDict(), "Title", "Title: %s\n");
2638 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2639 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2640 printInfoString(info.getDict(), "Author", "Author: %s\n");
2641 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2642 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2643 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2644 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2645 printf("Pages: %d\n", i->doc->getNumPages());
2646 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2647 printf("Encrypted: ");
2648 if (i->doc->isEncrypted()) {
2649 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2650 i->doc->okToPrint() ? "yes" : "no",
2651 i->doc->okToCopy() ? "yes" : "no",
2652 i->doc->okToChange() ? "yes" : "no",
2653 i->doc->okToAddNotes() ? "yes" : "no");
2660 pdf_doc->num_pages = i->doc->getNumPages();
2662 if (i->doc->isEncrypted()) {
2663 if(!i->doc->okToCopy()) {
2664 printf("PDF disallows copying.\n");
2667 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2671 InfoOutputDev*io = new InfoOutputDev();
2673 for(t=1;t<=pdf_doc->num_pages;t++) {
2675 i->doc->displayPage((OutputDev*)io, t, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2677 i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2689 delete globalParams;globalParams=0;
2690 Object::memCheck(stderr);
2695 void pdf_destroy(pdf_doc_t*pdf_doc)
2697 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2699 delete i->doc; i->doc=0;
2702 delete i->info;i->info=0;
2705 free(pdf_doc->internal);pdf_doc->internal=0;
2706 free(pdf_doc);pdf_doc=0;
2709 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2711 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2713 if(page < 1 || page > pdf_doc->num_pages)
2716 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2717 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2718 memset(pi, 0, sizeof(pdf_page_internal_t));
2719 pdf_page->internal = pi;
2721 pdf_page->parent = pdf_doc;
2722 pdf_page->nr = page;
2726 void pdf_page_destroy(pdf_page_t*pdf_page)
2728 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2729 free(pdf_page->internal);pdf_page->internal = 0;
2730 free(pdf_page);pdf_page=0;
2733 swf_output_t* swf_output_init()
2735 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2736 memset(swf_output, 0, sizeof(swf_output_t));
2737 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2738 memset(i, 0, sizeof(swf_output_internal_t));
2739 swf_output->internal = i;
2741 i->outputDev = new SWFOutputDev();
2745 void swf_output_setparameter(swf_output_t*swf, char*name, char*value)
2747 pdfswf_setparameter(name, value);
2750 void swf_output_startframe(swf_output_t*swf, int width, int height)
2752 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2753 i->outputDev->startFrame(width, height);
2756 void swf_output_endframe(swf_output_t*swf)
2758 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2759 i->outputDev->endframe();
2762 void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage)
2764 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2765 SWFOutputDev*o = i->outputDev;
2771 o->pagebuflen = 1024;
2772 o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
2773 memset(o->pages, -1, o->pagebuflen*sizeof(int));
2775 while(pdfpage >= o->pagebuflen)
2777 int oldlen = o->pagebuflen;
2778 o->pagebuflen+=1024;
2779 o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
2780 memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
2783 o->pages[pdfpage] = outputpage;
2784 if(pdfpage>o->pagepos)
2785 o->pagepos = pdfpage;
2788 int swf_output_save(swf_output_t*swf, char*filename)
2790 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2791 int ret = i->outputDev->save(filename);
2795 void* swf_output_get(swf_output_t*swf)
2797 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2798 void* ret = i->outputDev->getSWF();
2802 void swf_output_destroy(swf_output_t*output)
2804 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2805 delete i->outputDev; i->outputDev=0;
2806 free(output->internal);output->internal=0;
2810 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2812 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2813 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2816 msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2821 gfxdevice_t*dev = si->outputDev->output;
2822 dev->setparameter(dev, "protect", "1");
2824 si->outputDev->setInfo(pi->info);
2825 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2827 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2829 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2833 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2835 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2836 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2838 si->outputDev->setMove(x,y);
2839 if((x1|y1|x2|y2)==0) x2++;
2840 si->outputDev->setClip(x1,y1,x2,y2);
2842 pdf_page_render2(page, output);
2844 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2846 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2847 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2849 si->outputDev->setMove(0,0);
2850 si->outputDev->setClip(0,0,0,0);
2852 pdf_page_render2(page, output);
2856 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2858 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2859 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2860 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2861 memset(info, 0, sizeof(pdf_page_info_t));
2863 InfoOutputDev*output = new InfoOutputDev;
2866 pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2868 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2871 info->xMin = output->x1;
2872 info->yMin = output->y1;
2873 info->xMax = output->x2;
2874 info->yMax = output->y2;
2875 info->number_of_images = output->num_images;
2876 info->number_of_links = output->num_links;
2877 info->number_of_fonts = output->num_fonts;
2884 void pdf_page_info_destroy(pdf_page_info_t*info)