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);
1229 if(font->isCIDFont()) {
1230 GfxCIDFont*cfont = (GfxCIDFont*)font;
1232 if(font->getType() == fontCIDType2)
1233 CIDToGIDMap = cfont->getCIDToGID();
1236 font8 = (Gfx8BitFont*)font;
1237 char**enc=font8->getEncoding();
1241 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);
1244 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);
1250 charid = getGfxCharID(current_gfxfont, c, name, u);
1252 charid = getGfxCharID(current_gfxfont, c, name, -1);
1255 /* multiple unicodes- should usually map to a ligature.
1256 if the ligature doesn't exist, we need to draw
1257 the characters one-by-one. */
1259 msg("<warning> ligature %d missing in font %s\n", c, current_font_id);
1260 for(t=0;t<uLen;t++) {
1261 drawChar(state, x, y, dx, dy, originX, originY, c, nBytes, _u+t, 1);
1267 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1268 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1272 gfxmatrix_t m = this->current_font_matrix;
1273 state->transform(x, y, &m.tx, &m.ty);
1277 if(render == RENDER_FILL) {
1278 output->drawchar(output, current_font_id, charid, &col, &m);
1280 msg("<debug> Drawing glyph %d as shape", charid);
1282 msg("<notice> Some texts will be rendered as shape");
1285 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1286 gfxline_t*tglyph = gfxline_clone(glyph);
1287 gfxline_transform(tglyph, &m);
1288 if((render&3) != RENDER_INVISIBLE) {
1289 gfxline_t*add = gfxline_clone(tglyph);
1290 current_text_stroke = gfxline_append(current_text_stroke, add);
1292 if(render&RENDER_CLIP) {
1293 gfxline_t*add = gfxline_clone(tglyph);
1294 current_text_clip = gfxline_append(current_text_clip, add);
1296 gfxline_free(tglyph);
1300 void SWFOutputDev::endString(GfxState *state)
1302 int render = state->getRender();
1303 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1304 if(states[statepos].textRender != render)
1305 msg("<error> Internal error: drawChar.render!=beginString.render");
1307 if(current_text_stroke) {
1308 /* fillstroke and stroke text rendering objects we can process right
1309 now (as there may be texts of other rendering modes in this
1310 text object)- clipping objects have to wait until endTextObject,
1312 output->setparameter(output, "mark","TXT");
1313 if((render&3) == RENDER_FILL) {
1314 fillGfxLine(state, current_text_stroke);
1315 gfxline_free(current_text_stroke);
1316 current_text_stroke = 0;
1317 } else if((render&3) == RENDER_FILLSTROKE) {
1318 fillGfxLine(state, current_text_stroke);
1319 strokeGfxline(state, current_text_stroke);
1320 gfxline_free(current_text_stroke);
1321 current_text_stroke = 0;
1322 } else if((render&3) == RENDER_STROKE) {
1323 strokeGfxline(state, current_text_stroke);
1324 gfxline_free(current_text_stroke);
1325 current_text_stroke = 0;
1327 output->setparameter(output, "mark","");
1331 void SWFOutputDev::endTextObject(GfxState *state)
1333 int render = state->getRender();
1334 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1335 if(states[statepos].textRender != render)
1336 msg("<error> Internal error: drawChar.render!=beginString.render");
1338 if(current_text_clip) {
1339 output->setparameter(output, "mark","TXT");
1340 clipToGfxLine(state, current_text_clip);
1341 output->setparameter(output, "mark","");
1342 gfxline_free(current_text_clip);
1343 current_text_clip = 0;
1347 /* the logic seems to be as following:
1348 first, beginType3Char is called, with the charcode and the coordinates.
1349 if this function returns true, it already knew about the char and has now drawn it.
1350 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1351 the all draw operations until endType3Char are part of the char (which in this moment is
1352 at the position first passed to beginType3Char). the char ends with endType3Char.
1354 The drawing operations between beginType3Char and endType3Char are somewhat different to
1355 the normal ones. For example, the fillcolor equals the stroke color.
1358 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1360 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1362 /* the character itself is going to be passed using the draw functions */
1363 return gFalse; /* gTrue= is_in_cache? */
1366 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1367 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1369 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1370 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1374 void SWFOutputDev::endType3Char(GfxState *state)
1377 msg("<debug> endType3Char");
1380 void SWFOutputDev::startFrame(int width, int height)
1382 output->startpage(output, width, height);
1385 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1387 this->currentpage = pageNum;
1389 int rot = doc->getPageRotate(1);
1392 gfxline_t clippath[5];
1394 white.r = white.g = white.b = white.a = 255;
1396 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1397 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1398 Use CropBox, not MediaBox, as page size
1405 state->transform(crop_x1,crop_y1,&x1,&y1); //x1 += user_movex; y1 += user_movey;
1406 state->transform(crop_x2,crop_y2,&x2,&y2); //x2 += user_movex; y2 += user_movey;
1408 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1409 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1412 /* apply user clip box */
1413 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1414 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1415 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1416 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1417 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1420 //msg("<verbose> Bounding box is (%f,%f)-(%f,%f) [shifted by %d/%d]", x1,y1,x2,y2, user_movex, user_movey);
1422 if(outer_clip_box) {
1423 output->endclip(output);
1427 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);
1429 msg("<verbose> page is rotated %d degrees\n", rot);
1431 clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1432 clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1433 clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1434 clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1435 clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1436 output->startclip(output, clippath); outer_clip_box = 1;
1437 output->fill(output, clippath, &white);
1440 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1442 double x1, y1, x2, y2, w;
1443 gfxline_t points[5];
1446 msg("<debug> drawlink\n");
1448 link->getRect(&x1, &y1, &x2, &y2);
1449 cvtUserToDev(x1, y1, &x, &y);
1450 points[0].type = gfx_moveTo;
1451 points[0].x = points[4].x = x + user_movex;
1452 points[0].y = points[4].y = y + user_movey;
1453 points[0].next = &points[1];
1454 cvtUserToDev(x2, y1, &x, &y);
1455 points[1].type = gfx_lineTo;
1456 points[1].x = x + user_movex;
1457 points[1].y = y + user_movey;
1458 points[1].next = &points[2];
1459 cvtUserToDev(x2, y2, &x, &y);
1460 points[2].type = gfx_lineTo;
1461 points[2].x = x + user_movex;
1462 points[2].y = y + user_movey;
1463 points[2].next = &points[3];
1464 cvtUserToDev(x1, y2, &x, &y);
1465 points[3].type = gfx_lineTo;
1466 points[3].x = x + user_movex;
1467 points[3].y = y + user_movey;
1468 points[3].next = &points[4];
1469 cvtUserToDev(x1, y1, &x, &y);
1470 points[4].type = gfx_lineTo;
1471 points[4].x = x + user_movex;
1472 points[4].y = y + user_movey;
1475 LinkAction*action=link->getAction();
1482 switch(action->getKind())
1486 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1487 LinkDest *dest=NULL;
1488 if (ha->getDest()==NULL)
1489 dest=catalog->findDest(ha->getNamedDest());
1490 else dest=ha->getDest();
1492 if (dest->isPageRef()){
1493 Ref pageref=dest->getPageRef();
1494 page=catalog->findPage(pageref.num,pageref.gen);
1496 else page=dest->getPageNum();
1497 sprintf(buf, "%d", page);
1504 LinkGoToR*l = (LinkGoToR*)action;
1505 GString*g = l->getNamedDest();
1507 s = strdup(g->getCString());
1512 LinkNamed*l = (LinkNamed*)action;
1513 GString*name = l->getName();
1515 s = strdup(name->lowerCase()->getCString());
1516 named = name->getCString();
1519 if(strstr(s, "next") || strstr(s, "forward"))
1521 page = currentpage + 1;
1523 else if(strstr(s, "prev") || strstr(s, "back"))
1525 page = currentpage - 1;
1527 else if(strstr(s, "last") || strstr(s, "end"))
1529 if(pages && pagepos>0)
1530 page = pages[pagepos-1];
1532 else if(strstr(s, "first") || strstr(s, "top"))
1540 case actionLaunch: {
1542 LinkLaunch*l = (LinkLaunch*)action;
1543 GString * str = new GString(l->getFileName());
1544 GString * params = l->getParams();
1546 str->append(params);
1547 s = strdup(str->getCString());
1553 LinkURI*l = (LinkURI*)action;
1554 GString*g = l->getURI();
1556 url = g->getCString();
1561 case actionUnknown: {
1563 LinkUnknown*l = (LinkUnknown*)action;
1568 msg("<error> Unknown link type!\n");
1573 if(!s) s = strdup("-?-");
1575 if(!linkinfo && (page || url))
1577 msg("<notice> File contains links");
1585 for(t=1;t<=pagepos;t++) {
1586 if(pages[t]==page) {
1595 sprintf(buf, "page%d", lpage);
1596 output->drawlink(output, points, buf);
1600 output->drawlink(output, points, url);
1603 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1607 void SWFOutputDev::saveState(GfxState *state) {
1608 msg("<trace> saveState\n");
1611 msg("<error> Too many nested states in pdf.");
1615 states[statepos].clipping = 0; //? shouldn't this be the current value?
1616 states[statepos].textRender = states[statepos-1].textRender;
1619 void SWFOutputDev::restoreState(GfxState *state) {
1620 msg("<trace> restoreState\n");
1622 while(states[statepos].clipping) {
1623 output->endclip(output);
1624 states[statepos].clipping--;
1629 char* SWFOutputDev::searchFont(char*name)
1633 int is_standard_font = 0;
1635 msg("<verbose> SearchFont(%s)", name);
1637 /* see if it is a pdf standard font */
1638 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1640 if(!strcmp(name, pdf2t1map[i].pdffont))
1642 name = pdf2t1map[i].filename;
1643 is_standard_font = 1;
1647 /* look in all font files */
1648 for(i=0;i<fontnum;i++)
1650 if(strstr(fonts[i].filename, name))
1652 if(!fonts[i].used) {
1655 if(!is_standard_font)
1656 msg("<notice> Using %s for %s", fonts[i].filename, name);
1658 return strdup(fonts[i].filename);
1664 void SWFOutputDev::updateLineWidth(GfxState *state)
1666 double width = state->getTransformedLineWidth();
1667 //swfoutput_setlinewidth(&output, width);
1670 void SWFOutputDev::updateLineCap(GfxState *state)
1672 int c = state->getLineCap();
1675 void SWFOutputDev::updateLineJoin(GfxState *state)
1677 int j = state->getLineJoin();
1680 void SWFOutputDev::updateFillColor(GfxState *state)
1683 double opaq = state->getFillOpacity();
1684 state->getFillRGB(&rgb);
1686 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1689 void SWFOutputDev::updateStrokeColor(GfxState *state)
1692 double opaq = state->getStrokeOpacity();
1693 state->getStrokeRGB(&rgb);
1694 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1697 void FoFiWrite(void *stream, char *data, int len)
1699 fwrite(data, len, 1, (FILE*)stream);
1702 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1704 char*tmpFileName = NULL;
1710 Object refObj, strObj;
1712 tmpFileName = mktmpname(namebuf);
1715 ret = font->getEmbeddedFontID(&embRef);
1717 msg("<verbose> Didn't get embedded font id");
1718 /* not embedded- the caller should now search the font
1719 directories for this font */
1723 f = fopen(tmpFileName, "wb");
1725 msg("<error> Couldn't create temporary Type 1 font file");
1729 /*if(font->isCIDFont()) {
1730 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1731 GString c = cidFont->getCollection();
1732 msg("<notice> Collection: %s", c.getCString());
1735 //if (font->getType() == fontType1C) {
1736 if (0) { //font->getType() == fontType1C) {
1737 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1739 msg("<error> Couldn't read embedded font file");
1742 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1744 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1745 //cvt->convertToCIDType0("test", f);
1746 //cvt->convertToType0("test", f);
1749 } else if(font->getType() == fontTrueType) {
1750 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1751 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1753 msg("<error> Couldn't read embedded font file");
1756 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1757 cvt->writeTTF(FoFiWrite, f);
1761 font->getEmbeddedFontID(&embRef);
1762 refObj.initRef(embRef.num, embRef.gen);
1763 refObj.fetch(ref, &strObj);
1765 strObj.streamReset();
1770 f4[t] = strObj.streamGetChar();
1771 f4c[t] = (char)f4[t];
1776 if(!strncmp(f4c, "true", 4)) {
1777 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1778 Change this on the fly */
1779 f4[0] = f4[2] = f4[3] = 0;
1787 while ((c = strObj.streamGetChar()) != EOF) {
1791 strObj.streamClose();
1796 return strdup(tmpFileName);
1799 char* searchForSuitableFont(GfxFont*gfxFont)
1801 char*name = getFontName(gfxFont);
1805 if(!config_use_fontconfig)
1808 #ifdef HAVE_FONTCONFIG
1809 FcPattern *pattern, *match;
1813 static int fcinitcalled = false;
1815 msg("<debug> searchForSuitableFont(%s)", name);
1817 // call init ony once
1818 if (!fcinitcalled) {
1819 msg("<debug> Initializing FontConfig...");
1820 fcinitcalled = true;
1822 msg("<debug> FontConfig Initialization failed. Disabling.");
1823 config_use_fontconfig = 0;
1826 msg("<debug> ...initialized FontConfig");
1829 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1830 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1831 if (gfxFont->isItalic()) // check for italic
1832 msg("<debug> FontConfig: Adding Italic Slant");
1833 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1834 if (gfxFont->isBold()) // check for bold
1835 msg("<debug> FontConfig: Adding Bold Weight");
1836 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1838 msg("<debug> FontConfig: Try to match...");
1839 // configure and match using the original font name
1840 FcConfigSubstitute(0, pattern, FcMatchPattern);
1841 FcDefaultSubstitute(pattern);
1842 match = FcFontMatch(0, pattern, &result);
1844 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1845 msg("<debug> FontConfig: family=%s", (char*)v);
1846 // if we get an exact match
1847 if (strcmp((char *)v, name) == 0) {
1848 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1849 filename = strdup((char*)v); // mem leak
1850 char *nfn = strrchr(filename, '/');
1851 if(nfn) fontname = strdup(nfn+1);
1852 else fontname = filename;
1854 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1856 // initialize patterns
1857 FcPatternDestroy(pattern);
1858 FcPatternDestroy(match);
1860 // now match against serif etc.
1861 if (gfxFont->isSerif()) {
1862 msg("<debug> FontConfig: Create Serif Family Pattern");
1863 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1864 } else if (gfxFont->isFixedWidth()) {
1865 msg("<debug> FontConfig: Create Monospace Family Pattern");
1866 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1868 msg("<debug> FontConfig: Create Sans Family Pattern");
1869 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1873 if (gfxFont->isItalic()) {
1874 msg("<debug> FontConfig: Adding Italic Slant");
1875 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1878 if (gfxFont->isBold()) {
1879 msg("<debug> FontConfig: Adding Bold Weight");
1880 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1883 msg("<debug> FontConfig: Try to match... (2)");
1884 // configure and match using serif etc
1885 FcConfigSubstitute (0, pattern, FcMatchPattern);
1886 FcDefaultSubstitute (pattern);
1887 match = FcFontMatch (0, pattern, &result);
1889 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1890 filename = strdup((char*)v); // mem leak
1891 char *nfn = strrchr(filename, '/');
1892 if(nfn) fontname = strdup(nfn+1);
1893 else fontname = filename;
1895 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1899 //printf("FONTCONFIG: pattern");
1900 //FcPatternPrint(pattern);
1901 //printf("FONTCONFIG: match");
1902 //FcPatternPrint(match);
1904 FcPatternDestroy(pattern);
1905 FcPatternDestroy(match);
1907 pdfswf_addfont(filename);
1914 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1916 char*fontname = 0, *filename = 0;
1917 msg("<notice> substituteFont(%s)", oldname);
1919 if(!(fontname = searchForSuitableFont(gfxFont))) {
1920 fontname = "Times-Roman";
1922 filename = searchFont(fontname);
1924 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1928 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1929 msg("<fatal> Too many fonts in file.");
1933 substitutesource[substitutepos] = strdup(oldname); //mem leak
1934 substitutetarget[substitutepos] = fontname;
1935 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1938 return strdup(filename); //mem leak
1941 void unlinkfont(char* filename)
1948 if(!strncmp(&filename[l-4],".afm",4)) {
1949 memcpy(&filename[l-4],".pfb",4);
1951 memcpy(&filename[l-4],".pfa",4);
1953 memcpy(&filename[l-4],".afm",4);
1956 if(!strncmp(&filename[l-4],".pfa",4)) {
1957 memcpy(&filename[l-4],".afm",4);
1959 memcpy(&filename[l-4],".pfa",4);
1962 if(!strncmp(&filename[l-4],".pfb",4)) {
1963 memcpy(&filename[l-4],".afm",4);
1965 memcpy(&filename[l-4],".pfb",4);
1970 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1976 int SWFOutputDev::setGfxFont(char*id, char*name, char*filename, double maxSize)
1979 fontlist_t*last=0,*l = this->fontlist;
1981 /* TODO: should this be part of the state? */
1984 if(!strcmp(l->id, id)) {
1985 current_font_id = l->id;
1986 current_gfxfont = l->font;
1988 output->addfont(output, id, current_gfxfont);
1993 if(!filename) return 0;
1995 /* A font size of e.g. 9 means the font will be scaled down by
1996 1024 and scaled up by 9. So to have a maximum error of 1/20px,
1997 we have to divide 0.05 by (fontsize/1024)
1999 double quality = (1024 * 0.05) / maxSize;
2001 msg("<verbose> Loading %s...", filename);
2002 font = gfxfont_load(filename, quality);
2003 msg("<verbose> Font %s loaded successfully", filename);
2007 l->filename = strdup(filename);
2010 current_font_id = l->id;
2011 current_gfxfont = l->font;
2017 output->addfont(output, id, current_gfxfont);
2021 void SWFOutputDev::updateFont(GfxState *state)
2023 GfxFont*gfxFont = state->getFont();
2029 char * fontid = getFontID(gfxFont);
2030 char * fontname = getFontName(gfxFont);
2032 double maxSize = 1.0;
2035 maxSize = this->info->getMaximumFontSize(fontid);
2039 /* first, look if we substituted this font before-
2040 this way, we don't initialize the T1 Fonts
2042 for(t=0;t<substitutepos;t++) {
2043 if(!strcmp(fontid, substitutesource[t])) {
2044 free(fontid);fontid=0;
2045 fontid = strdup(substitutetarget[t]);
2050 /* second, see if this is a font which was used before-
2051 if so, we are done */
2052 if(setGfxFont(fontid, fontname, 0, 0)) {
2057 /* if(swfoutput_queryfont(&output, fontid))
2058 swfoutput_setfont(&output, fontid, 0);
2060 msg("<debug> updateFont(%s) [cached]", fontid);
2064 // look for Type 3 font
2065 if (gfxFont->getType() == fontType3) {
2067 type3Warning = gTrue;
2068 showFontError(gfxFont, 2);
2075 /* now either load the font, or find a substitution */
2078 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
2083 (gfxFont->getType() == fontType1 ||
2084 gfxFont->getType() == fontType1C ||
2085 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
2086 gfxFont->getType() == fontTrueType ||
2087 gfxFont->getType() == fontCIDType2
2090 fileName = writeEmbeddedFontToFile(xref, gfxFont);
2091 if(!fileName) showFontError(gfxFont,0);
2094 fileName = searchFont(fontname);
2095 if(!fileName) showFontError(gfxFont,0);
2098 char * fontname = getFontName(gfxFont);
2099 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
2102 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into %s", fontname, lastfontdir);
2104 msg("<warning> Try specifying one or more font directories");
2106 fileName = substituteFont(gfxFont, fontid);
2109 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
2110 msg("<notice> Font is now %s (%s)", fontid, fileName);
2114 msg("<error> Couldn't set font %s\n", fontid);
2120 msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
2121 dumpFontInfo("<verbose>", gfxFont);
2123 //swfoutput_setfont(&output, fontid, fileName);
2125 if(!setGfxFont(fontid, fontname, 0, 0)) {
2126 setGfxFont(fontid, fontname, fileName, maxSize);
2130 unlinkfont(fileName);
2140 #define SQR(x) ((x)*(x))
2142 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
2144 if((newwidth<2 || newheight<2) ||
2145 (width<=newwidth || height<=newheight))
2147 unsigned char*newdata;
2149 newdata= (unsigned char*)malloc(newwidth*newheight);
2151 double fx = (double)(width)/newwidth;
2152 double fy = (double)(height)/newheight;
2154 int blocksize = (int)(8192/(fx*fy));
2155 int r = 8192*256/palettesize;
2156 for(x=0;x<newwidth;x++) {
2157 double ex = px + fx;
2158 int fromx = (int)px;
2160 int xweight1 = (int)(((fromx+1)-px)*256);
2161 int xweight2 = (int)((ex-tox)*256);
2163 for(y=0;y<newheight;y++) {
2164 double ey = py + fy;
2165 int fromy = (int)py;
2167 int yweight1 = (int)(((fromy+1)-py)*256);
2168 int yweight2 = (int)((ey-toy)*256);
2171 for(xx=fromx;xx<=tox;xx++)
2172 for(yy=fromy;yy<=toy;yy++) {
2173 int b = 1-data[width*yy+xx];
2175 if(xx==fromx) weight = (weight*xweight1)/256;
2176 if(xx==tox) weight = (weight*xweight2)/256;
2177 if(yy==fromy) weight = (weight*yweight1)/256;
2178 if(yy==toy) weight = (weight*yweight2)/256;
2181 //if(a) a=(palettesize-1)*r/blocksize;
2182 newdata[y*newwidth+x] = (a*blocksize)/r;
2190 #define IMAGE_TYPE_JPEG 0
2191 #define IMAGE_TYPE_LOSSLESS 1
2193 static void drawimage(gfxdevice_t*dev, gfxcolor_t* data, int sizex,int sizey,
2194 double x1,double y1,
2195 double x2,double y2,
2196 double x3,double y3,
2197 double x4,double y4, int type)
2199 gfxcolor_t*newpic=0;
2201 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2202 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2204 gfxline_t p1,p2,p3,p4,p5;
2205 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2206 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2207 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2208 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2209 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2211 {p1.x = (int)(p1.x*20)/20.0;
2212 p1.y = (int)(p1.y*20)/20.0;
2213 p2.x = (int)(p2.x*20)/20.0;
2214 p2.y = (int)(p2.y*20)/20.0;
2215 p3.x = (int)(p3.x*20)/20.0;
2216 p3.y = (int)(p3.y*20)/20.0;
2217 p4.x = (int)(p4.x*20)/20.0;
2218 p4.y = (int)(p4.y*20)/20.0;
2219 p5.x = (int)(p5.x*20)/20.0;
2220 p5.y = (int)(p5.y*20)/20.0;
2227 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2228 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2233 img.data = (gfxcolor_t*)data;
2237 if(type == IMAGE_TYPE_JPEG)
2238 /* TODO: pass image_dpi to device instead */
2239 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2241 dev->fillbitmap(dev, &p1, &img, &m, 0);
2244 void drawimagejpeg(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2245 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2247 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2250 void drawimagelossless(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
2251 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2253 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2257 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2258 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2259 GBool inlineImg, int mask, int*maskColors,
2260 Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GfxImageColorMap*maskColorMap)
2262 double x1,y1,x2,y2,x3,y3,x4,y4;
2263 ImageStream *imgStr;
2268 unsigned char* maskbitmap = 0;
2271 ncomps = colorMap->getNumPixelComps();
2272 bits = colorMap->getBits();
2277 unsigned char buf[8];
2278 maskbitmap = (unsigned char*)malloc(maskHeight*maskWidth);
2280 ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, maskColorMap->getNumPixelComps(), maskColorMap->getBits());
2281 imgMaskStr->reset();
2282 unsigned char pal[256];
2283 int n = 1 << colorMap->getBits();
2288 maskColorMap->getGray(pixBuf, &gray);
2289 pal[t] = colToByte(gray);
2291 for (y = 0; y < maskHeight; y++) {
2292 for (x = 0; x < maskWidth; x++) {
2293 imgMaskStr->getPixel(buf);
2294 maskbitmap[y*maskWidth+x] = pal[buf[0]];
2299 ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, 1, 1);
2300 imgMaskStr->reset();
2301 for (y = 0; y < maskHeight; y++) {
2302 for (x = 0; x < maskWidth; x++) {
2303 imgMaskStr->getPixel(buf);
2305 maskbitmap[y*maskWidth+x] = (buf[0]^1)*255;
2312 imgStr = new ImageStream(str, width, ncomps,bits);
2315 if(!width || !height || (height<=1 && width<=1))
2317 msg("<verbose> Ignoring %d by %d image", width, height);
2318 unsigned char buf[8];
2320 for (y = 0; y < height; ++y)
2321 for (x = 0; x < width; ++x) {
2322 imgStr->getPixel(buf);
2330 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1 += user_movey;
2331 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2 += user_movey;
2332 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3 += user_movey;
2333 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4 += user_movey;
2335 if(!pbminfo && !(str->getKind()==strDCT)) {
2337 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2341 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2343 if(!jpeginfo && (str->getKind()==strDCT)) {
2344 msg("<notice> file contains jpeg pictures");
2350 unsigned char buf[8];
2352 unsigned char*pic = new unsigned char[width*height];
2353 gfxcolor_t pal[256];
2355 state->getFillRGB(&rgb);
2357 memset(pal,255,sizeof(pal));
2358 pal[0].r = (int)(colToByte(rgb.r)); pal[1].r = 0;
2359 pal[0].g = (int)(colToByte(rgb.g)); pal[1].g = 0;
2360 pal[0].b = (int)(colToByte(rgb.b)); pal[1].b = 0;
2361 pal[0].a = 255; pal[1].a = 0;
2364 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2365 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2366 for (y = 0; y < height; ++y)
2367 for (x = 0; x < width; ++x)
2369 imgStr->getPixel(buf);
2372 pic[width*y+x] = buf[0];
2375 /* the size of the drawn image is added to the identifier
2376 as the same image may require different bitmaps if displayed
2377 at different sizes (due to antialiasing): */
2380 unsigned char*pic2 = 0;
2383 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2392 height = realheight;
2396 /* make a black/white palette */
2398 float r = 255/(numpalette-1);
2400 for(t=0;t<numpalette;t++) {
2401 pal[t].r = colToByte(rgb.r);
2402 pal[t].g = colToByte(rgb.g);
2403 pal[t].b = colToByte(rgb.b);
2404 pal[t].a = (unsigned char)(t*r);
2408 gfxcolor_t*pic2 = new gfxcolor_t[width*height];
2409 for (y = 0; y < height; ++y) {
2410 for (x = 0; x < width; ++x) {
2411 pic2[width*y+x] = pal[pic[y*width+x]];
2414 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2418 if(maskbitmap) free(maskbitmap);
2424 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2425 gfxcolor_t*pic=new gfxcolor_t[width*height];
2426 for (y = 0; y < height; ++y) {
2427 for (x = 0; x < width; ++x) {
2428 imgStr->getPixel(pixBuf);
2429 colorMap->getRGB(pixBuf, &rgb);
2430 pic[width*y+x].r = (unsigned char)(colToByte(rgb.r));
2431 pic[width*y+x].g = (unsigned char)(colToByte(rgb.g));
2432 pic[width*y+x].b = (unsigned char)(colToByte(rgb.b));
2433 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2435 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2439 if(str->getKind()==strDCT)
2440 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2442 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2445 if(maskbitmap) free(maskbitmap);
2448 gfxcolor_t*pic=new gfxcolor_t[width*height];
2449 gfxcolor_t pal[256];
2450 int n = 1 << colorMap->getBits();
2452 for(t=0;t<256;t++) {
2454 colorMap->getRGB(pixBuf, &rgb);
2456 {/*if(maskColors && *maskColors==t) {
2457 msg("<notice> Color %d is transparent", t);
2458 if (imgData->maskColors) {
2460 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2461 if (pix[i] < imgData->maskColors[2*i] ||
2462 pix[i] > imgData->maskColors[2*i+1]) {
2477 pal[t].r = (unsigned char)(colToByte(rgb.r));
2478 pal[t].g = (unsigned char)(colToByte(rgb.g));
2479 pal[t].b = (unsigned char)(colToByte(rgb.b));
2480 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2483 for (y = 0; y < height; ++y) {
2484 for (x = 0; x < width; ++x) {
2485 imgStr->getPixel(pixBuf);
2486 pic[width*y+x] = pal[pixBuf[0]];
2488 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2492 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2496 if(maskbitmap) free(maskbitmap);
2501 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2502 int width, int height, GBool invert,
2505 if(states[statepos].textRender & 4) //clipped
2507 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2508 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0, 0,0,0,0, 0);
2511 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2512 int width, int height, GfxImageColorMap *colorMap,
2513 int *maskColors, GBool inlineImg)
2515 if(states[statepos].textRender & 4) //clipped
2518 msg("<verbose> drawImage %dx%d, %s, %s, inline=%d", width, height,
2519 colorMap?"colorMap":"no colorMap",
2520 maskColors?"maskColors":"no maskColors",
2523 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2524 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2525 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors, 0,0,0,0, 0);
2528 void SWFOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
2529 int width, int height,
2530 GfxImageColorMap *colorMap,
2531 Stream *maskStr, int maskWidth, int maskHeight,
2534 if(states[statepos].textRender & 4) //clipped
2537 msg("<verbose> drawMaskedImage %dx%d, %s, %dx%d mask", width, height,
2538 colorMap?"colorMap":"no colorMap",
2539 maskWidth, maskHeight);
2541 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2542 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2543 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, maskInvert, 0);
2546 void SWFOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
2547 int width, int height,
2548 GfxImageColorMap *colorMap,
2550 int maskWidth, int maskHeight,
2551 GfxImageColorMap *maskColorMap)
2553 if(states[statepos].textRender & 4) //clipped
2556 msg("<verbose> drawSoftMaskedImage %dx%d, %s, %dx%d mask", width, height,
2557 colorMap?"colorMap":"no colorMap",
2558 maskWidth, maskHeight);
2560 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2561 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2562 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, 0, maskColorMap);
2565 //SWFOutputDev*output = 0;
2567 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2572 if (infoDict->lookup(key, &obj)->isString()) {
2573 s1 = obj.getString();
2574 if ((s1->getChar(0) & 0xff) == 0xfe &&
2575 (s1->getChar(1) & 0xff) == 0xff) {
2577 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2578 if (s1->getChar(i) == '\0') {
2579 s2->append(s1->getChar(i+1));
2582 s2 = new GString("<unicode>");
2586 printf(fmt, s2->getCString());
2589 printf(fmt, s1->getCString());
2595 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2599 if (infoDict->lookup(key, &obj)->isString()) {
2600 s = obj.getString()->getCString();
2601 if (s[0] == 'D' && s[1] == ':') {
2612 void storeDeviceParameter(char*name, char*value)
2614 parameter_t*p = new parameter_t();
2615 p->name = strdup(name);
2616 p->value = strdup(value);
2618 if(device_config_next) {
2619 device_config_next->next = p;
2620 device_config_next = p;
2623 device_config_next = p;
2627 void pdfswf_setparameter(char*name, char*value)
2629 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2630 if(!strcmp(name, "caplinewidth")) {
2631 caplinewidth = atof(value);
2632 } else if(!strcmp(name, "zoom")) {
2635 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2636 storeDeviceParameter("jpegsubpixels", buf);
2637 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2638 storeDeviceParameter("ppmsubpixels", buf);
2639 } else if(!strcmp(name, "jpegdpi")) {
2641 jpeg_dpi = atoi(value);
2642 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2643 storeDeviceParameter("jpegsubpixels", buf);
2644 } else if(!strcmp(name, "ppmdpi")) {
2646 ppm_dpi = atoi(value);
2647 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2648 storeDeviceParameter("ppmsubpixels", buf);
2649 } else if(!strcmp(name, "forceType0Fonts")) {
2650 forceType0Fonts = atoi(value);
2651 } else if(!strncmp(name, "fontdir", strlen("fontdir"))) {
2652 pdfswf_addfontdir(value);
2653 } else if(!strncmp(name, "languagedir", strlen("languagedir"))) {
2654 pdfswf_addlanguagedir(value);
2655 } else if(!strcmp(name, "fontconfig")) {
2656 config_use_fontconfig = atoi(value);
2658 storeDeviceParameter(name,value);
2661 void pdfswf_addfont(char*filename)
2664 memset(&f, 0, sizeof(fontfile_t));
2665 f.filename = filename;
2666 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2667 fonts[fontnum++] = f;
2669 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2673 static char* dirseparator()
2682 void pdfswf_addlanguagedir(char*dir)
2685 globalParams = new GlobalParams("");
2687 msg("<notice> Adding %s to language pack directories", dir);
2691 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc") + 1);
2692 strcpy(config_file, dir);
2693 strcat(config_file, dirseparator());
2694 strcat(config_file, "add-to-xpdfrc");
2696 fi = fopen(config_file, "rb");
2698 msg("<error> Could not open %s", config_file);
2701 globalParams->parseFile(new GString(config_file), fi);
2705 void pdfswf_addfontdir(char*dirname)
2707 #ifdef HAVE_DIRENT_H
2708 msg("<notice> Adding %s to font directories", dirname);
2709 lastfontdir = strdup(dirname);
2710 DIR*dir = opendir(dirname);
2712 msg("<warning> Couldn't open directory %s\n", dirname);
2717 ent = readdir (dir);
2721 char*name = ent->d_name;
2727 if(!strncasecmp(&name[l-4], ".pfa", 4))
2729 if(!strncasecmp(&name[l-4], ".pfb", 4))
2731 if(!strncasecmp(&name[l-4], ".ttf", 4))
2735 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2736 strcpy(fontname, dirname);
2737 strcat(fontname, dirseparator());
2738 strcat(fontname, name);
2739 msg("<verbose> Adding %s to fonts", fontname);
2740 pdfswf_addfont(fontname);
2745 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2750 typedef struct _pdf_doc_internal
2755 } pdf_doc_internal_t;
2756 typedef struct _pdf_page_internal
2758 } pdf_page_internal_t;
2759 typedef struct _dev_output_internal
2761 SWFOutputDev*outputDev;
2762 } dev_output_internal_t;
2764 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2766 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2767 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2768 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2769 memset(i, 0, sizeof(pdf_doc_internal_t));
2770 pdf_doc->internal = i;
2772 GString *fileName = new GString(filename);
2778 globalParams = new GlobalParams("");
2781 if (userPassword && userPassword[0]) {
2782 userPW = new GString(userPassword);
2786 i->doc = new PDFDoc(fileName, userPW);
2790 if (!i->doc->isOk()) {
2795 i->doc->getDocInfo(&info);
2796 if (info.isDict() &&
2797 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2798 printInfoString(info.getDict(), "Title", "Title: %s\n");
2799 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2800 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2801 printInfoString(info.getDict(), "Author", "Author: %s\n");
2802 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2803 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2804 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2805 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2806 printf("Pages: %d\n", i->doc->getNumPages());
2807 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2808 printf("Encrypted: ");
2809 if (i->doc->isEncrypted()) {
2810 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2811 i->doc->okToPrint() ? "yes" : "no",
2812 i->doc->okToCopy() ? "yes" : "no",
2813 i->doc->okToChange() ? "yes" : "no",
2814 i->doc->okToAddNotes() ? "yes" : "no");
2821 pdf_doc->num_pages = i->doc->getNumPages();
2823 if (i->doc->isEncrypted()) {
2824 if(!i->doc->okToCopy()) {
2825 printf("PDF disallows copying.\n");
2828 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2832 InfoOutputDev*io = new InfoOutputDev();
2834 for(t=1;t<=pdf_doc->num_pages;t++) {
2835 i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, /*usemediabox*/true, /*crop*/true, /*doLinks*/(int)1);
2846 delete globalParams;globalParams=0;
2847 Object::memCheck(stderr);
2852 void pdf_destroy(pdf_doc_t*pdf_doc)
2854 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2856 delete i->doc; i->doc=0;
2859 delete i->info;i->info=0;
2862 free(pdf_doc->internal);pdf_doc->internal=0;
2863 free(pdf_doc);pdf_doc=0;
2866 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2868 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2870 if(page < 1 || page > pdf_doc->num_pages)
2873 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2874 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2875 memset(pi, 0, sizeof(pdf_page_internal_t));
2876 pdf_page->internal = pi;
2878 pdf_page->parent = pdf_doc;
2879 pdf_page->nr = page;
2883 void pdf_page_destroy(pdf_page_t*pdf_page)
2885 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2886 free(pdf_page->internal);pdf_page->internal = 0;
2887 free(pdf_page);pdf_page=0;
2890 dev_output_t* dev_output_init(gfxdevice_t*dev)
2892 dev_output_t*dev_output = (dev_output_t*)malloc(sizeof(dev_output_t));
2893 memset(dev_output, 0, sizeof(dev_output_t));
2894 dev_output_internal_t*i= (dev_output_internal_t*)malloc(sizeof(dev_output_internal_t));
2895 memset(i, 0, sizeof(dev_output_internal_t));
2896 dev_output->internal = i;
2898 i->outputDev = new SWFOutputDev(dev);
2902 void dev_output_setparameter(dev_output_t*swf, char*name, char*value)
2904 pdfswf_setparameter(name, value);
2907 void dev_output_startframe(dev_output_t*swf, int width, int height)
2909 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2910 i->outputDev->startFrame(width, height);
2913 void dev_output_endframe(dev_output_t*swf)
2915 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2916 i->outputDev->endframe();
2919 void dev_output_finish(dev_output_t*swf)
2921 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2922 i->outputDev->finish();
2925 void dev_output_preparepage(dev_output_t*swf, int pdfpage, int outputpage)
2927 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2928 SWFOutputDev*o = i->outputDev;
2934 o->pagebuflen = 1024;
2935 o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
2936 memset(o->pages, -1, o->pagebuflen*sizeof(int));
2938 while(pdfpage >= o->pagebuflen)
2940 int oldlen = o->pagebuflen;
2941 o->pagebuflen+=1024;
2942 o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
2943 memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
2946 o->pages[pdfpage] = outputpage;
2947 if(pdfpage>o->pagepos)
2948 o->pagepos = pdfpage;
2951 void dev_output_destroy(dev_output_t*output)
2953 dev_output_internal_t*i = (dev_output_internal_t*)output->internal;
2954 delete i->outputDev; i->outputDev=0;
2955 free(output->internal);output->internal=0;
2959 void pdf_page_render2(pdf_page_t*page, dev_output_t*swf)
2961 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2962 dev_output_internal_t*si = (dev_output_internal_t*)swf->internal;
2965 msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2970 gfxdevice_t*dev = si->outputDev->output;
2971 dev->setparameter(dev, "protect", "1");
2973 si->outputDev->setInfo(pi->info);
2974 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2975 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
2978 void pdf_page_rendersection(pdf_page_t*page, dev_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2980 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2981 dev_output_internal_t*si = (dev_output_internal_t*)output->internal;
2983 si->outputDev->setMove(x,y);
2984 if((x1|y1|x2|y2)==0) x2++;
2985 si->outputDev->setClip(x1,y1,x2,y2);
2987 pdf_page_render2(page, output);
2989 void pdf_page_render(pdf_page_t*page, dev_output_t*output)
2991 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2992 dev_output_internal_t*si = (dev_output_internal_t*)output->internal;
2994 si->outputDev->setMove(0,0);
2995 si->outputDev->setClip(0,0,0,0);
2997 pdf_page_render2(page, output);
3001 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
3003 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
3004 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
3005 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
3006 memset(info, 0, sizeof(pdf_page_info_t));
3008 InfoOutputDev*output = new InfoOutputDev;
3010 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
3012 info->xMin = output->x1;
3013 info->yMin = output->y1;
3014 info->xMax = output->x2;
3015 info->yMax = output->y2;
3016 info->number_of_images = output->num_images;
3017 info->number_of_links = output->num_links;
3018 info->number_of_fonts = output->num_fonts;
3025 void pdf_page_info_destroy(pdf_page_info_t*info)