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 {
155 virtual ~SWFOutputDev() ;
157 void setMove(int x,int y);
158 void setClip(int x1,int y1,int x2,int y2);
160 int save(char*filename);
164 void getDimensions(int*x1,int*y1,int*x2,int*y2);
166 //----- get info about output device
168 // Does this device use upside-down coordinates?
169 // (Upside-down means (0,0) is the top left corner of the page.)
170 virtual GBool upsideDown();
172 // Does this device use drawChar() or drawString()?
173 virtual GBool useDrawChar();
175 // Can this device draw gradients?
176 virtual GBool useGradients();
178 virtual GBool interpretType3Chars() {return gTrue;}
180 //----- initialization and control
182 void setXRef(PDFDoc*doc, XRef *xref);
185 virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
188 virtual void drawLink(Link *link, Catalog *catalog) ;
190 //----- save/restore graphics state
191 virtual void saveState(GfxState *state) ;
192 virtual void restoreState(GfxState *state) ;
194 //----- update graphics state
196 virtual void updateFont(GfxState *state);
197 virtual void updateFillColor(GfxState *state);
198 virtual void updateStrokeColor(GfxState *state);
199 virtual void updateLineWidth(GfxState *state);
200 virtual void updateLineJoin(GfxState *state);
201 virtual void updateLineCap(GfxState *state);
203 virtual void updateAll(GfxState *state)
206 updateFillColor(state);
207 updateStrokeColor(state);
208 updateLineWidth(state);
209 updateLineJoin(state);
210 updateLineCap(state);
213 //----- path painting
214 virtual void stroke(GfxState *state) ;
215 virtual void fill(GfxState *state) ;
216 virtual void eoFill(GfxState *state) ;
218 //----- path clipping
219 virtual void clip(GfxState *state) ;
220 virtual void eoClip(GfxState *state) ;
223 virtual void beginString(GfxState *state, GString *s) ;
224 virtual void endString(GfxState *state) ;
225 virtual void endTextObject(GfxState *state);
226 virtual void drawChar(GfxState *state, double x, double y,
227 double dx, double dy,
228 double originX, double originY,
229 CharCode code, Unicode *u, int uLen);
231 //----- image drawing
232 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
233 int width, int height, GBool invert,
235 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
236 int width, int height, GfxImageColorMap *colorMap,
237 int *maskColors, GBool inlineImg);
239 virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
240 virtual void endType3Char(GfxState *state);
242 virtual void type3D0(GfxState *state, double wx, double wy);
243 virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
246 void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
247 int width, int height, GfxImageColorMap*colorMap, GBool invert,
248 GBool inlineImg, int mask, int *maskColors);
249 int SWFOutputDev::setGfxFont(char*id, char*filename);
250 void strokeGfxline(GfxState *state, gfxline_t*line);
251 void clipToGfxLine(GfxState *state, gfxline_t*line);
252 void fillGfxLine(GfxState *state, gfxline_t*line);
256 gfxresult_t*result; //filled when complete
258 char outer_clip_box; //whether the page clip box is still on
260 SWFOutputState states[64];
268 char* searchFont(char*name);
269 char* substituteFont(GfxFont*gfxFont, char*oldname);
270 char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
272 int jpeginfo; // did we write "File contains jpegs" yet?
273 int pbminfo; // did we write "File contains jpegs" yet?
274 int linkinfo; // did we write "File contains links" yet?
275 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
276 int gradientinfo; // did we write "File contains Gradients yet?
278 int type3active; // are we between beginType3()/endType3()?
284 char* substitutetarget[256];
285 char* substitutesource[256];
288 int user_movex,user_movey;
289 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
291 gfxline_t* current_text_stroke;
292 gfxline_t* current_text_clip;
293 char* current_font_id;
294 gfxfont_t* current_gfxfont;
295 gfxmatrix_t current_font_matrix;
297 fontlist_t* fontlist;
300 static char*getFontID(GfxFont*font);
302 class InfoOutputDev: public OutputDev
316 virtual ~InfoOutputDev()
319 virtual GBool upsideDown() {return gTrue;}
320 virtual GBool useDrawChar() {return gTrue;}
321 virtual GBool useGradients() {return gTrue;}
322 virtual GBool interpretType3Chars() {return gTrue;}
323 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
326 state->transform(crop_x1,crop_y1,&x1,&y1);
327 state->transform(crop_x2,crop_y2,&x2,&y2);
328 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
329 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
335 virtual void drawLink(Link *link, Catalog *catalog)
339 virtual void updateFont(GfxState *state)
341 GfxFont*font = state->getFont();
344 /*char*id = getFontID(font);*/
348 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
349 int width, int height, GBool invert,
354 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
355 int width, int height, GfxImageColorMap *colorMap,
356 int *maskColors, GBool inlineImg)
362 SWFOutputDev::SWFOutputDev()
380 current_text_stroke = 0;
381 current_text_clip = 0;
385 output = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
386 memset(output, 0, sizeof(output));
389 void SWFOutputDev::setMove(int x,int y)
391 this->user_movex = x;
392 this->user_movey = y;
395 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
397 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
398 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
400 this->user_clipx1 = x1;
401 this->user_clipy1 = y1;
402 this->user_clipx2 = x2;
403 this->user_clipy2 = y2;
406 void SWFOutputDev::getDimensions(int*x1,int*y1,int*x2,int*y2)
409 *x1 = (int)result->get(result, "xmin");
410 *y1 = (int)result->get(result, "ymin");
411 *x2 = (int)result->get(result, "xmax");
412 *y2 = (int)result->get(result, "ymax");
414 *x1 = *y1 = *x2 = *y2 = 0;
418 static char*getFontID(GfxFont*font)
420 GString*gstr = font->getName();
421 char* fontname = gstr==0?0:gstr->getCString();
425 sprintf(buf, "UFONT%d", r->num);
428 return strdup(fontname);
431 static char*getFontName(GfxFont*font)
433 char*fontid = getFontID(font);
435 char* plus = strchr(fontid, '+');
436 if(plus && plus < &fontid[strlen(fontid)-1]) {
437 fontname = strdup(plus+1);
439 fontname = strdup(fontid);
445 static char mybuf[1024];
446 static char* gfxstate2str(GfxState *state)
450 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
457 if(state->getX1()!=0.0)
458 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
459 if(state->getY1()!=0.0)
460 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
461 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
462 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
463 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
464 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
465 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
466 state->getFillColor()->c[0], state->getFillColor()->c[1]);
467 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
468 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
469 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
470 state->getFillColor()->c[0], state->getFillColor()->c[1],
471 state->getFillColor()->c[2], state->getFillColor()->c[3],
472 state->getFillColor()->c[4], state->getFillColor()->c[5],
473 state->getFillColor()->c[6], state->getFillColor()->c[7]);
474 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
475 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
476 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
477 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
478 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
479 state->getFillRGB(&rgb);
480 if(rgb.r || rgb.g || rgb.b)
481 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
482 state->getStrokeRGB(&rgb);
483 if(rgb.r || rgb.g || rgb.b)
484 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
485 if(state->getFillColorSpace()->getNComps()>1)
486 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
487 if(state->getStrokeColorSpace()->getNComps()>1)
488 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
489 if(state->getFillPattern())
490 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
491 if(state->getStrokePattern())
492 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
494 if(state->getFillOpacity()!=1.0)
495 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
496 if(state->getStrokeOpacity()!=1.0)
497 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
499 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
504 state->getLineDash(&dash, &length, &start);
508 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
509 for(t=0;t<length;t++) {
510 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
512 bufpos+=sprintf(bufpos,"]");
515 if(state->getFlatness()!=1)
516 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
517 if(state->getLineJoin()!=0)
518 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
519 if(state->getLineJoin()!=0)
520 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
521 if(state->getLineJoin()!=0)
522 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
524 if(state->getFont() && getFontID(state->getFont()))
525 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
526 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
527 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
528 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
529 if(state->getCharSpace())
530 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
531 if(state->getWordSpace())
532 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
533 if(state->getHorizScaling()!=1.0)
534 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
535 if(state->getLeading())
536 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
538 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
539 if(state->getRender())
540 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
541 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
542 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
543 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
544 if(state->getLineX())
545 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
546 if(state->getLineY())
547 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
548 bufpos+=sprintf(bufpos," ");
552 static void dumpFontInfo(char*loglevel, GfxFont*font);
553 static int lastdumps[1024];
554 static int lastdumppos = 0;
559 static void showFontError(GfxFont*font, int nr)
563 for(t=0;t<lastdumppos;t++)
564 if(lastdumps[t] == r->num)
568 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
569 lastdumps[lastdumppos++] = r->num;
571 msg("<warning> The following font caused problems:");
573 msg("<warning> The following font caused problems (substituting):");
575 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
576 dumpFontInfo("<warning>", font);
579 static void dumpFontInfo(char*loglevel, GfxFont*font)
581 char* id = getFontID(font);
582 char* name = getFontName(font);
583 Ref* r=font->getID();
584 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
586 GString*gstr = font->getTag();
588 msg("%s| Tag: %s\n", loglevel, id);
590 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
592 GfxFontType type=font->getType();
594 case fontUnknownType:
595 msg("%s| Type: unknown\n",loglevel);
598 msg("%s| Type: 1\n",loglevel);
601 msg("%s| Type: 1C\n",loglevel);
604 msg("%s| Type: 3\n",loglevel);
607 msg("%s| Type: TrueType\n",loglevel);
610 msg("%s| Type: CIDType0\n",loglevel);
613 msg("%s| Type: CIDType0C\n",loglevel);
616 msg("%s| Type: CIDType2\n",loglevel);
621 GBool embedded = font->getEmbeddedFontID(&embRef);
623 if(font->getEmbeddedFontName()) {
624 embeddedName = font->getEmbeddedFontName()->getCString();
627 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
629 gstr = font->getExtFontFile();
631 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
633 // Get font descriptor flags.
634 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
635 if(font->isSerif()) msg("%s| is serif\n", loglevel);
636 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
637 if(font->isItalic()) msg("%s| is italic\n", loglevel);
638 if(font->isBold()) msg("%s| is bold\n", loglevel);
644 //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");}
645 //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");}
648 void dump_outline(gfxline_t*line)
651 if(line->type == gfx_moveTo) {
652 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
653 } else if(line->type == gfx_lineTo) {
654 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
655 } else if(line->type == gfx_splineTo) {
656 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
662 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey)
664 int num = path->getNumSubpaths();
667 double lastx=0,lasty=0,posx=0,posy=0;
670 msg("<warning> empty path");
674 gfxdrawer_target_gfxline(&draw);
676 for(t = 0; t < num; t++) {
677 GfxSubpath *subpath = path->getSubpath(t);
678 int subnum = subpath->getNumPoints();
679 double bx=0,by=0,cx=0,cy=0;
681 for(s=0;s<subnum;s++) {
684 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
689 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
690 draw.lineTo(&draw, lastx, lasty);
692 draw.moveTo(&draw, x,y);
697 } else if(subpath->getCurve(s) && cpos==0) {
701 } else if(subpath->getCurve(s) && cpos==1) {
709 draw.lineTo(&draw, x,y);
711 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y);
718 /* fix non-closed lines */
719 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
720 draw.lineTo(&draw, lastx, lasty);
722 gfxline_t*result = (gfxline_t*)draw.result(&draw);
726 /*----------------------------------------------------------------------------
727 * Primitive Graphic routines
728 *----------------------------------------------------------------------------*/
730 void SWFOutputDev::stroke(GfxState *state)
732 GfxPath * path = state->getPath();
733 gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex, user_movey);
734 strokeGfxline(state, line);
738 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
740 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
741 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
742 double miterLimit = state->getMiterLimit();
743 double width = state->getTransformedLineWidth();
746 double opaq = state->getStrokeOpacity();
748 state->getFillRGB(&rgb);
750 state->getStrokeRGB(&rgb);
752 col.r = (unsigned char)(rgb.r*255);
753 col.g = (unsigned char)(rgb.g*255);
754 col.b = (unsigned char)(rgb.b*255);
755 col.a = (unsigned char)(opaq*255);
757 gfx_capType capType = gfx_capRound;
758 if(lineCap == 0) capType = gfx_capButt;
759 else if(lineCap == 1) capType = gfx_capRound;
760 else if(lineCap == 2) capType = gfx_capSquare;
762 gfx_joinType joinType = gfx_joinRound;
763 if(lineJoin == 0) joinType = gfx_joinMiter;
764 else if(lineJoin == 1) joinType = gfx_joinRound;
765 else if(lineJoin == 2) joinType = gfx_joinBevel;
768 double dashphase = 0;
770 state->getLineDash(&ldash, &dashnum, &dashphase);
774 if(dashnum && ldash) {
775 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
779 msg("<trace> %d dashes", dashnum);
780 msg("<trace> | phase: %f", dashphase);
781 for(t=0;t<dashnum;t++) {
783 msg("<trace> | d%-3d: %f", t, ldash[t]);
786 if(getLogLevel() >= LOGLEVEL_TRACE) {
790 line2 = gfxtool_dash_line(line, dash, dashphase);
792 msg("<trace> After dashing:");
795 if(getLogLevel() >= LOGLEVEL_TRACE) {
797 state->getStrokeGray(&gray);
798 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n",
800 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
801 lineCap==0?"butt": (lineJoin==1?"round":"square"),
803 col.r,col.g,col.b,col.a,
809 //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
810 output->stroke(output, line, width, &col, capType, joinType, miterLimit);
816 gfxcolor_t getFillColor(GfxState * state)
819 double opaq = state->getFillOpacity();
820 state->getFillRGB(&rgb);
822 col.r = (unsigned char)(rgb.r*255);
823 col.g = (unsigned char)(rgb.g*255);
824 col.b = (unsigned char)(rgb.b*255);
825 col.a = (unsigned char)(opaq*255);
829 void SWFOutputDev::fillGfxLine(GfxState *state, gfxline_t*line)
831 gfxcolor_t col = getFillColor(state);
833 if(getLogLevel() >= LOGLEVEL_TRACE) {
834 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
837 output->fill(output, line, &col);
839 void SWFOutputDev::fill(GfxState *state)
841 GfxPath * path = state->getPath();
842 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
843 fillGfxLine(state, line);
846 void SWFOutputDev::eoFill(GfxState *state)
848 GfxPath * path = state->getPath();
849 gfxcolor_t col = getFillColor(state);
851 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
853 if(getLogLevel() >= LOGLEVEL_TRACE) {
854 msg("<trace> eofill\n");
858 output->fill(output, line, &col);
862 void SWFOutputDev::clip(GfxState *state)
864 GfxPath * path = state->getPath();
865 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
866 clipToGfxLine(state, line);
870 void SWFOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line)
872 if(getLogLevel() >= LOGLEVEL_TRACE) {
873 msg("<trace> clip\n");
877 output->startclip(output, line);
878 states[statepos].clipping++;
880 void SWFOutputDev::eoClip(GfxState *state)
882 GfxPath * path = state->getPath();
883 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
885 if(getLogLevel() >= LOGLEVEL_TRACE) {
886 msg("<trace> eoclip\n");
890 output->startclip(output, line);
891 states[statepos].clipping++;
895 /* pass through functions for swf_output */
896 int SWFOutputDev::save(char*filename)
899 return result->save(result, filename);
901 void SWFOutputDev::pagefeed()
904 output->endclip(output);
908 swfoutput_pagefeed(output);
910 void* SWFOutputDev::getSWF()
913 return result->get(result, "swf");
916 void SWFOutputDev::finish()
919 output->endclip(output);
923 this->result = output->finish(output);
924 free(output);output=0;
928 SWFOutputDev::~SWFOutputDev()
934 this->result->destroy(this->result);
938 fontlist_t*l = this->fontlist;
940 fontlist_t*next = l->next;
942 gfxfont_free(l->font);
949 GBool SWFOutputDev::upsideDown()
951 msg("<debug> upsidedown? yes");
954 GBool SWFOutputDev::useDrawChar()
958 GBool SWFOutputDev::useGradients()
962 msg("<notice> File contains gradients");
968 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
969 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
971 #define RENDER_FILL 0
972 #define RENDER_STROKE 1
973 #define RENDER_FILLSTROKE 2
974 #define RENDER_INVISIBLE 3
975 #define RENDER_CLIP 4
977 static char tmp_printstr[4096];
978 char* makeStringPrintable(char*str)
980 int len = strlen(str);
995 tmp_printstr[len++] = '.';
996 tmp_printstr[len++] = '.';
997 tmp_printstr[len++] = '.';
999 tmp_printstr[len] = 0;
1000 return tmp_printstr;
1004 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
1008 for(t=0;t<font->num_glyphs;t++) {
1009 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
1010 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1014 /* if we didn't find the character, maybe
1015 we can find the capitalized version */
1016 for(t=0;t<font->num_glyphs;t++) {
1017 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
1018 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1024 /* try to use the unicode id */
1025 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
1026 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
1027 return font->unicode2glyph[u];
1030 if(charnr>=0 && charnr<font->num_glyphs) {
1031 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1039 void SWFOutputDev::beginString(GfxState *state, GString *s)
1041 int render = state->getRender();
1042 if(current_text_stroke) {
1043 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
1046 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
1047 double m11,m21,m12,m22;
1048 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
1049 state->getFontTransMat(&m11, &m12, &m21, &m22);
1050 m11 *= state->getHorizScaling();
1051 m21 *= state->getHorizScaling();
1053 this->current_font_matrix.m00 = m11 / 1024.0;
1054 this->current_font_matrix.m01 = m12 / 1024.0;
1055 this->current_font_matrix.m10 = -m21 / 1024.0;
1056 this->current_font_matrix.m11 = -m22 / 1024.0;
1057 this->current_font_matrix.tx = 0;
1058 this->current_font_matrix.ty = 0;
1060 gfxmatrix_t m = this->current_font_matrix;
1062 /*if(render != 3 && render != 0)
1063 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1064 states[statepos].textRender = render;
1067 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1068 double dx, double dy,
1069 double originX, double originY,
1070 CharCode c, Unicode *_u, int uLen)
1072 int render = state->getRender();
1073 // check for invisible text -- this is used by Acrobat Capture
1077 if(states[statepos].textRender != render)
1078 msg("<error> Internal error: drawChar.render!=beginString.render");
1080 gfxcolor_t col = getFillColor(state);
1082 Gushort *CIDToGIDMap = 0;
1083 GfxFont*font = state->getFont();
1085 if(font->getType() == fontType3) {
1086 /* type 3 chars are passed as graphics */
1087 msg("<debug> type3 char at %f/%f", x, y);
1098 /* find out char name from unicode index
1099 TODO: should be precomputed
1101 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1102 if(nameToUnicodeTab[t].u == u) {
1103 name = nameToUnicodeTab[t].name;
1110 if(font->isCIDFont()) {
1111 GfxCIDFont*cfont = (GfxCIDFont*)font;
1113 if(font->getType() == fontCIDType2)
1114 CIDToGIDMap = cfont->getCIDToGID();
1117 font8 = (Gfx8BitFont*)font;
1118 char**enc=font8->getEncoding();
1123 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);
1126 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);
1129 int charid = getGfxCharID(current_gfxfont, c, name, u);
1131 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1132 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1136 gfxmatrix_t m = this->current_font_matrix;
1137 state->transform(x, y, &m.tx, &m.ty);
1141 if(render == RENDER_FILL) {
1142 output->drawchar(output, current_font_id, charid, &col, &m);
1144 msg("<debug> Drawing glyph %d as shape", charid);
1145 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1146 gfxline_t*tglyph = gfxline_clone(glyph);
1147 gfxline_transform(tglyph, &m);
1148 if((render&3) != RENDER_INVISIBLE) {
1149 gfxline_t*add = gfxline_clone(tglyph);
1150 current_text_stroke = gfxline_append(current_text_stroke, add);
1152 if(render&RENDER_CLIP) {
1153 gfxline_t*add = gfxline_clone(tglyph);
1154 current_text_clip = gfxline_append(current_text_clip, add);
1156 gfxline_free(tglyph);
1160 void SWFOutputDev::endString(GfxState *state)
1162 int render = state->getRender();
1163 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1164 if(states[statepos].textRender != render)
1165 msg("<error> Internal error: drawChar.render!=beginString.render");
1167 if(current_text_stroke) {
1168 /* fillstroke and stroke text rendering objects we can process right
1169 now (as there may be texts of other rendering modes in this
1170 text object)- clipping objects have to wait until endTextObject,
1172 if((render&3) == RENDER_FILL) {
1173 fillGfxLine(state, current_text_stroke);
1174 gfxline_free(current_text_stroke);
1175 current_text_stroke = 0;
1176 } else if((render&3) == RENDER_FILLSTROKE) {
1177 fillGfxLine(state, current_text_stroke);
1178 strokeGfxline(state, current_text_stroke);
1179 gfxline_free(current_text_stroke);
1180 current_text_stroke = 0;
1181 } else if((render&3) == RENDER_STROKE) {
1182 strokeGfxline(state, current_text_stroke);
1183 gfxline_free(current_text_stroke);
1184 current_text_stroke = 0;
1189 void SWFOutputDev::endTextObject(GfxState *state)
1191 int render = state->getRender();
1192 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1193 if(states[statepos].textRender != render)
1194 msg("<error> Internal error: drawChar.render!=beginString.render");
1196 if(current_text_clip) {
1197 clipToGfxLine(state, current_text_clip);
1198 gfxline_free(current_text_clip);
1199 current_text_clip = 0;
1203 /* the logic seems to be as following:
1204 first, beginType3Char is called, with the charcode and the coordinates.
1205 if this function returns true, it already knew about the char and has now drawn it.
1206 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1207 the all draw operations until endType3Char are part of the char (which in this moment is
1208 at the position first passed to beginType3Char). the char ends with endType3Char.
1210 The drawing operations between beginType3Char and endType3Char are somewhat different to
1211 the normal ones. For example, the fillcolor equals the stroke color.
1214 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1216 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1218 /* the character itself is going to be passed using the draw functions */
1219 return gFalse; /* gTrue= is_in_cache? */
1222 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1223 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1225 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1226 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1230 void SWFOutputDev::endType3Char(GfxState *state)
1233 msg("<debug> endType3Char");
1236 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1238 this->currentpage = pageNum;
1240 int rot = doc->getPageRotate(1);
1243 gfxline_t clippath[5];
1245 white.r = white.g = white.b = white.a = 255;
1247 msg("<verbose> startPage %d (%f,%f,%f,%f)\n", pageNum, crop_x1, crop_y1, crop_x2, crop_y2);
1249 msg("<verbose> page is rotated %d degrees\n", rot);
1251 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1252 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1253 Use CropBox, not MediaBox, as page size
1260 state->transform(crop_x1,crop_y1,&x1,&y1);
1261 state->transform(crop_x2,crop_y2,&x2,&y2);
1263 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1264 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1266 /* apply user clip box */
1267 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1268 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1269 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1270 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1271 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1274 if(!outputstarted) {
1275 msg("<verbose> Bounding box is (%f,%f)-(%f,%f)", x1,y1,x2,y2);
1277 gfxdevice_swf_init(output);
1279 /* configure device */
1280 parameter_t*p = device_config;
1282 output->setparameter(output, p->name, p->value);
1289 if(outer_clip_box) {
1290 output->endclip(output);
1294 msg("<notice> processing page %d (%dx%d:%d:%d)", pageNum, (int)x2-(int)x1,(int)y2-(int)y1, (int)x1, (int)y1);
1296 swfoutput_newpage(output, (int)x1, (int)y1, (int)x2, (int)y2);
1298 clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1299 clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1300 clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1301 clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1302 clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1303 output->startclip(output, clippath); outer_clip_box = 1;
1304 output->fill(output, clippath, &white);
1307 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1309 msg("<debug> drawlink\n");
1310 double x1, y1, x2, y2, w;
1312 gfxline_t points[5];
1316 link->getBorder(&x1, &y1, &x2, &y2, &w);
1318 link->getRect(&x1, &y1, &x2, &y2);
1323 cvtUserToDev(x1, y1, &x, &y);
1324 points[0].type = gfx_moveTo;
1325 points[0].x = points[4].x = x + user_movex;
1326 points[0].y = points[4].y = y + user_movey;
1327 points[0].next = &points[1];
1328 cvtUserToDev(x2, y1, &x, &y);
1329 points[1].type = gfx_lineTo;
1330 points[1].x = x + user_movex;
1331 points[1].y = y + user_movey;
1332 points[1].next = &points[2];
1333 cvtUserToDev(x2, y2, &x, &y);
1334 points[2].type = gfx_lineTo;
1335 points[2].x = x + user_movex;
1336 points[2].y = y + user_movey;
1337 points[2].next = &points[3];
1338 cvtUserToDev(x1, y2, &x, &y);
1339 points[3].type = gfx_lineTo;
1340 points[3].x = x + user_movex;
1341 points[3].y = y + user_movey;
1342 points[3].next = &points[4];
1343 cvtUserToDev(x1, y1, &x, &y);
1344 points[4].type = gfx_lineTo;
1345 points[4].x = x + user_movex;
1346 points[4].y = y + user_movey;
1349 LinkAction*action=link->getAction();
1356 switch(action->getKind())
1360 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1361 LinkDest *dest=NULL;
1362 if (ha->getDest()==NULL)
1363 dest=catalog->findDest(ha->getNamedDest());
1364 else dest=ha->getDest();
1366 if (dest->isPageRef()){
1367 Ref pageref=dest->getPageRef();
1368 page=catalog->findPage(pageref.num,pageref.gen);
1370 else page=dest->getPageNum();
1371 sprintf(buf, "%d", page);
1378 LinkGoToR*l = (LinkGoToR*)action;
1379 GString*g = l->getNamedDest();
1381 s = strdup(g->getCString());
1386 LinkNamed*l = (LinkNamed*)action;
1387 GString*name = l->getName();
1389 s = strdup(name->lowerCase()->getCString());
1390 named = name->getCString();
1393 if(strstr(s, "next") || strstr(s, "forward"))
1395 page = currentpage + 1;
1397 else if(strstr(s, "prev") || strstr(s, "back"))
1399 page = currentpage - 1;
1401 else if(strstr(s, "last") || strstr(s, "end"))
1403 page = pagepos>0?pages[pagepos-1]:0;
1405 else if(strstr(s, "first") || strstr(s, "top"))
1413 case actionLaunch: {
1415 LinkLaunch*l = (LinkLaunch*)action;
1416 GString * str = new GString(l->getFileName());
1417 str->append(l->getParams());
1418 s = strdup(str->getCString());
1424 LinkURI*l = (LinkURI*)action;
1425 GString*g = l->getURI();
1427 url = g->getCString();
1432 case actionUnknown: {
1434 LinkUnknown*l = (LinkUnknown*)action;
1439 msg("<error> Unknown link type!\n");
1443 if(!s) s = strdup("-?-");
1445 if(!linkinfo && (page || url))
1447 msg("<notice> File contains links");
1454 for(t=0;t<pagepos;t++)
1459 sprintf(buf, "page%d", t);
1460 output->drawlink(output, points, buf);
1465 output->drawlink(output, points, url);
1468 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1472 void SWFOutputDev::saveState(GfxState *state) {
1473 msg("<trace> saveState\n");
1476 msg("<error> Too many nested states in pdf.");
1480 states[statepos].clipping = 0; //? shouldn't this be the current value?
1481 states[statepos].textRender = states[statepos-1].textRender;
1484 void SWFOutputDev::restoreState(GfxState *state) {
1485 msg("<trace> restoreState\n");
1487 while(states[statepos].clipping) {
1488 output->endclip(output);
1489 states[statepos].clipping--;
1494 char* SWFOutputDev::searchFont(char*name)
1498 int is_standard_font = 0;
1500 msg("<verbose> SearchFont(%s)", name);
1502 /* see if it is a pdf standard font */
1503 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1505 if(!strcmp(name, pdf2t1map[i].pdffont))
1507 name = pdf2t1map[i].filename;
1508 is_standard_font = 1;
1512 /* look in all font files */
1513 for(i=0;i<fontnum;i++)
1515 if(strstr(fonts[i].filename, name))
1517 if(!fonts[i].used) {
1520 if(!is_standard_font)
1521 msg("<notice> Using %s for %s", fonts[i].filename, name);
1523 return strdup(fonts[i].filename);
1529 void SWFOutputDev::updateLineWidth(GfxState *state)
1531 double width = state->getTransformedLineWidth();
1532 //swfoutput_setlinewidth(&output, width);
1535 void SWFOutputDev::updateLineCap(GfxState *state)
1537 int c = state->getLineCap();
1540 void SWFOutputDev::updateLineJoin(GfxState *state)
1542 int j = state->getLineJoin();
1545 void SWFOutputDev::updateFillColor(GfxState *state)
1548 double opaq = state->getFillOpacity();
1549 state->getFillRGB(&rgb);
1551 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1554 void SWFOutputDev::updateStrokeColor(GfxState *state)
1557 double opaq = state->getStrokeOpacity();
1558 state->getStrokeRGB(&rgb);
1559 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1562 void FoFiWrite(void *stream, char *data, int len)
1564 fwrite(data, len, 1, (FILE*)stream);
1567 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1569 char*tmpFileName = NULL;
1575 Object refObj, strObj;
1577 tmpFileName = mktmpname(namebuf);
1580 ret = font->getEmbeddedFontID(&embRef);
1582 msg("<verbose> Didn't get embedded font id");
1583 /* not embedded- the caller should now search the font
1584 directories for this font */
1588 f = fopen(tmpFileName, "wb");
1590 msg("<error> Couldn't create temporary Type 1 font file");
1594 /*if(font->isCIDFont()) {
1595 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1596 GString c = cidFont->getCollection();
1597 msg("<notice> Collection: %s", c.getCString());
1600 //if (font->getType() == fontType1C) {
1601 if (0) { //font->getType() == fontType1C) {
1602 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1604 msg("<error> Couldn't read embedded font file");
1608 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1610 cvt->convertToType1(f);
1612 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1614 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1616 //cvt->convertToCIDType0("test", f);
1617 //cvt->convertToType0("test", f);
1620 } else if(font->getType() == fontTrueType) {
1621 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1622 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1624 msg("<error> Couldn't read embedded font file");
1628 TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1631 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1632 cvt->writeTTF(FoFiWrite, f);
1637 font->getEmbeddedFontID(&embRef);
1638 refObj.initRef(embRef.num, embRef.gen);
1639 refObj.fetch(ref, &strObj);
1641 strObj.streamReset();
1646 f4[t] = strObj.streamGetChar();
1647 f4c[t] = (char)f4[t];
1652 if(!strncmp(f4c, "true", 4)) {
1653 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1654 Change this on the fly */
1655 f4[0] = f4[2] = f4[3] = 0;
1663 while ((c = strObj.streamGetChar()) != EOF) {
1667 strObj.streamClose();
1672 return strdup(tmpFileName);
1675 char* searchForSuitableFont(GfxFont*gfxFont)
1677 char*name = getFontName(gfxFont);
1681 if(!config_use_fontconfig)
1684 #ifdef HAVE_FONTCONFIG
1685 FcPattern *pattern, *match;
1689 static int fcinitcalled = false;
1691 msg("<debug> searchForSuitableFont(%s)", name);
1693 // call init ony once
1694 if (!fcinitcalled) {
1695 msg("<debug> Initializing FontConfig...");
1696 fcinitcalled = true;
1698 msg("<debug> FontConfig Initialization failed. Disabling.");
1699 config_use_fontconfig = 0;
1702 msg("<debug> ...initialized FontConfig");
1705 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1706 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1707 if (gfxFont->isItalic()) // check for italic
1708 msg("<debug> FontConfig: Adding Italic Slant");
1709 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1710 if (gfxFont->isBold()) // check for bold
1711 msg("<debug> FontConfig: Adding Bold Weight");
1712 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1714 msg("<debug> FontConfig: Try to match...");
1715 // configure and match using the original font name
1716 FcConfigSubstitute(0, pattern, FcMatchPattern);
1717 FcDefaultSubstitute(pattern);
1718 match = FcFontMatch(0, pattern, &result);
1720 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1721 msg("<debug> FontConfig: family=%s", (char*)v);
1722 // if we get an exact match
1723 if (strcmp((char *)v, name) == 0) {
1724 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1725 filename = strdup((char*)v); // mem leak
1726 char *nfn = strrchr(filename, '/');
1727 if(nfn) fontname = strdup(nfn+1);
1728 else fontname = filename;
1730 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1732 // initialize patterns
1733 FcPatternDestroy(pattern);
1734 FcPatternDestroy(match);
1736 // now match against serif etc.
1737 if (gfxFont->isSerif()) {
1738 msg("<debug> FontConfig: Create Serif Family Pattern");
1739 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1740 } else if (gfxFont->isFixedWidth()) {
1741 msg("<debug> FontConfig: Create Monospace Family Pattern");
1742 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1744 msg("<debug> FontConfig: Create Sans Family Pattern");
1745 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1749 if (gfxFont->isItalic()) {
1750 msg("<debug> FontConfig: Adding Italic Slant");
1751 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1754 if (gfxFont->isBold()) {
1755 msg("<debug> FontConfig: Adding Bold Weight");
1756 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1759 msg("<debug> FontConfig: Try to match... (2)");
1760 // configure and match using serif etc
1761 FcConfigSubstitute (0, pattern, FcMatchPattern);
1762 FcDefaultSubstitute (pattern);
1763 match = FcFontMatch (0, pattern, &result);
1765 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1766 filename = strdup((char*)v); // mem leak
1767 char *nfn = strrchr(filename, '/');
1768 if(nfn) fontname = strdup(nfn+1);
1769 else fontname = filename;
1771 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1775 //printf("FONTCONFIG: pattern");
1776 //FcPatternPrint(pattern);
1777 //printf("FONTCONFIG: match");
1778 //FcPatternPrint(match);
1780 FcPatternDestroy(pattern);
1781 FcPatternDestroy(match);
1783 pdfswf_addfont(filename);
1790 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1792 char*fontname = 0, *filename = 0;
1793 msg("<notice> subsituteFont(%s)", oldname);
1795 if(!(fontname = searchForSuitableFont(gfxFont))) {
1796 fontname = "Times-Roman";
1798 filename = searchFont(fontname);
1800 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1804 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1805 msg("<fatal> Too many fonts in file.");
1809 substitutesource[substitutepos] = strdup(oldname); //mem leak
1810 substitutetarget[substitutepos] = fontname;
1811 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1814 return strdup(filename); //mem leak
1817 void unlinkfont(char* filename)
1824 if(!strncmp(&filename[l-4],".afm",4)) {
1825 memcpy(&filename[l-4],".pfb",4);
1827 memcpy(&filename[l-4],".pfa",4);
1829 memcpy(&filename[l-4],".afm",4);
1832 if(!strncmp(&filename[l-4],".pfa",4)) {
1833 memcpy(&filename[l-4],".afm",4);
1835 memcpy(&filename[l-4],".pfa",4);
1838 if(!strncmp(&filename[l-4],".pfb",4)) {
1839 memcpy(&filename[l-4],".afm",4);
1841 memcpy(&filename[l-4],".pfb",4);
1846 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1852 int SWFOutputDev::setGfxFont(char*id, char*filename)
1855 fontlist_t*last=0,*l = this->fontlist;
1857 /* TODO: should this be part of the state? */
1860 if(!strcmp(l->id, id)) {
1861 current_font_id = l->id;
1862 current_gfxfont = l->font;
1864 output->addfont(output, id, current_gfxfont);
1869 if(!filename) return 0;
1870 font = gfxfont_load(filename);
1873 l->filename = strdup(filename);
1876 current_font_id = l->id;
1877 current_gfxfont = l->font;
1883 output->addfont(output, id, current_gfxfont);
1887 void SWFOutputDev::updateFont(GfxState *state)
1889 GfxFont*gfxFont = state->getFont();
1894 char * fontid = getFontID(gfxFont);
1897 /* first, look if we substituted this font before-
1898 this way, we don't initialize the T1 Fonts
1900 for(t=0;t<substitutepos;t++) {
1901 if(!strcmp(fontid, substitutesource[t])) {
1902 free(fontid);fontid=0;
1903 fontid = strdup(substitutetarget[t]);
1908 /* second, see if this is a font which was used before-
1909 if so, we are done */
1910 if(setGfxFont(fontid, 0)) {
1914 /* if(swfoutput_queryfont(&output, fontid))
1915 swfoutput_setfont(&output, fontid, 0);
1917 msg("<debug> updateFont(%s) [cached]", fontid);
1921 // look for Type 3 font
1922 if (gfxFont->getType() == fontType3) {
1924 type3Warning = gTrue;
1925 showFontError(gfxFont, 2);
1931 /* now either load the font, or find a substitution */
1934 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1939 (gfxFont->getType() == fontType1 ||
1940 gfxFont->getType() == fontType1C ||
1941 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
1942 gfxFont->getType() == fontTrueType ||
1943 gfxFont->getType() == fontCIDType2
1946 fileName = writeEmbeddedFontToFile(xref, gfxFont);
1947 if(!fileName) showFontError(gfxFont,0);
1950 char * fontname = getFontName(gfxFont);
1951 fileName = searchFont(fontname);
1952 if(!fileName) showFontError(gfxFont,0);
1955 char * fontname = getFontName(gfxFont);
1956 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
1957 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
1958 fileName = substituteFont(gfxFont, fontid);
1959 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
1960 msg("<notice> Font is now %s (%s)", fontid, fileName);
1964 msg("<error> Couldn't set font %s\n", fontid);
1969 msg("<verbose> updateFont(%s) -> %s", fontid, fileName);
1970 dumpFontInfo("<verbose>", gfxFont);
1972 //swfoutput_setfont(&output, fontid, fileName);
1974 if(!setGfxFont(fontid, 0)) {
1975 setGfxFont(fontid, fileName);
1979 unlinkfont(fileName);
1985 #define SQR(x) ((x)*(x))
1987 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1989 if((newwidth<2 || newheight<2) ||
1990 (width<=newwidth || height<=newheight))
1992 unsigned char*newdata;
1994 newdata= (unsigned char*)malloc(newwidth*newheight);
1996 double fx = (double)(width)/newwidth;
1997 double fy = (double)(height)/newheight;
1999 int blocksize = (int)(8192/(fx*fy));
2000 int r = 8192*256/palettesize;
2001 for(x=0;x<newwidth;x++) {
2002 double ex = px + fx;
2003 int fromx = (int)px;
2005 int xweight1 = (int)(((fromx+1)-px)*256);
2006 int xweight2 = (int)((ex-tox)*256);
2008 for(y=0;y<newheight;y++) {
2009 double ey = py + fy;
2010 int fromy = (int)py;
2012 int yweight1 = (int)(((fromy+1)-py)*256);
2013 int yweight2 = (int)((ey-toy)*256);
2016 for(xx=fromx;xx<=tox;xx++)
2017 for(yy=fromy;yy<=toy;yy++) {
2018 int b = 1-data[width*yy+xx];
2020 if(xx==fromx) weight = (weight*xweight1)/256;
2021 if(xx==tox) weight = (weight*xweight2)/256;
2022 if(yy==fromy) weight = (weight*yweight1)/256;
2023 if(yy==toy) weight = (weight*yweight2)/256;
2026 //if(a) a=(palettesize-1)*r/blocksize;
2027 newdata[y*newwidth+x] = (a*blocksize)/r;
2035 #define IMAGE_TYPE_JPEG 0
2036 #define IMAGE_TYPE_LOSSLESS 1
2038 static void drawimage(gfxdevice_t*dev, RGBA* data, int sizex,int sizey,
2039 double x1,double y1,
2040 double x2,double y2,
2041 double x3,double y3,
2042 double x4,double y4, int type)
2046 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2047 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2049 gfxline_t p1,p2,p3,p4,p5;
2050 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2051 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2052 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2053 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2054 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2056 {p1.x = (int)(p1.x*20)/20.0;
2057 p1.y = (int)(p1.y*20)/20.0;
2058 p2.x = (int)(p2.x*20)/20.0;
2059 p2.y = (int)(p2.y*20)/20.0;
2060 p3.x = (int)(p3.x*20)/20.0;
2061 p3.y = (int)(p3.y*20)/20.0;
2062 p4.x = (int)(p4.x*20)/20.0;
2063 p4.y = (int)(p4.y*20)/20.0;
2064 p5.x = (int)(p5.x*20)/20.0;
2065 p5.y = (int)(p5.y*20)/20.0;
2072 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2073 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2078 img.data = (gfxcolor_t*)data;
2082 if(type == IMAGE_TYPE_JPEG)
2083 /* TODO: pass image_dpi to device instead */
2084 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2086 dev->fillbitmap(dev, &p1, &img, &m, 0);
2089 void drawimagejpeg(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_JPEG);
2095 void drawimagelossless(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
2096 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2098 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2102 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2103 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2104 GBool inlineImg, int mask, int*maskColors)
2109 double x1,y1,x2,y2,x3,y3,x4,y4;
2110 ImageStream *imgStr;
2117 ncomps = colorMap->getNumPixelComps();
2118 bits = colorMap->getBits();
2120 imgStr = new ImageStream(str, width, ncomps,bits);
2123 if(!width || !height || (height<=1 && width<=1))
2125 msg("<verbose> Ignoring %d by %d image", width, height);
2126 unsigned char buf[8];
2128 for (y = 0; y < height; ++y)
2129 for (x = 0; x < width; ++x) {
2130 imgStr->getPixel(buf);
2136 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1+= user_movey;
2137 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2+= user_movey;
2138 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3+= user_movey;
2139 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4+= user_movey;
2141 if(!pbminfo && !(str->getKind()==strDCT)) {
2143 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2147 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2149 if(!jpeginfo && (str->getKind()==strDCT)) {
2150 msg("<notice> file contains jpeg pictures");
2156 unsigned char buf[8];
2158 unsigned char*pic = new unsigned char[width*height];
2161 state->getFillRGB(&rgb);
2163 memset(pal,255,sizeof(pal));
2164 pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
2165 pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
2166 pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
2167 pal[0].a = 255; pal[1].a = 0;
2170 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2171 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2172 for (y = 0; y < height; ++y)
2173 for (x = 0; x < width; ++x)
2175 imgStr->getPixel(buf);
2178 pic[width*y+x] = buf[0];
2181 /* the size of the drawn image is added to the identifier
2182 as the same image may require different bitmaps if displayed
2183 at different sizes (due to antialiasing): */
2186 unsigned char*pic2 = 0;
2189 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2198 height = realheight;
2202 /* make a black/white palette */
2207 float r = 255/(numpalette-1);
2209 for(t=0;t<numpalette;t++) {
2210 pal[t].r = (U8)(255*rgb.r);
2211 pal[t].g = (U8)(255*rgb.g);
2212 pal[t].b = (U8)(255*rgb.b);
2213 pal[t].a = (U8)(t*r);
2217 RGBA*pic2 = new RGBA[width*height];
2218 for (y = 0; y < height; ++y) {
2219 for (x = 0; x < width; ++x) {
2220 pic2[width*y+x] = pal[pic[y*width+x]];
2223 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2232 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2233 RGBA*pic=new RGBA[width*height];
2234 for (y = 0; y < height; ++y) {
2235 for (x = 0; x < width; ++x) {
2236 imgStr->getPixel(pixBuf);
2237 colorMap->getRGB(pixBuf, &rgb);
2238 pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
2239 pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
2240 pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
2241 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2244 if(str->getKind()==strDCT)
2245 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2247 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2252 RGBA*pic=new RGBA[width*height];
2255 for(t=0;t<256;t++) {
2257 colorMap->getRGB(pixBuf, &rgb);
2258 /*if(maskColors && *maskColors==t) {
2259 msg("<notice> Color %d is transparent", t);
2260 if (imgData->maskColors) {
2262 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2263 if (pix[i] < imgData->maskColors[2*i] ||
2264 pix[i] > imgData->maskColors[2*i+1]) {
2279 pal[t].r = (U8)(rgb.r * 255 + 0.5);
2280 pal[t].g = (U8)(rgb.g * 255 + 0.5);
2281 pal[t].b = (U8)(rgb.b * 255 + 0.5);
2282 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2285 for (y = 0; y < height; ++y) {
2286 for (x = 0; x < width; ++x) {
2287 imgStr->getPixel(pixBuf);
2288 pic[width*y+x] = pal[pixBuf[0]];
2291 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2299 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2300 int width, int height, GBool invert,
2303 if(states[statepos].textRender & 4) //clipped
2305 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2306 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
2309 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2310 int width, int height, GfxImageColorMap *colorMap,
2311 int *maskColors, GBool inlineImg)
2313 if(states[statepos].textRender & 4) //clipped
2316 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
2317 colorMap?"colorMap":"no colorMap",
2318 maskColors?"maskColors":"no maskColors",
2321 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2322 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2323 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
2326 //SWFOutputDev*output = 0;
2328 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2333 if (infoDict->lookup(key, &obj)->isString()) {
2334 s1 = obj.getString();
2335 if ((s1->getChar(0) & 0xff) == 0xfe &&
2336 (s1->getChar(1) & 0xff) == 0xff) {
2338 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2339 if (s1->getChar(i) == '\0') {
2340 s2->append(s1->getChar(i+1));
2343 s2 = new GString("<unicode>");
2347 printf(fmt, s2->getCString());
2350 printf(fmt, s1->getCString());
2356 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2360 if (infoDict->lookup(key, &obj)->isString()) {
2361 s = obj.getString()->getCString();
2362 if (s[0] == 'D' && s[1] == ':') {
2373 void storeDeviceParameter(char*name, char*value)
2375 parameter_t*p = new parameter_t();
2376 p->name = strdup(name);
2377 p->value = strdup(value);
2379 if(device_config_next) {
2380 device_config_next->next = p;
2381 device_config_next = p;
2384 device_config_next = p;
2388 void pdfswf_setparameter(char*name, char*value)
2390 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2391 if(!strcmp(name, "caplinewidth")) {
2392 caplinewidth = atof(value);
2393 } else if(!strcmp(name, "zoom")) {
2396 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2397 storeDeviceParameter("jpegsubpixels", buf);
2398 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2399 storeDeviceParameter("ppmsubpixels", buf);
2400 } else if(!strcmp(name, "jpegdpi")) {
2402 jpeg_dpi = atoi(value);
2403 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2404 storeDeviceParameter("jpegsubpixels", buf);
2405 } else if(!strcmp(name, "ppmdpi")) {
2407 ppm_dpi = atoi(value);
2408 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2409 storeDeviceParameter("ppmsubpixels", buf);
2410 } else if(!strcmp(name, "forceType0Fonts")) {
2411 forceType0Fonts = atoi(value);
2412 } else if(!strcmp(name, "fontdir")) {
2413 pdfswf_addfontdir(value);
2414 } else if(!strcmp(name, "languagedir")) {
2415 pdfswf_addlanguagedir(value);
2416 } else if(!strcmp(name, "fontconfig")) {
2417 config_use_fontconfig = atoi(value);
2419 storeDeviceParameter(name,value);
2422 void pdfswf_addfont(char*filename)
2425 memset(&f, 0, sizeof(fontfile_t));
2426 f.filename = filename;
2427 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2428 fonts[fontnum++] = f;
2430 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2434 static char* dirseparator()
2443 void pdfswf_addlanguagedir(char*dir)
2446 globalParams = new GlobalParams("");
2448 msg("<notice> Adding %s to language pack directories", dir);
2452 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2453 strcpy(config_file, dir);
2454 strcat(config_file, dirseparator());
2455 strcat(config_file, "add-to-xpdfrc");
2457 fi = fopen(config_file, "rb");
2459 msg("<error> Could not open %s", config_file);
2462 globalParams->parseFile(new GString(config_file), fi);
2466 void pdfswf_addfontdir(char*dirname)
2468 #ifdef HAVE_DIRENT_H
2469 msg("<notice> Adding %s to font directories", dirname);
2470 DIR*dir = opendir(dirname);
2472 msg("<warning> Couldn't open directory %s\n", dirname);
2477 ent = readdir (dir);
2481 char*name = ent->d_name;
2487 if(!strncasecmp(&name[l-4], ".pfa", 4))
2489 if(!strncasecmp(&name[l-4], ".pfb", 4))
2491 if(!strncasecmp(&name[l-4], ".ttf", 4))
2495 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2496 strcpy(fontname, dirname);
2497 strcat(fontname, dirseparator());
2498 strcat(fontname, name);
2499 msg("<verbose> Adding %s to fonts", fontname);
2500 pdfswf_addfont(fontname);
2505 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2510 typedef struct _pdf_doc_internal
2514 } pdf_doc_internal_t;
2515 typedef struct _pdf_page_internal
2517 } pdf_page_internal_t;
2518 typedef struct _swf_output_internal
2520 SWFOutputDev*outputDev;
2521 } swf_output_internal_t;
2523 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2525 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2526 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2527 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2528 memset(i, 0, sizeof(pdf_doc_internal_t));
2529 pdf_doc->internal = i;
2531 GString *fileName = new GString(filename);
2537 globalParams = new GlobalParams("");
2540 if (userPassword && userPassword[0]) {
2541 userPW = new GString(userPassword);
2545 i->doc = new PDFDoc(fileName, userPW);
2549 if (!i->doc->isOk()) {
2554 i->doc->getDocInfo(&info);
2555 if (info.isDict() &&
2556 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2557 printInfoString(info.getDict(), "Title", "Title: %s\n");
2558 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2559 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2560 printInfoString(info.getDict(), "Author", "Author: %s\n");
2561 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2562 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2563 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2564 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2565 printf("Pages: %d\n", i->doc->getNumPages());
2566 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2567 printf("Encrypted: ");
2568 if (i->doc->isEncrypted()) {
2569 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2570 i->doc->okToPrint() ? "yes" : "no",
2571 i->doc->okToCopy() ? "yes" : "no",
2572 i->doc->okToChange() ? "yes" : "no",
2573 i->doc->okToAddNotes() ? "yes" : "no");
2580 pdf_doc->num_pages = i->doc->getNumPages();
2582 if (i->doc->isEncrypted()) {
2583 if(!i->doc->okToCopy()) {
2584 printf("PDF disallows copying.\n");
2587 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2594 void pdfswf_preparepage(int page)
2598 pages = (int*)malloc(1024*sizeof(int));
2601 if(pagepos == pagebuflen)
2604 pages = (int*)realloc(pages, pagebuflen);
2607 pages[pagepos++] = page;
2614 delete globalParams;globalParams=0;
2615 Object::memCheck(stderr);
2620 void pdf_destroy(pdf_doc_t*pdf_doc)
2622 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2624 msg("<debug> pdfswf.cc: pdfswf_close()");
2625 delete i->doc; i->doc=0;
2627 free(pages); pages = 0; //FIXME
2629 free(pdf_doc->internal);pdf_doc->internal=0;
2630 free(pdf_doc);pdf_doc=0;
2633 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2635 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2637 if(page < 1 || page > pdf_doc->num_pages)
2640 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2641 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2642 memset(pi, 0, sizeof(pdf_page_internal_t));
2643 pdf_page->internal = pi;
2645 pdf_page->parent = pdf_doc;
2646 pdf_page->nr = page;
2650 void pdf_page_destroy(pdf_page_t*pdf_page)
2652 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2653 free(pdf_page->internal);pdf_page->internal = 0;
2654 free(pdf_page);pdf_page=0;
2657 swf_output_t* swf_output_init()
2659 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2660 memset(swf_output, 0, sizeof(swf_output_t));
2661 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2662 memset(i, 0, sizeof(swf_output_internal_t));
2663 swf_output->internal = i;
2665 i->outputDev = new SWFOutputDev();
2669 void swf_output_setparameter(swf_output_t*swf_output, char*name, char*value)
2672 pdfswf_setparameter(name, value);
2675 void swf_output_pagefeed(swf_output_t*swf)
2677 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2678 i->outputDev->pagefeed();
2679 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2682 int swf_output_save(swf_output_t*swf, char*filename)
2684 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2685 int ret = i->outputDev->save(filename);
2686 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2690 void* swf_output_get(swf_output_t*swf)
2692 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2693 void* ret = i->outputDev->getSWF();
2694 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2698 void swf_output_destroy(swf_output_t*output)
2700 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2701 delete i->outputDev; i->outputDev=0;
2702 free(output->internal);output->internal=0;
2706 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2708 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2709 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2712 gfxdevice_t*dev = si->outputDev->output;
2713 dev->setparameter(dev, "protect", "1");
2715 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2717 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2719 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2721 si->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2724 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2726 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2727 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2729 si->outputDev->setMove(x,y);
2730 if((x1|y1|x2|y2)==0) x2++;
2731 si->outputDev->setClip(x1,y1,x2,y2);
2733 pdf_page_render2(page, output);
2735 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2737 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2738 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2740 si->outputDev->setMove(0,0);
2741 si->outputDev->setClip(0,0,0,0);
2743 pdf_page_render2(page, output);
2747 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2749 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2750 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2751 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2752 memset(info, 0, sizeof(pdf_page_info_t));
2754 InfoOutputDev*output = new InfoOutputDev;
2757 pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2759 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2762 info->xMin = output->x1;
2763 info->yMin = output->y1;
2764 info->xMax = output->x2;
2765 info->yMax = output->y2;
2766 info->number_of_images = output->num_images;
2767 info->number_of_links = output->num_links;
2768 info->number_of_fonts = output->num_fonts;
2775 void pdf_page_info_destroy(pdf_page_info_t*info)