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 // Can this device draw gradients?
173 virtual GBool useGradients();
175 virtual GBool interpretType3Chars() {return gTrue;}
177 //----- initialization and control
179 void setXRef(PDFDoc*doc, XRef *xref);
182 virtual void drawLink(Link *link, Catalog *catalog) ;
184 //----- save/restore graphics state
185 virtual void saveState(GfxState *state) ;
186 virtual void restoreState(GfxState *state) ;
188 //----- update graphics state
190 virtual void updateFont(GfxState *state);
191 virtual void updateFillColor(GfxState *state);
192 virtual void updateStrokeColor(GfxState *state);
193 virtual void updateLineWidth(GfxState *state);
194 virtual void updateLineJoin(GfxState *state);
195 virtual void updateLineCap(GfxState *state);
197 virtual void updateAll(GfxState *state)
200 updateFillColor(state);
201 updateStrokeColor(state);
202 updateLineWidth(state);
203 updateLineJoin(state);
204 updateLineCap(state);
207 //----- path painting
208 virtual void stroke(GfxState *state) ;
209 virtual void fill(GfxState *state) ;
210 virtual void eoFill(GfxState *state) ;
212 //----- path clipping
213 virtual void clip(GfxState *state) ;
214 virtual void eoClip(GfxState *state) ;
217 virtual void beginString(GfxState *state, GString *s) ;
218 virtual void endString(GfxState *state) ;
219 virtual void endTextObject(GfxState *state);
220 virtual void drawChar(GfxState *state, double x, double y,
221 double dx, double dy,
222 double originX, double originY,
223 CharCode code, int nBytes, Unicode *u, int uLen);
225 //----- image drawing
226 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
227 int width, int height, GBool invert,
229 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
230 int width, int height, GfxImageColorMap *colorMap,
231 int *maskColors, GBool inlineImg);
232 virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
233 int width, int height,
234 GfxImageColorMap *colorMap,
235 Stream *maskStr, int maskWidth, int maskHeight,
237 virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
238 int width, int height,
239 GfxImageColorMap *colorMap,
241 int maskWidth, int maskHeight,
242 GfxImageColorMap *maskColorMap);
244 virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
245 virtual void endType3Char(GfxState *state);
247 virtual void type3D0(GfxState *state, double wx, double wy);
248 virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
253 void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
254 int width, int height, GfxImageColorMap*colorMap, GBool invert,
255 GBool inlineImg, int mask, int *maskColors,
256 Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GfxImageColorMap*maskColorMap);
257 int SWFOutputDev::setGfxFont(char*id, char*name, char*filename, double quality);
258 void strokeGfxline(GfxState *state, gfxline_t*line);
259 void clipToGfxLine(GfxState *state, gfxline_t*line);
260 void fillGfxLine(GfxState *state, gfxline_t*line);
262 char outer_clip_box; //whether the page clip box is still on
265 SWFOutputState states[64];
273 char* searchFont(char*name);
274 char* substituteFont(GfxFont*gfxFont, char*oldname);
275 char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
277 int textmodeinfo; // did we write "Text will be rendered as polygon" yet?
278 int jpeginfo; // did we write "File contains jpegs" yet?
279 int pbminfo; // did we write "File contains jpegs" yet?
280 int linkinfo; // did we write "File contains links" yet?
281 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
282 int gradientinfo; // did we write "File contains Gradients yet?
284 int type3active; // are we between beginType3()/endType3()?
290 char* substitutetarget[256];
291 char* substitutesource[256];
294 int user_movex,user_movey;
295 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
297 gfxline_t* current_text_stroke;
298 gfxline_t* current_text_clip;
299 char* current_font_id;
300 gfxfont_t* current_gfxfont;
301 gfxmatrix_t current_font_matrix;
303 fontlist_t* fontlist;
309 friend void dev_output_preparepage(dev_output_t*swf, int pdfpage, int outputpage);
312 typedef struct _drawnchar
330 chars = (drawnchar_t*)malloc(sizeof(drawnchar_t)*buf_size);
331 memset(chars, 0, sizeof(drawnchar_t)*buf_size);
336 free(chars);chars = 0;
343 chars = (drawnchar_t*)realloc(chars, sizeof(drawnchar_t)*buf_size);
347 void addChar(int charid, gfxcoord_t x, gfxcoord_t y, gfxcolor_t color)
350 chars[num_chars].x = x;
351 chars[num_chars].y = y;
352 chars[num_chars].color = color;
353 chars[num_chars].charid = charid;
357 static char*getFontID(GfxFont*font);
365 class InfoOutputDev: public OutputDev
368 FontInfo* currentfont;
380 id2font = new GHash();
382 virtual ~InfoOutputDev()
386 virtual GBool upsideDown() {return gTrue;}
387 virtual GBool useDrawChar() {return gTrue;}
388 virtual GBool useGradients() {return gTrue;}
389 virtual GBool interpretType3Chars() {return gTrue;}
390 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
393 state->transform(crop_x1,crop_y1,&x1,&y1);
394 state->transform(crop_x2,crop_y2,&x2,&y2);
395 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
396 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
402 virtual void drawLink(Link *link, Catalog *catalog)
406 virtual double getMaximumFontSize(char*id)
408 FontInfo*info = (FontInfo*)id2font->lookup(id);
410 msg("<error> Unknown font id: %s", id);
413 return info->max_size;
416 virtual void updateFont(GfxState *state)
418 GfxFont*font = state->getFont();
421 char*id = getFontID(font);
423 FontInfo*info = (FontInfo*)id2font->lookup(id);
425 GString* idStr = new GString(id);
429 id2font->add(idStr, (void*)info);
436 virtual void drawChar(GfxState *state, double x, double y,
437 double dx, double dy,
438 double originX, double originY,
439 CharCode code, int nBytes, Unicode *u, int uLen)
441 int render = state->getRender();
444 double m11,m21,m12,m22;
445 state->getFontTransMat(&m11, &m12, &m21, &m22);
446 m11 *= state->getHorizScaling();
447 m21 *= state->getHorizScaling();
448 double lenx = sqrt(m11*m11 + m12*m12);
449 double leny = sqrt(m21*m21 + m22*m22);
450 double len = lenx>leny?lenx:leny;
451 if(currentfont && currentfont->max_size < len) {
452 currentfont->max_size = len;
455 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
456 int width, int height, GBool invert,
461 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
462 int width, int height, GfxImageColorMap *colorMap,
463 int *maskColors, GBool inlineImg)
469 SWFOutputDev::SWFOutputDev(gfxdevice_t*output)
471 this->output = output;
473 this->textmodeinfo = 0;
477 this->type3active = 0;
480 this->substitutepos = 0;
481 this->type3Warning = 0;
482 this->user_movex = 0;
483 this->user_movey = 0;
484 this->user_clipx1 = 0;
485 this->user_clipy1 = 0;
486 this->user_clipx2 = 0;
487 this->user_clipy2 = 0;
488 this->current_text_stroke = 0;
489 this->current_text_clip = 0;
491 this->outer_clip_box = 0;
493 this->pagebuflen = 0;
496 /* configure device */
497 parameter_t*p = device_config;
499 output->setparameter(output, p->name, p->value);
504 void SWFOutputDev::setMove(int x,int y)
506 this->user_movex = x;
507 this->user_movey = y;
510 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
512 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
513 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
515 this->user_clipx1 = x1;
516 this->user_clipy1 = y1;
517 this->user_clipx2 = x2;
518 this->user_clipy2 = y2;
521 static char*getFontID(GfxFont*font)
523 Ref*ref = font->getID();
524 GString*gstr = font->getName();
525 char* fname = gstr==0?0:gstr->getCString();
528 sprintf(buf, "font-%d-%d", ref->num, ref->gen);
530 sprintf(buf, "%s-%d-%d", fname, ref->num, ref->gen);
535 static char*getFontName(GfxFont*font)
538 GString*gstr = font->getName();
539 char* fname = gstr==0?0:gstr->getCString();
543 sprintf(buf, "UFONT%d", r->num);
544 fontid = strdup(buf);
546 fontid = strdup(fname);
549 char* plus = strchr(fontid, '+');
550 if(plus && plus < &fontid[strlen(fontid)-1]) {
551 fontname = strdup(plus+1);
553 fontname = strdup(fontid);
559 static char mybuf[1024];
560 static char* gfxstate2str(GfxState *state)
564 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
571 if(state->getX1()!=0.0)
572 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
573 if(state->getY1()!=0.0)
574 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
575 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
576 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
577 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
578 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
579 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
580 state->getFillColor()->c[0], state->getFillColor()->c[1]);
581 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
582 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
583 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
584 state->getFillColor()->c[0], state->getFillColor()->c[1],
585 state->getFillColor()->c[2], state->getFillColor()->c[3],
586 state->getFillColor()->c[4], state->getFillColor()->c[5],
587 state->getFillColor()->c[6], state->getFillColor()->c[7]);
588 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
589 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
590 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
591 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
592 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
593 state->getFillRGB(&rgb);
594 if(rgb.r || rgb.g || rgb.b)
595 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
596 state->getStrokeRGB(&rgb);
597 if(rgb.r || rgb.g || rgb.b)
598 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
599 if(state->getFillColorSpace()->getNComps()>1)
600 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
601 if(state->getStrokeColorSpace()->getNComps()>1)
602 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
603 if(state->getFillPattern())
604 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
605 if(state->getStrokePattern())
606 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
608 if(state->getFillOpacity()!=1.0)
609 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
610 if(state->getStrokeOpacity()!=1.0)
611 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
613 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
618 state->getLineDash(&dash, &length, &start);
622 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
623 for(t=0;t<length;t++) {
624 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
626 bufpos+=sprintf(bufpos,"]");
629 if(state->getFlatness()!=1)
630 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
631 if(state->getLineJoin()!=0)
632 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
633 if(state->getLineJoin()!=0)
634 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
635 if(state->getLineJoin()!=0)
636 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
638 if(state->getFont() && getFontID(state->getFont()))
639 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
640 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
641 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
642 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
643 if(state->getCharSpace())
644 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
645 if(state->getWordSpace())
646 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
647 if(state->getHorizScaling()!=1.0)
648 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
649 if(state->getLeading())
650 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
652 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
653 if(state->getRender())
654 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
655 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
656 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
657 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
658 if(state->getLineX())
659 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
660 if(state->getLineY())
661 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
662 bufpos+=sprintf(bufpos," ");
666 static void dumpFontInfo(char*loglevel, GfxFont*font);
667 static int lastdumps[1024];
668 static int lastdumppos = 0;
673 static void showFontError(GfxFont*font, int nr)
677 for(t=0;t<lastdumppos;t++)
678 if(lastdumps[t] == r->num)
682 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
683 lastdumps[lastdumppos++] = r->num;
685 msg("<warning> The following font caused problems:");
687 msg("<warning> The following font caused problems (substituting):");
689 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
690 dumpFontInfo("<warning>", font);
693 static void dumpFontInfo(char*loglevel, GfxFont*font)
695 char* id = getFontID(font);
696 char* name = getFontName(font);
697 Ref* r=font->getID();
698 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
700 GString*gstr = font->getTag();
702 msg("%s| Tag: %s\n", loglevel, id);
704 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
706 GfxFontType type=font->getType();
708 case fontUnknownType:
709 msg("%s| Type: unknown\n",loglevel);
712 msg("%s| Type: 1\n",loglevel);
715 msg("%s| Type: 1C\n",loglevel);
718 msg("%s| Type: 3\n",loglevel);
721 msg("%s| Type: TrueType\n",loglevel);
724 msg("%s| Type: CIDType0\n",loglevel);
727 msg("%s| Type: CIDType0C\n",loglevel);
730 msg("%s| Type: CIDType2\n",loglevel);
735 GBool embedded = font->getEmbeddedFontID(&embRef);
737 if(font->getEmbeddedFontName()) {
738 embeddedName = font->getEmbeddedFontName()->getCString();
741 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
743 gstr = font->getExtFontFile();
745 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
747 // Get font descriptor flags.
748 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
749 if(font->isSerif()) msg("%s| is serif\n", loglevel);
750 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
751 if(font->isItalic()) msg("%s| is italic\n", loglevel);
752 if(font->isBold()) msg("%s| is bold\n", loglevel);
758 //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");}
759 //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");}
762 void dump_outline(gfxline_t*line)
765 if(line->type == gfx_moveTo) {
766 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
767 } else if(line->type == gfx_lineTo) {
768 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
769 } else if(line->type == gfx_splineTo) {
770 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
776 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey)
778 int num = path->getNumSubpaths();
781 double lastx=0,lasty=0,posx=0,posy=0;
784 msg("<warning> empty path");
788 gfxdrawer_target_gfxline(&draw);
790 for(t = 0; t < num; t++) {
791 GfxSubpath *subpath = path->getSubpath(t);
792 int subnum = subpath->getNumPoints();
793 double bx=0,by=0,cx=0,cy=0;
795 for(s=0;s<subnum;s++) {
798 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
803 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
804 draw.lineTo(&draw, lastx, lasty);
806 draw.moveTo(&draw, x,y);
811 } else if(subpath->getCurve(s) && cpos==0) {
815 } else if(subpath->getCurve(s) && cpos==1) {
823 draw.lineTo(&draw, x,y);
825 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y, 0.05);
832 /* fix non-closed lines */
833 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
834 draw.lineTo(&draw, lastx, lasty);
836 gfxline_t*result = (gfxline_t*)draw.result(&draw);
840 /*----------------------------------------------------------------------------
841 * Primitive Graphic routines
842 *----------------------------------------------------------------------------*/
844 void SWFOutputDev::stroke(GfxState *state)
846 GfxPath * path = state->getPath();
847 gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex, user_movey);
848 strokeGfxline(state, line);
852 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
854 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
855 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
856 double miterLimit = state->getMiterLimit();
857 double width = state->getTransformedLineWidth();
860 double opaq = state->getStrokeOpacity();
862 state->getFillRGB(&rgb);
864 state->getStrokeRGB(&rgb);
866 col.r = colToByte(rgb.r);
867 col.g = colToByte(rgb.g);
868 col.b = colToByte(rgb.b);
869 col.a = (unsigned char)(opaq*255);
871 gfx_capType capType = gfx_capRound;
872 if(lineCap == 0) capType = gfx_capButt;
873 else if(lineCap == 1) capType = gfx_capRound;
874 else if(lineCap == 2) capType = gfx_capSquare;
876 gfx_joinType joinType = gfx_joinRound;
877 if(lineJoin == 0) joinType = gfx_joinMiter;
878 else if(lineJoin == 1) joinType = gfx_joinRound;
879 else if(lineJoin == 2) joinType = gfx_joinBevel;
882 double dashphase = 0;
884 state->getLineDash(&ldash, &dashnum, &dashphase);
888 if(dashnum && ldash) {
889 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
893 msg("<trace> %d dashes", dashnum);
894 msg("<trace> | phase: %f", dashphase);
895 for(t=0;t<dashnum;t++) {
897 msg("<trace> | d%-3d: %f", t, ldash[t]);
900 if(getLogLevel() >= LOGLEVEL_TRACE) {
904 line2 = gfxtool_dash_line(line, dash, dashphase);
907 msg("<trace> After dashing:");
910 if(getLogLevel() >= LOGLEVEL_TRACE) {
911 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x\n",
913 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
914 lineCap==0?"butt": (lineJoin==1?"round":"square"),
916 col.r,col.g,col.b,col.a
921 //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
922 output->stroke(output, line, width, &col, capType, joinType, miterLimit);
932 gfxcolor_t getFillColor(GfxState * state)
935 double opaq = state->getFillOpacity();
936 state->getFillRGB(&rgb);
938 col.r = colToByte(rgb.r);
939 col.g = colToByte(rgb.g);
940 col.b = colToByte(rgb.b);
941 col.a = (unsigned char)(opaq*255);
945 void SWFOutputDev::fillGfxLine(GfxState *state, gfxline_t*line)
947 gfxcolor_t col = getFillColor(state);
949 if(getLogLevel() >= LOGLEVEL_TRACE) {
950 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
953 output->fill(output, line, &col);
955 void SWFOutputDev::fill(GfxState *state)
957 GfxPath * path = state->getPath();
958 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
959 fillGfxLine(state, line);
962 void SWFOutputDev::eoFill(GfxState *state)
964 GfxPath * path = state->getPath();
965 gfxcolor_t col = getFillColor(state);
967 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
969 if(getLogLevel() >= LOGLEVEL_TRACE) {
970 msg("<trace> eofill\n");
974 output->fill(output, line, &col);
978 void SWFOutputDev::clip(GfxState *state)
980 GfxPath * path = state->getPath();
981 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
982 clipToGfxLine(state, line);
986 void SWFOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line)
988 if(getLogLevel() >= LOGLEVEL_TRACE) {
989 msg("<trace> clip\n");
993 output->startclip(output, line);
994 states[statepos].clipping++;
996 void SWFOutputDev::eoClip(GfxState *state)
998 GfxPath * path = state->getPath();
999 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
1001 if(getLogLevel() >= LOGLEVEL_TRACE) {
1002 msg("<trace> eoclip\n");
1006 output->startclip(output, line);
1007 states[statepos].clipping++;
1011 void SWFOutputDev::endframe()
1013 if(outer_clip_box) {
1014 output->endclip(output);
1018 output->endpage(output);
1021 void SWFOutputDev::finish()
1023 if(outer_clip_box) {
1025 output->endclip(output);
1031 SWFOutputDev::~SWFOutputDev()
1036 free(this->pages); this->pages = 0;
1039 fontlist_t*l = this->fontlist;
1041 fontlist_t*next = l->next;
1043 gfxfont_free(l->font);
1044 free(l->id);l->id=0;
1045 free(l->filename);l->filename=0;
1051 GBool SWFOutputDev::upsideDown()
1055 GBool SWFOutputDev::useDrawChar()
1059 GBool SWFOutputDev::useGradients()
1063 msg("<notice> File contains gradients");
1069 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
1070 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
1072 #define RENDER_FILL 0
1073 #define RENDER_STROKE 1
1074 #define RENDER_FILLSTROKE 2
1075 #define RENDER_INVISIBLE 3
1076 #define RENDER_CLIP 4
1078 static char tmp_printstr[4096];
1079 char* makeStringPrintable(char*str)
1081 int len = strlen(str);
1088 for(t=0;t<len;t++) {
1093 tmp_printstr[t] = c;
1096 tmp_printstr[len++] = '.';
1097 tmp_printstr[len++] = '.';
1098 tmp_printstr[len++] = '.';
1100 tmp_printstr[len] = 0;
1101 return tmp_printstr;
1105 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
1110 /* find out char name from unicode index
1111 TODO: should be precomputed
1113 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1114 if(nameToUnicodeTab[t].u == u) {
1115 uniname = nameToUnicodeTab[t].name;
1123 for(t=0;t<font->num_glyphs;t++) {
1124 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
1125 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1129 /* if we didn't find the character, maybe
1130 we can find the capitalized version */
1131 for(t=0;t<font->num_glyphs;t++) {
1132 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
1133 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1141 for(t=0;t<font->num_glyphs;t++) {
1142 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,uniname)) {
1143 msg("<debug> Char [%d,%s,>%d(%s)<] maps to %d\n", charnr, charname, u, uniname, t);
1147 /* if we didn't find the character, maybe
1148 we can find the capitalized version */
1149 for(t=0;t<font->num_glyphs;t++) {
1150 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,uniname)) {
1151 msg("<debug> Char [%d,%s,>>%d(%s)<<] maps to %d\n", charnr, charname, u, uniname, t);
1157 /* try to use the unicode id */
1158 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
1159 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
1160 return font->unicode2glyph[u];
1163 if(charnr>=0 && charnr<font->num_glyphs) {
1164 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1172 void SWFOutputDev::beginString(GfxState *state, GString *s)
1174 int render = state->getRender();
1175 if(current_text_stroke) {
1176 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
1179 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
1180 double m11,m21,m12,m22;
1181 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
1182 state->getFontTransMat(&m11, &m12, &m21, &m22);
1183 m11 *= state->getHorizScaling();
1184 m21 *= state->getHorizScaling();
1186 this->current_font_matrix.m00 = m11 / 1024.0;
1187 this->current_font_matrix.m01 = m12 / 1024.0;
1188 this->current_font_matrix.m10 = -m21 / 1024.0;
1189 this->current_font_matrix.m11 = -m22 / 1024.0;
1190 this->current_font_matrix.tx = 0;
1191 this->current_font_matrix.ty = 0;
1193 gfxmatrix_t m = this->current_font_matrix;
1195 /*if(render != 3 && render != 0)
1196 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1197 states[statepos].textRender = render;
1200 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1201 double dx, double dy,
1202 double originX, double originY,
1203 CharCode c, int nBytes, Unicode *_u, int uLen)
1205 int render = state->getRender();
1206 // check for invisible text -- this is used by Acrobat Capture
1208 msg("<debug> Ignoring invisible text: char %d at %f,%f", c, x, y);
1212 if(states[statepos].textRender != render)
1213 msg("<error> Internal error: drawChar.render!=beginString.render");
1215 gfxcolor_t col = getFillColor(state);
1217 Gushort *CIDToGIDMap = 0;
1218 GfxFont*font = state->getFont();
1220 if(font->getType() == fontType3) {
1221 /* type 3 chars are passed as graphics */
1222 msg("<debug> type3 char at %f/%f", x, y);
1232 if(font->isCIDFont()) {
1233 GfxCIDFont*cfont = (GfxCIDFont*)font;
1235 if(font->getType() == fontCIDType2)
1236 CIDToGIDMap = cfont->getCIDToGID();
1239 font8 = (Gfx8BitFont*)font;
1240 char**enc=font8->getEncoding();
1244 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);
1247 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);
1253 charid = getGfxCharID(current_gfxfont, c, name, u);
1255 charid = getGfxCharID(current_gfxfont, c, name, -1);
1258 /* multiple unicodes- should usually map to a ligature.
1259 if the ligature doesn't exist, we need to draw
1260 the characters one-by-one. */
1262 msg("<warning> ligature %d missing in font %s\n", c, current_font_id);
1263 for(t=0;t<uLen;t++) {
1264 drawChar(state, x, y, dx, dy, originX, originY, c, nBytes, _u+t, 1);
1270 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1271 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1275 gfxmatrix_t m = this->current_font_matrix;
1276 state->transform(x, y, &m.tx, &m.ty);
1280 if(render == RENDER_FILL) {
1281 output->drawchar(output, current_font_id, charid, &col, &m);
1283 msg("<debug> Drawing glyph %d as shape", charid);
1285 msg("<notice> Some texts will be rendered as shape");
1288 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1289 gfxline_t*tglyph = gfxline_clone(glyph);
1290 gfxline_transform(tglyph, &m);
1291 if((render&3) != RENDER_INVISIBLE) {
1292 gfxline_t*add = gfxline_clone(tglyph);
1293 current_text_stroke = gfxline_append(current_text_stroke, add);
1295 if(render&RENDER_CLIP) {
1296 gfxline_t*add = gfxline_clone(tglyph);
1297 current_text_clip = gfxline_append(current_text_clip, add);
1299 gfxline_free(tglyph);
1303 void SWFOutputDev::endString(GfxState *state)
1305 int render = state->getRender();
1306 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1307 if(states[statepos].textRender != render)
1308 msg("<error> Internal error: drawChar.render!=beginString.render");
1310 if(current_text_stroke) {
1311 /* fillstroke and stroke text rendering objects we can process right
1312 now (as there may be texts of other rendering modes in this
1313 text object)- clipping objects have to wait until endTextObject,
1315 output->setparameter(output, "mark","TXT");
1316 if((render&3) == RENDER_FILL) {
1317 fillGfxLine(state, current_text_stroke);
1318 gfxline_free(current_text_stroke);
1319 current_text_stroke = 0;
1320 } else if((render&3) == RENDER_FILLSTROKE) {
1321 fillGfxLine(state, current_text_stroke);
1322 strokeGfxline(state, current_text_stroke);
1323 gfxline_free(current_text_stroke);
1324 current_text_stroke = 0;
1325 } else if((render&3) == RENDER_STROKE) {
1326 strokeGfxline(state, current_text_stroke);
1327 gfxline_free(current_text_stroke);
1328 current_text_stroke = 0;
1330 output->setparameter(output, "mark","");
1334 void SWFOutputDev::endTextObject(GfxState *state)
1336 int render = state->getRender();
1337 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1338 if(states[statepos].textRender != render)
1339 msg("<error> Internal error: drawChar.render!=beginString.render");
1341 if(current_text_clip) {
1342 output->setparameter(output, "mark","TXT");
1343 clipToGfxLine(state, current_text_clip);
1344 output->setparameter(output, "mark","");
1345 gfxline_free(current_text_clip);
1346 current_text_clip = 0;
1350 /* the logic seems to be as following:
1351 first, beginType3Char is called, with the charcode and the coordinates.
1352 if this function returns true, it already knew about the char and has now drawn it.
1353 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1354 the all draw operations until endType3Char are part of the char (which in this moment is
1355 at the position first passed to beginType3Char). the char ends with endType3Char.
1357 The drawing operations between beginType3Char and endType3Char are somewhat different to
1358 the normal ones. For example, the fillcolor equals the stroke color.
1361 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1363 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1365 /* the character itself is going to be passed using the draw functions */
1366 return gFalse; /* gTrue= is_in_cache? */
1369 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1370 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1372 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1373 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1377 void SWFOutputDev::endType3Char(GfxState *state)
1380 msg("<debug> endType3Char");
1383 void SWFOutputDev::startFrame(int width, int height)
1385 output->startpage(output, width, height);
1388 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1390 this->currentpage = pageNum;
1392 int rot = doc->getPageRotate(1);
1395 gfxline_t clippath[5];
1397 white.r = white.g = white.b = white.a = 255;
1399 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1400 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1401 Use CropBox, not MediaBox, as page size
1408 state->transform(crop_x1,crop_y1,&x1,&y1); //x1 += user_movex; y1 += user_movey;
1409 state->transform(crop_x2,crop_y2,&x2,&y2); //x2 += user_movex; y2 += user_movey;
1411 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1412 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1415 /* apply user clip box */
1416 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1417 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1418 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1419 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1420 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1423 //msg("<verbose> Bounding box is (%f,%f)-(%f,%f) [shifted by %d/%d]", x1,y1,x2,y2, user_movex, user_movey);
1425 if(outer_clip_box) {
1426 output->endclip(output);
1430 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);
1432 msg("<verbose> page is rotated %d degrees\n", rot);
1434 clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1435 clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1436 clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1437 clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1438 clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1439 output->startclip(output, clippath); outer_clip_box = 1;
1440 output->fill(output, clippath, &white);
1443 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1445 double x1, y1, x2, y2, w;
1446 gfxline_t points[5];
1449 msg("<debug> drawlink\n");
1451 link->getRect(&x1, &y1, &x2, &y2);
1452 cvtUserToDev(x1, y1, &x, &y);
1453 points[0].type = gfx_moveTo;
1454 points[0].x = points[4].x = x + user_movex;
1455 points[0].y = points[4].y = y + user_movey;
1456 points[0].next = &points[1];
1457 cvtUserToDev(x2, y1, &x, &y);
1458 points[1].type = gfx_lineTo;
1459 points[1].x = x + user_movex;
1460 points[1].y = y + user_movey;
1461 points[1].next = &points[2];
1462 cvtUserToDev(x2, y2, &x, &y);
1463 points[2].type = gfx_lineTo;
1464 points[2].x = x + user_movex;
1465 points[2].y = y + user_movey;
1466 points[2].next = &points[3];
1467 cvtUserToDev(x1, y2, &x, &y);
1468 points[3].type = gfx_lineTo;
1469 points[3].x = x + user_movex;
1470 points[3].y = y + user_movey;
1471 points[3].next = &points[4];
1472 cvtUserToDev(x1, y1, &x, &y);
1473 points[4].type = gfx_lineTo;
1474 points[4].x = x + user_movex;
1475 points[4].y = y + user_movey;
1478 LinkAction*action=link->getAction();
1485 switch(action->getKind())
1489 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1490 LinkDest *dest=NULL;
1491 if (ha->getDest()==NULL)
1492 dest=catalog->findDest(ha->getNamedDest());
1493 else dest=ha->getDest();
1495 if (dest->isPageRef()){
1496 Ref pageref=dest->getPageRef();
1497 page=catalog->findPage(pageref.num,pageref.gen);
1499 else page=dest->getPageNum();
1500 sprintf(buf, "%d", page);
1507 LinkGoToR*l = (LinkGoToR*)action;
1508 GString*g = l->getNamedDest();
1510 s = strdup(g->getCString());
1515 LinkNamed*l = (LinkNamed*)action;
1516 GString*name = l->getName();
1518 s = strdup(name->lowerCase()->getCString());
1519 named = name->getCString();
1522 if(strstr(s, "next") || strstr(s, "forward"))
1524 page = currentpage + 1;
1526 else if(strstr(s, "prev") || strstr(s, "back"))
1528 page = currentpage - 1;
1530 else if(strstr(s, "last") || strstr(s, "end"))
1532 if(pages && pagepos>0)
1533 page = pages[pagepos-1];
1535 else if(strstr(s, "first") || strstr(s, "top"))
1543 case actionLaunch: {
1545 LinkLaunch*l = (LinkLaunch*)action;
1546 GString * str = new GString(l->getFileName());
1547 GString * params = l->getParams();
1549 str->append(params);
1550 s = strdup(str->getCString());
1556 LinkURI*l = (LinkURI*)action;
1557 GString*g = l->getURI();
1559 url = g->getCString();
1564 case actionUnknown: {
1566 LinkUnknown*l = (LinkUnknown*)action;
1571 msg("<error> Unknown link type!\n");
1576 if(!s) s = strdup("-?-");
1578 if(!linkinfo && (page || url))
1580 msg("<notice> File contains links");
1588 for(t=1;t<=pagepos;t++) {
1589 if(pages[t]==page) {
1598 sprintf(buf, "page%d", lpage);
1599 output->drawlink(output, points, buf);
1603 output->drawlink(output, points, url);
1606 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1610 void SWFOutputDev::saveState(GfxState *state) {
1611 msg("<trace> saveState\n");
1614 msg("<error> Too many nested states in pdf.");
1618 states[statepos].clipping = 0; //? shouldn't this be the current value?
1619 states[statepos].textRender = states[statepos-1].textRender;
1622 void SWFOutputDev::restoreState(GfxState *state) {
1623 msg("<trace> restoreState\n");
1625 while(states[statepos].clipping) {
1626 output->endclip(output);
1627 states[statepos].clipping--;
1632 char* SWFOutputDev::searchFont(char*name)
1636 int is_standard_font = 0;
1638 msg("<verbose> SearchFont(%s)", name);
1640 /* see if it is a pdf standard font */
1641 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1643 if(!strcmp(name, pdf2t1map[i].pdffont))
1645 name = pdf2t1map[i].filename;
1646 is_standard_font = 1;
1650 /* look in all font files */
1651 for(i=0;i<fontnum;i++)
1653 if(strstr(fonts[i].filename, name))
1655 if(!fonts[i].used) {
1658 if(!is_standard_font)
1659 msg("<notice> Using %s for %s", fonts[i].filename, name);
1661 return strdup(fonts[i].filename);
1667 void SWFOutputDev::updateLineWidth(GfxState *state)
1669 double width = state->getTransformedLineWidth();
1670 //swfoutput_setlinewidth(&output, width);
1673 void SWFOutputDev::updateLineCap(GfxState *state)
1675 int c = state->getLineCap();
1678 void SWFOutputDev::updateLineJoin(GfxState *state)
1680 int j = state->getLineJoin();
1683 void SWFOutputDev::updateFillColor(GfxState *state)
1686 double opaq = state->getFillOpacity();
1687 state->getFillRGB(&rgb);
1689 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1692 void SWFOutputDev::updateStrokeColor(GfxState *state)
1695 double opaq = state->getStrokeOpacity();
1696 state->getStrokeRGB(&rgb);
1697 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1700 void FoFiWrite(void *stream, char *data, int len)
1702 fwrite(data, len, 1, (FILE*)stream);
1705 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1707 char*tmpFileName = NULL;
1713 Object refObj, strObj;
1715 tmpFileName = mktmpname(namebuf);
1718 ret = font->getEmbeddedFontID(&embRef);
1720 msg("<verbose> Didn't get embedded font id");
1721 /* not embedded- the caller should now search the font
1722 directories for this font */
1726 f = fopen(tmpFileName, "wb");
1728 msg("<error> Couldn't create temporary Type 1 font file");
1732 /*if(font->isCIDFont()) {
1733 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1734 GString c = cidFont->getCollection();
1735 msg("<notice> Collection: %s", c.getCString());
1738 //if (font->getType() == fontType1C) {
1739 if (0) { //font->getType() == fontType1C) {
1740 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1742 msg("<error> Couldn't read embedded font file");
1745 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1747 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1748 //cvt->convertToCIDType0("test", f);
1749 //cvt->convertToType0("test", f);
1752 } else if(font->getType() == fontTrueType) {
1753 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1754 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1756 msg("<error> Couldn't read embedded font file");
1759 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1760 cvt->writeTTF(FoFiWrite, f);
1764 font->getEmbeddedFontID(&embRef);
1765 refObj.initRef(embRef.num, embRef.gen);
1766 refObj.fetch(ref, &strObj);
1768 strObj.streamReset();
1773 f4[t] = strObj.streamGetChar();
1774 f4c[t] = (char)f4[t];
1779 if(!strncmp(f4c, "true", 4)) {
1780 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1781 Change this on the fly */
1782 f4[0] = f4[2] = f4[3] = 0;
1790 while ((c = strObj.streamGetChar()) != EOF) {
1794 strObj.streamClose();
1799 return strdup(tmpFileName);
1802 char* searchForSuitableFont(GfxFont*gfxFont)
1804 char*name = getFontName(gfxFont);
1808 if(!config_use_fontconfig)
1811 #ifdef HAVE_FONTCONFIG
1812 FcPattern *pattern, *match;
1816 static int fcinitcalled = false;
1818 msg("<debug> searchForSuitableFont(%s)", name);
1820 // call init ony once
1821 if (!fcinitcalled) {
1822 msg("<debug> Initializing FontConfig...");
1823 fcinitcalled = true;
1825 msg("<debug> FontConfig Initialization failed. Disabling.");
1826 config_use_fontconfig = 0;
1829 msg("<debug> ...initialized FontConfig");
1832 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1833 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1834 if (gfxFont->isItalic()) // check for italic
1835 msg("<debug> FontConfig: Adding Italic Slant");
1836 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1837 if (gfxFont->isBold()) // check for bold
1838 msg("<debug> FontConfig: Adding Bold Weight");
1839 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1841 msg("<debug> FontConfig: Try to match...");
1842 // configure and match using the original font name
1843 FcConfigSubstitute(0, pattern, FcMatchPattern);
1844 FcDefaultSubstitute(pattern);
1845 match = FcFontMatch(0, pattern, &result);
1847 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1848 msg("<debug> FontConfig: family=%s", (char*)v);
1849 // if we get an exact match
1850 if (strcmp((char *)v, name) == 0) {
1851 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1852 filename = strdup((char*)v); // mem leak
1853 char *nfn = strrchr(filename, '/');
1854 if(nfn) fontname = strdup(nfn+1);
1855 else fontname = filename;
1857 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1859 // initialize patterns
1860 FcPatternDestroy(pattern);
1861 FcPatternDestroy(match);
1863 // now match against serif etc.
1864 if (gfxFont->isSerif()) {
1865 msg("<debug> FontConfig: Create Serif Family Pattern");
1866 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1867 } else if (gfxFont->isFixedWidth()) {
1868 msg("<debug> FontConfig: Create Monospace Family Pattern");
1869 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1871 msg("<debug> FontConfig: Create Sans Family Pattern");
1872 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1876 if (gfxFont->isItalic()) {
1877 msg("<debug> FontConfig: Adding Italic Slant");
1878 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1881 if (gfxFont->isBold()) {
1882 msg("<debug> FontConfig: Adding Bold Weight");
1883 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1886 msg("<debug> FontConfig: Try to match... (2)");
1887 // configure and match using serif etc
1888 FcConfigSubstitute (0, pattern, FcMatchPattern);
1889 FcDefaultSubstitute (pattern);
1890 match = FcFontMatch (0, pattern, &result);
1892 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1893 filename = strdup((char*)v); // mem leak
1894 char *nfn = strrchr(filename, '/');
1895 if(nfn) fontname = strdup(nfn+1);
1896 else fontname = filename;
1898 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1902 //printf("FONTCONFIG: pattern");
1903 //FcPatternPrint(pattern);
1904 //printf("FONTCONFIG: match");
1905 //FcPatternPrint(match);
1907 FcPatternDestroy(pattern);
1908 FcPatternDestroy(match);
1910 pdfswf_addfont(filename);
1917 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1919 char*fontname = 0, *filename = 0;
1920 msg("<notice> substituteFont(%s)", oldname);
1922 if(!(fontname = searchForSuitableFont(gfxFont))) {
1923 fontname = "Times-Roman";
1925 filename = searchFont(fontname);
1927 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1931 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1932 msg("<fatal> Too many fonts in file.");
1936 substitutesource[substitutepos] = strdup(oldname); //mem leak
1937 substitutetarget[substitutepos] = fontname;
1938 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1941 return strdup(filename); //mem leak
1944 void unlinkfont(char* filename)
1951 if(!strncmp(&filename[l-4],".afm",4)) {
1952 memcpy(&filename[l-4],".pfb",4);
1954 memcpy(&filename[l-4],".pfa",4);
1956 memcpy(&filename[l-4],".afm",4);
1959 if(!strncmp(&filename[l-4],".pfa",4)) {
1960 memcpy(&filename[l-4],".afm",4);
1962 memcpy(&filename[l-4],".pfa",4);
1965 if(!strncmp(&filename[l-4],".pfb",4)) {
1966 memcpy(&filename[l-4],".afm",4);
1968 memcpy(&filename[l-4],".pfb",4);
1973 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1979 int SWFOutputDev::setGfxFont(char*id, char*name, char*filename, double maxSize)
1982 fontlist_t*last=0,*l = this->fontlist;
1984 /* TODO: should this be part of the state? */
1987 if(!strcmp(l->id, id)) {
1988 current_font_id = l->id;
1989 current_gfxfont = l->font;
1991 output->addfont(output, id, current_gfxfont);
1996 if(!filename) return 0;
1998 /* A font size of e.g. 9 means the font will be scaled down by
1999 1024 and scaled up by 9. So to have a maximum error of 1/20px,
2000 we have to divide 0.05 by (fontsize/1024)
2002 double quality = (1024 * 0.05) / maxSize;
2004 msg("<verbose> Loading %s...", filename);
2005 font = gfxfont_load(filename, quality);
2006 msg("<verbose> Font %s loaded successfully", filename);
2010 l->filename = strdup(filename);
2013 current_font_id = l->id;
2014 current_gfxfont = l->font;
2020 output->addfont(output, id, current_gfxfont);
2024 void SWFOutputDev::updateFont(GfxState *state)
2026 GfxFont*gfxFont = state->getFont();
2032 char * fontid = getFontID(gfxFont);
2033 char * fontname = getFontName(gfxFont);
2035 double maxSize = 1.0;
2038 maxSize = this->info->getMaximumFontSize(fontid);
2042 /* first, look if we substituted this font before-
2043 this way, we don't initialize the T1 Fonts
2045 for(t=0;t<substitutepos;t++) {
2046 if(!strcmp(fontid, substitutesource[t])) {
2047 free(fontid);fontid=0;
2048 fontid = strdup(substitutetarget[t]);
2053 /* second, see if this is a font which was used before-
2054 if so, we are done */
2055 if(setGfxFont(fontid, fontname, 0, 0)) {
2060 /* if(swfoutput_queryfont(&output, fontid))
2061 swfoutput_setfont(&output, fontid, 0);
2063 msg("<debug> updateFont(%s) [cached]", fontid);
2067 // look for Type 3 font
2068 if (gfxFont->getType() == fontType3) {
2070 type3Warning = gTrue;
2071 showFontError(gfxFont, 2);
2078 /* now either load the font, or find a substitution */
2081 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
2086 (gfxFont->getType() == fontType1 ||
2087 gfxFont->getType() == fontType1C ||
2088 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
2089 gfxFont->getType() == fontTrueType ||
2090 gfxFont->getType() == fontCIDType2
2093 fileName = writeEmbeddedFontToFile(xref, gfxFont);
2094 if(!fileName) showFontError(gfxFont,0);
2097 fileName = searchFont(fontname);
2098 if(!fileName) showFontError(gfxFont,0);
2101 char * fontname = getFontName(gfxFont);
2102 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
2105 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into %s", fontname, lastfontdir);
2107 msg("<warning> Try specifying one or more font directories");
2109 fileName = substituteFont(gfxFont, fontid);
2112 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
2113 msg("<notice> Font is now %s (%s)", fontid, fileName);
2117 msg("<error> Couldn't set font %s\n", fontid);
2123 msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
2124 dumpFontInfo("<verbose>", gfxFont);
2126 //swfoutput_setfont(&output, fontid, fileName);
2128 if(!setGfxFont(fontid, fontname, 0, 0)) {
2129 setGfxFont(fontid, fontname, fileName, maxSize);
2133 unlinkfont(fileName);
2143 #define SQR(x) ((x)*(x))
2145 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
2147 if((newwidth<2 || newheight<2) ||
2148 (width<=newwidth || height<=newheight))
2150 unsigned char*newdata;
2152 newdata= (unsigned char*)malloc(newwidth*newheight);
2154 double fx = (double)(width)/newwidth;
2155 double fy = (double)(height)/newheight;
2157 int blocksize = (int)(8192/(fx*fy));
2158 int r = 8192*256/palettesize;
2159 for(x=0;x<newwidth;x++) {
2160 double ex = px + fx;
2161 int fromx = (int)px;
2163 int xweight1 = (int)(((fromx+1)-px)*256);
2164 int xweight2 = (int)((ex-tox)*256);
2166 for(y=0;y<newheight;y++) {
2167 double ey = py + fy;
2168 int fromy = (int)py;
2170 int yweight1 = (int)(((fromy+1)-py)*256);
2171 int yweight2 = (int)((ey-toy)*256);
2174 for(xx=fromx;xx<=tox;xx++)
2175 for(yy=fromy;yy<=toy;yy++) {
2176 int b = 1-data[width*yy+xx];
2178 if(xx==fromx) weight = (weight*xweight1)/256;
2179 if(xx==tox) weight = (weight*xweight2)/256;
2180 if(yy==fromy) weight = (weight*yweight1)/256;
2181 if(yy==toy) weight = (weight*yweight2)/256;
2184 //if(a) a=(palettesize-1)*r/blocksize;
2185 newdata[y*newwidth+x] = (a*blocksize)/r;
2193 #define IMAGE_TYPE_JPEG 0
2194 #define IMAGE_TYPE_LOSSLESS 1
2196 static void drawimage(gfxdevice_t*dev, gfxcolor_t* data, int sizex,int sizey,
2197 double x1,double y1,
2198 double x2,double y2,
2199 double x3,double y3,
2200 double x4,double y4, int type)
2202 gfxcolor_t*newpic=0;
2204 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2205 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2207 gfxline_t p1,p2,p3,p4,p5;
2208 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2209 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2210 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2211 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2212 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2214 {p1.x = (int)(p1.x*20)/20.0;
2215 p1.y = (int)(p1.y*20)/20.0;
2216 p2.x = (int)(p2.x*20)/20.0;
2217 p2.y = (int)(p2.y*20)/20.0;
2218 p3.x = (int)(p3.x*20)/20.0;
2219 p3.y = (int)(p3.y*20)/20.0;
2220 p4.x = (int)(p4.x*20)/20.0;
2221 p4.y = (int)(p4.y*20)/20.0;
2222 p5.x = (int)(p5.x*20)/20.0;
2223 p5.y = (int)(p5.y*20)/20.0;
2230 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2231 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2236 img.data = (gfxcolor_t*)data;
2240 if(type == IMAGE_TYPE_JPEG)
2241 /* TODO: pass image_dpi to device instead */
2242 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2244 dev->fillbitmap(dev, &p1, &img, &m, 0);
2247 void drawimagejpeg(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2248 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2250 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2253 void drawimagelossless(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2254 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2256 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2260 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2261 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2262 GBool inlineImg, int mask, int*maskColors,
2263 Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GfxImageColorMap*maskColorMap)
2265 double x1,y1,x2,y2,x3,y3,x4,y4;
2266 ImageStream *imgStr;
2271 unsigned char* maskbitmap = 0;
2274 ncomps = colorMap->getNumPixelComps();
2275 bits = colorMap->getBits();
2280 unsigned char buf[8];
2281 maskbitmap = (unsigned char*)malloc(maskHeight*maskWidth);
2283 ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, maskColorMap->getNumPixelComps(), maskColorMap->getBits());
2284 imgMaskStr->reset();
2285 unsigned char pal[256];
2286 int n = 1 << colorMap->getBits();
2291 maskColorMap->getGray(pixBuf, &gray);
2292 pal[t] = colToByte(gray);
2294 for (y = 0; y < maskHeight; y++) {
2295 for (x = 0; x < maskWidth; x++) {
2296 imgMaskStr->getPixel(buf);
2297 maskbitmap[y*maskWidth+x] = pal[buf[0]];
2302 ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, 1, 1);
2303 imgMaskStr->reset();
2304 for (y = 0; y < maskHeight; y++) {
2305 for (x = 0; x < maskWidth; x++) {
2306 imgMaskStr->getPixel(buf);
2308 maskbitmap[y*maskWidth+x] = (buf[0]^1)*255;
2316 imgStr = new ImageStream(str, width, ncomps,bits);
2319 if(!width || !height || (height<=1 && width<=1))
2321 msg("<verbose> Ignoring %d by %d image", width, height);
2322 unsigned char buf[8];
2324 for (y = 0; y < height; ++y)
2325 for (x = 0; x < width; ++x) {
2326 imgStr->getPixel(buf);
2334 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1 += user_movey;
2335 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2 += user_movey;
2336 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3 += user_movey;
2337 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4 += user_movey;
2340 if(!pbminfo && !(str->getKind()==strDCT)) {
2342 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2346 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2348 if(!jpeginfo && (str->getKind()==strDCT)) {
2349 msg("<notice> file contains jpeg pictures");
2355 unsigned char buf[8];
2357 unsigned char*pic = new unsigned char[width*height];
2358 gfxcolor_t pal[256];
2360 state->getFillRGB(&rgb);
2362 memset(pal,255,sizeof(pal));
2363 pal[0].r = (int)(colToByte(rgb.r)); pal[1].r = 0;
2364 pal[0].g = (int)(colToByte(rgb.g)); pal[1].g = 0;
2365 pal[0].b = (int)(colToByte(rgb.b)); pal[1].b = 0;
2366 pal[0].a = 255; pal[1].a = 0;
2369 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2370 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2371 for (y = 0; y < height; ++y)
2372 for (x = 0; x < width; ++x)
2374 imgStr->getPixel(buf);
2377 pic[width*y+x] = buf[0];
2380 /* the size of the drawn image is added to the identifier
2381 as the same image may require different bitmaps if displayed
2382 at different sizes (due to antialiasing): */
2385 unsigned char*pic2 = 0;
2388 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2397 height = realheight;
2401 /* make a black/white palette */
2403 float r = 255/(numpalette-1);
2405 for(t=0;t<numpalette;t++) {
2406 pal[t].r = colToByte(rgb.r);
2407 pal[t].g = colToByte(rgb.g);
2408 pal[t].b = colToByte(rgb.b);
2409 pal[t].a = (unsigned char)(t*r);
2413 gfxcolor_t*pic2 = new gfxcolor_t[width*height];
2414 for (y = 0; y < height; ++y) {
2415 for (x = 0; x < width; ++x) {
2416 pic2[width*y+x] = pal[pic[y*width+x]];
2419 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2423 if(maskbitmap) free(maskbitmap);
2429 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2430 gfxcolor_t*pic=new gfxcolor_t[width*height];
2431 for (y = 0; y < height; ++y) {
2432 for (x = 0; x < width; ++x) {
2433 imgStr->getPixel(pixBuf);
2434 colorMap->getRGB(pixBuf, &rgb);
2435 pic[width*y+x].r = (unsigned char)(colToByte(rgb.r));
2436 pic[width*y+x].g = (unsigned char)(colToByte(rgb.g));
2437 pic[width*y+x].b = (unsigned char)(colToByte(rgb.b));
2438 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2440 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2444 if(str->getKind()==strDCT)
2445 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2447 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2450 if(maskbitmap) free(maskbitmap);
2453 gfxcolor_t*pic=new gfxcolor_t[width*height];
2454 gfxcolor_t pal[256];
2455 int n = 1 << colorMap->getBits();
2457 for(t=0;t<256;t++) {
2459 colorMap->getRGB(pixBuf, &rgb);
2461 {/*if(maskColors && *maskColors==t) {
2462 msg("<notice> Color %d is transparent", t);
2463 if (imgData->maskColors) {
2465 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2466 if (pix[i] < imgData->maskColors[2*i] ||
2467 pix[i] > imgData->maskColors[2*i+1]) {
2482 pal[t].r = (unsigned char)(colToByte(rgb.r));
2483 pal[t].g = (unsigned char)(colToByte(rgb.g));
2484 pal[t].b = (unsigned char)(colToByte(rgb.b));
2485 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2488 for (y = 0; y < height; ++y) {
2489 for (x = 0; x < width; ++x) {
2490 imgStr->getPixel(pixBuf);
2491 pic[width*y+x] = pal[pixBuf[0]];
2493 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2497 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2501 if(maskbitmap) free(maskbitmap);
2506 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2507 int width, int height, GBool invert,
2510 if(states[statepos].textRender & 4) //clipped
2512 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2513 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0, 0,0,0,0, 0);
2516 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2517 int width, int height, GfxImageColorMap *colorMap,
2518 int *maskColors, GBool inlineImg)
2520 if(states[statepos].textRender & 4) //clipped
2523 msg("<verbose> drawImage %dx%d, %s, %s, inline=%d", width, height,
2524 colorMap?"colorMap":"no colorMap",
2525 maskColors?"maskColors":"no maskColors",
2528 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2529 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2530 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors, 0,0,0,0, 0);
2533 void SWFOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
2534 int width, int height,
2535 GfxImageColorMap *colorMap,
2536 Stream *maskStr, int maskWidth, int maskHeight,
2539 if(states[statepos].textRender & 4) //clipped
2542 msg("<verbose> drawMaskedImage %dx%d, %s, %dx%d mask", width, height,
2543 colorMap?"colorMap":"no colorMap",
2544 maskWidth, maskHeight);
2546 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2547 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2548 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, maskInvert, 0);
2551 void SWFOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
2552 int width, int height,
2553 GfxImageColorMap *colorMap,
2555 int maskWidth, int maskHeight,
2556 GfxImageColorMap *maskColorMap)
2558 if(states[statepos].textRender & 4) //clipped
2561 msg("<verbose> drawSoftMaskedImage %dx%d, %s, %dx%d mask", width, height,
2562 colorMap?"colorMap":"no colorMap",
2563 maskWidth, maskHeight);
2565 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2566 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2567 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, 0, maskColorMap);
2570 //SWFOutputDev*output = 0;
2572 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2577 if (infoDict->lookup(key, &obj)->isString()) {
2578 s1 = obj.getString();
2579 if ((s1->getChar(0) & 0xff) == 0xfe &&
2580 (s1->getChar(1) & 0xff) == 0xff) {
2582 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2583 if (s1->getChar(i) == '\0') {
2584 s2->append(s1->getChar(i+1));
2587 s2 = new GString("<unicode>");
2591 printf(fmt, s2->getCString());
2594 printf(fmt, s1->getCString());
2600 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2604 if (infoDict->lookup(key, &obj)->isString()) {
2605 s = obj.getString()->getCString();
2606 if (s[0] == 'D' && s[1] == ':') {
2617 void storeDeviceParameter(char*name, char*value)
2619 parameter_t*p = new parameter_t();
2620 p->name = strdup(name);
2621 p->value = strdup(value);
2623 if(device_config_next) {
2624 device_config_next->next = p;
2625 device_config_next = p;
2628 device_config_next = p;
2632 void pdfswf_setparameter(char*name, char*value)
2634 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2635 if(!strcmp(name, "caplinewidth")) {
2636 caplinewidth = atof(value);
2637 } else if(!strcmp(name, "zoom")) {
2640 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2641 storeDeviceParameter("jpegsubpixels", buf);
2642 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2643 storeDeviceParameter("ppmsubpixels", buf);
2644 } else if(!strcmp(name, "jpegdpi")) {
2646 jpeg_dpi = atoi(value);
2647 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2648 storeDeviceParameter("jpegsubpixels", buf);
2649 } else if(!strcmp(name, "ppmdpi")) {
2651 ppm_dpi = atoi(value);
2652 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2653 storeDeviceParameter("ppmsubpixels", buf);
2654 } else if(!strcmp(name, "forceType0Fonts")) {
2655 forceType0Fonts = atoi(value);
2656 } else if(!strncmp(name, "fontdir", strlen("fontdir"))) {
2657 pdfswf_addfontdir(value);
2658 } else if(!strncmp(name, "languagedir", strlen("languagedir"))) {
2659 pdfswf_addlanguagedir(value);
2660 } else if(!strcmp(name, "fontconfig")) {
2661 config_use_fontconfig = atoi(value);
2663 storeDeviceParameter(name,value);
2666 void pdfswf_addfont(char*filename)
2669 memset(&f, 0, sizeof(fontfile_t));
2670 f.filename = filename;
2671 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2672 fonts[fontnum++] = f;
2674 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2678 static char* dirseparator()
2687 void pdfswf_addlanguagedir(char*dir)
2690 globalParams = new GlobalParams("");
2692 msg("<notice> Adding %s to language pack directories", dir);
2696 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc") + 1);
2697 strcpy(config_file, dir);
2698 strcat(config_file, dirseparator());
2699 strcat(config_file, "add-to-xpdfrc");
2701 fi = fopen(config_file, "rb");
2703 msg("<error> Could not open %s", config_file);
2706 globalParams->parseFile(new GString(config_file), fi);
2710 void pdfswf_addfontdir(char*dirname)
2712 #ifdef HAVE_DIRENT_H
2713 msg("<notice> Adding %s to font directories", dirname);
2714 lastfontdir = strdup(dirname);
2715 DIR*dir = opendir(dirname);
2717 msg("<warning> Couldn't open directory %s\n", dirname);
2722 ent = readdir (dir);
2726 char*name = ent->d_name;
2732 if(!strncasecmp(&name[l-4], ".pfa", 4))
2734 if(!strncasecmp(&name[l-4], ".pfb", 4))
2736 if(!strncasecmp(&name[l-4], ".ttf", 4))
2740 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2741 strcpy(fontname, dirname);
2742 strcat(fontname, dirseparator());
2743 strcat(fontname, name);
2744 msg("<verbose> Adding %s to fonts", fontname);
2745 pdfswf_addfont(fontname);
2750 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2755 typedef struct _pdf_doc_internal
2760 } pdf_doc_internal_t;
2761 typedef struct _pdf_page_internal
2763 } pdf_page_internal_t;
2764 typedef struct _dev_output_internal
2766 SWFOutputDev*outputDev;
2767 } dev_output_internal_t;
2769 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2771 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2772 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2773 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2774 memset(i, 0, sizeof(pdf_doc_internal_t));
2775 pdf_doc->internal = i;
2777 GString *fileName = new GString(filename);
2783 globalParams = new GlobalParams("");
2786 if (userPassword && userPassword[0]) {
2787 userPW = new GString(userPassword);
2791 i->doc = new PDFDoc(fileName, userPW);
2795 if (!i->doc->isOk()) {
2800 i->doc->getDocInfo(&info);
2801 if (info.isDict() &&
2802 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2803 printInfoString(info.getDict(), "Title", "Title: %s\n");
2804 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2805 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2806 printInfoString(info.getDict(), "Author", "Author: %s\n");
2807 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2808 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2809 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2810 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2811 printf("Pages: %d\n", i->doc->getNumPages());
2812 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2813 printf("Encrypted: ");
2814 if (i->doc->isEncrypted()) {
2815 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2816 i->doc->okToPrint() ? "yes" : "no",
2817 i->doc->okToCopy() ? "yes" : "no",
2818 i->doc->okToChange() ? "yes" : "no",
2819 i->doc->okToAddNotes() ? "yes" : "no");
2826 pdf_doc->num_pages = i->doc->getNumPages();
2828 if (i->doc->isEncrypted()) {
2829 if(!i->doc->okToCopy()) {
2830 printf("PDF disallows copying.\n");
2833 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2837 InfoOutputDev*io = new InfoOutputDev();
2839 for(t=1;t<=pdf_doc->num_pages;t++) {
2840 i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, /*usemediabox*/true, /*crop*/true, /*doLinks*/(int)1);
2851 delete globalParams;globalParams=0;
2852 Object::memCheck(stderr);
2857 void pdf_destroy(pdf_doc_t*pdf_doc)
2859 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2861 delete i->doc; i->doc=0;
2864 delete i->info;i->info=0;
2867 free(pdf_doc->internal);pdf_doc->internal=0;
2868 free(pdf_doc);pdf_doc=0;
2871 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2873 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2875 if(page < 1 || page > pdf_doc->num_pages)
2878 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2879 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2880 memset(pi, 0, sizeof(pdf_page_internal_t));
2881 pdf_page->internal = pi;
2883 pdf_page->parent = pdf_doc;
2884 pdf_page->nr = page;
2888 void pdf_page_destroy(pdf_page_t*pdf_page)
2890 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2891 free(pdf_page->internal);pdf_page->internal = 0;
2892 free(pdf_page);pdf_page=0;
2895 dev_output_t* dev_output_init(gfxdevice_t*dev)
2897 dev_output_t*dev_output = (dev_output_t*)malloc(sizeof(dev_output_t));
2898 memset(dev_output, 0, sizeof(dev_output_t));
2899 dev_output_internal_t*i= (dev_output_internal_t*)malloc(sizeof(dev_output_internal_t));
2900 memset(i, 0, sizeof(dev_output_internal_t));
2901 dev_output->internal = i;
2903 i->outputDev = new SWFOutputDev(dev);
2907 void dev_output_setparameter(dev_output_t*swf, char*name, char*value)
2909 pdfswf_setparameter(name, value);
2912 void dev_output_startframe(dev_output_t*swf, int width, int height)
2914 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2915 i->outputDev->startFrame(width, height);
2918 void dev_output_endframe(dev_output_t*swf)
2920 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2921 i->outputDev->endframe();
2924 void dev_output_finish(dev_output_t*swf)
2926 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2927 i->outputDev->finish();
2930 void dev_output_preparepage(dev_output_t*swf, int pdfpage, int outputpage)
2932 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2933 SWFOutputDev*o = i->outputDev;
2939 o->pagebuflen = 1024;
2940 o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
2941 memset(o->pages, -1, o->pagebuflen*sizeof(int));
2943 while(pdfpage >= o->pagebuflen)
2945 int oldlen = o->pagebuflen;
2946 o->pagebuflen+=1024;
2947 o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
2948 memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
2951 o->pages[pdfpage] = outputpage;
2952 if(pdfpage>o->pagepos)
2953 o->pagepos = pdfpage;
2956 void dev_output_destroy(dev_output_t*output)
2958 dev_output_internal_t*i = (dev_output_internal_t*)output->internal;
2959 delete i->outputDev; i->outputDev=0;
2960 free(output->internal);output->internal=0;
2964 void pdf_page_render2(pdf_page_t*page, dev_output_t*swf)
2966 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2967 dev_output_internal_t*si = (dev_output_internal_t*)swf->internal;
2970 msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2975 gfxdevice_t*dev = si->outputDev->output;
2976 dev->setparameter(dev, "protect", "1");
2978 si->outputDev->setInfo(pi->info);
2979 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2980 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
2983 void pdf_page_rendersection(pdf_page_t*page, dev_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
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(x,y);
2989 if((x1|y1|x2|y2)==0) x2++;
2990 si->outputDev->setClip(x1,y1,x2,y2);
2992 pdf_page_render2(page, output);
2994 void pdf_page_render(pdf_page_t*page, dev_output_t*output)
2996 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2997 dev_output_internal_t*si = (dev_output_internal_t*)output->internal;
2999 si->outputDev->setMove(0,0);
3000 si->outputDev->setClip(0,0,0,0);
3002 pdf_page_render2(page, output);
3006 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
3008 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
3009 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
3010 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
3011 memset(info, 0, sizeof(pdf_page_info_t));
3013 InfoOutputDev*output = new InfoOutputDev;
3015 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
3017 info->xMin = output->x1;
3018 info->yMin = output->y1;
3019 info->xMax = output->x2;
3020 info->yMax = output->y2;
3021 info->number_of_images = output->num_images;
3022 info->number_of_links = output->num_links;
3023 info->number_of_fonts = output->num_fonts;
3030 void pdf_page_info_destroy(pdf_page_info_t*info)