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 gfxline_t* current_text_clip;
277 char* current_font_id;
278 gfxfont_t* current_gfxfont;
279 gfxmatrix_t current_font_matrix;
281 fontlist_t* fontlist;
284 static char*getFontID(GfxFont*font);
286 class InfoOutputDev: public OutputDev
300 virtual ~InfoOutputDev()
303 virtual GBool upsideDown() {return gTrue;}
304 virtual GBool useDrawChar() {return gTrue;}
305 virtual GBool useGradients() {return gTrue;}
306 virtual GBool interpretType3Chars() {return gTrue;}
307 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
310 state->transform(crop_x1,crop_y1,&x1,&y1);
311 state->transform(crop_x2,crop_y2,&x2,&y2);
312 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
313 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
319 virtual void drawLink(Link *link, Catalog *catalog)
323 virtual void updateFont(GfxState *state)
325 GfxFont*font = state->getFont();
328 /*char*id = getFontID(font);*/
332 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
333 int width, int height, GBool invert,
338 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
339 int width, int height, GfxImageColorMap *colorMap,
340 int *maskColors, GBool inlineImg)
346 SWFOutputDev::SWFOutputDev()
364 current_text_stroke = 0;
365 current_text_clip = 0;
367 memset(&output, 0, sizeof(output));
368 // printf("SWFOutputDev::SWFOutputDev() \n");
371 void SWFOutputDev::setMove(int x,int y)
373 this->user_movex = x;
374 this->user_movey = y;
377 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
379 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
380 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
382 this->user_clipx1 = x1;
383 this->user_clipy1 = y1;
384 this->user_clipx2 = x2;
385 this->user_clipy2 = y2;
387 void SWFOutputDev::getDimensions(int*x1,int*y1,int*x2,int*y2)
389 return swfoutput_getdimensions(&output, x1,y1,x2,y2);
392 static char*getFontID(GfxFont*font)
394 GString*gstr = font->getName();
395 char* fontname = gstr==0?0:gstr->getCString();
399 sprintf(buf, "UFONT%d", r->num);
402 return strdup(fontname);
405 static char*getFontName(GfxFont*font)
407 char*fontid = getFontID(font);
409 char* plus = strchr(fontid, '+');
410 if(plus && plus < &fontid[strlen(fontid)-1]) {
411 fontname = strdup(plus+1);
413 fontname = strdup(fontid);
419 static char mybuf[1024];
420 static char* gfxstate2str(GfxState *state)
424 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
431 if(state->getX1()!=0.0)
432 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
433 if(state->getY1()!=0.0)
434 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
435 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
436 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
437 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
438 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
439 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
440 state->getFillColor()->c[0], state->getFillColor()->c[1]);
441 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
442 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
443 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
444 state->getFillColor()->c[0], state->getFillColor()->c[1],
445 state->getFillColor()->c[2], state->getFillColor()->c[3],
446 state->getFillColor()->c[4], state->getFillColor()->c[5],
447 state->getFillColor()->c[6], state->getFillColor()->c[7]);
448 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
449 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
450 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
451 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
452 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
453 state->getFillRGB(&rgb);
454 if(rgb.r || rgb.g || rgb.b)
455 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
456 state->getStrokeRGB(&rgb);
457 if(rgb.r || rgb.g || rgb.b)
458 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
459 if(state->getFillColorSpace()->getNComps()>1)
460 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
461 if(state->getStrokeColorSpace()->getNComps()>1)
462 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
463 if(state->getFillPattern())
464 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
465 if(state->getStrokePattern())
466 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
468 if(state->getFillOpacity()!=1.0)
469 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
470 if(state->getStrokeOpacity()!=1.0)
471 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
473 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
478 state->getLineDash(&dash, &length, &start);
482 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
483 for(t=0;t<length;t++) {
484 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
486 bufpos+=sprintf(bufpos,"]");
489 if(state->getFlatness()!=1)
490 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
491 if(state->getLineJoin()!=0)
492 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
493 if(state->getLineJoin()!=0)
494 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
495 if(state->getLineJoin()!=0)
496 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
498 if(state->getFont() && getFontID(state->getFont()))
499 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
500 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
501 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
502 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
503 if(state->getCharSpace())
504 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
505 if(state->getWordSpace())
506 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
507 if(state->getHorizScaling()!=1.0)
508 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
509 if(state->getLeading())
510 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
512 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
513 if(state->getRender())
514 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
515 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
516 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
517 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
518 if(state->getLineX())
519 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
520 if(state->getLineY())
521 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
522 bufpos+=sprintf(bufpos," ");
526 static void dumpFontInfo(char*loglevel, GfxFont*font);
527 static int lastdumps[1024];
528 static int lastdumppos = 0;
533 static void showFontError(GfxFont*font, int nr)
537 for(t=0;t<lastdumppos;t++)
538 if(lastdumps[t] == r->num)
542 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
543 lastdumps[lastdumppos++] = r->num;
545 msg("<warning> The following font caused problems:");
547 msg("<warning> The following font caused problems (substituting):");
549 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
550 dumpFontInfo("<warning>", font);
553 static void dumpFontInfo(char*loglevel, GfxFont*font)
555 char* id = getFontID(font);
556 char* name = getFontName(font);
557 Ref* r=font->getID();
558 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
560 GString*gstr = font->getTag();
562 msg("%s| Tag: %s\n", loglevel, id);
564 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
566 GfxFontType type=font->getType();
568 case fontUnknownType:
569 msg("%s| Type: unknown\n",loglevel);
572 msg("%s| Type: 1\n",loglevel);
575 msg("%s| Type: 1C\n",loglevel);
578 msg("%s| Type: 3\n",loglevel);
581 msg("%s| Type: TrueType\n",loglevel);
584 msg("%s| Type: CIDType0\n",loglevel);
587 msg("%s| Type: CIDType0C\n",loglevel);
590 msg("%s| Type: CIDType2\n",loglevel);
595 GBool embedded = font->getEmbeddedFontID(&embRef);
597 if(font->getEmbeddedFontName()) {
598 embeddedName = font->getEmbeddedFontName()->getCString();
601 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
603 gstr = font->getExtFontFile();
605 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
607 // Get font descriptor flags.
608 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
609 if(font->isSerif()) msg("%s| is serif\n", loglevel);
610 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
611 if(font->isItalic()) msg("%s| is italic\n", loglevel);
612 if(font->isBold()) msg("%s| is bold\n", loglevel);
618 //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");}
619 //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");}
622 void dump_outline(gfxline_t*line)
625 if(line->type == gfx_moveTo) {
626 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
627 } else if(line->type == gfx_lineTo) {
628 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
629 } else if(line->type == gfx_splineTo) {
630 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
636 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed)
638 int num = path->getNumSubpaths();
641 double lastx=0,lasty=0,posx=0,posy=0;
644 msg("<warning> empty path");
648 gfxdrawer_target_gfxline(&draw);
650 for(t = 0; t < num; t++) {
651 GfxSubpath *subpath = path->getSubpath(t);
652 int subnum = subpath->getNumPoints();
653 double bx=0,by=0,cx=0,cy=0;
655 for(s=0;s<subnum;s++) {
657 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
659 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
660 draw.lineTo(&draw, lastx, lasty);
662 draw.moveTo(&draw, x,y);
667 } else if(subpath->getCurve(s) && cpos==0) {
671 } else if(subpath->getCurve(s) && cpos==1) {
679 draw.lineTo(&draw, x,y);
681 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y);
688 /* fix non-closed lines */
689 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
690 draw.lineTo(&draw, lastx, lasty);
692 gfxline_t*result = (gfxline_t*)draw.result(&draw);
696 /*----------------------------------------------------------------------------
697 * Primitive Graphic routines
698 *----------------------------------------------------------------------------*/
700 void SWFOutputDev::stroke(GfxState *state)
702 GfxPath * path = state->getPath();
703 gfxline_t*line= gfxPath_to_gfxline(state, path, 0);
704 strokeGfxline(state, line);
708 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
710 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
711 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
712 double miterLimit = state->getMiterLimit();
713 double width = state->getTransformedLineWidth();
716 double opaq = state->getStrokeOpacity();
718 state->getFillRGB(&rgb);
720 state->getStrokeRGB(&rgb);
722 col.r = (unsigned char)(rgb.r*255);
723 col.g = (unsigned char)(rgb.g*255);
724 col.b = (unsigned char)(rgb.b*255);
725 col.a = (unsigned char)(opaq*255);
727 gfx_capType capType = gfx_capRound;
728 if(lineCap == 0) capType = gfx_capButt;
729 else if(lineCap == 1) capType = gfx_capRound;
730 else if(lineCap == 2) capType = gfx_capSquare;
732 gfx_joinType joinType = gfx_joinRound;
733 if(lineJoin == 0) joinType = gfx_joinMiter;
734 else if(lineJoin == 1) joinType = gfx_joinRound;
735 else if(lineJoin == 2) joinType = gfx_joinBevel;
738 double dashphase = 0;
740 state->getLineDash(&ldash, &dashnum, &dashphase);
744 if(dashnum && ldash) {
745 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
749 msg("<trace> %d dashes", dashnum);
750 msg("<trace> | phase: %f", dashphase);
751 for(t=0;t<dashnum;t++) {
753 msg("<trace> | d%-3d: %f", t, ldash[t]);
756 if(getLogLevel() >= LOGLEVEL_TRACE) {
760 line2 = gfxtool_dash_line(line, dash, dashphase);
762 msg("<trace> After dashing:");
765 if(getLogLevel() >= LOGLEVEL_TRACE) {
767 state->getStrokeGray(&gray);
768 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n",
770 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
771 lineCap==0?"butt": (lineJoin==1?"round":"square"),
773 col.r,col.g,col.b,col.a,
779 swfoutput_drawgfxline(&output, line, width, &col, capType, joinType, miterLimit);
785 gfxcolor_t getFillColor(GfxState * state)
788 double opaq = state->getFillOpacity();
789 state->getFillRGB(&rgb);
791 col.r = (unsigned char)(rgb.r*255);
792 col.g = (unsigned char)(rgb.g*255);
793 col.b = (unsigned char)(rgb.b*255);
794 col.a = (unsigned char)(opaq*255);
798 void SWFOutputDev::fillGfxLine(GfxState *state, gfxline_t*line)
800 gfxcolor_t col = getFillColor(state);
802 if(getLogLevel() >= LOGLEVEL_TRACE) {
803 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
806 swfoutput_fillgfxline(&output, line, &col);
808 void SWFOutputDev::fill(GfxState *state)
810 GfxPath * path = state->getPath();
811 gfxline_t*line= gfxPath_to_gfxline(state, path, 1);
812 fillGfxLine(state, line);
815 void SWFOutputDev::eoFill(GfxState *state)
817 GfxPath * path = state->getPath();
818 gfxcolor_t col = getFillColor(state);
820 gfxline_t*line= gfxPath_to_gfxline(state, path, 1);
822 if(getLogLevel() >= LOGLEVEL_TRACE) {
823 msg("<trace> eofill\n");
827 swfoutput_fillgfxline(&output, line, &col);
831 void SWFOutputDev::clip(GfxState *state)
833 GfxPath * path = state->getPath();
834 gfxline_t*line = gfxPath_to_gfxline(state, path, 1);
835 clipToGfxLine(state, line);
839 void SWFOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line)
841 if(getLogLevel() >= LOGLEVEL_TRACE) {
842 msg("<trace> clip\n");
846 swfoutput_startclip(&output, line);
847 states[statepos].clipping++;
849 void SWFOutputDev::eoClip(GfxState *state)
851 GfxPath * path = state->getPath();
852 gfxline_t*line = gfxPath_to_gfxline(state, path, 1);
854 if(getLogLevel() >= LOGLEVEL_TRACE) {
855 msg("<trace> eoclip\n");
859 swfoutput_startclip(&output, line);
860 states[statepos].clipping++;
864 /* pass through functions for swf_output */
865 int SWFOutputDev::save(char*filename)
867 return swfoutput_save(&output, filename);
869 void SWFOutputDev::pagefeed()
871 swfoutput_pagefeed(&output);
873 void* SWFOutputDev::getSWF()
875 return (void*)swfoutput_get(&output);
878 SWFOutputDev::~SWFOutputDev()
880 swfoutput_destroy(&output);
883 fontlist_t*l = this->fontlist;
885 fontlist_t*next = l->next;
887 gfxfont_free(l->font);
894 GBool SWFOutputDev::upsideDown()
896 msg("<debug> upsidedown? yes");
899 GBool SWFOutputDev::useDrawChar()
903 GBool SWFOutputDev::useGradients()
907 msg("<notice> File contains gradients");
913 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
914 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
916 #define RENDER_FILL 0
917 #define RENDER_STROKE 1
918 #define RENDER_FILLSTROKE 2
919 #define RENDER_INVISIBLE 3
920 #define RENDER_CLIP 4
922 static char tmp_printstr[4096];
923 char* makeStringPrintable(char*str)
925 int len = strlen(str);
940 tmp_printstr[len++] = '.';
941 tmp_printstr[len++] = '.';
942 tmp_printstr[len++] = '.';
944 tmp_printstr[len] = 0;
949 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
953 for(t=0;t<font->num_glyphs;t++) {
954 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
955 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
959 /* if we didn't find the character, maybe
960 we can find the capitalized version */
961 for(t=0;t<font->num_glyphs;t++) {
962 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
963 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
969 /* try to use the unicode id */
970 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
971 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
972 return font->unicode2glyph[u];
975 if(charnr>=0 && charnr<font->num_glyphs) {
976 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
984 void SWFOutputDev::beginString(GfxState *state, GString *s)
986 int render = state->getRender();
987 if(current_text_stroke) {
988 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
991 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
992 double m11,m21,m12,m22;
993 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
994 state->getFontTransMat(&m11, &m12, &m21, &m22);
995 m11 *= state->getHorizScaling();
996 m21 *= state->getHorizScaling();
998 this->current_font_matrix.m00 = m11 / 1024.0;
999 this->current_font_matrix.m01 = m12 / 1024.0;
1000 this->current_font_matrix.m10 = -m21 / 1024.0;
1001 this->current_font_matrix.m11 = -m22 / 1024.0;
1002 this->current_font_matrix.tx = 0;
1003 this->current_font_matrix.ty = 0;
1005 gfxmatrix_t m = this->current_font_matrix;
1007 /*if(render != 3 && render != 0)
1008 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1009 states[statepos].textRender = render;
1012 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1013 double dx, double dy,
1014 double originX, double originY,
1015 CharCode c, Unicode *_u, int uLen)
1017 int render = state->getRender();
1018 // check for invisible text -- this is used by Acrobat Capture
1022 if(states[statepos].textRender != render)
1023 msg("<error> Internal error: drawChar.render!=beginString.render");
1025 gfxcolor_t col = getFillColor(state);
1027 Gushort *CIDToGIDMap = 0;
1028 GfxFont*font = state->getFont();
1030 if(font->getType() == fontType3) {
1031 /* type 3 chars are passed as graphics */
1032 msg("<debug> type3 char at %f/%f", x, y);
1043 /* find out char name from unicode index
1044 TODO: should be precomputed
1046 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1047 if(nameToUnicodeTab[t].u == u) {
1048 name = nameToUnicodeTab[t].name;
1055 if(font->isCIDFont()) {
1056 GfxCIDFont*cfont = (GfxCIDFont*)font;
1058 if(font->getType() == fontCIDType2)
1059 CIDToGIDMap = cfont->getCIDToGID();
1062 font8 = (Gfx8BitFont*)font;
1063 char**enc=font8->getEncoding();
1068 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);
1071 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);
1074 int charid = getGfxCharID(current_gfxfont, c, name, u);
1076 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1077 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1081 gfxmatrix_t m = this->current_font_matrix;
1082 state->transform(x, y, &m.tx, &m.ty);
1084 if(render == RENDER_FILL) {
1085 swfoutput_gfxdrawchar(&output, current_font_id, charid, &col, &m);
1087 msg("<debug> Drawing glyph %d as shape", charid);
1088 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1089 gfxline_t*tglyph = gfxline_clone(glyph);
1090 gfxline_transform(tglyph, &m);
1091 if((render&3) != RENDER_INVISIBLE) {
1092 gfxline_t*add = gfxline_clone(tglyph);
1093 current_text_stroke = gfxline_append(current_text_stroke, add);
1095 if(render&RENDER_CLIP) {
1096 gfxline_t*add = gfxline_clone(tglyph);
1097 current_text_clip = gfxline_append(current_text_clip, add);
1099 gfxline_free(tglyph);
1103 void SWFOutputDev::endString(GfxState *state)
1105 int render = state->getRender();
1106 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1107 if(states[statepos].textRender != render)
1108 msg("<error> Internal error: drawChar.render!=beginString.render");
1110 if(current_text_stroke) {
1111 /* fillstroke and stroke text rendering objects we can process right
1112 now (as there may be texts of other rendering modes in this
1113 text object)- clipping objects have to wait until endTextObject,
1115 if((render&3) == RENDER_FILL) {
1116 fillGfxLine(state, current_text_stroke);
1117 gfxline_free(current_text_stroke);
1118 current_text_stroke = 0;
1119 } else if((render&3) == RENDER_FILLSTROKE) {
1120 fillGfxLine(state, current_text_stroke);
1121 strokeGfxline(state, current_text_stroke);
1122 gfxline_free(current_text_stroke);
1123 current_text_stroke = 0;
1124 } else if((render&3) == RENDER_STROKE) {
1125 strokeGfxline(state, current_text_stroke);
1126 gfxline_free(current_text_stroke);
1127 current_text_stroke = 0;
1132 void SWFOutputDev::endTextObject(GfxState *state)
1134 int render = state->getRender();
1135 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1136 if(states[statepos].textRender != render)
1137 msg("<error> Internal error: drawChar.render!=beginString.render");
1139 if(current_text_clip) {
1140 clipToGfxLine(state, current_text_clip);
1141 gfxline_free(current_text_clip);
1142 current_text_clip = 0;
1146 /* the logic seems to be as following:
1147 first, beginType3Char is called, with the charcode and the coordinates.
1148 if this function returns true, it already knew about the char and has now drawn it.
1149 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1150 the all draw operations until endType3Char are part of the char (which in this moment is
1151 at the position first passed to beginType3Char). the char ends with endType3Char.
1153 The drawing operations between beginType3Char and endType3Char are somewhat different to
1154 the normal ones. For example, the fillcolor equals the stroke color.
1157 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1159 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1161 /* the character itself is going to be passed using the draw functions */
1162 return gFalse; /* gTrue= is_in_cache? */
1165 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1166 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1168 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1169 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1173 void SWFOutputDev::endType3Char(GfxState *state)
1176 msg("<debug> endType3Char");
1179 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1181 this->currentpage = pageNum;
1183 int rot = doc->getPageRotate(1);
1185 msg("<verbose> startPage %d (%f,%f,%f,%f)\n", pageNum, crop_x1, crop_y1, crop_x2, crop_y2);
1187 msg("<verbose> page is rotated %d degrees\n", rot);
1189 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1190 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1191 Use CropBox, not MediaBox, as page size
1198 state->transform(crop_x1,crop_y1,&x1,&y1);
1199 state->transform(crop_x2,crop_y2,&x2,&y2);
1201 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1202 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1204 /* apply user clip box */
1205 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1206 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1207 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1208 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1209 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1212 if(!outputstarted) {
1213 msg("<verbose> Bounding box is (%f,%f)-(%f,%f)", x1,y1,x2,y2);
1214 swfoutput_init(&output);
1218 swfoutput_newpage(&output, pageNum, user_movex, user_movey, (int)x1, (int)y1, (int)x2, (int)y2);
1221 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1223 msg("<debug> drawlink\n");
1224 double x1, y1, x2, y2, w;
1230 link->getBorder(&x1, &y1, &x2, &y2, &w);
1232 link->getRect(&x1, &y1, &x2, &y2);
1237 cvtUserToDev(x1, y1, &x, &y);
1238 points[0].x = points[4].x = (int)x;
1239 points[0].y = points[4].y = (int)y;
1240 cvtUserToDev(x2, y1, &x, &y);
1241 points[1].x = (int)x;
1242 points[1].y = (int)y;
1243 cvtUserToDev(x2, y2, &x, &y);
1244 points[2].x = (int)x;
1245 points[2].y = (int)y;
1246 cvtUserToDev(x1, y2, &x, &y);
1247 points[3].x = (int)x;
1248 points[3].y = (int)y;
1250 LinkAction*action=link->getAction();
1257 switch(action->getKind())
1261 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1262 LinkDest *dest=NULL;
1263 if (ha->getDest()==NULL)
1264 dest=catalog->findDest(ha->getNamedDest());
1265 else dest=ha->getDest();
1267 if (dest->isPageRef()){
1268 Ref pageref=dest->getPageRef();
1269 page=catalog->findPage(pageref.num,pageref.gen);
1271 else page=dest->getPageNum();
1272 sprintf(buf, "%d", page);
1279 LinkGoToR*l = (LinkGoToR*)action;
1280 GString*g = l->getNamedDest();
1282 s = strdup(g->getCString());
1287 LinkNamed*l = (LinkNamed*)action;
1288 GString*name = l->getName();
1290 s = strdup(name->lowerCase()->getCString());
1291 named = name->getCString();
1294 if(strstr(s, "next") || strstr(s, "forward"))
1296 page = currentpage + 1;
1298 else if(strstr(s, "prev") || strstr(s, "back"))
1300 page = currentpage - 1;
1302 else if(strstr(s, "last") || strstr(s, "end"))
1304 page = pagepos>0?pages[pagepos-1]:0;
1306 else if(strstr(s, "first") || strstr(s, "top"))
1314 case actionLaunch: {
1316 LinkLaunch*l = (LinkLaunch*)action;
1317 GString * str = new GString(l->getFileName());
1318 str->append(l->getParams());
1319 s = strdup(str->getCString());
1325 LinkURI*l = (LinkURI*)action;
1326 GString*g = l->getURI();
1328 url = g->getCString();
1333 case actionUnknown: {
1335 LinkUnknown*l = (LinkUnknown*)action;
1340 msg("<error> Unknown link type!\n");
1344 if(!s) s = strdup("-?-");
1346 if(!linkinfo && (page || url))
1348 msg("<notice> File contains links");
1354 for(t=0;t<pagepos;t++)
1358 swfoutput_linktopage(&output, t, points);
1362 swfoutput_linktourl(&output, url, points);
1366 swfoutput_namedlink(&output, named, points);
1368 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1372 void SWFOutputDev::saveState(GfxState *state) {
1373 msg("<trace> saveState\n");
1376 msg("<error> Too many nested states in pdf.");
1380 states[statepos].clipping = 0; //? shouldn't this be the current value?
1381 states[statepos].textRender = states[statepos-1].textRender;
1384 void SWFOutputDev::restoreState(GfxState *state) {
1385 msg("<trace> restoreState\n");
1387 while(states[statepos].clipping) {
1388 swfoutput_endclip(&output);
1389 states[statepos].clipping--;
1394 char* SWFOutputDev::searchFont(char*name)
1398 int is_standard_font = 0;
1400 msg("<verbose> SearchFont(%s)", name);
1402 /* see if it is a pdf standard font */
1403 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1405 if(!strcmp(name, pdf2t1map[i].pdffont))
1407 name = pdf2t1map[i].filename;
1408 is_standard_font = 1;
1412 /* look in all font files */
1413 for(i=0;i<fontnum;i++)
1415 if(strstr(fonts[i].filename, name))
1417 if(!fonts[i].used) {
1420 if(!is_standard_font)
1421 msg("<notice> Using %s for %s", fonts[i].filename, name);
1423 return strdup(fonts[i].filename);
1429 void SWFOutputDev::updateLineWidth(GfxState *state)
1431 double width = state->getTransformedLineWidth();
1432 //swfoutput_setlinewidth(&output, width);
1435 void SWFOutputDev::updateLineCap(GfxState *state)
1437 int c = state->getLineCap();
1440 void SWFOutputDev::updateLineJoin(GfxState *state)
1442 int j = state->getLineJoin();
1445 void SWFOutputDev::updateFillColor(GfxState *state)
1448 double opaq = state->getFillOpacity();
1449 state->getFillRGB(&rgb);
1451 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1454 void SWFOutputDev::updateStrokeColor(GfxState *state)
1457 double opaq = state->getStrokeOpacity();
1458 state->getStrokeRGB(&rgb);
1459 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1462 void FoFiWrite(void *stream, char *data, int len)
1464 fwrite(data, len, 1, (FILE*)stream);
1467 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1469 char*tmpFileName = NULL;
1475 Object refObj, strObj;
1477 tmpFileName = mktmpname(namebuf);
1480 ret = font->getEmbeddedFontID(&embRef);
1482 msg("<verbose> Didn't get embedded font id");
1483 /* not embedded- the caller should now search the font
1484 directories for this font */
1488 f = fopen(tmpFileName, "wb");
1490 msg("<error> Couldn't create temporary Type 1 font file");
1494 /*if(font->isCIDFont()) {
1495 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1496 GString c = cidFont->getCollection();
1497 msg("<notice> Collection: %s", c.getCString());
1500 //if (font->getType() == fontType1C) {
1501 if (0) { //font->getType() == fontType1C) {
1502 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1504 msg("<error> Couldn't read embedded font file");
1508 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1510 cvt->convertToType1(f);
1512 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1514 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1516 //cvt->convertToCIDType0("test", f);
1517 //cvt->convertToType0("test", f);
1520 } else if(font->getType() == fontTrueType) {
1521 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1522 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1524 msg("<error> Couldn't read embedded font file");
1528 TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1531 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1532 cvt->writeTTF(FoFiWrite, f);
1537 font->getEmbeddedFontID(&embRef);
1538 refObj.initRef(embRef.num, embRef.gen);
1539 refObj.fetch(ref, &strObj);
1541 strObj.streamReset();
1546 f4[t] = strObj.streamGetChar();
1547 f4c[t] = (char)f4[t];
1552 if(!strncmp(f4c, "true", 4)) {
1553 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1554 Change this on the fly */
1555 f4[0] = f4[2] = f4[3] = 0;
1563 while ((c = strObj.streamGetChar()) != EOF) {
1567 strObj.streamClose();
1572 return strdup(tmpFileName);
1575 char* searchForSuitableFont(GfxFont*gfxFont)
1577 char*name = getFontName(gfxFont);
1581 if(!config_use_fontconfig)
1584 #ifdef HAVE_FONTCONFIG
1585 FcPattern *pattern, *match;
1589 static int fcinitcalled = false;
1591 msg("<debug> searchForSuitableFont(%s)", name);
1593 // call init ony once
1594 if (!fcinitcalled) {
1595 msg("<debug> Initializing FontConfig...");
1596 fcinitcalled = true;
1598 msg("<debug> FontConfig Initialization failed. Disabling.");
1599 config_use_fontconfig = 0;
1602 msg("<debug> ...initialized FontConfig");
1605 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1606 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1607 if (gfxFont->isItalic()) // check for italic
1608 msg("<debug> FontConfig: Adding Italic Slant");
1609 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1610 if (gfxFont->isBold()) // check for bold
1611 msg("<debug> FontConfig: Adding Bold Weight");
1612 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1614 msg("<debug> FontConfig: Try to match...");
1615 // configure and match using the original font name
1616 FcConfigSubstitute(0, pattern, FcMatchPattern);
1617 FcDefaultSubstitute(pattern);
1618 match = FcFontMatch(0, pattern, &result);
1620 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1621 msg("<debug> FontConfig: family=%s", (char*)v);
1622 // if we get an exact match
1623 if (strcmp((char *)v, name) == 0) {
1624 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1625 filename = strdup((char*)v); // mem leak
1626 char *nfn = strrchr(filename, '/');
1627 if(nfn) fontname = strdup(nfn+1);
1628 else fontname = filename;
1630 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1632 // initialize patterns
1633 FcPatternDestroy(pattern);
1634 FcPatternDestroy(match);
1636 // now match against serif etc.
1637 if (gfxFont->isSerif()) {
1638 msg("<debug> FontConfig: Create Serif Family Pattern");
1639 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1640 } else if (gfxFont->isFixedWidth()) {
1641 msg("<debug> FontConfig: Create Monospace Family Pattern");
1642 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1644 msg("<debug> FontConfig: Create Sans Family Pattern");
1645 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1649 if (gfxFont->isItalic()) {
1650 msg("<debug> FontConfig: Adding Italic Slant");
1651 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1654 if (gfxFont->isBold()) {
1655 msg("<debug> FontConfig: Adding Bold Weight");
1656 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1659 msg("<debug> FontConfig: Try to match... (2)");
1660 // configure and match using serif etc
1661 FcConfigSubstitute (0, pattern, FcMatchPattern);
1662 FcDefaultSubstitute (pattern);
1663 match = FcFontMatch (0, pattern, &result);
1665 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1666 filename = strdup((char*)v); // mem leak
1667 char *nfn = strrchr(filename, '/');
1668 if(nfn) fontname = strdup(nfn+1);
1669 else fontname = filename;
1671 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1675 //printf("FONTCONFIG: pattern");
1676 //FcPatternPrint(pattern);
1677 //printf("FONTCONFIG: match");
1678 //FcPatternPrint(match);
1680 FcPatternDestroy(pattern);
1681 FcPatternDestroy(match);
1683 pdfswf_addfont(filename);
1690 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1692 char*fontname = 0, *filename = 0;
1693 msg("<notice> subsituteFont(%s)", oldname);
1695 if(!(fontname = searchForSuitableFont(gfxFont))) {
1696 fontname = "Times-Roman";
1698 filename = searchFont(fontname);
1700 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1704 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1705 msg("<fatal> Too many fonts in file.");
1709 substitutesource[substitutepos] = strdup(oldname); //mem leak
1710 substitutetarget[substitutepos] = fontname;
1711 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1714 return strdup(filename); //mem leak
1717 void unlinkfont(char* filename)
1724 if(!strncmp(&filename[l-4],".afm",4)) {
1725 memcpy(&filename[l-4],".pfb",4);
1727 memcpy(&filename[l-4],".pfa",4);
1729 memcpy(&filename[l-4],".afm",4);
1732 if(!strncmp(&filename[l-4],".pfa",4)) {
1733 memcpy(&filename[l-4],".afm",4);
1735 memcpy(&filename[l-4],".pfa",4);
1738 if(!strncmp(&filename[l-4],".pfb",4)) {
1739 memcpy(&filename[l-4],".afm",4);
1741 memcpy(&filename[l-4],".pfb",4);
1746 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1752 int SWFOutputDev::setGfxFont(char*id, char*filename)
1755 fontlist_t*last=0,*l = this->fontlist;
1757 /* TODO: should this be part of the state? */
1760 if(!strcmp(l->id, id)) {
1761 current_font_id = l->id;
1762 current_gfxfont = l->font;
1764 swfoutput_gfxaddfont(&this->output, id, current_gfxfont);
1769 if(!filename) return 0;
1770 font = gfxfont_load(filename);
1773 l->filename = strdup(filename);
1776 current_font_id = l->id;
1777 current_gfxfont = l->font;
1783 swfoutput_gfxaddfont(&this->output, id, current_gfxfont);
1787 void SWFOutputDev::updateFont(GfxState *state)
1789 GfxFont*gfxFont = state->getFont();
1794 char * fontid = getFontID(gfxFont);
1797 /* first, look if we substituted this font before-
1798 this way, we don't initialize the T1 Fonts
1800 for(t=0;t<substitutepos;t++) {
1801 if(!strcmp(fontid, substitutesource[t])) {
1802 free(fontid);fontid=0;
1803 fontid = strdup(substitutetarget[t]);
1808 /* second, see if this is a font which was used before-
1809 if so, we are done */
1810 if(setGfxFont(fontid, 0)) {
1814 /* if(swfoutput_queryfont(&output, fontid))
1815 swfoutput_setfont(&output, fontid, 0);
1817 msg("<debug> updateFont(%s) [cached]", fontid);
1821 // look for Type 3 font
1822 if (gfxFont->getType() == fontType3) {
1824 type3Warning = gTrue;
1825 showFontError(gfxFont, 2);
1831 /* now either load the font, or find a substitution */
1834 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1839 (gfxFont->getType() == fontType1 ||
1840 gfxFont->getType() == fontType1C ||
1841 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
1842 gfxFont->getType() == fontTrueType ||
1843 gfxFont->getType() == fontCIDType2
1846 fileName = writeEmbeddedFontToFile(xref, gfxFont);
1847 if(!fileName) showFontError(gfxFont,0);
1850 char * fontname = getFontName(gfxFont);
1851 fileName = searchFont(fontname);
1852 if(!fileName) showFontError(gfxFont,0);
1855 char * fontname = getFontName(gfxFont);
1856 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
1857 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
1858 fileName = substituteFont(gfxFont, fontid);
1859 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
1860 msg("<notice> Font is now %s (%s)", fontid, fileName);
1864 msg("<error> Couldn't set font %s\n", fontid);
1869 msg("<verbose> updateFont(%s) -> %s", fontid, fileName);
1870 dumpFontInfo("<verbose>", gfxFont);
1872 //swfoutput_setfont(&output, fontid, fileName);
1874 if(!setGfxFont(fontid, 0)) {
1875 setGfxFont(fontid, fileName);
1879 unlinkfont(fileName);
1885 #define SQR(x) ((x)*(x))
1887 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1889 if((newwidth<2 || newheight<2) ||
1890 (width<=newwidth || height<=newheight))
1892 unsigned char*newdata;
1894 newdata= (unsigned char*)malloc(newwidth*newheight);
1896 double fx = (double)(width)/newwidth;
1897 double fy = (double)(height)/newheight;
1899 int blocksize = (int)(8192/(fx*fy));
1900 int r = 8192*256/palettesize;
1901 for(x=0;x<newwidth;x++) {
1902 double ex = px + fx;
1903 int fromx = (int)px;
1905 int xweight1 = (int)(((fromx+1)-px)*256);
1906 int xweight2 = (int)((ex-tox)*256);
1908 for(y=0;y<newheight;y++) {
1909 double ey = py + fy;
1910 int fromy = (int)py;
1912 int yweight1 = (int)(((fromy+1)-py)*256);
1913 int yweight2 = (int)((ey-toy)*256);
1916 for(xx=fromx;xx<=tox;xx++)
1917 for(yy=fromy;yy<=toy;yy++) {
1918 int b = 1-data[width*yy+xx];
1920 if(xx==fromx) weight = (weight*xweight1)/256;
1921 if(xx==tox) weight = (weight*xweight2)/256;
1922 if(yy==fromy) weight = (weight*yweight1)/256;
1923 if(yy==toy) weight = (weight*yweight2)/256;
1926 //if(a) a=(palettesize-1)*r/blocksize;
1927 newdata[y*newwidth+x] = (a*blocksize)/r;
1935 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
1936 int width, int height, GfxImageColorMap*colorMap, GBool invert,
1937 GBool inlineImg, int mask, int*maskColors)
1942 double x1,y1,x2,y2,x3,y3,x4,y4;
1943 ImageStream *imgStr;
1950 ncomps = colorMap->getNumPixelComps();
1951 bits = colorMap->getBits();
1953 imgStr = new ImageStream(str, width, ncomps,bits);
1956 if(!width || !height || (height<=1 && width<=1))
1958 msg("<verbose> Ignoring %d by %d image", width, height);
1959 unsigned char buf[8];
1961 for (y = 0; y < height; ++y)
1962 for (x = 0; x < width; ++x) {
1963 imgStr->getPixel(buf);
1969 state->transform(0, 1, &x1, &y1);
1970 state->transform(0, 0, &x2, &y2);
1971 state->transform(1, 0, &x3, &y3);
1972 state->transform(1, 1, &x4, &y4);
1974 if(!pbminfo && !(str->getKind()==strDCT)) {
1976 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
1980 msg("<verbose> drawing %d by %d masked picture\n", width, height);
1982 if(!jpeginfo && (str->getKind()==strDCT)) {
1983 msg("<notice> file contains jpeg pictures");
1989 unsigned char buf[8];
1991 unsigned char*pic = new unsigned char[width*height];
1994 state->getFillRGB(&rgb);
1996 memset(pal,255,sizeof(pal));
1997 pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
1998 pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
1999 pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
2000 pal[0].a = 255; pal[1].a = 0;
2003 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2004 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2005 for (y = 0; y < height; ++y)
2006 for (x = 0; x < width; ++x)
2008 imgStr->getPixel(buf);
2011 pic[width*y+x] = buf[0];
2014 /* the size of the drawn image is added to the identifier
2015 as the same image may require different bitmaps if displayed
2016 at different sizes (due to antialiasing): */
2019 unsigned char*pic2 = 0;
2022 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2031 height = realheight;
2035 /* make a black/white palette */
2040 float r = 255/(numpalette-1);
2042 for(t=0;t<numpalette;t++) {
2043 pal[t].r = (U8)(255*rgb.r);
2044 pal[t].g = (U8)(255*rgb.g);
2045 pal[t].b = (U8)(255*rgb.b);
2046 pal[t].a = (U8)(t*r);
2050 RGBA*pic2 = new RGBA[width*height];
2051 for (y = 0; y < height; ++y) {
2052 for (x = 0; x < width; ++x) {
2053 pic2[width*y+x] = pal[pic[y*width+x]];
2056 swfoutput_drawimagelossless(&output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2065 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2066 RGBA*pic=new RGBA[width*height];
2067 for (y = 0; y < height; ++y) {
2068 for (x = 0; x < width; ++x) {
2069 imgStr->getPixel(pixBuf);
2070 colorMap->getRGB(pixBuf, &rgb);
2071 pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
2072 pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
2073 pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
2074 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2077 if(str->getKind()==strDCT)
2078 swfoutput_drawimagejpeg(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2080 swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2085 RGBA*pic=new RGBA[width*height];
2088 for(t=0;t<256;t++) {
2090 colorMap->getRGB(pixBuf, &rgb);
2091 /*if(maskColors && *maskColors==t) {
2092 msg("<notice> Color %d is transparent", t);
2093 if (imgData->maskColors) {
2095 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2096 if (pix[i] < imgData->maskColors[2*i] ||
2097 pix[i] > imgData->maskColors[2*i+1]) {
2112 pal[t].r = (U8)(rgb.r * 255 + 0.5);
2113 pal[t].g = (U8)(rgb.g * 255 + 0.5);
2114 pal[t].b = (U8)(rgb.b * 255 + 0.5);
2115 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2118 for (y = 0; y < height; ++y) {
2119 for (x = 0; x < width; ++x) {
2120 imgStr->getPixel(pixBuf);
2121 pic[width*y+x] = pal[pixBuf[0]];
2124 swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2132 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2133 int width, int height, GBool invert,
2136 if(states[statepos].textRender & 4) //clipped
2138 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2139 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
2142 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2143 int width, int height, GfxImageColorMap *colorMap,
2144 int *maskColors, GBool inlineImg)
2146 if(states[statepos].textRender & 4) //clipped
2149 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
2150 colorMap?"colorMap":"no colorMap",
2151 maskColors?"maskColors":"no maskColors",
2154 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2155 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2156 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
2159 SWFOutputDev*output = 0;
2161 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2166 if (infoDict->lookup(key, &obj)->isString()) {
2167 s1 = obj.getString();
2168 if ((s1->getChar(0) & 0xff) == 0xfe &&
2169 (s1->getChar(1) & 0xff) == 0xff) {
2171 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2172 if (s1->getChar(i) == '\0') {
2173 s2->append(s1->getChar(i+1));
2176 s2 = new GString("<unicode>");
2180 printf(fmt, s2->getCString());
2183 printf(fmt, s1->getCString());
2189 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2193 if (infoDict->lookup(key, &obj)->isString()) {
2194 s = obj.getString()->getCString();
2195 if (s[0] == 'D' && s[1] == ':') {
2206 void pdfswf_setparameter(char*name, char*value)
2208 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2209 if(!strcmp(name, "caplinewidth")) {
2210 caplinewidth = atof(value);
2211 } else if(!strcmp(name, "zoom")) {
2214 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2215 swfoutput_setparameter("jpegsubpixels", buf);
2216 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2217 swfoutput_setparameter("ppmsubpixels", buf);
2218 } else if(!strcmp(name, "jpegdpi")) {
2220 jpeg_dpi = atoi(value);
2221 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2222 swfoutput_setparameter("jpegsubpixels", buf);
2223 } else if(!strcmp(name, "ppmdpi")) {
2225 ppm_dpi = atoi(value);
2226 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2227 swfoutput_setparameter("ppmsubpixels", buf);
2228 } else if(!strcmp(name, "forceType0Fonts")) {
2229 forceType0Fonts = atoi(value);
2230 } else if(!strcmp(name, "fontdir")) {
2231 pdfswf_addfontdir(value);
2232 } else if(!strcmp(name, "languagedir")) {
2233 pdfswf_addlanguagedir(value);
2234 } else if(!strcmp(name, "fontconfig")) {
2235 config_use_fontconfig = atoi(value);
2237 swfoutput_setparameter(name, value);
2240 void pdfswf_addfont(char*filename)
2243 memset(&f, 0, sizeof(fontfile_t));
2244 f.filename = filename;
2245 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2246 fonts[fontnum++] = f;
2248 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2252 static char* dirseparator()
2261 void pdfswf_addlanguagedir(char*dir)
2264 globalParams = new GlobalParams("");
2266 msg("<notice> Adding %s to language pack directories", dir);
2270 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2271 strcpy(config_file, dir);
2272 strcat(config_file, dirseparator());
2273 strcat(config_file, "add-to-xpdfrc");
2275 fi = fopen(config_file, "rb");
2277 msg("<error> Could not open %s", config_file);
2280 globalParams->parseFile(new GString(config_file), fi);
2284 void pdfswf_addfontdir(char*dirname)
2286 #ifdef HAVE_DIRENT_H
2287 msg("<notice> Adding %s to font directories", dirname);
2288 DIR*dir = opendir(dirname);
2290 msg("<warning> Couldn't open directory %s\n", dirname);
2295 ent = readdir (dir);
2299 char*name = ent->d_name;
2305 if(!strncasecmp(&name[l-4], ".pfa", 4))
2307 if(!strncasecmp(&name[l-4], ".pfb", 4))
2309 if(!strncasecmp(&name[l-4], ".ttf", 4))
2313 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2314 strcpy(fontname, dirname);
2315 strcat(fontname, dirseparator());
2316 strcat(fontname, name);
2317 msg("<verbose> Adding %s to fonts", fontname);
2318 pdfswf_addfont(fontname);
2323 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2328 typedef struct _pdf_doc_internal
2332 } pdf_doc_internal_t;
2333 typedef struct _pdf_page_internal
2335 } pdf_page_internal_t;
2336 typedef struct _swf_output_internal
2338 SWFOutputDev*outputDev;
2339 } swf_output_internal_t;
2341 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2343 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2344 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2345 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2346 memset(i, 0, sizeof(pdf_doc_internal_t));
2347 pdf_doc->internal = i;
2349 GString *fileName = new GString(filename);
2355 globalParams = new GlobalParams("");
2358 if (userPassword && userPassword[0]) {
2359 userPW = new GString(userPassword);
2363 i->doc = new PDFDoc(fileName, userPW);
2367 if (!i->doc->isOk()) {
2372 i->doc->getDocInfo(&info);
2373 if (info.isDict() &&
2374 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2375 printInfoString(info.getDict(), "Title", "Title: %s\n");
2376 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2377 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2378 printInfoString(info.getDict(), "Author", "Author: %s\n");
2379 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2380 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2381 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2382 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2383 printf("Pages: %d\n", i->doc->getNumPages());
2384 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2385 printf("Encrypted: ");
2386 if (i->doc->isEncrypted()) {
2387 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2388 i->doc->okToPrint() ? "yes" : "no",
2389 i->doc->okToCopy() ? "yes" : "no",
2390 i->doc->okToChange() ? "yes" : "no",
2391 i->doc->okToAddNotes() ? "yes" : "no");
2398 pdf_doc->num_pages = i->doc->getNumPages();
2400 if (i->doc->isEncrypted()) {
2401 if(!i->doc->okToCopy()) {
2402 printf("PDF disallows copying.\n");
2405 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2412 void pdfswf_preparepage(int page)
2416 pages = (int*)malloc(1024*sizeof(int));
2419 if(pagepos == pagebuflen)
2422 pages = (int*)realloc(pages, pagebuflen);
2425 pages[pagepos++] = page;
2432 delete globalParams;globalParams=0;
2433 Object::memCheck(stderr);
2438 void pdf_destroy(pdf_doc_t*pdf_doc)
2440 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2442 msg("<debug> pdfswf.cc: pdfswf_close()");
2443 delete i->doc; i->doc=0;
2445 free(pages); pages = 0; //FIXME
2447 free(pdf_doc->internal);pdf_doc->internal=0;
2448 free(pdf_doc);pdf_doc=0;
2451 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2453 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2455 if(page < 1 || page > pdf_doc->num_pages)
2458 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2459 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2460 memset(pi, 0, sizeof(pdf_page_internal_t));
2461 pdf_page->internal = pi;
2463 pdf_page->parent = pdf_doc;
2464 pdf_page->nr = page;
2468 void pdf_page_destroy(pdf_page_t*pdf_page)
2470 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2471 free(pdf_page->internal);pdf_page->internal = 0;
2472 free(pdf_page);pdf_page=0;
2475 swf_output_t* swf_output_init()
2477 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2478 memset(swf_output, 0, sizeof(swf_output_t));
2479 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2480 memset(i, 0, sizeof(swf_output_internal_t));
2481 swf_output->internal = i;
2483 i->outputDev = new SWFOutputDev();
2487 void swf_output_setparameter(swf_output_t*swf_output, char*name, char*value)
2490 pdfswf_setparameter(name, value);
2493 void swf_output_pagefeed(swf_output_t*swf)
2495 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2496 i->outputDev->pagefeed();
2497 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2500 int swf_output_save(swf_output_t*swf, char*filename)
2502 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2503 int ret = i->outputDev->save(filename);
2504 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2508 void* swf_output_get(swf_output_t*swf)
2510 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2511 void* ret = i->outputDev->getSWF();
2512 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2516 void swf_output_destroy(swf_output_t*output)
2518 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2519 delete i->outputDev; i->outputDev=0;
2520 free(output->internal);output->internal=0;
2524 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2526 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2527 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2530 swfoutput_setparameter("protect", "1");
2532 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2534 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2536 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2538 si->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2541 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2543 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2544 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2546 si->outputDev->setMove(x,y);
2547 if((x1|y1|x2|y2)==0) x2++;
2548 si->outputDev->setClip(x1,y1,x2,y2);
2550 pdf_page_render2(page, output);
2552 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2554 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2555 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2557 si->outputDev->setMove(0,0);
2558 si->outputDev->setClip(0,0,0,0);
2560 pdf_page_render2(page, output);
2564 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2566 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2567 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2568 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2569 memset(info, 0, sizeof(pdf_page_info_t));
2571 InfoOutputDev*output = new InfoOutputDev;
2574 pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2576 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2579 info->xMin = output->x1;
2580 info->yMin = output->y1;
2581 info->xMax = output->x2;
2582 info->yMax = output->y2;
2583 info->number_of_images = output->num_images;
2584 info->number_of_links = output->num_links;
2585 info->number_of_fonts = output->num_fonts;
2592 void pdf_page_info_destroy(pdf_page_info_t*info)