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 msg("<trace> drawlink %.2f/%.2f %.2f/%.2f %.2f/%.2f %.2f/%.2f\n",
1468 points[0].x, points[0].y,
1469 points[1].x, points[1].y,
1470 points[2].x, points[2].y,
1471 points[3].x, points[3].y);
1473 LinkAction*action=link->getAction();
1479 msg("<trace> drawlink action=%d\n", action->getKind());
1480 switch(action->getKind())
1484 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1485 LinkDest *dest=NULL;
1486 if (ha->getDest()==NULL)
1487 dest=catalog->findDest(ha->getNamedDest());
1488 else dest=ha->getDest();
1490 if (dest->isPageRef()){
1491 Ref pageref=dest->getPageRef();
1492 page=catalog->findPage(pageref.num,pageref.gen);
1494 else page=dest->getPageNum();
1495 sprintf(buf, "%d", page);
1502 LinkGoToR*l = (LinkGoToR*)action;
1503 GString*g = l->getNamedDest();
1505 s = strdup(g->getCString());
1510 LinkNamed*l = (LinkNamed*)action;
1511 GString*name = l->getName();
1513 s = strdup(name->lowerCase()->getCString());
1514 named = name->getCString();
1517 if(strstr(s, "next") || strstr(s, "forward"))
1519 page = currentpage + 1;
1521 else if(strstr(s, "prev") || strstr(s, "back"))
1523 page = currentpage - 1;
1525 else if(strstr(s, "last") || strstr(s, "end"))
1527 if(pages && pagepos>0)
1528 page = pages[pagepos-1];
1530 else if(strstr(s, "first") || strstr(s, "top"))
1538 case actionLaunch: {
1540 LinkLaunch*l = (LinkLaunch*)action;
1541 GString * str = new GString(l->getFileName());
1542 GString * params = l->getParams();
1544 str->append(params);
1545 s = strdup(str->getCString());
1552 LinkURI*l = (LinkURI*)action;
1553 GString*g = l->getURI();
1555 url = g->getCString();
1560 case actionUnknown: {
1562 LinkUnknown*l = (LinkUnknown*)action;
1567 msg("<error> Unknown link type!\n");
1572 if(!s) s = strdup("-?-");
1574 msg("<trace> drawlink s=%s\n", s);
1576 if(!linkinfo && (page || s))
1578 msg("<notice> File contains links");
1586 for(t=1;t<=pagepos;t++) {
1587 if(pages[t]==page) {
1596 sprintf(buf, "page%d", lpage);
1597 output->drawlink(output, points, buf);
1601 output->drawlink(output, points, s);
1604 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1608 void SWFOutputDev::saveState(GfxState *state) {
1609 msg("<trace> saveState\n");
1612 msg("<error> Too many nested states in pdf.");
1616 states[statepos].clipping = 0; //? shouldn't this be the current value?
1617 states[statepos].textRender = states[statepos-1].textRender;
1620 void SWFOutputDev::restoreState(GfxState *state) {
1621 msg("<trace> restoreState\n");
1623 while(states[statepos].clipping) {
1624 output->endclip(output);
1625 states[statepos].clipping--;
1630 char* SWFOutputDev::searchFont(char*name)
1634 int is_standard_font = 0;
1636 msg("<verbose> SearchFont(%s)", name);
1638 /* see if it is a pdf standard font */
1639 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1641 if(!strcmp(name, pdf2t1map[i].pdffont))
1643 name = pdf2t1map[i].filename;
1644 is_standard_font = 1;
1648 /* look in all font files */
1649 for(i=0;i<fontnum;i++)
1651 if(strstr(fonts[i].filename, name))
1653 if(!fonts[i].used) {
1656 if(!is_standard_font)
1657 msg("<notice> Using %s for %s", fonts[i].filename, name);
1659 return strdup(fonts[i].filename);
1665 void SWFOutputDev::updateLineWidth(GfxState *state)
1667 double width = state->getTransformedLineWidth();
1668 //swfoutput_setlinewidth(&output, width);
1671 void SWFOutputDev::updateLineCap(GfxState *state)
1673 int c = state->getLineCap();
1676 void SWFOutputDev::updateLineJoin(GfxState *state)
1678 int j = state->getLineJoin();
1681 void SWFOutputDev::updateFillColor(GfxState *state)
1684 double opaq = state->getFillOpacity();
1685 state->getFillRGB(&rgb);
1687 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1690 void SWFOutputDev::updateStrokeColor(GfxState *state)
1693 double opaq = state->getStrokeOpacity();
1694 state->getStrokeRGB(&rgb);
1695 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1698 void FoFiWrite(void *stream, char *data, int len)
1700 fwrite(data, len, 1, (FILE*)stream);
1703 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1705 char*tmpFileName = NULL;
1711 Object refObj, strObj;
1713 tmpFileName = mktmpname(namebuf);
1716 ret = font->getEmbeddedFontID(&embRef);
1718 msg("<verbose> Didn't get embedded font id");
1719 /* not embedded- the caller should now search the font
1720 directories for this font */
1724 f = fopen(tmpFileName, "wb");
1726 msg("<error> Couldn't create temporary Type 1 font file");
1730 /*if(font->isCIDFont()) {
1731 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1732 GString c = cidFont->getCollection();
1733 msg("<notice> Collection: %s", c.getCString());
1736 //if (font->getType() == fontType1C) {
1737 if (0) { //font->getType() == fontType1C) {
1738 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1740 msg("<error> Couldn't read embedded font file");
1743 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1745 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1746 //cvt->convertToCIDType0("test", f);
1747 //cvt->convertToType0("test", f);
1750 } else if(font->getType() == fontTrueType) {
1751 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1752 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1754 msg("<error> Couldn't read embedded font file");
1757 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1758 cvt->writeTTF(FoFiWrite, f);
1762 font->getEmbeddedFontID(&embRef);
1763 refObj.initRef(embRef.num, embRef.gen);
1764 refObj.fetch(ref, &strObj);
1766 strObj.streamReset();
1771 f4[t] = strObj.streamGetChar();
1772 f4c[t] = (char)f4[t];
1777 if(!strncmp(f4c, "true", 4)) {
1778 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1779 Change this on the fly */
1780 f4[0] = f4[2] = f4[3] = 0;
1788 while ((c = strObj.streamGetChar()) != EOF) {
1792 strObj.streamClose();
1797 return strdup(tmpFileName);
1800 char* searchForSuitableFont(GfxFont*gfxFont)
1802 char*name = getFontName(gfxFont);
1806 if(!config_use_fontconfig)
1809 #ifdef HAVE_FONTCONFIG
1810 FcPattern *pattern, *match;
1814 static int fcinitcalled = false;
1816 msg("<debug> searchForSuitableFont(%s)", name);
1818 // call init ony once
1819 if (!fcinitcalled) {
1820 msg("<debug> Initializing FontConfig...");
1821 fcinitcalled = true;
1823 msg("<debug> FontConfig Initialization failed. Disabling.");
1824 config_use_fontconfig = 0;
1827 msg("<debug> ...initialized FontConfig");
1830 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1831 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1832 if (gfxFont->isItalic()) // check for italic
1833 msg("<debug> FontConfig: Adding Italic Slant");
1834 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1835 if (gfxFont->isBold()) // check for bold
1836 msg("<debug> FontConfig: Adding Bold Weight");
1837 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1839 msg("<debug> FontConfig: Try to match...");
1840 // configure and match using the original font name
1841 FcConfigSubstitute(0, pattern, FcMatchPattern);
1842 FcDefaultSubstitute(pattern);
1843 match = FcFontMatch(0, pattern, &result);
1845 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1846 msg("<debug> FontConfig: family=%s", (char*)v);
1847 // if we get an exact match
1848 if (strcmp((char *)v, name) == 0) {
1849 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1850 filename = strdup((char*)v); // mem leak
1851 char *nfn = strrchr(filename, '/');
1852 if(nfn) fontname = strdup(nfn+1);
1853 else fontname = filename;
1855 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1857 // initialize patterns
1858 FcPatternDestroy(pattern);
1859 FcPatternDestroy(match);
1861 // now match against serif etc.
1862 if (gfxFont->isSerif()) {
1863 msg("<debug> FontConfig: Create Serif Family Pattern");
1864 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1865 } else if (gfxFont->isFixedWidth()) {
1866 msg("<debug> FontConfig: Create Monospace Family Pattern");
1867 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1869 msg("<debug> FontConfig: Create Sans Family Pattern");
1870 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1874 if (gfxFont->isItalic()) {
1875 msg("<debug> FontConfig: Adding Italic Slant");
1876 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1879 if (gfxFont->isBold()) {
1880 msg("<debug> FontConfig: Adding Bold Weight");
1881 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1884 msg("<debug> FontConfig: Try to match... (2)");
1885 // configure and match using serif etc
1886 FcConfigSubstitute (0, pattern, FcMatchPattern);
1887 FcDefaultSubstitute (pattern);
1888 match = FcFontMatch (0, pattern, &result);
1890 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1891 filename = strdup((char*)v); // mem leak
1892 char *nfn = strrchr(filename, '/');
1893 if(nfn) fontname = strdup(nfn+1);
1894 else fontname = filename;
1896 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1900 //printf("FONTCONFIG: pattern");
1901 //FcPatternPrint(pattern);
1902 //printf("FONTCONFIG: match");
1903 //FcPatternPrint(match);
1905 FcPatternDestroy(pattern);
1906 FcPatternDestroy(match);
1908 pdfswf_addfont(filename);
1915 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1917 char*fontname = 0, *filename = 0;
1918 msg("<notice> substituteFont(%s)", oldname);
1920 if(!(fontname = searchForSuitableFont(gfxFont))) {
1921 fontname = "Times-Roman";
1923 filename = searchFont(fontname);
1925 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1929 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1930 msg("<fatal> Too many fonts in file.");
1934 substitutesource[substitutepos] = strdup(oldname); //mem leak
1935 substitutetarget[substitutepos] = fontname;
1936 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1939 return strdup(filename); //mem leak
1942 void unlinkfont(char* filename)
1949 if(!strncmp(&filename[l-4],".afm",4)) {
1950 memcpy(&filename[l-4],".pfb",4);
1952 memcpy(&filename[l-4],".pfa",4);
1954 memcpy(&filename[l-4],".afm",4);
1957 if(!strncmp(&filename[l-4],".pfa",4)) {
1958 memcpy(&filename[l-4],".afm",4);
1960 memcpy(&filename[l-4],".pfa",4);
1963 if(!strncmp(&filename[l-4],".pfb",4)) {
1964 memcpy(&filename[l-4],".afm",4);
1966 memcpy(&filename[l-4],".pfb",4);
1971 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1977 int SWFOutputDev::setGfxFont(char*id, char*name, char*filename, double maxSize)
1980 fontlist_t*last=0,*l = this->fontlist;
1982 /* TODO: should this be part of the state? */
1985 if(!strcmp(l->id, id)) {
1986 current_font_id = l->id;
1987 current_gfxfont = l->font;
1989 output->addfont(output, id, current_gfxfont);
1994 if(!filename) return 0;
1996 /* A font size of e.g. 9 means the font will be scaled down by
1997 1024 and scaled up by 9. So to have a maximum error of 1/20px,
1998 we have to divide 0.05 by (fontsize/1024)
2000 double quality = (1024 * 0.05) / maxSize;
2002 msg("<verbose> Loading %s...", filename);
2003 font = gfxfont_load(filename, quality);
2004 msg("<verbose> Font %s loaded successfully", filename);
2008 l->filename = strdup(filename);
2011 current_font_id = l->id;
2012 current_gfxfont = l->font;
2018 output->addfont(output, id, current_gfxfont);
2022 void SWFOutputDev::updateFont(GfxState *state)
2024 GfxFont*gfxFont = state->getFont();
2030 char * fontid = getFontID(gfxFont);
2031 char * fontname = getFontName(gfxFont);
2033 double maxSize = 1.0;
2036 maxSize = this->info->getMaximumFontSize(fontid);
2040 /* first, look if we substituted this font before-
2041 this way, we don't initialize the T1 Fonts
2043 for(t=0;t<substitutepos;t++) {
2044 if(!strcmp(fontid, substitutesource[t])) {
2045 free(fontid);fontid=0;
2046 fontid = strdup(substitutetarget[t]);
2051 /* second, see if this is a font which was used before-
2052 if so, we are done */
2053 if(setGfxFont(fontid, fontname, 0, 0)) {
2058 /* if(swfoutput_queryfont(&output, fontid))
2059 swfoutput_setfont(&output, fontid, 0);
2061 msg("<debug> updateFont(%s) [cached]", fontid);
2065 // look for Type 3 font
2066 if (gfxFont->getType() == fontType3) {
2068 type3Warning = gTrue;
2069 showFontError(gfxFont, 2);
2076 /* now either load the font, or find a substitution */
2079 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
2084 (gfxFont->getType() == fontType1 ||
2085 gfxFont->getType() == fontType1C ||
2086 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
2087 gfxFont->getType() == fontTrueType ||
2088 gfxFont->getType() == fontCIDType2
2091 fileName = writeEmbeddedFontToFile(xref, gfxFont);
2092 if(!fileName) showFontError(gfxFont,0);
2095 fileName = searchFont(fontname);
2096 if(!fileName) showFontError(gfxFont,0);
2099 char * fontname = getFontName(gfxFont);
2100 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
2103 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into %s", fontname, lastfontdir);
2105 msg("<warning> Try specifying one or more font directories");
2107 fileName = substituteFont(gfxFont, fontid);
2110 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
2111 msg("<notice> Font is now %s (%s)", fontid, fileName);
2115 msg("<error> Couldn't set font %s\n", fontid);
2121 msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
2122 dumpFontInfo("<verbose>", gfxFont);
2124 //swfoutput_setfont(&output, fontid, fileName);
2126 if(!setGfxFont(fontid, fontname, 0, 0)) {
2127 setGfxFont(fontid, fontname, fileName, maxSize);
2131 unlinkfont(fileName);
2141 #define SQR(x) ((x)*(x))
2143 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
2145 if((newwidth<2 || newheight<2) ||
2146 (width<=newwidth || height<=newheight))
2148 unsigned char*newdata;
2150 newdata= (unsigned char*)malloc(newwidth*newheight);
2152 double fx = (double)(width)/newwidth;
2153 double fy = (double)(height)/newheight;
2155 int blocksize = (int)(8192/(fx*fy));
2156 int r = 8192*256/palettesize;
2157 for(x=0;x<newwidth;x++) {
2158 double ex = px + fx;
2159 int fromx = (int)px;
2161 int xweight1 = (int)(((fromx+1)-px)*256);
2162 int xweight2 = (int)((ex-tox)*256);
2164 for(y=0;y<newheight;y++) {
2165 double ey = py + fy;
2166 int fromy = (int)py;
2168 int yweight1 = (int)(((fromy+1)-py)*256);
2169 int yweight2 = (int)((ey-toy)*256);
2172 for(xx=fromx;xx<=tox;xx++)
2173 for(yy=fromy;yy<=toy;yy++) {
2174 int b = 1-data[width*yy+xx];
2176 if(xx==fromx) weight = (weight*xweight1)/256;
2177 if(xx==tox) weight = (weight*xweight2)/256;
2178 if(yy==fromy) weight = (weight*yweight1)/256;
2179 if(yy==toy) weight = (weight*yweight2)/256;
2182 //if(a) a=(palettesize-1)*r/blocksize;
2183 newdata[y*newwidth+x] = (a*blocksize)/r;
2191 #define IMAGE_TYPE_JPEG 0
2192 #define IMAGE_TYPE_LOSSLESS 1
2194 static void drawimage(gfxdevice_t*dev, gfxcolor_t* data, int sizex,int sizey,
2195 double x1,double y1,
2196 double x2,double y2,
2197 double x3,double y3,
2198 double x4,double y4, int type)
2200 gfxcolor_t*newpic=0;
2202 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2203 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2205 gfxline_t p1,p2,p3,p4,p5;
2206 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2207 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2208 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2209 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2210 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2212 {p1.x = (int)(p1.x*20)/20.0;
2213 p1.y = (int)(p1.y*20)/20.0;
2214 p2.x = (int)(p2.x*20)/20.0;
2215 p2.y = (int)(p2.y*20)/20.0;
2216 p3.x = (int)(p3.x*20)/20.0;
2217 p3.y = (int)(p3.y*20)/20.0;
2218 p4.x = (int)(p4.x*20)/20.0;
2219 p4.y = (int)(p4.y*20)/20.0;
2220 p5.x = (int)(p5.x*20)/20.0;
2221 p5.y = (int)(p5.y*20)/20.0;
2228 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2229 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2234 img.data = (gfxcolor_t*)data;
2238 if(type == IMAGE_TYPE_JPEG)
2239 /* TODO: pass image_dpi to device instead */
2240 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2242 dev->fillbitmap(dev, &p1, &img, &m, 0);
2245 void drawimagejpeg(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2246 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2248 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2251 void drawimagelossless(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2252 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2254 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2258 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2259 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2260 GBool inlineImg, int mask, int*maskColors,
2261 Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GfxImageColorMap*maskColorMap)
2263 double x1,y1,x2,y2,x3,y3,x4,y4;
2264 ImageStream *imgStr;
2269 unsigned char* maskbitmap = 0;
2272 ncomps = colorMap->getNumPixelComps();
2273 bits = colorMap->getBits();
2278 unsigned char buf[8];
2279 maskbitmap = (unsigned char*)malloc(maskHeight*maskWidth);
2281 ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, maskColorMap->getNumPixelComps(), maskColorMap->getBits());
2282 imgMaskStr->reset();
2283 unsigned char pal[256];
2284 int n = 1 << colorMap->getBits();
2289 maskColorMap->getGray(pixBuf, &gray);
2290 pal[t] = colToByte(gray);
2292 for (y = 0; y < maskHeight; y++) {
2293 for (x = 0; x < maskWidth; x++) {
2294 imgMaskStr->getPixel(buf);
2295 maskbitmap[y*maskWidth+x] = pal[buf[0]];
2300 ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, 1, 1);
2301 imgMaskStr->reset();
2302 for (y = 0; y < maskHeight; y++) {
2303 for (x = 0; x < maskWidth; x++) {
2304 imgMaskStr->getPixel(buf);
2306 maskbitmap[y*maskWidth+x] = (buf[0]^1)*255;
2314 imgStr = new ImageStream(str, width, ncomps,bits);
2317 if(!width || !height || (height<=1 && width<=1))
2319 msg("<verbose> Ignoring %d by %d image", width, height);
2320 unsigned char buf[8];
2322 for (y = 0; y < height; ++y)
2323 for (x = 0; x < width; ++x) {
2324 imgStr->getPixel(buf);
2332 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1 += user_movey;
2333 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2 += user_movey;
2334 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3 += user_movey;
2335 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4 += user_movey;
2338 if(!pbminfo && !(str->getKind()==strDCT)) {
2340 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2344 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2346 if(!jpeginfo && (str->getKind()==strDCT)) {
2347 msg("<notice> file contains jpeg pictures");
2353 unsigned char buf[8];
2355 unsigned char*pic = new unsigned char[width*height];
2356 gfxcolor_t pal[256];
2358 state->getFillRGB(&rgb);
2360 memset(pal,255,sizeof(pal));
2361 pal[0].r = (int)(colToByte(rgb.r)); pal[1].r = 0;
2362 pal[0].g = (int)(colToByte(rgb.g)); pal[1].g = 0;
2363 pal[0].b = (int)(colToByte(rgb.b)); pal[1].b = 0;
2364 pal[0].a = 255; pal[1].a = 0;
2367 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2368 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2369 for (y = 0; y < height; ++y)
2370 for (x = 0; x < width; ++x)
2372 imgStr->getPixel(buf);
2375 pic[width*y+x] = buf[0];
2378 /* the size of the drawn image is added to the identifier
2379 as the same image may require different bitmaps if displayed
2380 at different sizes (due to antialiasing): */
2383 unsigned char*pic2 = 0;
2386 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2395 height = realheight;
2399 /* make a black/white palette */
2401 float r = 255/(numpalette-1);
2403 for(t=0;t<numpalette;t++) {
2404 pal[t].r = colToByte(rgb.r);
2405 pal[t].g = colToByte(rgb.g);
2406 pal[t].b = colToByte(rgb.b);
2407 pal[t].a = (unsigned char)(t*r);
2411 gfxcolor_t*pic2 = new gfxcolor_t[width*height];
2412 for (y = 0; y < height; ++y) {
2413 for (x = 0; x < width; ++x) {
2414 pic2[width*y+x] = pal[pic[y*width+x]];
2417 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2421 if(maskbitmap) free(maskbitmap);
2427 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2428 gfxcolor_t*pic=new gfxcolor_t[width*height];
2429 for (y = 0; y < height; ++y) {
2430 for (x = 0; x < width; ++x) {
2431 imgStr->getPixel(pixBuf);
2432 colorMap->getRGB(pixBuf, &rgb);
2433 pic[width*y+x].r = (unsigned char)(colToByte(rgb.r));
2434 pic[width*y+x].g = (unsigned char)(colToByte(rgb.g));
2435 pic[width*y+x].b = (unsigned char)(colToByte(rgb.b));
2436 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2438 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2442 if(str->getKind()==strDCT)
2443 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2445 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2448 if(maskbitmap) free(maskbitmap);
2451 gfxcolor_t*pic=new gfxcolor_t[width*height];
2452 gfxcolor_t pal[256];
2453 int n = 1 << colorMap->getBits();
2455 for(t=0;t<256;t++) {
2457 colorMap->getRGB(pixBuf, &rgb);
2459 {/*if(maskColors && *maskColors==t) {
2460 msg("<notice> Color %d is transparent", t);
2461 if (imgData->maskColors) {
2463 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2464 if (pix[i] < imgData->maskColors[2*i] ||
2465 pix[i] > imgData->maskColors[2*i+1]) {
2480 pal[t].r = (unsigned char)(colToByte(rgb.r));
2481 pal[t].g = (unsigned char)(colToByte(rgb.g));
2482 pal[t].b = (unsigned char)(colToByte(rgb.b));
2483 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2486 for (y = 0; y < height; ++y) {
2487 for (x = 0; x < width; ++x) {
2488 imgStr->getPixel(pixBuf);
2489 pic[width*y+x] = pal[pixBuf[0]];
2491 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2495 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2499 if(maskbitmap) free(maskbitmap);
2504 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2505 int width, int height, GBool invert,
2508 if(states[statepos].textRender & 4) //clipped
2510 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2511 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0, 0,0,0,0, 0);
2514 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2515 int width, int height, GfxImageColorMap *colorMap,
2516 int *maskColors, GBool inlineImg)
2518 if(states[statepos].textRender & 4) //clipped
2521 msg("<verbose> drawImage %dx%d, %s, %s, inline=%d", width, height,
2522 colorMap?"colorMap":"no colorMap",
2523 maskColors?"maskColors":"no maskColors",
2526 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2527 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2528 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors, 0,0,0,0, 0);
2531 void SWFOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
2532 int width, int height,
2533 GfxImageColorMap *colorMap,
2534 Stream *maskStr, int maskWidth, int maskHeight,
2537 if(states[statepos].textRender & 4) //clipped
2540 msg("<verbose> drawMaskedImage %dx%d, %s, %dx%d mask", width, height,
2541 colorMap?"colorMap":"no colorMap",
2542 maskWidth, maskHeight);
2544 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2545 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2546 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, maskInvert, 0);
2549 void SWFOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
2550 int width, int height,
2551 GfxImageColorMap *colorMap,
2553 int maskWidth, int maskHeight,
2554 GfxImageColorMap *maskColorMap)
2556 if(states[statepos].textRender & 4) //clipped
2559 msg("<verbose> drawSoftMaskedImage %dx%d, %s, %dx%d mask", width, height,
2560 colorMap?"colorMap":"no colorMap",
2561 maskWidth, maskHeight);
2563 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2564 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2565 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, 0, maskColorMap);
2568 //SWFOutputDev*output = 0;
2570 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2575 if (infoDict->lookup(key, &obj)->isString()) {
2576 s1 = obj.getString();
2577 if ((s1->getChar(0) & 0xff) == 0xfe &&
2578 (s1->getChar(1) & 0xff) == 0xff) {
2580 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2581 if (s1->getChar(i) == '\0') {
2582 s2->append(s1->getChar(i+1));
2585 s2 = new GString("<unicode>");
2589 printf(fmt, s2->getCString());
2592 printf(fmt, s1->getCString());
2598 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2602 if (infoDict->lookup(key, &obj)->isString()) {
2603 s = obj.getString()->getCString();
2604 if (s[0] == 'D' && s[1] == ':') {
2615 void storeDeviceParameter(char*name, char*value)
2617 parameter_t*p = new parameter_t();
2618 p->name = strdup(name);
2619 p->value = strdup(value);
2621 if(device_config_next) {
2622 device_config_next->next = p;
2623 device_config_next = p;
2626 device_config_next = p;
2630 void pdfswf_setparameter(char*name, char*value)
2632 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2633 if(!strcmp(name, "caplinewidth")) {
2634 caplinewidth = atof(value);
2635 } else if(!strcmp(name, "zoom")) {
2638 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2639 storeDeviceParameter("jpegsubpixels", buf);
2640 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2641 storeDeviceParameter("ppmsubpixels", buf);
2642 } else if(!strcmp(name, "jpegdpi")) {
2644 jpeg_dpi = atoi(value);
2645 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2646 storeDeviceParameter("jpegsubpixels", buf);
2647 } else if(!strcmp(name, "ppmdpi")) {
2649 ppm_dpi = atoi(value);
2650 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2651 storeDeviceParameter("ppmsubpixels", buf);
2652 } else if(!strcmp(name, "forceType0Fonts")) {
2653 forceType0Fonts = atoi(value);
2654 } else if(!strncmp(name, "fontdir", strlen("fontdir"))) {
2655 pdfswf_addfontdir(value);
2656 } else if(!strncmp(name, "languagedir", strlen("languagedir"))) {
2657 pdfswf_addlanguagedir(value);
2658 } else if(!strcmp(name, "fontconfig")) {
2659 config_use_fontconfig = atoi(value);
2661 storeDeviceParameter(name,value);
2664 void pdfswf_addfont(char*filename)
2667 memset(&f, 0, sizeof(fontfile_t));
2668 f.filename = filename;
2669 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2670 fonts[fontnum++] = f;
2672 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2676 static char* dirseparator()
2685 void pdfswf_addlanguagedir(char*dir)
2688 globalParams = new GlobalParams("");
2690 msg("<notice> Adding %s to language pack directories", dir);
2694 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc") + 1);
2695 strcpy(config_file, dir);
2696 strcat(config_file, dirseparator());
2697 strcat(config_file, "add-to-xpdfrc");
2699 fi = fopen(config_file, "rb");
2701 msg("<error> Could not open %s", config_file);
2704 globalParams->parseFile(new GString(config_file), fi);
2708 void pdfswf_addfontdir(char*dirname)
2710 #ifdef HAVE_DIRENT_H
2711 msg("<notice> Adding %s to font directories", dirname);
2712 lastfontdir = strdup(dirname);
2713 DIR*dir = opendir(dirname);
2715 msg("<warning> Couldn't open directory %s\n", dirname);
2720 ent = readdir (dir);
2724 char*name = ent->d_name;
2730 if(!strncasecmp(&name[l-4], ".pfa", 4))
2732 if(!strncasecmp(&name[l-4], ".pfb", 4))
2734 if(!strncasecmp(&name[l-4], ".ttf", 4))
2738 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2739 strcpy(fontname, dirname);
2740 strcat(fontname, dirseparator());
2741 strcat(fontname, name);
2742 msg("<verbose> Adding %s to fonts", fontname);
2743 pdfswf_addfont(fontname);
2748 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2753 typedef struct _pdf_doc_internal
2758 } pdf_doc_internal_t;
2759 typedef struct _pdf_page_internal
2761 } pdf_page_internal_t;
2762 typedef struct _dev_output_internal
2764 SWFOutputDev*outputDev;
2765 } dev_output_internal_t;
2767 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2769 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2770 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2771 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2772 memset(i, 0, sizeof(pdf_doc_internal_t));
2773 pdf_doc->internal = i;
2775 GString *fileName = new GString(filename);
2781 globalParams = new GlobalParams("");
2784 if (userPassword && userPassword[0]) {
2785 userPW = new GString(userPassword);
2789 i->doc = new PDFDoc(fileName, userPW);
2793 if (!i->doc->isOk()) {
2798 i->doc->getDocInfo(&info);
2799 if (info.isDict() &&
2800 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2801 printInfoString(info.getDict(), "Title", "Title: %s\n");
2802 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2803 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2804 printInfoString(info.getDict(), "Author", "Author: %s\n");
2805 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2806 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2807 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2808 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2809 printf("Pages: %d\n", i->doc->getNumPages());
2810 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2811 printf("Encrypted: ");
2812 if (i->doc->isEncrypted()) {
2813 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2814 i->doc->okToPrint() ? "yes" : "no",
2815 i->doc->okToCopy() ? "yes" : "no",
2816 i->doc->okToChange() ? "yes" : "no",
2817 i->doc->okToAddNotes() ? "yes" : "no");
2824 pdf_doc->num_pages = i->doc->getNumPages();
2826 if (i->doc->isEncrypted()) {
2827 if(!i->doc->okToCopy()) {
2828 printf("PDF disallows copying.\n");
2831 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2835 InfoOutputDev*io = new InfoOutputDev();
2837 for(t=1;t<=pdf_doc->num_pages;t++) {
2838 i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, /*usemediabox*/true, /*crop*/true, /*doLinks*/(int)1);
2849 delete globalParams;globalParams=0;
2850 Object::memCheck(stderr);
2855 void pdf_destroy(pdf_doc_t*pdf_doc)
2857 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2859 delete i->doc; i->doc=0;
2862 delete i->info;i->info=0;
2865 free(pdf_doc->internal);pdf_doc->internal=0;
2866 free(pdf_doc);pdf_doc=0;
2869 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2871 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2873 if(page < 1 || page > pdf_doc->num_pages)
2876 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2877 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2878 memset(pi, 0, sizeof(pdf_page_internal_t));
2879 pdf_page->internal = pi;
2881 pdf_page->parent = pdf_doc;
2882 pdf_page->nr = page;
2886 void pdf_page_destroy(pdf_page_t*pdf_page)
2888 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2889 free(pdf_page->internal);pdf_page->internal = 0;
2890 free(pdf_page);pdf_page=0;
2893 dev_output_t* dev_output_init(gfxdevice_t*dev)
2895 dev_output_t*dev_output = (dev_output_t*)malloc(sizeof(dev_output_t));
2896 memset(dev_output, 0, sizeof(dev_output_t));
2897 dev_output_internal_t*i= (dev_output_internal_t*)malloc(sizeof(dev_output_internal_t));
2898 memset(i, 0, sizeof(dev_output_internal_t));
2899 dev_output->internal = i;
2901 i->outputDev = new SWFOutputDev(dev);
2905 void dev_output_setparameter(dev_output_t*swf, char*name, char*value)
2907 pdfswf_setparameter(name, value);
2910 void dev_output_startframe(dev_output_t*swf, int width, int height)
2912 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2913 i->outputDev->startFrame(width, height);
2916 void dev_output_endframe(dev_output_t*swf)
2918 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2919 i->outputDev->endframe();
2922 void dev_output_finish(dev_output_t*swf)
2924 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2925 i->outputDev->finish();
2928 void dev_output_preparepage(dev_output_t*swf, int pdfpage, int outputpage)
2930 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2931 SWFOutputDev*o = i->outputDev;
2937 o->pagebuflen = 1024;
2938 o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
2939 memset(o->pages, -1, o->pagebuflen*sizeof(int));
2941 while(pdfpage >= o->pagebuflen)
2943 int oldlen = o->pagebuflen;
2944 o->pagebuflen+=1024;
2945 o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
2946 memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
2949 o->pages[pdfpage] = outputpage;
2950 if(pdfpage>o->pagepos)
2951 o->pagepos = pdfpage;
2954 void dev_output_destroy(dev_output_t*output)
2956 dev_output_internal_t*i = (dev_output_internal_t*)output->internal;
2957 delete i->outputDev; i->outputDev=0;
2958 free(output->internal);output->internal=0;
2962 void pdf_page_render2(pdf_page_t*page, dev_output_t*swf)
2964 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2965 dev_output_internal_t*si = (dev_output_internal_t*)swf->internal;
2968 msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2973 gfxdevice_t*dev = si->outputDev->output;
2974 dev->setparameter(dev, "protect", "1");
2976 si->outputDev->setInfo(pi->info);
2977 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2978 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
2981 void pdf_page_rendersection(pdf_page_t*page, dev_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2983 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2984 dev_output_internal_t*si = (dev_output_internal_t*)output->internal;
2986 si->outputDev->setMove(x,y);
2987 if((x1|y1|x2|y2)==0) x2++;
2988 si->outputDev->setClip(x1,y1,x2,y2);
2990 pdf_page_render2(page, output);
2992 void pdf_page_render(pdf_page_t*page, dev_output_t*output)
2994 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2995 dev_output_internal_t*si = (dev_output_internal_t*)output->internal;
2997 si->outputDev->setMove(0,0);
2998 si->outputDev->setClip(0,0,0,0);
3000 pdf_page_render2(page, output);
3004 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
3006 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
3007 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
3008 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
3009 memset(info, 0, sizeof(pdf_page_info_t));
3011 InfoOutputDev*output = new InfoOutputDev;
3013 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
3015 info->xMin = output->x1;
3016 info->yMin = output->y1;
3017 info->xMax = output->x2;
3018 info->yMax = output->y2;
3019 info->number_of_images = output->num_images;
3020 info->number_of_links = output->num_links;
3021 info->number_of_fonts = output->num_fonts;
3028 void pdf_page_info_destroy(pdf_page_info_t*info)