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"
62 #include "SWFOutputDev.h"
64 //swftools header files
65 #include "swfoutput.h"
66 #include "../lib/log.h"
67 #include "../lib/gfxdevice.h"
68 #include "../lib/gfxtools.h"
69 #include "../lib/gfxfont.h"
73 typedef struct _fontfile
80 static fontfile_t fonts[2048];
81 static int fontnum = 0;
83 static int config_use_fontconfig = 1;
86 // TODO: move into pdf_doc_t
88 static int pagebuflen = 0;
89 static int pagepos = 0;
92 static double caplinewidth = 3.0;
93 static int zoom = 72; /* xpdf: 86 */
94 static int forceType0Fonts = 1;
96 static void printInfoString(Dict *infoDict, char *key, char *fmt);
97 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
103 {"Times-Roman", "n021003l"},
104 {"Times-Italic", "n021023l"},
105 {"Times-Bold", "n021004l"},
106 {"Times-BoldItalic", "n021024l"},
107 {"Helvetica", "n019003l"},
108 {"Helvetica-Oblique", "n019023l"},
109 {"Helvetica-Bold", "n019004l"},
110 {"Helvetica-BoldOblique", "n019024l"},
111 {"Courier", "n022003l"},
112 {"Courier-Oblique", "n022023l"},
113 {"Courier-Bold", "n022004l"},
114 {"Courier-BoldOblique", "n022024l"},
115 {"Symbol", "s050000l"},
116 {"ZapfDingbats", "d050000l"}};
118 class SWFOutputState {
124 this->textRender = 0;
128 typedef struct _fontlist
136 class SWFOutputDev: public OutputDev {
138 struct swfoutput output;
145 virtual ~SWFOutputDev() ;
147 void setMove(int x,int y);
148 void setClip(int x1,int y1,int x2,int y2);
150 int save(char*filename);
154 void getDimensions(int*x1,int*y1,int*x2,int*y2);
156 //----- get info about output device
158 // Does this device use upside-down coordinates?
159 // (Upside-down means (0,0) is the top left corner of the page.)
160 virtual GBool upsideDown();
162 // Does this device use drawChar() or drawString()?
163 virtual GBool useDrawChar();
165 // Can this device draw gradients?
166 virtual GBool useGradients();
168 virtual GBool interpretType3Chars() {return gTrue;}
170 //----- initialization and control
172 void setXRef(PDFDoc*doc, XRef *xref);
175 virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
178 virtual void drawLink(Link *link, Catalog *catalog) ;
180 //----- save/restore graphics state
181 virtual void saveState(GfxState *state) ;
182 virtual void restoreState(GfxState *state) ;
184 //----- update graphics state
186 virtual void updateFont(GfxState *state);
187 virtual void updateFillColor(GfxState *state);
188 virtual void updateStrokeColor(GfxState *state);
189 virtual void updateLineWidth(GfxState *state);
190 virtual void updateLineJoin(GfxState *state);
191 virtual void updateLineCap(GfxState *state);
193 virtual void updateAll(GfxState *state)
196 updateFillColor(state);
197 updateStrokeColor(state);
198 updateLineWidth(state);
199 updateLineJoin(state);
200 updateLineCap(state);
203 //----- path painting
204 virtual void stroke(GfxState *state) ;
205 virtual void fill(GfxState *state) ;
206 virtual void eoFill(GfxState *state) ;
208 //----- path clipping
209 virtual void clip(GfxState *state) ;
210 virtual void eoClip(GfxState *state) ;
213 virtual void beginString(GfxState *state, GString *s) ;
214 virtual void endString(GfxState *state) ;
215 virtual void endTextObject(GfxState *state);
216 virtual void drawChar(GfxState *state, double x, double y,
217 double dx, double dy,
218 double originX, double originY,
219 CharCode code, Unicode *u, int uLen);
221 //----- image drawing
222 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
223 int width, int height, GBool invert,
225 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
226 int width, int height, GfxImageColorMap *colorMap,
227 int *maskColors, GBool inlineImg);
229 virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
230 virtual void endType3Char(GfxState *state);
232 virtual void type3D0(GfxState *state, double wx, double wy);
233 virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
236 void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
237 int width, int height, GfxImageColorMap*colorMap, GBool invert,
238 GBool inlineImg, int mask, int *maskColors);
239 int SWFOutputDev::setGfxFont(char*id, char*filename);
241 SWFOutputState states[64];
249 char* searchFont(char*name);
250 char* substituteFont(GfxFont*gfxFont, char*oldname);
251 char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
253 int jpeginfo; // did we write "File contains jpegs" yet?
254 int pbminfo; // did we write "File contains jpegs" yet?
255 int linkinfo; // did we write "File contains links" yet?
256 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
257 int gradientinfo; // did we write "File contains Gradients yet?
259 int type3active; // are we between beginType3()/endType3()?
265 char* substitutetarget[256];
266 char* substitutesource[256];
269 int user_movex,user_movey;
270 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
272 gfxline_t* current_text_stroke;
273 char* current_font_id;
274 gfxfont_t* current_gfxfont;
275 fontlist_t* fontlist;
278 static char*getFontID(GfxFont*font);
280 class InfoOutputDev: public OutputDev
294 virtual ~InfoOutputDev()
297 virtual GBool upsideDown() {return gTrue;}
298 virtual GBool useDrawChar() {return gTrue;}
299 virtual GBool useGradients() {return gTrue;}
300 virtual GBool interpretType3Chars() {return gTrue;}
301 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
304 state->transform(crop_x1,crop_y1,&x1,&y1);
305 state->transform(crop_x2,crop_y2,&x2,&y2);
306 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
307 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
313 virtual void drawLink(Link *link, Catalog *catalog)
317 virtual void updateFont(GfxState *state)
319 GfxFont*font = state->getFont();
322 /*char*id = getFontID(font);*/
326 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
327 int width, int height, GBool invert,
332 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
333 int width, int height, GfxImageColorMap *colorMap,
334 int *maskColors, GBool inlineImg)
340 SWFOutputDev::SWFOutputDev()
358 current_text_stroke = 0;
360 memset(&output, 0, sizeof(output));
361 // printf("SWFOutputDev::SWFOutputDev() \n");
364 void SWFOutputDev::setMove(int x,int y)
366 this->user_movex = x;
367 this->user_movey = y;
370 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
372 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
373 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
375 this->user_clipx1 = x1;
376 this->user_clipy1 = y1;
377 this->user_clipx2 = x2;
378 this->user_clipy2 = y2;
380 void SWFOutputDev::getDimensions(int*x1,int*y1,int*x2,int*y2)
382 return swfoutput_getdimensions(&output, x1,y1,x2,y2);
385 static char*getFontID(GfxFont*font)
387 GString*gstr = font->getName();
388 char* fontname = gstr==0?0:gstr->getCString();
392 sprintf(buf, "UFONT%d", r->num);
395 return strdup(fontname);
398 static char*getFontName(GfxFont*font)
400 char*fontid = getFontID(font);
402 char* plus = strchr(fontid, '+');
403 if(plus && plus < &fontid[strlen(fontid)-1]) {
404 fontname = strdup(plus+1);
406 fontname = strdup(fontid);
412 static char mybuf[1024];
413 static char* gfxstate2str(GfxState *state)
417 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
424 if(state->getX1()!=0.0)
425 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
426 if(state->getY1()!=0.0)
427 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
428 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
429 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
430 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
431 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
432 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
433 state->getFillColor()->c[0], state->getFillColor()->c[1]);
434 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
435 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
436 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
437 state->getFillColor()->c[0], state->getFillColor()->c[1],
438 state->getFillColor()->c[2], state->getFillColor()->c[3],
439 state->getFillColor()->c[4], state->getFillColor()->c[5],
440 state->getFillColor()->c[6], state->getFillColor()->c[7]);
441 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
442 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
443 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
444 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
445 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
446 state->getFillRGB(&rgb);
447 if(rgb.r || rgb.g || rgb.b)
448 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
449 state->getStrokeRGB(&rgb);
450 if(rgb.r || rgb.g || rgb.b)
451 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
452 if(state->getFillColorSpace()->getNComps()>1)
453 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
454 if(state->getStrokeColorSpace()->getNComps()>1)
455 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
456 if(state->getFillPattern())
457 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
458 if(state->getStrokePattern())
459 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
461 if(state->getFillOpacity()!=1.0)
462 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
463 if(state->getStrokeOpacity()!=1.0)
464 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
466 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
471 state->getLineDash(&dash, &length, &start);
475 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
476 for(t=0;t<length;t++) {
477 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
479 bufpos+=sprintf(bufpos,"]");
482 if(state->getFlatness()!=1)
483 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
484 if(state->getLineJoin()!=0)
485 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
486 if(state->getLineJoin()!=0)
487 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
488 if(state->getLineJoin()!=0)
489 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
491 if(state->getFont() && getFontID(state->getFont()))
492 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
493 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
494 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
495 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
496 if(state->getCharSpace())
497 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
498 if(state->getWordSpace())
499 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
500 if(state->getHorizScaling()!=1.0)
501 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
502 if(state->getLeading())
503 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
505 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
506 if(state->getRender())
507 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
508 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
509 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
510 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
511 if(state->getLineX())
512 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
513 if(state->getLineY())
514 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
515 bufpos+=sprintf(bufpos," ");
519 static void dumpFontInfo(char*loglevel, GfxFont*font);
520 static int lastdumps[1024];
521 static int lastdumppos = 0;
526 static void showFontError(GfxFont*font, int nr)
530 for(t=0;t<lastdumppos;t++)
531 if(lastdumps[t] == r->num)
535 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
536 lastdumps[lastdumppos++] = r->num;
538 msg("<warning> The following font caused problems:");
540 msg("<warning> The following font caused problems (substituting):");
542 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
543 dumpFontInfo("<warning>", font);
546 static void dumpFontInfo(char*loglevel, GfxFont*font)
548 char* id = getFontID(font);
549 char* name = getFontName(font);
550 Ref* r=font->getID();
551 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
553 GString*gstr = font->getTag();
555 msg("%s| Tag: %s\n", loglevel, id);
557 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
559 GfxFontType type=font->getType();
561 case fontUnknownType:
562 msg("%s| Type: unknown\n",loglevel);
565 msg("%s| Type: 1\n",loglevel);
568 msg("%s| Type: 1C\n",loglevel);
571 msg("%s| Type: 3\n",loglevel);
574 msg("%s| Type: TrueType\n",loglevel);
577 msg("%s| Type: CIDType0\n",loglevel);
580 msg("%s| Type: CIDType0C\n",loglevel);
583 msg("%s| Type: CIDType2\n",loglevel);
588 GBool embedded = font->getEmbeddedFontID(&embRef);
590 if(font->getEmbeddedFontName()) {
591 embeddedName = font->getEmbeddedFontName()->getCString();
594 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
596 gstr = font->getExtFontFile();
598 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
600 // Get font descriptor flags.
601 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
602 if(font->isSerif()) msg("%s| is serif\n", loglevel);
603 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
604 if(font->isItalic()) msg("%s| is italic\n", loglevel);
605 if(font->isBold()) msg("%s| is bold\n", loglevel);
611 //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");}
612 //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");}
615 void dump_outline(gfxline_t*line)
618 if(line->type == gfx_moveTo) {
619 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
620 } else if(line->type == gfx_lineTo) {
621 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
622 } else if(line->type == gfx_splineTo) {
623 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
629 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed)
631 int num = path->getNumSubpaths();
634 double lastx=0,lasty=0,posx=0,posy=0;
637 msg("<warning> empty path");
641 gfxdrawer_target_gfxline(&draw);
643 for(t = 0; t < num; t++) {
644 GfxSubpath *subpath = path->getSubpath(t);
645 int subnum = subpath->getNumPoints();
646 double bx=0,by=0,cx=0,cy=0;
648 for(s=0;s<subnum;s++) {
650 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
652 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
653 draw.lineTo(&draw, lastx, lasty);
655 draw.moveTo(&draw, x,y);
660 } else if(subpath->getCurve(s) && cpos==0) {
664 } else if(subpath->getCurve(s) && cpos==1) {
672 draw.lineTo(&draw, x,y);
674 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y);
681 /* fix non-closed lines */
682 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
683 draw.lineTo(&draw, lastx, lasty);
685 gfxline_t*result = (gfxline_t*)draw.result(&draw);
689 /*----------------------------------------------------------------------------
690 * Primitive Graphic routines
691 *----------------------------------------------------------------------------*/
693 void SWFOutputDev::stroke(GfxState *state)
695 GfxPath * path = state->getPath();
696 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
697 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
698 double miterLimit = state->getMiterLimit();
699 double width = state->getTransformedLineWidth();
702 double opaq = state->getStrokeOpacity();
704 state->getFillRGB(&rgb);
706 state->getStrokeRGB(&rgb);
708 col.r = (unsigned char)(rgb.r*255);
709 col.g = (unsigned char)(rgb.g*255);
710 col.b = (unsigned char)(rgb.b*255);
711 col.a = (unsigned char)(opaq*255);
713 gfx_capType capType = gfx_capRound;
714 if(lineCap == 0) capType = gfx_capButt;
715 else if(lineCap == 1) capType = gfx_capRound;
716 else if(lineCap == 2) capType = gfx_capSquare;
718 gfx_joinType joinType = gfx_joinRound;
719 if(lineJoin == 0) joinType = gfx_joinMiter;
720 else if(lineJoin == 1) joinType = gfx_joinRound;
721 else if(lineJoin == 2) joinType = gfx_joinBevel;
723 gfxline_t*line= gfxPath_to_gfxline(state, path, 0);
726 double dashphase = 0;
728 state->getLineDash(&ldash, &dashnum, &dashphase);
730 if(dashnum && ldash) {
731 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
735 msg("<trace> %d dashes", dashnum);
736 msg("<trace> | phase: %f", dashphase);
737 for(t=0;t<dashnum;t++) {
739 msg("<trace> | d%-3d: %f", t, ldash[t]);
742 if(getLogLevel() >= LOGLEVEL_TRACE) {
746 gfxline_t*line2 = gfxtool_dash_line(line, dash, dashphase);
749 msg("<trace> After dashing:");
752 if(getLogLevel() >= LOGLEVEL_TRACE) {
754 state->getStrokeGray(&gray);
755 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n",
757 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
758 lineCap==0?"butt": (lineJoin==1?"round":"square"),
760 col.r,col.g,col.b,col.a,
766 swfoutput_drawgfxline(&output, line, width, &col, capType, joinType, miterLimit);
769 void SWFOutputDev::fill(GfxState *state)
771 GfxPath * path = state->getPath();
772 double opaq = state->getFillOpacity();
774 state->getFillRGB(&rgb);
776 col.r = (unsigned char)(rgb.r*255);
777 col.g = (unsigned char)(rgb.g*255);
778 col.b = (unsigned char)(rgb.b*255);
779 col.a = (unsigned char)(opaq*255);
781 gfxline_t*line= gfxPath_to_gfxline(state, path, 1);
783 if(getLogLevel() >= LOGLEVEL_TRACE) {
784 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
788 swfoutput_fillgfxline(&output, line, &col);
791 void SWFOutputDev::eoFill(GfxState *state)
793 GfxPath * path = state->getPath();
794 double opaq = state->getFillOpacity();
796 state->getFillRGB(&rgb);
798 col.r = (unsigned char)(rgb.r*255);
799 col.g = (unsigned char)(rgb.g*255);
800 col.b = (unsigned char)(rgb.b*255);
801 col.a = (unsigned char)(opaq*255);
803 gfxline_t*line= gfxPath_to_gfxline(state, path, 1);
805 if(getLogLevel() >= LOGLEVEL_TRACE) {
806 msg("<trace> eofill\n");
810 swfoutput_fillgfxline(&output, line, &col);
813 void SWFOutputDev::clip(GfxState *state)
815 GfxPath * path = state->getPath();
816 gfxline_t*line = gfxPath_to_gfxline(state, path, 1);
818 if(getLogLevel() >= LOGLEVEL_TRACE) {
819 msg("<trace> clip\n");
823 swfoutput_startclip(&output, line);
824 states[statepos].clipping++;
827 void SWFOutputDev::eoClip(GfxState *state)
829 GfxPath * path = state->getPath();
830 gfxline_t*line = gfxPath_to_gfxline(state, path, 1);
832 if(getLogLevel() >= LOGLEVEL_TRACE) {
833 msg("<trace> eoclip\n");
837 swfoutput_startclip(&output, line);
838 states[statepos].clipping++;
842 /* pass through functions for swf_output */
843 int SWFOutputDev::save(char*filename)
845 return swfoutput_save(&output, filename);
847 void SWFOutputDev::pagefeed()
849 swfoutput_pagefeed(&output);
851 void* SWFOutputDev::getSWF()
853 return (void*)swfoutput_get(&output);
856 SWFOutputDev::~SWFOutputDev()
858 swfoutput_destroy(&output);
861 fontlist_t*l = this->fontlist;
863 fontlist_t*next = l->next;
865 gfxfont_free(l->font);
872 GBool SWFOutputDev::upsideDown()
874 msg("<debug> upsidedown? yes");
877 GBool SWFOutputDev::useDrawChar()
881 GBool SWFOutputDev::useGradients()
885 msg("<notice> File contains gradients");
891 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
892 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
894 static char tmp_printstr[4096];
895 char* makeStringPrintable(char*str)
897 int len = strlen(str);
912 tmp_printstr[len++] = '.';
913 tmp_printstr[len++] = '.';
914 tmp_printstr[len++] = '.';
916 tmp_printstr[len] = 0;
920 void SWFOutputDev::beginString(GfxState *state, GString *s)
922 int render = state->getRender();
923 msg("<trace> beginString(%s) render=%d", s->getCString(), render);
924 double m11,m21,m12,m22;
925 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
926 state->getFontTransMat(&m11, &m12, &m21, &m22);
927 m11 *= state->getHorizScaling();
928 m21 *= state->getHorizScaling();
929 swfoutput_setfontmatrix(&output, m11, -m21, m12, -m22);
930 if(render != 3 && render != 0)
931 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));
932 states[statepos].textRender = render;
935 static int textCount = 0;
937 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
938 double dx, double dy,
939 double originX, double originY,
940 CharCode c, Unicode *_u, int uLen)
944 int render = state->getRender();
945 // check for invisible text -- this is used by Acrobat Capture
949 if(states[statepos].textRender != render)
950 msg("<error> Internal error: drawChar.render!=beginString.render");
953 double opaq = state->getFillOpacity();
954 state->getFillRGB(&rgb);
956 col.r = (unsigned char)(rgb.r*255);
957 col.g = (unsigned char)(rgb.g*255);
958 col.b = (unsigned char)(rgb.b*255);
959 col.a = (unsigned char)(opaq*255);
961 Gushort *CIDToGIDMap = 0;
962 GfxFont*font = state->getFont();
964 if(font->getType() == fontType3) {
965 /* type 3 chars are passed as graphics */
966 msg("<debug> type3 char at %f/%f", x, y);
972 state->transform(x, y, &x1, &y1);
981 /* find out char name from unicode index
982 TODO: should be precomputed
984 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
985 if(nameToUnicodeTab[t].u == u) {
986 name = nameToUnicodeTab[t].name;
993 if(font->isCIDFont()) {
994 GfxCIDFont*cfont = (GfxCIDFont*)font;
996 if(font->getType() == fontCIDType2)
997 CIDToGIDMap = cfont->getCIDToGID();
1000 font8 = (Gfx8BitFont*)font;
1001 char**enc=font8->getEncoding();
1006 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);
1009 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);
1012 swfoutput_drawchar(&output, x1, y1, name, c, u, &col);
1015 void SWFOutputDev::endString(GfxState *state)
1017 msg("<trace> endString()");
1020 void SWFOutputDev::endTextObject(GfxState *state)
1022 if(states[statepos].textRender != state->getRender())
1023 msg("<error> Internal error: drawChar.render!=beginString.render");
1024 msg("<trace> endTextObject()");
1027 /* the logic seems to be as following:
1028 first, beginType3Char is called, with the charcode and the coordinates.
1029 if this function returns true, it already knew about the char and has now drawn it.
1030 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1031 the all draw operations until endType3Char are part of the char (which in this moment is
1032 at the position first passed to beginType3Char). the char ends with endType3Char.
1034 The drawing operations between beginType3Char and endType3Char are somewhat different to
1035 the normal ones. For example, the fillcolor equals the stroke color.
1038 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1040 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1042 /* the character itself is going to be passed using the draw functions */
1043 return gFalse; /* gTrue= is_in_cache? */
1046 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1047 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1049 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1050 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1054 void SWFOutputDev::endType3Char(GfxState *state)
1057 msg("<debug> endType3Char");
1060 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1062 this->currentpage = pageNum;
1064 int rot = doc->getPageRotate(1);
1066 msg("<verbose> startPage %d (%f,%f,%f,%f)\n", pageNum, crop_x1, crop_y1, crop_x2, crop_y2);
1068 msg("<verbose> page is rotated %d degrees\n", rot);
1070 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1071 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1072 Use CropBox, not MediaBox, as page size
1079 state->transform(crop_x1,crop_y1,&x1,&y1);
1080 state->transform(crop_x2,crop_y2,&x2,&y2);
1082 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1083 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1085 /* apply user clip box */
1086 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1087 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1088 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1089 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1090 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1093 if(!outputstarted) {
1094 msg("<verbose> Bounding box is (%f,%f)-(%f,%f)", x1,y1,x2,y2);
1095 swfoutput_init(&output);
1099 swfoutput_newpage(&output, pageNum, user_movex, user_movey, (int)x1, (int)y1, (int)x2, (int)y2);
1102 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1104 msg("<debug> drawlink\n");
1105 double x1, y1, x2, y2, w;
1111 link->getBorder(&x1, &y1, &x2, &y2, &w);
1113 link->getRect(&x1, &y1, &x2, &y2);
1118 cvtUserToDev(x1, y1, &x, &y);
1119 points[0].x = points[4].x = (int)x;
1120 points[0].y = points[4].y = (int)y;
1121 cvtUserToDev(x2, y1, &x, &y);
1122 points[1].x = (int)x;
1123 points[1].y = (int)y;
1124 cvtUserToDev(x2, y2, &x, &y);
1125 points[2].x = (int)x;
1126 points[2].y = (int)y;
1127 cvtUserToDev(x1, y2, &x, &y);
1128 points[3].x = (int)x;
1129 points[3].y = (int)y;
1131 LinkAction*action=link->getAction();
1138 switch(action->getKind())
1142 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1143 LinkDest *dest=NULL;
1144 if (ha->getDest()==NULL)
1145 dest=catalog->findDest(ha->getNamedDest());
1146 else dest=ha->getDest();
1148 if (dest->isPageRef()){
1149 Ref pageref=dest->getPageRef();
1150 page=catalog->findPage(pageref.num,pageref.gen);
1152 else page=dest->getPageNum();
1153 sprintf(buf, "%d", page);
1160 LinkGoToR*l = (LinkGoToR*)action;
1161 GString*g = l->getNamedDest();
1163 s = strdup(g->getCString());
1168 LinkNamed*l = (LinkNamed*)action;
1169 GString*name = l->getName();
1171 s = strdup(name->lowerCase()->getCString());
1172 named = name->getCString();
1175 if(strstr(s, "next") || strstr(s, "forward"))
1177 page = currentpage + 1;
1179 else if(strstr(s, "prev") || strstr(s, "back"))
1181 page = currentpage - 1;
1183 else if(strstr(s, "last") || strstr(s, "end"))
1185 page = pagepos>0?pages[pagepos-1]:0;
1187 else if(strstr(s, "first") || strstr(s, "top"))
1195 case actionLaunch: {
1197 LinkLaunch*l = (LinkLaunch*)action;
1198 GString * str = new GString(l->getFileName());
1199 str->append(l->getParams());
1200 s = strdup(str->getCString());
1206 LinkURI*l = (LinkURI*)action;
1207 GString*g = l->getURI();
1209 url = g->getCString();
1214 case actionUnknown: {
1216 LinkUnknown*l = (LinkUnknown*)action;
1221 msg("<error> Unknown link type!\n");
1225 if(!s) s = strdup("-?-");
1227 if(!linkinfo && (page || url))
1229 msg("<notice> File contains links");
1235 for(t=0;t<pagepos;t++)
1239 swfoutput_linktopage(&output, t, points);
1243 swfoutput_linktourl(&output, url, points);
1247 swfoutput_namedlink(&output, named, points);
1249 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1253 void SWFOutputDev::saveState(GfxState *state) {
1254 msg("<trace> saveState\n");
1257 msg("<error> Too many nested states in pdf.");
1261 states[statepos].clipping = 0; //? shouldn't this be the current value?
1262 states[statepos].textRender = states[statepos-1].textRender;
1265 void SWFOutputDev::restoreState(GfxState *state) {
1266 msg("<trace> restoreState\n");
1268 while(states[statepos].clipping) {
1269 swfoutput_endclip(&output);
1270 states[statepos].clipping--;
1275 char* SWFOutputDev::searchFont(char*name)
1279 int is_standard_font = 0;
1281 msg("<verbose> SearchFont(%s)", name);
1283 /* see if it is a pdf standard font */
1284 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1286 if(!strcmp(name, pdf2t1map[i].pdffont))
1288 name = pdf2t1map[i].filename;
1289 is_standard_font = 1;
1293 /* look in all font files */
1294 for(i=0;i<fontnum;i++)
1296 if(strstr(fonts[i].filename, name))
1298 if(!fonts[i].used) {
1301 if(!is_standard_font)
1302 msg("<notice> Using %s for %s", fonts[i].filename, name);
1304 return strdup(fonts[i].filename);
1310 void SWFOutputDev::updateLineWidth(GfxState *state)
1312 double width = state->getTransformedLineWidth();
1313 //swfoutput_setlinewidth(&output, width);
1316 void SWFOutputDev::updateLineCap(GfxState *state)
1318 int c = state->getLineCap();
1321 void SWFOutputDev::updateLineJoin(GfxState *state)
1323 int j = state->getLineJoin();
1326 void SWFOutputDev::updateFillColor(GfxState *state)
1329 double opaq = state->getFillOpacity();
1330 state->getFillRGB(&rgb);
1332 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1335 void SWFOutputDev::updateStrokeColor(GfxState *state)
1338 double opaq = state->getStrokeOpacity();
1339 state->getStrokeRGB(&rgb);
1340 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1343 void FoFiWrite(void *stream, char *data, int len)
1345 fwrite(data, len, 1, (FILE*)stream);
1348 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1350 char*tmpFileName = NULL;
1356 Object refObj, strObj;
1358 tmpFileName = mktmpname(namebuf);
1361 ret = font->getEmbeddedFontID(&embRef);
1363 msg("<verbose> Didn't get embedded font id");
1364 /* not embedded- the caller should now search the font
1365 directories for this font */
1369 f = fopen(tmpFileName, "wb");
1371 msg("<error> Couldn't create temporary Type 1 font file");
1375 /*if(font->isCIDFont()) {
1376 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1377 GString c = cidFont->getCollection();
1378 msg("<notice> Collection: %s", c.getCString());
1381 if (font->getType() == fontType1C) {
1382 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1384 msg("<error> Couldn't read embedded font file");
1388 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1390 cvt->convertToType1(f);
1392 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1394 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1396 //cvt->convertToCIDType0("test", f);
1397 //cvt->convertToType0("test", f);
1400 } else if(font->getType() == fontTrueType) {
1401 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1402 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1404 msg("<error> Couldn't read embedded font file");
1408 TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1411 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1412 cvt->writeTTF(FoFiWrite, f);
1417 font->getEmbeddedFontID(&embRef);
1418 refObj.initRef(embRef.num, embRef.gen);
1419 refObj.fetch(ref, &strObj);
1421 strObj.streamReset();
1426 f4[t] = strObj.streamGetChar();
1427 f4c[t] = (char)f4[t];
1432 if(!strncmp(f4c, "true", 4)) {
1433 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1434 Change this on the fly */
1435 f4[0] = f4[2] = f4[3] = 0;
1443 while ((c = strObj.streamGetChar()) != EOF) {
1447 strObj.streamClose();
1452 return strdup(tmpFileName);
1455 char* searchForSuitableFont(GfxFont*gfxFont)
1457 char*name = getFontName(gfxFont);
1461 if(!config_use_fontconfig)
1464 #ifdef HAVE_FONTCONFIG
1465 FcPattern *pattern, *match;
1469 static int fcinitcalled = false;
1471 msg("<debug> searchForSuitableFont(%s)", name);
1473 // call init ony once
1474 if (!fcinitcalled) {
1475 msg("<debug> Initializing FontConfig...");
1476 fcinitcalled = true;
1478 msg("<debug> FontConfig Initialization failed. Disabling.");
1479 config_use_fontconfig = 0;
1482 msg("<debug> ...initialized FontConfig");
1485 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1486 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1487 if (gfxFont->isItalic()) // check for italic
1488 msg("<debug> FontConfig: Adding Italic Slant");
1489 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1490 if (gfxFont->isBold()) // check for bold
1491 msg("<debug> FontConfig: Adding Bold Weight");
1492 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1494 msg("<debug> FontConfig: Try to match...");
1495 // configure and match using the original font name
1496 FcConfigSubstitute(0, pattern, FcMatchPattern);
1497 FcDefaultSubstitute(pattern);
1498 match = FcFontMatch(0, pattern, &result);
1500 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1501 msg("<debug> FontConfig: family=%s", (char*)v);
1502 // if we get an exact match
1503 if (strcmp((char *)v, name) == 0) {
1504 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1505 filename = strdup((char*)v); // mem leak
1506 char *nfn = strrchr(filename, '/');
1507 if(nfn) fontname = strdup(nfn+1);
1508 else fontname = filename;
1510 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1512 // initialize patterns
1513 FcPatternDestroy(pattern);
1514 FcPatternDestroy(match);
1516 // now match against serif etc.
1517 if (gfxFont->isSerif()) {
1518 msg("<debug> FontConfig: Create Serif Family Pattern");
1519 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1520 } else if (gfxFont->isFixedWidth()) {
1521 msg("<debug> FontConfig: Create Monospace Family Pattern");
1522 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1524 msg("<debug> FontConfig: Create Sans Family Pattern");
1525 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1529 if (gfxFont->isItalic()) {
1530 msg("<debug> FontConfig: Adding Italic Slant");
1531 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1534 if (gfxFont->isBold()) {
1535 msg("<debug> FontConfig: Adding Bold Weight");
1536 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1539 msg("<debug> FontConfig: Try to match... (2)");
1540 // configure and match using serif etc
1541 FcConfigSubstitute (0, pattern, FcMatchPattern);
1542 FcDefaultSubstitute (pattern);
1543 match = FcFontMatch (0, pattern, &result);
1545 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1546 filename = strdup((char*)v); // mem leak
1547 char *nfn = strrchr(filename, '/');
1548 if(nfn) fontname = strdup(nfn+1);
1549 else fontname = filename;
1551 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1555 //printf("FONTCONFIG: pattern");
1556 //FcPatternPrint(pattern);
1557 //printf("FONTCONFIG: match");
1558 //FcPatternPrint(match);
1560 FcPatternDestroy(pattern);
1561 FcPatternDestroy(match);
1563 pdfswf_addfont(filename);
1570 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1572 char*fontname = 0, *filename = 0;
1573 msg("<notice> subsituteFont(%s)", oldname);
1575 if(!(fontname = searchForSuitableFont(gfxFont))) {
1576 fontname = "Times-Roman";
1578 filename = searchFont(fontname);
1580 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1584 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1585 msg("<fatal> Too many fonts in file.");
1589 substitutesource[substitutepos] = strdup(oldname); //mem leak
1590 substitutetarget[substitutepos] = fontname;
1591 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1594 return strdup(filename); //mem leak
1597 void unlinkfont(char* filename)
1604 if(!strncmp(&filename[l-4],".afm",4)) {
1605 memcpy(&filename[l-4],".pfb",4);
1607 memcpy(&filename[l-4],".pfa",4);
1609 memcpy(&filename[l-4],".afm",4);
1612 if(!strncmp(&filename[l-4],".pfa",4)) {
1613 memcpy(&filename[l-4],".afm",4);
1615 memcpy(&filename[l-4],".pfa",4);
1618 if(!strncmp(&filename[l-4],".pfb",4)) {
1619 memcpy(&filename[l-4],".afm",4);
1621 memcpy(&filename[l-4],".pfb",4);
1626 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1632 int SWFOutputDev::setGfxFont(char*id, char*filename)
1635 fontlist_t*last=0,*l = this->fontlist;
1637 /* TODO: should this be part of the state? */
1640 if(!strcmp(l->id, id)) {
1641 current_font_id = l->id;
1642 current_gfxfont = l->font;
1648 if(!filename) return 0;
1649 font = gfxfont_load(filename);
1652 l->filename = strdup(filename);
1655 current_font_id = l->id;
1656 current_gfxfont = l->font;
1665 void SWFOutputDev::updateFont(GfxState *state)
1667 GfxFont*gfxFont = state->getFont();
1672 char * fontid = getFontID(gfxFont);
1675 /* first, look if we substituted this font before-
1676 this way, we don't initialize the T1 Fonts
1678 for(t=0;t<substitutepos;t++) {
1679 if(!strcmp(fontid, substitutesource[t])) {
1680 free(fontid);fontid=0;
1681 fontid = strdup(substitutetarget[t]);
1686 /* second, see if swfoutput already has this font
1687 cached- if so, we are done */
1688 setGfxFont(fontid, 0);
1689 if(swfoutput_queryfont(&output, fontid))
1691 swfoutput_setfont(&output, fontid, 0);
1693 msg("<debug> updateFont(%s) [cached]", fontid);
1698 // look for Type 3 font
1699 if (gfxFont->getType() == fontType3) {
1701 type3Warning = gTrue;
1702 showFontError(gfxFont, 2);
1708 /* now either load the font, or find a substitution */
1711 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1716 (gfxFont->getType() == fontType1 ||
1717 gfxFont->getType() == fontType1C ||
1718 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
1719 gfxFont->getType() == fontTrueType ||
1720 gfxFont->getType() == fontCIDType2
1723 fileName = writeEmbeddedFontToFile(xref, gfxFont);
1724 if(!fileName) showFontError(gfxFont,0);
1727 char * fontname = getFontName(gfxFont);
1728 fileName = searchFont(fontname);
1729 if(!fileName) showFontError(gfxFont,0);
1732 char * fontname = getFontName(gfxFont);
1733 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
1734 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
1735 fileName = substituteFont(gfxFont, fontid);
1736 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
1737 msg("<notice> Font is now %s (%s)", fontid, fileName);
1741 msg("<error> Couldn't set font %s\n", fontid);
1746 msg("<verbose> updateFont(%s) -> %s", fontid, fileName);
1747 dumpFontInfo("<verbose>", gfxFont);
1749 swfoutput_setfont(&output, fontid, fileName);
1751 if(!setGfxFont(fontid, 0)) {
1752 setGfxFont(fontid, fileName);
1756 unlinkfont(fileName);
1762 #define SQR(x) ((x)*(x))
1764 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1766 if((newwidth<2 || newheight<2) ||
1767 (width<=newwidth || height<=newheight))
1769 unsigned char*newdata;
1771 newdata= (unsigned char*)malloc(newwidth*newheight);
1773 double fx = (double)(width)/newwidth;
1774 double fy = (double)(height)/newheight;
1776 int blocksize = (int)(8192/(fx*fy));
1777 int r = 8192*256/palettesize;
1778 for(x=0;x<newwidth;x++) {
1779 double ex = px + fx;
1780 int fromx = (int)px;
1782 int xweight1 = (int)(((fromx+1)-px)*256);
1783 int xweight2 = (int)((ex-tox)*256);
1785 for(y=0;y<newheight;y++) {
1786 double ey = py + fy;
1787 int fromy = (int)py;
1789 int yweight1 = (int)(((fromy+1)-py)*256);
1790 int yweight2 = (int)((ey-toy)*256);
1793 for(xx=fromx;xx<=tox;xx++)
1794 for(yy=fromy;yy<=toy;yy++) {
1795 int b = 1-data[width*yy+xx];
1797 if(xx==fromx) weight = (weight*xweight1)/256;
1798 if(xx==tox) weight = (weight*xweight2)/256;
1799 if(yy==fromy) weight = (weight*yweight1)/256;
1800 if(yy==toy) weight = (weight*yweight2)/256;
1803 //if(a) a=(palettesize-1)*r/blocksize;
1804 newdata[y*newwidth+x] = (a*blocksize)/r;
1812 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
1813 int width, int height, GfxImageColorMap*colorMap, GBool invert,
1814 GBool inlineImg, int mask, int*maskColors)
1819 double x1,y1,x2,y2,x3,y3,x4,y4;
1820 ImageStream *imgStr;
1827 ncomps = colorMap->getNumPixelComps();
1828 bits = colorMap->getBits();
1830 imgStr = new ImageStream(str, width, ncomps,bits);
1833 if(!width || !height || (height<=1 && width<=1))
1835 msg("<verbose> Ignoring %d by %d image", width, height);
1836 unsigned char buf[8];
1838 for (y = 0; y < height; ++y)
1839 for (x = 0; x < width; ++x) {
1840 imgStr->getPixel(buf);
1846 state->transform(0, 1, &x1, &y1);
1847 state->transform(0, 0, &x2, &y2);
1848 state->transform(1, 0, &x3, &y3);
1849 state->transform(1, 1, &x4, &y4);
1851 if(!pbminfo && !(str->getKind()==strDCT)) {
1853 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
1857 msg("<verbose> drawing %d by %d masked picture\n", width, height);
1859 if(!jpeginfo && (str->getKind()==strDCT)) {
1860 msg("<notice> file contains jpeg pictures");
1866 unsigned char buf[8];
1868 unsigned char*pic = new unsigned char[width*height];
1871 state->getFillRGB(&rgb);
1873 memset(pal,255,sizeof(pal));
1874 pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
1875 pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
1876 pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
1877 pal[0].a = 255; pal[1].a = 0;
1880 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
1881 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
1882 for (y = 0; y < height; ++y)
1883 for (x = 0; x < width; ++x)
1885 imgStr->getPixel(buf);
1888 pic[width*y+x] = buf[0];
1891 /* the size of the drawn image is added to the identifier
1892 as the same image may require different bitmaps if displayed
1893 at different sizes (due to antialiasing): */
1896 unsigned char*pic2 = 0;
1899 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
1908 height = realheight;
1912 /* make a black/white palette */
1917 float r = 255/(numpalette-1);
1919 for(t=0;t<numpalette;t++) {
1920 pal[t].r = (U8)(255*rgb.r);
1921 pal[t].g = (U8)(255*rgb.g);
1922 pal[t].b = (U8)(255*rgb.b);
1923 pal[t].a = (U8)(t*r);
1927 RGBA*pic2 = new RGBA[width*height];
1928 for (y = 0; y < height; ++y) {
1929 for (x = 0; x < width; ++x) {
1930 pic2[width*y+x] = pal[pic[y*width+x]];
1933 swfoutput_drawimagelossless(&output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1942 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
1943 RGBA*pic=new RGBA[width*height];
1944 for (y = 0; y < height; ++y) {
1945 for (x = 0; x < width; ++x) {
1946 imgStr->getPixel(pixBuf);
1947 colorMap->getRGB(pixBuf, &rgb);
1948 pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
1949 pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
1950 pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
1951 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
1954 if(str->getKind()==strDCT)
1955 swfoutput_drawimagejpeg(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1957 swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1962 RGBA*pic=new RGBA[width*height];
1965 for(t=0;t<256;t++) {
1967 colorMap->getRGB(pixBuf, &rgb);
1968 /*if(maskColors && *maskColors==t) {
1969 msg("<notice> Color %d is transparent", t);
1970 if (imgData->maskColors) {
1972 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
1973 if (pix[i] < imgData->maskColors[2*i] ||
1974 pix[i] > imgData->maskColors[2*i+1]) {
1989 pal[t].r = (U8)(rgb.r * 255 + 0.5);
1990 pal[t].g = (U8)(rgb.g * 255 + 0.5);
1991 pal[t].b = (U8)(rgb.b * 255 + 0.5);
1992 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
1995 for (y = 0; y < height; ++y) {
1996 for (x = 0; x < width; ++x) {
1997 imgStr->getPixel(pixBuf);
1998 pic[width*y+x] = pal[pixBuf[0]];
2001 swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2009 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2010 int width, int height, GBool invert,
2013 if(states[statepos].textRender & 4) //clipped
2015 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2016 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
2019 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2020 int width, int height, GfxImageColorMap *colorMap,
2021 int *maskColors, GBool inlineImg)
2023 if(states[statepos].textRender & 4) //clipped
2026 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
2027 colorMap?"colorMap":"no colorMap",
2028 maskColors?"maskColors":"no maskColors",
2031 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2032 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2033 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
2036 SWFOutputDev*output = 0;
2038 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2043 if (infoDict->lookup(key, &obj)->isString()) {
2044 s1 = obj.getString();
2045 if ((s1->getChar(0) & 0xff) == 0xfe &&
2046 (s1->getChar(1) & 0xff) == 0xff) {
2048 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2049 if (s1->getChar(i) == '\0') {
2050 s2->append(s1->getChar(i+1));
2053 s2 = new GString("<unicode>");
2057 printf(fmt, s2->getCString());
2060 printf(fmt, s1->getCString());
2066 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2070 if (infoDict->lookup(key, &obj)->isString()) {
2071 s = obj.getString()->getCString();
2072 if (s[0] == 'D' && s[1] == ':') {
2083 void pdfswf_setparameter(char*name, char*value)
2085 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2086 if(!strcmp(name, "caplinewidth")) {
2087 caplinewidth = atof(value);
2088 } else if(!strcmp(name, "zoom")) {
2091 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2092 swfoutput_setparameter("jpegsubpixels", buf);
2093 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2094 swfoutput_setparameter("ppmsubpixels", buf);
2095 } else if(!strcmp(name, "jpegdpi")) {
2097 jpeg_dpi = atoi(value);
2098 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2099 swfoutput_setparameter("jpegsubpixels", buf);
2100 } else if(!strcmp(name, "ppmdpi")) {
2102 ppm_dpi = atoi(value);
2103 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2104 swfoutput_setparameter("ppmsubpixels", buf);
2105 } else if(!strcmp(name, "forceType0Fonts")) {
2106 forceType0Fonts = atoi(value);
2107 } else if(!strcmp(name, "fontdir")) {
2108 pdfswf_addfontdir(value);
2109 } else if(!strcmp(name, "languagedir")) {
2110 pdfswf_addlanguagedir(value);
2111 } else if(!strcmp(name, "fontconfig")) {
2112 config_use_fontconfig = atoi(value);
2114 swfoutput_setparameter(name, value);
2117 void pdfswf_addfont(char*filename)
2120 memset(&f, 0, sizeof(fontfile_t));
2121 f.filename = filename;
2122 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2123 fonts[fontnum++] = f;
2125 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2129 static char* dirseparator()
2138 void pdfswf_addlanguagedir(char*dir)
2141 globalParams = new GlobalParams("");
2143 msg("<notice> Adding %s to language pack directories", dir);
2147 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2148 strcpy(config_file, dir);
2149 strcat(config_file, dirseparator());
2150 strcat(config_file, "add-to-xpdfrc");
2152 fi = fopen(config_file, "rb");
2154 msg("<error> Could not open %s", config_file);
2157 globalParams->parseFile(new GString(config_file), fi);
2161 void pdfswf_addfontdir(char*dirname)
2163 #ifdef HAVE_DIRENT_H
2164 msg("<notice> Adding %s to font directories", dirname);
2165 DIR*dir = opendir(dirname);
2167 msg("<warning> Couldn't open directory %s\n", dirname);
2172 ent = readdir (dir);
2176 char*name = ent->d_name;
2182 if(!strncasecmp(&name[l-4], ".pfa", 4))
2184 if(!strncasecmp(&name[l-4], ".pfb", 4))
2186 if(!strncasecmp(&name[l-4], ".ttf", 4))
2190 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2191 strcpy(fontname, dirname);
2192 strcat(fontname, dirseparator());
2193 strcat(fontname, name);
2194 msg("<verbose> Adding %s to fonts", fontname);
2195 pdfswf_addfont(fontname);
2200 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2205 typedef struct _pdf_doc_internal
2209 } pdf_doc_internal_t;
2210 typedef struct _pdf_page_internal
2212 } pdf_page_internal_t;
2213 typedef struct _swf_output_internal
2215 SWFOutputDev*outputDev;
2216 } swf_output_internal_t;
2218 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2220 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2221 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2222 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2223 memset(i, 0, sizeof(pdf_doc_internal_t));
2224 pdf_doc->internal = i;
2226 GString *fileName = new GString(filename);
2232 globalParams = new GlobalParams("");
2235 if (userPassword && userPassword[0]) {
2236 userPW = new GString(userPassword);
2240 i->doc = new PDFDoc(fileName, userPW);
2244 if (!i->doc->isOk()) {
2249 i->doc->getDocInfo(&info);
2250 if (info.isDict() &&
2251 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2252 printInfoString(info.getDict(), "Title", "Title: %s\n");
2253 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2254 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2255 printInfoString(info.getDict(), "Author", "Author: %s\n");
2256 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2257 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2258 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2259 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2260 printf("Pages: %d\n", i->doc->getNumPages());
2261 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2262 printf("Encrypted: ");
2263 if (i->doc->isEncrypted()) {
2264 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2265 i->doc->okToPrint() ? "yes" : "no",
2266 i->doc->okToCopy() ? "yes" : "no",
2267 i->doc->okToChange() ? "yes" : "no",
2268 i->doc->okToAddNotes() ? "yes" : "no");
2275 pdf_doc->num_pages = i->doc->getNumPages();
2277 if (i->doc->isEncrypted()) {
2278 if(!i->doc->okToCopy()) {
2279 printf("PDF disallows copying.\n");
2282 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2289 void pdfswf_preparepage(int page)
2293 pages = (int*)malloc(1024*sizeof(int));
2296 if(pagepos == pagebuflen)
2299 pages = (int*)realloc(pages, pagebuflen);
2302 pages[pagepos++] = page;
2309 delete globalParams;globalParams=0;
2310 Object::memCheck(stderr);
2315 void pdf_destroy(pdf_doc_t*pdf_doc)
2317 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2319 msg("<debug> pdfswf.cc: pdfswf_close()");
2320 delete i->doc; i->doc=0;
2322 free(pages); pages = 0; //FIXME
2324 free(pdf_doc->internal);pdf_doc->internal=0;
2325 free(pdf_doc);pdf_doc=0;
2328 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2330 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2332 if(page < 1 || page > pdf_doc->num_pages)
2335 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2336 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2337 memset(pi, 0, sizeof(pdf_page_internal_t));
2338 pdf_page->internal = pi;
2340 pdf_page->parent = pdf_doc;
2341 pdf_page->nr = page;
2345 void pdf_page_destroy(pdf_page_t*pdf_page)
2347 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2348 free(pdf_page->internal);pdf_page->internal = 0;
2349 free(pdf_page);pdf_page=0;
2352 swf_output_t* swf_output_init()
2354 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2355 memset(swf_output, 0, sizeof(swf_output_t));
2356 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2357 memset(i, 0, sizeof(swf_output_internal_t));
2358 swf_output->internal = i;
2360 i->outputDev = new SWFOutputDev();
2364 void swf_output_setparameter(swf_output_t*swf_output, char*name, char*value)
2367 pdfswf_setparameter(name, value);
2370 void swf_output_pagefeed(swf_output_t*swf)
2372 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2373 i->outputDev->pagefeed();
2374 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2377 int swf_output_save(swf_output_t*swf, char*filename)
2379 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2380 int ret = i->outputDev->save(filename);
2381 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2385 void* swf_output_get(swf_output_t*swf)
2387 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2388 void* ret = i->outputDev->getSWF();
2389 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2393 void swf_output_destroy(swf_output_t*output)
2395 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2396 delete i->outputDev; i->outputDev=0;
2397 free(output->internal);output->internal=0;
2401 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2403 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2404 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2407 swfoutput_setparameter("protect", "1");
2409 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2411 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2413 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2415 si->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2418 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2420 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2421 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2423 si->outputDev->setMove(x,y);
2424 if((x1|y1|x2|y2)==0) x2++;
2425 si->outputDev->setClip(x1,y1,x2,y2);
2427 pdf_page_render2(page, output);
2429 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2431 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2432 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2434 si->outputDev->setMove(0,0);
2435 si->outputDev->setClip(0,0,0,0);
2437 pdf_page_render2(page, output);
2441 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2443 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2444 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2445 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2446 memset(info, 0, sizeof(pdf_page_info_t));
2448 InfoOutputDev*output = new InfoOutputDev;
2451 pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2453 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2456 info->xMin = output->x1;
2457 info->yMin = output->y1;
2458 info->xMax = output->x2;
2459 info->yMax = output->y2;
2460 info->number_of_images = output->num_images;
2461 info->number_of_links = output->num_links;
2462 info->number_of_fonts = output->num_fonts;
2469 void pdf_page_info_destroy(pdf_page_info_t*info)