reworked image code.
[swftools.git] / pdf2swf / SWFOutputDev.cc
1 /* pdfswf.cc
2    implements a pdf output device (OutputDev).
3
4    This file is part of swftools.
5
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.
10
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.
15
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 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stddef.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include "../config.h"
26 #ifdef HAVE_DIRENT_H
27 #include <dirent.h>
28 #endif
29 #ifdef HAVE_SYS_STAT_H
30 #include <sys/stat.h>
31 #endif
32 #ifdef HAVE_FONTCONFIG_H
33 #include <fontconfig.h>
34 #endif
35 //xpdf header files
36 #include "config.h"
37 #include "gfile.h"
38 #include "GString.h"
39 #include "gmem.h"
40 #include "Object.h"
41 #include "Stream.h"
42 #include "Array.h"
43 #include "Dict.h"
44 #include "XRef.h"
45 #include "Catalog.h"
46 #include "Page.h"
47 #include "PDFDoc.h"
48 #include "Error.h"
49 #include "OutputDev.h"
50 #include "GfxState.h"
51 #include "GfxFont.h"
52 #include "CharCodeToUnicode.h"
53 #include "NameToUnicodeTable.h"
54 #include "GlobalParams.h"
55 //#define XPDF_101
56 #ifdef XPDF_101
57 #include "FontFile.h"
58 #else
59 #include "FoFiType1C.h"
60 #include "FoFiTrueType.h"
61 #endif
62 #include "SWFOutputDev.h"
63
64 //swftools header files
65 #include "swfoutput.h"
66 #include "../lib/log.h"
67
68 #include <math.h>
69
70 typedef struct _fontfile
71 {
72     char*filename;
73     int used;
74 } fontfile_t;
75
76 // for pdfswf_addfont
77 static fontfile_t fonts[2048];
78 static int fontnum = 0;
79
80 static int config_use_fontconfig = 1;
81
82 // swf <-> pdf pages
83 // TODO: move into pdf_doc_t
84 static int*pages = 0;
85 static int pagebuflen = 0;
86 static int pagepos = 0;
87
88 /* config */
89 static double caplinewidth = 3.0;
90 static int zoom = 72; /* xpdf: 86 */
91 static int forceType0Fonts = 0;
92
93 static void printInfoString(Dict *infoDict, char *key, char *fmt);
94 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
95
96 struct mapping {
97     char*pdffont;
98     char*filename;
99 } pdf2t1map[] ={
100 {"Times-Roman",           "n021003l"},
101 {"Times-Italic",          "n021023l"},
102 {"Times-Bold",            "n021004l"},
103 {"Times-BoldItalic",      "n021024l"},
104 {"Helvetica",             "n019003l"},
105 {"Helvetica-Oblique",     "n019023l"},
106 {"Helvetica-Bold",        "n019004l"},
107 {"Helvetica-BoldOblique", "n019024l"},
108 {"Courier",               "n022003l"},
109 {"Courier-Oblique",       "n022023l"},
110 {"Courier-Bold",          "n022004l"},
111 {"Courier-BoldOblique",   "n022024l"},
112 {"Symbol",                "s050000l"},
113 {"ZapfDingbats",          "d050000l"}};
114
115 class SWFOutputDev:  public OutputDev {
116   int outputstarted;
117   struct swfoutput output;
118 public:
119
120   // Constructor.
121   SWFOutputDev();
122
123   // Destructor.
124   virtual ~SWFOutputDev() ;
125
126   void setMove(int x,int y);
127   void setClip(int x1,int y1,int x2,int y2);
128   
129   int save(char*filename);
130   void  pagefeed();
131   void* getSWF();
132
133   void getDimensions(int*x1,int*y1,int*x2,int*y2);
134
135   //----- get info about output device
136
137   // Does this device use upside-down coordinates?
138   // (Upside-down means (0,0) is the top left corner of the page.)
139   virtual GBool upsideDown();
140
141   // Does this device use drawChar() or drawString()?
142   virtual GBool useDrawChar();
143   
144   // Can this device draw gradients?
145   virtual GBool useGradients();
146   
147   virtual GBool interpretType3Chars() {return gTrue;}
148
149   //----- initialization and control
150
151   void setXRef(PDFDoc*doc, XRef *xref);
152
153   // Start a page.
154   virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
155
156   //----- link borders
157   virtual void drawLink(Link *link, Catalog *catalog) ;
158
159   //----- save/restore graphics state
160   virtual void saveState(GfxState *state) ;
161   virtual void restoreState(GfxState *state) ;
162
163   //----- update graphics state
164
165   virtual void updateFont(GfxState *state);
166   virtual void updateFillColor(GfxState *state);
167   virtual void updateStrokeColor(GfxState *state);
168   virtual void updateLineWidth(GfxState *state);
169   virtual void updateLineJoin(GfxState *state);
170   virtual void updateLineCap(GfxState *state);
171   
172   virtual void updateAll(GfxState *state) 
173   {
174       updateFont(state);
175       updateFillColor(state);
176       updateStrokeColor(state);
177       updateLineWidth(state);
178       updateLineJoin(state);
179       updateLineCap(state);
180   };
181
182   //----- path painting
183   virtual void stroke(GfxState *state) ;
184   virtual void fill(GfxState *state) ;
185   virtual void eoFill(GfxState *state) ;
186
187   //----- path clipping
188   virtual void clip(GfxState *state) ;
189   virtual void eoClip(GfxState *state) ;
190
191   //----- text drawing
192   virtual void beginString(GfxState *state, GString *s) ;
193   virtual void endString(GfxState *state) ;
194   virtual void drawChar(GfxState *state, double x, double y,
195                         double dx, double dy,
196                         double originX, double originY,
197                         CharCode code, Unicode *u, int uLen);
198
199   //----- image drawing
200   virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
201                              int width, int height, GBool invert,
202                              GBool inlineImg);
203   virtual void drawImage(GfxState *state, Object *ref, Stream *str,
204                          int width, int height, GfxImageColorMap *colorMap,
205                          int *maskColors, GBool inlineImg);
206   
207   virtual GBool beginType3Char(GfxState *state,
208                                CharCode code, Unicode *u, int uLen);
209   virtual void endType3Char(GfxState *state);
210
211   private:
212   void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
213                                    int width, int height, GfxImageColorMap*colorMap, GBool invert,
214                                    GBool inlineImg, int mask);
215   int clipping[64];
216   int clippos;
217
218   int currentpage;
219
220   PDFDoc*doc;
221   XRef*xref;
222
223   char* searchFont(char*name);
224   char* substituteFont(GfxFont*gfxFont, char*oldname);
225   char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
226   int t1id;
227   int jpeginfo; // did we write "File contains jpegs" yet?
228   int pbminfo; // did we write "File contains jpegs" yet?
229   int linkinfo; // did we write "File contains links" yet?
230   int ttfinfo; // did we write "File contains TrueType Fonts" yet?
231   int gradientinfo; // did we write "File contains Gradients yet?
232
233   int type3active; // are we between beginType3()/endType3()?
234
235   GfxState *laststate;
236
237   char type3Warning;
238
239   char* substitutetarget[256];
240   char* substitutesource[256];
241   int substitutepos;
242
243   int user_movex,user_movey;
244   int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
245 };
246
247 static char*getFontID(GfxFont*font);
248
249 class InfoOutputDev:  public OutputDev 
250 {
251   public:
252   int x1,y1,x2,y2;
253   int num_links;
254   int num_images;
255   int num_fonts;
256
257   InfoOutputDev() 
258   {
259       num_links = 0;
260       num_images = 0;
261       num_fonts = 0;
262   }
263   virtual ~InfoOutputDev() 
264   {
265   }
266   virtual GBool upsideDown() {return gTrue;}
267   virtual GBool useDrawChar() {return gTrue;}
268   virtual GBool useGradients() {return gTrue;}
269   virtual GBool interpretType3Chars() {return gTrue;}
270   virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
271   {
272       double x1,y1,x2,y2;
273       state->transform(crop_x1,crop_y1,&x1,&y1);
274       state->transform(crop_x2,crop_y2,&x2,&y2);
275       if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
276       if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
277       this->x1 = (int)x1;
278       this->y1 = (int)y1;
279       this->x2 = (int)x2;
280       this->y2 = (int)y2;
281   }
282   virtual void drawLink(Link *link, Catalog *catalog) 
283   {
284       num_links++;
285   }
286   virtual void updateFont(GfxState *state) 
287   {
288       GfxFont*font = state->getFont();
289       if(!font)
290           return;
291       char*id = getFontID(font);
292       /* FIXME*/
293       num_fonts++;
294   }
295   virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
296                              int width, int height, GBool invert,
297                              GBool inlineImg) 
298   {
299       num_images++;
300   }
301   virtual void drawImage(GfxState *state, Object *ref, Stream *str,
302                          int width, int height, GfxImageColorMap *colorMap,
303                          int *maskColors, GBool inlineImg)
304   {
305       num_images++;
306   }
307 };
308
309 SWFOutputDev::SWFOutputDev()
310 {
311     jpeginfo = 0;
312     ttfinfo = 0;
313     linkinfo = 0;
314     pbminfo = 0;
315     type3active = 0;
316     clippos = 0;
317     clipping[clippos] = 0;
318     outputstarted = 0;
319     xref = 0;
320     substitutepos = 0;
321     type3Warning = 0;
322     user_movex = 0;
323     user_movey = 0;
324     user_clipx1 = 0;
325     user_clipy1 = 0;
326     user_clipx2 = 0;
327     user_clipy2 = 0;
328     memset(&output, 0, sizeof(output));
329 //    printf("SWFOutputDev::SWFOutputDev() \n");
330 };
331   
332 void SWFOutputDev::setMove(int x,int y)
333 {
334     this->user_movex = x;
335     this->user_movey = y;
336 }
337
338 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
339 {
340     if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
341     if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
342
343     this->user_clipx1 = x1;
344     this->user_clipy1 = y1;
345     this->user_clipx2 = x2;
346     this->user_clipy2 = y2;
347 }
348 void SWFOutputDev::getDimensions(int*x1,int*y1,int*x2,int*y2)
349 {
350     return swfoutput_getdimensions(&output, x1,y1,x2,y2);
351 }
352
353 static char*getFontID(GfxFont*font)
354 {
355     GString*gstr = font->getName();
356     char* fontname = gstr==0?0:gstr->getCString();
357     if(fontname==0) {
358         char buf[32];
359         Ref*r=font->getID();
360         sprintf(buf, "UFONT%d", r->num);
361         return strdup(buf);
362     }
363     return strdup(fontname);
364 }
365
366 static char*getFontName(GfxFont*font)
367 {
368     char*fontid = getFontID(font);
369     char*fontname= 0;
370     char* plus = strchr(fontid, '+');
371     if(plus && plus < &fontid[strlen(fontid)-1]) {
372         fontname = strdup(plus+1);
373     } else {
374         fontname = strdup(fontid);
375     }
376     free(fontid);
377     return fontname;
378 }
379
380 static char mybuf[1024];
381 static char* gfxstate2str(GfxState *state)
382 {
383   char*bufpos = mybuf;
384   GfxRGB rgb;
385   bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
386                                     state->getCTM()[0],
387                                     state->getCTM()[1],
388                                     state->getCTM()[2],
389                                     state->getCTM()[3],
390                                     state->getCTM()[4],
391                                     state->getCTM()[5]);
392   if(state->getX1()!=0.0)
393   bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
394   if(state->getY1()!=0.0)
395   bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
396   bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
397   bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
398   bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
399   bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
400   /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
401           state->getFillColor()->c[0], state->getFillColor()->c[1]);
402   bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
403           state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
404 /*  bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
405           state->getFillColor()->c[0], state->getFillColor()->c[1],
406           state->getFillColor()->c[2], state->getFillColor()->c[3],
407           state->getFillColor()->c[4], state->getFillColor()->c[5],
408           state->getFillColor()->c[6], state->getFillColor()->c[7]);
409   bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
410           state->getStrokeColor()->c[0], state->getFillColor()->c[1],
411           state->getStrokeColor()->c[2], state->getFillColor()->c[3],
412           state->getStrokeColor()->c[4], state->getFillColor()->c[5],
413           state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
414   state->getFillRGB(&rgb);
415   if(rgb.r || rgb.g || rgb.b)
416   bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
417   state->getStrokeRGB(&rgb);
418   if(rgb.r || rgb.g || rgb.b)
419   bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
420   if(state->getFillColorSpace()->getNComps()>1)
421   bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
422   if(state->getStrokeColorSpace()->getNComps()>1)
423   bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
424   if(state->getFillPattern())
425   bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
426   if(state->getStrokePattern())
427   bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
428  
429   if(state->getFillOpacity()!=1.0)
430   bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
431   if(state->getStrokeOpacity()!=1.0)
432   bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
433
434   bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
435  
436   double * dash;
437   int length;
438   double start;
439   state->getLineDash(&dash, &length, &start);
440   int t;
441   if(length)
442   {
443       bufpos+=sprintf(bufpos,"DASH%.1f[",start);
444       for(t=0;t<length;t++) {
445           bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
446       }
447       bufpos+=sprintf(bufpos,"]");
448   }
449
450   if(state->getFlatness()!=1)
451   bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
452   if(state->getLineJoin()!=0)
453   bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
454   if(state->getLineJoin()!=0)
455   bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
456   if(state->getLineJoin()!=0)
457   bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
458
459   if(state->getFont() && getFontID(state->getFont()))
460   bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
461   bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
462   bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
463                                    state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
464   if(state->getCharSpace())
465   bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
466   if(state->getWordSpace())
467   bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
468   if(state->getHorizScaling()!=1.0)
469   bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
470   if(state->getLeading())
471   bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
472   if(state->getRise())
473   bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
474   if(state->getRender())
475   bufpos+=sprintf(bufpos,"R%d ", state->getRender());
476   bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
477   bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
478   bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
479   if(state->getLineX())
480   bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
481   if(state->getLineY())
482   bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
483   bufpos+=sprintf(bufpos," ");
484   return mybuf;
485 }
486
487 static void dumpFontInfo(char*loglevel, GfxFont*font);
488 static int lastdumps[1024];
489 static int lastdumppos = 0;
490 /* nr = 0  unknown
491    nr = 1  substituting
492    nr = 2  type 3
493  */
494 static void showFontError(GfxFont*font, int nr) 
495 {  
496     Ref*r=font->getID();
497     int t;
498     for(t=0;t<lastdumppos;t++)
499         if(lastdumps[t] == r->num)
500             break;
501     if(t < lastdumppos)
502       return;
503     if(lastdumppos<sizeof(lastdumps)/sizeof(int))
504     lastdumps[lastdumppos++] = r->num;
505     if(nr == 0)
506       msg("<warning> The following font caused problems:");
507     else if(nr == 1)
508       msg("<warning> The following font caused problems (substituting):");
509     else if(nr == 2)
510       msg("<warning> The following Type 3 Font will be rendered as bitmap:");
511     dumpFontInfo("<warning>", font);
512 }
513
514 static void dumpFontInfo(char*loglevel, GfxFont*font)
515 {
516   char* name = getFontID(font);
517   Ref* r=font->getID();
518   msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, getFontName(font), r->num,r->gen);
519
520   GString*gstr  = font->getTag();
521    
522   msg("%s| Tag: %s\n", loglevel, name);
523   
524   if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
525
526   GfxFontType type=font->getType();
527   switch(type) {
528     case fontUnknownType:
529      msg("%s| Type: unknown\n",loglevel);
530     break;
531     case fontType1:
532      msg("%s| Type: 1\n",loglevel);
533     break;
534     case fontType1C:
535      msg("%s| Type: 1C\n",loglevel);
536     break;
537     case fontType3:
538      msg("%s| Type: 3\n",loglevel);
539     break;
540     case fontTrueType:
541      msg("%s| Type: TrueType\n",loglevel);
542     break;
543     case fontCIDType0:
544      msg("%s| Type: CIDType0\n",loglevel);
545     break;
546     case fontCIDType0C:
547      msg("%s| Type: CIDType0C\n",loglevel);
548     break;
549     case fontCIDType2:
550      msg("%s| Type: CIDType2\n",loglevel);
551     break;
552   }
553   
554   Ref embRef;
555   GBool embedded = font->getEmbeddedFontID(&embRef);
556   if(font->getEmbeddedFontName())
557     name = font->getEmbeddedFontName()->getCString();
558   if(embedded)
559    msg("%s| Embedded name: %s id: %d\n",loglevel, FIXNULL(name), embRef.num);
560
561   gstr = font->getExtFontFile();
562   if(gstr)
563    msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
564
565   // Get font descriptor flags.
566   if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
567   if(font->isSerif()) msg("%s| is serif\n", loglevel);
568   if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
569   if(font->isItalic()) msg("%s| is italic\n", loglevel);
570   if(font->isBold()) msg("%s| is bold\n", loglevel);
571 }
572
573 //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");}
574 //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");}
575
576 static void free_outline(SWF_OUTLINE*outline)
577 {
578     while(outline) {
579         SWF_OUTLINE*next = outline->link;
580         free(outline);
581         outline = next;
582     }
583 }
584
585 static void dump_outline(SWF_OUTLINE*outline)
586 {
587     double x=0,y=0;
588     while(outline) {
589         double lastx=x,lasty=y;
590         x += (outline->dest.x/(float)0xffff);
591         y += (outline->dest.y/(float)0xffff);
592         if(outline->type == SWF_PATHTYPE_MOVE) {
593             msg("<trace> | moveto %f,%f", x,y);
594         } else if(outline->type == SWF_PATHTYPE_LINE) {
595             msg("<trace> | lineto: %f,%f\n",x,y);
596         } else if(outline->type == SWF_PATHTYPE_BEZIER) {
597             SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
598             float x1 = o2->C.x/(float)0xffff+lastx;
599             float y1 = o2->C.y/(float)0xffff+lasty;
600             float x2 = o2->B.x/(float)0xffff+lastx;
601             float y2 = o2->B.y/(float)0xffff+lasty;
602             msg("<trace> | spline: %f,%f -> %f,%f -> %f,%f\n",x1,y1,x2,y2,x,y);
603         } 
604         outline = outline->link;
605     }
606 }
607
608 SWF_OUTLINE* gfxPath_to_SWF_OUTLINE(GfxState*state, GfxPath*path)
609 {
610     int num = path->getNumSubpaths();
611     int s,t;
612     bezierpathsegment*start,*last=0;
613     bezierpathsegment*outline = start = (bezierpathsegment*)malloc(sizeof(bezierpathsegment));
614     int cpos = 0;
615     double lastx=0,lasty=0;
616     if(!num) {
617         msg("<warning> empty path");
618         outline->type = SWF_PATHTYPE_MOVE;
619         outline->dest.x = 0;
620         outline->dest.y = 0;
621         outline->link = 0;
622         return (SWF_OUTLINE*)outline;
623     }
624     for(t = 0; t < num; t++) {
625         GfxSubpath *subpath = path->getSubpath(t);
626         int subnum = subpath->getNumPoints();
627
628         for(s=0;s<subnum;s++) {
629            double nx,ny;
630            state->transform(subpath->getX(s),subpath->getY(s),&nx,&ny);
631            int x = (int)((nx-lastx)*0xffff);
632            int y = (int)((ny-lasty)*0xffff);
633            if(s==0) 
634            {
635                 last = outline;
636                 outline->type = SWF_PATHTYPE_MOVE;
637                 outline->dest.x = x;
638                 outline->dest.y = y;
639                 outline->link = (SWF_OUTLINE*)malloc(sizeof(bezierpathsegment));
640                 outline = (bezierpathsegment*)outline->link;
641                 cpos = 0;
642                 lastx = nx;
643                 lasty = ny;
644            }
645            else if(subpath->getCurve(s) && !cpos)
646            {
647                 outline->B.x = x;
648                 outline->B.y = y;
649                 cpos = 1;
650            } 
651            else if(subpath->getCurve(s) && cpos)
652            {
653                 outline->C.x = x;
654                 outline->C.y = y;
655                 cpos = 2;
656            }
657            else
658            {
659                 last = outline;
660                 outline->dest.x = x;
661                 outline->dest.y = y;
662                 outline->type = cpos?SWF_PATHTYPE_BEZIER:SWF_PATHTYPE_LINE;
663                 outline->link = (SWF_OUTLINE*)malloc(sizeof(bezierpathsegment));
664                 outline = (bezierpathsegment*)outline->link;
665                 cpos = 0;
666                 lastx = nx;
667                 lasty = ny;
668            }
669         }
670     }
671     if(last->link) {free(last->link);}
672     last->link = 0;
673
674     return (SWF_OUTLINE*)start;
675 }
676 /*----------------------------------------------------------------------------
677  * Primitive Graphic routines
678  *----------------------------------------------------------------------------*/
679
680 void SWFOutputDev::stroke(GfxState *state) 
681 {
682     GfxPath * path = state->getPath();
683     int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
684     int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
685     double miterLimit = state->getMiterLimit();
686     double width = state->getTransformedLineWidth();
687     struct swfmatrix m;
688     GfxRGB rgb;
689     double opaq = state->getStrokeOpacity();
690     state->getStrokeRGB(&rgb);
691
692     m.m11 = 1; m.m21 = 0; m.m22 = 1;
693     m.m12 = 0; m.m13 = 0; m.m23 = 0;
694     SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
695     
696     if(getLogLevel() >= LOGLEVEL_TRACE)  {
697         msg("<trace> stroke\n");
698         dump_outline(outline);
699     }
700
701     lineJoin = 1; // other line joins are not yet supported by the swf encoder
702                   // TODO: support bevel joints
703
704     if(((lineCap==1) && (lineJoin==1)) || width<=caplinewidth) {
705         /* FIXME- if the path is smaller than 2 segments, we could ignore
706            lineJoin */
707         swfoutput_setdrawmode(&output, DRAWMODE_STROKE);
708         swfoutput_drawpath(&output, outline, &m);
709     } else {
710         swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), 
711                                         (char)(rgb.b*255), (char)(opaq*255));
712
713         //swfoutput_setlinewidth(&output, 1.0); //only for debugging
714         //swfoutput_setstrokecolor(&output, 0, 255, 0, 255); //likewise, see below
715         //swfoutput_setfillcolor(&output, 255, 0, 0, 255); //likewise, see below
716
717         swfoutput_drawpath2poly(&output, outline, &m, lineJoin, lineCap, width, miterLimit);
718         updateLineWidth(state);  //reset
719         updateStrokeColor(state); //reset
720         updateFillColor(state);  //reset
721     }
722     free_outline(outline);
723 }
724 void SWFOutputDev::fill(GfxState *state) 
725 {
726     GfxPath * path = state->getPath();
727     struct swfmatrix m;
728     m.m11 = 1; m.m21 = 0; m.m22 = 1;
729     m.m12 = 0; m.m13 = 0; m.m23 = 0;
730     SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
731
732     if(getLogLevel() >= LOGLEVEL_TRACE)  {
733         msg("<trace> fill\n");
734         dump_outline(outline);
735     }
736
737     swfoutput_setdrawmode(&output, DRAWMODE_FILL);
738     swfoutput_drawpath(&output, outline, &m);
739     free_outline(outline);
740 }
741 void SWFOutputDev::eoFill(GfxState *state) 
742 {
743     GfxPath * path = state->getPath();
744     struct swfmatrix m;
745     m.m11 = 1; m.m21 = 0; m.m22 = 1;
746     m.m12 = 0; m.m13 = 0; m.m23 = 0;
747     SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
748
749     if(getLogLevel() >= LOGLEVEL_TRACE)  {
750         msg("<trace> eofill\n");
751         dump_outline(outline);
752     }
753
754     swfoutput_setdrawmode(&output, DRAWMODE_EOFILL);
755     swfoutput_drawpath(&output, outline, &m);
756     free_outline(outline);
757 }
758 void SWFOutputDev::clip(GfxState *state) 
759 {
760     GfxPath * path = state->getPath();
761     struct swfmatrix m;
762     m.m11 = 1; m.m22 = 1;
763     m.m12 = 0; m.m21 = 0; 
764     m.m13 = 0; m.m23 = 0;
765     SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
766
767     if(getLogLevel() >= LOGLEVEL_TRACE)  {
768         msg("<trace> clip\n");
769         dump_outline(outline);
770     }
771
772     swfoutput_startclip(&output, outline, &m);
773     clipping[clippos] ++;
774     free_outline(outline);
775 }
776 void SWFOutputDev::eoClip(GfxState *state) 
777 {
778     GfxPath * path = state->getPath();
779     struct swfmatrix m;
780     m.m11 = 1; m.m21 = 0; m.m22 = 1;
781     m.m12 = 0; m.m13 = 0; m.m23 = 0;
782     SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
783
784     if(getLogLevel() >= LOGLEVEL_TRACE)  {
785         msg("<trace> eoclip\n");
786         dump_outline(outline);
787     }
788
789     swfoutput_startclip(&output, outline, &m);
790     clipping[clippos] ++;
791     free_outline(outline);
792 }
793
794 /* pass through functions for swf_output */
795 int SWFOutputDev::save(char*filename)
796 {
797     return swfoutput_save(&output, filename);
798 }
799 void SWFOutputDev::pagefeed()
800 {
801     swfoutput_pagefeed(&output);
802 }
803 void* SWFOutputDev::getSWF()
804 {
805     return (void*)swfoutput_get(&output);
806 }
807
808 SWFOutputDev::~SWFOutputDev() 
809 {
810     swfoutput_destroy(&output);
811     outputstarted = 0;
812 };
813 GBool SWFOutputDev::upsideDown() 
814 {
815     msg("<debug> upsidedown? yes");
816     return gTrue;
817 };
818 GBool SWFOutputDev::useDrawChar() 
819 {
820     return gTrue;
821 }
822 GBool SWFOutputDev::useGradients()
823 {
824     if(!gradientinfo)
825     {
826         msg("<notice> File contains gradients");
827         gradientinfo = 1;
828     }
829     return gTrue;
830 }
831
832 void SWFOutputDev::beginString(GfxState *state, GString *s) 
833
834     double m11,m21,m12,m22;
835 //    msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
836     state->getFontTransMat(&m11, &m12, &m21, &m22);
837     m11 *= state->getHorizScaling();
838     m21 *= state->getHorizScaling();
839     swfoutput_setfontmatrix(&output, m11, -m21, m12, -m22);
840 }
841
842 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
843                         double dx, double dy,
844                         double originX, double originY,
845                         CharCode c, Unicode *_u, int uLen)
846 {
847     // check for invisible text -- this is used by Acrobat Capture
848     if ((state->getRender() & 3) == 3)
849         return;
850     Gushort *CIDToGIDMap = 0;
851     GfxFont*font = state->getFont();
852
853     if(font->getType() == fontType3) {
854         /* type 3 chars are passed as graphics */
855         return;
856     }
857     double x1,y1;
858     x1 = x;
859     y1 = y;
860     state->transform(x, y, &x1, &y1);
861     
862     Unicode u=0;
863     char*name=0;
864
865     if(_u && uLen) {
866         u = *_u;
867         if (u) {
868             int t;
869             /* find out char name from unicode index 
870                TODO: should be precomputed
871              */
872             for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
873                 if(nameToUnicodeTab[t].u == u) {
874                     name = nameToUnicodeTab[t].name;
875                     break;
876                 }
877             }
878         }
879     }
880
881     if(font->isCIDFont()) {
882         GfxCIDFont*cfont = (GfxCIDFont*)font;
883
884         if(font->getType() == fontCIDType2) {
885             CIDToGIDMap = cfont->getCIDToGID();
886         }
887     } else {
888         Gfx8BitFont*font8;
889         font8 = (Gfx8BitFont*)font;
890         char**enc=font8->getEncoding();
891         if(enc && enc[c])
892            name = enc[c];
893     }
894  
895     if (CIDToGIDMap) {
896         msg("<debug> drawChar(%f, %f, c='%c' (%d), GID=%d, u=%d <%d>) CID=%d name=\"%s\"\n", x, y, (c&127)>=32?c:'?', c, CIDToGIDMap[c], u, uLen, font->isCIDFont(), FIXNULL(name));
897         swfoutput_drawchar(&output, x1, y1, name, CIDToGIDMap[c], u);
898     } else {
899         msg("<debug> drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d name=\"%s\"\n",x,y,(c&127)>=32?c:'?',c,u, uLen, font->isCIDFont(), FIXNULL(name));
900         swfoutput_drawchar(&output, x1, y1, name, c, u);
901     }
902 }
903
904 void SWFOutputDev::endString(GfxState *state) { 
905 }    
906
907  
908 GBool SWFOutputDev::beginType3Char(GfxState *state,
909                                CharCode code, Unicode *u, int uLen)
910 {
911     msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
912     type3active = 1;
913     /* the character itself is going to be passed using
914        drawImageMask() */
915     return gFalse; /* gTrue= is_in_cache? */
916 }
917
918 void SWFOutputDev::endType3Char(GfxState *state)
919 {
920     type3active = 0;
921     msg("<debug> endType3Char");
922 }
923
924 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2) 
925 {
926     this->currentpage = pageNum;
927     double x1,y1,x2,y2;
928     int rot = doc->getPageRotate(1);
929     laststate = state;
930     msg("<verbose> startPage %d (%f,%f,%f,%f)\n", pageNum, crop_x1, crop_y1, crop_x2, crop_y2);
931     if(rot!=0)
932         msg("<verbose> page is rotated %d degrees\n", rot);
933
934     /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
935     state->transform(state->getX2(),state->getY2(),&x2,&y2);
936     Use CropBox, not MediaBox, as page size
937     */
938     
939     /*x1 = crop_x1;
940     y1 = crop_y1;
941     x2 = crop_x2;
942     y2 = crop_y2;*/
943     state->transform(crop_x1,crop_y1,&x1,&y1);
944     state->transform(crop_x2,crop_y2,&x2,&y2);
945
946     if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
947     if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
948
949     /* apply user clip box */
950     if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
951         /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
952         /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
953         /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
954         /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
955     }
956
957     if(!outputstarted) {
958         msg("<verbose> Bounding box is (%f,%f)-(%f,%f)", x1,y1,x2,y2);
959         swfoutput_init(&output);
960         outputstarted = 1;
961     }
962       
963     swfoutput_newpage(&output, pageNum, user_movex, user_movey, (int)x1, (int)y1, (int)x2, (int)y2);
964 }
965
966 void SWFOutputDev::drawLink(Link *link, Catalog *catalog) 
967 {
968     msg("<debug> drawlink\n");
969     double x1, y1, x2, y2, w;
970     GfxRGB rgb;
971     swfcoord points[5];
972     int x, y;
973
974 #ifdef XPDF_101
975     link->getBorder(&x1, &y1, &x2, &y2, &w);
976 #else
977     link->getRect(&x1, &y1, &x2, &y2);
978 #endif
979     rgb.r = 0;
980     rgb.g = 0;
981     rgb.b = 1;
982     cvtUserToDev(x1, y1, &x, &y);
983     points[0].x = points[4].x = (int)x;
984     points[0].y = points[4].y = (int)y;
985     cvtUserToDev(x2, y1, &x, &y);
986     points[1].x = (int)x;
987     points[1].y = (int)y;
988     cvtUserToDev(x2, y2, &x, &y);
989     points[2].x = (int)x;
990     points[2].y = (int)y;
991     cvtUserToDev(x1, y2, &x, &y);
992     points[3].x = (int)x;
993     points[3].y = (int)y;
994
995     LinkAction*action=link->getAction();
996     char buf[128];
997     char*s = 0;
998     char*type = "-?-";
999     char*url = 0;
1000     char*named = 0;
1001     int page = -1;
1002     switch(action->getKind())
1003     {
1004         case actionGoTo: {
1005             type = "GoTo";
1006             LinkGoTo *ha=(LinkGoTo *)link->getAction();
1007             LinkDest *dest=NULL;
1008             if (ha->getDest()==NULL) 
1009                 dest=catalog->findDest(ha->getNamedDest());
1010             else dest=ha->getDest();
1011             if (dest){ 
1012               if (dest->isPageRef()){
1013                 Ref pageref=dest->getPageRef();
1014                 page=catalog->findPage(pageref.num,pageref.gen);
1015               }
1016               else  page=dest->getPageNum();
1017               sprintf(buf, "%d", page);
1018               s = strdup(buf);
1019             }
1020         }
1021         break;
1022         case actionGoToR: {
1023             type = "GoToR";
1024             LinkGoToR*l = (LinkGoToR*)action;
1025             GString*g = l->getNamedDest();
1026             if(g)
1027              s = strdup(g->getCString());
1028         }
1029         break;
1030         case actionNamed: {
1031             type = "Named";
1032             LinkNamed*l = (LinkNamed*)action;
1033             GString*name = l->getName();
1034             if(name) {
1035                 s = strdup(name->lowerCase()->getCString());
1036                 named = name->getCString();
1037                 if(!strchr(s,':')) 
1038                 {
1039                     if(strstr(s, "next") || strstr(s, "forward"))
1040                     {
1041                         page = currentpage + 1;
1042                     }
1043                     else if(strstr(s, "prev") || strstr(s, "back"))
1044                     {
1045                         page = currentpage - 1;
1046                     }
1047                     else if(strstr(s, "last") || strstr(s, "end"))
1048                     {
1049                         page = pagepos>0?pages[pagepos-1]:0;
1050                     }
1051                     else if(strstr(s, "first") || strstr(s, "top"))
1052                     {
1053                         page = 1;
1054                     }
1055                 }
1056             }
1057         }
1058         break;
1059         case actionLaunch: {
1060             type = "Launch";
1061             LinkLaunch*l = (LinkLaunch*)action;
1062             GString * str = new GString(l->getFileName());
1063             str->append(l->getParams());
1064             s = strdup(str->getCString());
1065             delete str;
1066         }
1067         break;
1068         case actionURI: {
1069             type = "URI";
1070             LinkURI*l = (LinkURI*)action;
1071             GString*g = l->getURI();
1072             if(g) {
1073              url = g->getCString();
1074              s = strdup(url);
1075             }
1076         }
1077         break;
1078         case actionUnknown: {
1079             type = "Unknown";
1080             LinkUnknown*l = (LinkUnknown*)action;
1081             s = strdup("");
1082         }
1083         break;
1084         default: {
1085             msg("<error> Unknown link type!\n");
1086             break;
1087         }
1088     }
1089     if(!s) s = strdup("-?-");
1090
1091     if(!linkinfo && (page || url))
1092     {
1093         msg("<notice> File contains links");
1094         linkinfo = 1;
1095     }
1096     if(page>0)
1097     {
1098         int t;
1099         for(t=0;t<pagepos;t++)
1100             if(pages[t]==page)
1101                 break;
1102         if(t!=pagepos)
1103             swfoutput_linktopage(&output, t, points);
1104     }
1105     else if(url)
1106     {
1107         swfoutput_linktourl(&output, url, points);
1108     }
1109     else if(named)
1110     {
1111         swfoutput_namedlink(&output, named, points);
1112     }
1113     msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1114     free(s);s=0;
1115 }
1116
1117 void SWFOutputDev::saveState(GfxState *state) {
1118   msg("<debug> saveState\n");
1119   updateAll(state);
1120   if(clippos<64)
1121     clippos ++;
1122   else
1123     msg("<error> Too many nested states in pdf.");
1124   clipping[clippos] = 0;
1125 };
1126
1127 void SWFOutputDev::restoreState(GfxState *state) {
1128   msg("<debug> restoreState\n");
1129   updateAll(state);
1130   while(clipping[clippos]) {
1131       swfoutput_endclip(&output);
1132       clipping[clippos]--;
1133   }
1134   clippos--;
1135 }
1136
1137 char* SWFOutputDev::searchFont(char*name) 
1138 {       
1139     int i;
1140     char*filename=0;
1141     int is_standard_font = 0;
1142         
1143     msg("<verbose> SearchFont(%s)", name);
1144
1145     /* see if it is a pdf standard font */
1146     for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++) 
1147     {
1148         if(!strcmp(name, pdf2t1map[i].pdffont))
1149         {
1150             name = pdf2t1map[i].filename;
1151             is_standard_font = 1;
1152             break;
1153         }
1154     }
1155     /* look in all font files */
1156     for(i=0;i<fontnum;i++) 
1157     {
1158         if(strstr(fonts[i].filename, name))
1159         {
1160             if(!fonts[i].used) {
1161
1162                 fonts[i].used = 1;
1163                 if(!is_standard_font)
1164                     msg("<notice> Using %s for %s", fonts[i].filename, name);
1165             }
1166             return strdup(fonts[i].filename);
1167         }
1168     }
1169     return 0;
1170 }
1171
1172 void SWFOutputDev::updateLineWidth(GfxState *state)
1173 {
1174     double width = state->getTransformedLineWidth();
1175     swfoutput_setlinewidth(&output, width);
1176 }
1177
1178 void SWFOutputDev::updateLineCap(GfxState *state)
1179 {
1180     int c = state->getLineCap();
1181 }
1182
1183 void SWFOutputDev::updateLineJoin(GfxState *state)
1184 {
1185     int j = state->getLineJoin();
1186 }
1187
1188 void SWFOutputDev::updateFillColor(GfxState *state) 
1189 {
1190     GfxRGB rgb;
1191     double opaq = state->getFillOpacity();
1192     state->getFillRGB(&rgb);
1193
1194     swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), 
1195                                     (char)(rgb.b*255), (char)(opaq*255));
1196 }
1197
1198 void SWFOutputDev::updateStrokeColor(GfxState *state) 
1199 {
1200     GfxRGB rgb;
1201     double opaq = state->getStrokeOpacity();
1202     state->getStrokeRGB(&rgb);
1203
1204     swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), 
1205                                       (char)(rgb.b*255), (char)(opaq*255));
1206 }
1207
1208 void FoFiWrite(void *stream, char *data, int len)
1209 {
1210    fwrite(data, len, 1, (FILE*)stream);
1211 }
1212
1213 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1214 {
1215     char*tmpFileName = NULL;
1216     FILE *f;
1217     int c;
1218     char *fontBuf;
1219     int fontLen;
1220     Ref embRef;
1221     Object refObj, strObj;
1222     char namebuf[512];
1223     tmpFileName = mktmpname(namebuf);
1224     int ret;
1225
1226     ret = font->getEmbeddedFontID(&embRef);
1227     if(!ret) {
1228         msg("<verbose> Didn't get embedded font id");
1229         /* not embedded- the caller should now search the font
1230            directories for this font */
1231         return 0;
1232     }
1233
1234     f = fopen(tmpFileName, "wb");
1235     if (!f) {
1236       msg("<error> Couldn't create temporary Type 1 font file");
1237         return 0;
1238     }
1239
1240     /*if(font->isCIDFont()) {
1241         GfxCIDFont* cidFont = (GfxCIDFont *)font;
1242         GString c = cidFont->getCollection();
1243         msg("<notice> Collection: %s", c.getCString());
1244     }*/
1245
1246     if (font->getType() == fontType1C ||
1247         font->getType() == fontCIDType0C) {
1248       if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1249         fclose(f);
1250         msg("<error> Couldn't read embedded font file");
1251         return 0;
1252       }
1253 #ifdef XPDF_101
1254       Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1255       if(!cvt) return 0;
1256       cvt->convertToType1(f);
1257 #else
1258       FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1259       if(!cvt) return 0;
1260       cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1261 #endif
1262       //cvt->convertToCIDType0("test", f);
1263       //cvt->convertToType0("test", f);
1264       delete cvt;
1265       gfree(fontBuf);
1266     } else if(font->getType() == fontTrueType) {
1267       msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1268       if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1269         fclose(f);
1270         msg("<error> Couldn't read embedded font file");
1271         return 0;
1272       }
1273 #ifdef XPDF_101
1274       TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1275       cvt->writeTTF(f);
1276 #else
1277       FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1278       cvt->writeTTF(FoFiWrite, f);
1279 #endif
1280       delete cvt;
1281       gfree(fontBuf);
1282     } else {
1283       font->getEmbeddedFontID(&embRef);
1284       refObj.initRef(embRef.num, embRef.gen);
1285       refObj.fetch(ref, &strObj);
1286       refObj.free();
1287       strObj.streamReset();
1288       int f4[4];
1289       char f4c[4];
1290       int t;
1291       for(t=0;t<4;t++) {
1292           f4[t] = strObj.streamGetChar();
1293           f4c[t] = (char)f4[t];
1294           if(f4[t] == EOF)
1295               break;
1296       }
1297       if(t==4) {
1298           if(!strncmp(f4c, "true", 4)) {
1299               /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1300                  Change this on the fly */
1301               f4[0] = f4[2] = f4[3] = 0;
1302               f4[1] = 1;
1303           }
1304           fputc(f4[0], f);
1305           fputc(f4[1], f);
1306           fputc(f4[2], f);
1307           fputc(f4[3], f);
1308
1309           while ((c = strObj.streamGetChar()) != EOF) {
1310             fputc(c, f);
1311           }
1312       }
1313       strObj.streamClose();
1314       strObj.free();
1315     }
1316     fclose(f);
1317
1318     return strdup(tmpFileName);
1319 }
1320     
1321 char* searchForSuitableFont(GfxFont*gfxFont)
1322 {
1323     char*name = getFontName(gfxFont);
1324     char*fontname = 0;
1325     char*filename = 0;
1326
1327     if(!config_use_fontconfig)
1328         return 0;
1329     
1330 #ifdef HAVE_FONTCONFIG
1331     FcPattern *pattern, *match;
1332     FcResult result;
1333     FcChar8 *v;
1334
1335     static int fcinitcalled = false; 
1336         
1337     msg("<debug> searchForSuitableFont(%s)", name);
1338     
1339     // call init ony once
1340     if (!fcinitcalled) {
1341         msg("<debug> Initializing FontConfig...");
1342         fcinitcalled = true;
1343         if(FcInit()) {
1344             msg("<debug> FontConfig Initialization failed. Disabling.");
1345             config_use_fontconfig = 0;
1346             return 0;
1347         }
1348         msg("<debug> ...initialized FontConfig");
1349     }
1350    
1351     msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1352     pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1353     if (gfxFont->isItalic()) // check for italic
1354         msg("<debug> FontConfig: Adding Italic Slant");
1355         FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1356     if (gfxFont->isBold()) // check for bold
1357         msg("<debug> FontConfig: Adding Bold Weight");
1358         FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1359
1360     msg("<debug> FontConfig: Try to match...");
1361     // configure and match using the original font name 
1362     FcConfigSubstitute(0, pattern, FcMatchPattern); 
1363     FcDefaultSubstitute(pattern);
1364     match = FcFontMatch(0, pattern, &result);
1365     
1366     if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1367         msg("<debug> FontConfig: family=%s", (char*)v);
1368         // if we get an exact match
1369         if (strcmp((char *)v, name) == 0) {
1370             if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1371                 filename = strdup((char*)v);
1372                 char *nfn = strrchr(filename, '/');
1373                 if(nfn) fontname = strdup(nfn+1);
1374                 else    fontname = filename;
1375             }
1376             msg("<debug> FontConfig: Returning \"%s\"", fontname);
1377         } else {
1378             // initialize patterns
1379             FcPatternDestroy(pattern);
1380             FcPatternDestroy(match);
1381
1382             // now match against serif etc.
1383             if (gfxFont->isSerif()) {
1384                 msg("<debug> FontConfig: Create Serif Family Pattern");
1385                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1386             } else if (gfxFont->isFixedWidth()) {
1387                 msg("<debug> FontConfig: Create Monospace Family Pattern");
1388                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1389             } else {
1390                 msg("<debug> FontConfig: Create Sans Family Pattern");
1391                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1392             }
1393
1394             // check for italic
1395             if (gfxFont->isItalic()) {
1396                 msg("<debug> FontConfig: Adding Italic Slant");
1397                 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1398             }
1399             // check for bold
1400             if (gfxFont->isBold()) {
1401                 msg("<debug> FontConfig: Adding Bold Weight");
1402                 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1403             }
1404
1405             msg("<debug> FontConfig: Try to match... (2)");
1406             // configure and match using serif etc
1407             FcConfigSubstitute (0, pattern, FcMatchPattern);
1408             FcDefaultSubstitute (pattern);
1409             match = FcFontMatch (0, pattern, &result);
1410             
1411             if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1412                 filename = strdup((char*)v);
1413                 char *nfn = strrchr(filename, '/');
1414                 if(nfn) fontname = strdup(nfn+1);
1415                 else    fontname = filename;
1416             }
1417             msg("<debug> FontConfig: Returning \"%s\"", fontname);
1418         }        
1419     }
1420
1421     //printf("FONTCONFIG: pattern");
1422     //FcPatternPrint(pattern);
1423     //printf("FONTCONFIG: match");
1424     //FcPatternPrint(match);
1425  
1426     FcPatternDestroy(pattern);
1427     FcPatternDestroy(match);
1428
1429     pdfswf_addfont(filename);
1430     return fontname;
1431 #else
1432     return 0;
1433 #endif
1434 }
1435
1436 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1437 {
1438     char*fontname = 0, *filename = 0;
1439     msg("<notice> subsituteFont(%s)", oldname);
1440
1441     if(!(fontname = searchForSuitableFont(gfxFont))) {
1442         fontname = "Times-Roman";
1443     }
1444     filename = searchFont(fontname);
1445     if(!filename) {
1446         msg("<error> Couldn't find font %s- did you install the default fonts?");
1447         return 0;
1448     }
1449
1450     if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1451         msg("<fatal> Too many fonts in file.");
1452         exit(1);
1453     }
1454     if(oldname) {
1455         substitutesource[substitutepos] = oldname;
1456         substitutetarget[substitutepos] = fontname;
1457         msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1458         substitutepos ++;
1459     }
1460     return strdup(filename);
1461 }
1462
1463 void unlinkfont(char* filename)
1464 {
1465     int l;
1466     if(!filename)
1467         return;
1468     l=strlen(filename);
1469     unlink(filename);
1470     if(!strncmp(&filename[l-4],".afm",4)) {
1471         memcpy(&filename[l-4],".pfb",4);
1472         unlink(filename);
1473         memcpy(&filename[l-4],".pfa",4);
1474         unlink(filename);
1475         memcpy(&filename[l-4],".afm",4);
1476         return;
1477     } else 
1478     if(!strncmp(&filename[l-4],".pfa",4)) {
1479         memcpy(&filename[l-4],".afm",4);
1480         unlink(filename);
1481         memcpy(&filename[l-4],".pfa",4);
1482         return;
1483     } else 
1484     if(!strncmp(&filename[l-4],".pfb",4)) {
1485         memcpy(&filename[l-4],".afm",4);
1486         unlink(filename);
1487         memcpy(&filename[l-4],".pfb",4);
1488         return;
1489     }
1490 }
1491
1492 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref) 
1493 {
1494     this->doc = doc;
1495     this->xref = xref;
1496 }
1497
1498
1499 void SWFOutputDev::updateFont(GfxState *state) 
1500 {
1501     GfxFont*gfxFont = state->getFont();
1502       
1503     if (!gfxFont) {
1504         return;
1505     }  
1506     char * fontid = getFontID(gfxFont);
1507     
1508     int t;
1509     /* first, look if we substituted this font before-
1510        this way, we don't initialize the T1 Fonts
1511        too often */
1512     for(t=0;t<substitutepos;t++) {
1513         if(!strcmp(fontid, substitutesource[t])) {
1514             fontid = substitutetarget[t];
1515             break;
1516         }
1517     }
1518
1519     /* second, see if swfoutput already has this font
1520        cached- if so, we are done */
1521     if(swfoutput_queryfont(&output, fontid))
1522     {
1523         swfoutput_setfont(&output, fontid, 0);
1524         
1525         msg("<debug> updateFont(%s) [cached]", fontid);
1526         return;
1527     }
1528
1529     // look for Type 3 font
1530     if (gfxFont->getType() == fontType3) {
1531         if(!type3Warning) {
1532             type3Warning = gTrue;
1533             showFontError(gfxFont, 2);
1534         }
1535         return;
1536     }
1537
1538     /* now either load the font, or find a substitution */
1539
1540     Ref embRef;
1541     GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1542
1543     char*fileName = 0;
1544     int del = 0;
1545     if(embedded &&
1546        (gfxFont->getType() == fontType1 ||
1547         gfxFont->getType() == fontType1C ||
1548        (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
1549         gfxFont->getType() == fontTrueType ||
1550         gfxFont->getType() == fontCIDType2
1551        ))
1552     {
1553       fileName = writeEmbeddedFontToFile(xref, gfxFont);
1554       if(!fileName) showFontError(gfxFont,0);
1555       else del = 1;
1556     } else {
1557       char * fontname = getFontName(gfxFont);
1558       fileName = searchFont(fontname);
1559       if(!fileName) showFontError(gfxFont,0);
1560     }
1561     if(!fileName) {
1562         char * fontname = getFontName(gfxFont);
1563         msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
1564         msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
1565         fileName = substituteFont(gfxFont, fontid);
1566         if(fontid) { fontid = substitutetarget[substitutepos-1]; /*ugly hack*/};
1567         msg("<notice> Font is now %s (%s)", fontid, fileName);
1568     }
1569
1570     if(!fileName) {
1571         msg("<error> Couldn't set font %s\n", fontid);
1572         return;
1573     }
1574         
1575     msg("<verbose> updateFont(%s) -> %s", fontid, fileName);
1576     dumpFontInfo("<verbose>", gfxFont);
1577
1578     swfoutput_setfont(&output, fontid, fileName);
1579    
1580     if(fileName && del)
1581         unlinkfont(fileName);
1582     if(fileName)
1583         free(fileName);
1584 }
1585
1586 #define SQR(x) ((x)*(x))
1587
1588 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1589 {
1590     if((newwidth<2 || newheight<2) ||
1591        (width<=newwidth || height<=newheight))
1592         return 0;
1593     unsigned char*newdata;
1594     int x,y;
1595     newdata= (unsigned char*)malloc(newwidth*newheight);
1596     int t;
1597     double fx = (double)(width)/newwidth;
1598     double fy = (double)(height)/newheight;
1599     double px = 0;
1600     int blocksize = (int)(8192/(fx*fy));
1601     int r = 8192*256/palettesize;
1602     for(x=0;x<newwidth;x++) {
1603         double ex = px + fx;
1604         int fromx = (int)px;
1605         int tox = (int)ex;
1606         int xweight1 = (int)(((fromx+1)-px)*256);
1607         int xweight2 = (int)((ex-tox)*256);
1608         double py =0;
1609         for(y=0;y<newheight;y++) {
1610             double ey = py + fy;
1611             int fromy = (int)py;
1612             int toy = (int)ey;
1613             int yweight1 = (int)(((fromy+1)-py)*256);
1614             int yweight2 = (int)((ey-toy)*256);
1615             int a = 0;
1616             int xx,yy;
1617             for(xx=fromx;xx<=tox;xx++)
1618             for(yy=fromy;yy<=toy;yy++) {
1619                 int b = 1-data[width*yy+xx];
1620                 int weight=256;
1621                 if(xx==fromx) weight = (weight*xweight1)/256;
1622                 if(xx==tox) weight = (weight*xweight2)/256;
1623                 if(yy==fromy) weight = (weight*yweight1)/256;
1624                 if(yy==toy) weight = (weight*yweight2)/256;
1625                 a+=b*weight;
1626             }
1627             //if(a) a=(palettesize-1)*r/blocksize;
1628             newdata[y*newwidth+x] = (a*blocksize)/r;
1629             py = ey;
1630         }
1631         px = ex;
1632     }
1633     return newdata;
1634 }
1635
1636 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
1637                                    int width, int height, GfxImageColorMap*colorMap, GBool invert,
1638                                    GBool inlineImg, int mask)
1639 {
1640   FILE *fi;
1641   int c;
1642   char fileName[128];
1643   double x1,y1,x2,y2,x3,y3,x4,y4;
1644   ImageStream *imgStr;
1645   Guchar pixBuf[4];
1646   GfxRGB rgb;
1647   int ncomps = 1;
1648   int bits = 1;
1649                                  
1650   if(colorMap) {
1651     ncomps = colorMap->getNumPixelComps();
1652     bits = colorMap->getBits();
1653   }
1654   imgStr = new ImageStream(str, width, ncomps,bits);
1655   imgStr->reset();
1656
1657   if(!width || !height || (height<=1 && width<=1))
1658   {
1659       msg("<verbose> Ignoring %d by %d image", width, height);
1660       unsigned char buf[8];
1661       int x,y;
1662       for (y = 0; y < height; ++y)
1663       for (x = 0; x < width; ++x) {
1664           imgStr->getPixel(buf);
1665       }
1666       delete imgStr;
1667       return;
1668   }
1669   
1670   state->transform(0, 1, &x1, &y1);
1671   state->transform(0, 0, &x2, &y2);
1672   state->transform(1, 0, &x3, &y3);
1673   state->transform(1, 1, &x4, &y4);
1674
1675   if(!pbminfo && !(str->getKind()==strDCT)) {
1676       if(!type3active) {
1677           msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
1678           pbminfo = 1;
1679       }
1680       if(mask)
1681       msg("<verbose> drawing %d by %d masked picture\n", width, height);
1682   }
1683   if(!jpeginfo && (str->getKind()==strDCT)) {
1684       msg("<notice> file contains jpeg pictures");
1685       jpeginfo = 1;
1686   }
1687
1688   if(mask) {
1689       int i,j;
1690       unsigned char buf[8];
1691       int x,y;
1692       unsigned char*pic = new unsigned char[width*height];
1693       RGBA pal[256];
1694       GfxRGB rgb;
1695       state->getFillRGB(&rgb);
1696
1697       memset(pal,255,sizeof(pal));
1698       pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
1699       pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
1700       pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
1701       pal[0].a = 255;              pal[1].a = 0;
1702
1703       int numpalette = 2;
1704       int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
1705       int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
1706       for (y = 0; y < height; ++y)
1707       for (x = 0; x < width; ++x)
1708       {
1709             imgStr->getPixel(buf);
1710             if(invert) 
1711                 buf[0]=1-buf[0];
1712             pic[width*y+x] = buf[0];
1713       }
1714       
1715       /* the size of the drawn image is added to the identifier
1716          as the same image may require different bitmaps if displayed
1717          at different sizes (due to antialiasing): */
1718       int t,found = -1;
1719       if(type3active) {
1720           unsigned char*pic2 = 0;
1721           numpalette = 16;
1722           
1723           pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
1724
1725           if(!pic2) {
1726             delete pic;
1727             delete imgStr;
1728             return;
1729           }
1730
1731           width = realwidth;
1732           height = realheight;
1733           free(pic);
1734           pic = pic2;
1735           
1736           /* make a black/white palette */
1737           GfxRGB rgb2;
1738           rgb2.r = 1 - rgb.r;
1739           rgb2.g = 1 - rgb.g;
1740           rgb2.b = 1 - rgb.b;
1741           float r = 255/(numpalette-1);
1742           int t;
1743           for(t=0;t<numpalette;t++) {
1744               pal[t].r = (U8)(255*rgb.r);
1745               pal[t].g = (U8)(255*rgb.g);
1746               pal[t].b = (U8)(255*rgb.b);
1747               pal[t].a = (U8)(t*r);
1748           }
1749       }
1750
1751       RGBA*pic2 = new RGBA[width*height];
1752       for (y = 0; y < height; ++y) {
1753         for (x = 0; x < width; ++x) {
1754           pic2[width*y+x] = pal[pic[y*width+x]];
1755         }
1756       }
1757       swfoutput_drawimagelossless(&output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1758       free(pic2);
1759       free(pic);
1760       delete imgStr;
1761       return;
1762   } 
1763
1764   int x,y;
1765   
1766   if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
1767       RGBA*pic=new RGBA[width*height];
1768       for (y = 0; y < height; ++y) {
1769         for (x = 0; x < width; ++x) {
1770           imgStr->getPixel(pixBuf);
1771           colorMap->getRGB(pixBuf, &rgb);
1772           pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
1773           pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
1774           pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
1775           pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
1776         }
1777       }
1778       if(str->getKind()==strDCT)
1779           swfoutput_drawimagejpeg(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1780       else
1781           swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1782       delete pic;
1783       delete imgStr;
1784       return;
1785   } else {
1786       RGBA*pic=new RGBA[width*height];
1787       RGBA pal[256];
1788       int t;
1789       for(t=0;t<256;t++) {
1790           pixBuf[0] = t;
1791           colorMap->getRGB(pixBuf, &rgb);
1792           pal[t].r = (U8)(rgb.r * 255 + 0.5);
1793           pal[t].g = (U8)(rgb.g * 255 + 0.5);
1794           pal[t].b = (U8)(rgb.b * 255 + 0.5);
1795           pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
1796       }
1797       for (y = 0; y < height; ++y) {
1798         for (x = 0; x < width; ++x) {
1799           imgStr->getPixel(pixBuf);
1800           pic[width*y+x] = pal[pixBuf[0]];
1801         }
1802       }
1803       swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1804
1805       delete pic;
1806       delete imgStr;
1807       return;
1808   }
1809 }
1810
1811 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
1812                                    int width, int height, GBool invert,
1813                                    GBool inlineImg) 
1814 {
1815   msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
1816   drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1);
1817 }
1818
1819 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
1820                          int width, int height, GfxImageColorMap *colorMap,
1821                          int *maskColors, GBool inlineImg)
1822 {
1823   msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height, 
1824           colorMap?"colorMap":"no colorMap", 
1825           maskColors?"maskColors":"no maskColors",
1826           inlineImg);
1827   if(colorMap)
1828       msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
1829               colorMap->getBits(),colorMap->getColorSpace()->getMode());
1830   drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0);
1831 }
1832
1833 SWFOutputDev*output = 0; 
1834
1835 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
1836   Object obj;
1837   GString *s1, *s2;
1838   int i;
1839
1840   if (infoDict->lookup(key, &obj)->isString()) {
1841     s1 = obj.getString();
1842     if ((s1->getChar(0) & 0xff) == 0xfe &&
1843         (s1->getChar(1) & 0xff) == 0xff) {
1844       s2 = new GString();
1845       for (i = 2; i < obj.getString()->getLength(); i += 2) {
1846         if (s1->getChar(i) == '\0') {
1847           s2->append(s1->getChar(i+1));
1848         } else {
1849           delete s2;
1850           s2 = new GString("<unicode>");
1851           break;
1852         }
1853       }
1854       printf(fmt, s2->getCString());
1855       delete s2;
1856     } else {
1857       printf(fmt, s1->getCString());
1858     }
1859   }
1860   obj.free();
1861 }
1862
1863 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
1864   Object obj;
1865   char *s;
1866
1867   if (infoDict->lookup(key, &obj)->isString()) {
1868     s = obj.getString()->getCString();
1869     if (s[0] == 'D' && s[1] == ':') {
1870       s += 2;
1871     }
1872     printf(fmt, s);
1873   }
1874   obj.free();
1875 }
1876
1877 int jpeg_dpi = 0;
1878 int ppm_dpi = 0;
1879
1880 void pdfswf_setparameter(char*name, char*value)
1881 {
1882     msg("<verbose> setting parameter %s to \"%s\"", name, value);
1883     if(!strcmp(name, "caplinewidth")) {
1884         caplinewidth = atof(value);
1885     } else if(!strcmp(name, "zoom")) {
1886         char buf[80];
1887         zoom = atoi(value);
1888         sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
1889         swfoutput_setparameter("jpegsubpixels", buf);
1890         sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
1891         swfoutput_setparameter("ppmsubpixels", buf);
1892     } else if(!strcmp(name, "jpegdpi")) {
1893         char buf[80];
1894         jpeg_dpi = atoi(value);
1895         sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
1896         swfoutput_setparameter("jpegsubpixels", buf);
1897     } else if(!strcmp(name, "ppmdpi")) {
1898         char buf[80];
1899         ppm_dpi = atoi(value);
1900         sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
1901         swfoutput_setparameter("ppmsubpixels", buf);
1902     } else if(!strcmp(name, "forceType0Fonts")) {
1903         forceType0Fonts = atoi(value);
1904     } else if(!strcmp(name, "fontdir")) {
1905         pdfswf_addfontdir(value);
1906     } else if(!strcmp(name, "languagedir")) {
1907         pdfswf_addlanguagedir(value);
1908     } else if(!strcmp(name, "fontconfig")) {
1909         config_use_fontconfig = atoi(value);
1910     } else {
1911         swfoutput_setparameter(name, value);
1912     }
1913 }
1914 void pdfswf_addfont(char*filename)
1915 {
1916     fontfile_t f;
1917     memset(&f, 0, sizeof(fontfile_t));
1918     f.filename = filename;
1919     if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
1920         fonts[fontnum++] = f;
1921     } else {
1922         msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
1923     }
1924 }
1925
1926 static char* dirseparator()
1927 {
1928 #ifdef WIN32
1929     return "\\";
1930 #else
1931     return "/";
1932 #endif
1933 }
1934
1935 void pdfswf_addlanguagedir(char*dir)
1936 {
1937     if(!globalParams)
1938         globalParams = new GlobalParams("");
1939     
1940     msg("<notice> Adding %s to language pack directories", dir);
1941
1942     int l;
1943     FILE*fi = 0;
1944     char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
1945     strcpy(config_file, dir);
1946     strcat(config_file, dirseparator());
1947     strcat(config_file, "add-to-xpdfrc");
1948
1949     fi = fopen(config_file, "rb");
1950     if(!fi) {
1951         msg("<error> Could not open %s", config_file);
1952         return;
1953     }
1954     globalParams->parseFile(new GString(config_file), fi);
1955     fclose(fi);
1956 }
1957
1958 void pdfswf_addfontdir(char*dirname)
1959 {
1960 #ifdef HAVE_DIRENT_H
1961     msg("<notice> Adding %s to font directories", dirname);
1962     DIR*dir = opendir(dirname);
1963     if(!dir) {
1964         msg("<warning> Couldn't open directory %s\n", dirname);
1965         return;
1966     }
1967     struct dirent*ent;
1968     while(1) {
1969         ent = readdir (dir);
1970         if (!ent) 
1971             break;
1972         int l;
1973         char*name = ent->d_name;
1974         char type = 0;
1975         if(!name) continue;
1976         l=strlen(name);
1977         if(l<4)
1978             continue;
1979         if(!strncasecmp(&name[l-4], ".pfa", 4)) 
1980             type=1;
1981         if(!strncasecmp(&name[l-4], ".pfb", 4)) 
1982             type=3;
1983         if(!strncasecmp(&name[l-4], ".ttf", 4)) 
1984             type=2;
1985         if(type)
1986         {
1987             char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
1988             strcpy(fontname, dirname);
1989             strcat(fontname, dirseparator());
1990             strcat(fontname, name);
1991             msg("<verbose> Adding %s to fonts", fontname);
1992             pdfswf_addfont(fontname);
1993         }
1994     }
1995     closedir(dir);
1996 #else
1997     msg("<warning> No dirent.h- unable to add font dir %s", dir);
1998 #endif
1999 }
2000
2001
2002 typedef struct _pdf_doc_internal
2003 {
2004     int protect;
2005     PDFDoc*doc;
2006 } pdf_doc_internal_t;
2007 typedef struct _pdf_page_internal
2008 {
2009 } pdf_page_internal_t;
2010 typedef struct _swf_output_internal
2011 {
2012     SWFOutputDev*outputDev;
2013 } swf_output_internal_t;
2014
2015 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2016 {
2017     pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2018     memset(pdf_doc, 0, sizeof(pdf_doc_t));
2019     pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2020     memset(i, 0, sizeof(pdf_doc_internal_t));
2021     pdf_doc->internal = i;
2022     
2023     GString *fileName = new GString(filename);
2024     GString *userPW;
2025     Object info;
2026
2027     // read config file
2028     if(!globalParams)
2029         globalParams = new GlobalParams("");
2030
2031     // open PDF file
2032     if (userPassword && userPassword[0]) {
2033       userPW = new GString(userPassword);
2034     } else {
2035       userPW = NULL;
2036     }
2037     i->doc = new PDFDoc(fileName, userPW);
2038     if (userPW) {
2039       delete userPW;
2040     }
2041     if (!i->doc->isOk()) {
2042         return 0;
2043     }
2044
2045     // print doc info
2046     i->doc->getDocInfo(&info);
2047     if (info.isDict() &&
2048       (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2049       printInfoString(info.getDict(), "Title",        "Title:        %s\n");
2050       printInfoString(info.getDict(), "Subject",      "Subject:      %s\n");
2051       printInfoString(info.getDict(), "Keywords",     "Keywords:     %s\n");
2052       printInfoString(info.getDict(), "Author",       "Author:       %s\n");
2053       printInfoString(info.getDict(), "Creator",      "Creator:      %s\n");
2054       printInfoString(info.getDict(), "Producer",     "Producer:     %s\n");
2055       printInfoDate(info.getDict(),   "CreationDate", "CreationDate: %s\n");
2056       printInfoDate(info.getDict(),   "ModDate",      "ModDate:      %s\n");
2057       printf("Pages:        %d\n", i->doc->getNumPages());
2058       printf("Linearized:   %s\n", i->doc->isLinearized() ? "yes" : "no");
2059       printf("Encrypted:    ");
2060       if (i->doc->isEncrypted()) {
2061         printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2062                i->doc->okToPrint() ? "yes" : "no",
2063                i->doc->okToCopy() ? "yes" : "no",
2064                i->doc->okToChange() ? "yes" : "no",
2065                i->doc->okToAddNotes() ? "yes" : "no");
2066       } else {
2067         printf("no\n");
2068       }
2069     }
2070     info.free();
2071                    
2072     pdf_doc->num_pages = i->doc->getNumPages();
2073     i->protect = 0;
2074     if (i->doc->isEncrypted()) {
2075           if(!i->doc->okToCopy()) {
2076               printf("PDF disallows copying.\n");
2077               return 0;
2078           }
2079           if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2080               i->protect = 1;
2081     }
2082    
2083     return pdf_doc;
2084 }
2085
2086 void pdfswf_preparepage(int page)
2087 {
2088     /*FIXME*/
2089     if(!pages) {
2090         pages = (int*)malloc(1024*sizeof(int));
2091         pagebuflen = 1024;
2092     } else {
2093         if(pagepos == pagebuflen)
2094         {
2095             pagebuflen+=1024;
2096             pages = (int*)realloc(pages, pagebuflen);
2097         }
2098     }
2099     pages[pagepos++] = page;
2100 }
2101
2102 class MemCheck
2103 {
2104     public: ~MemCheck()
2105     {
2106         delete globalParams;globalParams=0;
2107         Object::memCheck(stderr);
2108         gMemReport(stderr);
2109     }
2110 } myMemCheck;
2111
2112 void pdf_destroy(pdf_doc_t*pdf_doc)
2113 {
2114     pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2115
2116     msg("<debug> pdfswf.cc: pdfswf_close()");
2117     delete i->doc; i->doc=0;
2118     
2119     free(pages); pages = 0; //FIXME
2120
2121     free(pdf_doc->internal);pdf_doc->internal=0;
2122     free(pdf_doc);pdf_doc=0;
2123 }
2124
2125 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2126 {
2127     pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2128
2129     if(page < 1 || page > pdf_doc->num_pages)
2130         return 0;
2131     
2132     pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2133     pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2134     memset(pi, 0, sizeof(pdf_page_internal_t));
2135     pdf_page->internal = pi;
2136
2137     pdf_page->parent = pdf_doc;
2138     pdf_page->nr = page;
2139     return pdf_page;
2140 }
2141
2142 void pdf_page_destroy(pdf_page_t*pdf_page)
2143 {
2144     pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2145     free(pdf_page->internal);pdf_page->internal = 0;
2146     free(pdf_page);pdf_page=0;
2147 }
2148
2149 swf_output_t* swf_output_init() 
2150 {
2151     swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2152     memset(swf_output, 0, sizeof(swf_output_t));
2153     swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2154     memset(i, 0, sizeof(swf_output_internal_t));
2155     swf_output->internal = i;
2156
2157     i->outputDev = new SWFOutputDev();
2158     return swf_output;
2159 }
2160
2161 void swf_output_setparameter(swf_output_t*swf_output, char*name, char*value)
2162 {
2163     /* FIXME */
2164     pdfswf_setparameter(name, value);
2165 }
2166
2167 void swf_output_pagefeed(swf_output_t*swf)
2168 {
2169     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2170     i->outputDev->pagefeed();
2171     i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2172 }
2173
2174 int swf_output_save(swf_output_t*swf, char*filename)
2175 {
2176     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2177     int ret = i->outputDev->save(filename);
2178     i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2179     return ret;
2180 }
2181
2182 void* swf_output_get(swf_output_t*swf)
2183 {
2184     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2185     void* ret = i->outputDev->getSWF();
2186     i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2187     return ret;
2188 }
2189
2190 void swf_output_destroy(swf_output_t*output)
2191 {
2192     swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2193     delete i->outputDev; i->outputDev=0;
2194     free(output->internal);output->internal=0;
2195     free(output);
2196 }
2197
2198 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2199 {
2200     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2201     swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2202
2203     if(pi->protect) {
2204         swfoutput_setparameter("protect", "1");
2205     }
2206     si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2207 #ifdef XPDF_101
2208     pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2209 #else
2210     pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2211 #endif
2212     si->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2213 }
2214
2215 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2216 {
2217     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2218     swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2219
2220     si->outputDev->setMove(x,y);
2221     if((x1|y1|x2|y2)==0) x2++;
2222     si->outputDev->setClip(x1,y1,x2,y2);
2223
2224     pdf_page_render2(page, output);
2225 }
2226 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2227 {
2228     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2229     swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2230     
2231     si->outputDev->setMove(0,0);
2232     si->outputDev->setClip(0,0,0,0);
2233     
2234     pdf_page_render2(page, output);
2235 }
2236
2237
2238 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2239 {
2240     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2241     pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2242     pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2243     memset(info, 0, sizeof(pdf_page_info_t));
2244
2245     InfoOutputDev*output = new InfoOutputDev;
2246     
2247 #ifdef XPDF_101
2248     pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2249 #else
2250     pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2251 #endif
2252
2253     info->xMin = output->x1;
2254     info->yMin = output->y1;
2255     info->xMax = output->x2;
2256     info->yMax = output->y2;
2257     info->number_of_images = output->num_images;
2258     info->number_of_links = output->num_links;
2259     info->number_of_fonts = output->num_fonts;
2260
2261     delete output;
2262
2263     return info;
2264 }
2265
2266 void pdf_page_info_destroy(pdf_page_info_t*info)
2267 {
2268     free(info);
2269 }