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)
1124 for(t=0;t<font->num_glyphs;t++) {
1125 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
1126 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1130 /* if we didn't find the character, maybe
1131 we can find the capitalized version */
1132 for(t=0;t<font->num_glyphs;t++) {
1133 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
1134 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1140 /* try to use the unicode id */
1141 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
1142 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
1143 return font->unicode2glyph[u];
1146 /* we don't need to "draw" space characters, so don't overdo the search
1147 for a matching glyph */
1148 if(charname && !strcasecmp(charname, "space"))
1151 if(charnr>=0 && charnr<font->num_glyphs) {
1152 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1160 void SWFOutputDev::beginString(GfxState *state, GString *s)
1162 int render = state->getRender();
1163 if(current_text_stroke) {
1164 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
1167 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
1168 double m11,m21,m12,m22;
1169 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
1170 state->getFontTransMat(&m11, &m12, &m21, &m22);
1171 m11 *= state->getHorizScaling();
1172 m21 *= state->getHorizScaling();
1174 this->current_font_matrix.m00 = m11 / 1024.0;
1175 this->current_font_matrix.m01 = m12 / 1024.0;
1176 this->current_font_matrix.m10 = -m21 / 1024.0;
1177 this->current_font_matrix.m11 = -m22 / 1024.0;
1178 this->current_font_matrix.tx = 0;
1179 this->current_font_matrix.ty = 0;
1181 gfxmatrix_t m = this->current_font_matrix;
1183 /*if(render != 3 && render != 0)
1184 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1185 states[statepos].textRender = render;
1188 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1189 double dx, double dy,
1190 double originX, double originY,
1191 CharCode c, int nBytes, Unicode *_u, int uLen)
1193 int render = state->getRender();
1194 // check for invisible text -- this is used by Acrobat Capture
1196 msg("<debug> Ignoring invisible text: char %d at %f,%f", c, x, y);
1200 if(states[statepos].textRender != render)
1201 msg("<error> Internal error: drawChar.render!=beginString.render");
1203 gfxcolor_t col = getFillColor(state);
1205 Gushort *CIDToGIDMap = 0;
1206 GfxFont*font = state->getFont();
1208 if(font->getType() == fontType3) {
1209 /* type 3 chars are passed as graphics */
1210 msg("<debug> type3 char at %f/%f", x, y);
1221 /* find out char name from unicode index
1222 TODO: should be precomputed
1224 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1225 if(nameToUnicodeTab[t].u == u) {
1226 name = nameToUnicodeTab[t].name;
1233 if(font->isCIDFont()) {
1234 GfxCIDFont*cfont = (GfxCIDFont*)font;
1236 if(font->getType() == fontCIDType2)
1237 CIDToGIDMap = cfont->getCIDToGID();
1240 font8 = (Gfx8BitFont*)font;
1241 char**enc=font8->getEncoding();
1242 if(enc && enc[c] && strcasecmp(enc[c], "space")) {
1247 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);
1250 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);
1256 charid = getGfxCharID(current_gfxfont, c, name, u);
1258 charid = getGfxCharID(current_gfxfont, c, 0, -1);
1260 /* multiple unicodes- should usually map to a ligature.
1261 if the ligature doesn't exist, we need to draw
1262 the characters one-by-one. */
1264 msg("<warning> ligature %d missing in font %s\n", c, current_font_id);
1265 for(t=0;t<uLen;t++) {
1266 drawChar(state, x, y, dx, dy, originX, originY, c, nBytes, _u+t, 1);
1273 if(!name || strcasecmp(name, "space")) {
1274 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1275 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1280 gfxmatrix_t m = this->current_font_matrix;
1281 state->transform(x, y, &m.tx, &m.ty);
1285 if(render == RENDER_FILL) {
1286 output->drawchar(output, current_font_id, charid, &col, &m);
1288 msg("<debug> Drawing glyph %d as shape", charid);
1290 msg("<notice> Some texts will be rendered as shape");
1293 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1294 gfxline_t*tglyph = gfxline_clone(glyph);
1295 gfxline_transform(tglyph, &m);
1296 if((render&3) != RENDER_INVISIBLE) {
1297 gfxline_t*add = gfxline_clone(tglyph);
1298 current_text_stroke = gfxline_append(current_text_stroke, add);
1300 if(render&RENDER_CLIP) {
1301 gfxline_t*add = gfxline_clone(tglyph);
1302 current_text_clip = gfxline_append(current_text_clip, add);
1304 gfxline_free(tglyph);
1308 void SWFOutputDev::endString(GfxState *state)
1310 int render = state->getRender();
1311 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1312 if(states[statepos].textRender != render)
1313 msg("<error> Internal error: drawChar.render!=beginString.render");
1315 if(current_text_stroke) {
1316 /* fillstroke and stroke text rendering objects we can process right
1317 now (as there may be texts of other rendering modes in this
1318 text object)- clipping objects have to wait until endTextObject,
1320 if((render&3) == RENDER_FILL) {
1321 fillGfxLine(state, current_text_stroke);
1322 gfxline_free(current_text_stroke);
1323 current_text_stroke = 0;
1324 } else if((render&3) == RENDER_FILLSTROKE) {
1325 fillGfxLine(state, current_text_stroke);
1326 strokeGfxline(state, current_text_stroke);
1327 gfxline_free(current_text_stroke);
1328 current_text_stroke = 0;
1329 } else if((render&3) == RENDER_STROKE) {
1330 strokeGfxline(state, current_text_stroke);
1331 gfxline_free(current_text_stroke);
1332 current_text_stroke = 0;
1337 void SWFOutputDev::endTextObject(GfxState *state)
1339 int render = state->getRender();
1340 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1341 if(states[statepos].textRender != render)
1342 msg("<error> Internal error: drawChar.render!=beginString.render");
1344 if(current_text_clip) {
1345 clipToGfxLine(state, current_text_clip);
1346 gfxline_free(current_text_clip);
1347 current_text_clip = 0;
1351 /* the logic seems to be as following:
1352 first, beginType3Char is called, with the charcode and the coordinates.
1353 if this function returns true, it already knew about the char and has now drawn it.
1354 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1355 the all draw operations until endType3Char are part of the char (which in this moment is
1356 at the position first passed to beginType3Char). the char ends with endType3Char.
1358 The drawing operations between beginType3Char and endType3Char are somewhat different to
1359 the normal ones. For example, the fillcolor equals the stroke color.
1362 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1364 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1366 /* the character itself is going to be passed using the draw functions */
1367 return gFalse; /* gTrue= is_in_cache? */
1370 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1371 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1373 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1374 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1378 void SWFOutputDev::endType3Char(GfxState *state)
1381 msg("<debug> endType3Char");
1384 void SWFOutputDev::startFrame(int width, int height)
1386 output->startpage(output, width, height);
1389 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1391 this->currentpage = pageNum;
1393 int rot = doc->getPageRotate(1);
1396 gfxline_t clippath[5];
1398 white.r = white.g = white.b = white.a = 255;
1400 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1401 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1402 Use CropBox, not MediaBox, as page size
1409 state->transform(crop_x1,crop_y1,&x1,&y1); //x1 += user_movex; y1 += user_movey;
1410 state->transform(crop_x2,crop_y2,&x2,&y2); //x2 += user_movex; y2 += user_movey;
1412 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1413 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1416 /* apply user clip box */
1417 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1418 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1419 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1420 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1421 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1424 //msg("<verbose> Bounding box is (%f,%f)-(%f,%f) [shifted by %d/%d]", x1,y1,x2,y2, user_movex, user_movey);
1426 if(outer_clip_box) {
1427 output->endclip(output);
1431 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);
1433 msg("<verbose> page is rotated %d degrees\n", rot);
1435 clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1436 clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1437 clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1438 clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1439 clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1440 output->startclip(output, clippath); outer_clip_box = 1;
1441 output->fill(output, clippath, &white);
1444 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1446 msg("<debug> drawlink\n");
1447 double x1, y1, x2, y2, w;
1448 gfxline_t points[5];
1451 link->getRect(&x1, &y1, &x2, &y2);
1452 cvtUserToDev(x1, y1, &x, &y);
1453 points[0].type = gfx_moveTo;
1454 points[0].x = points[4].x = x + user_movex;
1455 points[0].y = points[4].y = y + user_movey;
1456 points[0].next = &points[1];
1457 cvtUserToDev(x2, y1, &x, &y);
1458 points[1].type = gfx_lineTo;
1459 points[1].x = x + user_movex;
1460 points[1].y = y + user_movey;
1461 points[1].next = &points[2];
1462 cvtUserToDev(x2, y2, &x, &y);
1463 points[2].type = gfx_lineTo;
1464 points[2].x = x + user_movex;
1465 points[2].y = y + user_movey;
1466 points[2].next = &points[3];
1467 cvtUserToDev(x1, y2, &x, &y);
1468 points[3].type = gfx_lineTo;
1469 points[3].x = x + user_movex;
1470 points[3].y = y + user_movey;
1471 points[3].next = &points[4];
1472 cvtUserToDev(x1, y1, &x, &y);
1473 points[4].type = gfx_lineTo;
1474 points[4].x = x + user_movex;
1475 points[4].y = y + user_movey;
1478 LinkAction*action=link->getAction();
1485 switch(action->getKind())
1489 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1490 LinkDest *dest=NULL;
1491 if (ha->getDest()==NULL)
1492 dest=catalog->findDest(ha->getNamedDest());
1493 else dest=ha->getDest();
1495 if (dest->isPageRef()){
1496 Ref pageref=dest->getPageRef();
1497 page=catalog->findPage(pageref.num,pageref.gen);
1499 else page=dest->getPageNum();
1500 sprintf(buf, "%d", page);
1507 LinkGoToR*l = (LinkGoToR*)action;
1508 GString*g = l->getNamedDest();
1510 s = strdup(g->getCString());
1515 LinkNamed*l = (LinkNamed*)action;
1516 GString*name = l->getName();
1518 s = strdup(name->lowerCase()->getCString());
1519 named = name->getCString();
1522 if(strstr(s, "next") || strstr(s, "forward"))
1524 page = currentpage + 1;
1526 else if(strstr(s, "prev") || strstr(s, "back"))
1528 page = currentpage - 1;
1530 else if(strstr(s, "last") || strstr(s, "end"))
1532 if(pages && pagepos>0)
1533 page = pages[pagepos-1];
1535 else if(strstr(s, "first") || strstr(s, "top"))
1543 case actionLaunch: {
1545 LinkLaunch*l = (LinkLaunch*)action;
1546 GString * str = new GString(l->getFileName());
1547 str->append(l->getParams());
1548 s = strdup(str->getCString());
1554 LinkURI*l = (LinkURI*)action;
1555 GString*g = l->getURI();
1557 url = g->getCString();
1562 case actionUnknown: {
1564 LinkUnknown*l = (LinkUnknown*)action;
1569 msg("<error> Unknown link type!\n");
1573 if(!s) s = strdup("-?-");
1575 if(!linkinfo && (page || url))
1577 msg("<notice> File contains links");
1585 for(t=1;t<=pagepos;t++) {
1586 if(pages[t]==page) {
1595 sprintf(buf, "page%d", lpage);
1596 output->drawlink(output, points, buf);
1600 output->drawlink(output, points, url);
1603 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1607 void SWFOutputDev::saveState(GfxState *state) {
1608 msg("<trace> saveState\n");
1611 msg("<error> Too many nested states in pdf.");
1615 states[statepos].clipping = 0; //? shouldn't this be the current value?
1616 states[statepos].textRender = states[statepos-1].textRender;
1619 void SWFOutputDev::restoreState(GfxState *state) {
1620 msg("<trace> restoreState\n");
1622 while(states[statepos].clipping) {
1623 output->endclip(output);
1624 states[statepos].clipping--;
1629 char* SWFOutputDev::searchFont(char*name)
1633 int is_standard_font = 0;
1635 msg("<verbose> SearchFont(%s)", name);
1637 /* see if it is a pdf standard font */
1638 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1640 if(!strcmp(name, pdf2t1map[i].pdffont))
1642 name = pdf2t1map[i].filename;
1643 is_standard_font = 1;
1647 /* look in all font files */
1648 for(i=0;i<fontnum;i++)
1650 if(strstr(fonts[i].filename, name))
1652 if(!fonts[i].used) {
1655 if(!is_standard_font)
1656 msg("<notice> Using %s for %s", fonts[i].filename, name);
1658 return strdup(fonts[i].filename);
1664 void SWFOutputDev::updateLineWidth(GfxState *state)
1666 double width = state->getTransformedLineWidth();
1667 //swfoutput_setlinewidth(&output, width);
1670 void SWFOutputDev::updateLineCap(GfxState *state)
1672 int c = state->getLineCap();
1675 void SWFOutputDev::updateLineJoin(GfxState *state)
1677 int j = state->getLineJoin();
1680 void SWFOutputDev::updateFillColor(GfxState *state)
1683 double opaq = state->getFillOpacity();
1684 state->getFillRGB(&rgb);
1686 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1689 void SWFOutputDev::updateStrokeColor(GfxState *state)
1692 double opaq = state->getStrokeOpacity();
1693 state->getStrokeRGB(&rgb);
1694 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1697 void FoFiWrite(void *stream, char *data, int len)
1699 fwrite(data, len, 1, (FILE*)stream);
1702 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1704 char*tmpFileName = NULL;
1710 Object refObj, strObj;
1712 tmpFileName = mktmpname(namebuf);
1715 ret = font->getEmbeddedFontID(&embRef);
1717 msg("<verbose> Didn't get embedded font id");
1718 /* not embedded- the caller should now search the font
1719 directories for this font */
1723 f = fopen(tmpFileName, "wb");
1725 msg("<error> Couldn't create temporary Type 1 font file");
1729 /*if(font->isCIDFont()) {
1730 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1731 GString c = cidFont->getCollection();
1732 msg("<notice> Collection: %s", c.getCString());
1735 //if (font->getType() == fontType1C) {
1736 if (0) { //font->getType() == fontType1C) {
1737 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1739 msg("<error> Couldn't read embedded font file");
1742 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1744 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1745 //cvt->convertToCIDType0("test", f);
1746 //cvt->convertToType0("test", f);
1749 } else if(font->getType() == fontTrueType) {
1750 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1751 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1753 msg("<error> Couldn't read embedded font file");
1756 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1757 cvt->writeTTF(FoFiWrite, f);
1761 font->getEmbeddedFontID(&embRef);
1762 refObj.initRef(embRef.num, embRef.gen);
1763 refObj.fetch(ref, &strObj);
1765 strObj.streamReset();
1770 f4[t] = strObj.streamGetChar();
1771 f4c[t] = (char)f4[t];
1776 if(!strncmp(f4c, "true", 4)) {
1777 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1778 Change this on the fly */
1779 f4[0] = f4[2] = f4[3] = 0;
1787 while ((c = strObj.streamGetChar()) != EOF) {
1791 strObj.streamClose();
1796 return strdup(tmpFileName);
1799 char* searchForSuitableFont(GfxFont*gfxFont)
1801 char*name = getFontName(gfxFont);
1805 if(!config_use_fontconfig)
1808 #ifdef HAVE_FONTCONFIG
1809 FcPattern *pattern, *match;
1813 static int fcinitcalled = false;
1815 msg("<debug> searchForSuitableFont(%s)", name);
1817 // call init ony once
1818 if (!fcinitcalled) {
1819 msg("<debug> Initializing FontConfig...");
1820 fcinitcalled = true;
1822 msg("<debug> FontConfig Initialization failed. Disabling.");
1823 config_use_fontconfig = 0;
1826 msg("<debug> ...initialized FontConfig");
1829 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1830 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1831 if (gfxFont->isItalic()) // check for italic
1832 msg("<debug> FontConfig: Adding Italic Slant");
1833 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1834 if (gfxFont->isBold()) // check for bold
1835 msg("<debug> FontConfig: Adding Bold Weight");
1836 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1838 msg("<debug> FontConfig: Try to match...");
1839 // configure and match using the original font name
1840 FcConfigSubstitute(0, pattern, FcMatchPattern);
1841 FcDefaultSubstitute(pattern);
1842 match = FcFontMatch(0, pattern, &result);
1844 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1845 msg("<debug> FontConfig: family=%s", (char*)v);
1846 // if we get an exact match
1847 if (strcmp((char *)v, name) == 0) {
1848 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1849 filename = strdup((char*)v); // mem leak
1850 char *nfn = strrchr(filename, '/');
1851 if(nfn) fontname = strdup(nfn+1);
1852 else fontname = filename;
1854 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1856 // initialize patterns
1857 FcPatternDestroy(pattern);
1858 FcPatternDestroy(match);
1860 // now match against serif etc.
1861 if (gfxFont->isSerif()) {
1862 msg("<debug> FontConfig: Create Serif Family Pattern");
1863 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1864 } else if (gfxFont->isFixedWidth()) {
1865 msg("<debug> FontConfig: Create Monospace Family Pattern");
1866 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1868 msg("<debug> FontConfig: Create Sans Family Pattern");
1869 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1873 if (gfxFont->isItalic()) {
1874 msg("<debug> FontConfig: Adding Italic Slant");
1875 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1878 if (gfxFont->isBold()) {
1879 msg("<debug> FontConfig: Adding Bold Weight");
1880 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1883 msg("<debug> FontConfig: Try to match... (2)");
1884 // configure and match using serif etc
1885 FcConfigSubstitute (0, pattern, FcMatchPattern);
1886 FcDefaultSubstitute (pattern);
1887 match = FcFontMatch (0, pattern, &result);
1889 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1890 filename = strdup((char*)v); // mem leak
1891 char *nfn = strrchr(filename, '/');
1892 if(nfn) fontname = strdup(nfn+1);
1893 else fontname = filename;
1895 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1899 //printf("FONTCONFIG: pattern");
1900 //FcPatternPrint(pattern);
1901 //printf("FONTCONFIG: match");
1902 //FcPatternPrint(match);
1904 FcPatternDestroy(pattern);
1905 FcPatternDestroy(match);
1907 pdfswf_addfont(filename);
1914 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1916 char*fontname = 0, *filename = 0;
1917 msg("<notice> substituteFont(%s)", oldname);
1919 if(!(fontname = searchForSuitableFont(gfxFont))) {
1920 fontname = "Times-Roman";
1922 filename = searchFont(fontname);
1924 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1928 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1929 msg("<fatal> Too many fonts in file.");
1933 substitutesource[substitutepos] = strdup(oldname); //mem leak
1934 substitutetarget[substitutepos] = fontname;
1935 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1938 return strdup(filename); //mem leak
1941 void unlinkfont(char* filename)
1948 if(!strncmp(&filename[l-4],".afm",4)) {
1949 memcpy(&filename[l-4],".pfb",4);
1951 memcpy(&filename[l-4],".pfa",4);
1953 memcpy(&filename[l-4],".afm",4);
1956 if(!strncmp(&filename[l-4],".pfa",4)) {
1957 memcpy(&filename[l-4],".afm",4);
1959 memcpy(&filename[l-4],".pfa",4);
1962 if(!strncmp(&filename[l-4],".pfb",4)) {
1963 memcpy(&filename[l-4],".afm",4);
1965 memcpy(&filename[l-4],".pfb",4);
1970 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1976 int SWFOutputDev::setGfxFont(char*id, char*filename, double maxSize)
1979 fontlist_t*last=0,*l = this->fontlist;
1981 /* TODO: should this be part of the state? */
1984 if(!strcmp(l->id, id)) {
1985 current_font_id = l->id;
1986 current_gfxfont = l->font;
1988 output->addfont(output, id, current_gfxfont);
1993 if(!filename) return 0;
1995 /* A font size of e.g. 9 means the font will be scaled down by
1996 1024 and scaled up by 9. So to have a maximum error of 1/20px,
1997 we have to divide 0.05 by (fontsize/1024)
1999 double quality = (1024 * 0.05) / maxSize;
2001 msg("<verbose> Loading %s...", filename);
2002 font = gfxfont_load(filename, quality);
2003 msg("<verbose> Font %s loaded successfully", filename);
2007 l->filename = strdup(filename);
2010 current_font_id = l->id;
2011 current_gfxfont = l->font;
2017 output->addfont(output, id, current_gfxfont);
2021 void SWFOutputDev::updateFont(GfxState *state)
2023 GfxFont*gfxFont = state->getFont();
2028 char * fontid = getFontID(gfxFont);
2029 double maxSize = 1.0;
2032 maxSize = this->info->getMaximumFontSize(fontid);
2036 /* first, look if we substituted this font before-
2037 this way, we don't initialize the T1 Fonts
2039 for(t=0;t<substitutepos;t++) {
2040 if(!strcmp(fontid, substitutesource[t])) {
2041 free(fontid);fontid=0;
2042 fontid = strdup(substitutetarget[t]);
2047 /* second, see if this is a font which was used before-
2048 if so, we are done */
2049 if(setGfxFont(fontid, 0, 0)) {
2053 /* if(swfoutput_queryfont(&output, fontid))
2054 swfoutput_setfont(&output, fontid, 0);
2056 msg("<debug> updateFont(%s) [cached]", fontid);
2060 // look for Type 3 font
2061 if (gfxFont->getType() == fontType3) {
2063 type3Warning = gTrue;
2064 showFontError(gfxFont, 2);
2070 /* now either load the font, or find a substitution */
2073 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
2078 (gfxFont->getType() == fontType1 ||
2079 gfxFont->getType() == fontType1C ||
2080 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
2081 gfxFont->getType() == fontTrueType ||
2082 gfxFont->getType() == fontCIDType2
2085 fileName = writeEmbeddedFontToFile(xref, gfxFont);
2086 if(!fileName) showFontError(gfxFont,0);
2089 char * fontname = getFontName(gfxFont);
2090 fileName = searchFont(fontname);
2091 if(!fileName) showFontError(gfxFont,0);
2095 char * fontname = getFontName(gfxFont);
2096 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
2099 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into %s", fontname, lastfontdir);
2101 msg("<warning> Try specifying one or more font directories");
2103 fileName = substituteFont(gfxFont, fontid);
2104 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
2105 msg("<notice> Font is now %s (%s)", fontid, fileName);
2109 msg("<error> Couldn't set font %s\n", fontid);
2114 msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
2115 dumpFontInfo("<verbose>", gfxFont);
2117 //swfoutput_setfont(&output, fontid, fileName);
2119 if(!setGfxFont(fontid, 0, 0)) {
2120 setGfxFont(fontid, fileName, maxSize);
2124 unlinkfont(fileName);
2132 #define SQR(x) ((x)*(x))
2134 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
2136 if((newwidth<2 || newheight<2) ||
2137 (width<=newwidth || height<=newheight))
2139 unsigned char*newdata;
2141 newdata= (unsigned char*)malloc(newwidth*newheight);
2143 double fx = (double)(width)/newwidth;
2144 double fy = (double)(height)/newheight;
2146 int blocksize = (int)(8192/(fx*fy));
2147 int r = 8192*256/palettesize;
2148 for(x=0;x<newwidth;x++) {
2149 double ex = px + fx;
2150 int fromx = (int)px;
2152 int xweight1 = (int)(((fromx+1)-px)*256);
2153 int xweight2 = (int)((ex-tox)*256);
2155 for(y=0;y<newheight;y++) {
2156 double ey = py + fy;
2157 int fromy = (int)py;
2159 int yweight1 = (int)(((fromy+1)-py)*256);
2160 int yweight2 = (int)((ey-toy)*256);
2163 for(xx=fromx;xx<=tox;xx++)
2164 for(yy=fromy;yy<=toy;yy++) {
2165 int b = 1-data[width*yy+xx];
2167 if(xx==fromx) weight = (weight*xweight1)/256;
2168 if(xx==tox) weight = (weight*xweight2)/256;
2169 if(yy==fromy) weight = (weight*yweight1)/256;
2170 if(yy==toy) weight = (weight*yweight2)/256;
2173 //if(a) a=(palettesize-1)*r/blocksize;
2174 newdata[y*newwidth+x] = (a*blocksize)/r;
2182 #define IMAGE_TYPE_JPEG 0
2183 #define IMAGE_TYPE_LOSSLESS 1
2185 static void drawimage(gfxdevice_t*dev, gfxcolor_t* data, int sizex,int sizey,
2186 double x1,double y1,
2187 double x2,double y2,
2188 double x3,double y3,
2189 double x4,double y4, int type)
2191 gfxcolor_t*newpic=0;
2193 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2194 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2196 gfxline_t p1,p2,p3,p4,p5;
2197 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2198 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2199 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2200 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2201 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2203 {p1.x = (int)(p1.x*20)/20.0;
2204 p1.y = (int)(p1.y*20)/20.0;
2205 p2.x = (int)(p2.x*20)/20.0;
2206 p2.y = (int)(p2.y*20)/20.0;
2207 p3.x = (int)(p3.x*20)/20.0;
2208 p3.y = (int)(p3.y*20)/20.0;
2209 p4.x = (int)(p4.x*20)/20.0;
2210 p4.y = (int)(p4.y*20)/20.0;
2211 p5.x = (int)(p5.x*20)/20.0;
2212 p5.y = (int)(p5.y*20)/20.0;
2219 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2220 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2225 img.data = (gfxcolor_t*)data;
2229 if(type == IMAGE_TYPE_JPEG)
2230 /* TODO: pass image_dpi to device instead */
2231 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2233 dev->fillbitmap(dev, &p1, &img, &m, 0);
2236 void drawimagejpeg(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2237 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2239 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2242 void drawimagelossless(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2243 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2245 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2249 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2250 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2251 GBool inlineImg, int mask, int*maskColors,
2252 Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GfxImageColorMap*maskColorMap)
2254 double x1,y1,x2,y2,x3,y3,x4,y4;
2255 ImageStream *imgStr;
2260 unsigned char* maskbitmap = 0;
2263 ncomps = colorMap->getNumPixelComps();
2264 bits = colorMap->getBits();
2269 unsigned char buf[8];
2270 maskbitmap = (unsigned char*)malloc(maskHeight*maskWidth);
2272 ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, maskColorMap->getNumPixelComps(), maskColorMap->getBits());
2273 imgMaskStr->reset();
2274 unsigned char pal[256];
2275 int n = 1 << colorMap->getBits();
2280 maskColorMap->getGray(pixBuf, &gray);
2281 pal[t] = colToByte(gray);
2283 for (y = 0; y < maskHeight; y++) {
2284 for (x = 0; x < maskWidth; x++) {
2285 imgMaskStr->getPixel(buf);
2286 maskbitmap[y*maskWidth+x] = pal[buf[0]];
2291 ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, 1, 1);
2292 imgMaskStr->reset();
2293 for (y = 0; y < maskHeight; y++) {
2294 for (x = 0; x < maskWidth; x++) {
2295 imgMaskStr->getPixel(buf);
2297 maskbitmap[y*maskWidth+x] = (buf[0]^1)*255;
2304 imgStr = new ImageStream(str, width, ncomps,bits);
2307 if(!width || !height || (height<=1 && width<=1))
2309 msg("<verbose> Ignoring %d by %d image", width, height);
2310 unsigned char buf[8];
2312 for (y = 0; y < height; ++y)
2313 for (x = 0; x < width; ++x) {
2314 imgStr->getPixel(buf);
2322 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1 += user_movey;
2323 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2 += user_movey;
2324 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3 += user_movey;
2325 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4 += user_movey;
2327 if(!pbminfo && !(str->getKind()==strDCT)) {
2329 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2333 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2335 if(!jpeginfo && (str->getKind()==strDCT)) {
2336 msg("<notice> file contains jpeg pictures");
2342 unsigned char buf[8];
2344 unsigned char*pic = new unsigned char[width*height];
2345 gfxcolor_t pal[256];
2347 state->getFillRGB(&rgb);
2349 memset(pal,255,sizeof(pal));
2350 pal[0].r = (int)(colToByte(rgb.r)); pal[1].r = 0;
2351 pal[0].g = (int)(colToByte(rgb.g)); pal[1].g = 0;
2352 pal[0].b = (int)(colToByte(rgb.b)); pal[1].b = 0;
2353 pal[0].a = 255; pal[1].a = 0;
2356 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2357 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2358 for (y = 0; y < height; ++y)
2359 for (x = 0; x < width; ++x)
2361 imgStr->getPixel(buf);
2364 pic[width*y+x] = buf[0];
2367 /* the size of the drawn image is added to the identifier
2368 as the same image may require different bitmaps if displayed
2369 at different sizes (due to antialiasing): */
2372 unsigned char*pic2 = 0;
2375 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2384 height = realheight;
2388 /* make a black/white palette */
2390 float r = 255/(numpalette-1);
2392 for(t=0;t<numpalette;t++) {
2393 pal[t].r = colToByte(rgb.r);
2394 pal[t].g = colToByte(rgb.g);
2395 pal[t].b = colToByte(rgb.b);
2396 pal[t].a = (unsigned char)(t*r);
2400 gfxcolor_t*pic2 = new gfxcolor_t[width*height];
2401 for (y = 0; y < height; ++y) {
2402 for (x = 0; x < width; ++x) {
2403 pic2[width*y+x] = pal[pic[y*width+x]];
2406 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2410 if(maskbitmap) free(maskbitmap);
2416 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2417 gfxcolor_t*pic=new gfxcolor_t[width*height];
2418 for (y = 0; y < height; ++y) {
2419 for (x = 0; x < width; ++x) {
2420 imgStr->getPixel(pixBuf);
2421 colorMap->getRGB(pixBuf, &rgb);
2422 pic[width*y+x].r = (unsigned char)(colToByte(rgb.r));
2423 pic[width*y+x].g = (unsigned char)(colToByte(rgb.g));
2424 pic[width*y+x].b = (unsigned char)(colToByte(rgb.b));
2425 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2427 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2431 if(str->getKind()==strDCT)
2432 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2434 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2437 if(maskbitmap) free(maskbitmap);
2440 gfxcolor_t*pic=new gfxcolor_t[width*height];
2441 gfxcolor_t pal[256];
2442 int n = 1 << colorMap->getBits();
2444 for(t=0;t<256;t++) {
2446 colorMap->getRGB(pixBuf, &rgb);
2448 {/*if(maskColors && *maskColors==t) {
2449 msg("<notice> Color %d is transparent", t);
2450 if (imgData->maskColors) {
2452 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2453 if (pix[i] < imgData->maskColors[2*i] ||
2454 pix[i] > imgData->maskColors[2*i+1]) {
2469 pal[t].r = (unsigned char)(colToByte(rgb.r));
2470 pal[t].g = (unsigned char)(colToByte(rgb.g));
2471 pal[t].b = (unsigned char)(colToByte(rgb.b));
2472 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2475 for (y = 0; y < height; ++y) {
2476 for (x = 0; x < width; ++x) {
2477 imgStr->getPixel(pixBuf);
2478 pic[width*y+x] = pal[pixBuf[0]];
2480 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2484 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2488 if(maskbitmap) free(maskbitmap);
2493 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2494 int width, int height, GBool invert,
2497 if(states[statepos].textRender & 4) //clipped
2499 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2500 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0, 0,0,0,0, 0);
2503 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2504 int width, int height, GfxImageColorMap *colorMap,
2505 int *maskColors, GBool inlineImg)
2507 if(states[statepos].textRender & 4) //clipped
2510 msg("<verbose> drawImage %dx%d, %s, %s, inline=%d", width, height,
2511 colorMap?"colorMap":"no colorMap",
2512 maskColors?"maskColors":"no maskColors",
2515 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2516 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2517 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors, 0,0,0,0, 0);
2520 void SWFOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
2521 int width, int height,
2522 GfxImageColorMap *colorMap,
2523 Stream *maskStr, int maskWidth, int maskHeight,
2526 if(states[statepos].textRender & 4) //clipped
2529 msg("<verbose> drawMaskedImage %dx%d, %s, %dx%d mask", width, height,
2530 colorMap?"colorMap":"no colorMap",
2531 maskWidth, maskHeight);
2533 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2534 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2535 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, maskInvert, 0);
2538 void SWFOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
2539 int width, int height,
2540 GfxImageColorMap *colorMap,
2542 int maskWidth, int maskHeight,
2543 GfxImageColorMap *maskColorMap)
2545 if(states[statepos].textRender & 4) //clipped
2548 msg("<verbose> drawSoftMaskedImage %dx%d, %s, %dx%d mask", width, height,
2549 colorMap?"colorMap":"no colorMap",
2550 maskWidth, maskHeight);
2552 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2553 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2554 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, 0, maskColorMap);
2557 //SWFOutputDev*output = 0;
2559 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2564 if (infoDict->lookup(key, &obj)->isString()) {
2565 s1 = obj.getString();
2566 if ((s1->getChar(0) & 0xff) == 0xfe &&
2567 (s1->getChar(1) & 0xff) == 0xff) {
2569 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2570 if (s1->getChar(i) == '\0') {
2571 s2->append(s1->getChar(i+1));
2574 s2 = new GString("<unicode>");
2578 printf(fmt, s2->getCString());
2581 printf(fmt, s1->getCString());
2587 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2591 if (infoDict->lookup(key, &obj)->isString()) {
2592 s = obj.getString()->getCString();
2593 if (s[0] == 'D' && s[1] == ':') {
2604 void storeDeviceParameter(char*name, char*value)
2606 parameter_t*p = new parameter_t();
2607 p->name = strdup(name);
2608 p->value = strdup(value);
2610 if(device_config_next) {
2611 device_config_next->next = p;
2612 device_config_next = p;
2615 device_config_next = p;
2619 void pdfswf_setparameter(char*name, char*value)
2621 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2622 if(!strcmp(name, "caplinewidth")) {
2623 caplinewidth = atof(value);
2624 } else if(!strcmp(name, "zoom")) {
2627 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2628 storeDeviceParameter("jpegsubpixels", buf);
2629 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2630 storeDeviceParameter("ppmsubpixels", buf);
2631 } else if(!strcmp(name, "jpegdpi")) {
2633 jpeg_dpi = atoi(value);
2634 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2635 storeDeviceParameter("jpegsubpixels", buf);
2636 } else if(!strcmp(name, "ppmdpi")) {
2638 ppm_dpi = atoi(value);
2639 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2640 storeDeviceParameter("ppmsubpixels", buf);
2641 } else if(!strcmp(name, "forceType0Fonts")) {
2642 forceType0Fonts = atoi(value);
2643 } else if(!strncmp(name, "fontdir", strlen("fontdir"))) {
2644 pdfswf_addfontdir(value);
2645 } else if(!strncmp(name, "languagedir", strlen("languagedir"))) {
2646 pdfswf_addlanguagedir(value);
2647 } else if(!strcmp(name, "fontconfig")) {
2648 config_use_fontconfig = atoi(value);
2650 storeDeviceParameter(name,value);
2653 void pdfswf_addfont(char*filename)
2656 memset(&f, 0, sizeof(fontfile_t));
2657 f.filename = filename;
2658 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2659 fonts[fontnum++] = f;
2661 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2665 static char* dirseparator()
2674 void pdfswf_addlanguagedir(char*dir)
2677 globalParams = new GlobalParams("");
2679 msg("<notice> Adding %s to language pack directories", dir);
2683 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2684 strcpy(config_file, dir);
2685 strcat(config_file, dirseparator());
2686 strcat(config_file, "add-to-xpdfrc");
2688 fi = fopen(config_file, "rb");
2690 msg("<error> Could not open %s", config_file);
2693 globalParams->parseFile(new GString(config_file), fi);
2697 void pdfswf_addfontdir(char*dirname)
2699 #ifdef HAVE_DIRENT_H
2700 msg("<notice> Adding %s to font directories", dirname);
2701 lastfontdir = strdup(dirname);
2702 DIR*dir = opendir(dirname);
2704 msg("<warning> Couldn't open directory %s\n", dirname);
2709 ent = readdir (dir);
2713 char*name = ent->d_name;
2719 if(!strncasecmp(&name[l-4], ".pfa", 4))
2721 if(!strncasecmp(&name[l-4], ".pfb", 4))
2723 if(!strncasecmp(&name[l-4], ".ttf", 4))
2727 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2728 strcpy(fontname, dirname);
2729 strcat(fontname, dirseparator());
2730 strcat(fontname, name);
2731 msg("<verbose> Adding %s to fonts", fontname);
2732 pdfswf_addfont(fontname);
2737 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2742 typedef struct _pdf_doc_internal
2747 } pdf_doc_internal_t;
2748 typedef struct _pdf_page_internal
2750 } pdf_page_internal_t;
2751 typedef struct _swf_output_internal
2753 SWFOutputDev*outputDev;
2754 } swf_output_internal_t;
2756 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2758 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2759 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2760 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2761 memset(i, 0, sizeof(pdf_doc_internal_t));
2762 pdf_doc->internal = i;
2764 GString *fileName = new GString(filename);
2770 globalParams = new GlobalParams("");
2773 if (userPassword && userPassword[0]) {
2774 userPW = new GString(userPassword);
2778 i->doc = new PDFDoc(fileName, userPW);
2782 if (!i->doc->isOk()) {
2787 i->doc->getDocInfo(&info);
2788 if (info.isDict() &&
2789 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2790 printInfoString(info.getDict(), "Title", "Title: %s\n");
2791 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2792 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2793 printInfoString(info.getDict(), "Author", "Author: %s\n");
2794 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2795 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2796 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2797 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2798 printf("Pages: %d\n", i->doc->getNumPages());
2799 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2800 printf("Encrypted: ");
2801 if (i->doc->isEncrypted()) {
2802 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2803 i->doc->okToPrint() ? "yes" : "no",
2804 i->doc->okToCopy() ? "yes" : "no",
2805 i->doc->okToChange() ? "yes" : "no",
2806 i->doc->okToAddNotes() ? "yes" : "no");
2813 pdf_doc->num_pages = i->doc->getNumPages();
2815 if (i->doc->isEncrypted()) {
2816 if(!i->doc->okToCopy()) {
2817 printf("PDF disallows copying.\n");
2820 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2824 InfoOutputDev*io = new InfoOutputDev();
2826 for(t=1;t<=pdf_doc->num_pages;t++) {
2827 i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, /*usemediabox*/true, /*crop*/true, /*doLinks*/(int)1);
2838 delete globalParams;globalParams=0;
2839 Object::memCheck(stderr);
2844 void pdf_destroy(pdf_doc_t*pdf_doc)
2846 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2848 delete i->doc; i->doc=0;
2851 delete i->info;i->info=0;
2854 free(pdf_doc->internal);pdf_doc->internal=0;
2855 free(pdf_doc);pdf_doc=0;
2858 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2860 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2862 if(page < 1 || page > pdf_doc->num_pages)
2865 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2866 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2867 memset(pi, 0, sizeof(pdf_page_internal_t));
2868 pdf_page->internal = pi;
2870 pdf_page->parent = pdf_doc;
2871 pdf_page->nr = page;
2875 void pdf_page_destroy(pdf_page_t*pdf_page)
2877 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2878 free(pdf_page->internal);pdf_page->internal = 0;
2879 free(pdf_page);pdf_page=0;
2882 swf_output_t* swf_output_init()
2884 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2885 memset(swf_output, 0, sizeof(swf_output_t));
2886 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2887 memset(i, 0, sizeof(swf_output_internal_t));
2888 swf_output->internal = i;
2890 i->outputDev = new SWFOutputDev();
2894 void swf_output_setparameter(swf_output_t*swf, char*name, char*value)
2896 pdfswf_setparameter(name, value);
2899 void swf_output_startframe(swf_output_t*swf, int width, int height)
2901 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2902 i->outputDev->startFrame(width, height);
2905 void swf_output_endframe(swf_output_t*swf)
2907 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2908 i->outputDev->endframe();
2911 void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage)
2913 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2914 SWFOutputDev*o = i->outputDev;
2920 o->pagebuflen = 1024;
2921 o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
2922 memset(o->pages, -1, o->pagebuflen*sizeof(int));
2924 while(pdfpage >= o->pagebuflen)
2926 int oldlen = o->pagebuflen;
2927 o->pagebuflen+=1024;
2928 o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
2929 memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
2932 o->pages[pdfpage] = outputpage;
2933 if(pdfpage>o->pagepos)
2934 o->pagepos = pdfpage;
2937 int swf_output_save(swf_output_t*swf, char*filename)
2939 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2940 int ret = i->outputDev->save(filename);
2944 void* swf_output_get(swf_output_t*swf,char*name)
2946 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2947 void* ret = i->outputDev->get(name);
2951 void swf_output_destroy(swf_output_t*output)
2953 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2954 delete i->outputDev; i->outputDev=0;
2955 free(output->internal);output->internal=0;
2959 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2961 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2962 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2965 msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2970 gfxdevice_t*dev = si->outputDev->output;
2971 dev->setparameter(dev, "protect", "1");
2973 si->outputDev->setInfo(pi->info);
2974 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2975 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
2978 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2980 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2981 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2983 si->outputDev->setMove(x,y);
2984 if((x1|y1|x2|y2)==0) x2++;
2985 si->outputDev->setClip(x1,y1,x2,y2);
2987 pdf_page_render2(page, output);
2989 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2991 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2992 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2994 si->outputDev->setMove(0,0);
2995 si->outputDev->setClip(0,0,0,0);
2997 pdf_page_render2(page, output);
3001 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
3003 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
3004 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
3005 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
3006 memset(info, 0, sizeof(pdf_page_info_t));
3008 InfoOutputDev*output = new InfoOutputDev;
3010 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
3012 info->xMin = output->x1;
3013 info->yMin = output->y1;
3014 info->xMax = output->x2;
3015 info->yMax = output->y2;
3016 info->number_of_images = output->num_images;
3017 info->number_of_links = output->num_links;
3018 info->number_of_fonts = output->num_fonts;
3025 void pdf_page_info_destroy(pdf_page_info_t*info)