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
80 static fontfile_t fonts[2048];
81 static int fontnum = 0;
83 static int config_use_fontconfig = 1;
86 // TODO: move into pdf_doc_t
88 static int pagebuflen = 0;
89 static int pagepos = 0;
92 static double caplinewidth = 3.0;
93 static int zoom = 72; /* xpdf: 86 */
94 static int forceType0Fonts = 1;
96 static void printInfoString(Dict *infoDict, char *key, char *fmt);
97 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
103 {"Times-Roman", "n021003l"},
104 {"Times-Italic", "n021023l"},
105 {"Times-Bold", "n021004l"},
106 {"Times-BoldItalic", "n021024l"},
107 {"Helvetica", "n019003l"},
108 {"Helvetica-Oblique", "n019023l"},
109 {"Helvetica-Bold", "n019004l"},
110 {"Helvetica-BoldOblique", "n019024l"},
111 {"Courier", "n022003l"},
112 {"Courier-Oblique", "n022023l"},
113 {"Courier-Bold", "n022004l"},
114 {"Courier-BoldOblique", "n022024l"},
115 {"Symbol", "s050000l"},
116 {"ZapfDingbats", "d050000l"}};
118 class SWFOutputState {
124 this->textRender = 0;
128 typedef struct _fontlist
136 class SWFOutputDev: public OutputDev {
138 struct swfoutput output;
145 virtual ~SWFOutputDev() ;
147 void setMove(int x,int y);
148 void setClip(int x1,int y1,int x2,int y2);
150 int save(char*filename);
154 void getDimensions(int*x1,int*y1,int*x2,int*y2);
156 //----- get info about output device
158 // Does this device use upside-down coordinates?
159 // (Upside-down means (0,0) is the top left corner of the page.)
160 virtual GBool upsideDown();
162 // Does this device use drawChar() or drawString()?
163 virtual GBool useDrawChar();
165 // Can this device draw gradients?
166 virtual GBool useGradients();
168 virtual GBool interpretType3Chars() {return gTrue;}
170 //----- initialization and control
172 void setXRef(PDFDoc*doc, XRef *xref);
175 virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
178 virtual void drawLink(Link *link, Catalog *catalog) ;
180 //----- save/restore graphics state
181 virtual void saveState(GfxState *state) ;
182 virtual void restoreState(GfxState *state) ;
184 //----- update graphics state
186 virtual void updateFont(GfxState *state);
187 virtual void updateFillColor(GfxState *state);
188 virtual void updateStrokeColor(GfxState *state);
189 virtual void updateLineWidth(GfxState *state);
190 virtual void updateLineJoin(GfxState *state);
191 virtual void updateLineCap(GfxState *state);
193 virtual void updateAll(GfxState *state)
196 updateFillColor(state);
197 updateStrokeColor(state);
198 updateLineWidth(state);
199 updateLineJoin(state);
200 updateLineCap(state);
203 //----- path painting
204 virtual void stroke(GfxState *state) ;
205 virtual void fill(GfxState *state) ;
206 virtual void eoFill(GfxState *state) ;
208 //----- path clipping
209 virtual void clip(GfxState *state) ;
210 virtual void eoClip(GfxState *state) ;
213 virtual void beginString(GfxState *state, GString *s) ;
214 virtual void endString(GfxState *state) ;
215 virtual void endTextObject(GfxState *state);
216 virtual void drawChar(GfxState *state, double x, double y,
217 double dx, double dy,
218 double originX, double originY,
219 CharCode code, Unicode *u, int uLen);
221 //----- image drawing
222 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
223 int width, int height, GBool invert,
225 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
226 int width, int height, GfxImageColorMap *colorMap,
227 int *maskColors, GBool inlineImg);
229 virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
230 virtual void endType3Char(GfxState *state);
232 virtual void type3D0(GfxState *state, double wx, double wy);
233 virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
236 void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
237 int width, int height, GfxImageColorMap*colorMap, GBool invert,
238 GBool inlineImg, int mask, int *maskColors);
239 int SWFOutputDev::setGfxFont(char*id, char*filename);
240 void strokeGfxline(GfxState *state, gfxline_t*line);
241 void clipToGfxLine(GfxState *state, gfxline_t*line);
242 void fillGfxLine(GfxState *state, gfxline_t*line);
244 SWFOutputState states[64];
252 char* searchFont(char*name);
253 char* substituteFont(GfxFont*gfxFont, char*oldname);
254 char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
256 int jpeginfo; // did we write "File contains jpegs" yet?
257 int pbminfo; // did we write "File contains jpegs" yet?
258 int linkinfo; // did we write "File contains links" yet?
259 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
260 int gradientinfo; // did we write "File contains Gradients yet?
262 int type3active; // are we between beginType3()/endType3()?
268 char* substitutetarget[256];
269 char* substitutesource[256];
272 int user_movex,user_movey;
273 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
275 gfxline_t* current_text_stroke;
276 char* current_font_id;
277 gfxfont_t* current_gfxfont;
278 gfxmatrix_t current_font_matrix;
280 fontlist_t* fontlist;
283 static char*getFontID(GfxFont*font);
285 class InfoOutputDev: public OutputDev
299 virtual ~InfoOutputDev()
302 virtual GBool upsideDown() {return gTrue;}
303 virtual GBool useDrawChar() {return gTrue;}
304 virtual GBool useGradients() {return gTrue;}
305 virtual GBool interpretType3Chars() {return gTrue;}
306 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
309 state->transform(crop_x1,crop_y1,&x1,&y1);
310 state->transform(crop_x2,crop_y2,&x2,&y2);
311 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
312 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
318 virtual void drawLink(Link *link, Catalog *catalog)
322 virtual void updateFont(GfxState *state)
324 GfxFont*font = state->getFont();
327 /*char*id = getFontID(font);*/
331 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
332 int width, int height, GBool invert,
337 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
338 int width, int height, GfxImageColorMap *colorMap,
339 int *maskColors, GBool inlineImg)
345 SWFOutputDev::SWFOutputDev()
363 current_text_stroke = 0;
365 memset(&output, 0, sizeof(output));
366 // printf("SWFOutputDev::SWFOutputDev() \n");
369 void SWFOutputDev::setMove(int x,int y)
371 this->user_movex = x;
372 this->user_movey = y;
375 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
377 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
378 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
380 this->user_clipx1 = x1;
381 this->user_clipy1 = y1;
382 this->user_clipx2 = x2;
383 this->user_clipy2 = y2;
385 void SWFOutputDev::getDimensions(int*x1,int*y1,int*x2,int*y2)
387 return swfoutput_getdimensions(&output, x1,y1,x2,y2);
390 static char*getFontID(GfxFont*font)
392 GString*gstr = font->getName();
393 char* fontname = gstr==0?0:gstr->getCString();
397 sprintf(buf, "UFONT%d", r->num);
400 return strdup(fontname);
403 static char*getFontName(GfxFont*font)
405 char*fontid = getFontID(font);
407 char* plus = strchr(fontid, '+');
408 if(plus && plus < &fontid[strlen(fontid)-1]) {
409 fontname = strdup(plus+1);
411 fontname = strdup(fontid);
417 static char mybuf[1024];
418 static char* gfxstate2str(GfxState *state)
422 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
429 if(state->getX1()!=0.0)
430 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
431 if(state->getY1()!=0.0)
432 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
433 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
434 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
435 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
436 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
437 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
438 state->getFillColor()->c[0], state->getFillColor()->c[1]);
439 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
440 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
441 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
442 state->getFillColor()->c[0], state->getFillColor()->c[1],
443 state->getFillColor()->c[2], state->getFillColor()->c[3],
444 state->getFillColor()->c[4], state->getFillColor()->c[5],
445 state->getFillColor()->c[6], state->getFillColor()->c[7]);
446 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
447 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
448 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
449 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
450 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
451 state->getFillRGB(&rgb);
452 if(rgb.r || rgb.g || rgb.b)
453 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
454 state->getStrokeRGB(&rgb);
455 if(rgb.r || rgb.g || rgb.b)
456 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
457 if(state->getFillColorSpace()->getNComps()>1)
458 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
459 if(state->getStrokeColorSpace()->getNComps()>1)
460 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
461 if(state->getFillPattern())
462 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
463 if(state->getStrokePattern())
464 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
466 if(state->getFillOpacity()!=1.0)
467 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
468 if(state->getStrokeOpacity()!=1.0)
469 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
471 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
476 state->getLineDash(&dash, &length, &start);
480 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
481 for(t=0;t<length;t++) {
482 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
484 bufpos+=sprintf(bufpos,"]");
487 if(state->getFlatness()!=1)
488 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
489 if(state->getLineJoin()!=0)
490 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
491 if(state->getLineJoin()!=0)
492 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
493 if(state->getLineJoin()!=0)
494 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
496 if(state->getFont() && getFontID(state->getFont()))
497 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
498 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
499 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
500 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
501 if(state->getCharSpace())
502 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
503 if(state->getWordSpace())
504 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
505 if(state->getHorizScaling()!=1.0)
506 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
507 if(state->getLeading())
508 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
510 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
511 if(state->getRender())
512 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
513 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
514 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
515 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
516 if(state->getLineX())
517 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
518 if(state->getLineY())
519 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
520 bufpos+=sprintf(bufpos," ");
524 static void dumpFontInfo(char*loglevel, GfxFont*font);
525 static int lastdumps[1024];
526 static int lastdumppos = 0;
531 static void showFontError(GfxFont*font, int nr)
535 for(t=0;t<lastdumppos;t++)
536 if(lastdumps[t] == r->num)
540 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
541 lastdumps[lastdumppos++] = r->num;
543 msg("<warning> The following font caused problems:");
545 msg("<warning> The following font caused problems (substituting):");
547 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
548 dumpFontInfo("<warning>", font);
551 static void dumpFontInfo(char*loglevel, GfxFont*font)
553 char* id = getFontID(font);
554 char* name = getFontName(font);
555 Ref* r=font->getID();
556 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
558 GString*gstr = font->getTag();
560 msg("%s| Tag: %s\n", loglevel, id);
562 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
564 GfxFontType type=font->getType();
566 case fontUnknownType:
567 msg("%s| Type: unknown\n",loglevel);
570 msg("%s| Type: 1\n",loglevel);
573 msg("%s| Type: 1C\n",loglevel);
576 msg("%s| Type: 3\n",loglevel);
579 msg("%s| Type: TrueType\n",loglevel);
582 msg("%s| Type: CIDType0\n",loglevel);
585 msg("%s| Type: CIDType0C\n",loglevel);
588 msg("%s| Type: CIDType2\n",loglevel);
593 GBool embedded = font->getEmbeddedFontID(&embRef);
595 if(font->getEmbeddedFontName()) {
596 embeddedName = font->getEmbeddedFontName()->getCString();
599 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
601 gstr = font->getExtFontFile();
603 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
605 // Get font descriptor flags.
606 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
607 if(font->isSerif()) msg("%s| is serif\n", loglevel);
608 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
609 if(font->isItalic()) msg("%s| is italic\n", loglevel);
610 if(font->isBold()) msg("%s| is bold\n", loglevel);
616 //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");}
617 //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");}
620 void dump_outline(gfxline_t*line)
623 if(line->type == gfx_moveTo) {
624 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
625 } else if(line->type == gfx_lineTo) {
626 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
627 } else if(line->type == gfx_splineTo) {
628 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
634 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed)
636 int num = path->getNumSubpaths();
639 double lastx=0,lasty=0,posx=0,posy=0;
642 msg("<warning> empty path");
646 gfxdrawer_target_gfxline(&draw);
648 for(t = 0; t < num; t++) {
649 GfxSubpath *subpath = path->getSubpath(t);
650 int subnum = subpath->getNumPoints();
651 double bx=0,by=0,cx=0,cy=0;
653 for(s=0;s<subnum;s++) {
655 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
657 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
658 draw.lineTo(&draw, lastx, lasty);
660 draw.moveTo(&draw, x,y);
665 } else if(subpath->getCurve(s) && cpos==0) {
669 } else if(subpath->getCurve(s) && cpos==1) {
677 draw.lineTo(&draw, x,y);
679 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y);
686 /* fix non-closed lines */
687 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
688 draw.lineTo(&draw, lastx, lasty);
690 gfxline_t*result = (gfxline_t*)draw.result(&draw);
694 /*----------------------------------------------------------------------------
695 * Primitive Graphic routines
696 *----------------------------------------------------------------------------*/
698 void SWFOutputDev::stroke(GfxState *state)
700 GfxPath * path = state->getPath();
701 gfxline_t*line= gfxPath_to_gfxline(state, path, 0);
702 strokeGfxline(state, line);
706 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
708 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
709 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
710 double miterLimit = state->getMiterLimit();
711 double width = state->getTransformedLineWidth();
714 double opaq = state->getStrokeOpacity();
716 state->getFillRGB(&rgb);
718 state->getStrokeRGB(&rgb);
720 col.r = (unsigned char)(rgb.r*255);
721 col.g = (unsigned char)(rgb.g*255);
722 col.b = (unsigned char)(rgb.b*255);
723 col.a = (unsigned char)(opaq*255);
725 gfx_capType capType = gfx_capRound;
726 if(lineCap == 0) capType = gfx_capButt;
727 else if(lineCap == 1) capType = gfx_capRound;
728 else if(lineCap == 2) capType = gfx_capSquare;
730 gfx_joinType joinType = gfx_joinRound;
731 if(lineJoin == 0) joinType = gfx_joinMiter;
732 else if(lineJoin == 1) joinType = gfx_joinRound;
733 else if(lineJoin == 2) joinType = gfx_joinBevel;
736 double dashphase = 0;
738 state->getLineDash(&ldash, &dashnum, &dashphase);
740 if(dashnum && ldash) {
741 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
745 msg("<trace> %d dashes", dashnum);
746 msg("<trace> | phase: %f", dashphase);
747 for(t=0;t<dashnum;t++) {
749 msg("<trace> | d%-3d: %f", t, ldash[t]);
752 if(getLogLevel() >= LOGLEVEL_TRACE) {
756 gfxline_t*line2 = gfxtool_dash_line(line, dash, dashphase);
759 msg("<trace> After dashing:");
762 if(getLogLevel() >= LOGLEVEL_TRACE) {
764 state->getStrokeGray(&gray);
765 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n",
767 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
768 lineCap==0?"butt": (lineJoin==1?"round":"square"),
770 col.r,col.g,col.b,col.a,
776 swfoutput_drawgfxline(&output, line, width, &col, capType, joinType, miterLimit);
779 gfxcolor_t getFillColor(GfxState * state)
782 double opaq = state->getFillOpacity();
783 state->getFillRGB(&rgb);
785 col.r = (unsigned char)(rgb.r*255);
786 col.g = (unsigned char)(rgb.g*255);
787 col.b = (unsigned char)(rgb.b*255);
788 col.a = (unsigned char)(opaq*255);
792 void SWFOutputDev::fillGfxLine(GfxState *state, gfxline_t*line)
794 gfxcolor_t col = getFillColor(state);
796 if(getLogLevel() >= LOGLEVEL_TRACE) {
797 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
800 swfoutput_fillgfxline(&output, line, &col);
802 void SWFOutputDev::fill(GfxState *state)
804 GfxPath * path = state->getPath();
805 gfxline_t*line= gfxPath_to_gfxline(state, path, 1);
806 fillGfxLine(state, line);
809 void SWFOutputDev::eoFill(GfxState *state)
811 GfxPath * path = state->getPath();
812 gfxcolor_t col = getFillColor(state);
814 gfxline_t*line= gfxPath_to_gfxline(state, path, 1);
816 if(getLogLevel() >= LOGLEVEL_TRACE) {
817 msg("<trace> eofill\n");
821 swfoutput_fillgfxline(&output, line, &col);
825 void SWFOutputDev::clip(GfxState *state)
827 GfxPath * path = state->getPath();
828 gfxline_t*line = gfxPath_to_gfxline(state, path, 1);
829 clipToGfxLine(state, line);
833 void SWFOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line)
835 if(getLogLevel() >= LOGLEVEL_TRACE) {
836 msg("<trace> clip\n");
840 swfoutput_startclip(&output, line);
841 states[statepos].clipping++;
843 void SWFOutputDev::eoClip(GfxState *state)
845 GfxPath * path = state->getPath();
846 gfxline_t*line = gfxPath_to_gfxline(state, path, 1);
848 if(getLogLevel() >= LOGLEVEL_TRACE) {
849 msg("<trace> eoclip\n");
853 swfoutput_startclip(&output, line);
854 states[statepos].clipping++;
858 /* pass through functions for swf_output */
859 int SWFOutputDev::save(char*filename)
861 return swfoutput_save(&output, filename);
863 void SWFOutputDev::pagefeed()
865 swfoutput_pagefeed(&output);
867 void* SWFOutputDev::getSWF()
869 return (void*)swfoutput_get(&output);
872 SWFOutputDev::~SWFOutputDev()
874 swfoutput_destroy(&output);
877 fontlist_t*l = this->fontlist;
879 fontlist_t*next = l->next;
881 gfxfont_free(l->font);
888 GBool SWFOutputDev::upsideDown()
890 msg("<debug> upsidedown? yes");
893 GBool SWFOutputDev::useDrawChar()
897 GBool SWFOutputDev::useGradients()
901 msg("<notice> File contains gradients");
907 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
908 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
910 #define RENDER_FILL 0
911 #define RENDER_STROKE 1
912 #define RENDER_FILLSTROKE 2
913 #define RENDER_INVISIBLE 3
914 #define RENDER_CLIP 4
916 static char tmp_printstr[4096];
917 char* makeStringPrintable(char*str)
919 int len = strlen(str);
934 tmp_printstr[len++] = '.';
935 tmp_printstr[len++] = '.';
936 tmp_printstr[len++] = '.';
938 tmp_printstr[len] = 0;
943 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
947 for(t=0;t<font->num_glyphs;t++) {
948 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
949 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
953 /* if we didn't find the character, maybe
954 we can find the capitalized version */
955 for(t=0;t<font->num_glyphs;t++) {
956 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
957 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
963 /* try to use the unicode id */
964 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
965 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
966 return font->unicode2glyph[u];
969 if(charnr>=0 && charnr<font->num_glyphs) {
970 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
978 void SWFOutputDev::beginString(GfxState *state, GString *s)
980 int render = state->getRender();
981 if(current_text_stroke)
982 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
984 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
985 double m11,m21,m12,m22;
986 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
987 state->getFontTransMat(&m11, &m12, &m21, &m22);
988 m11 *= state->getHorizScaling();
989 m21 *= state->getHorizScaling();
991 this->current_font_matrix.m00 = m11 / 1024.0;
992 this->current_font_matrix.m01 = m12 / 1024.0;
993 this->current_font_matrix.m10 = -m21 / 1024.0;
994 this->current_font_matrix.m11 = -m22 / 1024.0;
995 this->current_font_matrix.tx = 0;
996 this->current_font_matrix.ty = 0;
998 gfxmatrix_t m = this->current_font_matrix;
1000 /*if(render != 3 && render != 0)
1001 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1002 states[statepos].textRender = render;
1005 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1006 double dx, double dy,
1007 double originX, double originY,
1008 CharCode c, Unicode *_u, int uLen)
1010 int render = state->getRender();
1011 // check for invisible text -- this is used by Acrobat Capture
1015 if(states[statepos].textRender != render)
1016 msg("<error> Internal error: drawChar.render!=beginString.render");
1018 gfxcolor_t col = getFillColor(state);
1020 Gushort *CIDToGIDMap = 0;
1021 GfxFont*font = state->getFont();
1023 if(font->getType() == fontType3) {
1024 /* type 3 chars are passed as graphics */
1025 msg("<debug> type3 char at %f/%f", x, y);
1036 /* find out char name from unicode index
1037 TODO: should be precomputed
1039 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1040 if(nameToUnicodeTab[t].u == u) {
1041 name = nameToUnicodeTab[t].name;
1048 if(font->isCIDFont()) {
1049 GfxCIDFont*cfont = (GfxCIDFont*)font;
1051 if(font->getType() == fontCIDType2)
1052 CIDToGIDMap = cfont->getCIDToGID();
1055 font8 = (Gfx8BitFont*)font;
1056 char**enc=font8->getEncoding();
1061 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);
1064 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);
1067 int charid = getGfxCharID(current_gfxfont, c, name, u);
1069 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1070 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1074 gfxmatrix_t m = this->current_font_matrix;
1075 state->transform(x, y, &m.tx, &m.ty);
1077 if(render == RENDER_FILL) {
1078 swfoutput_gfxdrawchar(&output, current_font_id, charid, &col, &m);
1080 msg("<debug> Drawing glyph %d as shape", charid);
1081 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1082 gfxline_t*tglyph = gfxline_clone(glyph);
1083 gfxline_transform(tglyph, &m);
1084 current_text_stroke = gfxline_append(current_text_stroke, tglyph);
1088 void SWFOutputDev::endString(GfxState *state)
1090 int render = state->getRender();
1091 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1092 if(states[statepos].textRender != render)
1093 msg("<error> Internal error: drawChar.render!=beginString.render");
1095 if(current_text_stroke) {
1096 /* fillstroke and stroke text rendering objects we can process right
1097 now (as there may be texts of other rendering modes in this
1098 text object)- clipping objects have to wait until endTextObject,
1100 if(render == RENDER_FILLSTROKE) {
1101 fillGfxLine(state, current_text_stroke);
1102 strokeGfxline(state, current_text_stroke);
1103 gfxline_free(current_text_stroke);
1104 current_text_stroke = 0;
1105 } else if(render == RENDER_STROKE) {
1106 strokeGfxline(state, current_text_stroke);
1107 gfxline_free(current_text_stroke);
1108 current_text_stroke = 0;
1113 void SWFOutputDev::endTextObject(GfxState *state)
1115 int render = state->getRender();
1116 msg("<trace> endTextObject() render=%d textstroke=%08x", render, current_text_stroke);
1117 if(states[statepos].textRender != render)
1118 msg("<error> Internal error: drawChar.render!=beginString.render");
1120 if(current_text_stroke) {
1121 if((render&3) == RENDER_FILL || (render&3) == RENDER_FILLSTROKE) {
1122 fillGfxLine(state, current_text_stroke);
1124 if((render&3) == RENDER_STROKE || (render&3) == RENDER_FILLSTROKE) {
1125 strokeGfxline(state, current_text_stroke);
1127 if((render&4) == RENDER_CLIP) {
1128 clipToGfxLine(state, current_text_stroke);
1130 gfxline_free(current_text_stroke);
1131 current_text_stroke = 0;
1135 /* the logic seems to be as following:
1136 first, beginType3Char is called, with the charcode and the coordinates.
1137 if this function returns true, it already knew about the char and has now drawn it.
1138 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1139 the all draw operations until endType3Char are part of the char (which in this moment is
1140 at the position first passed to beginType3Char). the char ends with endType3Char.
1142 The drawing operations between beginType3Char and endType3Char are somewhat different to
1143 the normal ones. For example, the fillcolor equals the stroke color.
1146 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1148 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1150 /* the character itself is going to be passed using the draw functions */
1151 return gFalse; /* gTrue= is_in_cache? */
1154 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1155 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1157 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1158 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1162 void SWFOutputDev::endType3Char(GfxState *state)
1165 msg("<debug> endType3Char");
1168 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1170 this->currentpage = pageNum;
1172 int rot = doc->getPageRotate(1);
1174 msg("<verbose> startPage %d (%f,%f,%f,%f)\n", pageNum, crop_x1, crop_y1, crop_x2, crop_y2);
1176 msg("<verbose> page is rotated %d degrees\n", rot);
1178 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1179 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1180 Use CropBox, not MediaBox, as page size
1187 state->transform(crop_x1,crop_y1,&x1,&y1);
1188 state->transform(crop_x2,crop_y2,&x2,&y2);
1190 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1191 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1193 /* apply user clip box */
1194 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1195 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1196 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1197 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1198 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1201 if(!outputstarted) {
1202 msg("<verbose> Bounding box is (%f,%f)-(%f,%f)", x1,y1,x2,y2);
1203 swfoutput_init(&output);
1207 swfoutput_newpage(&output, pageNum, user_movex, user_movey, (int)x1, (int)y1, (int)x2, (int)y2);
1210 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1212 msg("<debug> drawlink\n");
1213 double x1, y1, x2, y2, w;
1219 link->getBorder(&x1, &y1, &x2, &y2, &w);
1221 link->getRect(&x1, &y1, &x2, &y2);
1226 cvtUserToDev(x1, y1, &x, &y);
1227 points[0].x = points[4].x = (int)x;
1228 points[0].y = points[4].y = (int)y;
1229 cvtUserToDev(x2, y1, &x, &y);
1230 points[1].x = (int)x;
1231 points[1].y = (int)y;
1232 cvtUserToDev(x2, y2, &x, &y);
1233 points[2].x = (int)x;
1234 points[2].y = (int)y;
1235 cvtUserToDev(x1, y2, &x, &y);
1236 points[3].x = (int)x;
1237 points[3].y = (int)y;
1239 LinkAction*action=link->getAction();
1246 switch(action->getKind())
1250 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1251 LinkDest *dest=NULL;
1252 if (ha->getDest()==NULL)
1253 dest=catalog->findDest(ha->getNamedDest());
1254 else dest=ha->getDest();
1256 if (dest->isPageRef()){
1257 Ref pageref=dest->getPageRef();
1258 page=catalog->findPage(pageref.num,pageref.gen);
1260 else page=dest->getPageNum();
1261 sprintf(buf, "%d", page);
1268 LinkGoToR*l = (LinkGoToR*)action;
1269 GString*g = l->getNamedDest();
1271 s = strdup(g->getCString());
1276 LinkNamed*l = (LinkNamed*)action;
1277 GString*name = l->getName();
1279 s = strdup(name->lowerCase()->getCString());
1280 named = name->getCString();
1283 if(strstr(s, "next") || strstr(s, "forward"))
1285 page = currentpage + 1;
1287 else if(strstr(s, "prev") || strstr(s, "back"))
1289 page = currentpage - 1;
1291 else if(strstr(s, "last") || strstr(s, "end"))
1293 page = pagepos>0?pages[pagepos-1]:0;
1295 else if(strstr(s, "first") || strstr(s, "top"))
1303 case actionLaunch: {
1305 LinkLaunch*l = (LinkLaunch*)action;
1306 GString * str = new GString(l->getFileName());
1307 str->append(l->getParams());
1308 s = strdup(str->getCString());
1314 LinkURI*l = (LinkURI*)action;
1315 GString*g = l->getURI();
1317 url = g->getCString();
1322 case actionUnknown: {
1324 LinkUnknown*l = (LinkUnknown*)action;
1329 msg("<error> Unknown link type!\n");
1333 if(!s) s = strdup("-?-");
1335 if(!linkinfo && (page || url))
1337 msg("<notice> File contains links");
1343 for(t=0;t<pagepos;t++)
1347 swfoutput_linktopage(&output, t, points);
1351 swfoutput_linktourl(&output, url, points);
1355 swfoutput_namedlink(&output, named, points);
1357 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1361 void SWFOutputDev::saveState(GfxState *state) {
1362 msg("<trace> saveState\n");
1365 msg("<error> Too many nested states in pdf.");
1369 states[statepos].clipping = 0; //? shouldn't this be the current value?
1370 states[statepos].textRender = states[statepos-1].textRender;
1373 void SWFOutputDev::restoreState(GfxState *state) {
1374 msg("<trace> restoreState\n");
1376 while(states[statepos].clipping) {
1377 swfoutput_endclip(&output);
1378 states[statepos].clipping--;
1383 char* SWFOutputDev::searchFont(char*name)
1387 int is_standard_font = 0;
1389 msg("<verbose> SearchFont(%s)", name);
1391 /* see if it is a pdf standard font */
1392 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1394 if(!strcmp(name, pdf2t1map[i].pdffont))
1396 name = pdf2t1map[i].filename;
1397 is_standard_font = 1;
1401 /* look in all font files */
1402 for(i=0;i<fontnum;i++)
1404 if(strstr(fonts[i].filename, name))
1406 if(!fonts[i].used) {
1409 if(!is_standard_font)
1410 msg("<notice> Using %s for %s", fonts[i].filename, name);
1412 return strdup(fonts[i].filename);
1418 void SWFOutputDev::updateLineWidth(GfxState *state)
1420 double width = state->getTransformedLineWidth();
1421 //swfoutput_setlinewidth(&output, width);
1424 void SWFOutputDev::updateLineCap(GfxState *state)
1426 int c = state->getLineCap();
1429 void SWFOutputDev::updateLineJoin(GfxState *state)
1431 int j = state->getLineJoin();
1434 void SWFOutputDev::updateFillColor(GfxState *state)
1437 double opaq = state->getFillOpacity();
1438 state->getFillRGB(&rgb);
1440 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1443 void SWFOutputDev::updateStrokeColor(GfxState *state)
1446 double opaq = state->getStrokeOpacity();
1447 state->getStrokeRGB(&rgb);
1448 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1451 void FoFiWrite(void *stream, char *data, int len)
1453 fwrite(data, len, 1, (FILE*)stream);
1456 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1458 char*tmpFileName = NULL;
1464 Object refObj, strObj;
1466 tmpFileName = mktmpname(namebuf);
1469 ret = font->getEmbeddedFontID(&embRef);
1471 msg("<verbose> Didn't get embedded font id");
1472 /* not embedded- the caller should now search the font
1473 directories for this font */
1477 f = fopen(tmpFileName, "wb");
1479 msg("<error> Couldn't create temporary Type 1 font file");
1483 /*if(font->isCIDFont()) {
1484 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1485 GString c = cidFont->getCollection();
1486 msg("<notice> Collection: %s", c.getCString());
1489 if (font->getType() == fontType1C) {
1490 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1492 msg("<error> Couldn't read embedded font file");
1496 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1498 cvt->convertToType1(f);
1500 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1502 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1504 //cvt->convertToCIDType0("test", f);
1505 //cvt->convertToType0("test", f);
1508 } else if(font->getType() == fontTrueType) {
1509 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1510 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1512 msg("<error> Couldn't read embedded font file");
1516 TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1519 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1520 cvt->writeTTF(FoFiWrite, f);
1525 font->getEmbeddedFontID(&embRef);
1526 refObj.initRef(embRef.num, embRef.gen);
1527 refObj.fetch(ref, &strObj);
1529 strObj.streamReset();
1534 f4[t] = strObj.streamGetChar();
1535 f4c[t] = (char)f4[t];
1540 if(!strncmp(f4c, "true", 4)) {
1541 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1542 Change this on the fly */
1543 f4[0] = f4[2] = f4[3] = 0;
1551 while ((c = strObj.streamGetChar()) != EOF) {
1555 strObj.streamClose();
1560 return strdup(tmpFileName);
1563 char* searchForSuitableFont(GfxFont*gfxFont)
1565 char*name = getFontName(gfxFont);
1569 if(!config_use_fontconfig)
1572 #ifdef HAVE_FONTCONFIG
1573 FcPattern *pattern, *match;
1577 static int fcinitcalled = false;
1579 msg("<debug> searchForSuitableFont(%s)", name);
1581 // call init ony once
1582 if (!fcinitcalled) {
1583 msg("<debug> Initializing FontConfig...");
1584 fcinitcalled = true;
1586 msg("<debug> FontConfig Initialization failed. Disabling.");
1587 config_use_fontconfig = 0;
1590 msg("<debug> ...initialized FontConfig");
1593 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1594 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1595 if (gfxFont->isItalic()) // check for italic
1596 msg("<debug> FontConfig: Adding Italic Slant");
1597 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1598 if (gfxFont->isBold()) // check for bold
1599 msg("<debug> FontConfig: Adding Bold Weight");
1600 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1602 msg("<debug> FontConfig: Try to match...");
1603 // configure and match using the original font name
1604 FcConfigSubstitute(0, pattern, FcMatchPattern);
1605 FcDefaultSubstitute(pattern);
1606 match = FcFontMatch(0, pattern, &result);
1608 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1609 msg("<debug> FontConfig: family=%s", (char*)v);
1610 // if we get an exact match
1611 if (strcmp((char *)v, name) == 0) {
1612 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1613 filename = strdup((char*)v); // mem leak
1614 char *nfn = strrchr(filename, '/');
1615 if(nfn) fontname = strdup(nfn+1);
1616 else fontname = filename;
1618 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1620 // initialize patterns
1621 FcPatternDestroy(pattern);
1622 FcPatternDestroy(match);
1624 // now match against serif etc.
1625 if (gfxFont->isSerif()) {
1626 msg("<debug> FontConfig: Create Serif Family Pattern");
1627 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1628 } else if (gfxFont->isFixedWidth()) {
1629 msg("<debug> FontConfig: Create Monospace Family Pattern");
1630 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1632 msg("<debug> FontConfig: Create Sans Family Pattern");
1633 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1637 if (gfxFont->isItalic()) {
1638 msg("<debug> FontConfig: Adding Italic Slant");
1639 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1642 if (gfxFont->isBold()) {
1643 msg("<debug> FontConfig: Adding Bold Weight");
1644 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1647 msg("<debug> FontConfig: Try to match... (2)");
1648 // configure and match using serif etc
1649 FcConfigSubstitute (0, pattern, FcMatchPattern);
1650 FcDefaultSubstitute (pattern);
1651 match = FcFontMatch (0, pattern, &result);
1653 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1654 filename = strdup((char*)v); // mem leak
1655 char *nfn = strrchr(filename, '/');
1656 if(nfn) fontname = strdup(nfn+1);
1657 else fontname = filename;
1659 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1663 //printf("FONTCONFIG: pattern");
1664 //FcPatternPrint(pattern);
1665 //printf("FONTCONFIG: match");
1666 //FcPatternPrint(match);
1668 FcPatternDestroy(pattern);
1669 FcPatternDestroy(match);
1671 pdfswf_addfont(filename);
1678 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1680 char*fontname = 0, *filename = 0;
1681 msg("<notice> subsituteFont(%s)", oldname);
1683 if(!(fontname = searchForSuitableFont(gfxFont))) {
1684 fontname = "Times-Roman";
1686 filename = searchFont(fontname);
1688 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1692 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1693 msg("<fatal> Too many fonts in file.");
1697 substitutesource[substitutepos] = strdup(oldname); //mem leak
1698 substitutetarget[substitutepos] = fontname;
1699 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1702 return strdup(filename); //mem leak
1705 void unlinkfont(char* filename)
1712 if(!strncmp(&filename[l-4],".afm",4)) {
1713 memcpy(&filename[l-4],".pfb",4);
1715 memcpy(&filename[l-4],".pfa",4);
1717 memcpy(&filename[l-4],".afm",4);
1720 if(!strncmp(&filename[l-4],".pfa",4)) {
1721 memcpy(&filename[l-4],".afm",4);
1723 memcpy(&filename[l-4],".pfa",4);
1726 if(!strncmp(&filename[l-4],".pfb",4)) {
1727 memcpy(&filename[l-4],".afm",4);
1729 memcpy(&filename[l-4],".pfb",4);
1734 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1740 int SWFOutputDev::setGfxFont(char*id, char*filename)
1743 fontlist_t*last=0,*l = this->fontlist;
1745 /* TODO: should this be part of the state? */
1748 if(!strcmp(l->id, id)) {
1749 current_font_id = l->id;
1750 current_gfxfont = l->font;
1752 swfoutput_gfxaddfont(&this->output, id, current_gfxfont);
1757 if(!filename) return 0;
1758 font = gfxfont_load(filename);
1761 l->filename = strdup(filename);
1764 current_font_id = l->id;
1765 current_gfxfont = l->font;
1771 swfoutput_gfxaddfont(&this->output, id, current_gfxfont);
1775 void SWFOutputDev::updateFont(GfxState *state)
1777 GfxFont*gfxFont = state->getFont();
1782 char * fontid = getFontID(gfxFont);
1785 /* first, look if we substituted this font before-
1786 this way, we don't initialize the T1 Fonts
1788 for(t=0;t<substitutepos;t++) {
1789 if(!strcmp(fontid, substitutesource[t])) {
1790 free(fontid);fontid=0;
1791 fontid = strdup(substitutetarget[t]);
1796 /* second, see if this is a font which was used before-
1797 if so, we are done */
1798 if(setGfxFont(fontid, 0)) {
1802 /* if(swfoutput_queryfont(&output, fontid))
1803 swfoutput_setfont(&output, fontid, 0);
1805 msg("<debug> updateFont(%s) [cached]", fontid);
1809 // look for Type 3 font
1810 if (gfxFont->getType() == fontType3) {
1812 type3Warning = gTrue;
1813 showFontError(gfxFont, 2);
1819 /* now either load the font, or find a substitution */
1822 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1827 (gfxFont->getType() == fontType1 ||
1828 gfxFont->getType() == fontType1C ||
1829 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
1830 gfxFont->getType() == fontTrueType ||
1831 gfxFont->getType() == fontCIDType2
1834 fileName = writeEmbeddedFontToFile(xref, gfxFont);
1835 if(!fileName) showFontError(gfxFont,0);
1838 char * fontname = getFontName(gfxFont);
1839 fileName = searchFont(fontname);
1840 if(!fileName) showFontError(gfxFont,0);
1843 char * fontname = getFontName(gfxFont);
1844 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
1845 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
1846 fileName = substituteFont(gfxFont, fontid);
1847 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
1848 msg("<notice> Font is now %s (%s)", fontid, fileName);
1852 msg("<error> Couldn't set font %s\n", fontid);
1857 msg("<verbose> updateFont(%s) -> %s", fontid, fileName);
1858 dumpFontInfo("<verbose>", gfxFont);
1860 //swfoutput_setfont(&output, fontid, fileName);
1862 if(!setGfxFont(fontid, 0)) {
1863 setGfxFont(fontid, fileName);
1867 unlinkfont(fileName);
1873 #define SQR(x) ((x)*(x))
1875 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1877 if((newwidth<2 || newheight<2) ||
1878 (width<=newwidth || height<=newheight))
1880 unsigned char*newdata;
1882 newdata= (unsigned char*)malloc(newwidth*newheight);
1884 double fx = (double)(width)/newwidth;
1885 double fy = (double)(height)/newheight;
1887 int blocksize = (int)(8192/(fx*fy));
1888 int r = 8192*256/palettesize;
1889 for(x=0;x<newwidth;x++) {
1890 double ex = px + fx;
1891 int fromx = (int)px;
1893 int xweight1 = (int)(((fromx+1)-px)*256);
1894 int xweight2 = (int)((ex-tox)*256);
1896 for(y=0;y<newheight;y++) {
1897 double ey = py + fy;
1898 int fromy = (int)py;
1900 int yweight1 = (int)(((fromy+1)-py)*256);
1901 int yweight2 = (int)((ey-toy)*256);
1904 for(xx=fromx;xx<=tox;xx++)
1905 for(yy=fromy;yy<=toy;yy++) {
1906 int b = 1-data[width*yy+xx];
1908 if(xx==fromx) weight = (weight*xweight1)/256;
1909 if(xx==tox) weight = (weight*xweight2)/256;
1910 if(yy==fromy) weight = (weight*yweight1)/256;
1911 if(yy==toy) weight = (weight*yweight2)/256;
1914 //if(a) a=(palettesize-1)*r/blocksize;
1915 newdata[y*newwidth+x] = (a*blocksize)/r;
1923 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
1924 int width, int height, GfxImageColorMap*colorMap, GBool invert,
1925 GBool inlineImg, int mask, int*maskColors)
1930 double x1,y1,x2,y2,x3,y3,x4,y4;
1931 ImageStream *imgStr;
1938 ncomps = colorMap->getNumPixelComps();
1939 bits = colorMap->getBits();
1941 imgStr = new ImageStream(str, width, ncomps,bits);
1944 if(!width || !height || (height<=1 && width<=1))
1946 msg("<verbose> Ignoring %d by %d image", width, height);
1947 unsigned char buf[8];
1949 for (y = 0; y < height; ++y)
1950 for (x = 0; x < width; ++x) {
1951 imgStr->getPixel(buf);
1957 state->transform(0, 1, &x1, &y1);
1958 state->transform(0, 0, &x2, &y2);
1959 state->transform(1, 0, &x3, &y3);
1960 state->transform(1, 1, &x4, &y4);
1962 if(!pbminfo && !(str->getKind()==strDCT)) {
1964 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
1968 msg("<verbose> drawing %d by %d masked picture\n", width, height);
1970 if(!jpeginfo && (str->getKind()==strDCT)) {
1971 msg("<notice> file contains jpeg pictures");
1977 unsigned char buf[8];
1979 unsigned char*pic = new unsigned char[width*height];
1982 state->getFillRGB(&rgb);
1984 memset(pal,255,sizeof(pal));
1985 pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
1986 pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
1987 pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
1988 pal[0].a = 255; pal[1].a = 0;
1991 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
1992 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
1993 for (y = 0; y < height; ++y)
1994 for (x = 0; x < width; ++x)
1996 imgStr->getPixel(buf);
1999 pic[width*y+x] = buf[0];
2002 /* the size of the drawn image is added to the identifier
2003 as the same image may require different bitmaps if displayed
2004 at different sizes (due to antialiasing): */
2007 unsigned char*pic2 = 0;
2010 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2019 height = realheight;
2023 /* make a black/white palette */
2028 float r = 255/(numpalette-1);
2030 for(t=0;t<numpalette;t++) {
2031 pal[t].r = (U8)(255*rgb.r);
2032 pal[t].g = (U8)(255*rgb.g);
2033 pal[t].b = (U8)(255*rgb.b);
2034 pal[t].a = (U8)(t*r);
2038 RGBA*pic2 = new RGBA[width*height];
2039 for (y = 0; y < height; ++y) {
2040 for (x = 0; x < width; ++x) {
2041 pic2[width*y+x] = pal[pic[y*width+x]];
2044 swfoutput_drawimagelossless(&output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2053 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2054 RGBA*pic=new RGBA[width*height];
2055 for (y = 0; y < height; ++y) {
2056 for (x = 0; x < width; ++x) {
2057 imgStr->getPixel(pixBuf);
2058 colorMap->getRGB(pixBuf, &rgb);
2059 pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
2060 pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
2061 pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
2062 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2065 if(str->getKind()==strDCT)
2066 swfoutput_drawimagejpeg(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2068 swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2073 RGBA*pic=new RGBA[width*height];
2076 for(t=0;t<256;t++) {
2078 colorMap->getRGB(pixBuf, &rgb);
2079 /*if(maskColors && *maskColors==t) {
2080 msg("<notice> Color %d is transparent", t);
2081 if (imgData->maskColors) {
2083 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2084 if (pix[i] < imgData->maskColors[2*i] ||
2085 pix[i] > imgData->maskColors[2*i+1]) {
2100 pal[t].r = (U8)(rgb.r * 255 + 0.5);
2101 pal[t].g = (U8)(rgb.g * 255 + 0.5);
2102 pal[t].b = (U8)(rgb.b * 255 + 0.5);
2103 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2106 for (y = 0; y < height; ++y) {
2107 for (x = 0; x < width; ++x) {
2108 imgStr->getPixel(pixBuf);
2109 pic[width*y+x] = pal[pixBuf[0]];
2112 swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2120 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2121 int width, int height, GBool invert,
2124 if(states[statepos].textRender & 4) //clipped
2126 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2127 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
2130 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2131 int width, int height, GfxImageColorMap *colorMap,
2132 int *maskColors, GBool inlineImg)
2134 if(states[statepos].textRender & 4) //clipped
2137 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
2138 colorMap?"colorMap":"no colorMap",
2139 maskColors?"maskColors":"no maskColors",
2142 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2143 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2144 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
2147 SWFOutputDev*output = 0;
2149 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2154 if (infoDict->lookup(key, &obj)->isString()) {
2155 s1 = obj.getString();
2156 if ((s1->getChar(0) & 0xff) == 0xfe &&
2157 (s1->getChar(1) & 0xff) == 0xff) {
2159 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2160 if (s1->getChar(i) == '\0') {
2161 s2->append(s1->getChar(i+1));
2164 s2 = new GString("<unicode>");
2168 printf(fmt, s2->getCString());
2171 printf(fmt, s1->getCString());
2177 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2181 if (infoDict->lookup(key, &obj)->isString()) {
2182 s = obj.getString()->getCString();
2183 if (s[0] == 'D' && s[1] == ':') {
2194 void pdfswf_setparameter(char*name, char*value)
2196 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2197 if(!strcmp(name, "caplinewidth")) {
2198 caplinewidth = atof(value);
2199 } else if(!strcmp(name, "zoom")) {
2202 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2203 swfoutput_setparameter("jpegsubpixels", buf);
2204 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2205 swfoutput_setparameter("ppmsubpixels", buf);
2206 } else if(!strcmp(name, "jpegdpi")) {
2208 jpeg_dpi = atoi(value);
2209 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2210 swfoutput_setparameter("jpegsubpixels", buf);
2211 } else if(!strcmp(name, "ppmdpi")) {
2213 ppm_dpi = atoi(value);
2214 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2215 swfoutput_setparameter("ppmsubpixels", buf);
2216 } else if(!strcmp(name, "forceType0Fonts")) {
2217 forceType0Fonts = atoi(value);
2218 } else if(!strcmp(name, "fontdir")) {
2219 pdfswf_addfontdir(value);
2220 } else if(!strcmp(name, "languagedir")) {
2221 pdfswf_addlanguagedir(value);
2222 } else if(!strcmp(name, "fontconfig")) {
2223 config_use_fontconfig = atoi(value);
2225 swfoutput_setparameter(name, value);
2228 void pdfswf_addfont(char*filename)
2231 memset(&f, 0, sizeof(fontfile_t));
2232 f.filename = filename;
2233 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2234 fonts[fontnum++] = f;
2236 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2240 static char* dirseparator()
2249 void pdfswf_addlanguagedir(char*dir)
2252 globalParams = new GlobalParams("");
2254 msg("<notice> Adding %s to language pack directories", dir);
2258 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2259 strcpy(config_file, dir);
2260 strcat(config_file, dirseparator());
2261 strcat(config_file, "add-to-xpdfrc");
2263 fi = fopen(config_file, "rb");
2265 msg("<error> Could not open %s", config_file);
2268 globalParams->parseFile(new GString(config_file), fi);
2272 void pdfswf_addfontdir(char*dirname)
2274 #ifdef HAVE_DIRENT_H
2275 msg("<notice> Adding %s to font directories", dirname);
2276 DIR*dir = opendir(dirname);
2278 msg("<warning> Couldn't open directory %s\n", dirname);
2283 ent = readdir (dir);
2287 char*name = ent->d_name;
2293 if(!strncasecmp(&name[l-4], ".pfa", 4))
2295 if(!strncasecmp(&name[l-4], ".pfb", 4))
2297 if(!strncasecmp(&name[l-4], ".ttf", 4))
2301 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2302 strcpy(fontname, dirname);
2303 strcat(fontname, dirseparator());
2304 strcat(fontname, name);
2305 msg("<verbose> Adding %s to fonts", fontname);
2306 pdfswf_addfont(fontname);
2311 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2316 typedef struct _pdf_doc_internal
2320 } pdf_doc_internal_t;
2321 typedef struct _pdf_page_internal
2323 } pdf_page_internal_t;
2324 typedef struct _swf_output_internal
2326 SWFOutputDev*outputDev;
2327 } swf_output_internal_t;
2329 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2331 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2332 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2333 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2334 memset(i, 0, sizeof(pdf_doc_internal_t));
2335 pdf_doc->internal = i;
2337 GString *fileName = new GString(filename);
2343 globalParams = new GlobalParams("");
2346 if (userPassword && userPassword[0]) {
2347 userPW = new GString(userPassword);
2351 i->doc = new PDFDoc(fileName, userPW);
2355 if (!i->doc->isOk()) {
2360 i->doc->getDocInfo(&info);
2361 if (info.isDict() &&
2362 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2363 printInfoString(info.getDict(), "Title", "Title: %s\n");
2364 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2365 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2366 printInfoString(info.getDict(), "Author", "Author: %s\n");
2367 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2368 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2369 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2370 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2371 printf("Pages: %d\n", i->doc->getNumPages());
2372 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2373 printf("Encrypted: ");
2374 if (i->doc->isEncrypted()) {
2375 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2376 i->doc->okToPrint() ? "yes" : "no",
2377 i->doc->okToCopy() ? "yes" : "no",
2378 i->doc->okToChange() ? "yes" : "no",
2379 i->doc->okToAddNotes() ? "yes" : "no");
2386 pdf_doc->num_pages = i->doc->getNumPages();
2388 if (i->doc->isEncrypted()) {
2389 if(!i->doc->okToCopy()) {
2390 printf("PDF disallows copying.\n");
2393 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2400 void pdfswf_preparepage(int page)
2404 pages = (int*)malloc(1024*sizeof(int));
2407 if(pagepos == pagebuflen)
2410 pages = (int*)realloc(pages, pagebuflen);
2413 pages[pagepos++] = page;
2420 delete globalParams;globalParams=0;
2421 Object::memCheck(stderr);
2426 void pdf_destroy(pdf_doc_t*pdf_doc)
2428 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2430 msg("<debug> pdfswf.cc: pdfswf_close()");
2431 delete i->doc; i->doc=0;
2433 free(pages); pages = 0; //FIXME
2435 free(pdf_doc->internal);pdf_doc->internal=0;
2436 free(pdf_doc);pdf_doc=0;
2439 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2441 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2443 if(page < 1 || page > pdf_doc->num_pages)
2446 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2447 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2448 memset(pi, 0, sizeof(pdf_page_internal_t));
2449 pdf_page->internal = pi;
2451 pdf_page->parent = pdf_doc;
2452 pdf_page->nr = page;
2456 void pdf_page_destroy(pdf_page_t*pdf_page)
2458 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2459 free(pdf_page->internal);pdf_page->internal = 0;
2460 free(pdf_page);pdf_page=0;
2463 swf_output_t* swf_output_init()
2465 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2466 memset(swf_output, 0, sizeof(swf_output_t));
2467 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2468 memset(i, 0, sizeof(swf_output_internal_t));
2469 swf_output->internal = i;
2471 i->outputDev = new SWFOutputDev();
2475 void swf_output_setparameter(swf_output_t*swf_output, char*name, char*value)
2478 pdfswf_setparameter(name, value);
2481 void swf_output_pagefeed(swf_output_t*swf)
2483 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2484 i->outputDev->pagefeed();
2485 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2488 int swf_output_save(swf_output_t*swf, char*filename)
2490 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2491 int ret = i->outputDev->save(filename);
2492 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2496 void* swf_output_get(swf_output_t*swf)
2498 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2499 void* ret = i->outputDev->getSWF();
2500 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2504 void swf_output_destroy(swf_output_t*output)
2506 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2507 delete i->outputDev; i->outputDev=0;
2508 free(output->internal);output->internal=0;
2512 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2514 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2515 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2518 swfoutput_setparameter("protect", "1");
2520 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2522 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2524 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2526 si->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2529 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2531 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2532 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2534 si->outputDev->setMove(x,y);
2535 if((x1|y1|x2|y2)==0) x2++;
2536 si->outputDev->setClip(x1,y1,x2,y2);
2538 pdf_page_render2(page, output);
2540 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2542 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2543 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2545 si->outputDev->setMove(0,0);
2546 si->outputDev->setClip(0,0,0,0);
2548 pdf_page_render2(page, output);
2552 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2554 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2555 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2556 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2557 memset(info, 0, sizeof(pdf_page_info_t));
2559 InfoOutputDev*output = new InfoOutputDev;
2562 pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2564 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2567 info->xMin = output->x1;
2568 info->yMin = output->y1;
2569 info->xMax = output->x2;
2570 info->yMax = output->y2;
2571 info->number_of_images = output->num_images;
2572 info->number_of_links = output->num_links;
2573 info->number_of_fonts = output->num_fonts;
2580 void pdf_page_info_destroy(pdf_page_info_t*info)