2 implements a pdf output device (OutputDev).
4 This file is part of swftools.
6 Swftools is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 Swftools is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with swftools; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
25 #include "../config.h"
29 #ifdef HAVE_SYS_STAT_H
32 #ifdef HAVE_FONTCONFIG
33 #include <fontconfig.h>
50 #include "OutputDev.h"
53 #include "CharCodeToUnicode.h"
54 #include "NameToUnicodeTable.h"
55 #include "GlobalParams.h"
56 #include "FoFiType1C.h"
57 #include "FoFiTrueType.h"
59 #include "SWFOutputDev.h"
61 //swftools header files
62 #include "../lib/devices/swf.h"
63 #include "../lib/log.h"
64 #include "../lib/gfxdevice.h"
65 #include "../lib/gfxtools.h"
66 #include "../lib/gfxfont.h"
70 typedef struct _fontfile
76 typedef struct _parameter
80 struct _parameter*next;
83 static parameter_t* device_config = 0;
84 static parameter_t* device_config_next = 0;
87 static fontfile_t fonts[2048];
88 static int fontnum = 0;
90 static int config_use_fontconfig = 1;
93 static double caplinewidth = 3.0;
94 static double zoom = 72; /* xpdf: 86 */
95 static int forceType0Fonts = 1;
97 static void printInfoString(Dict *infoDict, char *key, char *fmt);
98 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
100 static char* lastfontdir = 0;
106 {"Times-Roman", "n021003l"},
107 {"Times-Italic", "n021023l"},
108 {"Times-Bold", "n021004l"},
109 {"Times-BoldItalic", "n021024l"},
110 {"Helvetica", "n019003l"},
111 {"Helvetica-Oblique", "n019023l"},
112 {"Helvetica-Bold", "n019004l"},
113 {"Helvetica-BoldOblique", "n019024l"},
114 {"Courier", "n022003l"},
115 {"Courier-Oblique", "n022023l"},
116 {"Courier-Bold", "n022004l"},
117 {"Courier-BoldOblique", "n022024l"},
118 {"Symbol", "s050000l"},
119 {"ZapfDingbats", "d050000l"}};
121 class SWFOutputState {
127 this->textRender = 0;
131 typedef struct _fontlist
141 class SWFOutputDev: public OutputDev {
149 virtual ~SWFOutputDev() ;
151 void setMove(int x,int y);
152 void setClip(int x1,int y1,int x2,int y2);
154 void setInfo(InfoOutputDev*info) {this->info = info;}
156 int save(char*filename);
159 void startFrame(int width, int height);
161 virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
164 void* get(char*name);
166 //----- get info about output device
168 // Does this device use upside-down coordinates?
169 // (Upside-down means (0,0) is the top left corner of the page.)
170 virtual GBool upsideDown();
172 // Does this device use drawChar() or drawString()?
173 virtual GBool useDrawChar();
175 // Can this device draw gradients?
176 virtual GBool useGradients();
178 virtual GBool interpretType3Chars() {return gTrue;}
180 //----- initialization and control
182 void setXRef(PDFDoc*doc, XRef *xref);
185 virtual void drawLink(Link *link, Catalog *catalog) ;
187 //----- save/restore graphics state
188 virtual void saveState(GfxState *state) ;
189 virtual void restoreState(GfxState *state) ;
191 //----- update graphics state
193 virtual void updateFont(GfxState *state);
194 virtual void updateFillColor(GfxState *state);
195 virtual void updateStrokeColor(GfxState *state);
196 virtual void updateLineWidth(GfxState *state);
197 virtual void updateLineJoin(GfxState *state);
198 virtual void updateLineCap(GfxState *state);
200 virtual void updateAll(GfxState *state)
203 updateFillColor(state);
204 updateStrokeColor(state);
205 updateLineWidth(state);
206 updateLineJoin(state);
207 updateLineCap(state);
210 //----- path painting
211 virtual void stroke(GfxState *state) ;
212 virtual void fill(GfxState *state) ;
213 virtual void eoFill(GfxState *state) ;
215 //----- path clipping
216 virtual void clip(GfxState *state) ;
217 virtual void eoClip(GfxState *state) ;
220 virtual void beginString(GfxState *state, GString *s) ;
221 virtual void endString(GfxState *state) ;
222 virtual void endTextObject(GfxState *state);
223 virtual void drawChar(GfxState *state, double x, double y,
224 double dx, double dy,
225 double originX, double originY,
226 CharCode code, int nBytes, Unicode *u, int uLen);
228 //----- image drawing
229 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
230 int width, int height, GBool invert,
232 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
233 int width, int height, GfxImageColorMap *colorMap,
234 int *maskColors, GBool inlineImg);
235 virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
236 int width, int height,
237 GfxImageColorMap *colorMap,
238 Stream *maskStr, int maskWidth, int maskHeight,
240 virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
241 int width, int height,
242 GfxImageColorMap *colorMap,
244 int maskWidth, int maskHeight,
245 GfxImageColorMap *maskColorMap);
247 virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
248 virtual void endType3Char(GfxState *state);
250 virtual void type3D0(GfxState *state, double wx, double wy);
251 virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
254 void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
255 int width, int height, GfxImageColorMap*colorMap, GBool invert,
256 GBool inlineImg, int mask, int *maskColors,
257 Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GfxImageColorMap*maskColorMap);
258 int SWFOutputDev::setGfxFont(char*id, char*name, char*filename, double quality);
259 void strokeGfxline(GfxState *state, gfxline_t*line);
260 void clipToGfxLine(GfxState *state, gfxline_t*line);
261 void fillGfxLine(GfxState *state, gfxline_t*line);
265 gfxresult_t*result; //filled when complete
267 char outer_clip_box; //whether the page clip box is still on
270 SWFOutputState states[64];
278 char* searchFont(char*name);
279 char* substituteFont(GfxFont*gfxFont, char*oldname);
280 char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
282 int textmodeinfo; // did we write "Text will be rendered as polygon" yet?
283 int jpeginfo; // did we write "File contains jpegs" yet?
284 int pbminfo; // did we write "File contains jpegs" yet?
285 int linkinfo; // did we write "File contains links" yet?
286 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
287 int gradientinfo; // did we write "File contains Gradients yet?
289 int type3active; // are we between beginType3()/endType3()?
295 char* substitutetarget[256];
296 char* substitutesource[256];
299 int user_movex,user_movey;
300 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
302 gfxline_t* current_text_stroke;
303 gfxline_t* current_text_clip;
304 char* current_font_id;
305 gfxfont_t* current_gfxfont;
306 gfxmatrix_t current_font_matrix;
308 fontlist_t* fontlist;
314 friend void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage);
317 typedef struct _drawnchar
335 chars = (drawnchar_t*)malloc(sizeof(drawnchar_t)*buf_size);
336 memset(chars, 0, sizeof(drawnchar_t)*buf_size);
341 free(chars);chars = 0;
348 chars = (drawnchar_t*)realloc(chars, sizeof(drawnchar_t)*buf_size);
352 void addChar(int charid, gfxcoord_t x, gfxcoord_t y, gfxcolor_t color)
355 chars[num_chars].x = x;
356 chars[num_chars].y = y;
357 chars[num_chars].color = color;
358 chars[num_chars].charid = charid;
362 static char*getFontID(GfxFont*font);
370 class InfoOutputDev: public OutputDev
373 FontInfo* currentfont;
385 id2font = new GHash();
387 virtual ~InfoOutputDev()
391 virtual GBool upsideDown() {return gTrue;}
392 virtual GBool useDrawChar() {return gTrue;}
393 virtual GBool useGradients() {return gTrue;}
394 virtual GBool interpretType3Chars() {return gTrue;}
395 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
398 state->transform(crop_x1,crop_y1,&x1,&y1);
399 state->transform(crop_x2,crop_y2,&x2,&y2);
400 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
401 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
407 virtual void drawLink(Link *link, Catalog *catalog)
411 virtual double getMaximumFontSize(char*id)
413 FontInfo*info = (FontInfo*)id2font->lookup(id);
415 msg("<error> Unknown font id: %s", id);
418 return info->max_size;
421 virtual void updateFont(GfxState *state)
423 GfxFont*font = state->getFont();
426 char*id = getFontID(font);
428 FontInfo*info = (FontInfo*)id2font->lookup(id);
430 GString* idStr = new GString(id);
434 id2font->add(idStr, (void*)info);
441 virtual void drawChar(GfxState *state, double x, double y,
442 double dx, double dy,
443 double originX, double originY,
444 CharCode code, int nBytes, Unicode *u, int uLen)
446 int render = state->getRender();
449 double m11,m21,m12,m22;
450 state->getFontTransMat(&m11, &m12, &m21, &m22);
451 m11 *= state->getHorizScaling();
452 m21 *= state->getHorizScaling();
453 double lenx = sqrt(m11*m11 + m12*m12);
454 double leny = sqrt(m21*m21 + m22*m22);
455 double len = lenx>leny?lenx:leny;
456 if(currentfont && currentfont->max_size < len) {
457 currentfont->max_size = len;
460 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
461 int width, int height, GBool invert,
466 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
467 int width, int height, GfxImageColorMap *colorMap,
468 int *maskColors, GBool inlineImg)
474 SWFOutputDev::SWFOutputDev()
492 current_text_stroke = 0;
493 current_text_clip = 0;
500 output = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
501 gfxdevice_swf_init(output);
502 /* configure device */
503 parameter_t*p = device_config;
505 output->setparameter(output, p->name, p->value);
510 void SWFOutputDev::setMove(int x,int y)
512 this->user_movex = x;
513 this->user_movey = y;
516 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
518 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
519 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
521 this->user_clipx1 = x1;
522 this->user_clipy1 = y1;
523 this->user_clipx2 = x2;
524 this->user_clipy2 = y2;
527 static char*getFontID(GfxFont*font)
529 Ref*ref = font->getID();
530 GString*gstr = font->getName();
531 char* fname = gstr==0?0:gstr->getCString();
534 sprintf(buf, "font-%d-%d", ref->num, ref->gen);
536 sprintf(buf, "%s-%d-%d", fname, ref->num, ref->gen);
541 static char*getFontName(GfxFont*font)
544 GString*gstr = font->getName();
545 char* fname = gstr==0?0:gstr->getCString();
549 sprintf(buf, "UFONT%d", r->num);
550 fontid = strdup(buf);
552 fontid = strdup(fname);
555 char* plus = strchr(fontid, '+');
556 if(plus && plus < &fontid[strlen(fontid)-1]) {
557 fontname = strdup(plus+1);
559 fontname = strdup(fontid);
565 static char mybuf[1024];
566 static char* gfxstate2str(GfxState *state)
570 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
577 if(state->getX1()!=0.0)
578 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
579 if(state->getY1()!=0.0)
580 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
581 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
582 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
583 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
584 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
585 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
586 state->getFillColor()->c[0], state->getFillColor()->c[1]);
587 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
588 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
589 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
590 state->getFillColor()->c[0], state->getFillColor()->c[1],
591 state->getFillColor()->c[2], state->getFillColor()->c[3],
592 state->getFillColor()->c[4], state->getFillColor()->c[5],
593 state->getFillColor()->c[6], state->getFillColor()->c[7]);
594 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
595 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
596 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
597 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
598 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
599 state->getFillRGB(&rgb);
600 if(rgb.r || rgb.g || rgb.b)
601 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
602 state->getStrokeRGB(&rgb);
603 if(rgb.r || rgb.g || rgb.b)
604 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
605 if(state->getFillColorSpace()->getNComps()>1)
606 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
607 if(state->getStrokeColorSpace()->getNComps()>1)
608 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
609 if(state->getFillPattern())
610 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
611 if(state->getStrokePattern())
612 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
614 if(state->getFillOpacity()!=1.0)
615 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
616 if(state->getStrokeOpacity()!=1.0)
617 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
619 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
624 state->getLineDash(&dash, &length, &start);
628 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
629 for(t=0;t<length;t++) {
630 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
632 bufpos+=sprintf(bufpos,"]");
635 if(state->getFlatness()!=1)
636 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
637 if(state->getLineJoin()!=0)
638 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
639 if(state->getLineJoin()!=0)
640 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
641 if(state->getLineJoin()!=0)
642 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
644 if(state->getFont() && getFontID(state->getFont()))
645 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
646 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
647 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
648 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
649 if(state->getCharSpace())
650 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
651 if(state->getWordSpace())
652 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
653 if(state->getHorizScaling()!=1.0)
654 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
655 if(state->getLeading())
656 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
658 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
659 if(state->getRender())
660 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
661 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
662 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
663 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
664 if(state->getLineX())
665 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
666 if(state->getLineY())
667 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
668 bufpos+=sprintf(bufpos," ");
672 static void dumpFontInfo(char*loglevel, GfxFont*font);
673 static int lastdumps[1024];
674 static int lastdumppos = 0;
679 static void showFontError(GfxFont*font, int nr)
683 for(t=0;t<lastdumppos;t++)
684 if(lastdumps[t] == r->num)
688 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
689 lastdumps[lastdumppos++] = r->num;
691 msg("<warning> The following font caused problems:");
693 msg("<warning> The following font caused problems (substituting):");
695 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
696 dumpFontInfo("<warning>", font);
699 static void dumpFontInfo(char*loglevel, GfxFont*font)
701 char* id = getFontID(font);
702 char* name = getFontName(font);
703 Ref* r=font->getID();
704 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
706 GString*gstr = font->getTag();
708 msg("%s| Tag: %s\n", loglevel, id);
710 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
712 GfxFontType type=font->getType();
714 case fontUnknownType:
715 msg("%s| Type: unknown\n",loglevel);
718 msg("%s| Type: 1\n",loglevel);
721 msg("%s| Type: 1C\n",loglevel);
724 msg("%s| Type: 3\n",loglevel);
727 msg("%s| Type: TrueType\n",loglevel);
730 msg("%s| Type: CIDType0\n",loglevel);
733 msg("%s| Type: CIDType0C\n",loglevel);
736 msg("%s| Type: CIDType2\n",loglevel);
741 GBool embedded = font->getEmbeddedFontID(&embRef);
743 if(font->getEmbeddedFontName()) {
744 embeddedName = font->getEmbeddedFontName()->getCString();
747 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
749 gstr = font->getExtFontFile();
751 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
753 // Get font descriptor flags.
754 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
755 if(font->isSerif()) msg("%s| is serif\n", loglevel);
756 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
757 if(font->isItalic()) msg("%s| is italic\n", loglevel);
758 if(font->isBold()) msg("%s| is bold\n", loglevel);
764 //void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) {printf("void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) \n");}
765 //void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) {printf("void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) \n");}
768 void dump_outline(gfxline_t*line)
771 if(line->type == gfx_moveTo) {
772 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
773 } else if(line->type == gfx_lineTo) {
774 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
775 } else if(line->type == gfx_splineTo) {
776 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
782 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey)
784 int num = path->getNumSubpaths();
787 double lastx=0,lasty=0,posx=0,posy=0;
790 msg("<warning> empty path");
794 gfxdrawer_target_gfxline(&draw);
796 for(t = 0; t < num; t++) {
797 GfxSubpath *subpath = path->getSubpath(t);
798 int subnum = subpath->getNumPoints();
799 double bx=0,by=0,cx=0,cy=0;
801 for(s=0;s<subnum;s++) {
804 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
809 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
810 draw.lineTo(&draw, lastx, lasty);
812 draw.moveTo(&draw, x,y);
817 } else if(subpath->getCurve(s) && cpos==0) {
821 } else if(subpath->getCurve(s) && cpos==1) {
829 draw.lineTo(&draw, x,y);
831 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y, 0.05);
838 /* fix non-closed lines */
839 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
840 draw.lineTo(&draw, lastx, lasty);
842 gfxline_t*result = (gfxline_t*)draw.result(&draw);
846 /*----------------------------------------------------------------------------
847 * Primitive Graphic routines
848 *----------------------------------------------------------------------------*/
850 void SWFOutputDev::stroke(GfxState *state)
852 GfxPath * path = state->getPath();
853 gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex, user_movey);
854 strokeGfxline(state, line);
858 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
860 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
861 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
862 double miterLimit = state->getMiterLimit();
863 double width = state->getTransformedLineWidth();
866 double opaq = state->getStrokeOpacity();
868 state->getFillRGB(&rgb);
870 state->getStrokeRGB(&rgb);
872 col.r = colToByte(rgb.r);
873 col.g = colToByte(rgb.g);
874 col.b = colToByte(rgb.b);
875 col.a = (unsigned char)(opaq*255);
877 gfx_capType capType = gfx_capRound;
878 if(lineCap == 0) capType = gfx_capButt;
879 else if(lineCap == 1) capType = gfx_capRound;
880 else if(lineCap == 2) capType = gfx_capSquare;
882 gfx_joinType joinType = gfx_joinRound;
883 if(lineJoin == 0) joinType = gfx_joinMiter;
884 else if(lineJoin == 1) joinType = gfx_joinRound;
885 else if(lineJoin == 2) joinType = gfx_joinBevel;
888 double dashphase = 0;
890 state->getLineDash(&ldash, &dashnum, &dashphase);
894 if(dashnum && ldash) {
895 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
899 msg("<trace> %d dashes", dashnum);
900 msg("<trace> | phase: %f", dashphase);
901 for(t=0;t<dashnum;t++) {
903 msg("<trace> | d%-3d: %f", t, ldash[t]);
906 if(getLogLevel() >= LOGLEVEL_TRACE) {
910 line2 = gfxtool_dash_line(line, dash, dashphase);
913 msg("<trace> After dashing:");
916 if(getLogLevel() >= LOGLEVEL_TRACE) {
917 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x\n",
919 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
920 lineCap==0?"butt": (lineJoin==1?"round":"square"),
922 col.r,col.g,col.b,col.a
927 //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
928 output->stroke(output, line, width, &col, capType, joinType, miterLimit);
938 gfxcolor_t getFillColor(GfxState * state)
941 double opaq = state->getFillOpacity();
942 state->getFillRGB(&rgb);
944 col.r = colToByte(rgb.r);
945 col.g = colToByte(rgb.g);
946 col.b = colToByte(rgb.b);
947 col.a = (unsigned char)(opaq*255);
951 void SWFOutputDev::fillGfxLine(GfxState *state, gfxline_t*line)
953 gfxcolor_t col = getFillColor(state);
955 if(getLogLevel() >= LOGLEVEL_TRACE) {
956 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
959 output->fill(output, line, &col);
961 void SWFOutputDev::fill(GfxState *state)
963 GfxPath * path = state->getPath();
964 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
965 fillGfxLine(state, line);
968 void SWFOutputDev::eoFill(GfxState *state)
970 GfxPath * path = state->getPath();
971 gfxcolor_t col = getFillColor(state);
973 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
975 if(getLogLevel() >= LOGLEVEL_TRACE) {
976 msg("<trace> eofill\n");
980 output->fill(output, line, &col);
984 void SWFOutputDev::clip(GfxState *state)
986 GfxPath * path = state->getPath();
987 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
988 clipToGfxLine(state, line);
992 void SWFOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line)
994 if(getLogLevel() >= LOGLEVEL_TRACE) {
995 msg("<trace> clip\n");
999 output->startclip(output, line);
1000 states[statepos].clipping++;
1002 void SWFOutputDev::eoClip(GfxState *state)
1004 GfxPath * path = state->getPath();
1005 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
1007 if(getLogLevel() >= LOGLEVEL_TRACE) {
1008 msg("<trace> eoclip\n");
1012 output->startclip(output, line);
1013 states[statepos].clipping++;
1017 void SWFOutputDev::endframe()
1019 if(outer_clip_box) {
1020 output->endclip(output);
1024 output->endpage(output);
1027 void SWFOutputDev::finish()
1029 if(outer_clip_box) {
1031 output->endclip(output);
1036 this->result = output->finish(output);
1037 free(output);output=0;
1041 int SWFOutputDev::save(char*filename)
1044 return result->save(result, filename);
1046 void* SWFOutputDev::get(char*name)
1049 return result->get(result, name);
1052 SWFOutputDev::~SWFOutputDev()
1057 this->result->destroy(this->result);
1062 free(this->pages); this->pages = 0;
1065 fontlist_t*l = this->fontlist;
1067 fontlist_t*next = l->next;
1069 gfxfont_free(l->font);
1077 GBool SWFOutputDev::upsideDown()
1081 GBool SWFOutputDev::useDrawChar()
1085 GBool SWFOutputDev::useGradients()
1089 msg("<notice> File contains gradients");
1095 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
1096 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
1098 #define RENDER_FILL 0
1099 #define RENDER_STROKE 1
1100 #define RENDER_FILLSTROKE 2
1101 #define RENDER_INVISIBLE 3
1102 #define RENDER_CLIP 4
1104 static char tmp_printstr[4096];
1105 char* makeStringPrintable(char*str)
1107 int len = strlen(str);
1114 for(t=0;t<len;t++) {
1119 tmp_printstr[t] = c;
1122 tmp_printstr[len++] = '.';
1123 tmp_printstr[len++] = '.';
1124 tmp_printstr[len++] = '.';
1126 tmp_printstr[len] = 0;
1127 return tmp_printstr;
1131 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
1136 /* find out char name from unicode index
1137 TODO: should be precomputed
1139 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1140 if(nameToUnicodeTab[t].u == u) {
1141 uniname = nameToUnicodeTab[t].name;
1149 for(t=0;t<font->num_glyphs;t++) {
1150 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
1151 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1155 /* if we didn't find the character, maybe
1156 we can find the capitalized version */
1157 for(t=0;t<font->num_glyphs;t++) {
1158 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
1159 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1167 for(t=0;t<font->num_glyphs;t++) {
1168 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,uniname)) {
1169 msg("<debug> Char [%d,%s,>%d(%s)<] maps to %d\n", charnr, charname, u, uniname, t);
1173 /* if we didn't find the character, maybe
1174 we can find the capitalized version */
1175 for(t=0;t<font->num_glyphs;t++) {
1176 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,uniname)) {
1177 msg("<debug> Char [%d,%s,>>%d(%s)<<] maps to %d\n", charnr, charname, u, uniname, t);
1183 /* try to use the unicode id */
1184 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
1185 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
1186 return font->unicode2glyph[u];
1189 if(charnr>=0 && charnr<font->num_glyphs) {
1190 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1198 void SWFOutputDev::beginString(GfxState *state, GString *s)
1200 int render = state->getRender();
1201 if(current_text_stroke) {
1202 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
1205 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
1206 double m11,m21,m12,m22;
1207 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
1208 state->getFontTransMat(&m11, &m12, &m21, &m22);
1209 m11 *= state->getHorizScaling();
1210 m21 *= state->getHorizScaling();
1212 this->current_font_matrix.m00 = m11 / 1024.0;
1213 this->current_font_matrix.m01 = m12 / 1024.0;
1214 this->current_font_matrix.m10 = -m21 / 1024.0;
1215 this->current_font_matrix.m11 = -m22 / 1024.0;
1216 this->current_font_matrix.tx = 0;
1217 this->current_font_matrix.ty = 0;
1219 gfxmatrix_t m = this->current_font_matrix;
1221 /*if(render != 3 && render != 0)
1222 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1223 states[statepos].textRender = render;
1226 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1227 double dx, double dy,
1228 double originX, double originY,
1229 CharCode c, int nBytes, Unicode *_u, int uLen)
1231 int render = state->getRender();
1232 // check for invisible text -- this is used by Acrobat Capture
1234 msg("<debug> Ignoring invisible text: char %d at %f,%f", c, x, y);
1238 if(states[statepos].textRender != render)
1239 msg("<error> Internal error: drawChar.render!=beginString.render");
1241 gfxcolor_t col = getFillColor(state);
1243 Gushort *CIDToGIDMap = 0;
1244 GfxFont*font = state->getFont();
1246 if(font->getType() == fontType3) {
1247 /* type 3 chars are passed as graphics */
1248 msg("<debug> type3 char at %f/%f", x, y);
1255 if(font->isCIDFont()) {
1256 GfxCIDFont*cfont = (GfxCIDFont*)font;
1258 if(font->getType() == fontCIDType2)
1259 CIDToGIDMap = cfont->getCIDToGID();
1262 font8 = (Gfx8BitFont*)font;
1263 char**enc=font8->getEncoding();
1267 msg("<debug> drawChar(%f, %f, c='%c' (%d), GID=%d, u=%d <%d>) CID=%d name=\"%s\" render=%d\n", x, y, (c&127)>=32?c:'?', c, CIDToGIDMap[c], u, uLen, font->isCIDFont(), FIXNULL(name), render);
1270 msg("<debug> drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d name=\"%s\" render=%d\n",x,y,(c&127)>=32?c:'?',c,u, uLen, font->isCIDFont(), FIXNULL(name), render);
1276 charid = getGfxCharID(current_gfxfont, c, name, u);
1278 charid = getGfxCharID(current_gfxfont, c, name, -1);
1281 /* multiple unicodes- should usually map to a ligature.
1282 if the ligature doesn't exist, we need to draw
1283 the characters one-by-one. */
1285 msg("<warning> ligature %d missing in font %s\n", c, current_font_id);
1286 for(t=0;t<uLen;t++) {
1287 drawChar(state, x, y, dx, dy, originX, originY, c, nBytes, _u+t, 1);
1293 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1294 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1298 gfxmatrix_t m = this->current_font_matrix;
1299 state->transform(x, y, &m.tx, &m.ty);
1303 if(render == RENDER_FILL) {
1304 output->drawchar(output, current_font_id, charid, &col, &m);
1306 msg("<debug> Drawing glyph %d as shape", charid);
1308 msg("<notice> Some texts will be rendered as shape");
1311 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1312 gfxline_t*tglyph = gfxline_clone(glyph);
1313 gfxline_transform(tglyph, &m);
1314 if((render&3) != RENDER_INVISIBLE) {
1315 gfxline_t*add = gfxline_clone(tglyph);
1316 current_text_stroke = gfxline_append(current_text_stroke, add);
1318 if(render&RENDER_CLIP) {
1319 gfxline_t*add = gfxline_clone(tglyph);
1320 current_text_clip = gfxline_append(current_text_clip, add);
1322 gfxline_free(tglyph);
1326 void SWFOutputDev::endString(GfxState *state)
1328 int render = state->getRender();
1329 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1330 if(states[statepos].textRender != render)
1331 msg("<error> Internal error: drawChar.render!=beginString.render");
1333 if(current_text_stroke) {
1334 /* fillstroke and stroke text rendering objects we can process right
1335 now (as there may be texts of other rendering modes in this
1336 text object)- clipping objects have to wait until endTextObject,
1338 if((render&3) == RENDER_FILL) {
1339 fillGfxLine(state, current_text_stroke);
1340 gfxline_free(current_text_stroke);
1341 current_text_stroke = 0;
1342 } else if((render&3) == RENDER_FILLSTROKE) {
1343 fillGfxLine(state, current_text_stroke);
1344 strokeGfxline(state, current_text_stroke);
1345 gfxline_free(current_text_stroke);
1346 current_text_stroke = 0;
1347 } else if((render&3) == RENDER_STROKE) {
1348 strokeGfxline(state, current_text_stroke);
1349 gfxline_free(current_text_stroke);
1350 current_text_stroke = 0;
1355 void SWFOutputDev::endTextObject(GfxState *state)
1357 int render = state->getRender();
1358 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1359 if(states[statepos].textRender != render)
1360 msg("<error> Internal error: drawChar.render!=beginString.render");
1362 if(current_text_clip) {
1363 clipToGfxLine(state, current_text_clip);
1364 gfxline_free(current_text_clip);
1365 current_text_clip = 0;
1369 /* the logic seems to be as following:
1370 first, beginType3Char is called, with the charcode and the coordinates.
1371 if this function returns true, it already knew about the char and has now drawn it.
1372 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1373 the all draw operations until endType3Char are part of the char (which in this moment is
1374 at the position first passed to beginType3Char). the char ends with endType3Char.
1376 The drawing operations between beginType3Char and endType3Char are somewhat different to
1377 the normal ones. For example, the fillcolor equals the stroke color.
1380 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1382 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1384 /* the character itself is going to be passed using the draw functions */
1385 return gFalse; /* gTrue= is_in_cache? */
1388 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1389 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1391 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1392 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1396 void SWFOutputDev::endType3Char(GfxState *state)
1399 msg("<debug> endType3Char");
1402 void SWFOutputDev::startFrame(int width, int height)
1404 output->startpage(output, width, height);
1407 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1409 this->currentpage = pageNum;
1411 int rot = doc->getPageRotate(1);
1414 gfxline_t clippath[5];
1416 white.r = white.g = white.b = white.a = 255;
1418 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1419 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1420 Use CropBox, not MediaBox, as page size
1427 state->transform(crop_x1,crop_y1,&x1,&y1); //x1 += user_movex; y1 += user_movey;
1428 state->transform(crop_x2,crop_y2,&x2,&y2); //x2 += user_movex; y2 += user_movey;
1430 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1431 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1434 /* apply user clip box */
1435 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1436 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1437 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1438 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1439 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1442 //msg("<verbose> Bounding box is (%f,%f)-(%f,%f) [shifted by %d/%d]", x1,y1,x2,y2, user_movex, user_movey);
1444 if(outer_clip_box) {
1445 output->endclip(output);
1449 msg("<notice> processing PDF page %d (%dx%d:%d:%d) (move:%d:%d)", pageNum, (int)x2-(int)x1,(int)y2-(int)y1, (int)x1, (int)y1, user_movex, user_movey);
1451 msg("<verbose> page is rotated %d degrees\n", rot);
1453 clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1454 clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1455 clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1456 clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1457 clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1458 output->startclip(output, clippath); outer_clip_box = 1;
1459 output->fill(output, clippath, &white);
1462 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1464 double x1, y1, x2, y2, w;
1465 gfxline_t points[5];
1468 msg("<debug> drawlink\n");
1470 link->getRect(&x1, &y1, &x2, &y2);
1471 cvtUserToDev(x1, y1, &x, &y);
1472 points[0].type = gfx_moveTo;
1473 points[0].x = points[4].x = x + user_movex;
1474 points[0].y = points[4].y = y + user_movey;
1475 points[0].next = &points[1];
1476 cvtUserToDev(x2, y1, &x, &y);
1477 points[1].type = gfx_lineTo;
1478 points[1].x = x + user_movex;
1479 points[1].y = y + user_movey;
1480 points[1].next = &points[2];
1481 cvtUserToDev(x2, y2, &x, &y);
1482 points[2].type = gfx_lineTo;
1483 points[2].x = x + user_movex;
1484 points[2].y = y + user_movey;
1485 points[2].next = &points[3];
1486 cvtUserToDev(x1, y2, &x, &y);
1487 points[3].type = gfx_lineTo;
1488 points[3].x = x + user_movex;
1489 points[3].y = y + user_movey;
1490 points[3].next = &points[4];
1491 cvtUserToDev(x1, y1, &x, &y);
1492 points[4].type = gfx_lineTo;
1493 points[4].x = x + user_movex;
1494 points[4].y = y + user_movey;
1497 LinkAction*action=link->getAction();
1504 switch(action->getKind())
1508 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1509 LinkDest *dest=NULL;
1510 if (ha->getDest()==NULL)
1511 dest=catalog->findDest(ha->getNamedDest());
1512 else dest=ha->getDest();
1514 if (dest->isPageRef()){
1515 Ref pageref=dest->getPageRef();
1516 page=catalog->findPage(pageref.num,pageref.gen);
1518 else page=dest->getPageNum();
1519 sprintf(buf, "%d", page);
1526 LinkGoToR*l = (LinkGoToR*)action;
1527 GString*g = l->getNamedDest();
1529 s = strdup(g->getCString());
1534 LinkNamed*l = (LinkNamed*)action;
1535 GString*name = l->getName();
1537 s = strdup(name->lowerCase()->getCString());
1538 named = name->getCString();
1541 if(strstr(s, "next") || strstr(s, "forward"))
1543 page = currentpage + 1;
1545 else if(strstr(s, "prev") || strstr(s, "back"))
1547 page = currentpage - 1;
1549 else if(strstr(s, "last") || strstr(s, "end"))
1551 if(pages && pagepos>0)
1552 page = pages[pagepos-1];
1554 else if(strstr(s, "first") || strstr(s, "top"))
1562 case actionLaunch: {
1564 LinkLaunch*l = (LinkLaunch*)action;
1565 GString * str = new GString(l->getFileName());
1566 GString * params = l->getParams();
1568 str->append(params);
1569 s = strdup(str->getCString());
1575 LinkURI*l = (LinkURI*)action;
1576 GString*g = l->getURI();
1578 url = g->getCString();
1583 case actionUnknown: {
1585 LinkUnknown*l = (LinkUnknown*)action;
1590 msg("<error> Unknown link type!\n");
1595 if(!s) s = strdup("-?-");
1597 if(!linkinfo && (page || url))
1599 msg("<notice> File contains links");
1607 for(t=1;t<=pagepos;t++) {
1608 if(pages[t]==page) {
1617 sprintf(buf, "page%d", lpage);
1618 output->drawlink(output, points, buf);
1622 output->drawlink(output, points, url);
1625 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1629 void SWFOutputDev::saveState(GfxState *state) {
1630 msg("<trace> saveState\n");
1633 msg("<error> Too many nested states in pdf.");
1637 states[statepos].clipping = 0; //? shouldn't this be the current value?
1638 states[statepos].textRender = states[statepos-1].textRender;
1641 void SWFOutputDev::restoreState(GfxState *state) {
1642 msg("<trace> restoreState\n");
1644 while(states[statepos].clipping) {
1645 output->endclip(output);
1646 states[statepos].clipping--;
1651 char* SWFOutputDev::searchFont(char*name)
1655 int is_standard_font = 0;
1657 msg("<verbose> SearchFont(%s)", name);
1659 /* see if it is a pdf standard font */
1660 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1662 if(!strcmp(name, pdf2t1map[i].pdffont))
1664 name = pdf2t1map[i].filename;
1665 is_standard_font = 1;
1669 /* look in all font files */
1670 for(i=0;i<fontnum;i++)
1672 if(strstr(fonts[i].filename, name))
1674 if(!fonts[i].used) {
1677 if(!is_standard_font)
1678 msg("<notice> Using %s for %s", fonts[i].filename, name);
1680 return strdup(fonts[i].filename);
1686 void SWFOutputDev::updateLineWidth(GfxState *state)
1688 double width = state->getTransformedLineWidth();
1689 //swfoutput_setlinewidth(&output, width);
1692 void SWFOutputDev::updateLineCap(GfxState *state)
1694 int c = state->getLineCap();
1697 void SWFOutputDev::updateLineJoin(GfxState *state)
1699 int j = state->getLineJoin();
1702 void SWFOutputDev::updateFillColor(GfxState *state)
1705 double opaq = state->getFillOpacity();
1706 state->getFillRGB(&rgb);
1708 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1711 void SWFOutputDev::updateStrokeColor(GfxState *state)
1714 double opaq = state->getStrokeOpacity();
1715 state->getStrokeRGB(&rgb);
1716 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1719 void FoFiWrite(void *stream, char *data, int len)
1721 fwrite(data, len, 1, (FILE*)stream);
1724 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1726 char*tmpFileName = NULL;
1732 Object refObj, strObj;
1734 tmpFileName = mktmpname(namebuf);
1737 ret = font->getEmbeddedFontID(&embRef);
1739 msg("<verbose> Didn't get embedded font id");
1740 /* not embedded- the caller should now search the font
1741 directories for this font */
1745 f = fopen(tmpFileName, "wb");
1747 msg("<error> Couldn't create temporary Type 1 font file");
1751 /*if(font->isCIDFont()) {
1752 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1753 GString c = cidFont->getCollection();
1754 msg("<notice> Collection: %s", c.getCString());
1757 //if (font->getType() == fontType1C) {
1758 if (0) { //font->getType() == fontType1C) {
1759 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1761 msg("<error> Couldn't read embedded font file");
1764 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1766 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1767 //cvt->convertToCIDType0("test", f);
1768 //cvt->convertToType0("test", f);
1771 } else if(font->getType() == fontTrueType) {
1772 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1773 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1775 msg("<error> Couldn't read embedded font file");
1778 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1779 cvt->writeTTF(FoFiWrite, f);
1783 font->getEmbeddedFontID(&embRef);
1784 refObj.initRef(embRef.num, embRef.gen);
1785 refObj.fetch(ref, &strObj);
1787 strObj.streamReset();
1792 f4[t] = strObj.streamGetChar();
1793 f4c[t] = (char)f4[t];
1798 if(!strncmp(f4c, "true", 4)) {
1799 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1800 Change this on the fly */
1801 f4[0] = f4[2] = f4[3] = 0;
1809 while ((c = strObj.streamGetChar()) != EOF) {
1813 strObj.streamClose();
1818 return strdup(tmpFileName);
1821 char* searchForSuitableFont(GfxFont*gfxFont)
1823 char*name = getFontName(gfxFont);
1827 if(!config_use_fontconfig)
1830 #ifdef HAVE_FONTCONFIG
1831 FcPattern *pattern, *match;
1835 static int fcinitcalled = false;
1837 msg("<debug> searchForSuitableFont(%s)", name);
1839 // call init ony once
1840 if (!fcinitcalled) {
1841 msg("<debug> Initializing FontConfig...");
1842 fcinitcalled = true;
1844 msg("<debug> FontConfig Initialization failed. Disabling.");
1845 config_use_fontconfig = 0;
1848 msg("<debug> ...initialized FontConfig");
1851 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1852 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1853 if (gfxFont->isItalic()) // check for italic
1854 msg("<debug> FontConfig: Adding Italic Slant");
1855 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1856 if (gfxFont->isBold()) // check for bold
1857 msg("<debug> FontConfig: Adding Bold Weight");
1858 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1860 msg("<debug> FontConfig: Try to match...");
1861 // configure and match using the original font name
1862 FcConfigSubstitute(0, pattern, FcMatchPattern);
1863 FcDefaultSubstitute(pattern);
1864 match = FcFontMatch(0, pattern, &result);
1866 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1867 msg("<debug> FontConfig: family=%s", (char*)v);
1868 // if we get an exact match
1869 if (strcmp((char *)v, name) == 0) {
1870 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1871 filename = strdup((char*)v); // mem leak
1872 char *nfn = strrchr(filename, '/');
1873 if(nfn) fontname = strdup(nfn+1);
1874 else fontname = filename;
1876 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1878 // initialize patterns
1879 FcPatternDestroy(pattern);
1880 FcPatternDestroy(match);
1882 // now match against serif etc.
1883 if (gfxFont->isSerif()) {
1884 msg("<debug> FontConfig: Create Serif Family Pattern");
1885 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1886 } else if (gfxFont->isFixedWidth()) {
1887 msg("<debug> FontConfig: Create Monospace Family Pattern");
1888 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1890 msg("<debug> FontConfig: Create Sans Family Pattern");
1891 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1895 if (gfxFont->isItalic()) {
1896 msg("<debug> FontConfig: Adding Italic Slant");
1897 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1900 if (gfxFont->isBold()) {
1901 msg("<debug> FontConfig: Adding Bold Weight");
1902 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1905 msg("<debug> FontConfig: Try to match... (2)");
1906 // configure and match using serif etc
1907 FcConfigSubstitute (0, pattern, FcMatchPattern);
1908 FcDefaultSubstitute (pattern);
1909 match = FcFontMatch (0, pattern, &result);
1911 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1912 filename = strdup((char*)v); // mem leak
1913 char *nfn = strrchr(filename, '/');
1914 if(nfn) fontname = strdup(nfn+1);
1915 else fontname = filename;
1917 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1921 //printf("FONTCONFIG: pattern");
1922 //FcPatternPrint(pattern);
1923 //printf("FONTCONFIG: match");
1924 //FcPatternPrint(match);
1926 FcPatternDestroy(pattern);
1927 FcPatternDestroy(match);
1929 pdfswf_addfont(filename);
1936 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1938 char*fontname = 0, *filename = 0;
1939 msg("<notice> substituteFont(%s)", oldname);
1941 if(!(fontname = searchForSuitableFont(gfxFont))) {
1942 fontname = "Times-Roman";
1944 filename = searchFont(fontname);
1946 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1950 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1951 msg("<fatal> Too many fonts in file.");
1955 substitutesource[substitutepos] = strdup(oldname); //mem leak
1956 substitutetarget[substitutepos] = fontname;
1957 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1960 return strdup(filename); //mem leak
1963 void unlinkfont(char* filename)
1970 if(!strncmp(&filename[l-4],".afm",4)) {
1971 memcpy(&filename[l-4],".pfb",4);
1973 memcpy(&filename[l-4],".pfa",4);
1975 memcpy(&filename[l-4],".afm",4);
1978 if(!strncmp(&filename[l-4],".pfa",4)) {
1979 memcpy(&filename[l-4],".afm",4);
1981 memcpy(&filename[l-4],".pfa",4);
1984 if(!strncmp(&filename[l-4],".pfb",4)) {
1985 memcpy(&filename[l-4],".afm",4);
1987 memcpy(&filename[l-4],".pfb",4);
1992 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1998 int SWFOutputDev::setGfxFont(char*id, char*name, char*filename, double maxSize)
2001 fontlist_t*last=0,*l = this->fontlist;
2003 /* TODO: should this be part of the state? */
2006 if(!strcmp(l->id, id)) {
2007 current_font_id = l->id;
2008 current_gfxfont = l->font;
2010 output->addfont(output, id, current_gfxfont);
2015 if(!filename) return 0;
2017 /* A font size of e.g. 9 means the font will be scaled down by
2018 1024 and scaled up by 9. So to have a maximum error of 1/20px,
2019 we have to divide 0.05 by (fontsize/1024)
2021 double quality = (1024 * 0.05) / maxSize;
2023 msg("<verbose> Loading %s...", filename);
2024 font = gfxfont_load(filename, quality);
2025 msg("<verbose> Font %s loaded successfully", filename);
2029 l->filename = strdup(filename);
2032 current_font_id = l->id;
2033 current_gfxfont = l->font;
2039 output->addfont(output, id, current_gfxfont);
2043 void SWFOutputDev::updateFont(GfxState *state)
2045 GfxFont*gfxFont = state->getFont();
2051 char * fontid = getFontID(gfxFont);
2052 char * fontname = getFontName(gfxFont);
2054 double maxSize = 1.0;
2057 maxSize = this->info->getMaximumFontSize(fontid);
2061 /* first, look if we substituted this font before-
2062 this way, we don't initialize the T1 Fonts
2064 for(t=0;t<substitutepos;t++) {
2065 if(!strcmp(fontid, substitutesource[t])) {
2066 free(fontid);fontid=0;
2067 fontid = strdup(substitutetarget[t]);
2072 /* second, see if this is a font which was used before-
2073 if so, we are done */
2074 if(setGfxFont(fontid, fontname, 0, 0)) {
2079 /* if(swfoutput_queryfont(&output, fontid))
2080 swfoutput_setfont(&output, fontid, 0);
2082 msg("<debug> updateFont(%s) [cached]", fontid);
2086 // look for Type 3 font
2087 if (gfxFont->getType() == fontType3) {
2089 type3Warning = gTrue;
2090 showFontError(gfxFont, 2);
2097 /* now either load the font, or find a substitution */
2100 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
2105 (gfxFont->getType() == fontType1 ||
2106 gfxFont->getType() == fontType1C ||
2107 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
2108 gfxFont->getType() == fontTrueType ||
2109 gfxFont->getType() == fontCIDType2
2112 fileName = writeEmbeddedFontToFile(xref, gfxFont);
2113 if(!fileName) showFontError(gfxFont,0);
2116 fileName = searchFont(fontname);
2117 if(!fileName) showFontError(gfxFont,0);
2120 char * fontname = getFontName(gfxFont);
2121 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
2124 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into %s", fontname, lastfontdir);
2126 msg("<warning> Try specifying one or more font directories");
2128 fileName = substituteFont(gfxFont, fontid);
2129 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
2130 msg("<notice> Font is now %s (%s)", fontid, fileName);
2134 msg("<error> Couldn't set font %s\n", fontid);
2140 msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
2141 dumpFontInfo("<verbose>", gfxFont);
2143 //swfoutput_setfont(&output, fontid, fileName);
2145 if(!setGfxFont(fontid, fontname, 0, 0)) {
2146 setGfxFont(fontid, fontname, fileName, maxSize);
2150 unlinkfont(fileName);
2160 #define SQR(x) ((x)*(x))
2162 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
2164 if((newwidth<2 || newheight<2) ||
2165 (width<=newwidth || height<=newheight))
2167 unsigned char*newdata;
2169 newdata= (unsigned char*)malloc(newwidth*newheight);
2171 double fx = (double)(width)/newwidth;
2172 double fy = (double)(height)/newheight;
2174 int blocksize = (int)(8192/(fx*fy));
2175 int r = 8192*256/palettesize;
2176 for(x=0;x<newwidth;x++) {
2177 double ex = px + fx;
2178 int fromx = (int)px;
2180 int xweight1 = (int)(((fromx+1)-px)*256);
2181 int xweight2 = (int)((ex-tox)*256);
2183 for(y=0;y<newheight;y++) {
2184 double ey = py + fy;
2185 int fromy = (int)py;
2187 int yweight1 = (int)(((fromy+1)-py)*256);
2188 int yweight2 = (int)((ey-toy)*256);
2191 for(xx=fromx;xx<=tox;xx++)
2192 for(yy=fromy;yy<=toy;yy++) {
2193 int b = 1-data[width*yy+xx];
2195 if(xx==fromx) weight = (weight*xweight1)/256;
2196 if(xx==tox) weight = (weight*xweight2)/256;
2197 if(yy==fromy) weight = (weight*yweight1)/256;
2198 if(yy==toy) weight = (weight*yweight2)/256;
2201 //if(a) a=(palettesize-1)*r/blocksize;
2202 newdata[y*newwidth+x] = (a*blocksize)/r;
2210 #define IMAGE_TYPE_JPEG 0
2211 #define IMAGE_TYPE_LOSSLESS 1
2213 static void drawimage(gfxdevice_t*dev, gfxcolor_t* data, int sizex,int sizey,
2214 double x1,double y1,
2215 double x2,double y2,
2216 double x3,double y3,
2217 double x4,double y4, int type)
2219 gfxcolor_t*newpic=0;
2221 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2222 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2224 gfxline_t p1,p2,p3,p4,p5;
2225 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2226 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2227 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2228 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2229 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2231 {p1.x = (int)(p1.x*20)/20.0;
2232 p1.y = (int)(p1.y*20)/20.0;
2233 p2.x = (int)(p2.x*20)/20.0;
2234 p2.y = (int)(p2.y*20)/20.0;
2235 p3.x = (int)(p3.x*20)/20.0;
2236 p3.y = (int)(p3.y*20)/20.0;
2237 p4.x = (int)(p4.x*20)/20.0;
2238 p4.y = (int)(p4.y*20)/20.0;
2239 p5.x = (int)(p5.x*20)/20.0;
2240 p5.y = (int)(p5.y*20)/20.0;
2247 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2248 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2253 img.data = (gfxcolor_t*)data;
2257 if(type == IMAGE_TYPE_JPEG)
2258 /* TODO: pass image_dpi to device instead */
2259 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2261 dev->fillbitmap(dev, &p1, &img, &m, 0);
2264 void drawimagejpeg(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2265 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2267 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2270 void drawimagelossless(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2271 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2273 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2277 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2278 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2279 GBool inlineImg, int mask, int*maskColors,
2280 Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GfxImageColorMap*maskColorMap)
2282 double x1,y1,x2,y2,x3,y3,x4,y4;
2283 ImageStream *imgStr;
2288 unsigned char* maskbitmap = 0;
2291 ncomps = colorMap->getNumPixelComps();
2292 bits = colorMap->getBits();
2297 unsigned char buf[8];
2298 maskbitmap = (unsigned char*)malloc(maskHeight*maskWidth);
2300 ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, maskColorMap->getNumPixelComps(), maskColorMap->getBits());
2301 imgMaskStr->reset();
2302 unsigned char pal[256];
2303 int n = 1 << colorMap->getBits();
2308 maskColorMap->getGray(pixBuf, &gray);
2309 pal[t] = colToByte(gray);
2311 for (y = 0; y < maskHeight; y++) {
2312 for (x = 0; x < maskWidth; x++) {
2313 imgMaskStr->getPixel(buf);
2314 maskbitmap[y*maskWidth+x] = pal[buf[0]];
2319 ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, 1, 1);
2320 imgMaskStr->reset();
2321 for (y = 0; y < maskHeight; y++) {
2322 for (x = 0; x < maskWidth; x++) {
2323 imgMaskStr->getPixel(buf);
2325 maskbitmap[y*maskWidth+x] = (buf[0]^1)*255;
2332 imgStr = new ImageStream(str, width, ncomps,bits);
2335 if(!width || !height || (height<=1 && width<=1))
2337 msg("<verbose> Ignoring %d by %d image", width, height);
2338 unsigned char buf[8];
2340 for (y = 0; y < height; ++y)
2341 for (x = 0; x < width; ++x) {
2342 imgStr->getPixel(buf);
2350 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1 += user_movey;
2351 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2 += user_movey;
2352 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3 += user_movey;
2353 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4 += user_movey;
2355 if(!pbminfo && !(str->getKind()==strDCT)) {
2357 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2361 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2363 if(!jpeginfo && (str->getKind()==strDCT)) {
2364 msg("<notice> file contains jpeg pictures");
2370 unsigned char buf[8];
2372 unsigned char*pic = new unsigned char[width*height];
2373 gfxcolor_t pal[256];
2375 state->getFillRGB(&rgb);
2377 memset(pal,255,sizeof(pal));
2378 pal[0].r = (int)(colToByte(rgb.r)); pal[1].r = 0;
2379 pal[0].g = (int)(colToByte(rgb.g)); pal[1].g = 0;
2380 pal[0].b = (int)(colToByte(rgb.b)); pal[1].b = 0;
2381 pal[0].a = 255; pal[1].a = 0;
2384 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2385 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2386 for (y = 0; y < height; ++y)
2387 for (x = 0; x < width; ++x)
2389 imgStr->getPixel(buf);
2392 pic[width*y+x] = buf[0];
2395 /* the size of the drawn image is added to the identifier
2396 as the same image may require different bitmaps if displayed
2397 at different sizes (due to antialiasing): */
2400 unsigned char*pic2 = 0;
2403 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2412 height = realheight;
2416 /* make a black/white palette */
2418 float r = 255/(numpalette-1);
2420 for(t=0;t<numpalette;t++) {
2421 pal[t].r = colToByte(rgb.r);
2422 pal[t].g = colToByte(rgb.g);
2423 pal[t].b = colToByte(rgb.b);
2424 pal[t].a = (unsigned char)(t*r);
2428 gfxcolor_t*pic2 = new gfxcolor_t[width*height];
2429 for (y = 0; y < height; ++y) {
2430 for (x = 0; x < width; ++x) {
2431 pic2[width*y+x] = pal[pic[y*width+x]];
2434 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2438 if(maskbitmap) free(maskbitmap);
2444 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2445 gfxcolor_t*pic=new gfxcolor_t[width*height];
2446 for (y = 0; y < height; ++y) {
2447 for (x = 0; x < width; ++x) {
2448 imgStr->getPixel(pixBuf);
2449 colorMap->getRGB(pixBuf, &rgb);
2450 pic[width*y+x].r = (unsigned char)(colToByte(rgb.r));
2451 pic[width*y+x].g = (unsigned char)(colToByte(rgb.g));
2452 pic[width*y+x].b = (unsigned char)(colToByte(rgb.b));
2453 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2455 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2459 if(str->getKind()==strDCT)
2460 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2462 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2465 if(maskbitmap) free(maskbitmap);
2468 gfxcolor_t*pic=new gfxcolor_t[width*height];
2469 gfxcolor_t pal[256];
2470 int n = 1 << colorMap->getBits();
2472 for(t=0;t<256;t++) {
2474 colorMap->getRGB(pixBuf, &rgb);
2476 {/*if(maskColors && *maskColors==t) {
2477 msg("<notice> Color %d is transparent", t);
2478 if (imgData->maskColors) {
2480 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2481 if (pix[i] < imgData->maskColors[2*i] ||
2482 pix[i] > imgData->maskColors[2*i+1]) {
2497 pal[t].r = (unsigned char)(colToByte(rgb.r));
2498 pal[t].g = (unsigned char)(colToByte(rgb.g));
2499 pal[t].b = (unsigned char)(colToByte(rgb.b));
2500 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2503 for (y = 0; y < height; ++y) {
2504 for (x = 0; x < width; ++x) {
2505 imgStr->getPixel(pixBuf);
2506 pic[width*y+x] = pal[pixBuf[0]];
2508 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2512 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2516 if(maskbitmap) free(maskbitmap);
2521 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2522 int width, int height, GBool invert,
2525 if(states[statepos].textRender & 4) //clipped
2527 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2528 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0, 0,0,0,0, 0);
2531 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2532 int width, int height, GfxImageColorMap *colorMap,
2533 int *maskColors, GBool inlineImg)
2535 if(states[statepos].textRender & 4) //clipped
2538 msg("<verbose> drawImage %dx%d, %s, %s, inline=%d", width, height,
2539 colorMap?"colorMap":"no colorMap",
2540 maskColors?"maskColors":"no maskColors",
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,inlineImg,0,maskColors, 0,0,0,0, 0);
2548 void SWFOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
2549 int width, int height,
2550 GfxImageColorMap *colorMap,
2551 Stream *maskStr, int maskWidth, int maskHeight,
2554 if(states[statepos].textRender & 4) //clipped
2557 msg("<verbose> drawMaskedImage %dx%d, %s, %dx%d mask", width, height,
2558 colorMap?"colorMap":"no colorMap",
2559 maskWidth, maskHeight);
2561 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2562 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2563 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, maskInvert, 0);
2566 void SWFOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
2567 int width, int height,
2568 GfxImageColorMap *colorMap,
2570 int maskWidth, int maskHeight,
2571 GfxImageColorMap *maskColorMap)
2573 if(states[statepos].textRender & 4) //clipped
2576 msg("<verbose> drawSoftMaskedImage %dx%d, %s, %dx%d mask", width, height,
2577 colorMap?"colorMap":"no colorMap",
2578 maskWidth, maskHeight);
2580 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2581 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2582 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, 0, maskColorMap);
2585 //SWFOutputDev*output = 0;
2587 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2592 if (infoDict->lookup(key, &obj)->isString()) {
2593 s1 = obj.getString();
2594 if ((s1->getChar(0) & 0xff) == 0xfe &&
2595 (s1->getChar(1) & 0xff) == 0xff) {
2597 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2598 if (s1->getChar(i) == '\0') {
2599 s2->append(s1->getChar(i+1));
2602 s2 = new GString("<unicode>");
2606 printf(fmt, s2->getCString());
2609 printf(fmt, s1->getCString());
2615 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2619 if (infoDict->lookup(key, &obj)->isString()) {
2620 s = obj.getString()->getCString();
2621 if (s[0] == 'D' && s[1] == ':') {
2632 void storeDeviceParameter(char*name, char*value)
2634 parameter_t*p = new parameter_t();
2635 p->name = strdup(name);
2636 p->value = strdup(value);
2638 if(device_config_next) {
2639 device_config_next->next = p;
2640 device_config_next = p;
2643 device_config_next = p;
2647 void pdfswf_setparameter(char*name, char*value)
2649 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2650 if(!strcmp(name, "caplinewidth")) {
2651 caplinewidth = atof(value);
2652 } else if(!strcmp(name, "zoom")) {
2655 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2656 storeDeviceParameter("jpegsubpixels", buf);
2657 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2658 storeDeviceParameter("ppmsubpixels", buf);
2659 } else if(!strcmp(name, "jpegdpi")) {
2661 jpeg_dpi = atoi(value);
2662 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2663 storeDeviceParameter("jpegsubpixels", buf);
2664 } else if(!strcmp(name, "ppmdpi")) {
2666 ppm_dpi = atoi(value);
2667 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2668 storeDeviceParameter("ppmsubpixels", buf);
2669 } else if(!strcmp(name, "forceType0Fonts")) {
2670 forceType0Fonts = atoi(value);
2671 } else if(!strncmp(name, "fontdir", strlen("fontdir"))) {
2672 pdfswf_addfontdir(value);
2673 } else if(!strncmp(name, "languagedir", strlen("languagedir"))) {
2674 pdfswf_addlanguagedir(value);
2675 } else if(!strcmp(name, "fontconfig")) {
2676 config_use_fontconfig = atoi(value);
2678 storeDeviceParameter(name,value);
2681 void pdfswf_addfont(char*filename)
2684 memset(&f, 0, sizeof(fontfile_t));
2685 f.filename = filename;
2686 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2687 fonts[fontnum++] = f;
2689 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2693 static char* dirseparator()
2702 void pdfswf_addlanguagedir(char*dir)
2705 globalParams = new GlobalParams("");
2707 msg("<notice> Adding %s to language pack directories", dir);
2711 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc") + 1);
2712 strcpy(config_file, dir);
2713 strcat(config_file, dirseparator());
2714 strcat(config_file, "add-to-xpdfrc");
2716 fi = fopen(config_file, "rb");
2718 msg("<error> Could not open %s", config_file);
2721 globalParams->parseFile(new GString(config_file), fi);
2725 void pdfswf_addfontdir(char*dirname)
2727 #ifdef HAVE_DIRENT_H
2728 msg("<notice> Adding %s to font directories", dirname);
2729 lastfontdir = strdup(dirname);
2730 DIR*dir = opendir(dirname);
2732 msg("<warning> Couldn't open directory %s\n", dirname);
2737 ent = readdir (dir);
2741 char*name = ent->d_name;
2747 if(!strncasecmp(&name[l-4], ".pfa", 4))
2749 if(!strncasecmp(&name[l-4], ".pfb", 4))
2751 if(!strncasecmp(&name[l-4], ".ttf", 4))
2755 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2756 strcpy(fontname, dirname);
2757 strcat(fontname, dirseparator());
2758 strcat(fontname, name);
2759 msg("<verbose> Adding %s to fonts", fontname);
2760 pdfswf_addfont(fontname);
2765 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2770 typedef struct _pdf_doc_internal
2775 } pdf_doc_internal_t;
2776 typedef struct _pdf_page_internal
2778 } pdf_page_internal_t;
2779 typedef struct _swf_output_internal
2781 SWFOutputDev*outputDev;
2782 } swf_output_internal_t;
2784 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2786 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2787 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2788 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2789 memset(i, 0, sizeof(pdf_doc_internal_t));
2790 pdf_doc->internal = i;
2792 GString *fileName = new GString(filename);
2798 globalParams = new GlobalParams("");
2801 if (userPassword && userPassword[0]) {
2802 userPW = new GString(userPassword);
2806 i->doc = new PDFDoc(fileName, userPW);
2810 if (!i->doc->isOk()) {
2815 i->doc->getDocInfo(&info);
2816 if (info.isDict() &&
2817 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2818 printInfoString(info.getDict(), "Title", "Title: %s\n");
2819 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2820 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2821 printInfoString(info.getDict(), "Author", "Author: %s\n");
2822 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2823 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2824 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2825 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2826 printf("Pages: %d\n", i->doc->getNumPages());
2827 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2828 printf("Encrypted: ");
2829 if (i->doc->isEncrypted()) {
2830 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2831 i->doc->okToPrint() ? "yes" : "no",
2832 i->doc->okToCopy() ? "yes" : "no",
2833 i->doc->okToChange() ? "yes" : "no",
2834 i->doc->okToAddNotes() ? "yes" : "no");
2841 pdf_doc->num_pages = i->doc->getNumPages();
2843 if (i->doc->isEncrypted()) {
2844 if(!i->doc->okToCopy()) {
2845 printf("PDF disallows copying.\n");
2848 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2852 InfoOutputDev*io = new InfoOutputDev();
2854 for(t=1;t<=pdf_doc->num_pages;t++) {
2855 i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, /*usemediabox*/true, /*crop*/true, /*doLinks*/(int)1);
2866 delete globalParams;globalParams=0;
2867 Object::memCheck(stderr);
2872 void pdf_destroy(pdf_doc_t*pdf_doc)
2874 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2876 delete i->doc; i->doc=0;
2879 delete i->info;i->info=0;
2882 free(pdf_doc->internal);pdf_doc->internal=0;
2883 free(pdf_doc);pdf_doc=0;
2886 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2888 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2890 if(page < 1 || page > pdf_doc->num_pages)
2893 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2894 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2895 memset(pi, 0, sizeof(pdf_page_internal_t));
2896 pdf_page->internal = pi;
2898 pdf_page->parent = pdf_doc;
2899 pdf_page->nr = page;
2903 void pdf_page_destroy(pdf_page_t*pdf_page)
2905 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2906 free(pdf_page->internal);pdf_page->internal = 0;
2907 free(pdf_page);pdf_page=0;
2910 swf_output_t* swf_output_init()
2912 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2913 memset(swf_output, 0, sizeof(swf_output_t));
2914 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2915 memset(i, 0, sizeof(swf_output_internal_t));
2916 swf_output->internal = i;
2918 i->outputDev = new SWFOutputDev();
2922 void swf_output_setparameter(swf_output_t*swf, char*name, char*value)
2924 pdfswf_setparameter(name, value);
2927 void swf_output_startframe(swf_output_t*swf, int width, int height)
2929 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2930 i->outputDev->startFrame(width, height);
2933 void swf_output_endframe(swf_output_t*swf)
2935 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2936 i->outputDev->endframe();
2939 void swf_output_preparepage(swf_output_t*swf, int pdfpage, int outputpage)
2941 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2942 SWFOutputDev*o = i->outputDev;
2948 o->pagebuflen = 1024;
2949 o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
2950 memset(o->pages, -1, o->pagebuflen*sizeof(int));
2952 while(pdfpage >= o->pagebuflen)
2954 int oldlen = o->pagebuflen;
2955 o->pagebuflen+=1024;
2956 o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
2957 memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
2960 o->pages[pdfpage] = outputpage;
2961 if(pdfpage>o->pagepos)
2962 o->pagepos = pdfpage;
2965 int swf_output_save(swf_output_t*swf, char*filename)
2967 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2968 int ret = i->outputDev->save(filename);
2972 void* swf_output_get(swf_output_t*swf,char*name)
2974 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2975 void* ret = i->outputDev->get(name);
2979 void swf_output_destroy(swf_output_t*output)
2981 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2982 delete i->outputDev; i->outputDev=0;
2983 free(output->internal);output->internal=0;
2987 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2989 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2990 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2993 msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2998 gfxdevice_t*dev = si->outputDev->output;
2999 dev->setparameter(dev, "protect", "1");
3001 si->outputDev->setInfo(pi->info);
3002 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
3003 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
3006 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
3008 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
3009 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
3011 si->outputDev->setMove(x,y);
3012 if((x1|y1|x2|y2)==0) x2++;
3013 si->outputDev->setClip(x1,y1,x2,y2);
3015 pdf_page_render2(page, output);
3017 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
3019 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
3020 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
3022 si->outputDev->setMove(0,0);
3023 si->outputDev->setClip(0,0,0,0);
3025 pdf_page_render2(page, output);
3029 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
3031 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
3032 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
3033 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
3034 memset(info, 0, sizeof(pdf_page_info_t));
3036 InfoOutputDev*output = new InfoOutputDev;
3038 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
3040 info->xMin = output->x1;
3041 info->yMin = output->y1;
3042 info->xMax = output->x2;
3043 info->yMax = output->y2;
3044 info->number_of_images = output->num_images;
3045 info->number_of_links = output->num_links;
3046 info->number_of_fonts = output->num_fonts;
3053 void pdf_page_info_destroy(pdf_page_info_t*info)