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*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 GString*gstr = font->getName();
530 char* fontname = gstr==0?0:gstr->getCString();
534 sprintf(buf, "UFONT%d", r->num);
537 return strdup(fontname);
540 static char*getFontName(GfxFont*font)
542 char*fontid = getFontID(font);
544 char* plus = strchr(fontid, '+');
545 if(plus && plus < &fontid[strlen(fontid)-1]) {
546 fontname = strdup(plus+1);
548 fontname = strdup(fontid);
554 static char mybuf[1024];
555 static char* gfxstate2str(GfxState *state)
559 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
566 if(state->getX1()!=0.0)
567 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
568 if(state->getY1()!=0.0)
569 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
570 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
571 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
572 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
573 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
574 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
575 state->getFillColor()->c[0], state->getFillColor()->c[1]);
576 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
577 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
578 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
579 state->getFillColor()->c[0], state->getFillColor()->c[1],
580 state->getFillColor()->c[2], state->getFillColor()->c[3],
581 state->getFillColor()->c[4], state->getFillColor()->c[5],
582 state->getFillColor()->c[6], state->getFillColor()->c[7]);
583 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
584 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
585 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
586 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
587 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
588 state->getFillRGB(&rgb);
589 if(rgb.r || rgb.g || rgb.b)
590 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
591 state->getStrokeRGB(&rgb);
592 if(rgb.r || rgb.g || rgb.b)
593 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
594 if(state->getFillColorSpace()->getNComps()>1)
595 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
596 if(state->getStrokeColorSpace()->getNComps()>1)
597 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
598 if(state->getFillPattern())
599 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
600 if(state->getStrokePattern())
601 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
603 if(state->getFillOpacity()!=1.0)
604 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
605 if(state->getStrokeOpacity()!=1.0)
606 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
608 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
613 state->getLineDash(&dash, &length, &start);
617 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
618 for(t=0;t<length;t++) {
619 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
621 bufpos+=sprintf(bufpos,"]");
624 if(state->getFlatness()!=1)
625 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
626 if(state->getLineJoin()!=0)
627 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
628 if(state->getLineJoin()!=0)
629 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
630 if(state->getLineJoin()!=0)
631 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
633 if(state->getFont() && getFontID(state->getFont()))
634 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
635 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
636 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
637 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
638 if(state->getCharSpace())
639 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
640 if(state->getWordSpace())
641 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
642 if(state->getHorizScaling()!=1.0)
643 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
644 if(state->getLeading())
645 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
647 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
648 if(state->getRender())
649 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
650 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
651 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
652 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
653 if(state->getLineX())
654 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
655 if(state->getLineY())
656 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
657 bufpos+=sprintf(bufpos," ");
661 static void dumpFontInfo(char*loglevel, GfxFont*font);
662 static int lastdumps[1024];
663 static int lastdumppos = 0;
668 static void showFontError(GfxFont*font, int nr)
672 for(t=0;t<lastdumppos;t++)
673 if(lastdumps[t] == r->num)
677 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
678 lastdumps[lastdumppos++] = r->num;
680 msg("<warning> The following font caused problems:");
682 msg("<warning> The following font caused problems (substituting):");
684 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
685 dumpFontInfo("<warning>", font);
688 static void dumpFontInfo(char*loglevel, GfxFont*font)
690 char* id = getFontID(font);
691 char* name = getFontName(font);
692 Ref* r=font->getID();
693 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
695 GString*gstr = font->getTag();
697 msg("%s| Tag: %s\n", loglevel, id);
699 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
701 GfxFontType type=font->getType();
703 case fontUnknownType:
704 msg("%s| Type: unknown\n",loglevel);
707 msg("%s| Type: 1\n",loglevel);
710 msg("%s| Type: 1C\n",loglevel);
713 msg("%s| Type: 3\n",loglevel);
716 msg("%s| Type: TrueType\n",loglevel);
719 msg("%s| Type: CIDType0\n",loglevel);
722 msg("%s| Type: CIDType0C\n",loglevel);
725 msg("%s| Type: CIDType2\n",loglevel);
730 GBool embedded = font->getEmbeddedFontID(&embRef);
732 if(font->getEmbeddedFontName()) {
733 embeddedName = font->getEmbeddedFontName()->getCString();
736 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
738 gstr = font->getExtFontFile();
740 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
742 // Get font descriptor flags.
743 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
744 if(font->isSerif()) msg("%s| is serif\n", loglevel);
745 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
746 if(font->isItalic()) msg("%s| is italic\n", loglevel);
747 if(font->isBold()) msg("%s| is bold\n", loglevel);
753 //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");}
754 //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");}
757 void dump_outline(gfxline_t*line)
760 if(line->type == gfx_moveTo) {
761 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
762 } else if(line->type == gfx_lineTo) {
763 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
764 } else if(line->type == gfx_splineTo) {
765 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
771 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey)
773 int num = path->getNumSubpaths();
776 double lastx=0,lasty=0,posx=0,posy=0;
779 msg("<warning> empty path");
783 gfxdrawer_target_gfxline(&draw);
785 for(t = 0; t < num; t++) {
786 GfxSubpath *subpath = path->getSubpath(t);
787 int subnum = subpath->getNumPoints();
788 double bx=0,by=0,cx=0,cy=0;
790 for(s=0;s<subnum;s++) {
793 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
798 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
799 draw.lineTo(&draw, lastx, lasty);
801 draw.moveTo(&draw, x,y);
806 } else if(subpath->getCurve(s) && cpos==0) {
810 } else if(subpath->getCurve(s) && cpos==1) {
818 draw.lineTo(&draw, x,y);
820 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y, 0.05);
827 /* fix non-closed lines */
828 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
829 draw.lineTo(&draw, lastx, lasty);
831 gfxline_t*result = (gfxline_t*)draw.result(&draw);
835 /*----------------------------------------------------------------------------
836 * Primitive Graphic routines
837 *----------------------------------------------------------------------------*/
839 void SWFOutputDev::stroke(GfxState *state)
841 GfxPath * path = state->getPath();
842 gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex, user_movey);
843 strokeGfxline(state, line);
847 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
849 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
850 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
851 double miterLimit = state->getMiterLimit();
852 double width = state->getTransformedLineWidth();
855 double opaq = state->getStrokeOpacity();
857 state->getFillRGB(&rgb);
859 state->getStrokeRGB(&rgb);
861 col.r = colToByte(rgb.r);
862 col.g = colToByte(rgb.g);
863 col.b = colToByte(rgb.b);
864 col.a = (unsigned char)(opaq*255);
866 gfx_capType capType = gfx_capRound;
867 if(lineCap == 0) capType = gfx_capButt;
868 else if(lineCap == 1) capType = gfx_capRound;
869 else if(lineCap == 2) capType = gfx_capSquare;
871 gfx_joinType joinType = gfx_joinRound;
872 if(lineJoin == 0) joinType = gfx_joinMiter;
873 else if(lineJoin == 1) joinType = gfx_joinRound;
874 else if(lineJoin == 2) joinType = gfx_joinBevel;
877 double dashphase = 0;
879 state->getLineDash(&ldash, &dashnum, &dashphase);
883 if(dashnum && ldash) {
884 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
888 msg("<trace> %d dashes", dashnum);
889 msg("<trace> | phase: %f", dashphase);
890 for(t=0;t<dashnum;t++) {
892 msg("<trace> | d%-3d: %f", t, ldash[t]);
895 if(getLogLevel() >= LOGLEVEL_TRACE) {
899 line2 = gfxtool_dash_line(line, dash, dashphase);
902 msg("<trace> After dashing:");
905 if(getLogLevel() >= LOGLEVEL_TRACE) {
906 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x\n",
908 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
909 lineCap==0?"butt": (lineJoin==1?"round":"square"),
911 col.r,col.g,col.b,col.a
916 //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
917 output->stroke(output, line, width, &col, capType, joinType, miterLimit);
927 gfxcolor_t getFillColor(GfxState * state)
930 double opaq = state->getFillOpacity();
931 state->getFillRGB(&rgb);
933 col.r = colToByte(rgb.r);
934 col.g = colToByte(rgb.g);
935 col.b = colToByte(rgb.b);
936 col.a = (unsigned char)(opaq*255);
940 void SWFOutputDev::fillGfxLine(GfxState *state, gfxline_t*line)
942 gfxcolor_t col = getFillColor(state);
944 if(getLogLevel() >= LOGLEVEL_TRACE) {
945 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
948 output->fill(output, line, &col);
950 void SWFOutputDev::fill(GfxState *state)
952 GfxPath * path = state->getPath();
953 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
954 fillGfxLine(state, line);
957 void SWFOutputDev::eoFill(GfxState *state)
959 GfxPath * path = state->getPath();
960 gfxcolor_t col = getFillColor(state);
962 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
964 if(getLogLevel() >= LOGLEVEL_TRACE) {
965 msg("<trace> eofill\n");
969 output->fill(output, line, &col);
973 void SWFOutputDev::clip(GfxState *state)
975 GfxPath * path = state->getPath();
976 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
977 clipToGfxLine(state, line);
981 void SWFOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line)
983 if(getLogLevel() >= LOGLEVEL_TRACE) {
984 msg("<trace> clip\n");
988 output->startclip(output, line);
989 states[statepos].clipping++;
991 void SWFOutputDev::eoClip(GfxState *state)
993 GfxPath * path = state->getPath();
994 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
996 if(getLogLevel() >= LOGLEVEL_TRACE) {
997 msg("<trace> eoclip\n");
1001 output->startclip(output, line);
1002 states[statepos].clipping++;
1006 void SWFOutputDev::endframe()
1008 if(outer_clip_box) {
1009 output->endclip(output);
1013 output->endpage(output);
1016 void SWFOutputDev::finish()
1018 if(outer_clip_box) {
1020 output->endclip(output);
1025 this->result = output->finish(output);
1026 free(output);output=0;
1030 int SWFOutputDev::save(char*filename)
1033 return result->save(result, filename);
1035 void* SWFOutputDev::get(char*name)
1038 return result->get(result, name);
1041 SWFOutputDev::~SWFOutputDev()
1046 this->result->destroy(this->result);
1051 free(this->pages); this->pages = 0;
1054 fontlist_t*l = this->fontlist;
1056 fontlist_t*next = l->next;
1058 gfxfont_free(l->font);
1066 GBool SWFOutputDev::upsideDown()
1070 GBool SWFOutputDev::useDrawChar()
1074 GBool SWFOutputDev::useGradients()
1078 msg("<notice> File contains gradients");
1084 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
1085 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
1087 #define RENDER_FILL 0
1088 #define RENDER_STROKE 1
1089 #define RENDER_FILLSTROKE 2
1090 #define RENDER_INVISIBLE 3
1091 #define RENDER_CLIP 4
1093 static char tmp_printstr[4096];
1094 char* makeStringPrintable(char*str)
1096 int len = strlen(str);
1103 for(t=0;t<len;t++) {
1108 tmp_printstr[t] = c;
1111 tmp_printstr[len++] = '.';
1112 tmp_printstr[len++] = '.';
1113 tmp_printstr[len++] = '.';
1115 tmp_printstr[len] = 0;
1116 return tmp_printstr;
1120 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
1125 /* find out char name from unicode index
1126 TODO: should be precomputed
1128 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1129 if(nameToUnicodeTab[t].u == u) {
1130 uniname = nameToUnicodeTab[t].name;
1138 for(t=0;t<font->num_glyphs;t++) {
1139 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
1140 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1144 /* if we didn't find the character, maybe
1145 we can find the capitalized version */
1146 for(t=0;t<font->num_glyphs;t++) {
1147 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
1148 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1156 for(t=0;t<font->num_glyphs;t++) {
1157 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,uniname)) {
1158 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, uniname, u, t);
1162 /* if we didn't find the character, maybe
1163 we can find the capitalized version */
1164 for(t=0;t<font->num_glyphs;t++) {
1165 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,uniname)) {
1166 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, uniname, u, t);
1172 /* try to use the unicode id */
1173 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
1174 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
1175 return font->unicode2glyph[u];
1178 if(charnr>=0 && charnr<font->num_glyphs) {
1179 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1187 void SWFOutputDev::beginString(GfxState *state, GString *s)
1189 int render = state->getRender();
1190 if(current_text_stroke) {
1191 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
1194 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
1195 double m11,m21,m12,m22;
1196 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
1197 state->getFontTransMat(&m11, &m12, &m21, &m22);
1198 m11 *= state->getHorizScaling();
1199 m21 *= state->getHorizScaling();
1201 this->current_font_matrix.m00 = m11 / 1024.0;
1202 this->current_font_matrix.m01 = m12 / 1024.0;
1203 this->current_font_matrix.m10 = -m21 / 1024.0;
1204 this->current_font_matrix.m11 = -m22 / 1024.0;
1205 this->current_font_matrix.tx = 0;
1206 this->current_font_matrix.ty = 0;
1208 gfxmatrix_t m = this->current_font_matrix;
1210 /*if(render != 3 && render != 0)
1211 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1212 states[statepos].textRender = render;
1215 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1216 double dx, double dy,
1217 double originX, double originY,
1218 CharCode c, int nBytes, Unicode *_u, int uLen)
1220 int render = state->getRender();
1221 // check for invisible text -- this is used by Acrobat Capture
1223 msg("<debug> Ignoring invisible text: char %d at %f,%f", c, x, y);
1227 if(states[statepos].textRender != render)
1228 msg("<error> Internal error: drawChar.render!=beginString.render");
1230 gfxcolor_t col = getFillColor(state);
1232 Gushort *CIDToGIDMap = 0;
1233 GfxFont*font = state->getFont();
1235 if(font->getType() == fontType3) {
1236 /* type 3 chars are passed as graphics */
1237 msg("<debug> type3 char at %f/%f", x, y);
1244 if(font->isCIDFont()) {
1245 GfxCIDFont*cfont = (GfxCIDFont*)font;
1247 if(font->getType() == fontCIDType2)
1248 CIDToGIDMap = cfont->getCIDToGID();
1251 font8 = (Gfx8BitFont*)font;
1252 char**enc=font8->getEncoding();
1256 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);
1259 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);
1265 charid = getGfxCharID(current_gfxfont, c, name, u);
1267 charid = getGfxCharID(current_gfxfont, c, name, -1);
1270 /* multiple unicodes- should usually map to a ligature.
1271 if the ligature doesn't exist, we need to draw
1272 the characters one-by-one. */
1274 msg("<warning> ligature %d missing in font %s\n", c, current_font_id);
1275 for(t=0;t<uLen;t++) {
1276 drawChar(state, x, y, dx, dy, originX, originY, c, nBytes, _u+t, 1);
1284 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1285 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1290 gfxmatrix_t m = this->current_font_matrix;
1291 state->transform(x, y, &m.tx, &m.ty);
1295 if(render == RENDER_FILL) {
1296 output->drawchar(output, current_font_id, charid, &col, &m);
1298 msg("<debug> Drawing glyph %d as shape", charid);
1300 msg("<notice> Some texts will be rendered as shape");
1303 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1304 gfxline_t*tglyph = gfxline_clone(glyph);
1305 gfxline_transform(tglyph, &m);
1306 if((render&3) != RENDER_INVISIBLE) {
1307 gfxline_t*add = gfxline_clone(tglyph);
1308 current_text_stroke = gfxline_append(current_text_stroke, add);
1310 if(render&RENDER_CLIP) {
1311 gfxline_t*add = gfxline_clone(tglyph);
1312 current_text_clip = gfxline_append(current_text_clip, add);
1314 gfxline_free(tglyph);
1318 void SWFOutputDev::endString(GfxState *state)
1320 int render = state->getRender();
1321 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1322 if(states[statepos].textRender != render)
1323 msg("<error> Internal error: drawChar.render!=beginString.render");
1325 if(current_text_stroke) {
1326 /* fillstroke and stroke text rendering objects we can process right
1327 now (as there may be texts of other rendering modes in this
1328 text object)- clipping objects have to wait until endTextObject,
1330 if((render&3) == RENDER_FILL) {
1331 fillGfxLine(state, current_text_stroke);
1332 gfxline_free(current_text_stroke);
1333 current_text_stroke = 0;
1334 } else if((render&3) == RENDER_FILLSTROKE) {
1335 fillGfxLine(state, current_text_stroke);
1336 strokeGfxline(state, current_text_stroke);
1337 gfxline_free(current_text_stroke);
1338 current_text_stroke = 0;
1339 } else if((render&3) == RENDER_STROKE) {
1340 strokeGfxline(state, current_text_stroke);
1341 gfxline_free(current_text_stroke);
1342 current_text_stroke = 0;
1347 void SWFOutputDev::endTextObject(GfxState *state)
1349 int render = state->getRender();
1350 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1351 if(states[statepos].textRender != render)
1352 msg("<error> Internal error: drawChar.render!=beginString.render");
1354 if(current_text_clip) {
1355 clipToGfxLine(state, current_text_clip);
1356 gfxline_free(current_text_clip);
1357 current_text_clip = 0;
1361 /* the logic seems to be as following:
1362 first, beginType3Char is called, with the charcode and the coordinates.
1363 if this function returns true, it already knew about the char and has now drawn it.
1364 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1365 the all draw operations until endType3Char are part of the char (which in this moment is
1366 at the position first passed to beginType3Char). the char ends with endType3Char.
1368 The drawing operations between beginType3Char and endType3Char are somewhat different to
1369 the normal ones. For example, the fillcolor equals the stroke color.
1372 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1374 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1376 /* the character itself is going to be passed using the draw functions */
1377 return gFalse; /* gTrue= is_in_cache? */
1380 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1381 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1383 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1384 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1388 void SWFOutputDev::endType3Char(GfxState *state)
1391 msg("<debug> endType3Char");
1394 void SWFOutputDev::startFrame(int width, int height)
1396 output->startpage(output, width, height);
1399 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1401 this->currentpage = pageNum;
1403 int rot = doc->getPageRotate(1);
1406 gfxline_t clippath[5];
1408 white.r = white.g = white.b = white.a = 255;
1410 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1411 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1412 Use CropBox, not MediaBox, as page size
1419 state->transform(crop_x1,crop_y1,&x1,&y1); //x1 += user_movex; y1 += user_movey;
1420 state->transform(crop_x2,crop_y2,&x2,&y2); //x2 += user_movex; y2 += user_movey;
1422 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1423 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1426 /* apply user clip box */
1427 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1428 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1429 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1430 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1431 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1434 //msg("<verbose> Bounding box is (%f,%f)-(%f,%f) [shifted by %d/%d]", x1,y1,x2,y2, user_movex, user_movey);
1436 if(outer_clip_box) {
1437 output->endclip(output);
1441 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);
1443 msg("<verbose> page is rotated %d degrees\n", rot);
1445 clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1446 clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1447 clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1448 clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1449 clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1450 output->startclip(output, clippath); outer_clip_box = 1;
1451 output->fill(output, clippath, &white);
1454 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1456 msg("<debug> drawlink\n");
1457 double x1, y1, x2, y2, w;
1458 gfxline_t points[5];
1461 link->getRect(&x1, &y1, &x2, &y2);
1462 cvtUserToDev(x1, y1, &x, &y);
1463 points[0].type = gfx_moveTo;
1464 points[0].x = points[4].x = x + user_movex;
1465 points[0].y = points[4].y = y + user_movey;
1466 points[0].next = &points[1];
1467 cvtUserToDev(x2, y1, &x, &y);
1468 points[1].type = gfx_lineTo;
1469 points[1].x = x + user_movex;
1470 points[1].y = y + user_movey;
1471 points[1].next = &points[2];
1472 cvtUserToDev(x2, y2, &x, &y);
1473 points[2].type = gfx_lineTo;
1474 points[2].x = x + user_movex;
1475 points[2].y = y + user_movey;
1476 points[2].next = &points[3];
1477 cvtUserToDev(x1, y2, &x, &y);
1478 points[3].type = gfx_lineTo;
1479 points[3].x = x + user_movex;
1480 points[3].y = y + user_movey;
1481 points[3].next = &points[4];
1482 cvtUserToDev(x1, y1, &x, &y);
1483 points[4].type = gfx_lineTo;
1484 points[4].x = x + user_movex;
1485 points[4].y = y + user_movey;
1488 LinkAction*action=link->getAction();
1495 switch(action->getKind())
1499 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1500 LinkDest *dest=NULL;
1501 if (ha->getDest()==NULL)
1502 dest=catalog->findDest(ha->getNamedDest());
1503 else dest=ha->getDest();
1505 if (dest->isPageRef()){
1506 Ref pageref=dest->getPageRef();
1507 page=catalog->findPage(pageref.num,pageref.gen);
1509 else page=dest->getPageNum();
1510 sprintf(buf, "%d", page);
1517 LinkGoToR*l = (LinkGoToR*)action;
1518 GString*g = l->getNamedDest();
1520 s = strdup(g->getCString());
1525 LinkNamed*l = (LinkNamed*)action;
1526 GString*name = l->getName();
1528 s = strdup(name->lowerCase()->getCString());
1529 named = name->getCString();
1532 if(strstr(s, "next") || strstr(s, "forward"))
1534 page = currentpage + 1;
1536 else if(strstr(s, "prev") || strstr(s, "back"))
1538 page = currentpage - 1;
1540 else if(strstr(s, "last") || strstr(s, "end"))
1542 if(pages && pagepos>0)
1543 page = pages[pagepos-1];
1545 else if(strstr(s, "first") || strstr(s, "top"))
1553 case actionLaunch: {
1555 LinkLaunch*l = (LinkLaunch*)action;
1556 GString * str = new GString(l->getFileName());
1557 str->append(l->getParams());
1558 s = strdup(str->getCString());
1564 LinkURI*l = (LinkURI*)action;
1565 GString*g = l->getURI();
1567 url = g->getCString();
1572 case actionUnknown: {
1574 LinkUnknown*l = (LinkUnknown*)action;
1579 msg("<error> Unknown link type!\n");
1583 if(!s) s = strdup("-?-");
1585 if(!linkinfo && (page || url))
1587 msg("<notice> File contains links");
1595 for(t=1;t<=pagepos;t++) {
1596 if(pages[t]==page) {
1605 sprintf(buf, "page%d", lpage);
1606 output->drawlink(output, points, buf);
1610 output->drawlink(output, points, url);
1613 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1617 void SWFOutputDev::saveState(GfxState *state) {
1618 msg("<trace> saveState\n");
1621 msg("<error> Too many nested states in pdf.");
1625 states[statepos].clipping = 0; //? shouldn't this be the current value?
1626 states[statepos].textRender = states[statepos-1].textRender;
1629 void SWFOutputDev::restoreState(GfxState *state) {
1630 msg("<trace> restoreState\n");
1632 while(states[statepos].clipping) {
1633 output->endclip(output);
1634 states[statepos].clipping--;
1639 char* SWFOutputDev::searchFont(char*name)
1643 int is_standard_font = 0;
1645 msg("<verbose> SearchFont(%s)", name);
1647 /* see if it is a pdf standard font */
1648 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1650 if(!strcmp(name, pdf2t1map[i].pdffont))
1652 name = pdf2t1map[i].filename;
1653 is_standard_font = 1;
1657 /* look in all font files */
1658 for(i=0;i<fontnum;i++)
1660 if(strstr(fonts[i].filename, name))
1662 if(!fonts[i].used) {
1665 if(!is_standard_font)
1666 msg("<notice> Using %s for %s", fonts[i].filename, name);
1668 return strdup(fonts[i].filename);
1674 void SWFOutputDev::updateLineWidth(GfxState *state)
1676 double width = state->getTransformedLineWidth();
1677 //swfoutput_setlinewidth(&output, width);
1680 void SWFOutputDev::updateLineCap(GfxState *state)
1682 int c = state->getLineCap();
1685 void SWFOutputDev::updateLineJoin(GfxState *state)
1687 int j = state->getLineJoin();
1690 void SWFOutputDev::updateFillColor(GfxState *state)
1693 double opaq = state->getFillOpacity();
1694 state->getFillRGB(&rgb);
1696 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1699 void SWFOutputDev::updateStrokeColor(GfxState *state)
1702 double opaq = state->getStrokeOpacity();
1703 state->getStrokeRGB(&rgb);
1704 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1707 void FoFiWrite(void *stream, char *data, int len)
1709 fwrite(data, len, 1, (FILE*)stream);
1712 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1714 char*tmpFileName = NULL;
1720 Object refObj, strObj;
1722 tmpFileName = mktmpname(namebuf);
1725 ret = font->getEmbeddedFontID(&embRef);
1727 msg("<verbose> Didn't get embedded font id");
1728 /* not embedded- the caller should now search the font
1729 directories for this font */
1733 f = fopen(tmpFileName, "wb");
1735 msg("<error> Couldn't create temporary Type 1 font file");
1739 /*if(font->isCIDFont()) {
1740 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1741 GString c = cidFont->getCollection();
1742 msg("<notice> Collection: %s", c.getCString());
1745 //if (font->getType() == fontType1C) {
1746 if (0) { //font->getType() == fontType1C) {
1747 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1749 msg("<error> Couldn't read embedded font file");
1752 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1754 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1755 //cvt->convertToCIDType0("test", f);
1756 //cvt->convertToType0("test", f);
1759 } else if(font->getType() == fontTrueType) {
1760 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1761 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1763 msg("<error> Couldn't read embedded font file");
1766 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1767 cvt->writeTTF(FoFiWrite, f);
1771 font->getEmbeddedFontID(&embRef);
1772 refObj.initRef(embRef.num, embRef.gen);
1773 refObj.fetch(ref, &strObj);
1775 strObj.streamReset();
1780 f4[t] = strObj.streamGetChar();
1781 f4c[t] = (char)f4[t];
1786 if(!strncmp(f4c, "true", 4)) {
1787 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1788 Change this on the fly */
1789 f4[0] = f4[2] = f4[3] = 0;
1797 while ((c = strObj.streamGetChar()) != EOF) {
1801 strObj.streamClose();
1806 return strdup(tmpFileName);
1809 char* searchForSuitableFont(GfxFont*gfxFont)
1811 char*name = getFontName(gfxFont);
1815 if(!config_use_fontconfig)
1818 #ifdef HAVE_FONTCONFIG
1819 FcPattern *pattern, *match;
1823 static int fcinitcalled = false;
1825 msg("<debug> searchForSuitableFont(%s)", name);
1827 // call init ony once
1828 if (!fcinitcalled) {
1829 msg("<debug> Initializing FontConfig...");
1830 fcinitcalled = true;
1832 msg("<debug> FontConfig Initialization failed. Disabling.");
1833 config_use_fontconfig = 0;
1836 msg("<debug> ...initialized FontConfig");
1839 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1840 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1841 if (gfxFont->isItalic()) // check for italic
1842 msg("<debug> FontConfig: Adding Italic Slant");
1843 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1844 if (gfxFont->isBold()) // check for bold
1845 msg("<debug> FontConfig: Adding Bold Weight");
1846 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1848 msg("<debug> FontConfig: Try to match...");
1849 // configure and match using the original font name
1850 FcConfigSubstitute(0, pattern, FcMatchPattern);
1851 FcDefaultSubstitute(pattern);
1852 match = FcFontMatch(0, pattern, &result);
1854 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1855 msg("<debug> FontConfig: family=%s", (char*)v);
1856 // if we get an exact match
1857 if (strcmp((char *)v, name) == 0) {
1858 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1859 filename = strdup((char*)v); // mem leak
1860 char *nfn = strrchr(filename, '/');
1861 if(nfn) fontname = strdup(nfn+1);
1862 else fontname = filename;
1864 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1866 // initialize patterns
1867 FcPatternDestroy(pattern);
1868 FcPatternDestroy(match);
1870 // now match against serif etc.
1871 if (gfxFont->isSerif()) {
1872 msg("<debug> FontConfig: Create Serif Family Pattern");
1873 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1874 } else if (gfxFont->isFixedWidth()) {
1875 msg("<debug> FontConfig: Create Monospace Family Pattern");
1876 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1878 msg("<debug> FontConfig: Create Sans Family Pattern");
1879 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1883 if (gfxFont->isItalic()) {
1884 msg("<debug> FontConfig: Adding Italic Slant");
1885 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1888 if (gfxFont->isBold()) {
1889 msg("<debug> FontConfig: Adding Bold Weight");
1890 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1893 msg("<debug> FontConfig: Try to match... (2)");
1894 // configure and match using serif etc
1895 FcConfigSubstitute (0, pattern, FcMatchPattern);
1896 FcDefaultSubstitute (pattern);
1897 match = FcFontMatch (0, pattern, &result);
1899 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1900 filename = strdup((char*)v); // mem leak
1901 char *nfn = strrchr(filename, '/');
1902 if(nfn) fontname = strdup(nfn+1);
1903 else fontname = filename;
1905 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1909 //printf("FONTCONFIG: pattern");
1910 //FcPatternPrint(pattern);
1911 //printf("FONTCONFIG: match");
1912 //FcPatternPrint(match);
1914 FcPatternDestroy(pattern);
1915 FcPatternDestroy(match);
1917 pdfswf_addfont(filename);
1924 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1926 char*fontname = 0, *filename = 0;
1927 msg("<notice> substituteFont(%s)", oldname);
1929 if(!(fontname = searchForSuitableFont(gfxFont))) {
1930 fontname = "Times-Roman";
1932 filename = searchFont(fontname);
1934 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1938 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1939 msg("<fatal> Too many fonts in file.");
1943 substitutesource[substitutepos] = strdup(oldname); //mem leak
1944 substitutetarget[substitutepos] = fontname;
1945 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1948 return strdup(filename); //mem leak
1951 void unlinkfont(char* filename)
1958 if(!strncmp(&filename[l-4],".afm",4)) {
1959 memcpy(&filename[l-4],".pfb",4);
1961 memcpy(&filename[l-4],".pfa",4);
1963 memcpy(&filename[l-4],".afm",4);
1966 if(!strncmp(&filename[l-4],".pfa",4)) {
1967 memcpy(&filename[l-4],".afm",4);
1969 memcpy(&filename[l-4],".pfa",4);
1972 if(!strncmp(&filename[l-4],".pfb",4)) {
1973 memcpy(&filename[l-4],".afm",4);
1975 memcpy(&filename[l-4],".pfb",4);
1980 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1986 int SWFOutputDev::setGfxFont(char*id, char*filename, double maxSize)
1989 fontlist_t*last=0,*l = this->fontlist;
1991 /* TODO: should this be part of the state? */
1994 if(!strcmp(l->id, id)) {
1995 current_font_id = l->id;
1996 current_gfxfont = l->font;
1998 output->addfont(output, id, current_gfxfont);
2003 if(!filename) return 0;
2005 /* A font size of e.g. 9 means the font will be scaled down by
2006 1024 and scaled up by 9. So to have a maximum error of 1/20px,
2007 we have to divide 0.05 by (fontsize/1024)
2009 double quality = (1024 * 0.05) / maxSize;
2011 msg("<verbose> Loading %s...", filename);
2012 font = gfxfont_load(filename, quality);
2013 msg("<verbose> Font %s loaded successfully", filename);
2017 l->filename = strdup(filename);
2020 current_font_id = l->id;
2021 current_gfxfont = l->font;
2027 output->addfont(output, id, current_gfxfont);
2031 void SWFOutputDev::updateFont(GfxState *state)
2033 GfxFont*gfxFont = state->getFont();
2038 char * fontid = getFontID(gfxFont);
2039 double maxSize = 1.0;
2042 maxSize = this->info->getMaximumFontSize(fontid);
2046 /* first, look if we substituted this font before-
2047 this way, we don't initialize the T1 Fonts
2049 for(t=0;t<substitutepos;t++) {
2050 if(!strcmp(fontid, substitutesource[t])) {
2051 free(fontid);fontid=0;
2052 fontid = strdup(substitutetarget[t]);
2057 /* second, see if this is a font which was used before-
2058 if so, we are done */
2059 if(setGfxFont(fontid, 0, 0)) {
2063 /* if(swfoutput_queryfont(&output, fontid))
2064 swfoutput_setfont(&output, fontid, 0);
2066 msg("<debug> updateFont(%s) [cached]", fontid);
2070 // look for Type 3 font
2071 if (gfxFont->getType() == fontType3) {
2073 type3Warning = gTrue;
2074 showFontError(gfxFont, 2);
2080 /* now either load the font, or find a substitution */
2083 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
2088 (gfxFont->getType() == fontType1 ||
2089 gfxFont->getType() == fontType1C ||
2090 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
2091 gfxFont->getType() == fontTrueType ||
2092 gfxFont->getType() == fontCIDType2
2095 fileName = writeEmbeddedFontToFile(xref, gfxFont);
2096 if(!fileName) showFontError(gfxFont,0);
2099 char * fontname = getFontName(gfxFont);
2100 fileName = searchFont(fontname);
2101 if(!fileName) showFontError(gfxFont,0);
2105 char * fontname = getFontName(gfxFont);
2106 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
2109 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into %s", fontname, lastfontdir);
2111 msg("<warning> Try specifying one or more font directories");
2113 fileName = substituteFont(gfxFont, fontid);
2114 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
2115 msg("<notice> Font is now %s (%s)", fontid, fileName);
2119 msg("<error> Couldn't set font %s\n", fontid);
2124 msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
2125 dumpFontInfo("<verbose>", gfxFont);
2127 //swfoutput_setfont(&output, fontid, fileName);
2129 if(!setGfxFont(fontid, 0, 0)) {
2130 setGfxFont(fontid, fileName, maxSize);
2134 unlinkfont(fileName);
2142 #define SQR(x) ((x)*(x))
2144 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
2146 if((newwidth<2 || newheight<2) ||
2147 (width<=newwidth || height<=newheight))
2149 unsigned char*newdata;
2151 newdata= (unsigned char*)malloc(newwidth*newheight);
2153 double fx = (double)(width)/newwidth;
2154 double fy = (double)(height)/newheight;
2156 int blocksize = (int)(8192/(fx*fy));
2157 int r = 8192*256/palettesize;
2158 for(x=0;x<newwidth;x++) {
2159 double ex = px + fx;
2160 int fromx = (int)px;
2162 int xweight1 = (int)(((fromx+1)-px)*256);
2163 int xweight2 = (int)((ex-tox)*256);
2165 for(y=0;y<newheight;y++) {
2166 double ey = py + fy;
2167 int fromy = (int)py;
2169 int yweight1 = (int)(((fromy+1)-py)*256);
2170 int yweight2 = (int)((ey-toy)*256);
2173 for(xx=fromx;xx<=tox;xx++)
2174 for(yy=fromy;yy<=toy;yy++) {
2175 int b = 1-data[width*yy+xx];
2177 if(xx==fromx) weight = (weight*xweight1)/256;
2178 if(xx==tox) weight = (weight*xweight2)/256;
2179 if(yy==fromy) weight = (weight*yweight1)/256;
2180 if(yy==toy) weight = (weight*yweight2)/256;
2183 //if(a) a=(palettesize-1)*r/blocksize;
2184 newdata[y*newwidth+x] = (a*blocksize)/r;
2192 #define IMAGE_TYPE_JPEG 0
2193 #define IMAGE_TYPE_LOSSLESS 1
2195 static void drawimage(gfxdevice_t*dev, gfxcolor_t* data, int sizex,int sizey,
2196 double x1,double y1,
2197 double x2,double y2,
2198 double x3,double y3,
2199 double x4,double y4, int type)
2201 gfxcolor_t*newpic=0;
2203 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2204 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2206 gfxline_t p1,p2,p3,p4,p5;
2207 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2208 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2209 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2210 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2211 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2213 {p1.x = (int)(p1.x*20)/20.0;
2214 p1.y = (int)(p1.y*20)/20.0;
2215 p2.x = (int)(p2.x*20)/20.0;
2216 p2.y = (int)(p2.y*20)/20.0;
2217 p3.x = (int)(p3.x*20)/20.0;
2218 p3.y = (int)(p3.y*20)/20.0;
2219 p4.x = (int)(p4.x*20)/20.0;
2220 p4.y = (int)(p4.y*20)/20.0;
2221 p5.x = (int)(p5.x*20)/20.0;
2222 p5.y = (int)(p5.y*20)/20.0;
2229 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2230 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2235 img.data = (gfxcolor_t*)data;
2239 if(type == IMAGE_TYPE_JPEG)
2240 /* TODO: pass image_dpi to device instead */
2241 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2243 dev->fillbitmap(dev, &p1, &img, &m, 0);
2246 void drawimagejpeg(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2247 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2249 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2252 void drawimagelossless(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2253 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2255 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2259 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2260 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2261 GBool inlineImg, int mask, int*maskColors,
2262 Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GfxImageColorMap*maskColorMap)
2264 double x1,y1,x2,y2,x3,y3,x4,y4;
2265 ImageStream *imgStr;
2270 unsigned char* maskbitmap = 0;
2273 ncomps = colorMap->getNumPixelComps();
2274 bits = colorMap->getBits();
2279 unsigned char buf[8];
2280 maskbitmap = (unsigned char*)malloc(maskHeight*maskWidth);
2282 ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, maskColorMap->getNumPixelComps(), maskColorMap->getBits());
2283 imgMaskStr->reset();
2284 unsigned char pal[256];
2285 int n = 1 << colorMap->getBits();
2290 maskColorMap->getGray(pixBuf, &gray);
2291 pal[t] = colToByte(gray);
2293 for (y = 0; y < maskHeight; y++) {
2294 for (x = 0; x < maskWidth; x++) {
2295 imgMaskStr->getPixel(buf);
2296 maskbitmap[y*maskWidth+x] = pal[buf[0]];
2301 ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, 1, 1);
2302 imgMaskStr->reset();
2303 for (y = 0; y < maskHeight; y++) {
2304 for (x = 0; x < maskWidth; x++) {
2305 imgMaskStr->getPixel(buf);
2307 maskbitmap[y*maskWidth+x] = (buf[0]^1)*255;
2314 imgStr = new ImageStream(str, width, ncomps,bits);
2317 if(!width || !height || (height<=1 && width<=1))
2319 msg("<verbose> Ignoring %d by %d image", width, height);
2320 unsigned char buf[8];
2322 for (y = 0; y < height; ++y)
2323 for (x = 0; x < width; ++x) {
2324 imgStr->getPixel(buf);
2332 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1 += user_movey;
2333 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2 += user_movey;
2334 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3 += user_movey;
2335 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4 += user_movey;
2337 if(!pbminfo && !(str->getKind()==strDCT)) {
2339 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2343 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2345 if(!jpeginfo && (str->getKind()==strDCT)) {
2346 msg("<notice> file contains jpeg pictures");
2352 unsigned char buf[8];
2354 unsigned char*pic = new unsigned char[width*height];
2355 gfxcolor_t pal[256];
2357 state->getFillRGB(&rgb);
2359 memset(pal,255,sizeof(pal));
2360 pal[0].r = (int)(colToByte(rgb.r)); pal[1].r = 0;
2361 pal[0].g = (int)(colToByte(rgb.g)); pal[1].g = 0;
2362 pal[0].b = (int)(colToByte(rgb.b)); pal[1].b = 0;
2363 pal[0].a = 255; pal[1].a = 0;
2366 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2367 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2368 for (y = 0; y < height; ++y)
2369 for (x = 0; x < width; ++x)
2371 imgStr->getPixel(buf);
2374 pic[width*y+x] = buf[0];
2377 /* the size of the drawn image is added to the identifier
2378 as the same image may require different bitmaps if displayed
2379 at different sizes (due to antialiasing): */
2382 unsigned char*pic2 = 0;
2385 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2394 height = realheight;
2398 /* make a black/white palette */
2400 float r = 255/(numpalette-1);
2402 for(t=0;t<numpalette;t++) {
2403 pal[t].r = colToByte(rgb.r);
2404 pal[t].g = colToByte(rgb.g);
2405 pal[t].b = colToByte(rgb.b);
2406 pal[t].a = (unsigned char)(t*r);
2410 gfxcolor_t*pic2 = new gfxcolor_t[width*height];
2411 for (y = 0; y < height; ++y) {
2412 for (x = 0; x < width; ++x) {
2413 pic2[width*y+x] = pal[pic[y*width+x]];
2416 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2420 if(maskbitmap) free(maskbitmap);
2426 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2427 gfxcolor_t*pic=new gfxcolor_t[width*height];
2428 for (y = 0; y < height; ++y) {
2429 for (x = 0; x < width; ++x) {
2430 imgStr->getPixel(pixBuf);
2431 colorMap->getRGB(pixBuf, &rgb);
2432 pic[width*y+x].r = (unsigned char)(colToByte(rgb.r));
2433 pic[width*y+x].g = (unsigned char)(colToByte(rgb.g));
2434 pic[width*y+x].b = (unsigned char)(colToByte(rgb.b));
2435 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2437 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2441 if(str->getKind()==strDCT)
2442 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2444 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2447 if(maskbitmap) free(maskbitmap);
2450 gfxcolor_t*pic=new gfxcolor_t[width*height];
2451 gfxcolor_t pal[256];
2452 int n = 1 << colorMap->getBits();
2454 for(t=0;t<256;t++) {
2456 colorMap->getRGB(pixBuf, &rgb);
2458 {/*if(maskColors && *maskColors==t) {
2459 msg("<notice> Color %d is transparent", t);
2460 if (imgData->maskColors) {
2462 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2463 if (pix[i] < imgData->maskColors[2*i] ||
2464 pix[i] > imgData->maskColors[2*i+1]) {
2479 pal[t].r = (unsigned char)(colToByte(rgb.r));
2480 pal[t].g = (unsigned char)(colToByte(rgb.g));
2481 pal[t].b = (unsigned char)(colToByte(rgb.b));
2482 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2485 for (y = 0; y < height; ++y) {
2486 for (x = 0; x < width; ++x) {
2487 imgStr->getPixel(pixBuf);
2488 pic[width*y+x] = pal[pixBuf[0]];
2490 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2494 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2498 if(maskbitmap) free(maskbitmap);
2503 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2504 int width, int height, GBool invert,
2507 if(states[statepos].textRender & 4) //clipped
2509 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2510 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0, 0,0,0,0, 0);
2513 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2514 int width, int height, GfxImageColorMap *colorMap,
2515 int *maskColors, GBool inlineImg)
2517 if(states[statepos].textRender & 4) //clipped
2520 msg("<verbose> drawImage %dx%d, %s, %s, inline=%d", width, height,
2521 colorMap?"colorMap":"no colorMap",
2522 maskColors?"maskColors":"no maskColors",
2525 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2526 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2527 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors, 0,0,0,0, 0);
2530 void SWFOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
2531 int width, int height,
2532 GfxImageColorMap *colorMap,
2533 Stream *maskStr, int maskWidth, int maskHeight,
2536 if(states[statepos].textRender & 4) //clipped
2539 msg("<verbose> drawMaskedImage %dx%d, %s, %dx%d mask", width, height,
2540 colorMap?"colorMap":"no colorMap",
2541 maskWidth, maskHeight);
2543 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2544 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2545 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, maskInvert, 0);
2548 void SWFOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
2549 int width, int height,
2550 GfxImageColorMap *colorMap,
2552 int maskWidth, int maskHeight,
2553 GfxImageColorMap *maskColorMap)
2555 if(states[statepos].textRender & 4) //clipped
2558 msg("<verbose> drawSoftMaskedImage %dx%d, %s, %dx%d mask", width, height,
2559 colorMap?"colorMap":"no colorMap",
2560 maskWidth, maskHeight);
2562 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2563 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2564 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, 0, maskColorMap);
2567 //SWFOutputDev*output = 0;
2569 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2574 if (infoDict->lookup(key, &obj)->isString()) {
2575 s1 = obj.getString();
2576 if ((s1->getChar(0) & 0xff) == 0xfe &&
2577 (s1->getChar(1) & 0xff) == 0xff) {
2579 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2580 if (s1->getChar(i) == '\0') {
2581 s2->append(s1->getChar(i+1));
2584 s2 = new GString("<unicode>");
2588 printf(fmt, s2->getCString());
2591 printf(fmt, s1->getCString());
2597 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2601 if (infoDict->lookup(key, &obj)->isString()) {
2602 s = obj.getString()->getCString();
2603 if (s[0] == 'D' && s[1] == ':') {
2614 void storeDeviceParameter(char*name, char*value)
2616 parameter_t*p = new parameter_t();
2617 p->name = strdup(name);
2618 p->value = strdup(value);
2620 if(device_config_next) {
2621 device_config_next->next = p;
2622 device_config_next = p;
2625 device_config_next = p;
2629 void pdfswf_setparameter(char*name, char*value)
2631 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2632 if(!strcmp(name, "caplinewidth")) {
2633 caplinewidth = atof(value);
2634 } else if(!strcmp(name, "zoom")) {
2637 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2638 storeDeviceParameter("jpegsubpixels", buf);
2639 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2640 storeDeviceParameter("ppmsubpixels", buf);
2641 } else if(!strcmp(name, "jpegdpi")) {
2643 jpeg_dpi = atoi(value);
2644 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2645 storeDeviceParameter("jpegsubpixels", buf);
2646 } else if(!strcmp(name, "ppmdpi")) {
2648 ppm_dpi = atoi(value);
2649 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2650 storeDeviceParameter("ppmsubpixels", buf);
2651 } else if(!strcmp(name, "forceType0Fonts")) {
2652 forceType0Fonts = atoi(value);
2653 } else if(!strncmp(name, "fontdir", strlen("fontdir"))) {
2654 pdfswf_addfontdir(value);
2655 } else if(!strncmp(name, "languagedir", strlen("languagedir"))) {
2656 pdfswf_addlanguagedir(value);
2657 } else if(!strcmp(name, "fontconfig")) {
2658 config_use_fontconfig = atoi(value);
2660 storeDeviceParameter(name,value);
2663 void pdfswf_addfont(char*filename)
2666 memset(&f, 0, sizeof(fontfile_t));
2667 f.filename = filename;
2668 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2669 fonts[fontnum++] = f;
2671 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2675 static char* dirseparator()
2684 void pdfswf_addlanguagedir(char*dir)
2687 globalParams = new GlobalParams("");
2689 msg("<notice> Adding %s to language pack directories", dir);
2693 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2694 strcpy(config_file, dir);
2695 strcat(config_file, dirseparator());
2696 strcat(config_file, "add-to-xpdfrc");
2698 fi = fopen(config_file, "rb");
2700 msg("<error> Could not open %s", config_file);
2703 globalParams->parseFile(new GString(config_file), fi);
2707 void pdfswf_addfontdir(char*dirname)
2709 #ifdef HAVE_DIRENT_H
2710 msg("<notice> Adding %s to font directories", dirname);
2711 lastfontdir = strdup(dirname);
2712 DIR*dir = opendir(dirname);
2714 msg("<warning> Couldn't open directory %s\n", dirname);
2719 ent = readdir (dir);
2723 char*name = ent->d_name;
2729 if(!strncasecmp(&name[l-4], ".pfa", 4))
2731 if(!strncasecmp(&name[l-4], ".pfb", 4))
2733 if(!strncasecmp(&name[l-4], ".ttf", 4))
2737 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2738 strcpy(fontname, dirname);
2739 strcat(fontname, dirseparator());
2740 strcat(fontname, name);
2741 msg("<verbose> Adding %s to fonts", fontname);
2742 pdfswf_addfont(fontname);
2747 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2752 typedef struct _pdf_doc_internal
2757 } pdf_doc_internal_t;
2758 typedef struct _pdf_page_internal
2760 } pdf_page_internal_t;
2761 typedef struct _swf_output_internal
2763 SWFOutputDev*outputDev;
2764 } swf_output_internal_t;
2766 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2768 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2769 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2770 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2771 memset(i, 0, sizeof(pdf_doc_internal_t));
2772 pdf_doc->internal = i;
2774 GString *fileName = new GString(filename);
2780 globalParams = new GlobalParams("");
2783 if (userPassword && userPassword[0]) {
2784 userPW = new GString(userPassword);
2788 i->doc = new PDFDoc(fileName, userPW);
2792 if (!i->doc->isOk()) {
2797 i->doc->getDocInfo(&info);
2798 if (info.isDict() &&
2799 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2800 printInfoString(info.getDict(), "Title", "Title: %s\n");
2801 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2802 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2803 printInfoString(info.getDict(), "Author", "Author: %s\n");
2804 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2805 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2806 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2807 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2808 printf("Pages: %d\n", i->doc->getNumPages());
2809 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2810 printf("Encrypted: ");
2811 if (i->doc->isEncrypted()) {
2812 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2813 i->doc->okToPrint() ? "yes" : "no",
2814 i->doc->okToCopy() ? "yes" : "no",
2815 i->doc->okToChange() ? "yes" : "no",
2816 i->doc->okToAddNotes() ? "yes" : "no");
2823 pdf_doc->num_pages = i->doc->getNumPages();
2825 if (i->doc->isEncrypted()) {
2826 if(!i->doc->okToCopy()) {
2827 printf("PDF disallows copying.\n");
2830 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2834 InfoOutputDev*io = new InfoOutputDev();
2836 for(t=1;t<=pdf_doc->num_pages;t++) {
2837 i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, /*usemediabox*/true, /*crop*/true, /*doLinks*/(int)1);
2848 delete globalParams;globalParams=0;
2849 Object::memCheck(stderr);
2854 void pdf_destroy(pdf_doc_t*pdf_doc)
2856 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2858 delete i->doc; i->doc=0;
2861 delete i->info;i->info=0;
2864 free(pdf_doc->internal);pdf_doc->internal=0;
2865 free(pdf_doc);pdf_doc=0;
2868 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2870 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2872 if(page < 1 || page > pdf_doc->num_pages)
2875 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2876 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2877 memset(pi, 0, sizeof(pdf_page_internal_t));
2878 pdf_page->internal = pi;
2880 pdf_page->parent = pdf_doc;
2881 pdf_page->nr = page;
2885 void pdf_page_destroy(pdf_page_t*pdf_page)
2887 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2888 free(pdf_page->internal);pdf_page->internal = 0;
2889 free(pdf_page);pdf_page=0;
2892 swf_output_t* swf_output_init()
2894 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2895 memset(swf_output, 0, sizeof(swf_output_t));
2896 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2897 memset(i, 0, sizeof(swf_output_internal_t));
2898 swf_output->internal = i;
2900 i->outputDev = new SWFOutputDev();
2904 void swf_output_setparameter(swf_output_t*swf, char*name, char*value)
2906 pdfswf_setparameter(name, value);
2909 void swf_output_startframe(swf_output_t*swf, int width, int height)
2911 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2912 i->outputDev->startFrame(width, height);
2915 void swf_output_endframe(swf_output_t*swf)
2917 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2918 i->outputDev->endframe();
2921 void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage)
2923 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2924 SWFOutputDev*o = i->outputDev;
2930 o->pagebuflen = 1024;
2931 o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
2932 memset(o->pages, -1, o->pagebuflen*sizeof(int));
2934 while(pdfpage >= o->pagebuflen)
2936 int oldlen = o->pagebuflen;
2937 o->pagebuflen+=1024;
2938 o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
2939 memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
2942 o->pages[pdfpage] = outputpage;
2943 if(pdfpage>o->pagepos)
2944 o->pagepos = pdfpage;
2947 int swf_output_save(swf_output_t*swf, char*filename)
2949 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2950 int ret = i->outputDev->save(filename);
2954 void* swf_output_get(swf_output_t*swf,char*name)
2956 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2957 void* ret = i->outputDev->get(name);
2961 void swf_output_destroy(swf_output_t*output)
2963 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2964 delete i->outputDev; i->outputDev=0;
2965 free(output->internal);output->internal=0;
2969 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2971 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2972 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2975 msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2980 gfxdevice_t*dev = si->outputDev->output;
2981 dev->setparameter(dev, "protect", "1");
2983 si->outputDev->setInfo(pi->info);
2984 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2985 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
2988 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2990 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2991 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2993 si->outputDev->setMove(x,y);
2994 if((x1|y1|x2|y2)==0) x2++;
2995 si->outputDev->setClip(x1,y1,x2,y2);
2997 pdf_page_render2(page, output);
2999 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
3001 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
3002 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
3004 si->outputDev->setMove(0,0);
3005 si->outputDev->setClip(0,0,0,0);
3007 pdf_page_render2(page, output);
3011 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
3013 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
3014 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
3015 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
3016 memset(info, 0, sizeof(pdf_page_info_t));
3018 InfoOutputDev*output = new InfoOutputDev;
3020 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
3022 info->xMin = output->x1;
3023 info->yMin = output->y1;
3024 info->xMax = output->x2;
3025 info->yMax = output->y2;
3026 info->number_of_images = output->num_images;
3027 info->number_of_links = output->num_links;
3028 info->number_of_fonts = output->num_fonts;
3035 void pdf_page_info_destroy(pdf_page_info_t*info)