2 implements a pdf output device (OutputDev).
4 This file is part of swftools.
6 Swftools is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 Swftools is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with swftools; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
25 #include "../config.h"
29 #ifdef HAVE_SYS_STAT_H
32 #ifdef HAVE_FONTCONFIG
33 #include <fontconfig.h>
50 #include "OutputDev.h"
53 #include "CharCodeToUnicode.h"
54 #include "NameToUnicodeTable.h"
55 #include "GlobalParams.h"
56 #include "FoFiType1C.h"
57 #include "FoFiTrueType.h"
59 #include "SWFOutputDev.h"
61 //swftools header files
62 #include "../lib/devices/swf.h"
63 #include "../lib/log.h"
64 #include "../lib/gfxdevice.h"
65 #include "../lib/gfxtools.h"
66 #include "../lib/gfxfont.h"
70 typedef struct _fontfile
76 typedef struct _parameter
80 struct _parameter*next;
83 static parameter_t* device_config = 0;
84 static parameter_t* device_config_next = 0;
87 static fontfile_t fonts[2048];
88 static int fontnum = 0;
90 static int config_use_fontconfig = 1;
93 static double caplinewidth = 3.0;
94 static double zoom = 72; /* xpdf: 86 */
95 static int forceType0Fonts = 1;
97 static void printInfoString(Dict *infoDict, char *key, char *fmt);
98 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
100 static char* lastfontdir = 0;
106 {"Times-Roman", "n021003l"},
107 {"Times-Italic", "n021023l"},
108 {"Times-Bold", "n021004l"},
109 {"Times-BoldItalic", "n021024l"},
110 {"Helvetica", "n019003l"},
111 {"Helvetica-Oblique", "n019023l"},
112 {"Helvetica-Bold", "n019004l"},
113 {"Helvetica-BoldOblique", "n019024l"},
114 {"Courier", "n022003l"},
115 {"Courier-Oblique", "n022023l"},
116 {"Courier-Bold", "n022004l"},
117 {"Courier-BoldOblique", "n022024l"},
118 {"Symbol", "s050000l"},
119 {"ZapfDingbats", "d050000l"}};
121 class SWFOutputState {
127 this->textRender = 0;
131 typedef struct _fontlist
141 class SWFOutputDev: public OutputDev {
149 virtual ~SWFOutputDev() ;
151 void setMove(int x,int y);
152 void setClip(int x1,int y1,int x2,int y2);
154 void setInfo(InfoOutputDev*info) {this->info = info;}
156 int save(char*filename);
159 void startFrame(int width, int height);
161 virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
164 void* get(char*name);
166 //----- get info about output device
168 // Does this device use upside-down coordinates?
169 // (Upside-down means (0,0) is the top left corner of the page.)
170 virtual GBool upsideDown();
172 // Does this device use drawChar() or drawString()?
173 virtual GBool useDrawChar();
175 // Can this device draw gradients?
176 virtual GBool useGradients();
178 virtual GBool interpretType3Chars() {return gTrue;}
180 //----- initialization and control
182 void setXRef(PDFDoc*doc, XRef *xref);
185 virtual void drawLink(Link *link, Catalog *catalog) ;
187 //----- save/restore graphics state
188 virtual void saveState(GfxState *state) ;
189 virtual void restoreState(GfxState *state) ;
191 //----- update graphics state
193 virtual void updateFont(GfxState *state);
194 virtual void updateFillColor(GfxState *state);
195 virtual void updateStrokeColor(GfxState *state);
196 virtual void updateLineWidth(GfxState *state);
197 virtual void updateLineJoin(GfxState *state);
198 virtual void updateLineCap(GfxState *state);
200 virtual void updateAll(GfxState *state)
203 updateFillColor(state);
204 updateStrokeColor(state);
205 updateLineWidth(state);
206 updateLineJoin(state);
207 updateLineCap(state);
210 //----- path painting
211 virtual void stroke(GfxState *state) ;
212 virtual void fill(GfxState *state) ;
213 virtual void eoFill(GfxState *state) ;
215 //----- path clipping
216 virtual void clip(GfxState *state) ;
217 virtual void eoClip(GfxState *state) ;
220 virtual void beginString(GfxState *state, GString *s) ;
221 virtual void endString(GfxState *state) ;
222 virtual void endTextObject(GfxState *state);
223 virtual void drawChar(GfxState *state, double x, double y,
224 double dx, double dy,
225 double originX, double originY,
226 CharCode code, int nBytes, Unicode *u, int uLen);
228 //----- image drawing
229 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
230 int width, int height, GBool invert,
232 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
233 int width, int height, GfxImageColorMap *colorMap,
234 int *maskColors, GBool inlineImg);
235 virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
236 int width, int height,
237 GfxImageColorMap *colorMap,
238 Stream *maskStr, int maskWidth, int maskHeight,
240 virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
241 int width, int height,
242 GfxImageColorMap *colorMap,
244 int maskWidth, int maskHeight,
245 GfxImageColorMap *maskColorMap);
247 virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
248 virtual void endType3Char(GfxState *state);
250 virtual void type3D0(GfxState *state, double wx, double wy);
251 virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
254 void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
255 int width, int height, GfxImageColorMap*colorMap, GBool invert,
256 GBool inlineImg, int mask, int *maskColors,
257 Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GfxImageColorMap*maskColorMap);
258 int SWFOutputDev::setGfxFont(char*id, char*name, char*filename, double quality);
259 void strokeGfxline(GfxState *state, gfxline_t*line);
260 void clipToGfxLine(GfxState *state, gfxline_t*line);
261 void fillGfxLine(GfxState *state, gfxline_t*line);
265 gfxresult_t*result; //filled when complete
267 char outer_clip_box; //whether the page clip box is still on
270 SWFOutputState states[64];
278 char* searchFont(char*name);
279 char* substituteFont(GfxFont*gfxFont, char*oldname);
280 char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
282 int textmodeinfo; // did we write "Text will be rendered as polygon" yet?
283 int jpeginfo; // did we write "File contains jpegs" yet?
284 int pbminfo; // did we write "File contains jpegs" yet?
285 int linkinfo; // did we write "File contains links" yet?
286 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
287 int gradientinfo; // did we write "File contains Gradients yet?
289 int type3active; // are we between beginType3()/endType3()?
295 char* substitutetarget[256];
296 char* substitutesource[256];
299 int user_movex,user_movey;
300 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
302 gfxline_t* current_text_stroke;
303 gfxline_t* current_text_clip;
304 char* current_font_id;
305 gfxfont_t* current_gfxfont;
306 gfxmatrix_t current_font_matrix;
308 fontlist_t* fontlist;
314 friend void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage);
317 typedef struct _drawnchar
335 chars = (drawnchar_t*)malloc(sizeof(drawnchar_t)*buf_size);
336 memset(chars, 0, sizeof(drawnchar_t)*buf_size);
341 free(chars);chars = 0;
348 chars = (drawnchar_t*)realloc(chars, sizeof(drawnchar_t)*buf_size);
352 void addChar(int charid, gfxcoord_t x, gfxcoord_t y, gfxcolor_t color)
355 chars[num_chars].x = x;
356 chars[num_chars].y = y;
357 chars[num_chars].color = color;
358 chars[num_chars].charid = charid;
362 static char*getFontID(GfxFont*font);
370 class InfoOutputDev: public OutputDev
373 FontInfo* currentfont;
385 id2font = new GHash();
387 virtual ~InfoOutputDev()
391 virtual GBool upsideDown() {return gTrue;}
392 virtual GBool useDrawChar() {return gTrue;}
393 virtual GBool useGradients() {return gTrue;}
394 virtual GBool interpretType3Chars() {return gTrue;}
395 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
398 state->transform(crop_x1,crop_y1,&x1,&y1);
399 state->transform(crop_x2,crop_y2,&x2,&y2);
400 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
401 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
407 virtual void drawLink(Link *link, Catalog *catalog)
411 virtual double getMaximumFontSize(char*id)
413 FontInfo*info = (FontInfo*)id2font->lookup(id);
415 msg("<error> Unknown font id: %s", id);
418 return info->max_size;
421 virtual void updateFont(GfxState *state)
423 GfxFont*font = state->getFont();
426 char*id = getFontID(font);
428 FontInfo*info = (FontInfo*)id2font->lookup(id);
430 GString* idStr = new GString(id);
434 id2font->add(idStr, (void*)info);
441 virtual void drawChar(GfxState *state, double x, double y,
442 double dx, double dy,
443 double originX, double originY,
444 CharCode code, int nBytes, Unicode *u, int uLen)
446 int render = state->getRender();
449 double m11,m21,m12,m22;
450 state->getFontTransMat(&m11, &m12, &m21, &m22);
451 m11 *= state->getHorizScaling();
452 m21 *= state->getHorizScaling();
453 double lenx = sqrt(m11*m11 + m12*m12);
454 double leny = sqrt(m21*m21 + m22*m22);
455 double len = lenx>leny?lenx:leny;
456 if(currentfont && currentfont->max_size < len) {
457 currentfont->max_size = len;
460 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
461 int width, int height, GBool invert,
466 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
467 int width, int height, GfxImageColorMap *colorMap,
468 int *maskColors, GBool inlineImg)
474 SWFOutputDev::SWFOutputDev()
492 current_text_stroke = 0;
493 current_text_clip = 0;
500 output = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
501 gfxdevice_swf_init(output);
502 /* configure device */
503 parameter_t*p = device_config;
505 output->setparameter(output, p->name, p->value);
510 void SWFOutputDev::setMove(int x,int y)
512 this->user_movex = x;
513 this->user_movey = y;
516 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
518 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
519 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
521 this->user_clipx1 = x1;
522 this->user_clipy1 = y1;
523 this->user_clipx2 = x2;
524 this->user_clipy2 = y2;
527 static char*getFontID(GfxFont*font)
529 Ref*ref = font->getID();
530 GString*gstr = font->getName();
531 char* fname = gstr==0?0:gstr->getCString();
534 sprintf(buf, "font-%d-%d", ref->num, ref->gen);
536 sprintf(buf, "%s-%d-%d", fname, ref->num, ref->gen);
541 static char*getFontName(GfxFont*font)
544 GString*gstr = font->getName();
545 char* fname = gstr==0?0:gstr->getCString();
549 sprintf(buf, "UFONT%d", r->num);
550 fontid = strdup(buf);
552 fontid = strdup(fname);
555 char* plus = strchr(fontid, '+');
556 if(plus && plus < &fontid[strlen(fontid)-1]) {
557 fontname = strdup(plus+1);
559 fontname = strdup(fontid);
565 static char mybuf[1024];
566 static char* gfxstate2str(GfxState *state)
570 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
577 if(state->getX1()!=0.0)
578 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
579 if(state->getY1()!=0.0)
580 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
581 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
582 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
583 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
584 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
585 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
586 state->getFillColor()->c[0], state->getFillColor()->c[1]);
587 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
588 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
589 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
590 state->getFillColor()->c[0], state->getFillColor()->c[1],
591 state->getFillColor()->c[2], state->getFillColor()->c[3],
592 state->getFillColor()->c[4], state->getFillColor()->c[5],
593 state->getFillColor()->c[6], state->getFillColor()->c[7]);
594 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
595 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
596 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
597 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
598 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
599 state->getFillRGB(&rgb);
600 if(rgb.r || rgb.g || rgb.b)
601 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
602 state->getStrokeRGB(&rgb);
603 if(rgb.r || rgb.g || rgb.b)
604 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
605 if(state->getFillColorSpace()->getNComps()>1)
606 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
607 if(state->getStrokeColorSpace()->getNComps()>1)
608 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
609 if(state->getFillPattern())
610 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
611 if(state->getStrokePattern())
612 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
614 if(state->getFillOpacity()!=1.0)
615 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
616 if(state->getStrokeOpacity()!=1.0)
617 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
619 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
624 state->getLineDash(&dash, &length, &start);
628 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
629 for(t=0;t<length;t++) {
630 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
632 bufpos+=sprintf(bufpos,"]");
635 if(state->getFlatness()!=1)
636 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
637 if(state->getLineJoin()!=0)
638 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
639 if(state->getLineJoin()!=0)
640 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
641 if(state->getLineJoin()!=0)
642 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
644 if(state->getFont() && getFontID(state->getFont()))
645 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
646 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
647 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
648 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
649 if(state->getCharSpace())
650 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
651 if(state->getWordSpace())
652 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
653 if(state->getHorizScaling()!=1.0)
654 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
655 if(state->getLeading())
656 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
658 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
659 if(state->getRender())
660 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
661 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
662 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
663 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
664 if(state->getLineX())
665 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
666 if(state->getLineY())
667 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
668 bufpos+=sprintf(bufpos," ");
672 static void dumpFontInfo(char*loglevel, GfxFont*font);
673 static int lastdumps[1024];
674 static int lastdumppos = 0;
679 static void showFontError(GfxFont*font, int nr)
683 for(t=0;t<lastdumppos;t++)
684 if(lastdumps[t] == r->num)
688 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
689 lastdumps[lastdumppos++] = r->num;
691 msg("<warning> The following font caused problems:");
693 msg("<warning> The following font caused problems (substituting):");
695 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
696 dumpFontInfo("<warning>", font);
699 static void dumpFontInfo(char*loglevel, GfxFont*font)
701 char* id = getFontID(font);
702 char* name = getFontName(font);
703 Ref* r=font->getID();
704 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
706 GString*gstr = font->getTag();
708 msg("%s| Tag: %s\n", loglevel, id);
710 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
712 GfxFontType type=font->getType();
714 case fontUnknownType:
715 msg("%s| Type: unknown\n",loglevel);
718 msg("%s| Type: 1\n",loglevel);
721 msg("%s| Type: 1C\n",loglevel);
724 msg("%s| Type: 3\n",loglevel);
727 msg("%s| Type: TrueType\n",loglevel);
730 msg("%s| Type: CIDType0\n",loglevel);
733 msg("%s| Type: CIDType0C\n",loglevel);
736 msg("%s| Type: CIDType2\n",loglevel);
741 GBool embedded = font->getEmbeddedFontID(&embRef);
743 if(font->getEmbeddedFontName()) {
744 embeddedName = font->getEmbeddedFontName()->getCString();
747 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
749 gstr = font->getExtFontFile();
751 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
753 // Get font descriptor flags.
754 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
755 if(font->isSerif()) msg("%s| is serif\n", loglevel);
756 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
757 if(font->isItalic()) msg("%s| is italic\n", loglevel);
758 if(font->isBold()) msg("%s| is bold\n", loglevel);
764 //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");}
765 //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");}
768 void dump_outline(gfxline_t*line)
771 if(line->type == gfx_moveTo) {
772 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
773 } else if(line->type == gfx_lineTo) {
774 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
775 } else if(line->type == gfx_splineTo) {
776 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
782 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey)
784 int num = path->getNumSubpaths();
787 double lastx=0,lasty=0,posx=0,posy=0;
790 msg("<warning> empty path");
794 gfxdrawer_target_gfxline(&draw);
796 for(t = 0; t < num; t++) {
797 GfxSubpath *subpath = path->getSubpath(t);
798 int subnum = subpath->getNumPoints();
799 double bx=0,by=0,cx=0,cy=0;
801 for(s=0;s<subnum;s++) {
804 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
809 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
810 draw.lineTo(&draw, lastx, lasty);
812 draw.moveTo(&draw, x,y);
817 } else if(subpath->getCurve(s) && cpos==0) {
821 } else if(subpath->getCurve(s) && cpos==1) {
829 draw.lineTo(&draw, x,y);
831 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y, 0.05);
838 /* fix non-closed lines */
839 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
840 draw.lineTo(&draw, lastx, lasty);
842 gfxline_t*result = (gfxline_t*)draw.result(&draw);
846 /*----------------------------------------------------------------------------
847 * Primitive Graphic routines
848 *----------------------------------------------------------------------------*/
850 void SWFOutputDev::stroke(GfxState *state)
852 GfxPath * path = state->getPath();
853 gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex, user_movey);
854 strokeGfxline(state, line);
858 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
860 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
861 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
862 double miterLimit = state->getMiterLimit();
863 double width = state->getTransformedLineWidth();
866 double opaq = state->getStrokeOpacity();
868 state->getFillRGB(&rgb);
870 state->getStrokeRGB(&rgb);
872 col.r = colToByte(rgb.r);
873 col.g = colToByte(rgb.g);
874 col.b = colToByte(rgb.b);
875 col.a = (unsigned char)(opaq*255);
877 gfx_capType capType = gfx_capRound;
878 if(lineCap == 0) capType = gfx_capButt;
879 else if(lineCap == 1) capType = gfx_capRound;
880 else if(lineCap == 2) capType = gfx_capSquare;
882 gfx_joinType joinType = gfx_joinRound;
883 if(lineJoin == 0) joinType = gfx_joinMiter;
884 else if(lineJoin == 1) joinType = gfx_joinRound;
885 else if(lineJoin == 2) joinType = gfx_joinBevel;
888 double dashphase = 0;
890 state->getLineDash(&ldash, &dashnum, &dashphase);
894 if(dashnum && ldash) {
895 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
899 msg("<trace> %d dashes", dashnum);
900 msg("<trace> | phase: %f", dashphase);
901 for(t=0;t<dashnum;t++) {
903 msg("<trace> | d%-3d: %f", t, ldash[t]);
906 if(getLogLevel() >= LOGLEVEL_TRACE) {
910 line2 = gfxtool_dash_line(line, dash, dashphase);
913 msg("<trace> After dashing:");
916 if(getLogLevel() >= LOGLEVEL_TRACE) {
917 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x\n",
919 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
920 lineCap==0?"butt": (lineJoin==1?"round":"square"),
922 col.r,col.g,col.b,col.a
927 //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
928 output->stroke(output, line, width, &col, capType, joinType, miterLimit);
938 gfxcolor_t getFillColor(GfxState * state)
941 double opaq = state->getFillOpacity();
942 state->getFillRGB(&rgb);
944 col.r = colToByte(rgb.r);
945 col.g = colToByte(rgb.g);
946 col.b = colToByte(rgb.b);
947 col.a = (unsigned char)(opaq*255);
951 void SWFOutputDev::fillGfxLine(GfxState *state, gfxline_t*line)
953 gfxcolor_t col = getFillColor(state);
955 if(getLogLevel() >= LOGLEVEL_TRACE) {
956 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
959 output->fill(output, line, &col);
961 void SWFOutputDev::fill(GfxState *state)
963 GfxPath * path = state->getPath();
964 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
965 fillGfxLine(state, line);
968 void SWFOutputDev::eoFill(GfxState *state)
970 GfxPath * path = state->getPath();
971 gfxcolor_t col = getFillColor(state);
973 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
975 if(getLogLevel() >= LOGLEVEL_TRACE) {
976 msg("<trace> eofill\n");
980 output->fill(output, line, &col);
984 void SWFOutputDev::clip(GfxState *state)
986 GfxPath * path = state->getPath();
987 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
988 clipToGfxLine(state, line);
992 void SWFOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line)
994 if(getLogLevel() >= LOGLEVEL_TRACE) {
995 msg("<trace> clip\n");
999 output->startclip(output, line);
1000 states[statepos].clipping++;
1002 void SWFOutputDev::eoClip(GfxState *state)
1004 GfxPath * path = state->getPath();
1005 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
1007 if(getLogLevel() >= LOGLEVEL_TRACE) {
1008 msg("<trace> eoclip\n");
1012 output->startclip(output, line);
1013 states[statepos].clipping++;
1017 void SWFOutputDev::endframe()
1019 if(outer_clip_box) {
1020 output->endclip(output);
1024 output->endpage(output);
1027 void SWFOutputDev::finish()
1029 if(outer_clip_box) {
1031 output->endclip(output);
1036 this->result = output->finish(output);
1037 free(output);output=0;
1041 int SWFOutputDev::save(char*filename)
1044 return result->save(result, filename);
1046 void* SWFOutputDev::get(char*name)
1049 return result->get(result, name);
1052 SWFOutputDev::~SWFOutputDev()
1057 this->result->destroy(this->result);
1062 free(this->pages); this->pages = 0;
1065 fontlist_t*l = this->fontlist;
1067 fontlist_t*next = l->next;
1069 gfxfont_free(l->font);
1077 GBool SWFOutputDev::upsideDown()
1081 GBool SWFOutputDev::useDrawChar()
1085 GBool SWFOutputDev::useGradients()
1089 msg("<notice> File contains gradients");
1095 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
1096 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
1098 #define RENDER_FILL 0
1099 #define RENDER_STROKE 1
1100 #define RENDER_FILLSTROKE 2
1101 #define RENDER_INVISIBLE 3
1102 #define RENDER_CLIP 4
1104 static char tmp_printstr[4096];
1105 char* makeStringPrintable(char*str)
1107 int len = strlen(str);
1114 for(t=0;t<len;t++) {
1119 tmp_printstr[t] = c;
1122 tmp_printstr[len++] = '.';
1123 tmp_printstr[len++] = '.';
1124 tmp_printstr[len++] = '.';
1126 tmp_printstr[len] = 0;
1127 return tmp_printstr;
1131 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
1136 /* find out char name from unicode index
1137 TODO: should be precomputed
1139 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1140 if(nameToUnicodeTab[t].u == u) {
1141 uniname = nameToUnicodeTab[t].name;
1149 for(t=0;t<font->num_glyphs;t++) {
1150 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
1151 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1155 /* if we didn't find the character, maybe
1156 we can find the capitalized version */
1157 for(t=0;t<font->num_glyphs;t++) {
1158 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
1159 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1167 for(t=0;t<font->num_glyphs;t++) {
1168 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,uniname)) {
1169 msg("<debug> Char [%d,%s,>%d(%s)<] maps to %d\n", charnr, charname, u, uniname, t);
1173 /* if we didn't find the character, maybe
1174 we can find the capitalized version */
1175 for(t=0;t<font->num_glyphs;t++) {
1176 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,uniname)) {
1177 msg("<debug> Char [%d,%s,>>%d(%s)<<] maps to %d\n", charnr, charname, u, uniname, t);
1183 /* try to use the unicode id */
1184 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
1185 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
1186 return font->unicode2glyph[u];
1189 if(charnr>=0 && charnr<font->num_glyphs) {
1190 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1198 void SWFOutputDev::beginString(GfxState *state, GString *s)
1200 int render = state->getRender();
1201 if(current_text_stroke) {
1202 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
1205 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
1206 double m11,m21,m12,m22;
1207 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
1208 state->getFontTransMat(&m11, &m12, &m21, &m22);
1209 m11 *= state->getHorizScaling();
1210 m21 *= state->getHorizScaling();
1212 this->current_font_matrix.m00 = m11 / 1024.0;
1213 this->current_font_matrix.m01 = m12 / 1024.0;
1214 this->current_font_matrix.m10 = -m21 / 1024.0;
1215 this->current_font_matrix.m11 = -m22 / 1024.0;
1216 this->current_font_matrix.tx = 0;
1217 this->current_font_matrix.ty = 0;
1219 gfxmatrix_t m = this->current_font_matrix;
1221 /*if(render != 3 && render != 0)
1222 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1223 states[statepos].textRender = render;
1226 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1227 double dx, double dy,
1228 double originX, double originY,
1229 CharCode c, int nBytes, Unicode *_u, int uLen)
1231 int render = state->getRender();
1232 // check for invisible text -- this is used by Acrobat Capture
1234 msg("<debug> Ignoring invisible text: char %d at %f,%f", c, x, y);
1238 if(states[statepos].textRender != render)
1239 msg("<error> Internal error: drawChar.render!=beginString.render");
1241 gfxcolor_t col = getFillColor(state);
1243 Gushort *CIDToGIDMap = 0;
1244 GfxFont*font = state->getFont();
1246 if(font->getType() == fontType3) {
1247 /* type 3 chars are passed as graphics */
1248 msg("<debug> type3 char at %f/%f", x, y);
1255 if(font->isCIDFont()) {
1256 GfxCIDFont*cfont = (GfxCIDFont*)font;
1258 if(font->getType() == fontCIDType2)
1259 CIDToGIDMap = cfont->getCIDToGID();
1262 font8 = (Gfx8BitFont*)font;
1263 char**enc=font8->getEncoding();
1267 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);
1270 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);
1276 charid = getGfxCharID(current_gfxfont, c, name, u);
1278 charid = getGfxCharID(current_gfxfont, c, name, -1);
1281 /* multiple unicodes- should usually map to a ligature.
1282 if the ligature doesn't exist, we need to draw
1283 the characters one-by-one. */
1285 msg("<warning> ligature %d missing in font %s\n", c, current_font_id);
1286 for(t=0;t<uLen;t++) {
1287 drawChar(state, x, y, dx, dy, originX, originY, c, nBytes, _u+t, 1);
1293 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1294 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1298 gfxmatrix_t m = this->current_font_matrix;
1299 state->transform(x, y, &m.tx, &m.ty);
1303 if(render == RENDER_FILL) {
1304 output->drawchar(output, current_font_id, charid, &col, &m);
1306 msg("<debug> Drawing glyph %d as shape", charid);
1308 msg("<notice> Some texts will be rendered as shape");
1311 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1312 gfxline_t*tglyph = gfxline_clone(glyph);
1313 gfxline_transform(tglyph, &m);
1314 if((render&3) != RENDER_INVISIBLE) {
1315 gfxline_t*add = gfxline_clone(tglyph);
1316 current_text_stroke = gfxline_append(current_text_stroke, add);
1318 if(render&RENDER_CLIP) {
1319 gfxline_t*add = gfxline_clone(tglyph);
1320 current_text_clip = gfxline_append(current_text_clip, add);
1322 gfxline_free(tglyph);
1326 void SWFOutputDev::endString(GfxState *state)
1328 int render = state->getRender();
1329 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1330 if(states[statepos].textRender != render)
1331 msg("<error> Internal error: drawChar.render!=beginString.render");
1333 if(current_text_stroke) {
1334 /* fillstroke and stroke text rendering objects we can process right
1335 now (as there may be texts of other rendering modes in this
1336 text object)- clipping objects have to wait until endTextObject,
1338 if((render&3) == RENDER_FILL) {
1339 fillGfxLine(state, current_text_stroke);
1340 gfxline_free(current_text_stroke);
1341 current_text_stroke = 0;
1342 } else if((render&3) == RENDER_FILLSTROKE) {
1343 fillGfxLine(state, current_text_stroke);
1344 strokeGfxline(state, current_text_stroke);
1345 gfxline_free(current_text_stroke);
1346 current_text_stroke = 0;
1347 } else if((render&3) == RENDER_STROKE) {
1348 strokeGfxline(state, current_text_stroke);
1349 gfxline_free(current_text_stroke);
1350 current_text_stroke = 0;
1355 void SWFOutputDev::endTextObject(GfxState *state)
1357 int render = state->getRender();
1358 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1359 if(states[statepos].textRender != render)
1360 msg("<error> Internal error: drawChar.render!=beginString.render");
1362 if(current_text_clip) {
1363 clipToGfxLine(state, current_text_clip);
1364 gfxline_free(current_text_clip);
1365 current_text_clip = 0;
1369 /* the logic seems to be as following:
1370 first, beginType3Char is called, with the charcode and the coordinates.
1371 if this function returns true, it already knew about the char and has now drawn it.
1372 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1373 the all draw operations until endType3Char are part of the char (which in this moment is
1374 at the position first passed to beginType3Char). the char ends with endType3Char.
1376 The drawing operations between beginType3Char and endType3Char are somewhat different to
1377 the normal ones. For example, the fillcolor equals the stroke color.
1380 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1382 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1384 /* the character itself is going to be passed using the draw functions */
1385 return gFalse; /* gTrue= is_in_cache? */
1388 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1389 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1391 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1392 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1396 void SWFOutputDev::endType3Char(GfxState *state)
1399 msg("<debug> endType3Char");
1402 void SWFOutputDev::startFrame(int width, int height)
1404 output->startpage(output, width, height);
1407 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1409 this->currentpage = pageNum;
1411 int rot = doc->getPageRotate(1);
1414 gfxline_t clippath[5];
1416 white.r = white.g = white.b = white.a = 255;
1418 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1419 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1420 Use CropBox, not MediaBox, as page size
1427 state->transform(crop_x1,crop_y1,&x1,&y1); //x1 += user_movex; y1 += user_movey;
1428 state->transform(crop_x2,crop_y2,&x2,&y2); //x2 += user_movex; y2 += user_movey;
1430 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1431 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1434 /* apply user clip box */
1435 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1436 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1437 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1438 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1439 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1442 //msg("<verbose> Bounding box is (%f,%f)-(%f,%f) [shifted by %d/%d]", x1,y1,x2,y2, user_movex, user_movey);
1444 if(outer_clip_box) {
1445 output->endclip(output);
1449 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);
1451 msg("<verbose> page is rotated %d degrees\n", rot);
1453 clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1454 clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1455 clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1456 clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1457 clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1458 output->startclip(output, clippath); outer_clip_box = 1;
1459 output->fill(output, clippath, &white);
1462 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1464 msg("<debug> drawlink\n");
1465 double x1, y1, x2, y2, w;
1466 gfxline_t points[5];
1469 link->getRect(&x1, &y1, &x2, &y2);
1470 cvtUserToDev(x1, y1, &x, &y);
1471 points[0].type = gfx_moveTo;
1472 points[0].x = points[4].x = x + user_movex;
1473 points[0].y = points[4].y = y + user_movey;
1474 points[0].next = &points[1];
1475 cvtUserToDev(x2, y1, &x, &y);
1476 points[1].type = gfx_lineTo;
1477 points[1].x = x + user_movex;
1478 points[1].y = y + user_movey;
1479 points[1].next = &points[2];
1480 cvtUserToDev(x2, y2, &x, &y);
1481 points[2].type = gfx_lineTo;
1482 points[2].x = x + user_movex;
1483 points[2].y = y + user_movey;
1484 points[2].next = &points[3];
1485 cvtUserToDev(x1, y2, &x, &y);
1486 points[3].type = gfx_lineTo;
1487 points[3].x = x + user_movex;
1488 points[3].y = y + user_movey;
1489 points[3].next = &points[4];
1490 cvtUserToDev(x1, y1, &x, &y);
1491 points[4].type = gfx_lineTo;
1492 points[4].x = x + user_movex;
1493 points[4].y = y + user_movey;
1496 LinkAction*action=link->getAction();
1503 switch(action->getKind())
1507 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1508 LinkDest *dest=NULL;
1509 if (ha->getDest()==NULL)
1510 dest=catalog->findDest(ha->getNamedDest());
1511 else dest=ha->getDest();
1513 if (dest->isPageRef()){
1514 Ref pageref=dest->getPageRef();
1515 page=catalog->findPage(pageref.num,pageref.gen);
1517 else page=dest->getPageNum();
1518 sprintf(buf, "%d", page);
1525 LinkGoToR*l = (LinkGoToR*)action;
1526 GString*g = l->getNamedDest();
1528 s = strdup(g->getCString());
1533 LinkNamed*l = (LinkNamed*)action;
1534 GString*name = l->getName();
1536 s = strdup(name->lowerCase()->getCString());
1537 named = name->getCString();
1540 if(strstr(s, "next") || strstr(s, "forward"))
1542 page = currentpage + 1;
1544 else if(strstr(s, "prev") || strstr(s, "back"))
1546 page = currentpage - 1;
1548 else if(strstr(s, "last") || strstr(s, "end"))
1550 if(pages && pagepos>0)
1551 page = pages[pagepos-1];
1553 else if(strstr(s, "first") || strstr(s, "top"))
1561 case actionLaunch: {
1563 LinkLaunch*l = (LinkLaunch*)action;
1564 GString * str = new GString(l->getFileName());
1565 str->append(l->getParams());
1566 s = strdup(str->getCString());
1572 LinkURI*l = (LinkURI*)action;
1573 GString*g = l->getURI();
1575 url = g->getCString();
1580 case actionUnknown: {
1582 LinkUnknown*l = (LinkUnknown*)action;
1587 msg("<error> Unknown link type!\n");
1591 if(!s) s = strdup("-?-");
1593 if(!linkinfo && (page || url))
1595 msg("<notice> File contains links");
1603 for(t=1;t<=pagepos;t++) {
1604 if(pages[t]==page) {
1613 sprintf(buf, "page%d", lpage);
1614 output->drawlink(output, points, buf);
1618 output->drawlink(output, points, url);
1621 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1625 void SWFOutputDev::saveState(GfxState *state) {
1626 msg("<trace> saveState\n");
1629 msg("<error> Too many nested states in pdf.");
1633 states[statepos].clipping = 0; //? shouldn't this be the current value?
1634 states[statepos].textRender = states[statepos-1].textRender;
1637 void SWFOutputDev::restoreState(GfxState *state) {
1638 msg("<trace> restoreState\n");
1640 while(states[statepos].clipping) {
1641 output->endclip(output);
1642 states[statepos].clipping--;
1647 char* SWFOutputDev::searchFont(char*name)
1651 int is_standard_font = 0;
1653 msg("<verbose> SearchFont(%s)", name);
1655 /* see if it is a pdf standard font */
1656 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1658 if(!strcmp(name, pdf2t1map[i].pdffont))
1660 name = pdf2t1map[i].filename;
1661 is_standard_font = 1;
1665 /* look in all font files */
1666 for(i=0;i<fontnum;i++)
1668 if(strstr(fonts[i].filename, name))
1670 if(!fonts[i].used) {
1673 if(!is_standard_font)
1674 msg("<notice> Using %s for %s", fonts[i].filename, name);
1676 return strdup(fonts[i].filename);
1682 void SWFOutputDev::updateLineWidth(GfxState *state)
1684 double width = state->getTransformedLineWidth();
1685 //swfoutput_setlinewidth(&output, width);
1688 void SWFOutputDev::updateLineCap(GfxState *state)
1690 int c = state->getLineCap();
1693 void SWFOutputDev::updateLineJoin(GfxState *state)
1695 int j = state->getLineJoin();
1698 void SWFOutputDev::updateFillColor(GfxState *state)
1701 double opaq = state->getFillOpacity();
1702 state->getFillRGB(&rgb);
1704 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1707 void SWFOutputDev::updateStrokeColor(GfxState *state)
1710 double opaq = state->getStrokeOpacity();
1711 state->getStrokeRGB(&rgb);
1712 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1715 void FoFiWrite(void *stream, char *data, int len)
1717 fwrite(data, len, 1, (FILE*)stream);
1720 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1722 char*tmpFileName = NULL;
1728 Object refObj, strObj;
1730 tmpFileName = mktmpname(namebuf);
1733 ret = font->getEmbeddedFontID(&embRef);
1735 msg("<verbose> Didn't get embedded font id");
1736 /* not embedded- the caller should now search the font
1737 directories for this font */
1741 f = fopen(tmpFileName, "wb");
1743 msg("<error> Couldn't create temporary Type 1 font file");
1747 /*if(font->isCIDFont()) {
1748 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1749 GString c = cidFont->getCollection();
1750 msg("<notice> Collection: %s", c.getCString());
1753 //if (font->getType() == fontType1C) {
1754 if (0) { //font->getType() == fontType1C) {
1755 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1757 msg("<error> Couldn't read embedded font file");
1760 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1762 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1763 //cvt->convertToCIDType0("test", f);
1764 //cvt->convertToType0("test", f);
1767 } else if(font->getType() == fontTrueType) {
1768 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1769 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1771 msg("<error> Couldn't read embedded font file");
1774 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1775 cvt->writeTTF(FoFiWrite, f);
1779 font->getEmbeddedFontID(&embRef);
1780 refObj.initRef(embRef.num, embRef.gen);
1781 refObj.fetch(ref, &strObj);
1783 strObj.streamReset();
1788 f4[t] = strObj.streamGetChar();
1789 f4c[t] = (char)f4[t];
1794 if(!strncmp(f4c, "true", 4)) {
1795 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1796 Change this on the fly */
1797 f4[0] = f4[2] = f4[3] = 0;
1805 while ((c = strObj.streamGetChar()) != EOF) {
1809 strObj.streamClose();
1814 return strdup(tmpFileName);
1817 char* searchForSuitableFont(GfxFont*gfxFont)
1819 char*name = getFontName(gfxFont);
1823 if(!config_use_fontconfig)
1826 #ifdef HAVE_FONTCONFIG
1827 FcPattern *pattern, *match;
1831 static int fcinitcalled = false;
1833 msg("<debug> searchForSuitableFont(%s)", name);
1835 // call init ony once
1836 if (!fcinitcalled) {
1837 msg("<debug> Initializing FontConfig...");
1838 fcinitcalled = true;
1840 msg("<debug> FontConfig Initialization failed. Disabling.");
1841 config_use_fontconfig = 0;
1844 msg("<debug> ...initialized FontConfig");
1847 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1848 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1849 if (gfxFont->isItalic()) // check for italic
1850 msg("<debug> FontConfig: Adding Italic Slant");
1851 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1852 if (gfxFont->isBold()) // check for bold
1853 msg("<debug> FontConfig: Adding Bold Weight");
1854 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1856 msg("<debug> FontConfig: Try to match...");
1857 // configure and match using the original font name
1858 FcConfigSubstitute(0, pattern, FcMatchPattern);
1859 FcDefaultSubstitute(pattern);
1860 match = FcFontMatch(0, pattern, &result);
1862 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1863 msg("<debug> FontConfig: family=%s", (char*)v);
1864 // if we get an exact match
1865 if (strcmp((char *)v, name) == 0) {
1866 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1867 filename = strdup((char*)v); // mem leak
1868 char *nfn = strrchr(filename, '/');
1869 if(nfn) fontname = strdup(nfn+1);
1870 else fontname = filename;
1872 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1874 // initialize patterns
1875 FcPatternDestroy(pattern);
1876 FcPatternDestroy(match);
1878 // now match against serif etc.
1879 if (gfxFont->isSerif()) {
1880 msg("<debug> FontConfig: Create Serif Family Pattern");
1881 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1882 } else if (gfxFont->isFixedWidth()) {
1883 msg("<debug> FontConfig: Create Monospace Family Pattern");
1884 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1886 msg("<debug> FontConfig: Create Sans Family Pattern");
1887 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1891 if (gfxFont->isItalic()) {
1892 msg("<debug> FontConfig: Adding Italic Slant");
1893 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1896 if (gfxFont->isBold()) {
1897 msg("<debug> FontConfig: Adding Bold Weight");
1898 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1901 msg("<debug> FontConfig: Try to match... (2)");
1902 // configure and match using serif etc
1903 FcConfigSubstitute (0, pattern, FcMatchPattern);
1904 FcDefaultSubstitute (pattern);
1905 match = FcFontMatch (0, pattern, &result);
1907 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1908 filename = strdup((char*)v); // mem leak
1909 char *nfn = strrchr(filename, '/');
1910 if(nfn) fontname = strdup(nfn+1);
1911 else fontname = filename;
1913 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1917 //printf("FONTCONFIG: pattern");
1918 //FcPatternPrint(pattern);
1919 //printf("FONTCONFIG: match");
1920 //FcPatternPrint(match);
1922 FcPatternDestroy(pattern);
1923 FcPatternDestroy(match);
1925 pdfswf_addfont(filename);
1932 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1934 char*fontname = 0, *filename = 0;
1935 msg("<notice> substituteFont(%s)", oldname);
1937 if(!(fontname = searchForSuitableFont(gfxFont))) {
1938 fontname = "Times-Roman";
1940 filename = searchFont(fontname);
1942 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1946 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1947 msg("<fatal> Too many fonts in file.");
1951 substitutesource[substitutepos] = strdup(oldname); //mem leak
1952 substitutetarget[substitutepos] = fontname;
1953 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1956 return strdup(filename); //mem leak
1959 void unlinkfont(char* filename)
1966 if(!strncmp(&filename[l-4],".afm",4)) {
1967 memcpy(&filename[l-4],".pfb",4);
1969 memcpy(&filename[l-4],".pfa",4);
1971 memcpy(&filename[l-4],".afm",4);
1974 if(!strncmp(&filename[l-4],".pfa",4)) {
1975 memcpy(&filename[l-4],".afm",4);
1977 memcpy(&filename[l-4],".pfa",4);
1980 if(!strncmp(&filename[l-4],".pfb",4)) {
1981 memcpy(&filename[l-4],".afm",4);
1983 memcpy(&filename[l-4],".pfb",4);
1988 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1994 int SWFOutputDev::setGfxFont(char*id, char*name, char*filename, double maxSize)
1997 fontlist_t*last=0,*l = this->fontlist;
1999 /* TODO: should this be part of the state? */
2002 if(!strcmp(l->id, id)) {
2003 current_font_id = l->id;
2004 current_gfxfont = l->font;
2006 output->addfont(output, id, current_gfxfont);
2011 if(!filename) return 0;
2013 /* A font size of e.g. 9 means the font will be scaled down by
2014 1024 and scaled up by 9. So to have a maximum error of 1/20px,
2015 we have to divide 0.05 by (fontsize/1024)
2017 double quality = (1024 * 0.05) / maxSize;
2019 msg("<verbose> Loading %s...", filename);
2020 font = gfxfont_load(filename, quality);
2021 msg("<verbose> Font %s loaded successfully", filename);
2025 l->filename = strdup(filename);
2028 current_font_id = l->id;
2029 current_gfxfont = l->font;
2035 output->addfont(output, id, current_gfxfont);
2039 void SWFOutputDev::updateFont(GfxState *state)
2041 GfxFont*gfxFont = state->getFont();
2047 char * fontid = getFontID(gfxFont);
2048 char * fontname = getFontName(gfxFont);
2050 double maxSize = 1.0;
2053 maxSize = this->info->getMaximumFontSize(fontid);
2057 /* first, look if we substituted this font before-
2058 this way, we don't initialize the T1 Fonts
2060 for(t=0;t<substitutepos;t++) {
2061 if(!strcmp(fontid, substitutesource[t])) {
2062 free(fontid);fontid=0;
2063 fontid = strdup(substitutetarget[t]);
2068 /* second, see if this is a font which was used before-
2069 if so, we are done */
2070 if(setGfxFont(fontid, fontname, 0, 0)) {
2075 /* if(swfoutput_queryfont(&output, fontid))
2076 swfoutput_setfont(&output, fontid, 0);
2078 msg("<debug> updateFont(%s) [cached]", fontid);
2082 // look for Type 3 font
2083 if (gfxFont->getType() == fontType3) {
2085 type3Warning = gTrue;
2086 showFontError(gfxFont, 2);
2093 /* now either load the font, or find a substitution */
2096 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
2101 (gfxFont->getType() == fontType1 ||
2102 gfxFont->getType() == fontType1C ||
2103 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
2104 gfxFont->getType() == fontTrueType ||
2105 gfxFont->getType() == fontCIDType2
2108 fileName = writeEmbeddedFontToFile(xref, gfxFont);
2109 if(!fileName) showFontError(gfxFont,0);
2112 fileName = searchFont(fontname);
2113 if(!fileName) showFontError(gfxFont,0);
2116 char * fontname = getFontName(gfxFont);
2117 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
2120 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into %s", fontname, lastfontdir);
2122 msg("<warning> Try specifying one or more font directories");
2124 fileName = substituteFont(gfxFont, fontid);
2125 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
2126 msg("<notice> Font is now %s (%s)", fontid, fileName);
2130 msg("<error> Couldn't set font %s\n", fontid);
2136 msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
2137 dumpFontInfo("<verbose>", gfxFont);
2139 //swfoutput_setfont(&output, fontid, fileName);
2141 if(!setGfxFont(fontid, fontname, 0, 0)) {
2142 setGfxFont(fontid, fontname, fileName, maxSize);
2146 unlinkfont(fileName);
2156 #define SQR(x) ((x)*(x))
2158 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
2160 if((newwidth<2 || newheight<2) ||
2161 (width<=newwidth || height<=newheight))
2163 unsigned char*newdata;
2165 newdata= (unsigned char*)malloc(newwidth*newheight);
2167 double fx = (double)(width)/newwidth;
2168 double fy = (double)(height)/newheight;
2170 int blocksize = (int)(8192/(fx*fy));
2171 int r = 8192*256/palettesize;
2172 for(x=0;x<newwidth;x++) {
2173 double ex = px + fx;
2174 int fromx = (int)px;
2176 int xweight1 = (int)(((fromx+1)-px)*256);
2177 int xweight2 = (int)((ex-tox)*256);
2179 for(y=0;y<newheight;y++) {
2180 double ey = py + fy;
2181 int fromy = (int)py;
2183 int yweight1 = (int)(((fromy+1)-py)*256);
2184 int yweight2 = (int)((ey-toy)*256);
2187 for(xx=fromx;xx<=tox;xx++)
2188 for(yy=fromy;yy<=toy;yy++) {
2189 int b = 1-data[width*yy+xx];
2191 if(xx==fromx) weight = (weight*xweight1)/256;
2192 if(xx==tox) weight = (weight*xweight2)/256;
2193 if(yy==fromy) weight = (weight*yweight1)/256;
2194 if(yy==toy) weight = (weight*yweight2)/256;
2197 //if(a) a=(palettesize-1)*r/blocksize;
2198 newdata[y*newwidth+x] = (a*blocksize)/r;
2206 #define IMAGE_TYPE_JPEG 0
2207 #define IMAGE_TYPE_LOSSLESS 1
2209 static void drawimage(gfxdevice_t*dev, gfxcolor_t* data, int sizex,int sizey,
2210 double x1,double y1,
2211 double x2,double y2,
2212 double x3,double y3,
2213 double x4,double y4, int type)
2215 gfxcolor_t*newpic=0;
2217 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2218 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2220 gfxline_t p1,p2,p3,p4,p5;
2221 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2222 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2223 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2224 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2225 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2227 {p1.x = (int)(p1.x*20)/20.0;
2228 p1.y = (int)(p1.y*20)/20.0;
2229 p2.x = (int)(p2.x*20)/20.0;
2230 p2.y = (int)(p2.y*20)/20.0;
2231 p3.x = (int)(p3.x*20)/20.0;
2232 p3.y = (int)(p3.y*20)/20.0;
2233 p4.x = (int)(p4.x*20)/20.0;
2234 p4.y = (int)(p4.y*20)/20.0;
2235 p5.x = (int)(p5.x*20)/20.0;
2236 p5.y = (int)(p5.y*20)/20.0;
2243 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2244 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2249 img.data = (gfxcolor_t*)data;
2253 if(type == IMAGE_TYPE_JPEG)
2254 /* TODO: pass image_dpi to device instead */
2255 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2257 dev->fillbitmap(dev, &p1, &img, &m, 0);
2260 void drawimagejpeg(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2261 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2263 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2266 void drawimagelossless(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2267 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2269 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2273 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2274 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2275 GBool inlineImg, int mask, int*maskColors,
2276 Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GfxImageColorMap*maskColorMap)
2278 double x1,y1,x2,y2,x3,y3,x4,y4;
2279 ImageStream *imgStr;
2284 unsigned char* maskbitmap = 0;
2287 ncomps = colorMap->getNumPixelComps();
2288 bits = colorMap->getBits();
2293 unsigned char buf[8];
2294 maskbitmap = (unsigned char*)malloc(maskHeight*maskWidth);
2296 ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, maskColorMap->getNumPixelComps(), maskColorMap->getBits());
2297 imgMaskStr->reset();
2298 unsigned char pal[256];
2299 int n = 1 << colorMap->getBits();
2304 maskColorMap->getGray(pixBuf, &gray);
2305 pal[t] = colToByte(gray);
2307 for (y = 0; y < maskHeight; y++) {
2308 for (x = 0; x < maskWidth; x++) {
2309 imgMaskStr->getPixel(buf);
2310 maskbitmap[y*maskWidth+x] = pal[buf[0]];
2315 ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, 1, 1);
2316 imgMaskStr->reset();
2317 for (y = 0; y < maskHeight; y++) {
2318 for (x = 0; x < maskWidth; x++) {
2319 imgMaskStr->getPixel(buf);
2321 maskbitmap[y*maskWidth+x] = (buf[0]^1)*255;
2328 imgStr = new ImageStream(str, width, ncomps,bits);
2331 if(!width || !height || (height<=1 && width<=1))
2333 msg("<verbose> Ignoring %d by %d image", width, height);
2334 unsigned char buf[8];
2336 for (y = 0; y < height; ++y)
2337 for (x = 0; x < width; ++x) {
2338 imgStr->getPixel(buf);
2346 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1 += user_movey;
2347 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2 += user_movey;
2348 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3 += user_movey;
2349 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4 += user_movey;
2351 if(!pbminfo && !(str->getKind()==strDCT)) {
2353 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2357 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2359 if(!jpeginfo && (str->getKind()==strDCT)) {
2360 msg("<notice> file contains jpeg pictures");
2366 unsigned char buf[8];
2368 unsigned char*pic = new unsigned char[width*height];
2369 gfxcolor_t pal[256];
2371 state->getFillRGB(&rgb);
2373 memset(pal,255,sizeof(pal));
2374 pal[0].r = (int)(colToByte(rgb.r)); pal[1].r = 0;
2375 pal[0].g = (int)(colToByte(rgb.g)); pal[1].g = 0;
2376 pal[0].b = (int)(colToByte(rgb.b)); pal[1].b = 0;
2377 pal[0].a = 255; pal[1].a = 0;
2380 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2381 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2382 for (y = 0; y < height; ++y)
2383 for (x = 0; x < width; ++x)
2385 imgStr->getPixel(buf);
2388 pic[width*y+x] = buf[0];
2391 /* the size of the drawn image is added to the identifier
2392 as the same image may require different bitmaps if displayed
2393 at different sizes (due to antialiasing): */
2396 unsigned char*pic2 = 0;
2399 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2408 height = realheight;
2412 /* make a black/white palette */
2414 float r = 255/(numpalette-1);
2416 for(t=0;t<numpalette;t++) {
2417 pal[t].r = colToByte(rgb.r);
2418 pal[t].g = colToByte(rgb.g);
2419 pal[t].b = colToByte(rgb.b);
2420 pal[t].a = (unsigned char)(t*r);
2424 gfxcolor_t*pic2 = new gfxcolor_t[width*height];
2425 for (y = 0; y < height; ++y) {
2426 for (x = 0; x < width; ++x) {
2427 pic2[width*y+x] = pal[pic[y*width+x]];
2430 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2434 if(maskbitmap) free(maskbitmap);
2440 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2441 gfxcolor_t*pic=new gfxcolor_t[width*height];
2442 for (y = 0; y < height; ++y) {
2443 for (x = 0; x < width; ++x) {
2444 imgStr->getPixel(pixBuf);
2445 colorMap->getRGB(pixBuf, &rgb);
2446 pic[width*y+x].r = (unsigned char)(colToByte(rgb.r));
2447 pic[width*y+x].g = (unsigned char)(colToByte(rgb.g));
2448 pic[width*y+x].b = (unsigned char)(colToByte(rgb.b));
2449 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2451 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2455 if(str->getKind()==strDCT)
2456 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2458 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2461 if(maskbitmap) free(maskbitmap);
2464 gfxcolor_t*pic=new gfxcolor_t[width*height];
2465 gfxcolor_t pal[256];
2466 int n = 1 << colorMap->getBits();
2468 for(t=0;t<256;t++) {
2470 colorMap->getRGB(pixBuf, &rgb);
2472 {/*if(maskColors && *maskColors==t) {
2473 msg("<notice> Color %d is transparent", t);
2474 if (imgData->maskColors) {
2476 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2477 if (pix[i] < imgData->maskColors[2*i] ||
2478 pix[i] > imgData->maskColors[2*i+1]) {
2493 pal[t].r = (unsigned char)(colToByte(rgb.r));
2494 pal[t].g = (unsigned char)(colToByte(rgb.g));
2495 pal[t].b = (unsigned char)(colToByte(rgb.b));
2496 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2499 for (y = 0; y < height; ++y) {
2500 for (x = 0; x < width; ++x) {
2501 imgStr->getPixel(pixBuf);
2502 pic[width*y+x] = pal[pixBuf[0]];
2504 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2508 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2512 if(maskbitmap) free(maskbitmap);
2517 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2518 int width, int height, GBool invert,
2521 if(states[statepos].textRender & 4) //clipped
2523 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2524 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0, 0,0,0,0, 0);
2527 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2528 int width, int height, GfxImageColorMap *colorMap,
2529 int *maskColors, GBool inlineImg)
2531 if(states[statepos].textRender & 4) //clipped
2534 msg("<verbose> drawImage %dx%d, %s, %s, inline=%d", width, height,
2535 colorMap?"colorMap":"no colorMap",
2536 maskColors?"maskColors":"no maskColors",
2539 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2540 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2541 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors, 0,0,0,0, 0);
2544 void SWFOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
2545 int width, int height,
2546 GfxImageColorMap *colorMap,
2547 Stream *maskStr, int maskWidth, int maskHeight,
2550 if(states[statepos].textRender & 4) //clipped
2553 msg("<verbose> drawMaskedImage %dx%d, %s, %dx%d mask", width, height,
2554 colorMap?"colorMap":"no colorMap",
2555 maskWidth, maskHeight);
2557 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2558 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2559 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, maskInvert, 0);
2562 void SWFOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
2563 int width, int height,
2564 GfxImageColorMap *colorMap,
2566 int maskWidth, int maskHeight,
2567 GfxImageColorMap *maskColorMap)
2569 if(states[statepos].textRender & 4) //clipped
2572 msg("<verbose> drawSoftMaskedImage %dx%d, %s, %dx%d mask", width, height,
2573 colorMap?"colorMap":"no colorMap",
2574 maskWidth, maskHeight);
2576 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2577 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2578 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, 0, maskColorMap);
2581 //SWFOutputDev*output = 0;
2583 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2588 if (infoDict->lookup(key, &obj)->isString()) {
2589 s1 = obj.getString();
2590 if ((s1->getChar(0) & 0xff) == 0xfe &&
2591 (s1->getChar(1) & 0xff) == 0xff) {
2593 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2594 if (s1->getChar(i) == '\0') {
2595 s2->append(s1->getChar(i+1));
2598 s2 = new GString("<unicode>");
2602 printf(fmt, s2->getCString());
2605 printf(fmt, s1->getCString());
2611 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2615 if (infoDict->lookup(key, &obj)->isString()) {
2616 s = obj.getString()->getCString();
2617 if (s[0] == 'D' && s[1] == ':') {
2628 void storeDeviceParameter(char*name, char*value)
2630 parameter_t*p = new parameter_t();
2631 p->name = strdup(name);
2632 p->value = strdup(value);
2634 if(device_config_next) {
2635 device_config_next->next = p;
2636 device_config_next = p;
2639 device_config_next = p;
2643 void pdfswf_setparameter(char*name, char*value)
2645 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2646 if(!strcmp(name, "caplinewidth")) {
2647 caplinewidth = atof(value);
2648 } else if(!strcmp(name, "zoom")) {
2651 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2652 storeDeviceParameter("jpegsubpixels", buf);
2653 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2654 storeDeviceParameter("ppmsubpixels", buf);
2655 } else if(!strcmp(name, "jpegdpi")) {
2657 jpeg_dpi = atoi(value);
2658 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2659 storeDeviceParameter("jpegsubpixels", buf);
2660 } else if(!strcmp(name, "ppmdpi")) {
2662 ppm_dpi = atoi(value);
2663 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2664 storeDeviceParameter("ppmsubpixels", buf);
2665 } else if(!strcmp(name, "forceType0Fonts")) {
2666 forceType0Fonts = atoi(value);
2667 } else if(!strncmp(name, "fontdir", strlen("fontdir"))) {
2668 pdfswf_addfontdir(value);
2669 } else if(!strncmp(name, "languagedir", strlen("languagedir"))) {
2670 pdfswf_addlanguagedir(value);
2671 } else if(!strcmp(name, "fontconfig")) {
2672 config_use_fontconfig = atoi(value);
2674 storeDeviceParameter(name,value);
2677 void pdfswf_addfont(char*filename)
2680 memset(&f, 0, sizeof(fontfile_t));
2681 f.filename = filename;
2682 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2683 fonts[fontnum++] = f;
2685 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2689 static char* dirseparator()
2698 void pdfswf_addlanguagedir(char*dir)
2701 globalParams = new GlobalParams("");
2703 msg("<notice> Adding %s to language pack directories", dir);
2707 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc") + 1);
2708 strcpy(config_file, dir);
2709 strcat(config_file, dirseparator());
2710 strcat(config_file, "add-to-xpdfrc");
2712 fi = fopen(config_file, "rb");
2714 msg("<error> Could not open %s", config_file);
2717 globalParams->parseFile(new GString(config_file), fi);
2721 void pdfswf_addfontdir(char*dirname)
2723 #ifdef HAVE_DIRENT_H
2724 msg("<notice> Adding %s to font directories", dirname);
2725 lastfontdir = strdup(dirname);
2726 DIR*dir = opendir(dirname);
2728 msg("<warning> Couldn't open directory %s\n", dirname);
2733 ent = readdir (dir);
2737 char*name = ent->d_name;
2743 if(!strncasecmp(&name[l-4], ".pfa", 4))
2745 if(!strncasecmp(&name[l-4], ".pfb", 4))
2747 if(!strncasecmp(&name[l-4], ".ttf", 4))
2751 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2752 strcpy(fontname, dirname);
2753 strcat(fontname, dirseparator());
2754 strcat(fontname, name);
2755 msg("<verbose> Adding %s to fonts", fontname);
2756 pdfswf_addfont(fontname);
2761 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2766 typedef struct _pdf_doc_internal
2771 } pdf_doc_internal_t;
2772 typedef struct _pdf_page_internal
2774 } pdf_page_internal_t;
2775 typedef struct _swf_output_internal
2777 SWFOutputDev*outputDev;
2778 } swf_output_internal_t;
2780 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2782 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2783 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2784 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2785 memset(i, 0, sizeof(pdf_doc_internal_t));
2786 pdf_doc->internal = i;
2788 GString *fileName = new GString(filename);
2794 globalParams = new GlobalParams("");
2797 if (userPassword && userPassword[0]) {
2798 userPW = new GString(userPassword);
2802 i->doc = new PDFDoc(fileName, userPW);
2806 if (!i->doc->isOk()) {
2811 i->doc->getDocInfo(&info);
2812 if (info.isDict() &&
2813 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2814 printInfoString(info.getDict(), "Title", "Title: %s\n");
2815 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2816 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2817 printInfoString(info.getDict(), "Author", "Author: %s\n");
2818 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2819 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2820 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2821 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2822 printf("Pages: %d\n", i->doc->getNumPages());
2823 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2824 printf("Encrypted: ");
2825 if (i->doc->isEncrypted()) {
2826 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2827 i->doc->okToPrint() ? "yes" : "no",
2828 i->doc->okToCopy() ? "yes" : "no",
2829 i->doc->okToChange() ? "yes" : "no",
2830 i->doc->okToAddNotes() ? "yes" : "no");
2837 pdf_doc->num_pages = i->doc->getNumPages();
2839 if (i->doc->isEncrypted()) {
2840 if(!i->doc->okToCopy()) {
2841 printf("PDF disallows copying.\n");
2844 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2848 InfoOutputDev*io = new InfoOutputDev();
2850 for(t=1;t<=pdf_doc->num_pages;t++) {
2851 i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, /*usemediabox*/true, /*crop*/true, /*doLinks*/(int)1);
2862 delete globalParams;globalParams=0;
2863 Object::memCheck(stderr);
2868 void pdf_destroy(pdf_doc_t*pdf_doc)
2870 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2872 delete i->doc; i->doc=0;
2875 delete i->info;i->info=0;
2878 free(pdf_doc->internal);pdf_doc->internal=0;
2879 free(pdf_doc);pdf_doc=0;
2882 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2884 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2886 if(page < 1 || page > pdf_doc->num_pages)
2889 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2890 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2891 memset(pi, 0, sizeof(pdf_page_internal_t));
2892 pdf_page->internal = pi;
2894 pdf_page->parent = pdf_doc;
2895 pdf_page->nr = page;
2899 void pdf_page_destroy(pdf_page_t*pdf_page)
2901 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2902 free(pdf_page->internal);pdf_page->internal = 0;
2903 free(pdf_page);pdf_page=0;
2906 swf_output_t* swf_output_init()
2908 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2909 memset(swf_output, 0, sizeof(swf_output_t));
2910 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2911 memset(i, 0, sizeof(swf_output_internal_t));
2912 swf_output->internal = i;
2914 i->outputDev = new SWFOutputDev();
2918 void swf_output_setparameter(swf_output_t*swf, char*name, char*value)
2920 pdfswf_setparameter(name, value);
2923 void swf_output_startframe(swf_output_t*swf, int width, int height)
2925 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2926 i->outputDev->startFrame(width, height);
2929 void swf_output_endframe(swf_output_t*swf)
2931 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2932 i->outputDev->endframe();
2935 void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage)
2937 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2938 SWFOutputDev*o = i->outputDev;
2944 o->pagebuflen = 1024;
2945 o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
2946 memset(o->pages, -1, o->pagebuflen*sizeof(int));
2948 while(pdfpage >= o->pagebuflen)
2950 int oldlen = o->pagebuflen;
2951 o->pagebuflen+=1024;
2952 o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
2953 memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
2956 o->pages[pdfpage] = outputpage;
2957 if(pdfpage>o->pagepos)
2958 o->pagepos = pdfpage;
2961 int swf_output_save(swf_output_t*swf, char*filename)
2963 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2964 int ret = i->outputDev->save(filename);
2968 void* swf_output_get(swf_output_t*swf,char*name)
2970 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2971 void* ret = i->outputDev->get(name);
2975 void swf_output_destroy(swf_output_t*output)
2977 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2978 delete i->outputDev; i->outputDev=0;
2979 free(output->internal);output->internal=0;
2983 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2985 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2986 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2989 msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2994 gfxdevice_t*dev = si->outputDev->output;
2995 dev->setparameter(dev, "protect", "1");
2997 si->outputDev->setInfo(pi->info);
2998 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2999 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
3002 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
3004 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
3005 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
3007 si->outputDev->setMove(x,y);
3008 if((x1|y1|x2|y2)==0) x2++;
3009 si->outputDev->setClip(x1,y1,x2,y2);
3011 pdf_page_render2(page, output);
3013 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
3015 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
3016 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
3018 si->outputDev->setMove(0,0);
3019 si->outputDev->setClip(0,0,0,0);
3021 pdf_page_render2(page, output);
3025 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
3027 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
3028 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
3029 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
3030 memset(info, 0, sizeof(pdf_page_info_t));
3032 InfoOutputDev*output = new InfoOutputDev;
3034 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
3036 info->xMin = output->x1;
3037 info->yMin = output->y1;
3038 info->xMax = output->x2;
3039 info->yMax = output->y2;
3040 info->number_of_images = output->num_images;
3041 info->number_of_links = output->num_links;
3042 info->number_of_fonts = output->num_fonts;
3049 void pdf_page_info_destroy(pdf_page_info_t*info)