2 implements a pdf output device (OutputDev).
4 This file is part of swftools.
6 Swftools is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 Swftools is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with swftools; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
25 #include "../config.h"
29 #ifdef HAVE_SYS_STAT_H
32 #ifdef HAVE_FONTCONFIG
33 #include <fontconfig.h>
49 #include "OutputDev.h"
52 #include "CharCodeToUnicode.h"
53 #include "NameToUnicodeTable.h"
54 #include "GlobalParams.h"
59 #include "FoFiType1C.h"
60 #include "FoFiTrueType.h"
62 #include "SWFOutputDev.h"
64 //swftools header files
65 #include "swfoutput.h"
66 #include "../lib/log.h"
67 #include "../lib/gfxdevice.h"
68 #include "../lib/gfxtools.h"
69 #include "../lib/gfxfont.h"
73 typedef struct _fontfile
79 typedef struct _parameter
83 struct _parameter*next;
86 static parameter_t* device_config = 0;
87 static parameter_t* device_config_next = 0;
90 static fontfile_t fonts[2048];
91 static int fontnum = 0;
93 static int config_use_fontconfig = 1;
96 // TODO: move into pdf_doc_t
98 static int pagebuflen = 0;
99 static int pagepos = 0;
102 static double caplinewidth = 3.0;
103 static double zoom = 72; /* xpdf: 86 */
104 static int forceType0Fonts = 1;
106 static void printInfoString(Dict *infoDict, char *key, char *fmt);
107 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
113 {"Times-Roman", "n021003l"},
114 {"Times-Italic", "n021023l"},
115 {"Times-Bold", "n021004l"},
116 {"Times-BoldItalic", "n021024l"},
117 {"Helvetica", "n019003l"},
118 {"Helvetica-Oblique", "n019023l"},
119 {"Helvetica-Bold", "n019004l"},
120 {"Helvetica-BoldOblique", "n019024l"},
121 {"Courier", "n022003l"},
122 {"Courier-Oblique", "n022023l"},
123 {"Courier-Bold", "n022004l"},
124 {"Courier-BoldOblique", "n022024l"},
125 {"Symbol", "s050000l"},
126 {"ZapfDingbats", "d050000l"}};
128 class SWFOutputState {
134 this->textRender = 0;
138 typedef struct _fontlist
146 class SWFOutputDev: public OutputDev {
155 virtual ~SWFOutputDev() ;
157 void setMove(int x,int y);
158 void setClip(int x1,int y1,int x2,int y2);
160 int save(char*filename);
164 void getDimensions(int*x1,int*y1,int*x2,int*y2);
166 //----- get info about output device
168 // Does this device use upside-down coordinates?
169 // (Upside-down means (0,0) is the top left corner of the page.)
170 virtual GBool upsideDown();
172 // Does this device use drawChar() or drawString()?
173 virtual GBool useDrawChar();
175 // Can this device draw gradients?
176 virtual GBool useGradients();
178 virtual GBool interpretType3Chars() {return gTrue;}
180 //----- initialization and control
182 void setXRef(PDFDoc*doc, XRef *xref);
185 virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
188 virtual void drawLink(Link *link, Catalog *catalog) ;
190 //----- save/restore graphics state
191 virtual void saveState(GfxState *state) ;
192 virtual void restoreState(GfxState *state) ;
194 //----- update graphics state
196 virtual void updateFont(GfxState *state);
197 virtual void updateFillColor(GfxState *state);
198 virtual void updateStrokeColor(GfxState *state);
199 virtual void updateLineWidth(GfxState *state);
200 virtual void updateLineJoin(GfxState *state);
201 virtual void updateLineCap(GfxState *state);
203 virtual void updateAll(GfxState *state)
206 updateFillColor(state);
207 updateStrokeColor(state);
208 updateLineWidth(state);
209 updateLineJoin(state);
210 updateLineCap(state);
213 //----- path painting
214 virtual void stroke(GfxState *state) ;
215 virtual void fill(GfxState *state) ;
216 virtual void eoFill(GfxState *state) ;
218 //----- path clipping
219 virtual void clip(GfxState *state) ;
220 virtual void eoClip(GfxState *state) ;
223 virtual void beginString(GfxState *state, GString *s) ;
224 virtual void endString(GfxState *state) ;
225 virtual void endTextObject(GfxState *state);
226 virtual void drawChar(GfxState *state, double x, double y,
227 double dx, double dy,
228 double originX, double originY,
229 CharCode code, Unicode *u, int uLen);
231 //----- image drawing
232 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
233 int width, int height, GBool invert,
235 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
236 int width, int height, GfxImageColorMap *colorMap,
237 int *maskColors, GBool inlineImg);
239 virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
240 virtual void endType3Char(GfxState *state);
242 virtual void type3D0(GfxState *state, double wx, double wy);
243 virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
246 void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
247 int width, int height, GfxImageColorMap*colorMap, GBool invert,
248 GBool inlineImg, int mask, int *maskColors);
249 int SWFOutputDev::setGfxFont(char*id, char*filename);
250 void strokeGfxline(GfxState *state, gfxline_t*line);
251 void clipToGfxLine(GfxState *state, gfxline_t*line);
252 void fillGfxLine(GfxState *state, gfxline_t*line);
256 SWF*swf; //filled upon completion
258 SWFOutputState states[64];
266 char* searchFont(char*name);
267 char* substituteFont(GfxFont*gfxFont, char*oldname);
268 char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
270 int jpeginfo; // did we write "File contains jpegs" yet?
271 int pbminfo; // did we write "File contains jpegs" yet?
272 int linkinfo; // did we write "File contains links" yet?
273 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
274 int gradientinfo; // did we write "File contains Gradients yet?
276 int type3active; // are we between beginType3()/endType3()?
282 char* substitutetarget[256];
283 char* substitutesource[256];
286 int user_movex,user_movey;
287 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
289 gfxline_t* current_text_stroke;
290 gfxline_t* current_text_clip;
291 char* current_font_id;
292 gfxfont_t* current_gfxfont;
293 gfxmatrix_t current_font_matrix;
295 fontlist_t* fontlist;
298 static char*getFontID(GfxFont*font);
300 class InfoOutputDev: public OutputDev
314 virtual ~InfoOutputDev()
317 virtual GBool upsideDown() {return gTrue;}
318 virtual GBool useDrawChar() {return gTrue;}
319 virtual GBool useGradients() {return gTrue;}
320 virtual GBool interpretType3Chars() {return gTrue;}
321 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
324 state->transform(crop_x1,crop_y1,&x1,&y1);
325 state->transform(crop_x2,crop_y2,&x2,&y2);
326 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
327 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
333 virtual void drawLink(Link *link, Catalog *catalog)
337 virtual void updateFont(GfxState *state)
339 GfxFont*font = state->getFont();
342 /*char*id = getFontID(font);*/
346 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
347 int width, int height, GBool invert,
352 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
353 int width, int height, GfxImageColorMap *colorMap,
354 int *maskColors, GBool inlineImg)
360 SWFOutputDev::SWFOutputDev()
378 current_text_stroke = 0;
379 current_text_clip = 0;
382 output = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
383 memset(output, 0, sizeof(output));
386 void SWFOutputDev::setMove(int x,int y)
388 this->user_movex = x;
389 this->user_movey = y;
392 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
394 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
395 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
397 this->user_clipx1 = x1;
398 this->user_clipy1 = y1;
399 this->user_clipx2 = x2;
400 this->user_clipy2 = y2;
402 void SWFOutputDev::getDimensions(int*x1,int*y1,int*x2,int*y2)
404 return gfxdevice_swf_getdimensions(output, x1,y1,x2,y2);
407 static char*getFontID(GfxFont*font)
409 GString*gstr = font->getName();
410 char* fontname = gstr==0?0:gstr->getCString();
414 sprintf(buf, "UFONT%d", r->num);
417 return strdup(fontname);
420 static char*getFontName(GfxFont*font)
422 char*fontid = getFontID(font);
424 char* plus = strchr(fontid, '+');
425 if(plus && plus < &fontid[strlen(fontid)-1]) {
426 fontname = strdup(plus+1);
428 fontname = strdup(fontid);
434 static char mybuf[1024];
435 static char* gfxstate2str(GfxState *state)
439 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
446 if(state->getX1()!=0.0)
447 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
448 if(state->getY1()!=0.0)
449 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
450 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
451 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
452 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
453 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
454 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
455 state->getFillColor()->c[0], state->getFillColor()->c[1]);
456 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
457 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
458 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
459 state->getFillColor()->c[0], state->getFillColor()->c[1],
460 state->getFillColor()->c[2], state->getFillColor()->c[3],
461 state->getFillColor()->c[4], state->getFillColor()->c[5],
462 state->getFillColor()->c[6], state->getFillColor()->c[7]);
463 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
464 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
465 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
466 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
467 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
468 state->getFillRGB(&rgb);
469 if(rgb.r || rgb.g || rgb.b)
470 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
471 state->getStrokeRGB(&rgb);
472 if(rgb.r || rgb.g || rgb.b)
473 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
474 if(state->getFillColorSpace()->getNComps()>1)
475 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
476 if(state->getStrokeColorSpace()->getNComps()>1)
477 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
478 if(state->getFillPattern())
479 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
480 if(state->getStrokePattern())
481 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
483 if(state->getFillOpacity()!=1.0)
484 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
485 if(state->getStrokeOpacity()!=1.0)
486 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
488 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
493 state->getLineDash(&dash, &length, &start);
497 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
498 for(t=0;t<length;t++) {
499 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
501 bufpos+=sprintf(bufpos,"]");
504 if(state->getFlatness()!=1)
505 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
506 if(state->getLineJoin()!=0)
507 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
508 if(state->getLineJoin()!=0)
509 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
510 if(state->getLineJoin()!=0)
511 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
513 if(state->getFont() && getFontID(state->getFont()))
514 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
515 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
516 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
517 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
518 if(state->getCharSpace())
519 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
520 if(state->getWordSpace())
521 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
522 if(state->getHorizScaling()!=1.0)
523 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
524 if(state->getLeading())
525 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
527 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
528 if(state->getRender())
529 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
530 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
531 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
532 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
533 if(state->getLineX())
534 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
535 if(state->getLineY())
536 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
537 bufpos+=sprintf(bufpos," ");
541 static void dumpFontInfo(char*loglevel, GfxFont*font);
542 static int lastdumps[1024];
543 static int lastdumppos = 0;
548 static void showFontError(GfxFont*font, int nr)
552 for(t=0;t<lastdumppos;t++)
553 if(lastdumps[t] == r->num)
557 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
558 lastdumps[lastdumppos++] = r->num;
560 msg("<warning> The following font caused problems:");
562 msg("<warning> The following font caused problems (substituting):");
564 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
565 dumpFontInfo("<warning>", font);
568 static void dumpFontInfo(char*loglevel, GfxFont*font)
570 char* id = getFontID(font);
571 char* name = getFontName(font);
572 Ref* r=font->getID();
573 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
575 GString*gstr = font->getTag();
577 msg("%s| Tag: %s\n", loglevel, id);
579 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
581 GfxFontType type=font->getType();
583 case fontUnknownType:
584 msg("%s| Type: unknown\n",loglevel);
587 msg("%s| Type: 1\n",loglevel);
590 msg("%s| Type: 1C\n",loglevel);
593 msg("%s| Type: 3\n",loglevel);
596 msg("%s| Type: TrueType\n",loglevel);
599 msg("%s| Type: CIDType0\n",loglevel);
602 msg("%s| Type: CIDType0C\n",loglevel);
605 msg("%s| Type: CIDType2\n",loglevel);
610 GBool embedded = font->getEmbeddedFontID(&embRef);
612 if(font->getEmbeddedFontName()) {
613 embeddedName = font->getEmbeddedFontName()->getCString();
616 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
618 gstr = font->getExtFontFile();
620 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
622 // Get font descriptor flags.
623 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
624 if(font->isSerif()) msg("%s| is serif\n", loglevel);
625 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
626 if(font->isItalic()) msg("%s| is italic\n", loglevel);
627 if(font->isBold()) msg("%s| is bold\n", loglevel);
633 //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");}
634 //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");}
637 void dump_outline(gfxline_t*line)
640 if(line->type == gfx_moveTo) {
641 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
642 } else if(line->type == gfx_lineTo) {
643 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
644 } else if(line->type == gfx_splineTo) {
645 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
651 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed)
653 int num = path->getNumSubpaths();
656 double lastx=0,lasty=0,posx=0,posy=0;
659 msg("<warning> empty path");
663 gfxdrawer_target_gfxline(&draw);
665 for(t = 0; t < num; t++) {
666 GfxSubpath *subpath = path->getSubpath(t);
667 int subnum = subpath->getNumPoints();
668 double bx=0,by=0,cx=0,cy=0;
670 for(s=0;s<subnum;s++) {
672 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
674 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
675 draw.lineTo(&draw, lastx, lasty);
677 draw.moveTo(&draw, x,y);
682 } else if(subpath->getCurve(s) && cpos==0) {
686 } else if(subpath->getCurve(s) && cpos==1) {
694 draw.lineTo(&draw, x,y);
696 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y);
703 /* fix non-closed lines */
704 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
705 draw.lineTo(&draw, lastx, lasty);
707 gfxline_t*result = (gfxline_t*)draw.result(&draw);
711 /*----------------------------------------------------------------------------
712 * Primitive Graphic routines
713 *----------------------------------------------------------------------------*/
715 void SWFOutputDev::stroke(GfxState *state)
717 GfxPath * path = state->getPath();
718 gfxline_t*line= gfxPath_to_gfxline(state, path, 0);
719 strokeGfxline(state, line);
723 void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
725 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
726 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
727 double miterLimit = state->getMiterLimit();
728 double width = state->getTransformedLineWidth();
731 double opaq = state->getStrokeOpacity();
733 state->getFillRGB(&rgb);
735 state->getStrokeRGB(&rgb);
737 col.r = (unsigned char)(rgb.r*255);
738 col.g = (unsigned char)(rgb.g*255);
739 col.b = (unsigned char)(rgb.b*255);
740 col.a = (unsigned char)(opaq*255);
742 gfx_capType capType = gfx_capRound;
743 if(lineCap == 0) capType = gfx_capButt;
744 else if(lineCap == 1) capType = gfx_capRound;
745 else if(lineCap == 2) capType = gfx_capSquare;
747 gfx_joinType joinType = gfx_joinRound;
748 if(lineJoin == 0) joinType = gfx_joinMiter;
749 else if(lineJoin == 1) joinType = gfx_joinRound;
750 else if(lineJoin == 2) joinType = gfx_joinBevel;
753 double dashphase = 0;
755 state->getLineDash(&ldash, &dashnum, &dashphase);
759 if(dashnum && ldash) {
760 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
764 msg("<trace> %d dashes", dashnum);
765 msg("<trace> | phase: %f", dashphase);
766 for(t=0;t<dashnum;t++) {
768 msg("<trace> | d%-3d: %f", t, ldash[t]);
771 if(getLogLevel() >= LOGLEVEL_TRACE) {
775 line2 = gfxtool_dash_line(line, dash, dashphase);
777 msg("<trace> After dashing:");
780 if(getLogLevel() >= LOGLEVEL_TRACE) {
782 state->getStrokeGray(&gray);
783 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n",
785 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
786 lineCap==0?"butt": (lineJoin==1?"round":"square"),
788 col.r,col.g,col.b,col.a,
794 //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
795 output->stroke(output, line, width, &col, capType, joinType, miterLimit);
801 gfxcolor_t getFillColor(GfxState * state)
804 double opaq = state->getFillOpacity();
805 state->getFillRGB(&rgb);
807 col.r = (unsigned char)(rgb.r*255);
808 col.g = (unsigned char)(rgb.g*255);
809 col.b = (unsigned char)(rgb.b*255);
810 col.a = (unsigned char)(opaq*255);
814 void SWFOutputDev::fillGfxLine(GfxState *state, gfxline_t*line)
816 gfxcolor_t col = getFillColor(state);
818 if(getLogLevel() >= LOGLEVEL_TRACE) {
819 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
822 output->fill(output, line, &col);
824 void SWFOutputDev::fill(GfxState *state)
826 GfxPath * path = state->getPath();
827 gfxline_t*line= gfxPath_to_gfxline(state, path, 1);
828 fillGfxLine(state, line);
831 void SWFOutputDev::eoFill(GfxState *state)
833 GfxPath * path = state->getPath();
834 gfxcolor_t col = getFillColor(state);
836 gfxline_t*line= gfxPath_to_gfxline(state, path, 1);
838 if(getLogLevel() >= LOGLEVEL_TRACE) {
839 msg("<trace> eofill\n");
843 output->fill(output, line, &col);
847 void SWFOutputDev::clip(GfxState *state)
849 GfxPath * path = state->getPath();
850 gfxline_t*line = gfxPath_to_gfxline(state, path, 1);
851 clipToGfxLine(state, line);
855 void SWFOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line)
857 if(getLogLevel() >= LOGLEVEL_TRACE) {
858 msg("<trace> clip\n");
862 output->startclip(output, line);
863 states[statepos].clipping++;
865 void SWFOutputDev::eoClip(GfxState *state)
867 GfxPath * path = state->getPath();
868 gfxline_t*line = gfxPath_to_gfxline(state, path, 1);
870 if(getLogLevel() >= LOGLEVEL_TRACE) {
871 msg("<trace> eoclip\n");
875 output->startclip(output, line);
876 states[statepos].clipping++;
880 /* pass through functions for swf_output */
881 int SWFOutputDev::save(char*filename)
883 return gfxdevice_swf_save(output, filename);
885 void SWFOutputDev::pagefeed()
887 swfoutput_pagefeed(output);
889 void* SWFOutputDev::getSWF()
891 return (void*)gfxdevice_swf_get(output);
894 void SWFOutputDev::finish()
897 this->swf = (SWF*)output->finish(output);
898 free(output);output=0;
902 SWFOutputDev::~SWFOutputDev()
908 swf_FreeTags(this->swf);
913 fontlist_t*l = this->fontlist;
915 fontlist_t*next = l->next;
917 gfxfont_free(l->font);
924 GBool SWFOutputDev::upsideDown()
926 msg("<debug> upsidedown? yes");
929 GBool SWFOutputDev::useDrawChar()
933 GBool SWFOutputDev::useGradients()
937 msg("<notice> File contains gradients");
943 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
944 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
946 #define RENDER_FILL 0
947 #define RENDER_STROKE 1
948 #define RENDER_FILLSTROKE 2
949 #define RENDER_INVISIBLE 3
950 #define RENDER_CLIP 4
952 static char tmp_printstr[4096];
953 char* makeStringPrintable(char*str)
955 int len = strlen(str);
970 tmp_printstr[len++] = '.';
971 tmp_printstr[len++] = '.';
972 tmp_printstr[len++] = '.';
974 tmp_printstr[len] = 0;
979 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
983 for(t=0;t<font->num_glyphs;t++) {
984 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
985 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
989 /* if we didn't find the character, maybe
990 we can find the capitalized version */
991 for(t=0;t<font->num_glyphs;t++) {
992 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
993 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
999 /* try to use the unicode id */
1000 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
1001 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
1002 return font->unicode2glyph[u];
1005 if(charnr>=0 && charnr<font->num_glyphs) {
1006 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1014 void SWFOutputDev::beginString(GfxState *state, GString *s)
1016 int render = state->getRender();
1017 if(current_text_stroke) {
1018 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
1021 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
1022 double m11,m21,m12,m22;
1023 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
1024 state->getFontTransMat(&m11, &m12, &m21, &m22);
1025 m11 *= state->getHorizScaling();
1026 m21 *= state->getHorizScaling();
1028 this->current_font_matrix.m00 = m11 / 1024.0;
1029 this->current_font_matrix.m01 = m12 / 1024.0;
1030 this->current_font_matrix.m10 = -m21 / 1024.0;
1031 this->current_font_matrix.m11 = -m22 / 1024.0;
1032 this->current_font_matrix.tx = 0;
1033 this->current_font_matrix.ty = 0;
1035 gfxmatrix_t m = this->current_font_matrix;
1037 /*if(render != 3 && render != 0)
1038 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
1039 states[statepos].textRender = render;
1042 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
1043 double dx, double dy,
1044 double originX, double originY,
1045 CharCode c, Unicode *_u, int uLen)
1047 int render = state->getRender();
1048 // check for invisible text -- this is used by Acrobat Capture
1052 if(states[statepos].textRender != render)
1053 msg("<error> Internal error: drawChar.render!=beginString.render");
1055 gfxcolor_t col = getFillColor(state);
1057 Gushort *CIDToGIDMap = 0;
1058 GfxFont*font = state->getFont();
1060 if(font->getType() == fontType3) {
1061 /* type 3 chars are passed as graphics */
1062 msg("<debug> type3 char at %f/%f", x, y);
1073 /* find out char name from unicode index
1074 TODO: should be precomputed
1076 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
1077 if(nameToUnicodeTab[t].u == u) {
1078 name = nameToUnicodeTab[t].name;
1085 if(font->isCIDFont()) {
1086 GfxCIDFont*cfont = (GfxCIDFont*)font;
1088 if(font->getType() == fontCIDType2)
1089 CIDToGIDMap = cfont->getCIDToGID();
1092 font8 = (Gfx8BitFont*)font;
1093 char**enc=font8->getEncoding();
1098 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);
1101 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);
1104 int charid = getGfxCharID(current_gfxfont, c, name, u);
1106 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1107 FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
1111 gfxmatrix_t m = this->current_font_matrix;
1112 state->transform(x, y, &m.tx, &m.ty);
1114 if(render == RENDER_FILL) {
1115 output->drawchar(output, current_font_id, charid, &col, &m);
1117 msg("<debug> Drawing glyph %d as shape", charid);
1118 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
1119 gfxline_t*tglyph = gfxline_clone(glyph);
1120 gfxline_transform(tglyph, &m);
1121 if((render&3) != RENDER_INVISIBLE) {
1122 gfxline_t*add = gfxline_clone(tglyph);
1123 current_text_stroke = gfxline_append(current_text_stroke, add);
1125 if(render&RENDER_CLIP) {
1126 gfxline_t*add = gfxline_clone(tglyph);
1127 current_text_clip = gfxline_append(current_text_clip, add);
1129 gfxline_free(tglyph);
1133 void SWFOutputDev::endString(GfxState *state)
1135 int render = state->getRender();
1136 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1137 if(states[statepos].textRender != render)
1138 msg("<error> Internal error: drawChar.render!=beginString.render");
1140 if(current_text_stroke) {
1141 /* fillstroke and stroke text rendering objects we can process right
1142 now (as there may be texts of other rendering modes in this
1143 text object)- clipping objects have to wait until endTextObject,
1145 if((render&3) == RENDER_FILL) {
1146 fillGfxLine(state, current_text_stroke);
1147 gfxline_free(current_text_stroke);
1148 current_text_stroke = 0;
1149 } else if((render&3) == RENDER_FILLSTROKE) {
1150 fillGfxLine(state, current_text_stroke);
1151 strokeGfxline(state, current_text_stroke);
1152 gfxline_free(current_text_stroke);
1153 current_text_stroke = 0;
1154 } else if((render&3) == RENDER_STROKE) {
1155 strokeGfxline(state, current_text_stroke);
1156 gfxline_free(current_text_stroke);
1157 current_text_stroke = 0;
1162 void SWFOutputDev::endTextObject(GfxState *state)
1164 int render = state->getRender();
1165 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1166 if(states[statepos].textRender != render)
1167 msg("<error> Internal error: drawChar.render!=beginString.render");
1169 if(current_text_clip) {
1170 clipToGfxLine(state, current_text_clip);
1171 gfxline_free(current_text_clip);
1172 current_text_clip = 0;
1176 /* the logic seems to be as following:
1177 first, beginType3Char is called, with the charcode and the coordinates.
1178 if this function returns true, it already knew about the char and has now drawn it.
1179 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1180 the all draw operations until endType3Char are part of the char (which in this moment is
1181 at the position first passed to beginType3Char). the char ends with endType3Char.
1183 The drawing operations between beginType3Char and endType3Char are somewhat different to
1184 the normal ones. For example, the fillcolor equals the stroke color.
1187 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1189 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1191 /* the character itself is going to be passed using the draw functions */
1192 return gFalse; /* gTrue= is_in_cache? */
1195 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1196 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1198 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1199 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1203 void SWFOutputDev::endType3Char(GfxState *state)
1206 msg("<debug> endType3Char");
1209 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1211 this->currentpage = pageNum;
1213 int rot = doc->getPageRotate(1);
1215 msg("<verbose> startPage %d (%f,%f,%f,%f)\n", pageNum, crop_x1, crop_y1, crop_x2, crop_y2);
1217 msg("<verbose> page is rotated %d degrees\n", rot);
1219 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1220 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1221 Use CropBox, not MediaBox, as page size
1228 state->transform(crop_x1,crop_y1,&x1,&y1);
1229 state->transform(crop_x2,crop_y2,&x2,&y2);
1231 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1232 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1234 /* apply user clip box */
1235 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1236 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1237 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1238 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1239 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1242 if(!outputstarted) {
1243 msg("<verbose> Bounding box is (%f,%f)-(%f,%f)", x1,y1,x2,y2);
1245 gfxdevice_swf_init(output);
1247 /* configure device */
1248 parameter_t*p = device_config;
1250 output->setparameter(output, p->name, p->value);
1257 swfoutput_newpage(output, pageNum, user_movex, user_movey, (int)x1, (int)y1, (int)x2, (int)y2);
1260 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1262 msg("<debug> drawlink\n");
1263 double x1, y1, x2, y2, w;
1265 gfxline_t points[5];
1269 link->getBorder(&x1, &y1, &x2, &y2, &w);
1271 link->getRect(&x1, &y1, &x2, &y2);
1276 cvtUserToDev(x1, y1, &x, &y);
1277 points[0].type = gfx_moveTo;
1278 points[0].x = points[4].x = (int)x;
1279 points[0].y = points[4].y = (int)y;
1280 points[0].next = &points[1];
1281 cvtUserToDev(x2, y1, &x, &y);
1282 points[1].type = gfx_lineTo;
1283 points[1].x = (int)x;
1284 points[1].y = (int)y;
1285 points[1].next = &points[2];
1286 cvtUserToDev(x2, y2, &x, &y);
1287 points[2].type = gfx_lineTo;
1288 points[2].x = (int)x;
1289 points[2].y = (int)y;
1290 points[2].next = &points[3];
1291 cvtUserToDev(x1, y2, &x, &y);
1292 points[3].type = gfx_lineTo;
1293 points[3].x = (int)x;
1294 points[3].y = (int)y;
1295 points[3].next = &points[4];
1296 cvtUserToDev(x1, y1, &x, &y);
1297 points[4].type = gfx_lineTo;
1298 points[4].x = (int)x;
1299 points[4].y = (int)y;
1302 LinkAction*action=link->getAction();
1309 switch(action->getKind())
1313 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1314 LinkDest *dest=NULL;
1315 if (ha->getDest()==NULL)
1316 dest=catalog->findDest(ha->getNamedDest());
1317 else dest=ha->getDest();
1319 if (dest->isPageRef()){
1320 Ref pageref=dest->getPageRef();
1321 page=catalog->findPage(pageref.num,pageref.gen);
1323 else page=dest->getPageNum();
1324 sprintf(buf, "%d", page);
1331 LinkGoToR*l = (LinkGoToR*)action;
1332 GString*g = l->getNamedDest();
1334 s = strdup(g->getCString());
1339 LinkNamed*l = (LinkNamed*)action;
1340 GString*name = l->getName();
1342 s = strdup(name->lowerCase()->getCString());
1343 named = name->getCString();
1346 if(strstr(s, "next") || strstr(s, "forward"))
1348 page = currentpage + 1;
1350 else if(strstr(s, "prev") || strstr(s, "back"))
1352 page = currentpage - 1;
1354 else if(strstr(s, "last") || strstr(s, "end"))
1356 page = pagepos>0?pages[pagepos-1]:0;
1358 else if(strstr(s, "first") || strstr(s, "top"))
1366 case actionLaunch: {
1368 LinkLaunch*l = (LinkLaunch*)action;
1369 GString * str = new GString(l->getFileName());
1370 str->append(l->getParams());
1371 s = strdup(str->getCString());
1377 LinkURI*l = (LinkURI*)action;
1378 GString*g = l->getURI();
1380 url = g->getCString();
1385 case actionUnknown: {
1387 LinkUnknown*l = (LinkUnknown*)action;
1392 msg("<error> Unknown link type!\n");
1396 if(!s) s = strdup("-?-");
1398 if(!linkinfo && (page || url))
1400 msg("<notice> File contains links");
1407 for(t=0;t<pagepos;t++)
1412 sprintf(buf, "page%d", t);
1413 output->drawlink(output, points, buf);
1418 output->drawlink(output, points, url);
1421 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1425 void SWFOutputDev::saveState(GfxState *state) {
1426 msg("<trace> saveState\n");
1429 msg("<error> Too many nested states in pdf.");
1433 states[statepos].clipping = 0; //? shouldn't this be the current value?
1434 states[statepos].textRender = states[statepos-1].textRender;
1437 void SWFOutputDev::restoreState(GfxState *state) {
1438 msg("<trace> restoreState\n");
1440 while(states[statepos].clipping) {
1441 output->endclip(output);
1442 states[statepos].clipping--;
1447 char* SWFOutputDev::searchFont(char*name)
1451 int is_standard_font = 0;
1453 msg("<verbose> SearchFont(%s)", name);
1455 /* see if it is a pdf standard font */
1456 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1458 if(!strcmp(name, pdf2t1map[i].pdffont))
1460 name = pdf2t1map[i].filename;
1461 is_standard_font = 1;
1465 /* look in all font files */
1466 for(i=0;i<fontnum;i++)
1468 if(strstr(fonts[i].filename, name))
1470 if(!fonts[i].used) {
1473 if(!is_standard_font)
1474 msg("<notice> Using %s for %s", fonts[i].filename, name);
1476 return strdup(fonts[i].filename);
1482 void SWFOutputDev::updateLineWidth(GfxState *state)
1484 double width = state->getTransformedLineWidth();
1485 //swfoutput_setlinewidth(&output, width);
1488 void SWFOutputDev::updateLineCap(GfxState *state)
1490 int c = state->getLineCap();
1493 void SWFOutputDev::updateLineJoin(GfxState *state)
1495 int j = state->getLineJoin();
1498 void SWFOutputDev::updateFillColor(GfxState *state)
1501 double opaq = state->getFillOpacity();
1502 state->getFillRGB(&rgb);
1504 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1507 void SWFOutputDev::updateStrokeColor(GfxState *state)
1510 double opaq = state->getStrokeOpacity();
1511 state->getStrokeRGB(&rgb);
1512 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1515 void FoFiWrite(void *stream, char *data, int len)
1517 fwrite(data, len, 1, (FILE*)stream);
1520 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1522 char*tmpFileName = NULL;
1528 Object refObj, strObj;
1530 tmpFileName = mktmpname(namebuf);
1533 ret = font->getEmbeddedFontID(&embRef);
1535 msg("<verbose> Didn't get embedded font id");
1536 /* not embedded- the caller should now search the font
1537 directories for this font */
1541 f = fopen(tmpFileName, "wb");
1543 msg("<error> Couldn't create temporary Type 1 font file");
1547 /*if(font->isCIDFont()) {
1548 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1549 GString c = cidFont->getCollection();
1550 msg("<notice> Collection: %s", c.getCString());
1553 //if (font->getType() == fontType1C) {
1554 if (0) { //font->getType() == fontType1C) {
1555 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1557 msg("<error> Couldn't read embedded font file");
1561 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1563 cvt->convertToType1(f);
1565 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1567 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1569 //cvt->convertToCIDType0("test", f);
1570 //cvt->convertToType0("test", f);
1573 } else if(font->getType() == fontTrueType) {
1574 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1575 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1577 msg("<error> Couldn't read embedded font file");
1581 TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1584 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1585 cvt->writeTTF(FoFiWrite, f);
1590 font->getEmbeddedFontID(&embRef);
1591 refObj.initRef(embRef.num, embRef.gen);
1592 refObj.fetch(ref, &strObj);
1594 strObj.streamReset();
1599 f4[t] = strObj.streamGetChar();
1600 f4c[t] = (char)f4[t];
1605 if(!strncmp(f4c, "true", 4)) {
1606 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1607 Change this on the fly */
1608 f4[0] = f4[2] = f4[3] = 0;
1616 while ((c = strObj.streamGetChar()) != EOF) {
1620 strObj.streamClose();
1625 return strdup(tmpFileName);
1628 char* searchForSuitableFont(GfxFont*gfxFont)
1630 char*name = getFontName(gfxFont);
1634 if(!config_use_fontconfig)
1637 #ifdef HAVE_FONTCONFIG
1638 FcPattern *pattern, *match;
1642 static int fcinitcalled = false;
1644 msg("<debug> searchForSuitableFont(%s)", name);
1646 // call init ony once
1647 if (!fcinitcalled) {
1648 msg("<debug> Initializing FontConfig...");
1649 fcinitcalled = true;
1651 msg("<debug> FontConfig Initialization failed. Disabling.");
1652 config_use_fontconfig = 0;
1655 msg("<debug> ...initialized FontConfig");
1658 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1659 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1660 if (gfxFont->isItalic()) // check for italic
1661 msg("<debug> FontConfig: Adding Italic Slant");
1662 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1663 if (gfxFont->isBold()) // check for bold
1664 msg("<debug> FontConfig: Adding Bold Weight");
1665 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1667 msg("<debug> FontConfig: Try to match...");
1668 // configure and match using the original font name
1669 FcConfigSubstitute(0, pattern, FcMatchPattern);
1670 FcDefaultSubstitute(pattern);
1671 match = FcFontMatch(0, pattern, &result);
1673 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1674 msg("<debug> FontConfig: family=%s", (char*)v);
1675 // if we get an exact match
1676 if (strcmp((char *)v, name) == 0) {
1677 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1678 filename = strdup((char*)v); // mem leak
1679 char *nfn = strrchr(filename, '/');
1680 if(nfn) fontname = strdup(nfn+1);
1681 else fontname = filename;
1683 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1685 // initialize patterns
1686 FcPatternDestroy(pattern);
1687 FcPatternDestroy(match);
1689 // now match against serif etc.
1690 if (gfxFont->isSerif()) {
1691 msg("<debug> FontConfig: Create Serif Family Pattern");
1692 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1693 } else if (gfxFont->isFixedWidth()) {
1694 msg("<debug> FontConfig: Create Monospace Family Pattern");
1695 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1697 msg("<debug> FontConfig: Create Sans Family Pattern");
1698 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1702 if (gfxFont->isItalic()) {
1703 msg("<debug> FontConfig: Adding Italic Slant");
1704 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1707 if (gfxFont->isBold()) {
1708 msg("<debug> FontConfig: Adding Bold Weight");
1709 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1712 msg("<debug> FontConfig: Try to match... (2)");
1713 // configure and match using serif etc
1714 FcConfigSubstitute (0, pattern, FcMatchPattern);
1715 FcDefaultSubstitute (pattern);
1716 match = FcFontMatch (0, pattern, &result);
1718 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1719 filename = strdup((char*)v); // mem leak
1720 char *nfn = strrchr(filename, '/');
1721 if(nfn) fontname = strdup(nfn+1);
1722 else fontname = filename;
1724 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1728 //printf("FONTCONFIG: pattern");
1729 //FcPatternPrint(pattern);
1730 //printf("FONTCONFIG: match");
1731 //FcPatternPrint(match);
1733 FcPatternDestroy(pattern);
1734 FcPatternDestroy(match);
1736 pdfswf_addfont(filename);
1743 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1745 char*fontname = 0, *filename = 0;
1746 msg("<notice> subsituteFont(%s)", oldname);
1748 if(!(fontname = searchForSuitableFont(gfxFont))) {
1749 fontname = "Times-Roman";
1751 filename = searchFont(fontname);
1753 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1757 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1758 msg("<fatal> Too many fonts in file.");
1762 substitutesource[substitutepos] = strdup(oldname); //mem leak
1763 substitutetarget[substitutepos] = fontname;
1764 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1767 return strdup(filename); //mem leak
1770 void unlinkfont(char* filename)
1777 if(!strncmp(&filename[l-4],".afm",4)) {
1778 memcpy(&filename[l-4],".pfb",4);
1780 memcpy(&filename[l-4],".pfa",4);
1782 memcpy(&filename[l-4],".afm",4);
1785 if(!strncmp(&filename[l-4],".pfa",4)) {
1786 memcpy(&filename[l-4],".afm",4);
1788 memcpy(&filename[l-4],".pfa",4);
1791 if(!strncmp(&filename[l-4],".pfb",4)) {
1792 memcpy(&filename[l-4],".afm",4);
1794 memcpy(&filename[l-4],".pfb",4);
1799 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1805 int SWFOutputDev::setGfxFont(char*id, char*filename)
1808 fontlist_t*last=0,*l = this->fontlist;
1810 /* TODO: should this be part of the state? */
1813 if(!strcmp(l->id, id)) {
1814 current_font_id = l->id;
1815 current_gfxfont = l->font;
1817 output->addfont(output, id, current_gfxfont);
1822 if(!filename) return 0;
1823 font = gfxfont_load(filename);
1826 l->filename = strdup(filename);
1829 current_font_id = l->id;
1830 current_gfxfont = l->font;
1836 output->addfont(output, id, current_gfxfont);
1840 void SWFOutputDev::updateFont(GfxState *state)
1842 GfxFont*gfxFont = state->getFont();
1847 char * fontid = getFontID(gfxFont);
1850 /* first, look if we substituted this font before-
1851 this way, we don't initialize the T1 Fonts
1853 for(t=0;t<substitutepos;t++) {
1854 if(!strcmp(fontid, substitutesource[t])) {
1855 free(fontid);fontid=0;
1856 fontid = strdup(substitutetarget[t]);
1861 /* second, see if this is a font which was used before-
1862 if so, we are done */
1863 if(setGfxFont(fontid, 0)) {
1867 /* if(swfoutput_queryfont(&output, fontid))
1868 swfoutput_setfont(&output, fontid, 0);
1870 msg("<debug> updateFont(%s) [cached]", fontid);
1874 // look for Type 3 font
1875 if (gfxFont->getType() == fontType3) {
1877 type3Warning = gTrue;
1878 showFontError(gfxFont, 2);
1884 /* now either load the font, or find a substitution */
1887 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1892 (gfxFont->getType() == fontType1 ||
1893 gfxFont->getType() == fontType1C ||
1894 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
1895 gfxFont->getType() == fontTrueType ||
1896 gfxFont->getType() == fontCIDType2
1899 fileName = writeEmbeddedFontToFile(xref, gfxFont);
1900 if(!fileName) showFontError(gfxFont,0);
1903 char * fontname = getFontName(gfxFont);
1904 fileName = searchFont(fontname);
1905 if(!fileName) showFontError(gfxFont,0);
1908 char * fontname = getFontName(gfxFont);
1909 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
1910 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
1911 fileName = substituteFont(gfxFont, fontid);
1912 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
1913 msg("<notice> Font is now %s (%s)", fontid, fileName);
1917 msg("<error> Couldn't set font %s\n", fontid);
1922 msg("<verbose> updateFont(%s) -> %s", fontid, fileName);
1923 dumpFontInfo("<verbose>", gfxFont);
1925 //swfoutput_setfont(&output, fontid, fileName);
1927 if(!setGfxFont(fontid, 0)) {
1928 setGfxFont(fontid, fileName);
1932 unlinkfont(fileName);
1938 #define SQR(x) ((x)*(x))
1940 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1942 if((newwidth<2 || newheight<2) ||
1943 (width<=newwidth || height<=newheight))
1945 unsigned char*newdata;
1947 newdata= (unsigned char*)malloc(newwidth*newheight);
1949 double fx = (double)(width)/newwidth;
1950 double fy = (double)(height)/newheight;
1952 int blocksize = (int)(8192/(fx*fy));
1953 int r = 8192*256/palettesize;
1954 for(x=0;x<newwidth;x++) {
1955 double ex = px + fx;
1956 int fromx = (int)px;
1958 int xweight1 = (int)(((fromx+1)-px)*256);
1959 int xweight2 = (int)((ex-tox)*256);
1961 for(y=0;y<newheight;y++) {
1962 double ey = py + fy;
1963 int fromy = (int)py;
1965 int yweight1 = (int)(((fromy+1)-py)*256);
1966 int yweight2 = (int)((ey-toy)*256);
1969 for(xx=fromx;xx<=tox;xx++)
1970 for(yy=fromy;yy<=toy;yy++) {
1971 int b = 1-data[width*yy+xx];
1973 if(xx==fromx) weight = (weight*xweight1)/256;
1974 if(xx==tox) weight = (weight*xweight2)/256;
1975 if(yy==fromy) weight = (weight*yweight1)/256;
1976 if(yy==toy) weight = (weight*yweight2)/256;
1979 //if(a) a=(palettesize-1)*r/blocksize;
1980 newdata[y*newwidth+x] = (a*blocksize)/r;
1988 #define IMAGE_TYPE_JPEG 0
1989 #define IMAGE_TYPE_LOSSLESS 1
1991 static void drawimage(gfxdevice_t*dev, RGBA* data, int sizex,int sizey,
1992 double x1,double y1,
1993 double x2,double y2,
1994 double x3,double y3,
1995 double x4,double y4, int type)
1999 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2000 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2002 gfxline_t p1,p2,p3,p4,p5;
2003 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2004 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2005 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2006 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2007 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2009 {p1.x = (int)(p1.x*20)/20.0;
2010 p1.y = (int)(p1.y*20)/20.0;
2011 p2.x = (int)(p2.x*20)/20.0;
2012 p2.y = (int)(p2.y*20)/20.0;
2013 p3.x = (int)(p3.x*20)/20.0;
2014 p3.y = (int)(p3.y*20)/20.0;
2015 p4.x = (int)(p4.x*20)/20.0;
2016 p4.y = (int)(p4.y*20)/20.0;
2017 p5.x = (int)(p5.x*20)/20.0;
2018 p5.y = (int)(p5.y*20)/20.0;
2025 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
2026 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
2031 img.data = (gfxcolor_t*)data;
2035 if(type == IMAGE_TYPE_JPEG)
2036 /* TODO: pass image_dpi to device instead */
2037 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
2039 dev->fillbitmap(dev, &p1, &img, &m, 0);
2042 void drawimagejpeg(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
2043 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2045 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2048 void drawimagelossless(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
2049 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2051 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2055 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
2056 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2057 GBool inlineImg, int mask, int*maskColors)
2062 double x1,y1,x2,y2,x3,y3,x4,y4;
2063 ImageStream *imgStr;
2070 ncomps = colorMap->getNumPixelComps();
2071 bits = colorMap->getBits();
2073 imgStr = new ImageStream(str, width, ncomps,bits);
2076 if(!width || !height || (height<=1 && width<=1))
2078 msg("<verbose> Ignoring %d by %d image", width, height);
2079 unsigned char buf[8];
2081 for (y = 0; y < height; ++y)
2082 for (x = 0; x < width; ++x) {
2083 imgStr->getPixel(buf);
2089 state->transform(0, 1, &x1, &y1);
2090 state->transform(0, 0, &x2, &y2);
2091 state->transform(1, 0, &x3, &y3);
2092 state->transform(1, 1, &x4, &y4);
2094 if(!pbminfo && !(str->getKind()==strDCT)) {
2096 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2100 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2102 if(!jpeginfo && (str->getKind()==strDCT)) {
2103 msg("<notice> file contains jpeg pictures");
2109 unsigned char buf[8];
2111 unsigned char*pic = new unsigned char[width*height];
2114 state->getFillRGB(&rgb);
2116 memset(pal,255,sizeof(pal));
2117 pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
2118 pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
2119 pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
2120 pal[0].a = 255; pal[1].a = 0;
2123 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2124 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2125 for (y = 0; y < height; ++y)
2126 for (x = 0; x < width; ++x)
2128 imgStr->getPixel(buf);
2131 pic[width*y+x] = buf[0];
2134 /* the size of the drawn image is added to the identifier
2135 as the same image may require different bitmaps if displayed
2136 at different sizes (due to antialiasing): */
2139 unsigned char*pic2 = 0;
2142 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2151 height = realheight;
2155 /* make a black/white palette */
2160 float r = 255/(numpalette-1);
2162 for(t=0;t<numpalette;t++) {
2163 pal[t].r = (U8)(255*rgb.r);
2164 pal[t].g = (U8)(255*rgb.g);
2165 pal[t].b = (U8)(255*rgb.b);
2166 pal[t].a = (U8)(t*r);
2170 RGBA*pic2 = new RGBA[width*height];
2171 for (y = 0; y < height; ++y) {
2172 for (x = 0; x < width; ++x) {
2173 pic2[width*y+x] = pal[pic[y*width+x]];
2176 drawimagelossless(output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2185 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2186 RGBA*pic=new RGBA[width*height];
2187 for (y = 0; y < height; ++y) {
2188 for (x = 0; x < width; ++x) {
2189 imgStr->getPixel(pixBuf);
2190 colorMap->getRGB(pixBuf, &rgb);
2191 pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
2192 pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
2193 pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
2194 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2197 if(str->getKind()==strDCT)
2198 drawimagejpeg(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2200 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2205 RGBA*pic=new RGBA[width*height];
2208 for(t=0;t<256;t++) {
2210 colorMap->getRGB(pixBuf, &rgb);
2211 /*if(maskColors && *maskColors==t) {
2212 msg("<notice> Color %d is transparent", t);
2213 if (imgData->maskColors) {
2215 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2216 if (pix[i] < imgData->maskColors[2*i] ||
2217 pix[i] > imgData->maskColors[2*i+1]) {
2232 pal[t].r = (U8)(rgb.r * 255 + 0.5);
2233 pal[t].g = (U8)(rgb.g * 255 + 0.5);
2234 pal[t].b = (U8)(rgb.b * 255 + 0.5);
2235 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2238 for (y = 0; y < height; ++y) {
2239 for (x = 0; x < width; ++x) {
2240 imgStr->getPixel(pixBuf);
2241 pic[width*y+x] = pal[pixBuf[0]];
2244 drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2252 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2253 int width, int height, GBool invert,
2256 if(states[statepos].textRender & 4) //clipped
2258 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2259 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
2262 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2263 int width, int height, GfxImageColorMap *colorMap,
2264 int *maskColors, GBool inlineImg)
2266 if(states[statepos].textRender & 4) //clipped
2269 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
2270 colorMap?"colorMap":"no colorMap",
2271 maskColors?"maskColors":"no maskColors",
2274 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2275 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2276 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
2279 //SWFOutputDev*output = 0;
2281 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
2286 if (infoDict->lookup(key, &obj)->isString()) {
2287 s1 = obj.getString();
2288 if ((s1->getChar(0) & 0xff) == 0xfe &&
2289 (s1->getChar(1) & 0xff) == 0xff) {
2291 for (i = 2; i < obj.getString()->getLength(); i += 2) {
2292 if (s1->getChar(i) == '\0') {
2293 s2->append(s1->getChar(i+1));
2296 s2 = new GString("<unicode>");
2300 printf(fmt, s2->getCString());
2303 printf(fmt, s1->getCString());
2309 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2313 if (infoDict->lookup(key, &obj)->isString()) {
2314 s = obj.getString()->getCString();
2315 if (s[0] == 'D' && s[1] == ':') {
2326 void storeDeviceParameter(char*name, char*value)
2328 parameter_t*p = new parameter_t();
2329 p->name = strdup(name);
2330 p->value = strdup(value);
2332 if(device_config_next) {
2333 device_config_next->next = p;
2334 device_config_next = p;
2337 device_config_next = p;
2341 void pdfswf_setparameter(char*name, char*value)
2343 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2344 if(!strcmp(name, "caplinewidth")) {
2345 caplinewidth = atof(value);
2346 } else if(!strcmp(name, "zoom")) {
2349 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2350 storeDeviceParameter("jpegsubpixels", buf);
2351 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2352 storeDeviceParameter("ppmsubpixels", buf);
2353 } else if(!strcmp(name, "jpegdpi")) {
2355 jpeg_dpi = atoi(value);
2356 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2357 storeDeviceParameter("jpegsubpixels", buf);
2358 } else if(!strcmp(name, "ppmdpi")) {
2360 ppm_dpi = atoi(value);
2361 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2362 storeDeviceParameter("ppmsubpixels", buf);
2363 } else if(!strcmp(name, "forceType0Fonts")) {
2364 forceType0Fonts = atoi(value);
2365 } else if(!strcmp(name, "fontdir")) {
2366 pdfswf_addfontdir(value);
2367 } else if(!strcmp(name, "languagedir")) {
2368 pdfswf_addlanguagedir(value);
2369 } else if(!strcmp(name, "fontconfig")) {
2370 config_use_fontconfig = atoi(value);
2372 storeDeviceParameter(name,value);
2375 void pdfswf_addfont(char*filename)
2378 memset(&f, 0, sizeof(fontfile_t));
2379 f.filename = filename;
2380 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2381 fonts[fontnum++] = f;
2383 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2387 static char* dirseparator()
2396 void pdfswf_addlanguagedir(char*dir)
2399 globalParams = new GlobalParams("");
2401 msg("<notice> Adding %s to language pack directories", dir);
2405 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2406 strcpy(config_file, dir);
2407 strcat(config_file, dirseparator());
2408 strcat(config_file, "add-to-xpdfrc");
2410 fi = fopen(config_file, "rb");
2412 msg("<error> Could not open %s", config_file);
2415 globalParams->parseFile(new GString(config_file), fi);
2419 void pdfswf_addfontdir(char*dirname)
2421 #ifdef HAVE_DIRENT_H
2422 msg("<notice> Adding %s to font directories", dirname);
2423 DIR*dir = opendir(dirname);
2425 msg("<warning> Couldn't open directory %s\n", dirname);
2430 ent = readdir (dir);
2434 char*name = ent->d_name;
2440 if(!strncasecmp(&name[l-4], ".pfa", 4))
2442 if(!strncasecmp(&name[l-4], ".pfb", 4))
2444 if(!strncasecmp(&name[l-4], ".ttf", 4))
2448 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2449 strcpy(fontname, dirname);
2450 strcat(fontname, dirseparator());
2451 strcat(fontname, name);
2452 msg("<verbose> Adding %s to fonts", fontname);
2453 pdfswf_addfont(fontname);
2458 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2463 typedef struct _pdf_doc_internal
2467 } pdf_doc_internal_t;
2468 typedef struct _pdf_page_internal
2470 } pdf_page_internal_t;
2471 typedef struct _swf_output_internal
2473 SWFOutputDev*outputDev;
2474 } swf_output_internal_t;
2476 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2478 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2479 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2480 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2481 memset(i, 0, sizeof(pdf_doc_internal_t));
2482 pdf_doc->internal = i;
2484 GString *fileName = new GString(filename);
2490 globalParams = new GlobalParams("");
2493 if (userPassword && userPassword[0]) {
2494 userPW = new GString(userPassword);
2498 i->doc = new PDFDoc(fileName, userPW);
2502 if (!i->doc->isOk()) {
2507 i->doc->getDocInfo(&info);
2508 if (info.isDict() &&
2509 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2510 printInfoString(info.getDict(), "Title", "Title: %s\n");
2511 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2512 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2513 printInfoString(info.getDict(), "Author", "Author: %s\n");
2514 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2515 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2516 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2517 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2518 printf("Pages: %d\n", i->doc->getNumPages());
2519 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2520 printf("Encrypted: ");
2521 if (i->doc->isEncrypted()) {
2522 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2523 i->doc->okToPrint() ? "yes" : "no",
2524 i->doc->okToCopy() ? "yes" : "no",
2525 i->doc->okToChange() ? "yes" : "no",
2526 i->doc->okToAddNotes() ? "yes" : "no");
2533 pdf_doc->num_pages = i->doc->getNumPages();
2535 if (i->doc->isEncrypted()) {
2536 if(!i->doc->okToCopy()) {
2537 printf("PDF disallows copying.\n");
2540 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2547 void pdfswf_preparepage(int page)
2551 pages = (int*)malloc(1024*sizeof(int));
2554 if(pagepos == pagebuflen)
2557 pages = (int*)realloc(pages, pagebuflen);
2560 pages[pagepos++] = page;
2567 delete globalParams;globalParams=0;
2568 Object::memCheck(stderr);
2573 void pdf_destroy(pdf_doc_t*pdf_doc)
2575 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2577 msg("<debug> pdfswf.cc: pdfswf_close()");
2578 delete i->doc; i->doc=0;
2580 free(pages); pages = 0; //FIXME
2582 free(pdf_doc->internal);pdf_doc->internal=0;
2583 free(pdf_doc);pdf_doc=0;
2586 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2588 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2590 if(page < 1 || page > pdf_doc->num_pages)
2593 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2594 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2595 memset(pi, 0, sizeof(pdf_page_internal_t));
2596 pdf_page->internal = pi;
2598 pdf_page->parent = pdf_doc;
2599 pdf_page->nr = page;
2603 void pdf_page_destroy(pdf_page_t*pdf_page)
2605 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2606 free(pdf_page->internal);pdf_page->internal = 0;
2607 free(pdf_page);pdf_page=0;
2610 swf_output_t* swf_output_init()
2612 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2613 memset(swf_output, 0, sizeof(swf_output_t));
2614 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2615 memset(i, 0, sizeof(swf_output_internal_t));
2616 swf_output->internal = i;
2618 i->outputDev = new SWFOutputDev();
2622 void swf_output_setparameter(swf_output_t*swf_output, char*name, char*value)
2625 pdfswf_setparameter(name, value);
2628 void swf_output_pagefeed(swf_output_t*swf)
2630 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2631 i->outputDev->pagefeed();
2632 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2635 int swf_output_save(swf_output_t*swf, char*filename)
2637 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2638 int ret = i->outputDev->save(filename);
2639 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2643 void* swf_output_get(swf_output_t*swf)
2645 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2646 void* ret = i->outputDev->getSWF();
2647 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2651 void swf_output_destroy(swf_output_t*output)
2653 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2654 delete i->outputDev; i->outputDev=0;
2655 free(output->internal);output->internal=0;
2659 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2661 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2662 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2665 gfxdevice_t*dev = si->outputDev->output;
2666 dev->setparameter(dev, "protect", "1");
2668 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2670 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2672 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2674 si->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2677 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2679 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2680 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2682 si->outputDev->setMove(x,y);
2683 if((x1|y1|x2|y2)==0) x2++;
2684 si->outputDev->setClip(x1,y1,x2,y2);
2686 pdf_page_render2(page, output);
2688 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2690 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2691 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2693 si->outputDev->setMove(0,0);
2694 si->outputDev->setClip(0,0,0,0);
2696 pdf_page_render2(page, output);
2700 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2702 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2703 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2704 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2705 memset(info, 0, sizeof(pdf_page_info_t));
2707 InfoOutputDev*output = new InfoOutputDev;
2710 pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2712 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2715 info->xMin = output->x1;
2716 info->yMin = output->y1;
2717 info->xMax = output->x2;
2718 info->yMax = output->y2;
2719 info->number_of_images = output->num_images;
2720 info->number_of_links = output->num_links;
2721 info->number_of_fonts = output->num_fonts;
2728 void pdf_page_info_destroy(pdf_page_info_t*info)