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>
49 #include "OutputDev.h"
52 #include "CharCodeToUnicode.h"
53 #include "NameToUnicodeTable.h"
54 #include "GlobalParams.h"
59 #include "FoFiType1C.h"
60 #include "FoFiTrueType.h"
62 #include "SWFOutputDev.h"
64 //swftools header files
65 #include "swfoutput.h"
66 #include "../lib/log.h"
67 #include "../lib/gfxdevice.h"
68 #include "../lib/gfxtools.h"
69 #include "../lib/gfxfont.h"
73 typedef struct _fontfile
79 typedef struct _parameter
83 struct _parameter*next;
86 static parameter_t* device_config = 0;
87 static parameter_t* device_config_next = 0;
90 static fontfile_t fonts[2048];
91 static int fontnum = 0;
93 static int config_use_fontconfig = 1;
96 // TODO: move into pdf_doc_t
98 static int pagebuflen = 0;
99 static int pagepos = 0;
102 static double caplinewidth = 3.0;
103 static double zoom = 72; /* xpdf: 86 */
104 static int forceType0Fonts = 1;
106 static void printInfoString(Dict *infoDict, char *key, char *fmt);
107 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
113 {"Times-Roman", "n021003l"},
114 {"Times-Italic", "n021023l"},
115 {"Times-Bold", "n021004l"},
116 {"Times-BoldItalic", "n021024l"},
117 {"Helvetica", "n019003l"},
118 {"Helvetica-Oblique", "n019023l"},
119 {"Helvetica-Bold", "n019004l"},
120 {"Helvetica-BoldOblique", "n019024l"},
121 {"Courier", "n022003l"},
122 {"Courier-Oblique", "n022023l"},
123 {"Courier-Bold", "n022004l"},
124 {"Courier-BoldOblique", "n022024l"},
125 {"Symbol", "s050000l"},
126 {"ZapfDingbats", "d050000l"}};
128 class SWFOutputState {
134 this->textRender = 0;
138 typedef struct _fontlist
146 class SWFOutputDev: public OutputDev {
154 virtual ~SWFOutputDev() ;
156 void setMove(int x,int y);
157 void setClip(int x1,int y1,int x2,int y2);
159 int save(char*filename);
163 void getDimensions(int*x1,int*y1,int*x2,int*y2);
165 //----- get info about output device
167 // Does this device use upside-down coordinates?
168 // (Upside-down means (0,0) is the top left corner of the page.)
169 virtual GBool upsideDown();
171 // Does this device use drawChar() or drawString()?
172 virtual GBool useDrawChar();
174 // Can this device draw gradients?
175 virtual GBool useGradients();
177 virtual GBool interpretType3Chars() {return gTrue;}
179 //----- initialization and control
181 void setXRef(PDFDoc*doc, XRef *xref);
184 virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
187 virtual void drawLink(Link *link, Catalog *catalog) ;
189 //----- save/restore graphics state
190 virtual void saveState(GfxState *state) ;
191 virtual void restoreState(GfxState *state) ;
193 //----- update graphics state
195 virtual void updateFont(GfxState *state);
196 virtual void updateFillColor(GfxState *state);
197 virtual void updateStrokeColor(GfxState *state);
198 virtual void updateLineWidth(GfxState *state);
199 virtual void updateLineJoin(GfxState *state);
200 virtual void updateLineCap(GfxState *state);
202 virtual void updateAll(GfxState *state)
205 updateFillColor(state);
206 updateStrokeColor(state);
207 updateLineWidth(state);
208 updateLineJoin(state);
209 updateLineCap(state);
212 //----- path painting
213 virtual void stroke(GfxState *state) ;
214 virtual void fill(GfxState *state) ;
215 virtual void eoFill(GfxState *state) ;
217 //----- path clipping
218 virtual void clip(GfxState *state) ;
219 virtual void eoClip(GfxState *state) ;
222 virtual void beginString(GfxState *state, GString *s) ;
223 virtual void endString(GfxState *state) ;
224 virtual void endTextObject(GfxState *state);
225 virtual void drawChar(GfxState *state, double x, double y,
226 double dx, double dy,
227 double originX, double originY,
228 CharCode code, Unicode *u, int uLen);
230 //----- image drawing
231 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
232 int width, int height, GBool invert,
234 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
235 int width, int height, GfxImageColorMap *colorMap,
236 int *maskColors, GBool inlineImg);
238 virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
239 virtual void endType3Char(GfxState *state);
241 virtual void type3D0(GfxState *state, double wx, double wy);
242 virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
245 void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
246 int width, int height, GfxImageColorMap*colorMap, GBool invert,
247 GBool inlineImg, int mask, int *maskColors);
248 int SWFOutputDev::setGfxFont(char*id, char*filename);
249 void strokeGfxline(GfxState *state, gfxline_t*line);
250 void clipToGfxLine(GfxState *state, gfxline_t*line);
251 void fillGfxLine(GfxState *state, gfxline_t*line);
255 gfxresult_t*result; //filled when complete
257 char outer_clip_box; //whether the page clip box is still on
259 SWFOutputState states[64];
267 char* searchFont(char*name);
268 char* substituteFont(GfxFont*gfxFont, char*oldname);
269 char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
271 int jpeginfo; // did we write "File contains jpegs" yet?
272 int pbminfo; // did we write "File contains jpegs" yet?
273 int linkinfo; // did we write "File contains links" yet?
274 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
275 int gradientinfo; // did we write "File contains Gradients yet?
277 int type3active; // are we between beginType3()/endType3()?
283 char* substitutetarget[256];
284 char* substitutesource[256];
287 int user_movex,user_movey;
288 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
290 gfxline_t* current_text_stroke;
291 gfxline_t* current_text_clip;
292 char* current_font_id;
293 gfxfont_t* current_gfxfont;
294 gfxmatrix_t current_font_matrix;
296 fontlist_t* fontlist;
299 static char*getFontID(GfxFont*font);
301 class InfoOutputDev: public OutputDev
315 virtual ~InfoOutputDev()
318 virtual GBool upsideDown() {return gTrue;}
319 virtual GBool useDrawChar() {return gTrue;}
320 virtual GBool useGradients() {return gTrue;}
321 virtual GBool interpretType3Chars() {return gTrue;}
322 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
325 state->transform(crop_x1,crop_y1,&x1,&y1);
326 state->transform(crop_x2,crop_y2,&x2,&y2);
327 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
328 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
334 virtual void drawLink(Link *link, Catalog *catalog)
338 virtual void updateFont(GfxState *state)
340 GfxFont*font = state->getFont();
343 /*char*id = getFontID(font);*/
347 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
348 int width, int height, GBool invert,
353 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
354 int width, int height, GfxImageColorMap *colorMap,
355 int *maskColors, GBool inlineImg)
361 SWFOutputDev::SWFOutputDev()
378 current_text_stroke = 0;
379 current_text_clip = 0;
383 output = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
384 gfxdevice_swf_init(output);
385 /* configure device */
386 parameter_t*p = device_config;
388 output->setparameter(output, p->name, p->value);
393 void SWFOutputDev::setMove(int x,int y)
395 this->user_movex = x;
396 this->user_movey = y;
399 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
401 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
402 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
404 this->user_clipx1 = x1;
405 this->user_clipy1 = y1;
406 this->user_clipx2 = x2;
407 this->user_clipy2 = y2;
410 void SWFOutputDev::getDimensions(int*x1,int*y1,int*x2,int*y2)
413 *x1 = (int)result->get(result, "xmin");
414 *y1 = (int)result->get(result, "ymin");
415 *x2 = (int)result->get(result, "xmax");
416 *y2 = (int)result->get(result, "ymax");
418 *x1 = *y1 = *x2 = *y2 = 0;
422 static char*getFontID(GfxFont*font)
424 GString*gstr = font->getName();
425 char* fontname = gstr==0?0:gstr->getCString();
429 sprintf(buf, "UFONT%d", r->num);
432 return strdup(fontname);
435 static char*getFontName(GfxFont*font)
437 char*fontid = getFontID(font);
439 char* plus = strchr(fontid, '+');
440 if(plus && plus < &fontid[strlen(fontid)-1]) {
441 fontname = strdup(plus+1);
443 fontname = strdup(fontid);
449 static char mybuf[1024];
450 static char* gfxstate2str(GfxState *state)
454 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
461 if(state->getX1()!=0.0)
462 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
463 if(state->getY1()!=0.0)
464 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
465 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
466 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
467 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
468 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
469 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
470 state->getFillColor()->c[0], state->getFillColor()->c[1]);
471 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
472 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
473 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
474 state->getFillColor()->c[0], state->getFillColor()->c[1],
475 state->getFillColor()->c[2], state->getFillColor()->c[3],
476 state->getFillColor()->c[4], state->getFillColor()->c[5],
477 state->getFillColor()->c[6], state->getFillColor()->c[7]);
478 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
479 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
480 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
481 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
482 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
483 state->getFillRGB(&rgb);
484 if(rgb.r || rgb.g || rgb.b)
485 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
486 state->getStrokeRGB(&rgb);
487 if(rgb.r || rgb.g || rgb.b)
488 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
489 if(state->getFillColorSpace()->getNComps()>1)
490 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
491 if(state->getStrokeColorSpace()->getNComps()>1)
492 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
493 if(state->getFillPattern())
494 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
495 if(state->getStrokePattern())
496 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
498 if(state->getFillOpacity()!=1.0)
499 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
500 if(state->getStrokeOpacity()!=1.0)
501 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
503 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
508 state->getLineDash(&dash, &length, &start);
512 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
513 for(t=0;t<length;t++) {
514 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
516 bufpos+=sprintf(bufpos,"]");
519 if(state->getFlatness()!=1)
520 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
521 if(state->getLineJoin()!=0)
522 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
523 if(state->getLineJoin()!=0)
524 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
525 if(state->getLineJoin()!=0)
526 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
528 if(state->getFont() && getFontID(state->getFont()))
529 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
530 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
531 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
532 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
533 if(state->getCharSpace())
534 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
535 if(state->getWordSpace())
536 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
537 if(state->getHorizScaling()!=1.0)
538 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
539 if(state->getLeading())
540 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
542 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
543 if(state->getRender())
544 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
545 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
546 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
547 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
548 if(state->getLineX())
549 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
550 if(state->getLineY())
551 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
552 bufpos+=sprintf(bufpos," ");
556 static void dumpFontInfo(char*loglevel, GfxFont*font);
557 static int lastdumps[1024];
558 static int lastdumppos = 0;
563 static void showFontError(GfxFont*font, int nr)
567 for(t=0;t<lastdumppos;t++)
568 if(lastdumps[t] == r->num)
572 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
573 lastdumps[lastdumppos++] = r->num;
575 msg("<warning> The following font caused problems:");
577 msg("<warning> The following font caused problems (substituting):");
579 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
580 dumpFontInfo("<warning>", font);
583 static void dumpFontInfo(char*loglevel, GfxFont*font)
585 char* id = getFontID(font);
586 char* name = getFontName(font);
587 Ref* r=font->getID();
588 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
590 GString*gstr = font->getTag();
592 msg("%s| Tag: %s\n", loglevel, id);
594 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
596 GfxFontType type=font->getType();
598 case fontUnknownType:
599 msg("%s| Type: unknown\n",loglevel);
602 msg("%s| Type: 1\n",loglevel);
605 msg("%s| Type: 1C\n",loglevel);
608 msg("%s| Type: 3\n",loglevel);
611 msg("%s| Type: TrueType\n",loglevel);
614 msg("%s| Type: CIDType0\n",loglevel);
617 msg("%s| Type: CIDType0C\n",loglevel);
620 msg("%s| Type: CIDType2\n",loglevel);
625 GBool embedded = font->getEmbeddedFontID(&embRef);
627 if(font->getEmbeddedFontName()) {
628 embeddedName = font->getEmbeddedFontName()->getCString();
631 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
633 gstr = font->getExtFontFile();
635 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
637 // Get font descriptor flags.
638 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
639 if(font->isSerif()) msg("%s| is serif\n", loglevel);
640 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
641 if(font->isItalic()) msg("%s| is italic\n", loglevel);
642 if(font->isBold()) msg("%s| is bold\n", loglevel);
648 //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");}
649 //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");}
652 void dump_outline(gfxline_t*line)
655 if(line->type == gfx_moveTo) {
656 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
657 } else if(line->type == gfx_lineTo) {
658 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
659 } else if(line->type == gfx_splineTo) {
660 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
666 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey)
668 int num = path->getNumSubpaths();
671 double lastx=0,lasty=0,posx=0,posy=0;
674 msg("<warning> empty path");
678 gfxdrawer_target_gfxline(&draw);
680 for(t = 0; t < num; t++) {
681 GfxSubpath *subpath = path->getSubpath(t);
682 int subnum = subpath->getNumPoints();
683 double bx=0,by=0,cx=0,cy=0;
685 for(s=0;s<subnum;s++) {
688 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
693 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
694 draw.lineTo(&draw, lastx, lasty);
696 draw.moveTo(&draw, x,y);
701 } else if(subpath->getCurve(s) && cpos==0) {
705 } else if(subpath->getCurve(s) && cpos==1) {
713 draw.lineTo(&draw, x,y);
715 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y);
722 /* fix non-closed lines */
723 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
724 draw.lineTo(&draw, lastx, lasty);
726 gfxline_t*result = (gfxline_t*)draw.result(&draw);
730 /*----------------------------------------------------------------------------
731 * Primitive Graphic routines
732 *----------------------------------------------------------------------------*/
734 void SWFOutputDev::stroke(GfxState *state)
736 GfxPath * path = state->getPath();
737 gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex, user_movey);
738 strokeGfxline(state, line);
742 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
744 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
745 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
746 double miterLimit = state->getMiterLimit();
747 double width = state->getTransformedLineWidth();
750 double opaq = state->getStrokeOpacity();
752 state->getFillRGB(&rgb);
754 state->getStrokeRGB(&rgb);
756 col.r = (unsigned char)(rgb.r*255);
757 col.g = (unsigned char)(rgb.g*255);
758 col.b = (unsigned char)(rgb.b*255);
759 col.a = (unsigned char)(opaq*255);
761 gfx_capType capType = gfx_capRound;
762 if(lineCap == 0) capType = gfx_capButt;
763 else if(lineCap == 1) capType = gfx_capRound;
764 else if(lineCap == 2) capType = gfx_capSquare;
766 gfx_joinType joinType = gfx_joinRound;
767 if(lineJoin == 0) joinType = gfx_joinMiter;
768 else if(lineJoin == 1) joinType = gfx_joinRound;
769 else if(lineJoin == 2) joinType = gfx_joinBevel;
772 double dashphase = 0;
774 state->getLineDash(&ldash, &dashnum, &dashphase);
778 if(dashnum && ldash) {
779 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
783 msg("<trace> %d dashes", dashnum);
784 msg("<trace> | phase: %f", dashphase);
785 for(t=0;t<dashnum;t++) {
787 msg("<trace> | d%-3d: %f", t, ldash[t]);
790 if(getLogLevel() >= LOGLEVEL_TRACE) {
794 line2 = gfxtool_dash_line(line, dash, dashphase);
797 msg("<trace> After dashing:");
800 if(getLogLevel() >= LOGLEVEL_TRACE) {
802 state->getStrokeGray(&gray);
803 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n",
805 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
806 lineCap==0?"butt": (lineJoin==1?"round":"square"),
808 col.r,col.g,col.b,col.a,
814 //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
815 output->stroke(output, line, width, &col, capType, joinType, miterLimit);
821 gfxcolor_t getFillColor(GfxState * state)
824 double opaq = state->getFillOpacity();
825 state->getFillRGB(&rgb);
827 col.r = (unsigned char)(rgb.r*255);
828 col.g = (unsigned char)(rgb.g*255);
829 col.b = (unsigned char)(rgb.b*255);
830 col.a = (unsigned char)(opaq*255);
834 void SWFOutputDev::fillGfxLine(GfxState *state, gfxline_t*line)
836 gfxcolor_t col = getFillColor(state);
838 if(getLogLevel() >= LOGLEVEL_TRACE) {
839 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
842 output->fill(output, line, &col);
844 void SWFOutputDev::fill(GfxState *state)
846 GfxPath * path = state->getPath();
847 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
848 fillGfxLine(state, line);
851 void SWFOutputDev::eoFill(GfxState *state)
853 GfxPath * path = state->getPath();
854 gfxcolor_t col = getFillColor(state);
856 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
858 if(getLogLevel() >= LOGLEVEL_TRACE) {
859 msg("<trace> eofill\n");
863 output->fill(output, line, &col);
867 void SWFOutputDev::clip(GfxState *state)
869 GfxPath * path = state->getPath();
870 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
871 clipToGfxLine(state, line);
875 void SWFOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line)
877 if(getLogLevel() >= LOGLEVEL_TRACE) {
878 msg("<trace> clip\n");
882 output->startclip(output, line);
883 states[statepos].clipping++;
885 void SWFOutputDev::eoClip(GfxState *state)
887 GfxPath * path = state->getPath();
888 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
890 if(getLogLevel() >= LOGLEVEL_TRACE) {
891 msg("<trace> eoclip\n");
895 output->startclip(output, line);
896 states[statepos].clipping++;
900 void SWFOutputDev::pagefeed()
903 output->endclip(output);
907 swfoutput_pagefeed(output);
910 void SWFOutputDev::finish()
914 output->endclip(output);
919 this->result = output->finish(output);
920 free(output);output=0;
924 int SWFOutputDev::save(char*filename)
927 return result->save(result, filename);
929 void* SWFOutputDev::getSWF()
932 return result->get(result, "swf");
935 SWFOutputDev::~SWFOutputDev()
940 this->result->destroy(this->result);
944 fontlist_t*l = this->fontlist;
946 fontlist_t*next = l->next;
948 gfxfont_free(l->font);
956 GBool SWFOutputDev::upsideDown()
960 GBool SWFOutputDev::useDrawChar()
964 GBool SWFOutputDev::useGradients()
968 msg("<notice> File contains gradients");
974 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
975 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
977 #define RENDER_FILL 0
978 #define RENDER_STROKE 1
979 #define RENDER_FILLSTROKE 2
980 #define RENDER_INVISIBLE 3
981 #define RENDER_CLIP 4
983 static char tmp_printstr[4096];
984 char* makeStringPrintable(char*str)
986 int len = strlen(str);
1001 tmp_printstr[len++] = '.';
1002 tmp_printstr[len++] = '.';
1003 tmp_printstr[len++] = '.';
1005 tmp_printstr[len] = 0;
1006 return tmp_printstr;
1010 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
1014 for(t=0;t<font->num_glyphs;t++) {
1015 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
1016 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1020 /* if we didn't find the character, maybe
1021 we can find the capitalized version */
1022 for(t=0;t<font->num_glyphs;t++) {
1023 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
1024 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1030 /* try to use the unicode id */
1031 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
1032 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
1033 return font->unicode2glyph[u];
1036 if(charnr>=0 && charnr<font->num_glyphs) {
1037 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1045 void SWFOutputDev::beginString(GfxState *state, GString *s)
1047 int render = state->getRender();
1048 if(current_text_stroke) {
1049 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
1052 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
1053 double m11,m21,m12,m22;
1054 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
1055 state->getFontTransMat(&m11, &m12, &m21, &m22);
1056 m11 *= state->getHorizScaling();
1057 m21 *= state->getHorizScaling();
1059 this->current_font_matrix.m00 = m11 / 1024.0;
1060 this->current_font_matrix.m01 = m12 / 1024.0;
1061 this->current_font_matrix.m10 = -m21 / 1024.0;
1062 this->current_font_matrix.m11 = -m22 / 1024.0;
1063 this->current_font_matrix.tx = 0;
1064 this->current_font_matrix.ty = 0;
1066 gfxmatrix_t m = this->current_font_matrix;
1068 /*if(render != 3 && render != 0)
1069 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1070 states[statepos].textRender = render;
1073 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1074 double dx, double dy,
1075 double originX, double originY,
1076 CharCode c, Unicode *_u, int uLen)
1078 int render = state->getRender();
1079 // check for invisible text -- this is used by Acrobat Capture
1083 if(states[statepos].textRender != render)
1084 msg("<error> Internal error: drawChar.render!=beginString.render");
1086 gfxcolor_t col = getFillColor(state);
1088 Gushort *CIDToGIDMap = 0;
1089 GfxFont*font = state->getFont();
1091 if(font->getType() == fontType3) {
1092 /* type 3 chars are passed as graphics */
1093 msg("<debug> type3 char at %f/%f", x, y);
1104 /* find out char name from unicode index
1105 TODO: should be precomputed
1107 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1108 if(nameToUnicodeTab[t].u == u) {
1109 name = nameToUnicodeTab[t].name;
1116 if(font->isCIDFont()) {
1117 GfxCIDFont*cfont = (GfxCIDFont*)font;
1119 if(font->getType() == fontCIDType2)
1120 CIDToGIDMap = cfont->getCIDToGID();
1123 font8 = (Gfx8BitFont*)font;
1124 char**enc=font8->getEncoding();
1129 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);
1132 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);
1135 int charid = getGfxCharID(current_gfxfont, c, name, u);
1137 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1138 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1142 gfxmatrix_t m = this->current_font_matrix;
1143 state->transform(x, y, &m.tx, &m.ty);
1147 if(render == RENDER_FILL) {
1148 output->drawchar(output, current_font_id, charid, &col, &m);
1150 msg("<debug> Drawing glyph %d as shape", charid);
1151 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1152 gfxline_t*tglyph = gfxline_clone(glyph);
1153 gfxline_transform(tglyph, &m);
1154 if((render&3) != RENDER_INVISIBLE) {
1155 gfxline_t*add = gfxline_clone(tglyph);
1156 current_text_stroke = gfxline_append(current_text_stroke, add);
1158 if(render&RENDER_CLIP) {
1159 gfxline_t*add = gfxline_clone(tglyph);
1160 current_text_clip = gfxline_append(current_text_clip, add);
1162 gfxline_free(tglyph);
1166 void SWFOutputDev::endString(GfxState *state)
1168 int render = state->getRender();
1169 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1170 if(states[statepos].textRender != render)
1171 msg("<error> Internal error: drawChar.render!=beginString.render");
1173 if(current_text_stroke) {
1174 /* fillstroke and stroke text rendering objects we can process right
1175 now (as there may be texts of other rendering modes in this
1176 text object)- clipping objects have to wait until endTextObject,
1178 if((render&3) == RENDER_FILL) {
1179 fillGfxLine(state, current_text_stroke);
1180 gfxline_free(current_text_stroke);
1181 current_text_stroke = 0;
1182 } else if((render&3) == RENDER_FILLSTROKE) {
1183 fillGfxLine(state, current_text_stroke);
1184 strokeGfxline(state, current_text_stroke);
1185 gfxline_free(current_text_stroke);
1186 current_text_stroke = 0;
1187 } else if((render&3) == RENDER_STROKE) {
1188 strokeGfxline(state, current_text_stroke);
1189 gfxline_free(current_text_stroke);
1190 current_text_stroke = 0;
1195 void SWFOutputDev::endTextObject(GfxState *state)
1197 int render = state->getRender();
1198 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1199 if(states[statepos].textRender != render)
1200 msg("<error> Internal error: drawChar.render!=beginString.render");
1202 if(current_text_clip) {
1203 clipToGfxLine(state, current_text_clip);
1204 gfxline_free(current_text_clip);
1205 current_text_clip = 0;
1209 /* the logic seems to be as following:
1210 first, beginType3Char is called, with the charcode and the coordinates.
1211 if this function returns true, it already knew about the char and has now drawn it.
1212 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1213 the all draw operations until endType3Char are part of the char (which in this moment is
1214 at the position first passed to beginType3Char). the char ends with endType3Char.
1216 The drawing operations between beginType3Char and endType3Char are somewhat different to
1217 the normal ones. For example, the fillcolor equals the stroke color.
1220 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1222 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1224 /* the character itself is going to be passed using the draw functions */
1225 return gFalse; /* gTrue= is_in_cache? */
1228 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1229 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1231 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1232 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1236 void SWFOutputDev::endType3Char(GfxState *state)
1239 msg("<debug> endType3Char");
1242 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1244 this->currentpage = pageNum;
1246 int rot = doc->getPageRotate(1);
1249 gfxline_t clippath[5];
1251 white.r = white.g = white.b = white.a = 255;
1253 msg("<verbose> startPage %d (%f,%f,%f,%f)\n", pageNum, crop_x1, crop_y1, crop_x2, crop_y2);
1255 msg("<verbose> page is rotated %d degrees\n", rot);
1257 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1258 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1259 Use CropBox, not MediaBox, as page size
1266 state->transform(crop_x1,crop_y1,&x1,&y1);
1267 state->transform(crop_x2,crop_y2,&x2,&y2);
1269 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1270 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1272 /* apply user clip box */
1273 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1274 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1275 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1276 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1277 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1280 msg("<verbose> Bounding box is (%f,%f)-(%f,%f)", x1,y1,x2,y2);
1282 if(outer_clip_box) {
1283 output->endclip(output);
1287 msg("<notice> processing page %d (%dx%d:%d:%d)", pageNum, (int)x2-(int)x1,(int)y2-(int)y1, (int)x1, (int)y1);
1289 swfoutput_newpage(output, (int)x1, (int)y1, (int)x2, (int)y2);
1291 clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1292 clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1293 clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1294 clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1295 clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1296 output->startclip(output, clippath); outer_clip_box = 1;
1297 output->fill(output, clippath, &white);
1300 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1302 msg("<debug> drawlink\n");
1303 double x1, y1, x2, y2, w;
1305 gfxline_t points[5];
1309 link->getBorder(&x1, &y1, &x2, &y2, &w);
1311 link->getRect(&x1, &y1, &x2, &y2);
1316 cvtUserToDev(x1, y1, &x, &y);
1317 points[0].type = gfx_moveTo;
1318 points[0].x = points[4].x = x + user_movex;
1319 points[0].y = points[4].y = y + user_movey;
1320 points[0].next = &points[1];
1321 cvtUserToDev(x2, y1, &x, &y);
1322 points[1].type = gfx_lineTo;
1323 points[1].x = x + user_movex;
1324 points[1].y = y + user_movey;
1325 points[1].next = &points[2];
1326 cvtUserToDev(x2, y2, &x, &y);
1327 points[2].type = gfx_lineTo;
1328 points[2].x = x + user_movex;
1329 points[2].y = y + user_movey;
1330 points[2].next = &points[3];
1331 cvtUserToDev(x1, y2, &x, &y);
1332 points[3].type = gfx_lineTo;
1333 points[3].x = x + user_movex;
1334 points[3].y = y + user_movey;
1335 points[3].next = &points[4];
1336 cvtUserToDev(x1, y1, &x, &y);
1337 points[4].type = gfx_lineTo;
1338 points[4].x = x + user_movex;
1339 points[4].y = y + user_movey;
1342 LinkAction*action=link->getAction();
1349 switch(action->getKind())
1353 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1354 LinkDest *dest=NULL;
1355 if (ha->getDest()==NULL)
1356 dest=catalog->findDest(ha->getNamedDest());
1357 else dest=ha->getDest();
1359 if (dest->isPageRef()){
1360 Ref pageref=dest->getPageRef();
1361 page=catalog->findPage(pageref.num,pageref.gen);
1363 else page=dest->getPageNum();
1364 sprintf(buf, "%d", page);
1371 LinkGoToR*l = (LinkGoToR*)action;
1372 GString*g = l->getNamedDest();
1374 s = strdup(g->getCString());
1379 LinkNamed*l = (LinkNamed*)action;
1380 GString*name = l->getName();
1382 s = strdup(name->lowerCase()->getCString());
1383 named = name->getCString();
1386 if(strstr(s, "next") || strstr(s, "forward"))
1388 page = currentpage + 1;
1390 else if(strstr(s, "prev") || strstr(s, "back"))
1392 page = currentpage - 1;
1394 else if(strstr(s, "last") || strstr(s, "end"))
1396 page = pagepos>0?pages[pagepos-1]:0;
1398 else if(strstr(s, "first") || strstr(s, "top"))
1406 case actionLaunch: {
1408 LinkLaunch*l = (LinkLaunch*)action;
1409 GString * str = new GString(l->getFileName());
1410 str->append(l->getParams());
1411 s = strdup(str->getCString());
1417 LinkURI*l = (LinkURI*)action;
1418 GString*g = l->getURI();
1420 url = g->getCString();
1425 case actionUnknown: {
1427 LinkUnknown*l = (LinkUnknown*)action;
1432 msg("<error> Unknown link type!\n");
1436 if(!s) s = strdup("-?-");
1438 if(!linkinfo && (page || url))
1440 msg("<notice> File contains links");
1447 for(t=0;t<pagepos;t++)
1452 sprintf(buf, "page%d", t);
1453 output->drawlink(output, points, buf);
1458 output->drawlink(output, points, url);
1461 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1465 void SWFOutputDev::saveState(GfxState *state) {
1466 msg("<trace> saveState\n");
1469 msg("<error> Too many nested states in pdf.");
1473 states[statepos].clipping = 0; //? shouldn't this be the current value?
1474 states[statepos].textRender = states[statepos-1].textRender;
1477 void SWFOutputDev::restoreState(GfxState *state) {
1478 msg("<trace> restoreState\n");
1480 while(states[statepos].clipping) {
1481 output->endclip(output);
1482 states[statepos].clipping--;
1487 char* SWFOutputDev::searchFont(char*name)
1491 int is_standard_font = 0;
1493 msg("<verbose> SearchFont(%s)", name);
1495 /* see if it is a pdf standard font */
1496 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1498 if(!strcmp(name, pdf2t1map[i].pdffont))
1500 name = pdf2t1map[i].filename;
1501 is_standard_font = 1;
1505 /* look in all font files */
1506 for(i=0;i<fontnum;i++)
1508 if(strstr(fonts[i].filename, name))
1510 if(!fonts[i].used) {
1513 if(!is_standard_font)
1514 msg("<notice> Using %s for %s", fonts[i].filename, name);
1516 return strdup(fonts[i].filename);
1522 void SWFOutputDev::updateLineWidth(GfxState *state)
1524 double width = state->getTransformedLineWidth();
1525 //swfoutput_setlinewidth(&output, width);
1528 void SWFOutputDev::updateLineCap(GfxState *state)
1530 int c = state->getLineCap();
1533 void SWFOutputDev::updateLineJoin(GfxState *state)
1535 int j = state->getLineJoin();
1538 void SWFOutputDev::updateFillColor(GfxState *state)
1541 double opaq = state->getFillOpacity();
1542 state->getFillRGB(&rgb);
1544 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1547 void SWFOutputDev::updateStrokeColor(GfxState *state)
1550 double opaq = state->getStrokeOpacity();
1551 state->getStrokeRGB(&rgb);
1552 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1555 void FoFiWrite(void *stream, char *data, int len)
1557 fwrite(data, len, 1, (FILE*)stream);
1560 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1562 char*tmpFileName = NULL;
1568 Object refObj, strObj;
1570 tmpFileName = mktmpname(namebuf);
1573 ret = font->getEmbeddedFontID(&embRef);
1575 msg("<verbose> Didn't get embedded font id");
1576 /* not embedded- the caller should now search the font
1577 directories for this font */
1581 f = fopen(tmpFileName, "wb");
1583 msg("<error> Couldn't create temporary Type 1 font file");
1587 /*if(font->isCIDFont()) {
1588 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1589 GString c = cidFont->getCollection();
1590 msg("<notice> Collection: %s", c.getCString());
1593 //if (font->getType() == fontType1C) {
1594 if (0) { //font->getType() == fontType1C) {
1595 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1597 msg("<error> Couldn't read embedded font file");
1601 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1603 cvt->convertToType1(f);
1605 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1607 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1609 //cvt->convertToCIDType0("test", f);
1610 //cvt->convertToType0("test", f);
1613 } else if(font->getType() == fontTrueType) {
1614 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1615 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1617 msg("<error> Couldn't read embedded font file");
1621 TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1624 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1625 cvt->writeTTF(FoFiWrite, f);
1630 font->getEmbeddedFontID(&embRef);
1631 refObj.initRef(embRef.num, embRef.gen);
1632 refObj.fetch(ref, &strObj);
1634 strObj.streamReset();
1639 f4[t] = strObj.streamGetChar();
1640 f4c[t] = (char)f4[t];
1645 if(!strncmp(f4c, "true", 4)) {
1646 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1647 Change this on the fly */
1648 f4[0] = f4[2] = f4[3] = 0;
1656 while ((c = strObj.streamGetChar()) != EOF) {
1660 strObj.streamClose();
1665 return strdup(tmpFileName);
1668 char* searchForSuitableFont(GfxFont*gfxFont)
1670 char*name = getFontName(gfxFont);
1674 if(!config_use_fontconfig)
1677 #ifdef HAVE_FONTCONFIG
1678 FcPattern *pattern, *match;
1682 static int fcinitcalled = false;
1684 msg("<debug> searchForSuitableFont(%s)", name);
1686 // call init ony once
1687 if (!fcinitcalled) {
1688 msg("<debug> Initializing FontConfig...");
1689 fcinitcalled = true;
1691 msg("<debug> FontConfig Initialization failed. Disabling.");
1692 config_use_fontconfig = 0;
1695 msg("<debug> ...initialized FontConfig");
1698 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1699 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1700 if (gfxFont->isItalic()) // check for italic
1701 msg("<debug> FontConfig: Adding Italic Slant");
1702 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1703 if (gfxFont->isBold()) // check for bold
1704 msg("<debug> FontConfig: Adding Bold Weight");
1705 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1707 msg("<debug> FontConfig: Try to match...");
1708 // configure and match using the original font name
1709 FcConfigSubstitute(0, pattern, FcMatchPattern);
1710 FcDefaultSubstitute(pattern);
1711 match = FcFontMatch(0, pattern, &result);
1713 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1714 msg("<debug> FontConfig: family=%s", (char*)v);
1715 // if we get an exact match
1716 if (strcmp((char *)v, name) == 0) {
1717 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1718 filename = strdup((char*)v); // mem leak
1719 char *nfn = strrchr(filename, '/');
1720 if(nfn) fontname = strdup(nfn+1);
1721 else fontname = filename;
1723 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1725 // initialize patterns
1726 FcPatternDestroy(pattern);
1727 FcPatternDestroy(match);
1729 // now match against serif etc.
1730 if (gfxFont->isSerif()) {
1731 msg("<debug> FontConfig: Create Serif Family Pattern");
1732 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1733 } else if (gfxFont->isFixedWidth()) {
1734 msg("<debug> FontConfig: Create Monospace Family Pattern");
1735 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1737 msg("<debug> FontConfig: Create Sans Family Pattern");
1738 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1742 if (gfxFont->isItalic()) {
1743 msg("<debug> FontConfig: Adding Italic Slant");
1744 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1747 if (gfxFont->isBold()) {
1748 msg("<debug> FontConfig: Adding Bold Weight");
1749 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1752 msg("<debug> FontConfig: Try to match... (2)");
1753 // configure and match using serif etc
1754 FcConfigSubstitute (0, pattern, FcMatchPattern);
1755 FcDefaultSubstitute (pattern);
1756 match = FcFontMatch (0, pattern, &result);
1758 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1759 filename = strdup((char*)v); // mem leak
1760 char *nfn = strrchr(filename, '/');
1761 if(nfn) fontname = strdup(nfn+1);
1762 else fontname = filename;
1764 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1768 //printf("FONTCONFIG: pattern");
1769 //FcPatternPrint(pattern);
1770 //printf("FONTCONFIG: match");
1771 //FcPatternPrint(match);
1773 FcPatternDestroy(pattern);
1774 FcPatternDestroy(match);
1776 pdfswf_addfont(filename);
1783 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1785 char*fontname = 0, *filename = 0;
1786 msg("<notice> subsituteFont(%s)", oldname);
1788 if(!(fontname = searchForSuitableFont(gfxFont))) {
1789 fontname = "Times-Roman";
1791 filename = searchFont(fontname);
1793 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1797 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1798 msg("<fatal> Too many fonts in file.");
1802 substitutesource[substitutepos] = strdup(oldname); //mem leak
1803 substitutetarget[substitutepos] = fontname;
1804 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1807 return strdup(filename); //mem leak
1810 void unlinkfont(char* filename)
1817 if(!strncmp(&filename[l-4],".afm",4)) {
1818 memcpy(&filename[l-4],".pfb",4);
1820 memcpy(&filename[l-4],".pfa",4);
1822 memcpy(&filename[l-4],".afm",4);
1825 if(!strncmp(&filename[l-4],".pfa",4)) {
1826 memcpy(&filename[l-4],".afm",4);
1828 memcpy(&filename[l-4],".pfa",4);
1831 if(!strncmp(&filename[l-4],".pfb",4)) {
1832 memcpy(&filename[l-4],".afm",4);
1834 memcpy(&filename[l-4],".pfb",4);
1839 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1845 int SWFOutputDev::setGfxFont(char*id, char*filename)
1848 fontlist_t*last=0,*l = this->fontlist;
1850 /* TODO: should this be part of the state? */
1853 if(!strcmp(l->id, id)) {
1854 current_font_id = l->id;
1855 current_gfxfont = l->font;
1857 output->addfont(output, id, current_gfxfont);
1862 if(!filename) return 0;
1863 font = gfxfont_load(filename);
1866 l->filename = strdup(filename);
1869 current_font_id = l->id;
1870 current_gfxfont = l->font;
1876 output->addfont(output, id, current_gfxfont);
1880 void SWFOutputDev::updateFont(GfxState *state)
1882 GfxFont*gfxFont = state->getFont();
1887 char * fontid = getFontID(gfxFont);
1890 /* first, look if we substituted this font before-
1891 this way, we don't initialize the T1 Fonts
1893 for(t=0;t<substitutepos;t++) {
1894 if(!strcmp(fontid, substitutesource[t])) {
1895 free(fontid);fontid=0;
1896 fontid = strdup(substitutetarget[t]);
1901 /* second, see if this is a font which was used before-
1902 if so, we are done */
1903 if(setGfxFont(fontid, 0)) {
1907 /* if(swfoutput_queryfont(&output, fontid))
1908 swfoutput_setfont(&output, fontid, 0);
1910 msg("<debug> updateFont(%s) [cached]", fontid);
1914 // look for Type 3 font
1915 if (gfxFont->getType() == fontType3) {
1917 type3Warning = gTrue;
1918 showFontError(gfxFont, 2);
1924 /* now either load the font, or find a substitution */
1927 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1932 (gfxFont->getType() == fontType1 ||
1933 gfxFont->getType() == fontType1C ||
1934 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
1935 gfxFont->getType() == fontTrueType ||
1936 gfxFont->getType() == fontCIDType2
1939 fileName = writeEmbeddedFontToFile(xref, gfxFont);
1940 if(!fileName) showFontError(gfxFont,0);
1943 char * fontname = getFontName(gfxFont);
1944 fileName = searchFont(fontname);
1945 if(!fileName) showFontError(gfxFont,0);
1949 char * fontname = getFontName(gfxFont);
1950 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
1951 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
1952 fileName = substituteFont(gfxFont, fontid);
1953 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
1954 msg("<notice> Font is now %s (%s)", fontid, fileName);
1958 msg("<error> Couldn't set font %s\n", fontid);
1963 msg("<verbose> updateFont(%s) -> %s", fontid, fileName);
1964 dumpFontInfo("<verbose>", gfxFont);
1966 //swfoutput_setfont(&output, fontid, fileName);
1968 if(!setGfxFont(fontid, 0)) {
1969 setGfxFont(fontid, fileName);
1973 unlinkfont(fileName);
1979 #define SQR(x) ((x)*(x))
1981 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1983 if((newwidth<2 || newheight<2) ||
1984 (width<=newwidth || height<=newheight))
1986 unsigned char*newdata;
1988 newdata= (unsigned char*)malloc(newwidth*newheight);
1990 double fx = (double)(width)/newwidth;
1991 double fy = (double)(height)/newheight;
1993 int blocksize = (int)(8192/(fx*fy));
1994 int r = 8192*256/palettesize;
1995 for(x=0;x<newwidth;x++) {
1996 double ex = px + fx;
1997 int fromx = (int)px;
1999 int xweight1 = (int)(((fromx+1)-px)*256);
2000 int xweight2 = (int)((ex-tox)*256);
2002 for(y=0;y<newheight;y++) {
2003 double ey = py + fy;
2004 int fromy = (int)py;
2006 int yweight1 = (int)(((fromy+1)-py)*256);
2007 int yweight2 = (int)((ey-toy)*256);
2010 for(xx=fromx;xx<=tox;xx++)
2011 for(yy=fromy;yy<=toy;yy++) {
2012 int b = 1-data[width*yy+xx];
2014 if(xx==fromx) weight = (weight*xweight1)/256;
2015 if(xx==tox) weight = (weight*xweight2)/256;
2016 if(yy==fromy) weight = (weight*yweight1)/256;
2017 if(yy==toy) weight = (weight*yweight2)/256;
2020 //if(a) a=(palettesize-1)*r/blocksize;
2021 newdata[y*newwidth+x] = (a*blocksize)/r;
2029 #define IMAGE_TYPE_JPEG 0
2030 #define IMAGE_TYPE_LOSSLESS 1
2032 static void drawimage(gfxdevice_t*dev, RGBA* data, int sizex,int sizey,
2033 double x1,double y1,
2034 double x2,double y2,
2035 double x3,double y3,
2036 double x4,double y4, int type)
2040 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2041 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2043 gfxline_t p1,p2,p3,p4,p5;
2044 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2045 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2046 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2047 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2048 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2050 {p1.x = (int)(p1.x*20)/20.0;
2051 p1.y = (int)(p1.y*20)/20.0;
2052 p2.x = (int)(p2.x*20)/20.0;
2053 p2.y = (int)(p2.y*20)/20.0;
2054 p3.x = (int)(p3.x*20)/20.0;
2055 p3.y = (int)(p3.y*20)/20.0;
2056 p4.x = (int)(p4.x*20)/20.0;
2057 p4.y = (int)(p4.y*20)/20.0;
2058 p5.x = (int)(p5.x*20)/20.0;
2059 p5.y = (int)(p5.y*20)/20.0;
2066 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2067 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2072 img.data = (gfxcolor_t*)data;
2076 if(type == IMAGE_TYPE_JPEG)
2077 /* TODO: pass image_dpi to device instead */
2078 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2080 dev->fillbitmap(dev, &p1, &img, &m, 0);
2083 void drawimagejpeg(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
2084 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2086 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2089 void drawimagelossless(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
2090 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2092 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2096 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2097 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2098 GBool inlineImg, int mask, int*maskColors)
2103 double x1,y1,x2,y2,x3,y3,x4,y4;
2104 ImageStream *imgStr;
2111 ncomps = colorMap->getNumPixelComps();
2112 bits = colorMap->getBits();
2114 imgStr = new ImageStream(str, width, ncomps,bits);
2117 if(!width || !height || (height<=1 && width<=1))
2119 msg("<verbose> Ignoring %d by %d image", width, height);
2120 unsigned char buf[8];
2122 for (y = 0; y < height; ++y)
2123 for (x = 0; x < width; ++x) {
2124 imgStr->getPixel(buf);
2130 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1+= user_movey;
2131 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2+= user_movey;
2132 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3+= user_movey;
2133 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4+= user_movey;
2135 if(!pbminfo && !(str->getKind()==strDCT)) {
2137 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2141 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2143 if(!jpeginfo && (str->getKind()==strDCT)) {
2144 msg("<notice> file contains jpeg pictures");
2150 unsigned char buf[8];
2152 unsigned char*pic = new unsigned char[width*height];
2155 state->getFillRGB(&rgb);
2157 memset(pal,255,sizeof(pal));
2158 pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
2159 pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
2160 pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
2161 pal[0].a = 255; pal[1].a = 0;
2164 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2165 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2166 for (y = 0; y < height; ++y)
2167 for (x = 0; x < width; ++x)
2169 imgStr->getPixel(buf);
2172 pic[width*y+x] = buf[0];
2175 /* the size of the drawn image is added to the identifier
2176 as the same image may require different bitmaps if displayed
2177 at different sizes (due to antialiasing): */
2180 unsigned char*pic2 = 0;
2183 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2192 height = realheight;
2196 /* make a black/white palette */
2201 float r = 255/(numpalette-1);
2203 for(t=0;t<numpalette;t++) {
2204 pal[t].r = (U8)(255*rgb.r);
2205 pal[t].g = (U8)(255*rgb.g);
2206 pal[t].b = (U8)(255*rgb.b);
2207 pal[t].a = (U8)(t*r);
2211 RGBA*pic2 = new RGBA[width*height];
2212 for (y = 0; y < height; ++y) {
2213 for (x = 0; x < width; ++x) {
2214 pic2[width*y+x] = pal[pic[y*width+x]];
2217 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2226 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2227 RGBA*pic=new RGBA[width*height];
2228 for (y = 0; y < height; ++y) {
2229 for (x = 0; x < width; ++x) {
2230 imgStr->getPixel(pixBuf);
2231 colorMap->getRGB(pixBuf, &rgb);
2232 pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
2233 pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
2234 pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
2235 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2238 if(str->getKind()==strDCT)
2239 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2241 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2246 RGBA*pic=new RGBA[width*height];
2249 for(t=0;t<256;t++) {
2251 colorMap->getRGB(pixBuf, &rgb);
2252 /*if(maskColors && *maskColors==t) {
2253 msg("<notice> Color %d is transparent", t);
2254 if (imgData->maskColors) {
2256 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2257 if (pix[i] < imgData->maskColors[2*i] ||
2258 pix[i] > imgData->maskColors[2*i+1]) {
2273 pal[t].r = (U8)(rgb.r * 255 + 0.5);
2274 pal[t].g = (U8)(rgb.g * 255 + 0.5);
2275 pal[t].b = (U8)(rgb.b * 255 + 0.5);
2276 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2279 for (y = 0; y < height; ++y) {
2280 for (x = 0; x < width; ++x) {
2281 imgStr->getPixel(pixBuf);
2282 pic[width*y+x] = pal[pixBuf[0]];
2285 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2293 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2294 int width, int height, GBool invert,
2297 if(states[statepos].textRender & 4) //clipped
2299 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2300 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
2303 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2304 int width, int height, GfxImageColorMap *colorMap,
2305 int *maskColors, GBool inlineImg)
2307 if(states[statepos].textRender & 4) //clipped
2310 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
2311 colorMap?"colorMap":"no colorMap",
2312 maskColors?"maskColors":"no maskColors",
2315 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2316 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2317 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
2320 //SWFOutputDev*output = 0;
2322 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2327 if (infoDict->lookup(key, &obj)->isString()) {
2328 s1 = obj.getString();
2329 if ((s1->getChar(0) & 0xff) == 0xfe &&
2330 (s1->getChar(1) & 0xff) == 0xff) {
2332 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2333 if (s1->getChar(i) == '\0') {
2334 s2->append(s1->getChar(i+1));
2337 s2 = new GString("<unicode>");
2341 printf(fmt, s2->getCString());
2344 printf(fmt, s1->getCString());
2350 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2354 if (infoDict->lookup(key, &obj)->isString()) {
2355 s = obj.getString()->getCString();
2356 if (s[0] == 'D' && s[1] == ':') {
2367 void storeDeviceParameter(char*name, char*value)
2369 parameter_t*p = new parameter_t();
2370 p->name = strdup(name);
2371 p->value = strdup(value);
2373 if(device_config_next) {
2374 device_config_next->next = p;
2375 device_config_next = p;
2378 device_config_next = p;
2382 void pdfswf_setparameter(char*name, char*value)
2384 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2385 if(!strcmp(name, "caplinewidth")) {
2386 caplinewidth = atof(value);
2387 } else if(!strcmp(name, "zoom")) {
2390 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2391 storeDeviceParameter("jpegsubpixels", buf);
2392 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2393 storeDeviceParameter("ppmsubpixels", buf);
2394 } else if(!strcmp(name, "jpegdpi")) {
2396 jpeg_dpi = atoi(value);
2397 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2398 storeDeviceParameter("jpegsubpixels", buf);
2399 } else if(!strcmp(name, "ppmdpi")) {
2401 ppm_dpi = atoi(value);
2402 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2403 storeDeviceParameter("ppmsubpixels", buf);
2404 } else if(!strcmp(name, "forceType0Fonts")) {
2405 forceType0Fonts = atoi(value);
2406 } else if(!strcmp(name, "fontdir")) {
2407 pdfswf_addfontdir(value);
2408 } else if(!strcmp(name, "languagedir")) {
2409 pdfswf_addlanguagedir(value);
2410 } else if(!strcmp(name, "fontconfig")) {
2411 config_use_fontconfig = atoi(value);
2413 storeDeviceParameter(name,value);
2416 void pdfswf_addfont(char*filename)
2419 memset(&f, 0, sizeof(fontfile_t));
2420 f.filename = filename;
2421 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2422 fonts[fontnum++] = f;
2424 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2428 static char* dirseparator()
2437 void pdfswf_addlanguagedir(char*dir)
2440 globalParams = new GlobalParams("");
2442 msg("<notice> Adding %s to language pack directories", dir);
2446 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2447 strcpy(config_file, dir);
2448 strcat(config_file, dirseparator());
2449 strcat(config_file, "add-to-xpdfrc");
2451 fi = fopen(config_file, "rb");
2453 msg("<error> Could not open %s", config_file);
2456 globalParams->parseFile(new GString(config_file), fi);
2460 void pdfswf_addfontdir(char*dirname)
2462 #ifdef HAVE_DIRENT_H
2463 msg("<notice> Adding %s to font directories", dirname);
2464 DIR*dir = opendir(dirname);
2466 msg("<warning> Couldn't open directory %s\n", dirname);
2471 ent = readdir (dir);
2475 char*name = ent->d_name;
2481 if(!strncasecmp(&name[l-4], ".pfa", 4))
2483 if(!strncasecmp(&name[l-4], ".pfb", 4))
2485 if(!strncasecmp(&name[l-4], ".ttf", 4))
2489 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2490 strcpy(fontname, dirname);
2491 strcat(fontname, dirseparator());
2492 strcat(fontname, name);
2493 msg("<verbose> Adding %s to fonts", fontname);
2494 pdfswf_addfont(fontname);
2499 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2504 typedef struct _pdf_doc_internal
2508 } pdf_doc_internal_t;
2509 typedef struct _pdf_page_internal
2511 } pdf_page_internal_t;
2512 typedef struct _swf_output_internal
2514 SWFOutputDev*outputDev;
2515 } swf_output_internal_t;
2517 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2519 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2520 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2521 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2522 memset(i, 0, sizeof(pdf_doc_internal_t));
2523 pdf_doc->internal = i;
2525 GString *fileName = new GString(filename);
2531 globalParams = new GlobalParams("");
2534 if (userPassword && userPassword[0]) {
2535 userPW = new GString(userPassword);
2539 i->doc = new PDFDoc(fileName, userPW);
2543 if (!i->doc->isOk()) {
2548 i->doc->getDocInfo(&info);
2549 if (info.isDict() &&
2550 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2551 printInfoString(info.getDict(), "Title", "Title: %s\n");
2552 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2553 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2554 printInfoString(info.getDict(), "Author", "Author: %s\n");
2555 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2556 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2557 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2558 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2559 printf("Pages: %d\n", i->doc->getNumPages());
2560 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2561 printf("Encrypted: ");
2562 if (i->doc->isEncrypted()) {
2563 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2564 i->doc->okToPrint() ? "yes" : "no",
2565 i->doc->okToCopy() ? "yes" : "no",
2566 i->doc->okToChange() ? "yes" : "no",
2567 i->doc->okToAddNotes() ? "yes" : "no");
2574 pdf_doc->num_pages = i->doc->getNumPages();
2576 if (i->doc->isEncrypted()) {
2577 if(!i->doc->okToCopy()) {
2578 printf("PDF disallows copying.\n");
2581 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2588 void pdfswf_preparepage(int page)
2592 pages = (int*)malloc(1024*sizeof(int));
2595 if(pagepos == pagebuflen)
2598 pages = (int*)realloc(pages, pagebuflen);
2601 pages[pagepos++] = page;
2608 delete globalParams;globalParams=0;
2609 Object::memCheck(stderr);
2614 void pdf_destroy(pdf_doc_t*pdf_doc)
2616 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2618 msg("<debug> pdfswf.cc: pdfswf_close()");
2619 delete i->doc; i->doc=0;
2621 free(pages); pages = 0; //FIXME
2623 free(pdf_doc->internal);pdf_doc->internal=0;
2624 free(pdf_doc);pdf_doc=0;
2627 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2629 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2631 if(page < 1 || page > pdf_doc->num_pages)
2634 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2635 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2636 memset(pi, 0, sizeof(pdf_page_internal_t));
2637 pdf_page->internal = pi;
2639 pdf_page->parent = pdf_doc;
2640 pdf_page->nr = page;
2644 void pdf_page_destroy(pdf_page_t*pdf_page)
2646 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2647 free(pdf_page->internal);pdf_page->internal = 0;
2648 free(pdf_page);pdf_page=0;
2651 swf_output_t* swf_output_init()
2653 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2654 memset(swf_output, 0, sizeof(swf_output_t));
2655 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2656 memset(i, 0, sizeof(swf_output_internal_t));
2657 swf_output->internal = i;
2659 i->outputDev = new SWFOutputDev();
2663 void swf_output_setparameter(swf_output_t*swf_output, char*name, char*value)
2666 pdfswf_setparameter(name, value);
2669 void swf_output_pagefeed(swf_output_t*swf)
2671 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2672 i->outputDev->pagefeed();
2673 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2676 int swf_output_save(swf_output_t*swf, char*filename)
2678 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2679 int ret = i->outputDev->save(filename);
2680 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2684 void* swf_output_get(swf_output_t*swf)
2686 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2687 void* ret = i->outputDev->getSWF();
2688 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2692 void swf_output_destroy(swf_output_t*output)
2694 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2695 delete i->outputDev; i->outputDev=0;
2696 free(output->internal);output->internal=0;
2700 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2702 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2703 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2706 gfxdevice_t*dev = si->outputDev->output;
2707 dev->setparameter(dev, "protect", "1");
2709 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2711 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2713 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2715 si->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2718 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2720 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2721 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2723 si->outputDev->setMove(x,y);
2724 if((x1|y1|x2|y2)==0) x2++;
2725 si->outputDev->setClip(x1,y1,x2,y2);
2727 pdf_page_render2(page, output);
2729 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2731 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2732 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2734 si->outputDev->setMove(0,0);
2735 si->outputDev->setClip(0,0,0,0);
2737 pdf_page_render2(page, output);
2741 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2743 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2744 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2745 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2746 memset(info, 0, sizeof(pdf_page_info_t));
2748 InfoOutputDev*output = new InfoOutputDev;
2751 pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2753 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2756 info->xMin = output->x1;
2757 info->yMin = output->y1;
2758 info->xMax = output->x2;
2759 info->yMax = output->y2;
2760 info->number_of_images = output->num_images;
2761 info->number_of_links = output->num_links;
2762 info->number_of_fonts = output->num_fonts;
2769 void pdf_page_info_destroy(pdf_page_info_t*info)