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 {
146 SWFOutputDev(gfxdevice_t*output);
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;}
157 void startFrame(int width, int height);
159 virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
163 //----- get info about output device
165 // Does this device use upside-down coordinates?
166 // (Upside-down means (0,0) is the top left corner of the page.)
167 virtual GBool upsideDown();
169 // Does this device use drawChar() or drawString()?
170 virtual GBool useDrawChar();
172 virtual GBool interpretType3Chars() {return gTrue;}
174 //virtual GBool useShadedFills() { return gTrue; }
176 //----- initialization and control
178 void setXRef(PDFDoc*doc, XRef *xref);
181 virtual void drawLink(Link *link, Catalog *catalog) ;
183 //----- save/restore graphics state
184 virtual void saveState(GfxState *state) ;
185 virtual void restoreState(GfxState *state) ;
187 //----- update graphics state
189 virtual void updateFont(GfxState *state);
190 virtual void updateFillColor(GfxState *state);
191 virtual void updateStrokeColor(GfxState *state);
192 virtual void updateLineWidth(GfxState *state);
193 virtual void updateLineJoin(GfxState *state);
194 virtual void updateLineCap(GfxState *state);
196 virtual void updateAll(GfxState *state)
199 updateFillColor(state);
200 updateStrokeColor(state);
201 updateLineWidth(state);
202 updateLineJoin(state);
203 updateLineCap(state);
206 //----- path painting
207 virtual void stroke(GfxState *state) ;
208 virtual void fill(GfxState *state) ;
209 virtual void eoFill(GfxState *state) ;
211 //----- path clipping
212 virtual void clip(GfxState *state) ;
213 virtual void eoClip(GfxState *state) ;
216 virtual void beginString(GfxState *state, GString *s) ;
217 virtual void endString(GfxState *state) ;
218 virtual void endTextObject(GfxState *state);
219 virtual void drawChar(GfxState *state, double x, double y,
220 double dx, double dy,
221 double originX, double originY,
222 CharCode code, int nBytes, Unicode *u, int uLen);
224 //----- image drawing
225 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
226 int width, int height, GBool invert,
228 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
229 int width, int height, GfxImageColorMap *colorMap,
230 int *maskColors, GBool inlineImg);
231 virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
232 int width, int height,
233 GfxImageColorMap *colorMap,
234 Stream *maskStr, int maskWidth, int maskHeight,
236 virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
237 int width, int height,
238 GfxImageColorMap *colorMap,
240 int maskWidth, int maskHeight,
241 GfxImageColorMap *maskColorMap);
243 virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
244 virtual void endType3Char(GfxState *state);
246 virtual void type3D0(GfxState *state, double wx, double wy);
247 virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
252 void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
253 int width, int height, GfxImageColorMap*colorMap, GBool invert,
254 GBool inlineImg, int mask, int *maskColors,
255 Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GfxImageColorMap*maskColorMap);
256 int SWFOutputDev::setGfxFont(char*id, char*name, char*filename, double quality);
257 void strokeGfxline(GfxState *state, gfxline_t*line);
258 void clipToGfxLine(GfxState *state, gfxline_t*line);
259 void fillGfxLine(GfxState *state, gfxline_t*line);
261 char outer_clip_box; //whether the page clip box is still on
264 SWFOutputState states[64];
272 char* searchFont(char*name);
273 char* substituteFont(GfxFont*gfxFont, char*oldname);
274 char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
276 int textmodeinfo; // did we write "Text will be rendered as polygon" yet?
277 int jpeginfo; // did we write "File contains jpegs" yet?
278 int pbminfo; // did we write "File contains jpegs" yet?
279 int linkinfo; // did we write "File contains links" yet?
280 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
281 int gradientinfo; // did we write "File contains Gradients yet?
283 int type3active; // are we between beginType3()/endType3()?
289 char* substitutetarget[256];
290 char* substitutesource[256];
293 int user_movex,user_movey;
294 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
296 gfxline_t* current_text_stroke;
297 gfxline_t* current_text_clip;
298 char* current_font_id;
299 gfxfont_t* current_gfxfont;
300 gfxmatrix_t current_font_matrix;
302 fontlist_t* fontlist;
308 friend void dev_output_preparepage(dev_output_t*swf, int pdfpage, int outputpage);
311 typedef struct _drawnchar
329 chars = (drawnchar_t*)malloc(sizeof(drawnchar_t)*buf_size);
330 memset(chars, 0, sizeof(drawnchar_t)*buf_size);
335 free(chars);chars = 0;
342 chars = (drawnchar_t*)realloc(chars, sizeof(drawnchar_t)*buf_size);
346 void addChar(int charid, gfxcoord_t x, gfxcoord_t y, gfxcolor_t color)
349 chars[num_chars].x = x;
350 chars[num_chars].y = y;
351 chars[num_chars].color = color;
352 chars[num_chars].charid = charid;
356 static char*getFontID(GfxFont*font);
364 class InfoOutputDev: public OutputDev
367 FontInfo* currentfont;
379 id2font = new GHash();
381 virtual ~InfoOutputDev()
385 virtual GBool upsideDown() {return gTrue;}
386 virtual GBool useDrawChar() {return gTrue;}
387 virtual GBool interpretType3Chars() {return gTrue;}
388 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
391 state->transform(crop_x1,crop_y1,&x1,&y1);
392 state->transform(crop_x2,crop_y2,&x2,&y2);
393 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
394 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
400 virtual void drawLink(Link *link, Catalog *catalog)
404 virtual double getMaximumFontSize(char*id)
406 FontInfo*info = (FontInfo*)id2font->lookup(id);
408 msg("<error> Unknown font id: %s", id);
411 return info->max_size;
414 virtual void updateFont(GfxState *state)
416 GfxFont*font = state->getFont();
419 char*id = getFontID(font);
421 FontInfo*info = (FontInfo*)id2font->lookup(id);
423 GString* idStr = new GString(id);
427 id2font->add(idStr, (void*)info);
434 virtual void drawChar(GfxState *state, double x, double y,
435 double dx, double dy,
436 double originX, double originY,
437 CharCode code, int nBytes, Unicode *u, int uLen)
439 int render = state->getRender();
442 double m11,m21,m12,m22;
443 state->getFontTransMat(&m11, &m12, &m21, &m22);
444 m11 *= state->getHorizScaling();
445 m21 *= state->getHorizScaling();
446 double lenx = sqrt(m11*m11 + m12*m12);
447 double leny = sqrt(m21*m21 + m22*m22);
448 double len = lenx>leny?lenx:leny;
449 if(currentfont && currentfont->max_size < len) {
450 currentfont->max_size = len;
453 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
454 int width, int height, GBool invert,
459 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
460 int width, int height, GfxImageColorMap *colorMap,
461 int *maskColors, GBool inlineImg)
467 SWFOutputDev::SWFOutputDev(gfxdevice_t*output)
469 this->output = output;
471 this->textmodeinfo = 0;
475 this->type3active = 0;
478 this->substitutepos = 0;
479 this->type3Warning = 0;
480 this->user_movex = 0;
481 this->user_movey = 0;
482 this->user_clipx1 = 0;
483 this->user_clipy1 = 0;
484 this->user_clipx2 = 0;
485 this->user_clipy2 = 0;
486 this->current_text_stroke = 0;
487 this->current_text_clip = 0;
489 this->outer_clip_box = 0;
491 this->pagebuflen = 0;
494 /* configure device */
495 parameter_t*p = device_config;
497 output->setparameter(output, p->name, p->value);
502 void SWFOutputDev::setMove(int x,int y)
504 this->user_movex = x;
505 this->user_movey = y;
508 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
510 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
511 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
513 this->user_clipx1 = x1;
514 this->user_clipy1 = y1;
515 this->user_clipx2 = x2;
516 this->user_clipy2 = y2;
519 static char*getFontID(GfxFont*font)
521 Ref*ref = font->getID();
522 GString*gstr = font->getName();
523 char* fname = gstr==0?0:gstr->getCString();
526 sprintf(buf, "font-%d-%d", ref->num, ref->gen);
528 sprintf(buf, "%s-%d-%d", fname, ref->num, ref->gen);
533 static char*getFontName(GfxFont*font)
536 GString*gstr = font->getName();
537 char* fname = gstr==0?0:gstr->getCString();
541 sprintf(buf, "UFONT%d", r->num);
542 fontid = strdup(buf);
544 fontid = strdup(fname);
547 char* plus = strchr(fontid, '+');
548 if(plus && plus < &fontid[strlen(fontid)-1]) {
549 fontname = strdup(plus+1);
551 fontname = strdup(fontid);
557 static char mybuf[1024];
558 static char* gfxstate2str(GfxState *state)
562 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
569 if(state->getX1()!=0.0)
570 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
571 if(state->getY1()!=0.0)
572 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
573 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
574 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
575 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
576 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
577 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
578 state->getFillColor()->c[0], state->getFillColor()->c[1]);
579 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
580 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
581 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
582 state->getFillColor()->c[0], state->getFillColor()->c[1],
583 state->getFillColor()->c[2], state->getFillColor()->c[3],
584 state->getFillColor()->c[4], state->getFillColor()->c[5],
585 state->getFillColor()->c[6], state->getFillColor()->c[7]);
586 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
587 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
588 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
589 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
590 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
591 state->getFillRGB(&rgb);
592 if(rgb.r || rgb.g || rgb.b)
593 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
594 state->getStrokeRGB(&rgb);
595 if(rgb.r || rgb.g || rgb.b)
596 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
597 if(state->getFillColorSpace()->getNComps()>1)
598 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
599 if(state->getStrokeColorSpace()->getNComps()>1)
600 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
601 if(state->getFillPattern())
602 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
603 if(state->getStrokePattern())
604 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
606 if(state->getFillOpacity()!=1.0)
607 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
608 if(state->getStrokeOpacity()!=1.0)
609 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
611 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
616 state->getLineDash(&dash, &length, &start);
620 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
621 for(t=0;t<length;t++) {
622 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
624 bufpos+=sprintf(bufpos,"]");
627 if(state->getFlatness()!=1)
628 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
629 if(state->getLineJoin()!=0)
630 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
631 if(state->getLineJoin()!=0)
632 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
633 if(state->getLineJoin()!=0)
634 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
636 if(state->getFont() && getFontID(state->getFont()))
637 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
638 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
639 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
640 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
641 if(state->getCharSpace())
642 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
643 if(state->getWordSpace())
644 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
645 if(state->getHorizScaling()!=1.0)
646 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
647 if(state->getLeading())
648 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
650 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
651 if(state->getRender())
652 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
653 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
654 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
655 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
656 if(state->getLineX())
657 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
658 if(state->getLineY())
659 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
660 bufpos+=sprintf(bufpos," ");
664 static void dumpFontInfo(char*loglevel, GfxFont*font);
665 static int lastdumps[1024];
666 static int lastdumppos = 0;
671 static void showFontError(GfxFont*font, int nr)
675 for(t=0;t<lastdumppos;t++)
676 if(lastdumps[t] == r->num)
680 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
681 lastdumps[lastdumppos++] = r->num;
683 msg("<warning> The following font caused problems:");
685 msg("<warning> The following font caused problems (substituting):");
687 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
688 dumpFontInfo("<warning>", font);
691 static void dumpFontInfo(char*loglevel, GfxFont*font)
693 char* id = getFontID(font);
694 char* name = getFontName(font);
695 Ref* r=font->getID();
696 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
698 GString*gstr = font->getTag();
700 msg("%s| Tag: %s\n", loglevel, id);
702 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
704 GfxFontType type=font->getType();
706 case fontUnknownType:
707 msg("%s| Type: unknown\n",loglevel);
710 msg("%s| Type: 1\n",loglevel);
713 msg("%s| Type: 1C\n",loglevel);
716 msg("%s| Type: 3\n",loglevel);
719 msg("%s| Type: TrueType\n",loglevel);
722 msg("%s| Type: CIDType0\n",loglevel);
725 msg("%s| Type: CIDType0C\n",loglevel);
728 msg("%s| Type: CIDType2\n",loglevel);
733 GBool embedded = font->getEmbeddedFontID(&embRef);
735 if(font->getEmbeddedFontName()) {
736 embeddedName = font->getEmbeddedFontName()->getCString();
739 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
741 gstr = font->getExtFontFile();
743 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
745 // Get font descriptor flags.
746 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
747 if(font->isSerif()) msg("%s| is serif\n", loglevel);
748 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
749 if(font->isItalic()) msg("%s| is italic\n", loglevel);
750 if(font->isBold()) msg("%s| is bold\n", loglevel);
756 //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");}
757 //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");}
760 void dump_outline(gfxline_t*line)
763 if(line->type == gfx_moveTo) {
764 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
765 } else if(line->type == gfx_lineTo) {
766 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
767 } else if(line->type == gfx_splineTo) {
768 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
774 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey)
776 int num = path->getNumSubpaths();
779 double lastx=0,lasty=0,posx=0,posy=0;
782 msg("<warning> empty path");
786 gfxdrawer_target_gfxline(&draw);
788 for(t = 0; t < num; t++) {
789 GfxSubpath *subpath = path->getSubpath(t);
790 int subnum = subpath->getNumPoints();
791 double bx=0,by=0,cx=0,cy=0;
793 for(s=0;s<subnum;s++) {
796 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
801 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
802 draw.lineTo(&draw, lastx, lasty);
804 draw.moveTo(&draw, x,y);
809 } else if(subpath->getCurve(s) && cpos==0) {
813 } else if(subpath->getCurve(s) && cpos==1) {
821 draw.lineTo(&draw, x,y);
823 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y, 0.05);
830 /* fix non-closed lines */
831 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
832 draw.lineTo(&draw, lastx, lasty);
834 gfxline_t*result = (gfxline_t*)draw.result(&draw);
838 /*----------------------------------------------------------------------------
839 * Primitive Graphic routines
840 *----------------------------------------------------------------------------*/
842 void SWFOutputDev::stroke(GfxState *state)
844 GfxPath * path = state->getPath();
845 gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex, user_movey);
846 strokeGfxline(state, line);
850 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
852 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
853 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
854 double miterLimit = state->getMiterLimit();
855 double width = state->getTransformedLineWidth();
858 double opaq = state->getStrokeOpacity();
860 state->getFillRGB(&rgb);
862 state->getStrokeRGB(&rgb);
864 col.r = colToByte(rgb.r);
865 col.g = colToByte(rgb.g);
866 col.b = colToByte(rgb.b);
867 col.a = (unsigned char)(opaq*255);
869 gfx_capType capType = gfx_capRound;
870 if(lineCap == 0) capType = gfx_capButt;
871 else if(lineCap == 1) capType = gfx_capRound;
872 else if(lineCap == 2) capType = gfx_capSquare;
874 gfx_joinType joinType = gfx_joinRound;
875 if(lineJoin == 0) joinType = gfx_joinMiter;
876 else if(lineJoin == 1) joinType = gfx_joinRound;
877 else if(lineJoin == 2) joinType = gfx_joinBevel;
880 double dashphase = 0;
882 state->getLineDash(&ldash, &dashnum, &dashphase);
886 if(dashnum && ldash) {
887 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
891 msg("<trace> %d dashes", dashnum);
892 msg("<trace> | phase: %f", dashphase);
893 for(t=0;t<dashnum;t++) {
895 msg("<trace> | d%-3d: %f", t, ldash[t]);
898 if(getLogLevel() >= LOGLEVEL_TRACE) {
902 line2 = gfxtool_dash_line(line, dash, dashphase);
905 msg("<trace> After dashing:");
908 if(getLogLevel() >= LOGLEVEL_TRACE) {
909 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x\n",
911 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
912 lineCap==0?"butt": (lineJoin==1?"round":"square"),
914 col.r,col.g,col.b,col.a
919 //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
920 output->stroke(output, line, width, &col, capType, joinType, miterLimit);
930 gfxcolor_t getFillColor(GfxState * state)
933 double opaq = state->getFillOpacity();
934 state->getFillRGB(&rgb);
936 col.r = colToByte(rgb.r);
937 col.g = colToByte(rgb.g);
938 col.b = colToByte(rgb.b);
939 col.a = (unsigned char)(opaq*255);
943 void SWFOutputDev::fillGfxLine(GfxState *state, gfxline_t*line)
945 gfxcolor_t col = getFillColor(state);
947 if(getLogLevel() >= LOGLEVEL_TRACE) {
948 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
951 output->fill(output, line, &col);
953 void SWFOutputDev::fill(GfxState *state)
955 GfxPath * path = state->getPath();
956 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
957 fillGfxLine(state, line);
960 void SWFOutputDev::eoFill(GfxState *state)
962 GfxPath * path = state->getPath();
963 gfxcolor_t col = getFillColor(state);
965 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
967 if(getLogLevel() >= LOGLEVEL_TRACE) {
968 msg("<trace> eofill\n");
972 output->fill(output, line, &col);
976 void SWFOutputDev::clip(GfxState *state)
978 GfxPath * path = state->getPath();
979 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
980 clipToGfxLine(state, line);
984 void SWFOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line)
986 if(getLogLevel() >= LOGLEVEL_TRACE) {
987 msg("<trace> clip\n");
991 output->startclip(output, line);
992 states[statepos].clipping++;
994 void SWFOutputDev::eoClip(GfxState *state)
996 GfxPath * path = state->getPath();
997 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
999 if(getLogLevel() >= LOGLEVEL_TRACE) {
1000 msg("<trace> eoclip\n");
1004 output->startclip(output, line);
1005 states[statepos].clipping++;
1009 void SWFOutputDev::endframe()
1011 if(outer_clip_box) {
1012 output->endclip(output);
1016 output->endpage(output);
1019 void SWFOutputDev::finish()
1021 if(outer_clip_box) {
1023 output->endclip(output);
1029 SWFOutputDev::~SWFOutputDev()
1034 free(this->pages); this->pages = 0;
1037 fontlist_t*l = this->fontlist;
1039 fontlist_t*next = l->next;
1041 gfxfont_free(l->font);
1042 free(l->id);l->id=0;
1043 free(l->filename);l->filename=0;
1049 GBool SWFOutputDev::upsideDown()
1053 GBool SWFOutputDev::useDrawChar()
1058 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
1059 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
1061 #define RENDER_FILL 0
1062 #define RENDER_STROKE 1
1063 #define RENDER_FILLSTROKE 2
1064 #define RENDER_INVISIBLE 3
1065 #define RENDER_CLIP 4
1067 static char tmp_printstr[4096];
1068 char* makeStringPrintable(char*str)
1070 int len = strlen(str);
1077 for(t=0;t<len;t++) {
1082 tmp_printstr[t] = c;
1085 tmp_printstr[len++] = '.';
1086 tmp_printstr[len++] = '.';
1087 tmp_printstr[len++] = '.';
1089 tmp_printstr[len] = 0;
1090 return tmp_printstr;
1094 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
1099 /* find out char name from unicode index
1100 TODO: should be precomputed
1102 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1103 if(nameToUnicodeTab[t].u == u) {
1104 uniname = nameToUnicodeTab[t].name;
1112 for(t=0;t<font->num_glyphs;t++) {
1113 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
1114 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1118 /* if we didn't find the character, maybe
1119 we can find the capitalized version */
1120 for(t=0;t<font->num_glyphs;t++) {
1121 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
1122 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1130 for(t=0;t<font->num_glyphs;t++) {
1131 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,uniname)) {
1132 msg("<debug> Char [%d,%s,>%d(%s)<] maps to %d\n", charnr, charname, u, uniname, t);
1136 /* if we didn't find the character, maybe
1137 we can find the capitalized version */
1138 for(t=0;t<font->num_glyphs;t++) {
1139 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,uniname)) {
1140 msg("<debug> Char [%d,%s,>>%d(%s)<<] maps to %d\n", charnr, charname, u, uniname, t);
1146 /* try to use the unicode id */
1147 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
1148 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
1149 return font->unicode2glyph[u];
1152 if(charnr>=0 && charnr<font->num_glyphs) {
1153 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1161 void SWFOutputDev::beginString(GfxState *state, GString *s)
1163 int render = state->getRender();
1164 if(current_text_stroke) {
1165 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
1168 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
1169 double m11,m21,m12,m22;
1170 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
1171 state->getFontTransMat(&m11, &m12, &m21, &m22);
1172 m11 *= state->getHorizScaling();
1173 m21 *= state->getHorizScaling();
1175 this->current_font_matrix.m00 = m11 / 1024.0;
1176 this->current_font_matrix.m01 = m12 / 1024.0;
1177 this->current_font_matrix.m10 = -m21 / 1024.0;
1178 this->current_font_matrix.m11 = -m22 / 1024.0;
1179 this->current_font_matrix.tx = 0;
1180 this->current_font_matrix.ty = 0;
1182 gfxmatrix_t m = this->current_font_matrix;
1184 /*if(render != 3 && render != 0)
1185 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1186 states[statepos].textRender = render;
1189 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1190 double dx, double dy,
1191 double originX, double originY,
1192 CharCode c, int nBytes, Unicode *_u, int uLen)
1194 int render = state->getRender();
1195 // check for invisible text -- this is used by Acrobat Capture
1197 msg("<debug> Ignoring invisible text: char %d at %f,%f", c, x, y);
1201 if(states[statepos].textRender != render)
1202 msg("<error> Internal error: drawChar.render!=beginString.render");
1204 gfxcolor_t col = getFillColor(state);
1206 Gushort *CIDToGIDMap = 0;
1207 GfxFont*font = state->getFont();
1209 if(font->getType() == fontType3) {
1210 /* type 3 chars are passed as graphics */
1211 msg("<debug> type3 char at %f/%f", x, y);
1221 if(font->isCIDFont()) {
1222 GfxCIDFont*cfont = (GfxCIDFont*)font;
1224 if(font->getType() == fontCIDType2)
1225 CIDToGIDMap = cfont->getCIDToGID();
1228 font8 = (Gfx8BitFont*)font;
1229 char**enc=font8->getEncoding();
1233 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);
1236 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);
1242 charid = getGfxCharID(current_gfxfont, c, name, u);
1244 charid = getGfxCharID(current_gfxfont, c, name, -1);
1247 /* multiple unicodes- should usually map to a ligature.
1248 if the ligature doesn't exist, we need to draw
1249 the characters one-by-one. */
1251 msg("<warning> ligature %d missing in font %s\n", c, current_font_id);
1252 for(t=0;t<uLen;t++) {
1253 drawChar(state, x, y, dx, dy, originX, originY, c, nBytes, _u+t, 1);
1259 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1260 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1264 gfxmatrix_t m = this->current_font_matrix;
1265 state->transform(x, y, &m.tx, &m.ty);
1269 if(render == RENDER_FILL) {
1270 output->drawchar(output, current_font_id, charid, &col, &m);
1272 msg("<debug> Drawing glyph %d as shape", charid);
1274 msg("<notice> Some texts will be rendered as shape");
1277 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1278 gfxline_t*tglyph = gfxline_clone(glyph);
1279 gfxline_transform(tglyph, &m);
1280 if((render&3) != RENDER_INVISIBLE) {
1281 gfxline_t*add = gfxline_clone(tglyph);
1282 current_text_stroke = gfxline_append(current_text_stroke, add);
1284 if(render&RENDER_CLIP) {
1285 gfxline_t*add = gfxline_clone(tglyph);
1286 current_text_clip = gfxline_append(current_text_clip, add);
1288 gfxline_free(tglyph);
1292 void SWFOutputDev::endString(GfxState *state)
1294 int render = state->getRender();
1295 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1296 if(states[statepos].textRender != render)
1297 msg("<error> Internal error: drawChar.render!=beginString.render");
1299 if(current_text_stroke) {
1300 /* fillstroke and stroke text rendering objects we can process right
1301 now (as there may be texts of other rendering modes in this
1302 text object)- clipping objects have to wait until endTextObject,
1304 output->setparameter(output, "mark","TXT");
1305 if((render&3) == RENDER_FILL) {
1306 fillGfxLine(state, current_text_stroke);
1307 gfxline_free(current_text_stroke);
1308 current_text_stroke = 0;
1309 } else if((render&3) == RENDER_FILLSTROKE) {
1310 fillGfxLine(state, current_text_stroke);
1311 strokeGfxline(state, current_text_stroke);
1312 gfxline_free(current_text_stroke);
1313 current_text_stroke = 0;
1314 } else if((render&3) == RENDER_STROKE) {
1315 strokeGfxline(state, current_text_stroke);
1316 gfxline_free(current_text_stroke);
1317 current_text_stroke = 0;
1319 output->setparameter(output, "mark","");
1323 void SWFOutputDev::endTextObject(GfxState *state)
1325 int render = state->getRender();
1326 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1327 if(states[statepos].textRender != render)
1328 msg("<error> Internal error: drawChar.render!=beginString.render");
1330 if(current_text_clip) {
1331 output->setparameter(output, "mark","TXT");
1332 clipToGfxLine(state, current_text_clip);
1333 output->setparameter(output, "mark","");
1334 gfxline_free(current_text_clip);
1335 current_text_clip = 0;
1339 /* the logic seems to be as following:
1340 first, beginType3Char is called, with the charcode and the coordinates.
1341 if this function returns true, it already knew about the char and has now drawn it.
1342 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1343 the all draw operations until endType3Char are part of the char (which in this moment is
1344 at the position first passed to beginType3Char). the char ends with endType3Char.
1346 The drawing operations between beginType3Char and endType3Char are somewhat different to
1347 the normal ones. For example, the fillcolor equals the stroke color.
1350 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1352 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1354 /* the character itself is going to be passed using the draw functions */
1355 return gFalse; /* gTrue= is_in_cache? */
1358 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1359 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1361 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1362 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1366 void SWFOutputDev::endType3Char(GfxState *state)
1369 msg("<debug> endType3Char");
1372 void SWFOutputDev::startFrame(int width, int height)
1374 output->startpage(output, width, height);
1377 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1379 this->currentpage = pageNum;
1381 int rot = doc->getPageRotate(1);
1384 gfxline_t clippath[5];
1386 white.r = white.g = white.b = white.a = 255;
1388 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1389 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1390 Use CropBox, not MediaBox, as page size
1397 state->transform(crop_x1,crop_y1,&x1,&y1); //x1 += user_movex; y1 += user_movey;
1398 state->transform(crop_x2,crop_y2,&x2,&y2); //x2 += user_movex; y2 += user_movey;
1400 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1401 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1404 /* apply user clip box */
1405 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1406 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1407 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1408 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1409 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1412 //msg("<verbose> Bounding box is (%f,%f)-(%f,%f) [shifted by %d/%d]", x1,y1,x2,y2, user_movex, user_movey);
1414 if(outer_clip_box) {
1415 output->endclip(output);
1419 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);
1421 msg("<verbose> page is rotated %d degrees\n", rot);
1423 clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1424 clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1425 clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1426 clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1427 clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1428 output->startclip(output, clippath); outer_clip_box = 1;
1429 output->fill(output, clippath, &white);
1432 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1434 double x1, y1, x2, y2, w;
1435 gfxline_t points[5];
1438 msg("<debug> drawlink\n");
1440 link->getRect(&x1, &y1, &x2, &y2);
1441 cvtUserToDev(x1, y1, &x, &y);
1442 points[0].type = gfx_moveTo;
1443 points[0].x = points[4].x = x + user_movex;
1444 points[0].y = points[4].y = y + user_movey;
1445 points[0].next = &points[1];
1446 cvtUserToDev(x2, y1, &x, &y);
1447 points[1].type = gfx_lineTo;
1448 points[1].x = x + user_movex;
1449 points[1].y = y + user_movey;
1450 points[1].next = &points[2];
1451 cvtUserToDev(x2, y2, &x, &y);
1452 points[2].type = gfx_lineTo;
1453 points[2].x = x + user_movex;
1454 points[2].y = y + user_movey;
1455 points[2].next = &points[3];
1456 cvtUserToDev(x1, y2, &x, &y);
1457 points[3].type = gfx_lineTo;
1458 points[3].x = x + user_movex;
1459 points[3].y = y + user_movey;
1460 points[3].next = &points[4];
1461 cvtUserToDev(x1, y1, &x, &y);
1462 points[4].type = gfx_lineTo;
1463 points[4].x = x + user_movex;
1464 points[4].y = y + user_movey;
1467 LinkAction*action=link->getAction();
1474 switch(action->getKind())
1478 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1479 LinkDest *dest=NULL;
1480 if (ha->getDest()==NULL)
1481 dest=catalog->findDest(ha->getNamedDest());
1482 else dest=ha->getDest();
1484 if (dest->isPageRef()){
1485 Ref pageref=dest->getPageRef();
1486 page=catalog->findPage(pageref.num,pageref.gen);
1488 else page=dest->getPageNum();
1489 sprintf(buf, "%d", page);
1496 LinkGoToR*l = (LinkGoToR*)action;
1497 GString*g = l->getNamedDest();
1499 s = strdup(g->getCString());
1504 LinkNamed*l = (LinkNamed*)action;
1505 GString*name = l->getName();
1507 s = strdup(name->lowerCase()->getCString());
1508 named = name->getCString();
1511 if(strstr(s, "next") || strstr(s, "forward"))
1513 page = currentpage + 1;
1515 else if(strstr(s, "prev") || strstr(s, "back"))
1517 page = currentpage - 1;
1519 else if(strstr(s, "last") || strstr(s, "end"))
1521 if(pages && pagepos>0)
1522 page = pages[pagepos-1];
1524 else if(strstr(s, "first") || strstr(s, "top"))
1532 case actionLaunch: {
1534 LinkLaunch*l = (LinkLaunch*)action;
1535 GString * str = new GString(l->getFileName());
1536 GString * params = l->getParams();
1538 str->append(params);
1539 s = strdup(str->getCString());
1545 LinkURI*l = (LinkURI*)action;
1546 GString*g = l->getURI();
1548 url = g->getCString();
1553 case actionUnknown: {
1555 LinkUnknown*l = (LinkUnknown*)action;
1560 msg("<error> Unknown link type!\n");
1565 if(!s) s = strdup("-?-");
1567 if(!linkinfo && (page || url))
1569 msg("<notice> File contains links");
1577 for(t=1;t<=pagepos;t++) {
1578 if(pages[t]==page) {
1587 sprintf(buf, "page%d", lpage);
1588 output->drawlink(output, points, buf);
1592 output->drawlink(output, points, url);
1595 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1599 void SWFOutputDev::saveState(GfxState *state) {
1600 msg("<trace> saveState\n");
1603 msg("<error> Too many nested states in pdf.");
1607 states[statepos].clipping = 0; //? shouldn't this be the current value?
1608 states[statepos].textRender = states[statepos-1].textRender;
1611 void SWFOutputDev::restoreState(GfxState *state) {
1612 msg("<trace> restoreState\n");
1614 while(states[statepos].clipping) {
1615 output->endclip(output);
1616 states[statepos].clipping--;
1621 char* SWFOutputDev::searchFont(char*name)
1625 int is_standard_font = 0;
1627 msg("<verbose> SearchFont(%s)", name);
1629 /* see if it is a pdf standard font */
1630 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1632 if(!strcmp(name, pdf2t1map[i].pdffont))
1634 name = pdf2t1map[i].filename;
1635 is_standard_font = 1;
1639 /* look in all font files */
1640 for(i=0;i<fontnum;i++)
1642 if(strstr(fonts[i].filename, name))
1644 if(!fonts[i].used) {
1647 if(!is_standard_font)
1648 msg("<notice> Using %s for %s", fonts[i].filename, name);
1650 return strdup(fonts[i].filename);
1656 void SWFOutputDev::updateLineWidth(GfxState *state)
1658 double width = state->getTransformedLineWidth();
1659 //swfoutput_setlinewidth(&output, width);
1662 void SWFOutputDev::updateLineCap(GfxState *state)
1664 int c = state->getLineCap();
1667 void SWFOutputDev::updateLineJoin(GfxState *state)
1669 int j = state->getLineJoin();
1672 void SWFOutputDev::updateFillColor(GfxState *state)
1675 double opaq = state->getFillOpacity();
1676 state->getFillRGB(&rgb);
1678 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1681 void SWFOutputDev::updateStrokeColor(GfxState *state)
1684 double opaq = state->getStrokeOpacity();
1685 state->getStrokeRGB(&rgb);
1686 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1689 void FoFiWrite(void *stream, char *data, int len)
1691 fwrite(data, len, 1, (FILE*)stream);
1694 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1696 char*tmpFileName = NULL;
1702 Object refObj, strObj;
1704 tmpFileName = mktmpname(namebuf);
1707 ret = font->getEmbeddedFontID(&embRef);
1709 msg("<verbose> Didn't get embedded font id");
1710 /* not embedded- the caller should now search the font
1711 directories for this font */
1715 f = fopen(tmpFileName, "wb");
1717 msg("<error> Couldn't create temporary Type 1 font file");
1721 /*if(font->isCIDFont()) {
1722 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1723 GString c = cidFont->getCollection();
1724 msg("<notice> Collection: %s", c.getCString());
1727 //if (font->getType() == fontType1C) {
1728 if (0) { //font->getType() == fontType1C) {
1729 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1731 msg("<error> Couldn't read embedded font file");
1734 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1736 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1737 //cvt->convertToCIDType0("test", f);
1738 //cvt->convertToType0("test", f);
1741 } else if(font->getType() == fontTrueType) {
1742 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1743 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1745 msg("<error> Couldn't read embedded font file");
1748 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1749 cvt->writeTTF(FoFiWrite, f);
1753 font->getEmbeddedFontID(&embRef);
1754 refObj.initRef(embRef.num, embRef.gen);
1755 refObj.fetch(ref, &strObj);
1757 strObj.streamReset();
1762 f4[t] = strObj.streamGetChar();
1763 f4c[t] = (char)f4[t];
1768 if(!strncmp(f4c, "true", 4)) {
1769 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1770 Change this on the fly */
1771 f4[0] = f4[2] = f4[3] = 0;
1779 while ((c = strObj.streamGetChar()) != EOF) {
1783 strObj.streamClose();
1788 return strdup(tmpFileName);
1791 char* searchForSuitableFont(GfxFont*gfxFont)
1793 char*name = getFontName(gfxFont);
1797 if(!config_use_fontconfig)
1800 #ifdef HAVE_FONTCONFIG
1801 FcPattern *pattern, *match;
1805 static int fcinitcalled = false;
1807 msg("<debug> searchForSuitableFont(%s)", name);
1809 // call init ony once
1810 if (!fcinitcalled) {
1811 msg("<debug> Initializing FontConfig...");
1812 fcinitcalled = true;
1814 msg("<debug> FontConfig Initialization failed. Disabling.");
1815 config_use_fontconfig = 0;
1818 msg("<debug> ...initialized FontConfig");
1821 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1822 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1823 if (gfxFont->isItalic()) // check for italic
1824 msg("<debug> FontConfig: Adding Italic Slant");
1825 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1826 if (gfxFont->isBold()) // check for bold
1827 msg("<debug> FontConfig: Adding Bold Weight");
1828 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1830 msg("<debug> FontConfig: Try to match...");
1831 // configure and match using the original font name
1832 FcConfigSubstitute(0, pattern, FcMatchPattern);
1833 FcDefaultSubstitute(pattern);
1834 match = FcFontMatch(0, pattern, &result);
1836 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1837 msg("<debug> FontConfig: family=%s", (char*)v);
1838 // if we get an exact match
1839 if (strcmp((char *)v, name) == 0) {
1840 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1841 filename = strdup((char*)v); // mem leak
1842 char *nfn = strrchr(filename, '/');
1843 if(nfn) fontname = strdup(nfn+1);
1844 else fontname = filename;
1846 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1848 // initialize patterns
1849 FcPatternDestroy(pattern);
1850 FcPatternDestroy(match);
1852 // now match against serif etc.
1853 if (gfxFont->isSerif()) {
1854 msg("<debug> FontConfig: Create Serif Family Pattern");
1855 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1856 } else if (gfxFont->isFixedWidth()) {
1857 msg("<debug> FontConfig: Create Monospace Family Pattern");
1858 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1860 msg("<debug> FontConfig: Create Sans Family Pattern");
1861 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1865 if (gfxFont->isItalic()) {
1866 msg("<debug> FontConfig: Adding Italic Slant");
1867 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1870 if (gfxFont->isBold()) {
1871 msg("<debug> FontConfig: Adding Bold Weight");
1872 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1875 msg("<debug> FontConfig: Try to match... (2)");
1876 // configure and match using serif etc
1877 FcConfigSubstitute (0, pattern, FcMatchPattern);
1878 FcDefaultSubstitute (pattern);
1879 match = FcFontMatch (0, pattern, &result);
1881 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1882 filename = strdup((char*)v); // mem leak
1883 char *nfn = strrchr(filename, '/');
1884 if(nfn) fontname = strdup(nfn+1);
1885 else fontname = filename;
1887 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1891 //printf("FONTCONFIG: pattern");
1892 //FcPatternPrint(pattern);
1893 //printf("FONTCONFIG: match");
1894 //FcPatternPrint(match);
1896 FcPatternDestroy(pattern);
1897 FcPatternDestroy(match);
1899 pdfswf_addfont(filename);
1906 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1908 char*fontname = 0, *filename = 0;
1909 msg("<notice> substituteFont(%s)", oldname);
1911 if(!(fontname = searchForSuitableFont(gfxFont))) {
1912 fontname = "Times-Roman";
1914 filename = searchFont(fontname);
1916 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1920 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1921 msg("<fatal> Too many fonts in file.");
1925 substitutesource[substitutepos] = strdup(oldname); //mem leak
1926 substitutetarget[substitutepos] = fontname;
1927 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1930 return strdup(filename); //mem leak
1933 void unlinkfont(char* filename)
1940 if(!strncmp(&filename[l-4],".afm",4)) {
1941 memcpy(&filename[l-4],".pfb",4);
1943 memcpy(&filename[l-4],".pfa",4);
1945 memcpy(&filename[l-4],".afm",4);
1948 if(!strncmp(&filename[l-4],".pfa",4)) {
1949 memcpy(&filename[l-4],".afm",4);
1951 memcpy(&filename[l-4],".pfa",4);
1954 if(!strncmp(&filename[l-4],".pfb",4)) {
1955 memcpy(&filename[l-4],".afm",4);
1957 memcpy(&filename[l-4],".pfb",4);
1962 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1968 int SWFOutputDev::setGfxFont(char*id, char*name, char*filename, double maxSize)
1971 fontlist_t*last=0,*l = this->fontlist;
1973 /* TODO: should this be part of the state? */
1976 if(!strcmp(l->id, id)) {
1977 current_font_id = l->id;
1978 current_gfxfont = l->font;
1980 output->addfont(output, id, current_gfxfont);
1985 if(!filename) return 0;
1987 /* A font size of e.g. 9 means the font will be scaled down by
1988 1024 and scaled up by 9. So to have a maximum error of 1/20px,
1989 we have to divide 0.05 by (fontsize/1024)
1991 double quality = (1024 * 0.05) / maxSize;
1993 msg("<verbose> Loading %s...", filename);
1994 font = gfxfont_load(filename, quality);
1995 msg("<verbose> Font %s loaded successfully", filename);
1999 l->filename = strdup(filename);
2002 current_font_id = l->id;
2003 current_gfxfont = l->font;
2009 output->addfont(output, id, current_gfxfont);
2013 void SWFOutputDev::updateFont(GfxState *state)
2015 GfxFont*gfxFont = state->getFont();
2021 char * fontid = getFontID(gfxFont);
2022 char * fontname = getFontName(gfxFont);
2024 double maxSize = 1.0;
2027 maxSize = this->info->getMaximumFontSize(fontid);
2031 /* first, look if we substituted this font before-
2032 this way, we don't initialize the T1 Fonts
2034 for(t=0;t<substitutepos;t++) {
2035 if(!strcmp(fontid, substitutesource[t])) {
2036 free(fontid);fontid=0;
2037 fontid = strdup(substitutetarget[t]);
2042 /* second, see if this is a font which was used before-
2043 if so, we are done */
2044 if(setGfxFont(fontid, fontname, 0, 0)) {
2049 /* if(swfoutput_queryfont(&output, fontid))
2050 swfoutput_setfont(&output, fontid, 0);
2052 msg("<debug> updateFont(%s) [cached]", fontid);
2056 // look for Type 3 font
2057 if (gfxFont->getType() == fontType3) {
2059 type3Warning = gTrue;
2060 showFontError(gfxFont, 2);
2067 /* now either load the font, or find a substitution */
2070 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
2075 (gfxFont->getType() == fontType1 ||
2076 gfxFont->getType() == fontType1C ||
2077 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
2078 gfxFont->getType() == fontTrueType ||
2079 gfxFont->getType() == fontCIDType2
2082 fileName = writeEmbeddedFontToFile(xref, gfxFont);
2083 if(!fileName) showFontError(gfxFont,0);
2086 fileName = searchFont(fontname);
2087 if(!fileName) showFontError(gfxFont,0);
2090 char * fontname = getFontName(gfxFont);
2091 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
2094 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into %s", fontname, lastfontdir);
2096 msg("<warning> Try specifying one or more font directories");
2098 fileName = substituteFont(gfxFont, fontid);
2101 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
2102 msg("<notice> Font is now %s (%s)", fontid, fileName);
2106 msg("<error> Couldn't set font %s\n", fontid);
2112 msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
2113 dumpFontInfo("<verbose>", gfxFont);
2115 //swfoutput_setfont(&output, fontid, fileName);
2117 if(!setGfxFont(fontid, fontname, 0, 0)) {
2118 setGfxFont(fontid, fontname, fileName, maxSize);
2122 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;
2305 imgStr = new ImageStream(str, width, ncomps,bits);
2308 if(!width || !height || (height<=1 && width<=1))
2310 msg("<verbose> Ignoring %d by %d image", width, height);
2311 unsigned char buf[8];
2313 for (y = 0; y < height; ++y)
2314 for (x = 0; x < width; ++x) {
2315 imgStr->getPixel(buf);
2323 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1 += user_movey;
2324 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2 += user_movey;
2325 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3 += user_movey;
2326 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4 += user_movey;
2329 if(!pbminfo && !(str->getKind()==strDCT)) {
2331 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2335 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2337 if(!jpeginfo && (str->getKind()==strDCT)) {
2338 msg("<notice> file contains jpeg pictures");
2344 unsigned char buf[8];
2346 unsigned char*pic = new unsigned char[width*height];
2347 gfxcolor_t pal[256];
2349 state->getFillRGB(&rgb);
2351 memset(pal,255,sizeof(pal));
2352 pal[0].r = (int)(colToByte(rgb.r)); pal[1].r = 0;
2353 pal[0].g = (int)(colToByte(rgb.g)); pal[1].g = 0;
2354 pal[0].b = (int)(colToByte(rgb.b)); pal[1].b = 0;
2355 pal[0].a = 255; pal[1].a = 0;
2358 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2359 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2360 for (y = 0; y < height; ++y)
2361 for (x = 0; x < width; ++x)
2363 imgStr->getPixel(buf);
2366 pic[width*y+x] = buf[0];
2369 /* the size of the drawn image is added to the identifier
2370 as the same image may require different bitmaps if displayed
2371 at different sizes (due to antialiasing): */
2374 unsigned char*pic2 = 0;
2377 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2386 height = realheight;
2390 /* make a black/white palette */
2392 float r = 255/(numpalette-1);
2394 for(t=0;t<numpalette;t++) {
2395 pal[t].r = colToByte(rgb.r);
2396 pal[t].g = colToByte(rgb.g);
2397 pal[t].b = colToByte(rgb.b);
2398 pal[t].a = (unsigned char)(t*r);
2402 gfxcolor_t*pic2 = new gfxcolor_t[width*height];
2403 for (y = 0; y < height; ++y) {
2404 for (x = 0; x < width; ++x) {
2405 pic2[width*y+x] = pal[pic[y*width+x]];
2408 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2412 if(maskbitmap) free(maskbitmap);
2418 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2419 gfxcolor_t*pic=new gfxcolor_t[width*height];
2420 for (y = 0; y < height; ++y) {
2421 for (x = 0; x < width; ++x) {
2422 imgStr->getPixel(pixBuf);
2423 colorMap->getRGB(pixBuf, &rgb);
2424 pic[width*y+x].r = (unsigned char)(colToByte(rgb.r));
2425 pic[width*y+x].g = (unsigned char)(colToByte(rgb.g));
2426 pic[width*y+x].b = (unsigned char)(colToByte(rgb.b));
2427 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2429 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2433 if(str->getKind()==strDCT)
2434 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2436 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2439 if(maskbitmap) free(maskbitmap);
2442 gfxcolor_t*pic=new gfxcolor_t[width*height];
2443 gfxcolor_t pal[256];
2444 int n = 1 << colorMap->getBits();
2446 for(t=0;t<256;t++) {
2448 colorMap->getRGB(pixBuf, &rgb);
2450 {/*if(maskColors && *maskColors==t) {
2451 msg("<notice> Color %d is transparent", t);
2452 if (imgData->maskColors) {
2454 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2455 if (pix[i] < imgData->maskColors[2*i] ||
2456 pix[i] > imgData->maskColors[2*i+1]) {
2471 pal[t].r = (unsigned char)(colToByte(rgb.r));
2472 pal[t].g = (unsigned char)(colToByte(rgb.g));
2473 pal[t].b = (unsigned char)(colToByte(rgb.b));
2474 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2477 for (y = 0; y < height; ++y) {
2478 for (x = 0; x < width; ++x) {
2479 imgStr->getPixel(pixBuf);
2480 pic[width*y+x] = pal[pixBuf[0]];
2482 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2486 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2490 if(maskbitmap) free(maskbitmap);
2495 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2496 int width, int height, GBool invert,
2499 if(states[statepos].textRender & 4) //clipped
2501 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2502 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0, 0,0,0,0, 0);
2505 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2506 int width, int height, GfxImageColorMap *colorMap,
2507 int *maskColors, GBool inlineImg)
2509 if(states[statepos].textRender & 4) //clipped
2512 msg("<verbose> drawImage %dx%d, %s, %s, inline=%d", width, height,
2513 colorMap?"colorMap":"no colorMap",
2514 maskColors?"maskColors":"no maskColors",
2517 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2518 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2519 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors, 0,0,0,0, 0);
2522 void SWFOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
2523 int width, int height,
2524 GfxImageColorMap *colorMap,
2525 Stream *maskStr, int maskWidth, int maskHeight,
2528 if(states[statepos].textRender & 4) //clipped
2531 msg("<verbose> drawMaskedImage %dx%d, %s, %dx%d mask", width, height,
2532 colorMap?"colorMap":"no colorMap",
2533 maskWidth, maskHeight);
2535 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2536 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2537 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, maskInvert, 0);
2540 void SWFOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
2541 int width, int height,
2542 GfxImageColorMap *colorMap,
2544 int maskWidth, int maskHeight,
2545 GfxImageColorMap *maskColorMap)
2547 if(states[statepos].textRender & 4) //clipped
2550 msg("<verbose> drawSoftMaskedImage %dx%d, %s, %dx%d mask", width, height,
2551 colorMap?"colorMap":"no colorMap",
2552 maskWidth, maskHeight);
2554 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2555 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2556 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, 0, maskColorMap);
2559 //SWFOutputDev*output = 0;
2561 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2566 if (infoDict->lookup(key, &obj)->isString()) {
2567 s1 = obj.getString();
2568 if ((s1->getChar(0) & 0xff) == 0xfe &&
2569 (s1->getChar(1) & 0xff) == 0xff) {
2571 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2572 if (s1->getChar(i) == '\0') {
2573 s2->append(s1->getChar(i+1));
2576 s2 = new GString("<unicode>");
2580 printf(fmt, s2->getCString());
2583 printf(fmt, s1->getCString());
2589 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2593 if (infoDict->lookup(key, &obj)->isString()) {
2594 s = obj.getString()->getCString();
2595 if (s[0] == 'D' && s[1] == ':') {
2606 void storeDeviceParameter(char*name, char*value)
2608 parameter_t*p = new parameter_t();
2609 p->name = strdup(name);
2610 p->value = strdup(value);
2612 if(device_config_next) {
2613 device_config_next->next = p;
2614 device_config_next = p;
2617 device_config_next = p;
2621 void pdfswf_setparameter(char*name, char*value)
2623 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2624 if(!strcmp(name, "caplinewidth")) {
2625 caplinewidth = atof(value);
2626 } else if(!strcmp(name, "zoom")) {
2629 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2630 storeDeviceParameter("jpegsubpixels", buf);
2631 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2632 storeDeviceParameter("ppmsubpixels", buf);
2633 } else if(!strcmp(name, "jpegdpi")) {
2635 jpeg_dpi = atoi(value);
2636 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2637 storeDeviceParameter("jpegsubpixels", buf);
2638 } else if(!strcmp(name, "ppmdpi")) {
2640 ppm_dpi = atoi(value);
2641 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2642 storeDeviceParameter("ppmsubpixels", buf);
2643 } else if(!strcmp(name, "forceType0Fonts")) {
2644 forceType0Fonts = atoi(value);
2645 } else if(!strncmp(name, "fontdir", strlen("fontdir"))) {
2646 pdfswf_addfontdir(value);
2647 } else if(!strncmp(name, "languagedir", strlen("languagedir"))) {
2648 pdfswf_addlanguagedir(value);
2649 } else if(!strcmp(name, "fontconfig")) {
2650 config_use_fontconfig = atoi(value);
2652 storeDeviceParameter(name,value);
2655 void pdfswf_addfont(char*filename)
2658 memset(&f, 0, sizeof(fontfile_t));
2659 f.filename = filename;
2660 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2661 fonts[fontnum++] = f;
2663 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2667 static char* dirseparator()
2676 void pdfswf_addlanguagedir(char*dir)
2679 globalParams = new GlobalParams("");
2681 msg("<notice> Adding %s to language pack directories", dir);
2685 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc") + 1);
2686 strcpy(config_file, dir);
2687 strcat(config_file, dirseparator());
2688 strcat(config_file, "add-to-xpdfrc");
2690 fi = fopen(config_file, "rb");
2692 msg("<error> Could not open %s", config_file);
2695 globalParams->parseFile(new GString(config_file), fi);
2699 void pdfswf_addfontdir(char*dirname)
2701 #ifdef HAVE_DIRENT_H
2702 msg("<notice> Adding %s to font directories", dirname);
2703 lastfontdir = strdup(dirname);
2704 DIR*dir = opendir(dirname);
2706 msg("<warning> Couldn't open directory %s\n", dirname);
2711 ent = readdir (dir);
2715 char*name = ent->d_name;
2721 if(!strncasecmp(&name[l-4], ".pfa", 4))
2723 if(!strncasecmp(&name[l-4], ".pfb", 4))
2725 if(!strncasecmp(&name[l-4], ".ttf", 4))
2729 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2730 strcpy(fontname, dirname);
2731 strcat(fontname, dirseparator());
2732 strcat(fontname, name);
2733 msg("<verbose> Adding %s to fonts", fontname);
2734 pdfswf_addfont(fontname);
2739 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2744 typedef struct _pdf_doc_internal
2749 } pdf_doc_internal_t;
2750 typedef struct _pdf_page_internal
2752 } pdf_page_internal_t;
2753 typedef struct _dev_output_internal
2755 SWFOutputDev*outputDev;
2756 } dev_output_internal_t;
2758 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2760 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2761 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2762 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2763 memset(i, 0, sizeof(pdf_doc_internal_t));
2764 pdf_doc->internal = i;
2766 GString *fileName = new GString(filename);
2772 globalParams = new GlobalParams("");
2775 if (userPassword && userPassword[0]) {
2776 userPW = new GString(userPassword);
2780 i->doc = new PDFDoc(fileName, userPW);
2784 if (!i->doc->isOk()) {
2789 i->doc->getDocInfo(&info);
2790 if (info.isDict() &&
2791 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2792 printInfoString(info.getDict(), "Title", "Title: %s\n");
2793 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2794 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2795 printInfoString(info.getDict(), "Author", "Author: %s\n");
2796 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2797 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2798 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2799 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2800 printf("Pages: %d\n", i->doc->getNumPages());
2801 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2802 printf("Encrypted: ");
2803 if (i->doc->isEncrypted()) {
2804 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2805 i->doc->okToPrint() ? "yes" : "no",
2806 i->doc->okToCopy() ? "yes" : "no",
2807 i->doc->okToChange() ? "yes" : "no",
2808 i->doc->okToAddNotes() ? "yes" : "no");
2815 pdf_doc->num_pages = i->doc->getNumPages();
2817 if (i->doc->isEncrypted()) {
2818 if(!i->doc->okToCopy()) {
2819 printf("PDF disallows copying.\n");
2822 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2826 InfoOutputDev*io = new InfoOutputDev();
2828 for(t=1;t<=pdf_doc->num_pages;t++) {
2829 i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, /*usemediabox*/true, /*crop*/true, /*doLinks*/(int)1);
2840 delete globalParams;globalParams=0;
2841 Object::memCheck(stderr);
2846 void pdf_destroy(pdf_doc_t*pdf_doc)
2848 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2850 delete i->doc; i->doc=0;
2853 delete i->info;i->info=0;
2856 free(pdf_doc->internal);pdf_doc->internal=0;
2857 free(pdf_doc);pdf_doc=0;
2860 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2862 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2864 if(page < 1 || page > pdf_doc->num_pages)
2867 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2868 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2869 memset(pi, 0, sizeof(pdf_page_internal_t));
2870 pdf_page->internal = pi;
2872 pdf_page->parent = pdf_doc;
2873 pdf_page->nr = page;
2877 void pdf_page_destroy(pdf_page_t*pdf_page)
2879 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2880 free(pdf_page->internal);pdf_page->internal = 0;
2881 free(pdf_page);pdf_page=0;
2884 dev_output_t* dev_output_init(gfxdevice_t*dev)
2886 dev_output_t*dev_output = (dev_output_t*)malloc(sizeof(dev_output_t));
2887 memset(dev_output, 0, sizeof(dev_output_t));
2888 dev_output_internal_t*i= (dev_output_internal_t*)malloc(sizeof(dev_output_internal_t));
2889 memset(i, 0, sizeof(dev_output_internal_t));
2890 dev_output->internal = i;
2892 i->outputDev = new SWFOutputDev(dev);
2896 void dev_output_setparameter(dev_output_t*swf, char*name, char*value)
2898 pdfswf_setparameter(name, value);
2901 void dev_output_startframe(dev_output_t*swf, int width, int height)
2903 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2904 i->outputDev->startFrame(width, height);
2907 void dev_output_endframe(dev_output_t*swf)
2909 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2910 i->outputDev->endframe();
2913 void dev_output_finish(dev_output_t*swf)
2915 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2916 i->outputDev->finish();
2919 void dev_output_preparepage(dev_output_t*swf, int pdfpage, int outputpage)
2921 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2922 SWFOutputDev*o = i->outputDev;
2928 o->pagebuflen = 1024;
2929 o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
2930 memset(o->pages, -1, o->pagebuflen*sizeof(int));
2932 while(pdfpage >= o->pagebuflen)
2934 int oldlen = o->pagebuflen;
2935 o->pagebuflen+=1024;
2936 o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
2937 memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
2940 o->pages[pdfpage] = outputpage;
2941 if(pdfpage>o->pagepos)
2942 o->pagepos = pdfpage;
2945 void dev_output_destroy(dev_output_t*output)
2947 dev_output_internal_t*i = (dev_output_internal_t*)output->internal;
2948 delete i->outputDev; i->outputDev=0;
2949 free(output->internal);output->internal=0;
2953 void pdf_page_render2(pdf_page_t*page, dev_output_t*swf)
2955 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2956 dev_output_internal_t*si = (dev_output_internal_t*)swf->internal;
2959 msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2964 gfxdevice_t*dev = si->outputDev->output;
2965 dev->setparameter(dev, "protect", "1");
2967 si->outputDev->setInfo(pi->info);
2968 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2969 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
2972 void pdf_page_rendersection(pdf_page_t*page, dev_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2974 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2975 dev_output_internal_t*si = (dev_output_internal_t*)output->internal;
2977 si->outputDev->setMove(x,y);
2978 if((x1|y1|x2|y2)==0) x2++;
2979 si->outputDev->setClip(x1,y1,x2,y2);
2981 pdf_page_render2(page, output);
2983 void pdf_page_render(pdf_page_t*page, dev_output_t*output)
2985 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2986 dev_output_internal_t*si = (dev_output_internal_t*)output->internal;
2988 si->outputDev->setMove(0,0);
2989 si->outputDev->setClip(0,0,0,0);
2991 pdf_page_render2(page, output);
2995 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2997 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2998 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2999 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
3000 memset(info, 0, sizeof(pdf_page_info_t));
3002 InfoOutputDev*output = new InfoOutputDev;
3004 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
3006 info->xMin = output->x1;
3007 info->yMin = output->y1;
3008 info->xMax = output->x2;
3009 info->yMax = output->y2;
3010 info->number_of_images = output->num_images;
3011 info->number_of_links = output->num_links;
3012 info->number_of_fonts = output->num_fonts;
3019 void pdf_page_info_destroy(pdf_page_info_t*info)