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 void getDimensions(int*x1,int*y1,int*x2,int*y2);
171 //----- get info about output device
173 // Does this device use upside-down coordinates?
174 // (Upside-down means (0,0) is the top left corner of the page.)
175 virtual GBool upsideDown();
177 // Does this device use drawChar() or drawString()?
178 virtual GBool useDrawChar();
180 // Can this device draw gradients?
181 virtual GBool useGradients();
183 virtual GBool interpretType3Chars() {return gTrue;}
185 //----- initialization and control
187 void setXRef(PDFDoc*doc, XRef *xref);
190 virtual void drawLink(Link *link, Catalog *catalog) ;
192 //----- save/restore graphics state
193 virtual void saveState(GfxState *state) ;
194 virtual void restoreState(GfxState *state) ;
196 //----- update graphics state
198 virtual void updateFont(GfxState *state);
199 virtual void updateFillColor(GfxState *state);
200 virtual void updateStrokeColor(GfxState *state);
201 virtual void updateLineWidth(GfxState *state);
202 virtual void updateLineJoin(GfxState *state);
203 virtual void updateLineCap(GfxState *state);
205 virtual void updateAll(GfxState *state)
208 updateFillColor(state);
209 updateStrokeColor(state);
210 updateLineWidth(state);
211 updateLineJoin(state);
212 updateLineCap(state);
215 //----- path painting
216 virtual void stroke(GfxState *state) ;
217 virtual void fill(GfxState *state) ;
218 virtual void eoFill(GfxState *state) ;
220 //----- path clipping
221 virtual void clip(GfxState *state) ;
222 virtual void eoClip(GfxState *state) ;
225 virtual void beginString(GfxState *state, GString *s) ;
226 virtual void endString(GfxState *state) ;
227 virtual void endTextObject(GfxState *state);
228 virtual void drawChar(GfxState *state, double x, double y,
229 double dx, double dy,
230 double originX, double originY,
231 CharCode code, Unicode *u, int uLen);
233 //----- image drawing
234 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
235 int width, int height, GBool invert,
237 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
238 int width, int height, GfxImageColorMap *colorMap,
239 int *maskColors, GBool inlineImg);
241 virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
242 virtual void endType3Char(GfxState *state);
244 virtual void type3D0(GfxState *state, double wx, double wy);
245 virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
248 void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
249 int width, int height, GfxImageColorMap*colorMap, GBool invert,
250 GBool inlineImg, int mask, int *maskColors);
251 int SWFOutputDev::setGfxFont(char*id, char*filename);
252 void strokeGfxline(GfxState *state, gfxline_t*line);
253 void clipToGfxLine(GfxState *state, gfxline_t*line);
254 void fillGfxLine(GfxState *state, gfxline_t*line);
258 gfxresult_t*result; //filled when complete
260 char outer_clip_box; //whether the page clip box is still on
262 SWFOutputState states[64];
270 char* searchFont(char*name);
271 char* substituteFont(GfxFont*gfxFont, char*oldname);
272 char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
274 int jpeginfo; // did we write "File contains jpegs" yet?
275 int pbminfo; // did we write "File contains jpegs" yet?
276 int linkinfo; // did we write "File contains links" yet?
277 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
278 int gradientinfo; // did we write "File contains Gradients yet?
280 int type3active; // are we between beginType3()/endType3()?
286 char* substitutetarget[256];
287 char* substitutesource[256];
290 int user_movex,user_movey;
291 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
293 gfxline_t* current_text_stroke;
294 gfxline_t* current_text_clip;
295 char* current_font_id;
296 gfxfont_t* current_gfxfont;
297 gfxmatrix_t current_font_matrix;
299 fontlist_t* fontlist;
302 static char*getFontID(GfxFont*font);
304 class InfoOutputDev: public OutputDev
318 virtual ~InfoOutputDev()
321 virtual GBool upsideDown() {return gTrue;}
322 virtual GBool useDrawChar() {return gTrue;}
323 virtual GBool useGradients() {return gTrue;}
324 virtual GBool interpretType3Chars() {return gTrue;}
325 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
328 state->transform(crop_x1,crop_y1,&x1,&y1);
329 state->transform(crop_x2,crop_y2,&x2,&y2);
330 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
331 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
337 virtual void drawLink(Link *link, Catalog *catalog)
341 virtual void updateFont(GfxState *state)
343 GfxFont*font = state->getFont();
346 /*char*id = getFontID(font);*/
350 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
351 int width, int height, GBool invert,
356 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
357 int width, int height, GfxImageColorMap *colorMap,
358 int *maskColors, GBool inlineImg)
364 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 void SWFOutputDev::getDimensions(int*x1,int*y1,int*x2,int*y2)
416 *x1 = (int)result->get(result, "xmin");
417 *y1 = (int)result->get(result, "ymin");
418 *x2 = (int)result->get(result, "xmax");
419 *y2 = (int)result->get(result, "ymax");
421 *x1 = *y1 = *x2 = *y2 = 0;
425 static char*getFontID(GfxFont*font)
427 GString*gstr = font->getName();
428 char* fontname = gstr==0?0:gstr->getCString();
432 sprintf(buf, "UFONT%d", r->num);
435 return strdup(fontname);
438 static char*getFontName(GfxFont*font)
440 char*fontid = getFontID(font);
442 char* plus = strchr(fontid, '+');
443 if(plus && plus < &fontid[strlen(fontid)-1]) {
444 fontname = strdup(plus+1);
446 fontname = strdup(fontid);
452 static char mybuf[1024];
453 static char* gfxstate2str(GfxState *state)
457 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
464 if(state->getX1()!=0.0)
465 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
466 if(state->getY1()!=0.0)
467 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
468 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
469 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
470 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
471 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
472 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
473 state->getFillColor()->c[0], state->getFillColor()->c[1]);
474 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
475 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
476 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
477 state->getFillColor()->c[0], state->getFillColor()->c[1],
478 state->getFillColor()->c[2], state->getFillColor()->c[3],
479 state->getFillColor()->c[4], state->getFillColor()->c[5],
480 state->getFillColor()->c[6], state->getFillColor()->c[7]);
481 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
482 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
483 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
484 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
485 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
486 state->getFillRGB(&rgb);
487 if(rgb.r || rgb.g || rgb.b)
488 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
489 state->getStrokeRGB(&rgb);
490 if(rgb.r || rgb.g || rgb.b)
491 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
492 if(state->getFillColorSpace()->getNComps()>1)
493 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
494 if(state->getStrokeColorSpace()->getNComps()>1)
495 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
496 if(state->getFillPattern())
497 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
498 if(state->getStrokePattern())
499 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
501 if(state->getFillOpacity()!=1.0)
502 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
503 if(state->getStrokeOpacity()!=1.0)
504 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
506 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
511 state->getLineDash(&dash, &length, &start);
515 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
516 for(t=0;t<length;t++) {
517 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
519 bufpos+=sprintf(bufpos,"]");
522 if(state->getFlatness()!=1)
523 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
524 if(state->getLineJoin()!=0)
525 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
526 if(state->getLineJoin()!=0)
527 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
528 if(state->getLineJoin()!=0)
529 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
531 if(state->getFont() && getFontID(state->getFont()))
532 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
533 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
534 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
535 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
536 if(state->getCharSpace())
537 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
538 if(state->getWordSpace())
539 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
540 if(state->getHorizScaling()!=1.0)
541 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
542 if(state->getLeading())
543 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
545 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
546 if(state->getRender())
547 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
548 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
549 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
550 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
551 if(state->getLineX())
552 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
553 if(state->getLineY())
554 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
555 bufpos+=sprintf(bufpos," ");
559 static void dumpFontInfo(char*loglevel, GfxFont*font);
560 static int lastdumps[1024];
561 static int lastdumppos = 0;
566 static void showFontError(GfxFont*font, int nr)
570 for(t=0;t<lastdumppos;t++)
571 if(lastdumps[t] == r->num)
575 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
576 lastdumps[lastdumppos++] = r->num;
578 msg("<warning> The following font caused problems:");
580 msg("<warning> The following font caused problems (substituting):");
582 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
583 dumpFontInfo("<warning>", font);
586 static void dumpFontInfo(char*loglevel, GfxFont*font)
588 char* id = getFontID(font);
589 char* name = getFontName(font);
590 Ref* r=font->getID();
591 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
593 GString*gstr = font->getTag();
595 msg("%s| Tag: %s\n", loglevel, id);
597 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
599 GfxFontType type=font->getType();
601 case fontUnknownType:
602 msg("%s| Type: unknown\n",loglevel);
605 msg("%s| Type: 1\n",loglevel);
608 msg("%s| Type: 1C\n",loglevel);
611 msg("%s| Type: 3\n",loglevel);
614 msg("%s| Type: TrueType\n",loglevel);
617 msg("%s| Type: CIDType0\n",loglevel);
620 msg("%s| Type: CIDType0C\n",loglevel);
623 msg("%s| Type: CIDType2\n",loglevel);
628 GBool embedded = font->getEmbeddedFontID(&embRef);
630 if(font->getEmbeddedFontName()) {
631 embeddedName = font->getEmbeddedFontName()->getCString();
634 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
636 gstr = font->getExtFontFile();
638 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
640 // Get font descriptor flags.
641 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
642 if(font->isSerif()) msg("%s| is serif\n", loglevel);
643 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
644 if(font->isItalic()) msg("%s| is italic\n", loglevel);
645 if(font->isBold()) msg("%s| is bold\n", loglevel);
651 //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");}
652 //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");}
655 void dump_outline(gfxline_t*line)
658 if(line->type == gfx_moveTo) {
659 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
660 } else if(line->type == gfx_lineTo) {
661 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
662 } else if(line->type == gfx_splineTo) {
663 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
669 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey)
671 int num = path->getNumSubpaths();
674 double lastx=0,lasty=0,posx=0,posy=0;
677 msg("<warning> empty path");
681 gfxdrawer_target_gfxline(&draw);
683 for(t = 0; t < num; t++) {
684 GfxSubpath *subpath = path->getSubpath(t);
685 int subnum = subpath->getNumPoints();
686 double bx=0,by=0,cx=0,cy=0;
688 for(s=0;s<subnum;s++) {
691 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
696 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
697 draw.lineTo(&draw, lastx, lasty);
699 draw.moveTo(&draw, x,y);
704 } else if(subpath->getCurve(s) && cpos==0) {
708 } else if(subpath->getCurve(s) && cpos==1) {
716 draw.lineTo(&draw, x,y);
718 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y);
725 /* fix non-closed lines */
726 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
727 draw.lineTo(&draw, lastx, lasty);
729 gfxline_t*result = (gfxline_t*)draw.result(&draw);
733 /*----------------------------------------------------------------------------
734 * Primitive Graphic routines
735 *----------------------------------------------------------------------------*/
737 void SWFOutputDev::stroke(GfxState *state)
739 GfxPath * path = state->getPath();
740 gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex, user_movey);
741 strokeGfxline(state, line);
745 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
747 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
748 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
749 double miterLimit = state->getMiterLimit();
750 double width = state->getTransformedLineWidth();
753 double opaq = state->getStrokeOpacity();
755 state->getFillRGB(&rgb);
757 state->getStrokeRGB(&rgb);
759 col.r = (unsigned char)(rgb.r*255);
760 col.g = (unsigned char)(rgb.g*255);
761 col.b = (unsigned char)(rgb.b*255);
762 col.a = (unsigned char)(opaq*255);
764 gfx_capType capType = gfx_capRound;
765 if(lineCap == 0) capType = gfx_capButt;
766 else if(lineCap == 1) capType = gfx_capRound;
767 else if(lineCap == 2) capType = gfx_capSquare;
769 gfx_joinType joinType = gfx_joinRound;
770 if(lineJoin == 0) joinType = gfx_joinMiter;
771 else if(lineJoin == 1) joinType = gfx_joinRound;
772 else if(lineJoin == 2) joinType = gfx_joinBevel;
775 double dashphase = 0;
777 state->getLineDash(&ldash, &dashnum, &dashphase);
781 if(dashnum && ldash) {
782 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
786 msg("<trace> %d dashes", dashnum);
787 msg("<trace> | phase: %f", dashphase);
788 for(t=0;t<dashnum;t++) {
790 msg("<trace> | d%-3d: %f", t, ldash[t]);
793 if(getLogLevel() >= LOGLEVEL_TRACE) {
797 line2 = gfxtool_dash_line(line, dash, dashphase);
800 msg("<trace> After dashing:");
803 if(getLogLevel() >= LOGLEVEL_TRACE) {
805 state->getStrokeGray(&gray);
806 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n",
808 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
809 lineCap==0?"butt": (lineJoin==1?"round":"square"),
811 col.r,col.g,col.b,col.a,
817 //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
818 output->stroke(output, line, width, &col, capType, joinType, miterLimit);
824 gfxcolor_t getFillColor(GfxState * state)
827 double opaq = state->getFillOpacity();
828 state->getFillRGB(&rgb);
830 col.r = (unsigned char)(rgb.r*255);
831 col.g = (unsigned char)(rgb.g*255);
832 col.b = (unsigned char)(rgb.b*255);
833 col.a = (unsigned char)(opaq*255);
837 void SWFOutputDev::fillGfxLine(GfxState *state, gfxline_t*line)
839 gfxcolor_t col = getFillColor(state);
841 if(getLogLevel() >= LOGLEVEL_TRACE) {
842 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
845 output->fill(output, line, &col);
847 void SWFOutputDev::fill(GfxState *state)
849 GfxPath * path = state->getPath();
850 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
851 fillGfxLine(state, line);
854 void SWFOutputDev::eoFill(GfxState *state)
856 GfxPath * path = state->getPath();
857 gfxcolor_t col = getFillColor(state);
859 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
861 if(getLogLevel() >= LOGLEVEL_TRACE) {
862 msg("<trace> eofill\n");
866 output->fill(output, line, &col);
870 void SWFOutputDev::clip(GfxState *state)
872 GfxPath * path = state->getPath();
873 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
874 clipToGfxLine(state, line);
878 void SWFOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line)
880 if(getLogLevel() >= LOGLEVEL_TRACE) {
881 msg("<trace> clip\n");
885 output->startclip(output, line);
886 states[statepos].clipping++;
888 void SWFOutputDev::eoClip(GfxState *state)
890 GfxPath * path = state->getPath();
891 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex, user_movey);
893 if(getLogLevel() >= LOGLEVEL_TRACE) {
894 msg("<trace> eoclip\n");
898 output->startclip(output, line);
899 states[statepos].clipping++;
903 void SWFOutputDev::endframe()
906 output->endclip(output);
910 output->endpage(output);
913 void SWFOutputDev::finish()
917 output->endclip(output);
922 this->result = output->finish(output);
923 free(output);output=0;
927 int SWFOutputDev::save(char*filename)
930 return result->save(result, filename);
932 void* SWFOutputDev::getSWF()
935 return result->get(result, "swf");
938 SWFOutputDev::~SWFOutputDev()
943 this->result->destroy(this->result);
947 fontlist_t*l = this->fontlist;
949 fontlist_t*next = l->next;
951 gfxfont_free(l->font);
959 GBool SWFOutputDev::upsideDown()
963 GBool SWFOutputDev::useDrawChar()
967 GBool SWFOutputDev::useGradients()
971 msg("<notice> File contains gradients");
977 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
978 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
980 #define RENDER_FILL 0
981 #define RENDER_STROKE 1
982 #define RENDER_FILLSTROKE 2
983 #define RENDER_INVISIBLE 3
984 #define RENDER_CLIP 4
986 static char tmp_printstr[4096];
987 char* makeStringPrintable(char*str)
989 int len = strlen(str);
1001 tmp_printstr[t] = c;
1004 tmp_printstr[len++] = '.';
1005 tmp_printstr[len++] = '.';
1006 tmp_printstr[len++] = '.';
1008 tmp_printstr[len] = 0;
1009 return tmp_printstr;
1013 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
1017 for(t=0;t<font->num_glyphs;t++) {
1018 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
1019 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1023 /* if we didn't find the character, maybe
1024 we can find the capitalized version */
1025 for(t=0;t<font->num_glyphs;t++) {
1026 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
1027 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1033 /* try to use the unicode id */
1034 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
1035 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
1036 return font->unicode2glyph[u];
1039 if(charnr>=0 && charnr<font->num_glyphs) {
1040 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1048 void SWFOutputDev::beginString(GfxState *state, GString *s)
1050 int render = state->getRender();
1051 if(current_text_stroke) {
1052 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
1055 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
1056 double m11,m21,m12,m22;
1057 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
1058 state->getFontTransMat(&m11, &m12, &m21, &m22);
1059 m11 *= state->getHorizScaling();
1060 m21 *= state->getHorizScaling();
1062 this->current_font_matrix.m00 = m11 / 1024.0;
1063 this->current_font_matrix.m01 = m12 / 1024.0;
1064 this->current_font_matrix.m10 = -m21 / 1024.0;
1065 this->current_font_matrix.m11 = -m22 / 1024.0;
1066 this->current_font_matrix.tx = 0;
1067 this->current_font_matrix.ty = 0;
1069 gfxmatrix_t m = this->current_font_matrix;
1071 /*if(render != 3 && render != 0)
1072 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1073 states[statepos].textRender = render;
1076 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1077 double dx, double dy,
1078 double originX, double originY,
1079 CharCode c, Unicode *_u, int uLen)
1081 int render = state->getRender();
1082 // check for invisible text -- this is used by Acrobat Capture
1086 if(states[statepos].textRender != render)
1087 msg("<error> Internal error: drawChar.render!=beginString.render");
1089 gfxcolor_t col = getFillColor(state);
1091 Gushort *CIDToGIDMap = 0;
1092 GfxFont*font = state->getFont();
1094 if(font->getType() == fontType3) {
1095 /* type 3 chars are passed as graphics */
1096 msg("<debug> type3 char at %f/%f", x, y);
1107 /* find out char name from unicode index
1108 TODO: should be precomputed
1110 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1111 if(nameToUnicodeTab[t].u == u) {
1112 name = nameToUnicodeTab[t].name;
1119 if(font->isCIDFont()) {
1120 GfxCIDFont*cfont = (GfxCIDFont*)font;
1122 if(font->getType() == fontCIDType2)
1123 CIDToGIDMap = cfont->getCIDToGID();
1126 font8 = (Gfx8BitFont*)font;
1127 char**enc=font8->getEncoding();
1132 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);
1135 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);
1138 int charid = getGfxCharID(current_gfxfont, c, name, u);
1140 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1141 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1145 gfxmatrix_t m = this->current_font_matrix;
1146 state->transform(x, y, &m.tx, &m.ty);
1150 if(render == RENDER_FILL) {
1151 output->drawchar(output, current_font_id, charid, &col, &m);
1153 msg("<debug> Drawing glyph %d as shape", charid);
1154 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1155 gfxline_t*tglyph = gfxline_clone(glyph);
1156 gfxline_transform(tglyph, &m);
1157 if((render&3) != RENDER_INVISIBLE) {
1158 gfxline_t*add = gfxline_clone(tglyph);
1159 current_text_stroke = gfxline_append(current_text_stroke, add);
1161 if(render&RENDER_CLIP) {
1162 gfxline_t*add = gfxline_clone(tglyph);
1163 current_text_clip = gfxline_append(current_text_clip, add);
1165 gfxline_free(tglyph);
1169 void SWFOutputDev::endString(GfxState *state)
1171 int render = state->getRender();
1172 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1173 if(states[statepos].textRender != render)
1174 msg("<error> Internal error: drawChar.render!=beginString.render");
1176 if(current_text_stroke) {
1177 /* fillstroke and stroke text rendering objects we can process right
1178 now (as there may be texts of other rendering modes in this
1179 text object)- clipping objects have to wait until endTextObject,
1181 if((render&3) == RENDER_FILL) {
1182 fillGfxLine(state, current_text_stroke);
1183 gfxline_free(current_text_stroke);
1184 current_text_stroke = 0;
1185 } else if((render&3) == RENDER_FILLSTROKE) {
1186 fillGfxLine(state, current_text_stroke);
1187 strokeGfxline(state, current_text_stroke);
1188 gfxline_free(current_text_stroke);
1189 current_text_stroke = 0;
1190 } else if((render&3) == RENDER_STROKE) {
1191 strokeGfxline(state, current_text_stroke);
1192 gfxline_free(current_text_stroke);
1193 current_text_stroke = 0;
1198 void SWFOutputDev::endTextObject(GfxState *state)
1200 int render = state->getRender();
1201 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1202 if(states[statepos].textRender != render)
1203 msg("<error> Internal error: drawChar.render!=beginString.render");
1205 if(current_text_clip) {
1206 clipToGfxLine(state, current_text_clip);
1207 gfxline_free(current_text_clip);
1208 current_text_clip = 0;
1212 /* the logic seems to be as following:
1213 first, beginType3Char is called, with the charcode and the coordinates.
1214 if this function returns true, it already knew about the char and has now drawn it.
1215 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1216 the all draw operations until endType3Char are part of the char (which in this moment is
1217 at the position first passed to beginType3Char). the char ends with endType3Char.
1219 The drawing operations between beginType3Char and endType3Char are somewhat different to
1220 the normal ones. For example, the fillcolor equals the stroke color.
1223 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1225 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1227 /* the character itself is going to be passed using the draw functions */
1228 return gFalse; /* gTrue= is_in_cache? */
1231 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1232 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1234 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1235 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1239 void SWFOutputDev::endType3Char(GfxState *state)
1242 msg("<debug> endType3Char");
1245 void SWFOutputDev::startFrame(int width, int height)
1247 output->startpage(output, width, height);
1250 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1252 this->currentpage = pageNum;
1254 int rot = doc->getPageRotate(1);
1257 gfxline_t clippath[5];
1259 white.r = white.g = white.b = white.a = 255;
1261 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1262 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1263 Use CropBox, not MediaBox, as page size
1270 state->transform(crop_x1,crop_y1,&x1,&y1); //x1 += user_movex; y1 += user_movey;
1271 state->transform(crop_x2,crop_y2,&x2,&y2); //x2 += user_movex; y2 += user_movey;
1273 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1274 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1277 /* apply user clip box */
1278 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1279 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1280 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1281 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1282 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1285 //msg("<verbose> Bounding box is (%f,%f)-(%f,%f) [shifted by %d/%d]", x1,y1,x2,y2, user_movex, user_movey);
1287 if(outer_clip_box) {
1288 output->endclip(output);
1292 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);
1294 msg("<verbose> page is rotated %d degrees\n", rot);
1296 clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1297 clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1298 clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1299 clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1300 clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1301 output->startclip(output, clippath); outer_clip_box = 1;
1302 output->fill(output, clippath, &white);
1305 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1307 msg("<debug> drawlink\n");
1308 double x1, y1, x2, y2, w;
1310 gfxline_t points[5];
1314 link->getBorder(&x1, &y1, &x2, &y2, &w);
1316 link->getRect(&x1, &y1, &x2, &y2);
1321 cvtUserToDev(x1, y1, &x, &y);
1322 points[0].type = gfx_moveTo;
1323 points[0].x = points[4].x = x + user_movex;
1324 points[0].y = points[4].y = y + user_movey;
1325 points[0].next = &points[1];
1326 cvtUserToDev(x2, y1, &x, &y);
1327 points[1].type = gfx_lineTo;
1328 points[1].x = x + user_movex;
1329 points[1].y = y + user_movey;
1330 points[1].next = &points[2];
1331 cvtUserToDev(x2, y2, &x, &y);
1332 points[2].type = gfx_lineTo;
1333 points[2].x = x + user_movex;
1334 points[2].y = y + user_movey;
1335 points[2].next = &points[3];
1336 cvtUserToDev(x1, y2, &x, &y);
1337 points[3].type = gfx_lineTo;
1338 points[3].x = x + user_movex;
1339 points[3].y = y + user_movey;
1340 points[3].next = &points[4];
1341 cvtUserToDev(x1, y1, &x, &y);
1342 points[4].type = gfx_lineTo;
1343 points[4].x = x + user_movex;
1344 points[4].y = y + user_movey;
1347 LinkAction*action=link->getAction();
1354 switch(action->getKind())
1358 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1359 LinkDest *dest=NULL;
1360 if (ha->getDest()==NULL)
1361 dest=catalog->findDest(ha->getNamedDest());
1362 else dest=ha->getDest();
1364 if (dest->isPageRef()){
1365 Ref pageref=dest->getPageRef();
1366 page=catalog->findPage(pageref.num,pageref.gen);
1368 else page=dest->getPageNum();
1369 sprintf(buf, "%d", page);
1376 LinkGoToR*l = (LinkGoToR*)action;
1377 GString*g = l->getNamedDest();
1379 s = strdup(g->getCString());
1384 LinkNamed*l = (LinkNamed*)action;
1385 GString*name = l->getName();
1387 s = strdup(name->lowerCase()->getCString());
1388 named = name->getCString();
1391 if(strstr(s, "next") || strstr(s, "forward"))
1393 page = currentpage + 1;
1395 else if(strstr(s, "prev") || strstr(s, "back"))
1397 page = currentpage - 1;
1399 else if(strstr(s, "last") || strstr(s, "end"))
1401 page = pagepos>0?pages[pagepos-1]:0;
1403 else if(strstr(s, "first") || strstr(s, "top"))
1411 case actionLaunch: {
1413 LinkLaunch*l = (LinkLaunch*)action;
1414 GString * str = new GString(l->getFileName());
1415 str->append(l->getParams());
1416 s = strdup(str->getCString());
1422 LinkURI*l = (LinkURI*)action;
1423 GString*g = l->getURI();
1425 url = g->getCString();
1430 case actionUnknown: {
1432 LinkUnknown*l = (LinkUnknown*)action;
1437 msg("<error> Unknown link type!\n");
1441 if(!s) s = strdup("-?-");
1443 if(!linkinfo && (page || url))
1445 msg("<notice> File contains links");
1452 for(t=0;t<pagepos;t++)
1457 sprintf(buf, "page%d", t);
1458 output->drawlink(output, points, buf);
1463 output->drawlink(output, points, url);
1466 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1470 void SWFOutputDev::saveState(GfxState *state) {
1471 msg("<trace> saveState\n");
1474 msg("<error> Too many nested states in pdf.");
1478 states[statepos].clipping = 0; //? shouldn't this be the current value?
1479 states[statepos].textRender = states[statepos-1].textRender;
1482 void SWFOutputDev::restoreState(GfxState *state) {
1483 msg("<trace> restoreState\n");
1485 while(states[statepos].clipping) {
1486 output->endclip(output);
1487 states[statepos].clipping--;
1492 char* SWFOutputDev::searchFont(char*name)
1496 int is_standard_font = 0;
1498 msg("<verbose> SearchFont(%s)", name);
1500 /* see if it is a pdf standard font */
1501 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1503 if(!strcmp(name, pdf2t1map[i].pdffont))
1505 name = pdf2t1map[i].filename;
1506 is_standard_font = 1;
1510 /* look in all font files */
1511 for(i=0;i<fontnum;i++)
1513 if(strstr(fonts[i].filename, name))
1515 if(!fonts[i].used) {
1518 if(!is_standard_font)
1519 msg("<notice> Using %s for %s", fonts[i].filename, name);
1521 return strdup(fonts[i].filename);
1527 void SWFOutputDev::updateLineWidth(GfxState *state)
1529 double width = state->getTransformedLineWidth();
1530 //swfoutput_setlinewidth(&output, width);
1533 void SWFOutputDev::updateLineCap(GfxState *state)
1535 int c = state->getLineCap();
1538 void SWFOutputDev::updateLineJoin(GfxState *state)
1540 int j = state->getLineJoin();
1543 void SWFOutputDev::updateFillColor(GfxState *state)
1546 double opaq = state->getFillOpacity();
1547 state->getFillRGB(&rgb);
1549 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1552 void SWFOutputDev::updateStrokeColor(GfxState *state)
1555 double opaq = state->getStrokeOpacity();
1556 state->getStrokeRGB(&rgb);
1557 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1560 void FoFiWrite(void *stream, char *data, int len)
1562 fwrite(data, len, 1, (FILE*)stream);
1565 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1567 char*tmpFileName = NULL;
1573 Object refObj, strObj;
1575 tmpFileName = mktmpname(namebuf);
1578 ret = font->getEmbeddedFontID(&embRef);
1580 msg("<verbose> Didn't get embedded font id");
1581 /* not embedded- the caller should now search the font
1582 directories for this font */
1586 f = fopen(tmpFileName, "wb");
1588 msg("<error> Couldn't create temporary Type 1 font file");
1592 /*if(font->isCIDFont()) {
1593 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1594 GString c = cidFont->getCollection();
1595 msg("<notice> Collection: %s", c.getCString());
1598 //if (font->getType() == fontType1C) {
1599 if (0) { //font->getType() == fontType1C) {
1600 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1602 msg("<error> Couldn't read embedded font file");
1606 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1608 cvt->convertToType1(f);
1610 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1612 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1614 //cvt->convertToCIDType0("test", f);
1615 //cvt->convertToType0("test", f);
1618 } else if(font->getType() == fontTrueType) {
1619 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1620 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1622 msg("<error> Couldn't read embedded font file");
1626 TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1629 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1630 cvt->writeTTF(FoFiWrite, f);
1635 font->getEmbeddedFontID(&embRef);
1636 refObj.initRef(embRef.num, embRef.gen);
1637 refObj.fetch(ref, &strObj);
1639 strObj.streamReset();
1644 f4[t] = strObj.streamGetChar();
1645 f4c[t] = (char)f4[t];
1650 if(!strncmp(f4c, "true", 4)) {
1651 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1652 Change this on the fly */
1653 f4[0] = f4[2] = f4[3] = 0;
1661 while ((c = strObj.streamGetChar()) != EOF) {
1665 strObj.streamClose();
1670 return strdup(tmpFileName);
1673 char* searchForSuitableFont(GfxFont*gfxFont)
1675 char*name = getFontName(gfxFont);
1679 if(!config_use_fontconfig)
1682 #ifdef HAVE_FONTCONFIG
1683 FcPattern *pattern, *match;
1687 static int fcinitcalled = false;
1689 msg("<debug> searchForSuitableFont(%s)", name);
1691 // call init ony once
1692 if (!fcinitcalled) {
1693 msg("<debug> Initializing FontConfig...");
1694 fcinitcalled = true;
1696 msg("<debug> FontConfig Initialization failed. Disabling.");
1697 config_use_fontconfig = 0;
1700 msg("<debug> ...initialized FontConfig");
1703 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1704 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1705 if (gfxFont->isItalic()) // check for italic
1706 msg("<debug> FontConfig: Adding Italic Slant");
1707 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1708 if (gfxFont->isBold()) // check for bold
1709 msg("<debug> FontConfig: Adding Bold Weight");
1710 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1712 msg("<debug> FontConfig: Try to match...");
1713 // configure and match using the original font name
1714 FcConfigSubstitute(0, pattern, FcMatchPattern);
1715 FcDefaultSubstitute(pattern);
1716 match = FcFontMatch(0, pattern, &result);
1718 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1719 msg("<debug> FontConfig: family=%s", (char*)v);
1720 // if we get an exact match
1721 if (strcmp((char *)v, name) == 0) {
1722 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1723 filename = strdup((char*)v); // mem leak
1724 char *nfn = strrchr(filename, '/');
1725 if(nfn) fontname = strdup(nfn+1);
1726 else fontname = filename;
1728 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1730 // initialize patterns
1731 FcPatternDestroy(pattern);
1732 FcPatternDestroy(match);
1734 // now match against serif etc.
1735 if (gfxFont->isSerif()) {
1736 msg("<debug> FontConfig: Create Serif Family Pattern");
1737 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1738 } else if (gfxFont->isFixedWidth()) {
1739 msg("<debug> FontConfig: Create Monospace Family Pattern");
1740 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1742 msg("<debug> FontConfig: Create Sans Family Pattern");
1743 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1747 if (gfxFont->isItalic()) {
1748 msg("<debug> FontConfig: Adding Italic Slant");
1749 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1752 if (gfxFont->isBold()) {
1753 msg("<debug> FontConfig: Adding Bold Weight");
1754 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1757 msg("<debug> FontConfig: Try to match... (2)");
1758 // configure and match using serif etc
1759 FcConfigSubstitute (0, pattern, FcMatchPattern);
1760 FcDefaultSubstitute (pattern);
1761 match = FcFontMatch (0, pattern, &result);
1763 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1764 filename = strdup((char*)v); // mem leak
1765 char *nfn = strrchr(filename, '/');
1766 if(nfn) fontname = strdup(nfn+1);
1767 else fontname = filename;
1769 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1773 //printf("FONTCONFIG: pattern");
1774 //FcPatternPrint(pattern);
1775 //printf("FONTCONFIG: match");
1776 //FcPatternPrint(match);
1778 FcPatternDestroy(pattern);
1779 FcPatternDestroy(match);
1781 pdfswf_addfont(filename);
1788 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1790 char*fontname = 0, *filename = 0;
1791 msg("<notice> subsituteFont(%s)", oldname);
1793 if(!(fontname = searchForSuitableFont(gfxFont))) {
1794 fontname = "Times-Roman";
1796 filename = searchFont(fontname);
1798 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1802 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1803 msg("<fatal> Too many fonts in file.");
1807 substitutesource[substitutepos] = strdup(oldname); //mem leak
1808 substitutetarget[substitutepos] = fontname;
1809 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1812 return strdup(filename); //mem leak
1815 void unlinkfont(char* filename)
1822 if(!strncmp(&filename[l-4],".afm",4)) {
1823 memcpy(&filename[l-4],".pfb",4);
1825 memcpy(&filename[l-4],".pfa",4);
1827 memcpy(&filename[l-4],".afm",4);
1830 if(!strncmp(&filename[l-4],".pfa",4)) {
1831 memcpy(&filename[l-4],".afm",4);
1833 memcpy(&filename[l-4],".pfa",4);
1836 if(!strncmp(&filename[l-4],".pfb",4)) {
1837 memcpy(&filename[l-4],".afm",4);
1839 memcpy(&filename[l-4],".pfb",4);
1844 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1850 int SWFOutputDev::setGfxFont(char*id, char*filename)
1853 fontlist_t*last=0,*l = this->fontlist;
1855 /* TODO: should this be part of the state? */
1858 if(!strcmp(l->id, id)) {
1859 current_font_id = l->id;
1860 current_gfxfont = l->font;
1862 output->addfont(output, id, current_gfxfont);
1867 if(!filename) return 0;
1868 font = gfxfont_load(filename);
1871 l->filename = strdup(filename);
1874 current_font_id = l->id;
1875 current_gfxfont = l->font;
1881 output->addfont(output, id, current_gfxfont);
1885 void SWFOutputDev::updateFont(GfxState *state)
1887 GfxFont*gfxFont = state->getFont();
1892 char * fontid = getFontID(gfxFont);
1895 /* first, look if we substituted this font before-
1896 this way, we don't initialize the T1 Fonts
1898 for(t=0;t<substitutepos;t++) {
1899 if(!strcmp(fontid, substitutesource[t])) {
1900 free(fontid);fontid=0;
1901 fontid = strdup(substitutetarget[t]);
1906 /* second, see if this is a font which was used before-
1907 if so, we are done */
1908 if(setGfxFont(fontid, 0)) {
1912 /* if(swfoutput_queryfont(&output, fontid))
1913 swfoutput_setfont(&output, fontid, 0);
1915 msg("<debug> updateFont(%s) [cached]", fontid);
1919 // look for Type 3 font
1920 if (gfxFont->getType() == fontType3) {
1922 type3Warning = gTrue;
1923 showFontError(gfxFont, 2);
1929 /* now either load the font, or find a substitution */
1932 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1937 (gfxFont->getType() == fontType1 ||
1938 gfxFont->getType() == fontType1C ||
1939 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
1940 gfxFont->getType() == fontTrueType ||
1941 gfxFont->getType() == fontCIDType2
1944 fileName = writeEmbeddedFontToFile(xref, gfxFont);
1945 if(!fileName) showFontError(gfxFont,0);
1948 char * fontname = getFontName(gfxFont);
1949 fileName = searchFont(fontname);
1950 if(!fileName) showFontError(gfxFont,0);
1954 char * fontname = getFontName(gfxFont);
1955 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
1956 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
1957 fileName = substituteFont(gfxFont, fontid);
1958 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
1959 msg("<notice> Font is now %s (%s)", fontid, fileName);
1963 msg("<error> Couldn't set font %s\n", fontid);
1968 msg("<verbose> updateFont(%s) -> %s", fontid, fileName);
1969 dumpFontInfo("<verbose>", gfxFont);
1971 //swfoutput_setfont(&output, fontid, fileName);
1973 if(!setGfxFont(fontid, 0)) {
1974 setGfxFont(fontid, fileName);
1978 unlinkfont(fileName);
1984 #define SQR(x) ((x)*(x))
1986 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1988 if((newwidth<2 || newheight<2) ||
1989 (width<=newwidth || height<=newheight))
1991 unsigned char*newdata;
1993 newdata= (unsigned char*)malloc(newwidth*newheight);
1995 double fx = (double)(width)/newwidth;
1996 double fy = (double)(height)/newheight;
1998 int blocksize = (int)(8192/(fx*fy));
1999 int r = 8192*256/palettesize;
2000 for(x=0;x<newwidth;x++) {
2001 double ex = px + fx;
2002 int fromx = (int)px;
2004 int xweight1 = (int)(((fromx+1)-px)*256);
2005 int xweight2 = (int)((ex-tox)*256);
2007 for(y=0;y<newheight;y++) {
2008 double ey = py + fy;
2009 int fromy = (int)py;
2011 int yweight1 = (int)(((fromy+1)-py)*256);
2012 int yweight2 = (int)((ey-toy)*256);
2015 for(xx=fromx;xx<=tox;xx++)
2016 for(yy=fromy;yy<=toy;yy++) {
2017 int b = 1-data[width*yy+xx];
2019 if(xx==fromx) weight = (weight*xweight1)/256;
2020 if(xx==tox) weight = (weight*xweight2)/256;
2021 if(yy==fromy) weight = (weight*yweight1)/256;
2022 if(yy==toy) weight = (weight*yweight2)/256;
2025 //if(a) a=(palettesize-1)*r/blocksize;
2026 newdata[y*newwidth+x] = (a*blocksize)/r;
2034 #define IMAGE_TYPE_JPEG 0
2035 #define IMAGE_TYPE_LOSSLESS 1
2037 static void drawimage(gfxdevice_t*dev, RGBA* data, int sizex,int sizey,
2038 double x1,double y1,
2039 double x2,double y2,
2040 double x3,double y3,
2041 double x4,double y4, int type)
2045 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2046 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2048 gfxline_t p1,p2,p3,p4,p5;
2049 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2050 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2051 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2052 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2053 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2055 {p1.x = (int)(p1.x*20)/20.0;
2056 p1.y = (int)(p1.y*20)/20.0;
2057 p2.x = (int)(p2.x*20)/20.0;
2058 p2.y = (int)(p2.y*20)/20.0;
2059 p3.x = (int)(p3.x*20)/20.0;
2060 p3.y = (int)(p3.y*20)/20.0;
2061 p4.x = (int)(p4.x*20)/20.0;
2062 p4.y = (int)(p4.y*20)/20.0;
2063 p5.x = (int)(p5.x*20)/20.0;
2064 p5.y = (int)(p5.y*20)/20.0;
2071 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2072 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2077 img.data = (gfxcolor_t*)data;
2081 if(type == IMAGE_TYPE_JPEG)
2082 /* TODO: pass image_dpi to device instead */
2083 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2085 dev->fillbitmap(dev, &p1, &img, &m, 0);
2088 void drawimagejpeg(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
2089 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2091 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2094 void drawimagelossless(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
2095 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2097 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2101 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2102 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2103 GBool inlineImg, int mask, int*maskColors)
2108 double x1,y1,x2,y2,x3,y3,x4,y4;
2109 ImageStream *imgStr;
2116 ncomps = colorMap->getNumPixelComps();
2117 bits = colorMap->getBits();
2119 imgStr = new ImageStream(str, width, ncomps,bits);
2122 if(!width || !height || (height<=1 && width<=1))
2124 msg("<verbose> Ignoring %d by %d image", width, height);
2125 unsigned char buf[8];
2127 for (y = 0; y < height; ++y)
2128 for (x = 0; x < width; ++x) {
2129 imgStr->getPixel(buf);
2135 state->transform(0, 1, &x1, &y1); x1 += user_movex; y1+= user_movey;
2136 state->transform(0, 0, &x2, &y2); x2 += user_movex; y2+= user_movey;
2137 state->transform(1, 0, &x3, &y3); x3 += user_movex; y3+= user_movey;
2138 state->transform(1, 1, &x4, &y4); x4 += user_movex; y4+= user_movey;
2140 if(!pbminfo && !(str->getKind()==strDCT)) {
2142 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2146 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2148 if(!jpeginfo && (str->getKind()==strDCT)) {
2149 msg("<notice> file contains jpeg pictures");
2155 unsigned char buf[8];
2157 unsigned char*pic = new unsigned char[width*height];
2160 state->getFillRGB(&rgb);
2162 memset(pal,255,sizeof(pal));
2163 pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
2164 pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
2165 pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
2166 pal[0].a = 255; pal[1].a = 0;
2169 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2170 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2171 for (y = 0; y < height; ++y)
2172 for (x = 0; x < width; ++x)
2174 imgStr->getPixel(buf);
2177 pic[width*y+x] = buf[0];
2180 /* the size of the drawn image is added to the identifier
2181 as the same image may require different bitmaps if displayed
2182 at different sizes (due to antialiasing): */
2185 unsigned char*pic2 = 0;
2188 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2197 height = realheight;
2201 /* make a black/white palette */
2206 float r = 255/(numpalette-1);
2208 for(t=0;t<numpalette;t++) {
2209 pal[t].r = (U8)(255*rgb.r);
2210 pal[t].g = (U8)(255*rgb.g);
2211 pal[t].b = (U8)(255*rgb.b);
2212 pal[t].a = (U8)(t*r);
2216 RGBA*pic2 = new RGBA[width*height];
2217 for (y = 0; y < height; ++y) {
2218 for (x = 0; x < width; ++x) {
2219 pic2[width*y+x] = pal[pic[y*width+x]];
2222 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2231 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2232 RGBA*pic=new RGBA[width*height];
2233 for (y = 0; y < height; ++y) {
2234 for (x = 0; x < width; ++x) {
2235 imgStr->getPixel(pixBuf);
2236 colorMap->getRGB(pixBuf, &rgb);
2237 pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
2238 pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
2239 pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
2240 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2243 if(str->getKind()==strDCT)
2244 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2246 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2251 RGBA*pic=new RGBA[width*height];
2254 for(t=0;t<256;t++) {
2256 colorMap->getRGB(pixBuf, &rgb);
2257 /*if(maskColors && *maskColors==t) {
2258 msg("<notice> Color %d is transparent", t);
2259 if (imgData->maskColors) {
2261 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2262 if (pix[i] < imgData->maskColors[2*i] ||
2263 pix[i] > imgData->maskColors[2*i+1]) {
2278 pal[t].r = (U8)(rgb.r * 255 + 0.5);
2279 pal[t].g = (U8)(rgb.g * 255 + 0.5);
2280 pal[t].b = (U8)(rgb.b * 255 + 0.5);
2281 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2284 for (y = 0; y < height; ++y) {
2285 for (x = 0; x < width; ++x) {
2286 imgStr->getPixel(pixBuf);
2287 pic[width*y+x] = pal[pixBuf[0]];
2290 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2298 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2299 int width, int height, GBool invert,
2302 if(states[statepos].textRender & 4) //clipped
2304 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2305 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
2308 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2309 int width, int height, GfxImageColorMap *colorMap,
2310 int *maskColors, GBool inlineImg)
2312 if(states[statepos].textRender & 4) //clipped
2315 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
2316 colorMap?"colorMap":"no colorMap",
2317 maskColors?"maskColors":"no maskColors",
2320 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2321 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2322 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
2325 //SWFOutputDev*output = 0;
2327 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2332 if (infoDict->lookup(key, &obj)->isString()) {
2333 s1 = obj.getString();
2334 if ((s1->getChar(0) & 0xff) == 0xfe &&
2335 (s1->getChar(1) & 0xff) == 0xff) {
2337 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2338 if (s1->getChar(i) == '\0') {
2339 s2->append(s1->getChar(i+1));
2342 s2 = new GString("<unicode>");
2346 printf(fmt, s2->getCString());
2349 printf(fmt, s1->getCString());
2355 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2359 if (infoDict->lookup(key, &obj)->isString()) {
2360 s = obj.getString()->getCString();
2361 if (s[0] == 'D' && s[1] == ':') {
2372 void storeDeviceParameter(char*name, char*value)
2374 parameter_t*p = new parameter_t();
2375 p->name = strdup(name);
2376 p->value = strdup(value);
2378 if(device_config_next) {
2379 device_config_next->next = p;
2380 device_config_next = p;
2383 device_config_next = p;
2387 void pdfswf_setparameter(char*name, char*value)
2389 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2390 if(!strcmp(name, "caplinewidth")) {
2391 caplinewidth = atof(value);
2392 } else if(!strcmp(name, "zoom")) {
2395 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2396 storeDeviceParameter("jpegsubpixels", buf);
2397 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2398 storeDeviceParameter("ppmsubpixels", buf);
2399 } else if(!strcmp(name, "jpegdpi")) {
2401 jpeg_dpi = atoi(value);
2402 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2403 storeDeviceParameter("jpegsubpixels", buf);
2404 } else if(!strcmp(name, "ppmdpi")) {
2406 ppm_dpi = atoi(value);
2407 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2408 storeDeviceParameter("ppmsubpixels", buf);
2409 } else if(!strcmp(name, "forceType0Fonts")) {
2410 forceType0Fonts = atoi(value);
2411 } else if(!strcmp(name, "fontdir")) {
2412 pdfswf_addfontdir(value);
2413 } else if(!strcmp(name, "languagedir")) {
2414 pdfswf_addlanguagedir(value);
2415 } else if(!strcmp(name, "fontconfig")) {
2416 config_use_fontconfig = atoi(value);
2418 storeDeviceParameter(name,value);
2421 void pdfswf_addfont(char*filename)
2424 memset(&f, 0, sizeof(fontfile_t));
2425 f.filename = filename;
2426 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2427 fonts[fontnum++] = f;
2429 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2433 static char* dirseparator()
2442 void pdfswf_addlanguagedir(char*dir)
2445 globalParams = new GlobalParams("");
2447 msg("<notice> Adding %s to language pack directories", dir);
2451 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2452 strcpy(config_file, dir);
2453 strcat(config_file, dirseparator());
2454 strcat(config_file, "add-to-xpdfrc");
2456 fi = fopen(config_file, "rb");
2458 msg("<error> Could not open %s", config_file);
2461 globalParams->parseFile(new GString(config_file), fi);
2465 void pdfswf_addfontdir(char*dirname)
2467 #ifdef HAVE_DIRENT_H
2468 msg("<notice> Adding %s to font directories", dirname);
2469 DIR*dir = opendir(dirname);
2471 msg("<warning> Couldn't open directory %s\n", dirname);
2476 ent = readdir (dir);
2480 char*name = ent->d_name;
2486 if(!strncasecmp(&name[l-4], ".pfa", 4))
2488 if(!strncasecmp(&name[l-4], ".pfb", 4))
2490 if(!strncasecmp(&name[l-4], ".ttf", 4))
2494 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2495 strcpy(fontname, dirname);
2496 strcat(fontname, dirseparator());
2497 strcat(fontname, name);
2498 msg("<verbose> Adding %s to fonts", fontname);
2499 pdfswf_addfont(fontname);
2504 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2509 typedef struct _pdf_doc_internal
2513 } pdf_doc_internal_t;
2514 typedef struct _pdf_page_internal
2516 } pdf_page_internal_t;
2517 typedef struct _swf_output_internal
2519 SWFOutputDev*outputDev;
2520 } swf_output_internal_t;
2522 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2524 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2525 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2526 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2527 memset(i, 0, sizeof(pdf_doc_internal_t));
2528 pdf_doc->internal = i;
2530 GString *fileName = new GString(filename);
2536 globalParams = new GlobalParams("");
2539 if (userPassword && userPassword[0]) {
2540 userPW = new GString(userPassword);
2544 i->doc = new PDFDoc(fileName, userPW);
2548 if (!i->doc->isOk()) {
2553 i->doc->getDocInfo(&info);
2554 if (info.isDict() &&
2555 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2556 printInfoString(info.getDict(), "Title", "Title: %s\n");
2557 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2558 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2559 printInfoString(info.getDict(), "Author", "Author: %s\n");
2560 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2561 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2562 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2563 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2564 printf("Pages: %d\n", i->doc->getNumPages());
2565 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2566 printf("Encrypted: ");
2567 if (i->doc->isEncrypted()) {
2568 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2569 i->doc->okToPrint() ? "yes" : "no",
2570 i->doc->okToCopy() ? "yes" : "no",
2571 i->doc->okToChange() ? "yes" : "no",
2572 i->doc->okToAddNotes() ? "yes" : "no");
2579 pdf_doc->num_pages = i->doc->getNumPages();
2581 if (i->doc->isEncrypted()) {
2582 if(!i->doc->okToCopy()) {
2583 printf("PDF disallows copying.\n");
2586 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2593 static void pdfswf_preparepage(int page)
2597 pages = (int*)malloc(1024*sizeof(int));
2600 if(pagepos == pagebuflen)
2603 pages = (int*)realloc(pages, pagebuflen);
2606 pages[pagepos++] = page;
2613 delete globalParams;globalParams=0;
2614 Object::memCheck(stderr);
2619 void pdf_destroy(pdf_doc_t*pdf_doc)
2621 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2623 delete i->doc; i->doc=0;
2625 free(pages); pages = 0; //FIXME
2627 free(pdf_doc->internal);pdf_doc->internal=0;
2628 free(pdf_doc);pdf_doc=0;
2631 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2633 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2635 if(page < 1 || page > pdf_doc->num_pages)
2638 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2639 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2640 memset(pi, 0, sizeof(pdf_page_internal_t));
2641 pdf_page->internal = pi;
2643 pdf_page->parent = pdf_doc;
2644 pdf_page->nr = page;
2648 void pdf_page_destroy(pdf_page_t*pdf_page)
2650 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2651 free(pdf_page->internal);pdf_page->internal = 0;
2652 free(pdf_page);pdf_page=0;
2655 swf_output_t* swf_output_init()
2657 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2658 memset(swf_output, 0, sizeof(swf_output_t));
2659 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2660 memset(i, 0, sizeof(swf_output_internal_t));
2661 swf_output->internal = i;
2663 i->outputDev = new SWFOutputDev();
2667 void swf_output_setparameter(swf_output_t*swf, char*name, char*value)
2669 pdfswf_setparameter(name, value);
2672 void swf_output_startframe(swf_output_t*swf, int width, int height)
2674 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2675 i->outputDev->startFrame(width, height);
2676 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2679 void swf_output_endframe(swf_output_t*swf)
2681 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2682 i->outputDev->endframe();
2683 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2686 int swf_output_save(swf_output_t*swf, char*filename)
2688 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2689 int ret = i->outputDev->save(filename);
2690 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2694 void* swf_output_get(swf_output_t*swf)
2696 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2697 void* ret = i->outputDev->getSWF();
2698 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2702 void swf_output_destroy(swf_output_t*output)
2704 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2705 delete i->outputDev; i->outputDev=0;
2706 free(output->internal);output->internal=0;
2710 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2712 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2713 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2716 gfxdevice_t*dev = si->outputDev->output;
2717 dev->setparameter(dev, "protect", "1");
2719 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2721 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2723 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2725 si->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2728 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2730 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2731 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2733 si->outputDev->setMove(x,y);
2734 if((x1|y1|x2|y2)==0) x2++;
2735 si->outputDev->setClip(x1,y1,x2,y2);
2737 pdf_page_render2(page, output);
2739 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2741 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2742 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2744 si->outputDev->setMove(0,0);
2745 si->outputDev->setClip(0,0,0,0);
2747 pdf_page_render2(page, output);
2751 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2753 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2754 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2755 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2756 memset(info, 0, sizeof(pdf_page_info_t));
2758 InfoOutputDev*output = new InfoOutputDev;
2761 pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2763 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2766 info->xMin = output->x1;
2767 info->yMin = output->y1;
2768 info->xMax = output->x2;
2769 info->yMax = output->y2;
2770 info->number_of_images = output->num_images;
2771 info->number_of_links = output->num_links;
2772 info->number_of_fonts = output->num_fonts;
2779 void pdf_page_info_destroy(pdf_page_info_t*info)