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;
2315 imgStr = new ImageStream(str, width, ncomps,bits);
2318 if(!width || !height || (height<=1 && width<=1))
2320 msg("<verbose> Ignoring %d by %d image", width, height);
2321 unsigned char buf[8];
2323 for (y = 0; y < height; ++y)
2324 for (x = 0; x < width; ++x) {
2325 imgStr->getPixel(buf);
2333 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1 += user_movey;
2334 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2 += user_movey;
2335 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3 += user_movey;
2336 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4 += user_movey;
2338 if(!pbminfo && !(str->getKind()==strDCT)) {
2340 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2344 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2346 if(!jpeginfo && (str->getKind()==strDCT)) {
2347 msg("<notice> file contains jpeg pictures");
2353 unsigned char buf[8];
2355 unsigned char*pic = new unsigned char[width*height];
2356 gfxcolor_t pal[256];
2358 state->getFillRGB(&rgb);
2360 memset(pal,255,sizeof(pal));
2361 pal[0].r = (int)(colToByte(rgb.r)); pal[1].r = 0;
2362 pal[0].g = (int)(colToByte(rgb.g)); pal[1].g = 0;
2363 pal[0].b = (int)(colToByte(rgb.b)); pal[1].b = 0;
2364 pal[0].a = 255; pal[1].a = 0;
2367 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2368 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2369 for (y = 0; y < height; ++y)
2370 for (x = 0; x < width; ++x)
2372 imgStr->getPixel(buf);
2375 pic[width*y+x] = buf[0];
2378 /* the size of the drawn image is added to the identifier
2379 as the same image may require different bitmaps if displayed
2380 at different sizes (due to antialiasing): */
2383 unsigned char*pic2 = 0;
2386 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2395 height = realheight;
2399 /* make a black/white palette */
2401 float r = 255/(numpalette-1);
2403 for(t=0;t<numpalette;t++) {
2404 pal[t].r = colToByte(rgb.r);
2405 pal[t].g = colToByte(rgb.g);
2406 pal[t].b = colToByte(rgb.b);
2407 pal[t].a = (unsigned char)(t*r);
2411 gfxcolor_t*pic2 = new gfxcolor_t[width*height];
2412 for (y = 0; y < height; ++y) {
2413 for (x = 0; x < width; ++x) {
2414 pic2[width*y+x] = pal[pic[y*width+x]];
2417 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2421 if(maskbitmap) free(maskbitmap);
2427 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2428 gfxcolor_t*pic=new gfxcolor_t[width*height];
2429 for (y = 0; y < height; ++y) {
2430 for (x = 0; x < width; ++x) {
2431 imgStr->getPixel(pixBuf);
2432 colorMap->getRGB(pixBuf, &rgb);
2433 pic[width*y+x].r = (unsigned char)(colToByte(rgb.r));
2434 pic[width*y+x].g = (unsigned char)(colToByte(rgb.g));
2435 pic[width*y+x].b = (unsigned char)(colToByte(rgb.b));
2436 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2438 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2442 if(str->getKind()==strDCT)
2443 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2445 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2448 if(maskbitmap) free(maskbitmap);
2451 gfxcolor_t*pic=new gfxcolor_t[width*height];
2452 gfxcolor_t pal[256];
2453 int n = 1 << colorMap->getBits();
2455 for(t=0;t<256;t++) {
2457 colorMap->getRGB(pixBuf, &rgb);
2459 {/*if(maskColors && *maskColors==t) {
2460 msg("<notice> Color %d is transparent", t);
2461 if (imgData->maskColors) {
2463 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2464 if (pix[i] < imgData->maskColors[2*i] ||
2465 pix[i] > imgData->maskColors[2*i+1]) {
2480 pal[t].r = (unsigned char)(colToByte(rgb.r));
2481 pal[t].g = (unsigned char)(colToByte(rgb.g));
2482 pal[t].b = (unsigned char)(colToByte(rgb.b));
2483 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2486 for (y = 0; y < height; ++y) {
2487 for (x = 0; x < width; ++x) {
2488 imgStr->getPixel(pixBuf);
2489 pic[width*y+x] = pal[pixBuf[0]];
2491 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2495 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2499 if(maskbitmap) free(maskbitmap);
2504 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2505 int width, int height, GBool invert,
2508 if(states[statepos].textRender & 4) //clipped
2510 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2511 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0, 0,0,0,0, 0);
2514 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2515 int width, int height, GfxImageColorMap *colorMap,
2516 int *maskColors, GBool inlineImg)
2518 if(states[statepos].textRender & 4) //clipped
2521 msg("<verbose> drawImage %dx%d, %s, %s, inline=%d", width, height,
2522 colorMap?"colorMap":"no colorMap",
2523 maskColors?"maskColors":"no maskColors",
2526 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2527 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2528 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors, 0,0,0,0, 0);
2531 void SWFOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
2532 int width, int height,
2533 GfxImageColorMap *colorMap,
2534 Stream *maskStr, int maskWidth, int maskHeight,
2537 if(states[statepos].textRender & 4) //clipped
2540 msg("<verbose> drawMaskedImage %dx%d, %s, %dx%d mask", width, height,
2541 colorMap?"colorMap":"no colorMap",
2542 maskWidth, maskHeight);
2544 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2545 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2546 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, maskInvert, 0);
2549 void SWFOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
2550 int width, int height,
2551 GfxImageColorMap *colorMap,
2553 int maskWidth, int maskHeight,
2554 GfxImageColorMap *maskColorMap)
2556 if(states[statepos].textRender & 4) //clipped
2559 msg("<verbose> drawSoftMaskedImage %dx%d, %s, %dx%d mask", width, height,
2560 colorMap?"colorMap":"no colorMap",
2561 maskWidth, maskHeight);
2563 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2564 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2565 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, 0, maskColorMap);
2568 //SWFOutputDev*output = 0;
2570 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2575 if (infoDict->lookup(key, &obj)->isString()) {
2576 s1 = obj.getString();
2577 if ((s1->getChar(0) & 0xff) == 0xfe &&
2578 (s1->getChar(1) & 0xff) == 0xff) {
2580 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2581 if (s1->getChar(i) == '\0') {
2582 s2->append(s1->getChar(i+1));
2585 s2 = new GString("<unicode>");
2589 printf(fmt, s2->getCString());
2592 printf(fmt, s1->getCString());
2598 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2602 if (infoDict->lookup(key, &obj)->isString()) {
2603 s = obj.getString()->getCString();
2604 if (s[0] == 'D' && s[1] == ':') {
2615 void storeDeviceParameter(char*name, char*value)
2617 parameter_t*p = new parameter_t();
2618 p->name = strdup(name);
2619 p->value = strdup(value);
2621 if(device_config_next) {
2622 device_config_next->next = p;
2623 device_config_next = p;
2626 device_config_next = p;
2630 void pdfswf_setparameter(char*name, char*value)
2632 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2633 if(!strcmp(name, "caplinewidth")) {
2634 caplinewidth = atof(value);
2635 } else if(!strcmp(name, "zoom")) {
2638 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2639 storeDeviceParameter("jpegsubpixels", buf);
2640 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2641 storeDeviceParameter("ppmsubpixels", buf);
2642 } else if(!strcmp(name, "jpegdpi")) {
2644 jpeg_dpi = atoi(value);
2645 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2646 storeDeviceParameter("jpegsubpixels", buf);
2647 } else if(!strcmp(name, "ppmdpi")) {
2649 ppm_dpi = atoi(value);
2650 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2651 storeDeviceParameter("ppmsubpixels", buf);
2652 } else if(!strcmp(name, "forceType0Fonts")) {
2653 forceType0Fonts = atoi(value);
2654 } else if(!strncmp(name, "fontdir", strlen("fontdir"))) {
2655 pdfswf_addfontdir(value);
2656 } else if(!strncmp(name, "languagedir", strlen("languagedir"))) {
2657 pdfswf_addlanguagedir(value);
2658 } else if(!strcmp(name, "fontconfig")) {
2659 config_use_fontconfig = atoi(value);
2661 storeDeviceParameter(name,value);
2664 void pdfswf_addfont(char*filename)
2667 memset(&f, 0, sizeof(fontfile_t));
2668 f.filename = filename;
2669 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2670 fonts[fontnum++] = f;
2672 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2676 static char* dirseparator()
2685 void pdfswf_addlanguagedir(char*dir)
2688 globalParams = new GlobalParams("");
2690 msg("<notice> Adding %s to language pack directories", dir);
2694 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc") + 1);
2695 strcpy(config_file, dir);
2696 strcat(config_file, dirseparator());
2697 strcat(config_file, "add-to-xpdfrc");
2699 fi = fopen(config_file, "rb");
2701 msg("<error> Could not open %s", config_file);
2704 globalParams->parseFile(new GString(config_file), fi);
2708 void pdfswf_addfontdir(char*dirname)
2710 #ifdef HAVE_DIRENT_H
2711 msg("<notice> Adding %s to font directories", dirname);
2712 lastfontdir = strdup(dirname);
2713 DIR*dir = opendir(dirname);
2715 msg("<warning> Couldn't open directory %s\n", dirname);
2720 ent = readdir (dir);
2724 char*name = ent->d_name;
2730 if(!strncasecmp(&name[l-4], ".pfa", 4))
2732 if(!strncasecmp(&name[l-4], ".pfb", 4))
2734 if(!strncasecmp(&name[l-4], ".ttf", 4))
2738 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2739 strcpy(fontname, dirname);
2740 strcat(fontname, dirseparator());
2741 strcat(fontname, name);
2742 msg("<verbose> Adding %s to fonts", fontname);
2743 pdfswf_addfont(fontname);
2748 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2753 typedef struct _pdf_doc_internal
2758 } pdf_doc_internal_t;
2759 typedef struct _pdf_page_internal
2761 } pdf_page_internal_t;
2762 typedef struct _dev_output_internal
2764 SWFOutputDev*outputDev;
2765 } dev_output_internal_t;
2767 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2769 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2770 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2771 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2772 memset(i, 0, sizeof(pdf_doc_internal_t));
2773 pdf_doc->internal = i;
2775 GString *fileName = new GString(filename);
2781 globalParams = new GlobalParams("");
2784 if (userPassword && userPassword[0]) {
2785 userPW = new GString(userPassword);
2789 i->doc = new PDFDoc(fileName, userPW);
2793 if (!i->doc->isOk()) {
2798 i->doc->getDocInfo(&info);
2799 if (info.isDict() &&
2800 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2801 printInfoString(info.getDict(), "Title", "Title: %s\n");
2802 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2803 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2804 printInfoString(info.getDict(), "Author", "Author: %s\n");
2805 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2806 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2807 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2808 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2809 printf("Pages: %d\n", i->doc->getNumPages());
2810 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2811 printf("Encrypted: ");
2812 if (i->doc->isEncrypted()) {
2813 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2814 i->doc->okToPrint() ? "yes" : "no",
2815 i->doc->okToCopy() ? "yes" : "no",
2816 i->doc->okToChange() ? "yes" : "no",
2817 i->doc->okToAddNotes() ? "yes" : "no");
2824 pdf_doc->num_pages = i->doc->getNumPages();
2826 if (i->doc->isEncrypted()) {
2827 if(!i->doc->okToCopy()) {
2828 printf("PDF disallows copying.\n");
2831 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2835 InfoOutputDev*io = new InfoOutputDev();
2837 for(t=1;t<=pdf_doc->num_pages;t++) {
2838 i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, /*usemediabox*/true, /*crop*/true, /*doLinks*/(int)1);
2849 delete globalParams;globalParams=0;
2850 Object::memCheck(stderr);
2855 void pdf_destroy(pdf_doc_t*pdf_doc)
2857 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2859 delete i->doc; i->doc=0;
2862 delete i->info;i->info=0;
2865 free(pdf_doc->internal);pdf_doc->internal=0;
2866 free(pdf_doc);pdf_doc=0;
2869 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2871 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2873 if(page < 1 || page > pdf_doc->num_pages)
2876 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2877 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2878 memset(pi, 0, sizeof(pdf_page_internal_t));
2879 pdf_page->internal = pi;
2881 pdf_page->parent = pdf_doc;
2882 pdf_page->nr = page;
2886 void pdf_page_destroy(pdf_page_t*pdf_page)
2888 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2889 free(pdf_page->internal);pdf_page->internal = 0;
2890 free(pdf_page);pdf_page=0;
2893 dev_output_t* dev_output_init(gfxdevice_t*dev)
2895 dev_output_t*dev_output = (dev_output_t*)malloc(sizeof(dev_output_t));
2896 memset(dev_output, 0, sizeof(dev_output_t));
2897 dev_output_internal_t*i= (dev_output_internal_t*)malloc(sizeof(dev_output_internal_t));
2898 memset(i, 0, sizeof(dev_output_internal_t));
2899 dev_output->internal = i;
2901 i->outputDev = new SWFOutputDev(dev);
2905 void dev_output_setparameter(dev_output_t*swf, char*name, char*value)
2907 pdfswf_setparameter(name, value);
2910 void dev_output_startframe(dev_output_t*swf, int width, int height)
2912 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2913 i->outputDev->startFrame(width, height);
2916 void dev_output_endframe(dev_output_t*swf)
2918 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2919 i->outputDev->endframe();
2922 void dev_output_finish(dev_output_t*swf)
2924 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2925 i->outputDev->finish();
2928 void dev_output_preparepage(dev_output_t*swf, int pdfpage, int outputpage)
2930 dev_output_internal_t*i= (dev_output_internal_t*)swf->internal;
2931 SWFOutputDev*o = i->outputDev;
2937 o->pagebuflen = 1024;
2938 o->pages = (int*)malloc(o->pagebuflen*sizeof(int));
2939 memset(o->pages, -1, o->pagebuflen*sizeof(int));
2941 while(pdfpage >= o->pagebuflen)
2943 int oldlen = o->pagebuflen;
2944 o->pagebuflen+=1024;
2945 o->pages = (int*)realloc(o->pages, o->pagebuflen*sizeof(int));
2946 memset(&o->pages[oldlen], -1, (o->pagebuflen-oldlen)*sizeof(int));
2949 o->pages[pdfpage] = outputpage;
2950 if(pdfpage>o->pagepos)
2951 o->pagepos = pdfpage;
2954 void dev_output_destroy(dev_output_t*output)
2956 dev_output_internal_t*i = (dev_output_internal_t*)output->internal;
2957 delete i->outputDev; i->outputDev=0;
2958 free(output->internal);output->internal=0;
2962 void pdf_page_render2(pdf_page_t*page, dev_output_t*swf)
2964 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2965 dev_output_internal_t*si = (dev_output_internal_t*)swf->internal;
2968 msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
2973 gfxdevice_t*dev = si->outputDev->output;
2974 dev->setparameter(dev, "protect", "1");
2976 si->outputDev->setInfo(pi->info);
2977 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2978 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
2981 void pdf_page_rendersection(pdf_page_t*page, dev_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2983 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2984 dev_output_internal_t*si = (dev_output_internal_t*)output->internal;
2986 si->outputDev->setMove(x,y);
2987 if((x1|y1|x2|y2)==0) x2++;
2988 si->outputDev->setClip(x1,y1,x2,y2);
2990 pdf_page_render2(page, output);
2992 void pdf_page_render(pdf_page_t*page, dev_output_t*output)
2994 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2995 dev_output_internal_t*si = (dev_output_internal_t*)output->internal;
2997 si->outputDev->setMove(0,0);
2998 si->outputDev->setClip(0,0,0,0);
3000 pdf_page_render2(page, output);
3004 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
3006 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
3007 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
3008 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
3009 memset(info, 0, sizeof(pdf_page_info_t));
3011 InfoOutputDev*output = new InfoOutputDev;
3013 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
3015 info->xMin = output->x1;
3016 info->yMin = output->y1;
3017 info->xMax = output->x2;
3018 info->yMax = output->y2;
3019 info->number_of_images = output->num_images;
3020 info->number_of_links = output->num_links;
3021 info->number_of_fonts = output->num_fonts;
3028 void pdf_page_info_destroy(pdf_page_info_t*info)