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);
162 void startFrame(int width, int height);
164 virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
169 //----- get info about output device
171 // Does this device use upside-down coordinates?
172 // (Upside-down means (0,0) is the top left corner of the page.)
173 virtual GBool upsideDown();
175 // Does this device use drawChar() or drawString()?
176 virtual GBool useDrawChar();
178 // Can this device draw gradients?
179 virtual GBool useGradients();
181 virtual GBool interpretType3Chars() {return gTrue;}
183 //----- initialization and control
185 void setXRef(PDFDoc*doc, XRef *xref);
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 textmodeinfo; // did we write "Text will be rendered as polygon" yet?
273 int jpeginfo; // did we write "File contains jpegs" yet?
274 int pbminfo; // did we write "File contains jpegs" yet?
275 int linkinfo; // did we write "File contains links" yet?
276 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
277 int gradientinfo; // did we write "File contains Gradients yet?
279 int type3active; // are we between beginType3()/endType3()?
285 char* substitutetarget[256];
286 char* substitutesource[256];
289 int user_movex,user_movey;
290 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
292 gfxline_t* current_text_stroke;
293 gfxline_t* current_text_clip;
294 char* current_font_id;
295 gfxfont_t* current_gfxfont;
296 gfxmatrix_t current_font_matrix;
298 fontlist_t* fontlist;
301 static char*getFontID(GfxFont*font);
303 class InfoOutputDev: public OutputDev
317 virtual ~InfoOutputDev()
320 virtual GBool upsideDown() {return gTrue;}
321 virtual GBool useDrawChar() {return gTrue;}
322 virtual GBool useGradients() {return gTrue;}
323 virtual GBool interpretType3Chars() {return gTrue;}
324 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
327 state->transform(crop_x1,crop_y1,&x1,&y1);
328 state->transform(crop_x2,crop_y2,&x2,&y2);
329 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
330 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
336 virtual void drawLink(Link *link, Catalog *catalog)
340 virtual void updateFont(GfxState *state)
342 GfxFont*font = state->getFont();
345 /*char*id = getFontID(font);*/
349 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
350 int width, int height, GBool invert,
355 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
356 int width, int height, GfxImageColorMap *colorMap,
357 int *maskColors, GBool inlineImg)
363 SWFOutputDev::SWFOutputDev()
381 current_text_stroke = 0;
382 current_text_clip = 0;
386 output = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
387 gfxdevice_swf_init(output);
388 /* configure device */
389 parameter_t*p = device_config;
391 output->setparameter(output, p->name, p->value);
396 void SWFOutputDev::setMove(int x,int y)
398 this->user_movex = x;
399 this->user_movey = y;
402 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
404 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
405 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
407 this->user_clipx1 = x1;
408 this->user_clipy1 = y1;
409 this->user_clipx2 = x2;
410 this->user_clipy2 = y2;
413 static char*getFontID(GfxFont*font)
415 GString*gstr = font->getName();
416 char* fontname = gstr==0?0:gstr->getCString();
420 sprintf(buf, "UFONT%d", r->num);
423 return strdup(fontname);
426 static char*getFontName(GfxFont*font)
428 char*fontid = getFontID(font);
430 char* plus = strchr(fontid, '+');
431 if(plus && plus < &fontid[strlen(fontid)-1]) {
432 fontname = strdup(plus+1);
434 fontname = strdup(fontid);
440 static char mybuf[1024];
441 static char* gfxstate2str(GfxState *state)
445 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
452 if(state->getX1()!=0.0)
453 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
454 if(state->getY1()!=0.0)
455 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
456 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
457 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
458 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
459 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
460 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
461 state->getFillColor()->c[0], state->getFillColor()->c[1]);
462 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
463 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
464 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
465 state->getFillColor()->c[0], state->getFillColor()->c[1],
466 state->getFillColor()->c[2], state->getFillColor()->c[3],
467 state->getFillColor()->c[4], state->getFillColor()->c[5],
468 state->getFillColor()->c[6], state->getFillColor()->c[7]);
469 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
470 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
471 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
472 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
473 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
474 state->getFillRGB(&rgb);
475 if(rgb.r || rgb.g || rgb.b)
476 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
477 state->getStrokeRGB(&rgb);
478 if(rgb.r || rgb.g || rgb.b)
479 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
480 if(state->getFillColorSpace()->getNComps()>1)
481 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
482 if(state->getStrokeColorSpace()->getNComps()>1)
483 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
484 if(state->getFillPattern())
485 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
486 if(state->getStrokePattern())
487 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
489 if(state->getFillOpacity()!=1.0)
490 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
491 if(state->getStrokeOpacity()!=1.0)
492 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
494 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
499 state->getLineDash(&dash, &length, &start);
503 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
504 for(t=0;t<length;t++) {
505 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
507 bufpos+=sprintf(bufpos,"]");
510 if(state->getFlatness()!=1)
511 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
512 if(state->getLineJoin()!=0)
513 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
514 if(state->getLineJoin()!=0)
515 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
516 if(state->getLineJoin()!=0)
517 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
519 if(state->getFont() && getFontID(state->getFont()))
520 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
521 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
522 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
523 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
524 if(state->getCharSpace())
525 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
526 if(state->getWordSpace())
527 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
528 if(state->getHorizScaling()!=1.0)
529 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
530 if(state->getLeading())
531 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
533 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
534 if(state->getRender())
535 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
536 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
537 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
538 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
539 if(state->getLineX())
540 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
541 if(state->getLineY())
542 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
543 bufpos+=sprintf(bufpos," ");
547 static void dumpFontInfo(char*loglevel, GfxFont*font);
548 static int lastdumps[1024];
549 static int lastdumppos = 0;
554 static void showFontError(GfxFont*font, int nr)
558 for(t=0;t<lastdumppos;t++)
559 if(lastdumps[t] == r->num)
563 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
564 lastdumps[lastdumppos++] = r->num;
566 msg("<warning> The following font caused problems:");
568 msg("<warning> The following font caused problems (substituting):");
570 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
571 dumpFontInfo("<warning>", font);
574 static void dumpFontInfo(char*loglevel, GfxFont*font)
576 char* id = getFontID(font);
577 char* name = getFontName(font);
578 Ref* r=font->getID();
579 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
581 GString*gstr = font->getTag();
583 msg("%s| Tag: %s\n", loglevel, id);
585 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
587 GfxFontType type=font->getType();
589 case fontUnknownType:
590 msg("%s| Type: unknown\n",loglevel);
593 msg("%s| Type: 1\n",loglevel);
596 msg("%s| Type: 1C\n",loglevel);
599 msg("%s| Type: 3\n",loglevel);
602 msg("%s| Type: TrueType\n",loglevel);
605 msg("%s| Type: CIDType0\n",loglevel);
608 msg("%s| Type: CIDType0C\n",loglevel);
611 msg("%s| Type: CIDType2\n",loglevel);
616 GBool embedded = font->getEmbeddedFontID(&embRef);
618 if(font->getEmbeddedFontName()) {
619 embeddedName = font->getEmbeddedFontName()->getCString();
622 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
624 gstr = font->getExtFontFile();
626 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
628 // Get font descriptor flags.
629 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
630 if(font->isSerif()) msg("%s| is serif\n", loglevel);
631 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
632 if(font->isItalic()) msg("%s| is italic\n", loglevel);
633 if(font->isBold()) msg("%s| is bold\n", loglevel);
639 //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");}
640 //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");}
643 void dump_outline(gfxline_t*line)
646 if(line->type == gfx_moveTo) {
647 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
648 } else if(line->type == gfx_lineTo) {
649 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
650 } else if(line->type == gfx_splineTo) {
651 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
657 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey)
659 int num = path->getNumSubpaths();
662 double lastx=0,lasty=0,posx=0,posy=0;
665 msg("<warning> empty path");
669 gfxdrawer_target_gfxline(&draw);
671 for(t = 0; t < num; t++) {
672 GfxSubpath *subpath = path->getSubpath(t);
673 int subnum = subpath->getNumPoints();
674 double bx=0,by=0,cx=0,cy=0;
676 for(s=0;s<subnum;s++) {
679 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
684 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
685 draw.lineTo(&draw, lastx, lasty);
687 draw.moveTo(&draw, x,y);
692 } else if(subpath->getCurve(s) && cpos==0) {
696 } else if(subpath->getCurve(s) && cpos==1) {
704 draw.lineTo(&draw, x,y);
706 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y);
713 /* fix non-closed lines */
714 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
715 draw.lineTo(&draw, lastx, lasty);
717 gfxline_t*result = (gfxline_t*)draw.result(&draw);
721 /*----------------------------------------------------------------------------
722 * Primitive Graphic routines
723 *----------------------------------------------------------------------------*/
725 void SWFOutputDev::stroke(GfxState *state)
727 GfxPath * path = state->getPath();
728 gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex, user_movey);
729 strokeGfxline(state, line);
733 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
735 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
736 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
737 double miterLimit = state->getMiterLimit();
738 double width = state->getTransformedLineWidth();
741 double opaq = state->getStrokeOpacity();
743 state->getFillRGB(&rgb);
745 state->getStrokeRGB(&rgb);
747 col.r = (unsigned char)(rgb.r*255);
748 col.g = (unsigned char)(rgb.g*255);
749 col.b = (unsigned char)(rgb.b*255);
750 col.a = (unsigned char)(opaq*255);
752 gfx_capType capType = gfx_capRound;
753 if(lineCap == 0) capType = gfx_capButt;
754 else if(lineCap == 1) capType = gfx_capRound;
755 else if(lineCap == 2) capType = gfx_capSquare;
757 gfx_joinType joinType = gfx_joinRound;
758 if(lineJoin == 0) joinType = gfx_joinMiter;
759 else if(lineJoin == 1) joinType = gfx_joinRound;
760 else if(lineJoin == 2) joinType = gfx_joinBevel;
763 double dashphase = 0;
765 state->getLineDash(&ldash, &dashnum, &dashphase);
769 if(dashnum && ldash) {
770 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
774 msg("<trace> %d dashes", dashnum);
775 msg("<trace> | phase: %f", dashphase);
776 for(t=0;t<dashnum;t++) {
778 msg("<trace> | d%-3d: %f", t, ldash[t]);
781 if(getLogLevel() >= LOGLEVEL_TRACE) {
785 line2 = gfxtool_dash_line(line, dash, dashphase);
788 msg("<trace> After dashing:");
791 if(getLogLevel() >= LOGLEVEL_TRACE) {
793 state->getStrokeGray(&gray);
794 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n",
796 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
797 lineCap==0?"butt": (lineJoin==1?"round":"square"),
799 col.r,col.g,col.b,col.a,
805 //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
806 output->stroke(output, line, width, &col, capType, joinType, miterLimit);
812 gfxcolor_t getFillColor(GfxState * state)
815 double opaq = state->getFillOpacity();
816 state->getFillRGB(&rgb);
818 col.r = (unsigned char)(rgb.r*255);
819 col.g = (unsigned char)(rgb.g*255);
820 col.b = (unsigned char)(rgb.b*255);
821 col.a = (unsigned char)(opaq*255);
825 void SWFOutputDev::fillGfxLine(GfxState *state, gfxline_t*line)
827 gfxcolor_t col = getFillColor(state);
829 if(getLogLevel() >= LOGLEVEL_TRACE) {
830 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
833 output->fill(output, line, &col);
835 void SWFOutputDev::fill(GfxState *state)
837 GfxPath * path = state->getPath();
838 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
839 fillGfxLine(state, line);
842 void SWFOutputDev::eoFill(GfxState *state)
844 GfxPath * path = state->getPath();
845 gfxcolor_t col = getFillColor(state);
847 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
849 if(getLogLevel() >= LOGLEVEL_TRACE) {
850 msg("<trace> eofill\n");
854 output->fill(output, line, &col);
858 void SWFOutputDev::clip(GfxState *state)
860 GfxPath * path = state->getPath();
861 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
862 clipToGfxLine(state, line);
866 void SWFOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line)
868 if(getLogLevel() >= LOGLEVEL_TRACE) {
869 msg("<trace> clip\n");
873 output->startclip(output, line);
874 states[statepos].clipping++;
876 void SWFOutputDev::eoClip(GfxState *state)
878 GfxPath * path = state->getPath();
879 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
881 if(getLogLevel() >= LOGLEVEL_TRACE) {
882 msg("<trace> eoclip\n");
886 output->startclip(output, line);
887 states[statepos].clipping++;
891 void SWFOutputDev::endframe()
894 output->endclip(output);
898 output->endpage(output);
901 void SWFOutputDev::finish()
905 output->endclip(output);
910 this->result = output->finish(output);
911 free(output);output=0;
915 int SWFOutputDev::save(char*filename)
918 return result->save(result, filename);
920 void* SWFOutputDev::getSWF()
923 return result->get(result, "swf");
926 SWFOutputDev::~SWFOutputDev()
931 this->result->destroy(this->result);
935 fontlist_t*l = this->fontlist;
937 fontlist_t*next = l->next;
939 gfxfont_free(l->font);
947 GBool SWFOutputDev::upsideDown()
951 GBool SWFOutputDev::useDrawChar()
955 GBool SWFOutputDev::useGradients()
959 msg("<notice> File contains gradients");
965 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
966 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
968 #define RENDER_FILL 0
969 #define RENDER_STROKE 1
970 #define RENDER_FILLSTROKE 2
971 #define RENDER_INVISIBLE 3
972 #define RENDER_CLIP 4
974 static char tmp_printstr[4096];
975 char* makeStringPrintable(char*str)
977 int len = strlen(str);
992 tmp_printstr[len++] = '.';
993 tmp_printstr[len++] = '.';
994 tmp_printstr[len++] = '.';
996 tmp_printstr[len] = 0;
1001 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
1005 for(t=0;t<font->num_glyphs;t++) {
1006 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
1007 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1011 /* if we didn't find the character, maybe
1012 we can find the capitalized version */
1013 for(t=0;t<font->num_glyphs;t++) {
1014 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
1015 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1021 /* try to use the unicode id */
1022 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
1023 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
1024 return font->unicode2glyph[u];
1027 /* we don't need to "draw" space characters, so don't overdo the search
1028 for a matching glyph */
1029 if(charname && !strcasecmp(charname, "space"))
1032 if(charnr>=0 && charnr<font->num_glyphs) {
1033 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1041 void SWFOutputDev::beginString(GfxState *state, GString *s)
1043 int render = state->getRender();
1044 if(current_text_stroke) {
1045 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
1048 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
1049 double m11,m21,m12,m22;
1050 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
1051 state->getFontTransMat(&m11, &m12, &m21, &m22);
1052 m11 *= state->getHorizScaling();
1053 m21 *= state->getHorizScaling();
1055 this->current_font_matrix.m00 = m11 / 1024.0;
1056 this->current_font_matrix.m01 = m12 / 1024.0;
1057 this->current_font_matrix.m10 = -m21 / 1024.0;
1058 this->current_font_matrix.m11 = -m22 / 1024.0;
1059 this->current_font_matrix.tx = 0;
1060 this->current_font_matrix.ty = 0;
1062 gfxmatrix_t m = this->current_font_matrix;
1064 /*if(render != 3 && render != 0)
1065 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1066 states[statepos].textRender = render;
1069 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1070 double dx, double dy,
1071 double originX, double originY,
1072 CharCode c, Unicode *_u, int uLen)
1074 int render = state->getRender();
1075 // check for invisible text -- this is used by Acrobat Capture
1079 if(states[statepos].textRender != render)
1080 msg("<error> Internal error: drawChar.render!=beginString.render");
1082 gfxcolor_t col = getFillColor(state);
1084 Gushort *CIDToGIDMap = 0;
1085 GfxFont*font = state->getFont();
1087 if(font->getType() == fontType3) {
1088 /* type 3 chars are passed as graphics */
1089 msg("<debug> type3 char at %f/%f", x, y);
1100 /* find out char name from unicode index
1101 TODO: should be precomputed
1103 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1104 if(nameToUnicodeTab[t].u == u) {
1105 name = nameToUnicodeTab[t].name;
1112 if(font->isCIDFont()) {
1113 GfxCIDFont*cfont = (GfxCIDFont*)font;
1115 if(font->getType() == fontCIDType2)
1116 CIDToGIDMap = cfont->getCIDToGID();
1119 font8 = (Gfx8BitFont*)font;
1120 char**enc=font8->getEncoding();
1125 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);
1128 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);
1131 int charid = getGfxCharID(current_gfxfont, c, name, u);
1133 if(strcasecmp(name, "space")) {
1134 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1135 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1140 gfxmatrix_t m = this->current_font_matrix;
1141 state->transform(x, y, &m.tx, &m.ty);
1145 if(render == RENDER_FILL) {
1146 output->drawchar(output, current_font_id, charid, &col, &m);
1148 msg("<debug> Drawing glyph %d as shape", charid);
1150 msg("<notice> Some texts will be rendered as shape");
1153 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1154 gfxline_t*tglyph = gfxline_clone(glyph);
1155 gfxline_transform(tglyph, &m);
1156 if((render&3) != RENDER_INVISIBLE) {
1157 gfxline_t*add = gfxline_clone(tglyph);
1158 current_text_stroke = gfxline_append(current_text_stroke, add);
1160 if(render&RENDER_CLIP) {
1161 gfxline_t*add = gfxline_clone(tglyph);
1162 current_text_clip = gfxline_append(current_text_clip, add);
1164 gfxline_free(tglyph);
1168 void SWFOutputDev::endString(GfxState *state)
1170 int render = state->getRender();
1171 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1172 if(states[statepos].textRender != render)
1173 msg("<error> Internal error: drawChar.render!=beginString.render");
1175 if(current_text_stroke) {
1176 /* fillstroke and stroke text rendering objects we can process right
1177 now (as there may be texts of other rendering modes in this
1178 text object)- clipping objects have to wait until endTextObject,
1180 if((render&3) == RENDER_FILL) {
1181 fillGfxLine(state, current_text_stroke);
1182 gfxline_free(current_text_stroke);
1183 current_text_stroke = 0;
1184 } else if((render&3) == RENDER_FILLSTROKE) {
1185 fillGfxLine(state, current_text_stroke);
1186 strokeGfxline(state, current_text_stroke);
1187 gfxline_free(current_text_stroke);
1188 current_text_stroke = 0;
1189 } else if((render&3) == RENDER_STROKE) {
1190 strokeGfxline(state, current_text_stroke);
1191 gfxline_free(current_text_stroke);
1192 current_text_stroke = 0;
1197 void SWFOutputDev::endTextObject(GfxState *state)
1199 int render = state->getRender();
1200 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1201 if(states[statepos].textRender != render)
1202 msg("<error> Internal error: drawChar.render!=beginString.render");
1204 if(current_text_clip) {
1205 clipToGfxLine(state, current_text_clip);
1206 gfxline_free(current_text_clip);
1207 current_text_clip = 0;
1211 /* the logic seems to be as following:
1212 first, beginType3Char is called, with the charcode and the coordinates.
1213 if this function returns true, it already knew about the char and has now drawn it.
1214 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1215 the all draw operations until endType3Char are part of the char (which in this moment is
1216 at the position first passed to beginType3Char). the char ends with endType3Char.
1218 The drawing operations between beginType3Char and endType3Char are somewhat different to
1219 the normal ones. For example, the fillcolor equals the stroke color.
1222 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1224 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1226 /* the character itself is going to be passed using the draw functions */
1227 return gFalse; /* gTrue= is_in_cache? */
1230 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1231 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1233 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1234 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1238 void SWFOutputDev::endType3Char(GfxState *state)
1241 msg("<debug> endType3Char");
1244 void SWFOutputDev::startFrame(int width, int height)
1246 output->startpage(output, width, height);
1249 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1251 this->currentpage = pageNum;
1253 int rot = doc->getPageRotate(1);
1256 gfxline_t clippath[5];
1258 white.r = white.g = white.b = white.a = 255;
1260 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1261 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1262 Use CropBox, not MediaBox, as page size
1269 state->transform(crop_x1,crop_y1,&x1,&y1); //x1 += user_movex; y1 += user_movey;
1270 state->transform(crop_x2,crop_y2,&x2,&y2); //x2 += user_movex; y2 += user_movey;
1272 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1273 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1276 /* apply user clip box */
1277 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1278 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1279 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1280 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1281 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1284 //msg("<verbose> Bounding box is (%f,%f)-(%f,%f) [shifted by %d/%d]", x1,y1,x2,y2, user_movex, user_movey);
1286 if(outer_clip_box) {
1287 output->endclip(output);
1291 msg("<notice> processing PDF page %d (%dx%d:%d:%d) (move:%d:%d)", pageNum, (int)x2-(int)x1,(int)y2-(int)y1, (int)x1, (int)y1, user_movex, user_movey);
1293 msg("<verbose> page is rotated %d degrees\n", rot);
1295 clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1296 clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1297 clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1298 clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1299 clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1300 output->startclip(output, clippath); outer_clip_box = 1;
1301 output->fill(output, clippath, &white);
1304 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1306 msg("<debug> drawlink\n");
1307 double x1, y1, x2, y2, w;
1309 gfxline_t points[5];
1313 link->getBorder(&x1, &y1, &x2, &y2, &w);
1315 link->getRect(&x1, &y1, &x2, &y2);
1320 cvtUserToDev(x1, y1, &x, &y);
1321 points[0].type = gfx_moveTo;
1322 points[0].x = points[4].x = x + user_movex;
1323 points[0].y = points[4].y = y + user_movey;
1324 points[0].next = &points[1];
1325 cvtUserToDev(x2, y1, &x, &y);
1326 points[1].type = gfx_lineTo;
1327 points[1].x = x + user_movex;
1328 points[1].y = y + user_movey;
1329 points[1].next = &points[2];
1330 cvtUserToDev(x2, y2, &x, &y);
1331 points[2].type = gfx_lineTo;
1332 points[2].x = x + user_movex;
1333 points[2].y = y + user_movey;
1334 points[2].next = &points[3];
1335 cvtUserToDev(x1, y2, &x, &y);
1336 points[3].type = gfx_lineTo;
1337 points[3].x = x + user_movex;
1338 points[3].y = y + user_movey;
1339 points[3].next = &points[4];
1340 cvtUserToDev(x1, y1, &x, &y);
1341 points[4].type = gfx_lineTo;
1342 points[4].x = x + user_movex;
1343 points[4].y = y + user_movey;
1346 LinkAction*action=link->getAction();
1353 switch(action->getKind())
1357 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1358 LinkDest *dest=NULL;
1359 if (ha->getDest()==NULL)
1360 dest=catalog->findDest(ha->getNamedDest());
1361 else dest=ha->getDest();
1363 if (dest->isPageRef()){
1364 Ref pageref=dest->getPageRef();
1365 page=catalog->findPage(pageref.num,pageref.gen);
1367 else page=dest->getPageNum();
1368 sprintf(buf, "%d", page);
1375 LinkGoToR*l = (LinkGoToR*)action;
1376 GString*g = l->getNamedDest();
1378 s = strdup(g->getCString());
1383 LinkNamed*l = (LinkNamed*)action;
1384 GString*name = l->getName();
1386 s = strdup(name->lowerCase()->getCString());
1387 named = name->getCString();
1390 if(strstr(s, "next") || strstr(s, "forward"))
1392 page = currentpage + 1;
1394 else if(strstr(s, "prev") || strstr(s, "back"))
1396 page = currentpage - 1;
1398 else if(strstr(s, "last") || strstr(s, "end"))
1400 page = pagepos>0?pages[pagepos-1]:0;
1402 else if(strstr(s, "first") || strstr(s, "top"))
1410 case actionLaunch: {
1412 LinkLaunch*l = (LinkLaunch*)action;
1413 GString * str = new GString(l->getFileName());
1414 str->append(l->getParams());
1415 s = strdup(str->getCString());
1421 LinkURI*l = (LinkURI*)action;
1422 GString*g = l->getURI();
1424 url = g->getCString();
1429 case actionUnknown: {
1431 LinkUnknown*l = (LinkUnknown*)action;
1436 msg("<error> Unknown link type!\n");
1440 if(!s) s = strdup("-?-");
1442 if(!linkinfo && (page || url))
1444 msg("<notice> File contains links");
1451 for(t=0;t<pagepos;t++)
1456 sprintf(buf, "page%d", t);
1457 output->drawlink(output, points, buf);
1462 output->drawlink(output, points, url);
1465 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1469 void SWFOutputDev::saveState(GfxState *state) {
1470 msg("<trace> saveState\n");
1473 msg("<error> Too many nested states in pdf.");
1477 states[statepos].clipping = 0; //? shouldn't this be the current value?
1478 states[statepos].textRender = states[statepos-1].textRender;
1481 void SWFOutputDev::restoreState(GfxState *state) {
1482 msg("<trace> restoreState\n");
1484 while(states[statepos].clipping) {
1485 output->endclip(output);
1486 states[statepos].clipping--;
1491 char* SWFOutputDev::searchFont(char*name)
1495 int is_standard_font = 0;
1497 msg("<verbose> SearchFont(%s)", name);
1499 /* see if it is a pdf standard font */
1500 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1502 if(!strcmp(name, pdf2t1map[i].pdffont))
1504 name = pdf2t1map[i].filename;
1505 is_standard_font = 1;
1509 /* look in all font files */
1510 for(i=0;i<fontnum;i++)
1512 if(strstr(fonts[i].filename, name))
1514 if(!fonts[i].used) {
1517 if(!is_standard_font)
1518 msg("<notice> Using %s for %s", fonts[i].filename, name);
1520 return strdup(fonts[i].filename);
1526 void SWFOutputDev::updateLineWidth(GfxState *state)
1528 double width = state->getTransformedLineWidth();
1529 //swfoutput_setlinewidth(&output, width);
1532 void SWFOutputDev::updateLineCap(GfxState *state)
1534 int c = state->getLineCap();
1537 void SWFOutputDev::updateLineJoin(GfxState *state)
1539 int j = state->getLineJoin();
1542 void SWFOutputDev::updateFillColor(GfxState *state)
1545 double opaq = state->getFillOpacity();
1546 state->getFillRGB(&rgb);
1548 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1551 void SWFOutputDev::updateStrokeColor(GfxState *state)
1554 double opaq = state->getStrokeOpacity();
1555 state->getStrokeRGB(&rgb);
1556 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1559 void FoFiWrite(void *stream, char *data, int len)
1561 fwrite(data, len, 1, (FILE*)stream);
1564 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1566 char*tmpFileName = NULL;
1572 Object refObj, strObj;
1574 tmpFileName = mktmpname(namebuf);
1577 ret = font->getEmbeddedFontID(&embRef);
1579 msg("<verbose> Didn't get embedded font id");
1580 /* not embedded- the caller should now search the font
1581 directories for this font */
1585 f = fopen(tmpFileName, "wb");
1587 msg("<error> Couldn't create temporary Type 1 font file");
1591 /*if(font->isCIDFont()) {
1592 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1593 GString c = cidFont->getCollection();
1594 msg("<notice> Collection: %s", c.getCString());
1597 //if (font->getType() == fontType1C) {
1598 if (0) { //font->getType() == fontType1C) {
1599 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1601 msg("<error> Couldn't read embedded font file");
1605 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1607 cvt->convertToType1(f);
1609 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1611 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1613 //cvt->convertToCIDType0("test", f);
1614 //cvt->convertToType0("test", f);
1617 } else if(font->getType() == fontTrueType) {
1618 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1619 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1621 msg("<error> Couldn't read embedded font file");
1625 TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1628 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1629 cvt->writeTTF(FoFiWrite, f);
1634 font->getEmbeddedFontID(&embRef);
1635 refObj.initRef(embRef.num, embRef.gen);
1636 refObj.fetch(ref, &strObj);
1638 strObj.streamReset();
1643 f4[t] = strObj.streamGetChar();
1644 f4c[t] = (char)f4[t];
1649 if(!strncmp(f4c, "true", 4)) {
1650 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1651 Change this on the fly */
1652 f4[0] = f4[2] = f4[3] = 0;
1660 while ((c = strObj.streamGetChar()) != EOF) {
1664 strObj.streamClose();
1669 return strdup(tmpFileName);
1672 char* searchForSuitableFont(GfxFont*gfxFont)
1674 char*name = getFontName(gfxFont);
1678 if(!config_use_fontconfig)
1681 #ifdef HAVE_FONTCONFIG
1682 FcPattern *pattern, *match;
1686 static int fcinitcalled = false;
1688 msg("<debug> searchForSuitableFont(%s)", name);
1690 // call init ony once
1691 if (!fcinitcalled) {
1692 msg("<debug> Initializing FontConfig...");
1693 fcinitcalled = true;
1695 msg("<debug> FontConfig Initialization failed. Disabling.");
1696 config_use_fontconfig = 0;
1699 msg("<debug> ...initialized FontConfig");
1702 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1703 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1704 if (gfxFont->isItalic()) // check for italic
1705 msg("<debug> FontConfig: Adding Italic Slant");
1706 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1707 if (gfxFont->isBold()) // check for bold
1708 msg("<debug> FontConfig: Adding Bold Weight");
1709 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1711 msg("<debug> FontConfig: Try to match...");
1712 // configure and match using the original font name
1713 FcConfigSubstitute(0, pattern, FcMatchPattern);
1714 FcDefaultSubstitute(pattern);
1715 match = FcFontMatch(0, pattern, &result);
1717 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1718 msg("<debug> FontConfig: family=%s", (char*)v);
1719 // if we get an exact match
1720 if (strcmp((char *)v, name) == 0) {
1721 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1722 filename = strdup((char*)v); // mem leak
1723 char *nfn = strrchr(filename, '/');
1724 if(nfn) fontname = strdup(nfn+1);
1725 else fontname = filename;
1727 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1729 // initialize patterns
1730 FcPatternDestroy(pattern);
1731 FcPatternDestroy(match);
1733 // now match against serif etc.
1734 if (gfxFont->isSerif()) {
1735 msg("<debug> FontConfig: Create Serif Family Pattern");
1736 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1737 } else if (gfxFont->isFixedWidth()) {
1738 msg("<debug> FontConfig: Create Monospace Family Pattern");
1739 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1741 msg("<debug> FontConfig: Create Sans Family Pattern");
1742 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1746 if (gfxFont->isItalic()) {
1747 msg("<debug> FontConfig: Adding Italic Slant");
1748 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1751 if (gfxFont->isBold()) {
1752 msg("<debug> FontConfig: Adding Bold Weight");
1753 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1756 msg("<debug> FontConfig: Try to match... (2)");
1757 // configure and match using serif etc
1758 FcConfigSubstitute (0, pattern, FcMatchPattern);
1759 FcDefaultSubstitute (pattern);
1760 match = FcFontMatch (0, pattern, &result);
1762 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1763 filename = strdup((char*)v); // mem leak
1764 char *nfn = strrchr(filename, '/');
1765 if(nfn) fontname = strdup(nfn+1);
1766 else fontname = filename;
1768 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1772 //printf("FONTCONFIG: pattern");
1773 //FcPatternPrint(pattern);
1774 //printf("FONTCONFIG: match");
1775 //FcPatternPrint(match);
1777 FcPatternDestroy(pattern);
1778 FcPatternDestroy(match);
1780 pdfswf_addfont(filename);
1787 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1789 char*fontname = 0, *filename = 0;
1790 msg("<notice> subsituteFont(%s)", oldname);
1792 if(!(fontname = searchForSuitableFont(gfxFont))) {
1793 fontname = "Times-Roman";
1795 filename = searchFont(fontname);
1797 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1801 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1802 msg("<fatal> Too many fonts in file.");
1806 substitutesource[substitutepos] = strdup(oldname); //mem leak
1807 substitutetarget[substitutepos] = fontname;
1808 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1811 return strdup(filename); //mem leak
1814 void unlinkfont(char* filename)
1821 if(!strncmp(&filename[l-4],".afm",4)) {
1822 memcpy(&filename[l-4],".pfb",4);
1824 memcpy(&filename[l-4],".pfa",4);
1826 memcpy(&filename[l-4],".afm",4);
1829 if(!strncmp(&filename[l-4],".pfa",4)) {
1830 memcpy(&filename[l-4],".afm",4);
1832 memcpy(&filename[l-4],".pfa",4);
1835 if(!strncmp(&filename[l-4],".pfb",4)) {
1836 memcpy(&filename[l-4],".afm",4);
1838 memcpy(&filename[l-4],".pfb",4);
1843 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1849 int SWFOutputDev::setGfxFont(char*id, char*filename)
1852 fontlist_t*last=0,*l = this->fontlist;
1854 /* TODO: should this be part of the state? */
1857 if(!strcmp(l->id, id)) {
1858 current_font_id = l->id;
1859 current_gfxfont = l->font;
1861 output->addfont(output, id, current_gfxfont);
1866 if(!filename) return 0;
1867 font = gfxfont_load(filename);
1870 l->filename = strdup(filename);
1873 current_font_id = l->id;
1874 current_gfxfont = l->font;
1880 output->addfont(output, id, current_gfxfont);
1884 void SWFOutputDev::updateFont(GfxState *state)
1886 GfxFont*gfxFont = state->getFont();
1891 char * fontid = getFontID(gfxFont);
1894 /* first, look if we substituted this font before-
1895 this way, we don't initialize the T1 Fonts
1897 for(t=0;t<substitutepos;t++) {
1898 if(!strcmp(fontid, substitutesource[t])) {
1899 free(fontid);fontid=0;
1900 fontid = strdup(substitutetarget[t]);
1905 /* second, see if this is a font which was used before-
1906 if so, we are done */
1907 if(setGfxFont(fontid, 0)) {
1911 /* if(swfoutput_queryfont(&output, fontid))
1912 swfoutput_setfont(&output, fontid, 0);
1914 msg("<debug> updateFont(%s) [cached]", fontid);
1918 // look for Type 3 font
1919 if (gfxFont->getType() == fontType3) {
1921 type3Warning = gTrue;
1922 showFontError(gfxFont, 2);
1928 /* now either load the font, or find a substitution */
1931 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1936 (gfxFont->getType() == fontType1 ||
1937 gfxFont->getType() == fontType1C ||
1938 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
1939 gfxFont->getType() == fontTrueType ||
1940 gfxFont->getType() == fontCIDType2
1943 fileName = writeEmbeddedFontToFile(xref, gfxFont);
1944 if(!fileName) showFontError(gfxFont,0);
1947 char * fontname = getFontName(gfxFont);
1948 fileName = searchFont(fontname);
1949 if(!fileName) showFontError(gfxFont,0);
1953 char * fontname = getFontName(gfxFont);
1954 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
1955 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
1956 fileName = substituteFont(gfxFont, fontid);
1957 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
1958 msg("<notice> Font is now %s (%s)", fontid, fileName);
1962 msg("<error> Couldn't set font %s\n", fontid);
1967 msg("<verbose> updateFont(%s) -> %s", fontid, fileName);
1968 dumpFontInfo("<verbose>", gfxFont);
1970 //swfoutput_setfont(&output, fontid, fileName);
1972 if(!setGfxFont(fontid, 0)) {
1973 setGfxFont(fontid, fileName);
1977 unlinkfont(fileName);
1983 #define SQR(x) ((x)*(x))
1985 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1987 if((newwidth<2 || newheight<2) ||
1988 (width<=newwidth || height<=newheight))
1990 unsigned char*newdata;
1992 newdata= (unsigned char*)malloc(newwidth*newheight);
1994 double fx = (double)(width)/newwidth;
1995 double fy = (double)(height)/newheight;
1997 int blocksize = (int)(8192/(fx*fy));
1998 int r = 8192*256/palettesize;
1999 for(x=0;x<newwidth;x++) {
2000 double ex = px + fx;
2001 int fromx = (int)px;
2003 int xweight1 = (int)(((fromx+1)-px)*256);
2004 int xweight2 = (int)((ex-tox)*256);
2006 for(y=0;y<newheight;y++) {
2007 double ey = py + fy;
2008 int fromy = (int)py;
2010 int yweight1 = (int)(((fromy+1)-py)*256);
2011 int yweight2 = (int)((ey-toy)*256);
2014 for(xx=fromx;xx<=tox;xx++)
2015 for(yy=fromy;yy<=toy;yy++) {
2016 int b = 1-data[width*yy+xx];
2018 if(xx==fromx) weight = (weight*xweight1)/256;
2019 if(xx==tox) weight = (weight*xweight2)/256;
2020 if(yy==fromy) weight = (weight*yweight1)/256;
2021 if(yy==toy) weight = (weight*yweight2)/256;
2024 //if(a) a=(palettesize-1)*r/blocksize;
2025 newdata[y*newwidth+x] = (a*blocksize)/r;
2033 #define IMAGE_TYPE_JPEG 0
2034 #define IMAGE_TYPE_LOSSLESS 1
2036 static void drawimage(gfxdevice_t*dev, RGBA* data, int sizex,int sizey,
2037 double x1,double y1,
2038 double x2,double y2,
2039 double x3,double y3,
2040 double x4,double y4, int type)
2044 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2045 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2047 gfxline_t p1,p2,p3,p4,p5;
2048 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2049 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2050 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2051 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2052 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2054 {p1.x = (int)(p1.x*20)/20.0;
2055 p1.y = (int)(p1.y*20)/20.0;
2056 p2.x = (int)(p2.x*20)/20.0;
2057 p2.y = (int)(p2.y*20)/20.0;
2058 p3.x = (int)(p3.x*20)/20.0;
2059 p3.y = (int)(p3.y*20)/20.0;
2060 p4.x = (int)(p4.x*20)/20.0;
2061 p4.y = (int)(p4.y*20)/20.0;
2062 p5.x = (int)(p5.x*20)/20.0;
2063 p5.y = (int)(p5.y*20)/20.0;
2070 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2071 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2076 img.data = (gfxcolor_t*)data;
2080 if(type == IMAGE_TYPE_JPEG)
2081 /* TODO: pass image_dpi to device instead */
2082 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2084 dev->fillbitmap(dev, &p1, &img, &m, 0);
2087 void drawimagejpeg(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
2088 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2090 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2093 void drawimagelossless(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
2094 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2096 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2100 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2101 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2102 GBool inlineImg, int mask, int*maskColors)
2107 double x1,y1,x2,y2,x3,y3,x4,y4;
2108 ImageStream *imgStr;
2115 ncomps = colorMap->getNumPixelComps();
2116 bits = colorMap->getBits();
2118 imgStr = new ImageStream(str, width, ncomps,bits);
2121 if(!width || !height || (height<=1 && width<=1))
2123 msg("<verbose> Ignoring %d by %d image", width, height);
2124 unsigned char buf[8];
2126 for (y = 0; y < height; ++y)
2127 for (x = 0; x < width; ++x) {
2128 imgStr->getPixel(buf);
2134 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1+= user_movey;
2135 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2+= user_movey;
2136 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3+= user_movey;
2137 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4+= user_movey;
2139 if(!pbminfo && !(str->getKind()==strDCT)) {
2141 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2145 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2147 if(!jpeginfo && (str->getKind()==strDCT)) {
2148 msg("<notice> file contains jpeg pictures");
2154 unsigned char buf[8];
2156 unsigned char*pic = new unsigned char[width*height];
2159 state->getFillRGB(&rgb);
2161 memset(pal,255,sizeof(pal));
2162 pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
2163 pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
2164 pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
2165 pal[0].a = 255; pal[1].a = 0;
2168 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2169 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2170 for (y = 0; y < height; ++y)
2171 for (x = 0; x < width; ++x)
2173 imgStr->getPixel(buf);
2176 pic[width*y+x] = buf[0];
2179 /* the size of the drawn image is added to the identifier
2180 as the same image may require different bitmaps if displayed
2181 at different sizes (due to antialiasing): */
2184 unsigned char*pic2 = 0;
2187 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2196 height = realheight;
2200 /* make a black/white palette */
2205 float r = 255/(numpalette-1);
2207 for(t=0;t<numpalette;t++) {
2208 pal[t].r = (U8)(255*rgb.r);
2209 pal[t].g = (U8)(255*rgb.g);
2210 pal[t].b = (U8)(255*rgb.b);
2211 pal[t].a = (U8)(t*r);
2215 RGBA*pic2 = new RGBA[width*height];
2216 for (y = 0; y < height; ++y) {
2217 for (x = 0; x < width; ++x) {
2218 pic2[width*y+x] = pal[pic[y*width+x]];
2221 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2230 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2231 RGBA*pic=new RGBA[width*height];
2232 for (y = 0; y < height; ++y) {
2233 for (x = 0; x < width; ++x) {
2234 imgStr->getPixel(pixBuf);
2235 colorMap->getRGB(pixBuf, &rgb);
2236 pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
2237 pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
2238 pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
2239 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2242 if(str->getKind()==strDCT)
2243 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2245 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2250 RGBA*pic=new RGBA[width*height];
2253 for(t=0;t<256;t++) {
2255 colorMap->getRGB(pixBuf, &rgb);
2256 /*if(maskColors && *maskColors==t) {
2257 msg("<notice> Color %d is transparent", t);
2258 if (imgData->maskColors) {
2260 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2261 if (pix[i] < imgData->maskColors[2*i] ||
2262 pix[i] > imgData->maskColors[2*i+1]) {
2277 pal[t].r = (U8)(rgb.r * 255 + 0.5);
2278 pal[t].g = (U8)(rgb.g * 255 + 0.5);
2279 pal[t].b = (U8)(rgb.b * 255 + 0.5);
2280 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2283 for (y = 0; y < height; ++y) {
2284 for (x = 0; x < width; ++x) {
2285 imgStr->getPixel(pixBuf);
2286 pic[width*y+x] = pal[pixBuf[0]];
2289 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2297 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2298 int width, int height, GBool invert,
2301 if(states[statepos].textRender & 4) //clipped
2303 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2304 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
2307 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2308 int width, int height, GfxImageColorMap *colorMap,
2309 int *maskColors, GBool inlineImg)
2311 if(states[statepos].textRender & 4) //clipped
2314 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
2315 colorMap?"colorMap":"no colorMap",
2316 maskColors?"maskColors":"no maskColors",
2319 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2320 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2321 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
2324 //SWFOutputDev*output = 0;
2326 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2331 if (infoDict->lookup(key, &obj)->isString()) {
2332 s1 = obj.getString();
2333 if ((s1->getChar(0) & 0xff) == 0xfe &&
2334 (s1->getChar(1) & 0xff) == 0xff) {
2336 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2337 if (s1->getChar(i) == '\0') {
2338 s2->append(s1->getChar(i+1));
2341 s2 = new GString("<unicode>");
2345 printf(fmt, s2->getCString());
2348 printf(fmt, s1->getCString());
2354 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2358 if (infoDict->lookup(key, &obj)->isString()) {
2359 s = obj.getString()->getCString();
2360 if (s[0] == 'D' && s[1] == ':') {
2371 void storeDeviceParameter(char*name, char*value)
2373 parameter_t*p = new parameter_t();
2374 p->name = strdup(name);
2375 p->value = strdup(value);
2377 if(device_config_next) {
2378 device_config_next->next = p;
2379 device_config_next = p;
2382 device_config_next = p;
2386 void pdfswf_setparameter(char*name, char*value)
2388 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2389 if(!strcmp(name, "caplinewidth")) {
2390 caplinewidth = atof(value);
2391 } else if(!strcmp(name, "zoom")) {
2394 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2395 storeDeviceParameter("jpegsubpixels", buf);
2396 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2397 storeDeviceParameter("ppmsubpixels", buf);
2398 } else if(!strcmp(name, "jpegdpi")) {
2400 jpeg_dpi = atoi(value);
2401 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2402 storeDeviceParameter("jpegsubpixels", buf);
2403 } else if(!strcmp(name, "ppmdpi")) {
2405 ppm_dpi = atoi(value);
2406 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2407 storeDeviceParameter("ppmsubpixels", buf);
2408 } else if(!strcmp(name, "forceType0Fonts")) {
2409 forceType0Fonts = atoi(value);
2410 } else if(!strcmp(name, "fontdir")) {
2411 pdfswf_addfontdir(value);
2412 } else if(!strcmp(name, "languagedir")) {
2413 pdfswf_addlanguagedir(value);
2414 } else if(!strcmp(name, "fontconfig")) {
2415 config_use_fontconfig = atoi(value);
2417 storeDeviceParameter(name,value);
2420 void pdfswf_addfont(char*filename)
2423 memset(&f, 0, sizeof(fontfile_t));
2424 f.filename = filename;
2425 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2426 fonts[fontnum++] = f;
2428 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2432 static char* dirseparator()
2441 void pdfswf_addlanguagedir(char*dir)
2444 globalParams = new GlobalParams("");
2446 msg("<notice> Adding %s to language pack directories", dir);
2450 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2451 strcpy(config_file, dir);
2452 strcat(config_file, dirseparator());
2453 strcat(config_file, "add-to-xpdfrc");
2455 fi = fopen(config_file, "rb");
2457 msg("<error> Could not open %s", config_file);
2460 globalParams->parseFile(new GString(config_file), fi);
2464 void pdfswf_addfontdir(char*dirname)
2466 #ifdef HAVE_DIRENT_H
2467 msg("<notice> Adding %s to font directories", dirname);
2468 DIR*dir = opendir(dirname);
2470 msg("<warning> Couldn't open directory %s\n", dirname);
2475 ent = readdir (dir);
2479 char*name = ent->d_name;
2485 if(!strncasecmp(&name[l-4], ".pfa", 4))
2487 if(!strncasecmp(&name[l-4], ".pfb", 4))
2489 if(!strncasecmp(&name[l-4], ".ttf", 4))
2493 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2494 strcpy(fontname, dirname);
2495 strcat(fontname, dirseparator());
2496 strcat(fontname, name);
2497 msg("<verbose> Adding %s to fonts", fontname);
2498 pdfswf_addfont(fontname);
2503 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2508 typedef struct _pdf_doc_internal
2512 } pdf_doc_internal_t;
2513 typedef struct _pdf_page_internal
2515 } pdf_page_internal_t;
2516 typedef struct _swf_output_internal
2518 SWFOutputDev*outputDev;
2519 } swf_output_internal_t;
2521 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2523 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2524 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2525 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2526 memset(i, 0, sizeof(pdf_doc_internal_t));
2527 pdf_doc->internal = i;
2529 GString *fileName = new GString(filename);
2535 globalParams = new GlobalParams("");
2538 if (userPassword && userPassword[0]) {
2539 userPW = new GString(userPassword);
2543 i->doc = new PDFDoc(fileName, userPW);
2547 if (!i->doc->isOk()) {
2552 i->doc->getDocInfo(&info);
2553 if (info.isDict() &&
2554 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2555 printInfoString(info.getDict(), "Title", "Title: %s\n");
2556 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2557 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2558 printInfoString(info.getDict(), "Author", "Author: %s\n");
2559 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2560 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2561 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2562 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2563 printf("Pages: %d\n", i->doc->getNumPages());
2564 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2565 printf("Encrypted: ");
2566 if (i->doc->isEncrypted()) {
2567 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2568 i->doc->okToPrint() ? "yes" : "no",
2569 i->doc->okToCopy() ? "yes" : "no",
2570 i->doc->okToChange() ? "yes" : "no",
2571 i->doc->okToAddNotes() ? "yes" : "no");
2578 pdf_doc->num_pages = i->doc->getNumPages();
2580 if (i->doc->isEncrypted()) {
2581 if(!i->doc->okToCopy()) {
2582 printf("PDF disallows copying.\n");
2585 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2592 static void pdfswf_preparepage(int page)
2596 pages = (int*)malloc(1024*sizeof(int));
2599 if(pagepos == pagebuflen)
2602 pages = (int*)realloc(pages, pagebuflen);
2605 pages[pagepos++] = page;
2612 delete globalParams;globalParams=0;
2613 Object::memCheck(stderr);
2618 void pdf_destroy(pdf_doc_t*pdf_doc)
2620 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2622 delete i->doc; i->doc=0;
2624 free(pages); pages = 0; //FIXME
2626 free(pdf_doc->internal);pdf_doc->internal=0;
2627 free(pdf_doc);pdf_doc=0;
2630 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2632 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2634 if(page < 1 || page > pdf_doc->num_pages)
2637 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2638 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2639 memset(pi, 0, sizeof(pdf_page_internal_t));
2640 pdf_page->internal = pi;
2642 pdf_page->parent = pdf_doc;
2643 pdf_page->nr = page;
2647 void pdf_page_destroy(pdf_page_t*pdf_page)
2649 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2650 free(pdf_page->internal);pdf_page->internal = 0;
2651 free(pdf_page);pdf_page=0;
2654 swf_output_t* swf_output_init()
2656 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2657 memset(swf_output, 0, sizeof(swf_output_t));
2658 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2659 memset(i, 0, sizeof(swf_output_internal_t));
2660 swf_output->internal = i;
2662 i->outputDev = new SWFOutputDev();
2666 void swf_output_setparameter(swf_output_t*swf, char*name, char*value)
2668 pdfswf_setparameter(name, value);
2671 void swf_output_startframe(swf_output_t*swf, int width, int height)
2673 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2674 i->outputDev->startFrame(width, height);
2677 void swf_output_endframe(swf_output_t*swf)
2679 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2680 i->outputDev->endframe();
2683 int swf_output_save(swf_output_t*swf, char*filename)
2685 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2686 int ret = i->outputDev->save(filename);
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();
2697 void swf_output_destroy(swf_output_t*output)
2699 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2700 delete i->outputDev; i->outputDev=0;
2701 free(output->internal);output->internal=0;
2705 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2707 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2708 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2711 gfxdevice_t*dev = si->outputDev->output;
2712 dev->setparameter(dev, "protect", "1");
2714 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2716 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2718 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2722 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2724 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2725 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2727 si->outputDev->setMove(x,y);
2728 if((x1|y1|x2|y2)==0) x2++;
2729 si->outputDev->setClip(x1,y1,x2,y2);
2731 pdf_page_render2(page, output);
2733 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2735 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2736 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2738 si->outputDev->setMove(0,0);
2739 si->outputDev->setClip(0,0,0,0);
2741 pdf_page_render2(page, output);
2745 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2747 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2748 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2749 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2750 memset(info, 0, sizeof(pdf_page_info_t));
2752 InfoOutputDev*output = new InfoOutputDev;
2755 pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2757 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2760 info->xMin = output->x1;
2761 info->yMin = output->y1;
2762 info->xMax = output->x2;
2763 info->yMax = output->y2;
2764 info->number_of_images = output->num_images;
2765 info->number_of_links = output->num_links;
2766 info->number_of_fonts = output->num_fonts;
2773 void pdf_page_info_destroy(pdf_page_info_t*info)