reapplied change 1.61, due to a CVS conflict.
[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 //xpdf header files
27 #include "config.h"
28 #include "gfile.h"
29 #include "GString.h"
30 #include "gmem.h"
31 #include "Object.h"
32 #include "Stream.h"
33 #include "Array.h"
34 #include "Dict.h"
35 #include "XRef.h"
36 #include "Catalog.h"
37 #include "Page.h"
38 #include "PDFDoc.h"
39 #include "Error.h"
40 #include "OutputDev.h"
41 #include "GfxState.h"
42 #include "GfxFont.h"
43 #include "CharCodeToUnicode.h"
44 #include "NameToUnicodeTable.h"
45 #include "FontFile.h"
46 #include "GlobalParams.h"
47 //swftools header files
48 #include "swfoutput.h"
49 #include "../lib/log.h"
50
51 #include "ttf2pt1.h"
52 #include <math.h>
53
54 static PDFDoc*doc = 0;
55 static char* swffilename = 0;
56 int numpages;
57 int currentpage;
58
59 // swf <-> pdf pages
60 int*pages = 0;
61 int pagebuflen = 0;
62 int pagepos = 0;
63
64 double caplinewidth = 3.0;
65
66 static void printInfoString(Dict *infoDict, char *key, char *fmt);
67 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
68
69 double fontsizes[] = 
70 {
71  0.833,0.833,0.889,0.889,
72  0.788,0.722,0.833,0.778,
73  0.600,0.600,0.600,0.600,
74  0.576,0.576,0.576,0.576,
75  0.733 //?
76 };
77 char*fontnames[]={
78 "Helvetica",             
79 "Helvetica-Bold",        
80 "Helvetica-BoldOblique", 
81 "Helvetica-Oblique",     
82 "Times-Roman",           
83 "Times-Bold",            
84 "Times-BoldItalic",      
85 "Times-Italic",          
86 "Courier",               
87 "Courier-Bold",          
88 "Courier-BoldOblique",   
89 "Courier-Oblique",       
90 "Symbol",                
91 "Symbol",                
92 "Symbol",                
93 "Symbol",
94 "ZapfDingBats"
95 };
96
97 struct mapping {
98     char*pdffont;
99     char*filename;
100     int id;
101 } pdf2t1map[] ={
102 {"Times-Roman",           "n021003l.pfb"},
103 {"Times-Italic",          "n021023l.pfb"},
104 {"Times-Bold",            "n021004l.pfb"},
105 {"Times-BoldItalic",      "n021024l.pfb"},
106 {"Helvetica",             "n019003l.pfb"},
107 {"Helvetica-Oblique",     "n019023l.pfb"},
108 {"Helvetica-Bold",        "n019004l.pfb"},
109 {"Helvetica-BoldOblique", "n019024l.pfb"},
110 {"Courier",               "n022003l.pfb"},
111 {"Courier-Oblique",       "n022023l.pfb"},
112 {"Courier-Bold",          "n022004l.pfb"},
113 {"Courier-BoldOblique",   "n022024l.pfb"},
114 {"Symbol",                "s050000l.pfb"},
115 {"ZapfDingbats",          "d050000l.pfb"}};
116
117 class GfxState;
118 class GfxImageColorMap;
119
120 class SWFOutputDev:  public OutputDev {
121   struct swfoutput output;
122   int outputstarted;
123 public:
124
125   // Constructor.
126   SWFOutputDev();
127
128   // Destructor.
129   virtual ~SWFOutputDev() ;
130
131   //----- get info about output device
132
133   // Does this device use upside-down coordinates?
134   // (Upside-down means (0,0) is the top left corner of the page.)
135   virtual GBool upsideDown();
136
137   // Does this device use drawChar() or drawString()?
138   virtual GBool useDrawChar();
139   
140   virtual GBool interpretType3Chars() {return gTrue;}
141
142   //----- initialization and control
143
144   void startDoc(XRef *xref);
145
146   // Start a page.
147   virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
148
149   //----- link borders
150   virtual void drawLink(Link *link, Catalog *catalog) ;
151
152   //----- save/restore graphics state
153   virtual void saveState(GfxState *state) ;
154   virtual void restoreState(GfxState *state) ;
155
156   //----- update graphics state
157
158   virtual void updateFont(GfxState *state);
159   virtual void updateFillColor(GfxState *state);
160   virtual void updateStrokeColor(GfxState *state);
161   virtual void updateLineWidth(GfxState *state);
162   virtual void updateLineJoin(GfxState *state);
163   virtual void updateLineCap(GfxState *state);
164   
165   virtual void updateAll(GfxState *state) 
166   {
167       updateFont(state);
168       updateFillColor(state);
169       updateStrokeColor(state);
170       updateLineWidth(state);
171       updateLineJoin(state);
172       updateLineCap(state);
173   };
174
175   //----- path painting
176   virtual void stroke(GfxState *state) ;
177   virtual void fill(GfxState *state) ;
178   virtual void eoFill(GfxState *state) ;
179
180   //----- path clipping
181   virtual void clip(GfxState *state) ;
182   virtual void eoClip(GfxState *state) ;
183
184   //----- text drawing
185   virtual void beginString(GfxState *state, GString *s) ;
186   virtual void endString(GfxState *state) ;
187   virtual void drawChar(GfxState *state, double x, double y,
188                         double dx, double dy,
189                         double originX, double originY,
190                         CharCode code, Unicode *u, int uLen);
191
192   //----- image drawing
193   virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
194                              int width, int height, GBool invert,
195                              GBool inlineImg);
196   virtual void drawImage(GfxState *state, Object *ref, Stream *str,
197                          int width, int height, GfxImageColorMap *colorMap,
198                          int *maskColors, GBool inlineImg);
199   
200   virtual GBool beginType3Char(GfxState *state,
201                                CharCode code, Unicode *u, int uLen);
202   virtual void endType3Char(GfxState *state);
203
204   private:
205   void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
206                                    int width, int height, GfxImageColorMap*colorMap, GBool invert,
207                                    GBool inlineImg, int mask);
208   int clipping[64];
209   int clippos;
210
211   XRef*xref;
212
213   int searchT1Font(char*name);
214   char* substituteFont(GfxFont*gfxFont, char*oldname);
215   char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
216   int t1id;
217   int jpeginfo; // did we write "File contains jpegs" yet?
218   int pbminfo; // did we write "File contains jpegs" yet?
219   int linkinfo; // did we write "File contains links" yet?
220   int ttfinfo; // did we write "File contains TrueType Fonts" yet?
221
222   int type3active; // are we between beginType3()/endType3()?
223
224   GfxState *laststate;
225 };
226
227 char*getFontName(GfxFont*font)
228 {
229     GString*gstr = font->getName();
230     char* fontname = gstr==0?0:gstr->getCString();
231     if(fontname==0) {
232         char buf[32];
233         Ref*r=font->getID();
234         sprintf(buf, "UFONT%d", r->num);
235         return strdup(buf);
236     }
237     char* plus = strchr(fontname, '+');
238     if(plus && plus < &fontname[strlen(fontname)-1])
239         fontname = plus+1;
240     return fontname;
241 }
242
243 char mybuf[1024];
244 char* gfxstate2str(GfxState *state)
245 {
246   char*bufpos = mybuf;
247   GfxRGB rgb;
248   bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
249                                     state->getCTM()[0],
250                                     state->getCTM()[1],
251                                     state->getCTM()[2],
252                                     state->getCTM()[3],
253                                     state->getCTM()[4],
254                                     state->getCTM()[5]);
255   if(state->getX1()!=0.0)
256   bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
257   if(state->getY1()!=0.0)
258   bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
259   bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
260   bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
261   bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
262   bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
263   /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
264           state->getFillColor()->c[0], state->getFillColor()->c[1]);
265   bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
266           state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
267 /*  bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
268           state->getFillColor()->c[0], state->getFillColor()->c[1],
269           state->getFillColor()->c[2], state->getFillColor()->c[3],
270           state->getFillColor()->c[4], state->getFillColor()->c[5],
271           state->getFillColor()->c[6], state->getFillColor()->c[7]);
272   bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
273           state->getStrokeColor()->c[0], state->getFillColor()->c[1],
274           state->getStrokeColor()->c[2], state->getFillColor()->c[3],
275           state->getStrokeColor()->c[4], state->getFillColor()->c[5],
276           state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
277   state->getFillRGB(&rgb);
278   if(rgb.r || rgb.g || rgb.b)
279   bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
280   state->getStrokeRGB(&rgb);
281   if(rgb.r || rgb.g || rgb.b)
282   bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
283   if(state->getFillColorSpace()->getNComps()>1)
284   bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
285   if(state->getStrokeColorSpace()->getNComps()>1)
286   bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
287   if(state->getFillPattern())
288   bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
289   if(state->getStrokePattern())
290   bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
291  
292   if(state->getFillOpacity()!=1.0)
293   bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
294   if(state->getStrokeOpacity()!=1.0)
295   bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
296
297   bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
298  
299   double * dash;
300   int length;
301   double start;
302   state->getLineDash(&dash, &length, &start);
303   int t;
304   if(length)
305   {
306       bufpos+=sprintf(bufpos,"DASH%.1f[",start);
307       for(t=0;t<length;t++) {
308           bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
309       }
310       bufpos+=sprintf(bufpos,"]");
311   }
312
313   if(state->getFlatness()!=1)
314   bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
315   if(state->getLineJoin()!=0)
316   bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
317   if(state->getLineJoin()!=0)
318   bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
319   if(state->getLineJoin()!=0)
320   bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
321
322   if(state->getFont() && getFontName(state->getFont()))
323   bufpos+=sprintf(bufpos,"F\"%s\" ",getFontName(state->getFont()));
324   bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
325   bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
326                                    state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
327   if(state->getCharSpace())
328   bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
329   if(state->getWordSpace())
330   bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
331   if(state->getHorizScaling()!=1.0)
332   bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
333   if(state->getLeading())
334   bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
335   if(state->getRise())
336   bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
337   if(state->getRender())
338   bufpos+=sprintf(bufpos,"R%d ", state->getRender());
339   bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
340   bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
341   bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
342   if(state->getLineX())
343   bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
344   if(state->getLineY())
345   bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
346   bufpos+=sprintf(bufpos," ");
347   return mybuf;
348 }
349
350
351
352 void dumpFontInfo(char*loglevel, GfxFont*font);
353 int lastdumps[1024];
354 int lastdumppos = 0;
355 /* nr = 0  unknown
356    nr = 1  substituting
357    nr = 2  type 3
358  */
359 void showFontError(GfxFont*font, int nr) 
360 {  
361     Ref*r=font->getID();
362     int t;
363     for(t=0;t<lastdumppos;t++)
364         if(lastdumps[t] == r->num)
365             break;
366     if(t < lastdumppos)
367       return;
368     if(lastdumppos<sizeof(lastdumps)/sizeof(int))
369     lastdumps[lastdumppos++] = r->num;
370     if(nr == 0)
371       msg("<warning> The following font caused problems:");
372     else if(nr == 1)
373       msg("<warning> The following font caused problems (substituting):");
374     else if(nr == 2)
375       msg("<warning> The following Type 3 Font will be rendered as bitmap:");
376     dumpFontInfo("<warning>", font);
377 }
378
379 void dumpFontInfo(char*loglevel, GfxFont*font)
380 {
381   char* name = getFontName(font);
382   Ref* r=font->getID();
383   msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
384
385   GString*gstr  = font->getTag();
386    
387   msg("%sTag: %s\n", loglevel, name);
388   
389   if(font->isCIDFont()) msg("%sis CID font\n", loglevel);
390
391   GfxFontType type=font->getType();
392   switch(type) {
393     case fontUnknownType:
394      msg("%sType: unknown\n",loglevel);
395     break;
396     case fontType1:
397      msg("%sType: 1\n",loglevel);
398     break;
399     case fontType1C:
400      msg("%sType: 1C\n",loglevel);
401     break;
402     case fontType3:
403      msg("%sType: 3\n",loglevel);
404     break;
405     case fontTrueType:
406      msg("%sType: TrueType\n",loglevel);
407     break;
408     case fontCIDType0:
409      msg("%sType: CIDType0\n",loglevel);
410     break;
411     case fontCIDType0C:
412      msg("%sType: CIDType0C\n",loglevel);
413     break;
414     case fontCIDType2:
415      msg("%sType: CIDType2\n",loglevel);
416     break;
417   }
418   
419   Ref embRef;
420   GBool embedded = font->getEmbeddedFontID(&embRef);
421   if(font->getEmbeddedFontName())
422     name = font->getEmbeddedFontName()->getCString();
423   if(embedded)
424    msg("%sEmbedded name: %s id: %d\n",loglevel, FIXNULL(name), embRef.num);
425
426   gstr = font->getExtFontFile();
427   if(gstr)
428    msg("%sExternal Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
429
430   // Get font descriptor flags.
431   if(font->isFixedWidth()) msg("%sis fixed width\n", loglevel);
432   if(font->isSerif()) msg("%sis serif\n", loglevel);
433   if(font->isSymbolic()) msg("%sis symbolic\n", loglevel);
434   if(font->isItalic()) msg("%sis italic\n", loglevel);
435   if(font->isBold()) msg("%sis bold\n", loglevel);
436 }
437
438 //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");}
439 //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");}
440
441 SWFOutputDev::SWFOutputDev() 
442 {
443     jpeginfo = 0;
444     ttfinfo = 0;
445     linkinfo = 0;
446     pbminfo = 0;
447     type3active = 0;
448     clippos = 0;
449     clipping[clippos] = 0;
450     outputstarted = 0;
451     xref = 0;
452 //    printf("SWFOutputDev::SWFOutputDev() \n");
453 };
454
455 T1_OUTLINE* gfxPath_to_T1_OUTLINE(GfxState*state, GfxPath*path)
456 {
457     int num = path->getNumSubpaths();
458     int s,t;
459     bezierpathsegment*start,*last=0;
460     bezierpathsegment*outline = start = new bezierpathsegment();
461     int cpos = 0;
462     double lastx=0,lasty=0;
463     if(!num) {
464         msg("<warning> empty path");
465         outline->type = T1_PATHTYPE_MOVE;
466         outline->dest.x = 0;
467         outline->dest.y = 0;
468         outline->link = 0;
469         return (T1_OUTLINE*)outline;
470     }
471     for(t = 0; t < num; t++) {
472         GfxSubpath *subpath = path->getSubpath(t);
473         int subnum = subpath->getNumPoints();
474
475         for(s=0;s<subnum;s++) {
476            double nx,ny;
477            state->transform(subpath->getX(s),subpath->getY(s),&nx,&ny);
478            int x = (int)((nx-lastx)*0xffff);
479            int y = (int)((ny-lasty)*0xffff);
480            if(s==0) 
481            {
482                 last = outline;
483                 outline->type = T1_PATHTYPE_MOVE;
484                 outline->dest.x = x;
485                 outline->dest.y = y;
486                 outline->link = (T1_OUTLINE*)new bezierpathsegment();
487                 outline = (bezierpathsegment*)outline->link;
488                 cpos = 0;
489                 lastx = nx;
490                 lasty = ny;
491            }
492            else if(subpath->getCurve(s) && !cpos)
493            {
494                 outline->B.x = x;
495                 outline->B.y = y;
496                 cpos = 1;
497            } 
498            else if(subpath->getCurve(s) && cpos)
499            {
500                 outline->C.x = x;
501                 outline->C.y = y;
502                 cpos = 2;
503            }
504            else
505            {
506                 last = outline;
507                 outline->dest.x = x;
508                 outline->dest.y = y;
509                 outline->type = cpos?T1_PATHTYPE_BEZIER:T1_PATHTYPE_LINE;
510                 outline->link = 0;
511                 outline->link = (T1_OUTLINE*)new bezierpathsegment();
512                 outline = (bezierpathsegment*)outline->link;
513                 cpos = 0;
514                 lastx = nx;
515                 lasty = ny;
516            }
517         }
518     }
519     last->link = 0;
520     return (T1_OUTLINE*)start;
521 }
522 /*----------------------------------------------------------------------------
523  * Primitive Graphic routines
524  *----------------------------------------------------------------------------*/
525
526 void SWFOutputDev::stroke(GfxState *state) 
527 {
528     msg("<debug> stroke\n");
529     GfxPath * path = state->getPath();
530     int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
531     int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
532     double miterLimit = state->getMiterLimit();
533     double width = state->getTransformedLineWidth();
534     struct swfmatrix m;
535     GfxRGB rgb;
536     double opaq = state->getStrokeOpacity();
537     state->getStrokeRGB(&rgb);
538
539     m.m11 = 1; m.m21 = 0; m.m22 = 1;
540     m.m12 = 0; m.m13 = 0; m.m23 = 0;
541     T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path);
542
543     lineJoin = 1; // other line joins are not yet supported by the swf encoder
544                   // TODO: support bevel joints
545
546     if(((lineCap==1) && (lineJoin==1)) || width<=caplinewidth) {
547         /* FIXME- if the path is smaller than 2 segments, we could ignore
548            lineJoin */
549         swfoutput_setdrawmode(&output, DRAWMODE_STROKE);
550         swfoutput_drawpath(&output, outline, &m);
551     } else {
552         swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), 
553                                         (char)(rgb.b*255), (char)(opaq*255));
554
555         //swfoutput_setlinewidth(&output, 1.0); //only for debugging
556         //swfoutput_setstrokecolor(&output, 0, 255, 0, 255); //likewise, see below
557         //swfoutput_setfillcolor(&output, 255, 0, 0, 255); //likewise, see below
558
559         swfoutput_drawpath2poly(&output, outline, &m, lineJoin, lineCap, width, miterLimit);
560         updateLineWidth(state);  //reset
561         updateStrokeColor(state); //reset
562         updateFillColor(state);  //reset
563     }
564 }
565 void SWFOutputDev::fill(GfxState *state) 
566 {
567     msg("<debug> fill\n");
568     GfxPath * path = state->getPath();
569     struct swfmatrix m;
570     m.m11 = 1; m.m21 = 0; m.m22 = 1;
571     m.m12 = 0; m.m13 = 0; m.m23 = 0;
572     T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path);
573     swfoutput_setdrawmode(&output, DRAWMODE_FILL);
574     swfoutput_drawpath(&output, outline, &m);
575 }
576 void SWFOutputDev::eoFill(GfxState *state) 
577 {
578     msg("<debug> eofill\n");
579     GfxPath * path = state->getPath();
580     struct swfmatrix m;
581     m.m11 = 1; m.m21 = 0; m.m22 = 1;
582     m.m12 = 0; m.m13 = 0; m.m23 = 0;
583     T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path);
584     swfoutput_setdrawmode(&output, DRAWMODE_EOFILL);
585     swfoutput_drawpath(&output, outline, &m);
586 }
587 void SWFOutputDev::clip(GfxState *state) 
588 {
589     msg("<debug> clip\n");
590     GfxPath * path = state->getPath();
591     struct swfmatrix m;
592     m.m11 = 1; m.m22 = 1;
593     m.m12 = 0; m.m21 = 0; 
594     m.m13 = 0; m.m23 = 0;
595     T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path);
596     swfoutput_startclip(&output, outline, &m);
597     clipping[clippos] ++;
598 }
599 void SWFOutputDev::eoClip(GfxState *state) 
600 {
601     msg("<debug> eoclip\n");
602     GfxPath * path = state->getPath();
603     struct swfmatrix m;
604     m.m11 = 1; m.m21 = 0; m.m22 = 1;
605     m.m12 = 0; m.m13 = 0; m.m23 = 0;
606     T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path);
607     swfoutput_startclip(&output, outline, &m);
608     clipping[clippos] ++;
609 }
610
611 SWFOutputDev::~SWFOutputDev() 
612 {
613     swfoutput_destroy(&output);
614     outputstarted = 0;
615 };
616 GBool SWFOutputDev::upsideDown() 
617 {
618     msg("<debug> upsidedown?");
619     return gTrue;
620 };
621 GBool SWFOutputDev::useDrawChar() 
622 {
623     msg("<debug> usedrawchar?");
624     return gTrue;
625 }
626
627 void SWFOutputDev::beginString(GfxState *state, GString *s) 
628
629     double m11,m21,m12,m22;
630 //    msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
631     state->getFontTransMat(&m11, &m12, &m21, &m22);
632     m11 *= state->getHorizScaling();
633     m21 *= state->getHorizScaling();
634     swfoutput_setfontmatrix(&output, m11, -m21, m12, -m22);
635 }
636
637 int charcounter = 0;
638 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
639                         double dx, double dy,
640                         double originX, double originY,
641                         CharCode c, Unicode *_u, int uLen)
642 {
643     // check for invisible text -- this is used by Acrobat Capture
644     if ((state->getRender() & 3) == 3)
645         return;
646
647     GfxFont*font = state->getFont();
648
649     if(font->getType() == fontType3) {
650         /* type 3 chars are passed primarily as graphics */
651         return;
652     }
653     double x1,y1;
654     x1 = x;
655     y1 = y;
656     state->transform(x, y, &x1, &y1);
657         
658     Unicode u=0;
659     if(_u) 
660         u = *_u;
661     
662     msg("<debug> drawChar(%f,%f,%f,%f,'%c',%d) CID=%d\n",x,y,dx,dy,c,u, font->isCIDFont());
663
664     if(font->isCIDFont()) {
665         GfxCIDFont*cfont = (GfxCIDFont*)font;
666         char*name=0;
667         if(u) {
668             int t;
669             for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++)
670                 /* todo: should be precomputed */
671                 if(nameToUnicodeTab[t].u == u) {
672                     name = nameToUnicodeTab[t].name;
673                     break;
674                 }
675         }
676
677         if(name)
678            swfoutput_drawchar(&output, x1, y1, name, c);
679         else {
680            msg("<warning> couldn't get name for CID character %02x from Encoding", c);
681            swfoutput_drawchar(&output, x1, y1, "<unknown>", c);
682         }
683     } else {
684         Gfx8BitFont*font8;
685         font8 = (Gfx8BitFont*)font;
686         char**enc=font8->getEncoding();
687
688         if(enc && enc[c])
689            swfoutput_drawchar(&output, x1, y1, enc[c], c);
690         else {
691            msg("<warning> couldn't get name for character %02x from Encoding", c);
692            swfoutput_drawchar(&output, x1, y1, "<unknown>", c);
693         }
694     }
695 }
696
697 void SWFOutputDev::endString(GfxState *state) 
698
699     msg("<debug> endstring\n");
700 }    
701
702  
703 GBool SWFOutputDev::beginType3Char(GfxState *state,
704                                CharCode code, Unicode *u, int uLen)
705 {
706     msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
707     type3active = 1;
708     /* the character itself is going to be passed using
709        drawImageMask() */
710     return gFalse; /* gTrue= is_in_cache? */
711 }
712
713 void SWFOutputDev::endType3Char(GfxState *state)
714 {
715     type3active = 0;
716     msg("<debug> endType3Char");
717 }
718
719 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2) 
720 {
721   double x1,y1,x2,y2;
722   laststate = state;
723   msg("<verbose> startPage %d (%f,%f,%f,%f)\n", pageNum, crop_x1, crop_y1, crop_x2, crop_y2);
724   msg("<notice> processing page %d", pageNum);
725
726   /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
727   state->transform(state->getX2(),state->getY2(),&x2,&y2);
728   Use CropBox, not MediaBox, as page size
729   */
730   x1 = crop_x1;
731   y1 = crop_y1;
732   x2 = crop_x2;
733   y2 = crop_y2;
734
735   if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
736   if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
737
738   if(!outputstarted) {
739     msg("<verbose> Bounding box is (%f,%f)-(%f,%f)", x1,y1,x2,y2);
740     swfoutput_init(&output, swffilename,(int)x1,(int)y1,(int)x2,(int)y2);
741     outputstarted = 1;
742   }
743   else
744     swfoutput_newpage(&output);
745 }
746
747 void SWFOutputDev::drawLink(Link *link, Catalog *catalog) 
748 {
749   msg("<debug> drawlink\n");
750   double x1, y1, x2, y2, w;
751   GfxRGB rgb;
752   swfcoord points[5];
753   int x, y;
754
755   link->getBorder(&x1, &y1, &x2, &y2, &w);
756 //  if (w > 0) 
757   {
758     rgb.r = 0;
759     rgb.g = 0;
760     rgb.b = 1;
761     cvtUserToDev(x1, y1, &x, &y);
762     points[0].x = points[4].x = (int)x;
763     points[0].y = points[4].y = (int)y;
764     cvtUserToDev(x2, y1, &x, &y);
765     points[1].x = (int)x;
766     points[1].y = (int)y;
767     cvtUserToDev(x2, y2, &x, &y);
768     points[2].x = (int)x;
769     points[2].y = (int)y;
770     cvtUserToDev(x1, y2, &x, &y);
771     points[3].x = (int)x;
772     points[3].y = (int)y;
773
774     LinkAction*action=link->getAction();
775     char buf[128];
776     char*s = "-?-";
777     char*type = "-?-";
778     char*url = 0;
779     char*named = 0;
780     int page = -1;
781     switch(action->getKind())
782     {
783         case actionGoTo: {
784             type = "GoTo";
785             LinkGoTo *ha=(LinkGoTo *)link->getAction();
786             LinkDest *dest=NULL;
787             if (ha->getDest()==NULL) 
788                 dest=catalog->findDest(ha->getNamedDest());
789             else dest=ha->getDest();
790             if (dest){ 
791               if (dest->isPageRef()){
792                 Ref pageref=dest->getPageRef();
793                 page=catalog->findPage(pageref.num,pageref.gen);
794               }
795               else  page=dest->getPageNum();
796               sprintf(buf, "%d", page);
797               s = buf;
798             }
799         }
800         break;
801         case actionGoToR: {
802             type = "GoToR";
803             LinkGoToR*l = (LinkGoToR*)action;
804             GString*g = l->getNamedDest();
805             if(g)
806              s = g->getCString();
807         }
808         break;
809         case actionNamed: {
810             type = "Named";
811             LinkNamed*l = (LinkNamed*)action;
812             GString*name = l->getName();
813             if(name) {
814                 s = name->lowerCase()->getCString();
815                 named = name->getCString();
816                 if(!strchr(s,':')) 
817                 {
818                     if(strstr(s, "next") || strstr(s, "forward"))
819                     {
820                         page = currentpage + 1;
821                     }
822                     else if(strstr(s, "prev") || strstr(s, "back"))
823                     {
824                         page = currentpage - 1;
825                     }
826                     else if(strstr(s, "last") || strstr(s, "end"))
827                     {
828                         page = pages[pagepos-1]; //:)
829                     }
830                     else if(strstr(s, "first") || strstr(s, "top"))
831                     {
832                         page = 1;
833                     }
834                 }
835             }
836         }
837         break;
838         case actionLaunch: {
839             type = "Launch";
840             LinkLaunch*l = (LinkLaunch*)action;
841             GString * str = new GString(l->getFileName());
842             str->append(l->getParams());
843             s = str->getCString();
844         }
845         break;
846         case actionURI: {
847             type = "URI";
848             LinkURI*l = (LinkURI*)action;
849             GString*g = l->getURI();
850             if(g) {
851              url = g->getCString();
852              s = url;
853             }
854         }
855         break;
856         case actionUnknown: {
857             type = "Unknown";
858             LinkUnknown*l = (LinkUnknown*)action;
859             s = "";
860         }
861         break;
862         default: {
863             msg("<error> Unknown link type!\n");
864             break;
865         }
866     }
867     if(!linkinfo && (page || url))
868     {
869         msg("<notice> File contains links");
870         linkinfo = 1;
871     }
872     if(page>0)
873     {
874         int t;
875         for(t=0;t<pagepos;t++)
876             if(pages[t]==page)
877                 break;
878         if(t!=pagepos)
879         swfoutput_linktopage(&output, t, points);
880     }
881     else if(url)
882     {
883         swfoutput_linktourl(&output, url, points);
884     }
885     else if(named)
886     {
887         swfoutput_namedlink(&output, named, points);
888     }
889     msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
890   }
891 }
892
893 void SWFOutputDev::saveState(GfxState *state) {
894   msg("<debug> saveState\n");
895   updateAll(state);
896   if(clippos<64)
897     clippos ++;
898   else
899     msg("<error> Too many nested states in pdf.");
900   clipping[clippos] = 0;
901 };
902
903 void SWFOutputDev::restoreState(GfxState *state) {
904   msg("<debug> restoreState\n");
905   updateAll(state);
906   while(clipping[clippos]) {
907       swfoutput_endclip(&output);
908       clipping[clippos]--;
909   }
910   clippos--;
911 }
912
913 char type3Warning=0;
914
915 int SWFOutputDev::searchT1Font(char*name) 
916 {       
917     int i;
918     int mapid=-1;
919     char*filename=0;
920         
921     msg("<verbose> SearchT1Font(%s)", name);
922
923     for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++) 
924     {
925         if(!strcmp(name, pdf2t1map[i].pdffont))
926         {
927             filename = pdf2t1map[i].filename;
928             mapid = i;
929         }
930     }
931     if(filename) {
932         for(i=0; i<T1_Get_no_fonts(); i++)
933         {
934             char*fontfilename = T1_GetFontFileName (i);
935             if(strstr(fontfilename, filename))
936             {
937                     pdf2t1map[i].id = mapid;
938                     return i;
939             }
940         }
941     } else {
942         for(i=0; i<T1_Get_no_fonts(); i++)
943         {
944             char*fontname = T1_GetFontName (i);
945             if(!fontname) {
946                 T1_LoadFont(i);
947                 fontname = T1_GetFontName (i);
948                 msg("<verbose> Loading extra font %s from %s\n", FIXNULL(fontname), 
949                                                                   FIXNULL(T1_GetFontFileName(i)));
950             }
951
952             if(fontname && !strcmp(name, fontname)) {
953                 msg("<notice> Extra font %d, \"%s\" is being used.\n", i, fontname);
954                 return i;
955             }
956             fontname = T1_GetFontFileName(i);
957             if(strrchr(fontname,'/'))
958                     fontname = strrchr(fontname,'/')+1;
959  
960             if(strstr(fontname, name)) {
961                 msg("<notice> Extra font %d, \"%s\" is being used.\n", i, fontname);
962                 return i;
963             }
964         }
965     }
966     return -1;
967 }
968
969 void SWFOutputDev::updateLineWidth(GfxState *state)
970 {
971     double width = state->getTransformedLineWidth();
972     swfoutput_setlinewidth(&output, width);
973 }
974
975 void SWFOutputDev::updateLineCap(GfxState *state)
976 {
977     int c = state->getLineCap();
978 }
979
980 void SWFOutputDev::updateLineJoin(GfxState *state)
981 {
982     int j = state->getLineJoin();
983 }
984
985 void SWFOutputDev::updateFillColor(GfxState *state) 
986 {
987     GfxRGB rgb;
988     double opaq = state->getFillOpacity();
989     state->getFillRGB(&rgb);
990
991     swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), 
992                                     (char)(rgb.b*255), (char)(opaq*255));
993 }
994
995 void SWFOutputDev::updateStrokeColor(GfxState *state) 
996 {
997     GfxRGB rgb;
998     double opaq = state->getStrokeOpacity();
999     state->getStrokeRGB(&rgb);
1000
1001     swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), 
1002                                       (char)(rgb.b*255), (char)(opaq*255));
1003 }
1004
1005 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1006 {
1007       char*tmpFileName = NULL;
1008       FILE *f;
1009       int c;
1010       char *fontBuf;
1011       int fontLen;
1012       Ref embRef;
1013       Object refObj, strObj;
1014       char namebuf[512];
1015       tmpFileName = mktmpname(namebuf);
1016       int ret;
1017
1018       ret = font->getEmbeddedFontID(&embRef);
1019       if(!ret) {
1020           msg("<verbose> Didn't get embedded font id");
1021           /* not embedded- the caller should now search the font
1022              directories for this font */
1023           return 0;
1024       }
1025
1026       f = fopen(tmpFileName, "wb");
1027       if (!f) {
1028         msg("<error> Couldn't create temporary Type 1 font file");
1029           return 0;
1030       }
1031       if (font->getType() == fontType1C ||
1032           font->getType() == fontCIDType0C) {
1033         if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1034           fclose(f);
1035           msg("<error> Couldn't read embedded font file");
1036           return 0;
1037         }
1038         Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1039         cvt->convertToType1(f);
1040         delete cvt;
1041         gfree(fontBuf);
1042       } else if(font->getType() == fontTrueType) {
1043         msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1044         if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1045           fclose(f);
1046           msg("<error> Couldn't read embedded font file");
1047           return 0;
1048         }
1049         TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1050         cvt->writeTTF(f);
1051         delete cvt;
1052         gfree(fontBuf);
1053       } else {
1054         font->getEmbeddedFontID(&embRef);
1055         refObj.initRef(embRef.num, embRef.gen);
1056         refObj.fetch(ref, &strObj);
1057         refObj.free();
1058         strObj.streamReset();
1059         int f4[4];
1060         char f4c[4];
1061         int t;
1062         for(t=0;t<4;t++) {
1063             f4[t] = strObj.streamGetChar();
1064             f4c[t] = (char)f4[t];
1065             if(f4[t] == EOF)
1066                 break;
1067         }
1068         if(t==4) {
1069             if(!strncmp(f4c, "true", 4)) {
1070                 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1071                    Change this on the fly */
1072                 f4[0] = f4[2] = f4[3] = 0;
1073                 f4[1] = 1;
1074             }
1075             fputc(f4[0], f);
1076             fputc(f4[1], f);
1077             fputc(f4[2], f);
1078             fputc(f4[3], f);
1079
1080             while ((c = strObj.streamGetChar()) != EOF) {
1081               fputc(c, f);
1082             }
1083         }
1084         strObj.streamClose();
1085         strObj.free();
1086       }
1087       fclose(f);
1088
1089       if(font->getType() == fontTrueType ||
1090          font->getType() == fontCIDType2)
1091       {
1092           if(!ttfinfo) {
1093               msg("<notice> File contains TrueType fonts");
1094               ttfinfo = 1;
1095           }
1096           char name2[512];
1097           char*tmp;
1098           tmp = strdup(mktmpname((char*)name2));
1099           sprintf(name2, "%s", tmp);
1100           char*a[] = {"./ttf2pt1", "-W", "0",
1101 #ifndef USE_FREETYPE
1102               "-p", "ttf",
1103 #else
1104               "-p", "ft",
1105 #endif
1106               "-b", tmpFileName, name2};
1107           msg("<verbose> Invoking %s %s %s %s %s %s %s %s",a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]);
1108           ttf2pt1_main(8,a);
1109           unlink(tmpFileName);
1110           sprintf(name2,"%s.pfb",tmp);
1111           tmpFileName = strdup(name2);
1112       }
1113
1114     return strdup(tmpFileName);
1115 }
1116
1117
1118 char* substitutetarget[256];
1119 char* substitutesource[256];
1120 int substitutepos = 0;
1121
1122 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1123 {
1124 /* ------------------------------ V1 */
1125
1126     char*fontname = "Times-Roman";
1127     msg("<verbose> substituteFont(,%s)", FIXNULL(oldname));
1128     this->t1id = searchT1Font(fontname);
1129     if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1130         msg("<fatal> Too many fonts in file.");
1131         exit(1);
1132     }
1133     if(oldname) {
1134         substitutesource[substitutepos] = oldname;
1135         substitutetarget[substitutepos] = fontname;
1136         msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1137         substitutepos ++;
1138     }
1139     return fontname;
1140
1141 /* ------------------------------ V2 */
1142
1143 /*      //substitute font
1144       char* fontname = 0;
1145       double m11, m12, m21, m22;
1146       int index;
1147       int code;
1148       double w,w1,w2;
1149       double*fm;
1150       double v;
1151       if(gfxFont->getName()) {
1152         fontname = gfxFont->getName()->getCString();
1153       }
1154
1155 //        printf("%d %s\n", t, gfxFont->getCharName(t));
1156       showFontError(gfxFont, 1);
1157       if(1) { //if (!gfxFont->isCIDFont()) { FIXME: xpdf 1.01 does not have is16Bit()
1158         if(gfxFont->isSymbolic()) {
1159           if(fontname && (strstr(fontname,"ing"))) //Dingbats, Wingdings etc.
1160            index = 16;
1161           else 
1162            index = 12;
1163         } else if (gfxFont->isFixedWidth()) {
1164           index = 8;
1165         } else if (gfxFont->isSerif()) {
1166           index = 4;
1167         } else {
1168           index = 0;
1169         }
1170         if (gfxFont->isBold() && index!=16)
1171           index += 2;
1172         if (gfxFont->isItalic() && index!=16)
1173           index += 1;
1174         fontname = fontnames[index];
1175         // get width of 'm' in real font and substituted font
1176         if ((code = gfxFont->getCharCode("m")) >= 0)
1177           w1 = gfxFont->getWidth(code);
1178         else
1179           w1 = 0;
1180         w2 = fontsizes[index];
1181         if (gfxFont->getType() == fontType3) {
1182           // This is a hack which makes it possible to substitute for some
1183           // Type 3 fonts.  The problem is that it's impossible to know what
1184           // the base coordinate system used in the font is without actually
1185           // rendering the font.  This code tries to guess by looking at the
1186           // width of the character 'm' (which breaks if the font is a
1187           // subset that doesn't contain 'm').
1188           if (w1 > 0 && (w1 > 1.1 * w2 || w1 < 0.9 * w2)) {
1189             w1 /= w2;
1190             m11 *= w1;
1191             m12 *= w1;
1192             m21 *= w1;
1193             m22 *= w1;
1194           }
1195           fm = gfxFont->getFontMatrix();
1196           v = (fm[0] == 0) ? 1 : (fm[3] / fm[0]);
1197           m21 *= v;
1198           m22 *= v;
1199         } else if (!gfxFont->isSymbolic()) {
1200           // if real font is substantially narrower than substituted
1201           // font, reduce the font size accordingly
1202           if (w1 > 0.01 && w1 < 0.9 * w2) {
1203             w1 /= w2;
1204             if (w1 < 0.8) {
1205               w1 = 0.8;
1206             }
1207             m11 *= w1;
1208             m12 *= w1;
1209             m21 *= w1;
1210             m22 *= w1;
1211           }
1212         }
1213       }
1214       if(fontname) {
1215         this->t1id = searchT1Font(fontname);
1216       }
1217       if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1218           msg("<fatal> Too many fonts in file.");
1219           exit(1);
1220       }
1221       if(oldname) {
1222           substitutesource[substitutepos] = oldname;
1223           substitutetarget[substitutepos] = fontname;
1224           msg("<verbose> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1225           substitutepos ++;
1226       }
1227       return fontname;*/
1228 }
1229
1230 void unlinkfont(char* filename)
1231 {
1232     int l;
1233     if(!filename)
1234         return;
1235     l=strlen(filename);
1236     unlink(filename);
1237     if(!strncmp(&filename[l-4],".afm",4)) {
1238         memcpy(&filename[l-4],".pfb",4);
1239         unlink(filename);
1240         memcpy(&filename[l-4],".pfa",4);
1241         unlink(filename);
1242         memcpy(&filename[l-4],".afm",4);
1243         return;
1244     } else 
1245     if(!strncmp(&filename[l-4],".pfa",4)) {
1246         memcpy(&filename[l-4],".afm",4);
1247         unlink(filename);
1248         memcpy(&filename[l-4],".pfa",4);
1249         return;
1250     } else 
1251     if(!strncmp(&filename[l-4],".pfb",4)) {
1252         memcpy(&filename[l-4],".afm",4);
1253         unlink(filename);
1254         memcpy(&filename[l-4],".pfb",4);
1255         return;
1256     }
1257 }
1258
1259 void SWFOutputDev::startDoc(XRef *xref) 
1260 {
1261   this->xref = xref;
1262 }
1263
1264
1265 void SWFOutputDev::updateFont(GfxState *state) 
1266 {
1267   GfxFont*gfxFont = state->getFont();
1268   char * fileName = 0;
1269     
1270   if (!gfxFont) {
1271     return;
1272   }  
1273   char * fontname = getFontName(gfxFont);
1274  
1275   int t;
1276   /* first, look if we substituted this font before-
1277      this way, we don't initialize the T1 Fonts
1278      too often */
1279   for(t=0;t<substitutepos;t++) {
1280       if(!strcmp(fontname, substitutesource[t])) {
1281           fontname = substitutetarget[t];
1282           break;
1283       }
1284   }
1285
1286   /* second, see if swfoutput already has this font
1287      cached- if so, we are done */
1288
1289   if(swfoutput_queryfont(&output, fontname))
1290   {
1291       swfoutput_setfont(&output, fontname, -1, 0);
1292       return;
1293   }
1294
1295   // look for Type 3 font
1296   if (!type3Warning && gfxFont->getType() == fontType3) {
1297     type3Warning = gTrue;
1298     showFontError(gfxFont, 2);
1299   }
1300
1301   /* now either load the font, or find a substitution */
1302
1303   Ref embRef;
1304   GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1305   if(embedded) {
1306     if (gfxFont->getType() == fontType1 ||
1307         gfxFont->getType() == fontCIDType0C ||
1308         gfxFont->getType() == fontType1C ||
1309         gfxFont->getType() == fontTrueType ||
1310         gfxFont->getType() == fontCIDType2
1311         )
1312     {
1313         fileName = writeEmbeddedFontToFile(xref, gfxFont);
1314         if(!fileName) {
1315           msg("<error> Couldn't write font to file");
1316           showFontError(gfxFont,0);
1317           return ;
1318         }
1319         this->t1id = T1_AddFont(fileName);
1320         if(this->t1id<0) {
1321           msg("<error> Couldn't load font from file %s", fileName);
1322           showFontError(gfxFont,0);
1323           unlinkfont(fileName);
1324           return ;
1325         }
1326     }
1327     else {
1328         /* in case the font is embedded, but has an
1329            unsupported format, we just look through the
1330            font directories */
1331         int newt1id = searchT1Font(fontname);
1332         if(newt1id<0) {
1333             msg("<error> Couldn't find any suitable replacement for %s",fontname);
1334             showFontError(gfxFont,0);
1335             fontname = substituteFont(gfxFont, fontname);
1336         } else
1337             this->t1id = newt1id;
1338     }
1339   } else {
1340     if(fontname) {
1341         int newt1id = searchT1Font(fontname);
1342         if(newt1id<0) {
1343             showFontError(gfxFont,1);
1344             fontname = substituteFont(gfxFont, fontname);
1345         } else
1346             this->t1id = newt1id;
1347     }
1348     else {
1349         showFontError(gfxFont,1);
1350         fontname = substituteFont(gfxFont, fontname);
1351     }
1352   }
1353
1354   if(t1id<0) {
1355       msg("<error> Current font's t1id is %d", t1id);
1356       //showFontError(gfxFont,0);
1357       return;
1358   }
1359  
1360   /* we may have done some substitutions here, so check
1361      again if this font is cached. */
1362   if(swfoutput_queryfont(&output, fontname))
1363   {
1364       swfoutput_setfont(&output, fontname, -1, 0);
1365       return;
1366   }
1367
1368   msg("<verbose> Creating new SWF font: t1id: %d, filename: %s name:%s", this->t1id, FIXNULL(fileName), FIXNULL(fontname));
1369   swfoutput_setfont(&output, fontname, this->t1id, fileName);
1370   if(fileName)
1371       unlinkfont(fileName);
1372 }
1373
1374 int pic_xids[1024];
1375 int pic_yids[1024];
1376 int pic_ids[1024];
1377 int pic_width[1024];
1378 int pic_height[1024];
1379 int picpos = 0;
1380 int pic_id = 0;
1381
1382 #define SQR(x) ((x)*(x))
1383
1384 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1385 {
1386     if((newwidth<2 || newheight<2) ||
1387        (width<=newwidth || height<=newheight))
1388         return 0;
1389     unsigned char*newdata;
1390     int x,y;
1391     newdata= (unsigned char*)malloc(newwidth*newheight);
1392     int t;
1393     double fx = (double)(width)/newwidth;
1394     double fy = (double)(height)/newheight;
1395     double px = 0;
1396     int blocksize = (int)(8192/(fx*fy));
1397     int r = 8192*256/palettesize;
1398     for(x=0;x<newwidth;x++) {
1399         double ex = px + fx;
1400         int fromx = (int)px;
1401         int tox = (int)ex;
1402         int xweight1 = (int)(((fromx+1)-px)*256);
1403         int xweight2 = (int)((ex-tox)*256);
1404         double py =0;
1405         for(y=0;y<newheight;y++) {
1406             double ey = py + fy;
1407             int fromy = (int)py;
1408             int toy = (int)ey;
1409             int yweight1 = (int)(((fromy+1)-py)*256);
1410             int yweight2 = (int)((ey-toy)*256);
1411             int a = 0;
1412             int xx,yy;
1413             for(xx=fromx;xx<=tox;xx++)
1414             for(yy=fromy;yy<=toy;yy++) {
1415                 int b = 1-data[width*yy+xx];
1416                 int weight=256;
1417                 if(xx==fromx) weight = (weight*xweight1)/256;
1418                 if(xx==tox) weight = (weight*xweight2)/256;
1419                 if(yy==fromy) weight = (weight*yweight1)/256;
1420                 if(yy==toy) weight = (weight*yweight2)/256;
1421                 a+=b*weight;
1422             }
1423             //if(a) a=(palettesize-1)*r/blocksize;
1424             newdata[y*newwidth+x] = (a*blocksize)/r;
1425             py = ey;
1426         }
1427         px = ex;
1428     }
1429     return newdata;
1430 }
1431
1432 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
1433                                    int width, int height, GfxImageColorMap*colorMap, GBool invert,
1434                                    GBool inlineImg, int mask)
1435 {
1436   FILE *fi;
1437   int c;
1438   char fileName[128];
1439   double x1,y1,x2,y2,x3,y3,x4,y4;
1440   ImageStream *imgStr;
1441   Guchar pixBuf[4];
1442   GfxRGB rgb;
1443   int ncomps = 1;
1444   int bits = 1;
1445                                  
1446   if(colorMap) {
1447     ncomps = colorMap->getNumPixelComps();
1448     bits = colorMap->getBits();
1449   }
1450   imgStr = new ImageStream(str, width, ncomps,bits);
1451   imgStr->reset();
1452
1453   if(!width || !height || (height<=1 && width<=1))
1454   {
1455       msg("<verbose> Ignoring %d by %d image", width, height);
1456       unsigned char buf[8];
1457       int x,y;
1458       for (y = 0; y < height; ++y)
1459       for (x = 0; x < width; ++x) {
1460           imgStr->getPixel(buf);
1461       }
1462       delete imgStr;
1463       return;
1464   }
1465   
1466   state->transform(0, 1, &x1, &y1);
1467   state->transform(0, 0, &x2, &y2);
1468   state->transform(1, 0, &x3, &y3);
1469   state->transform(1, 1, &x4, &y4);
1470
1471   if(!pbminfo && !(str->getKind()==strDCT)) {
1472       if(!type3active) {
1473           msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
1474           pbminfo = 1;
1475       }
1476       if(mask)
1477       msg("<verbose> drawing %d by %d masked picture\n", width, height);
1478   }
1479   if(!jpeginfo && (str->getKind()==strDCT)) {
1480       msg("<notice> file contains jpeg pictures");
1481       jpeginfo = 1;
1482   }
1483
1484   if(mask) {
1485       int yes=0,i,j;
1486       unsigned char buf[8];
1487       int xid = 0;
1488       int yid = 0;
1489       int x,y;
1490       unsigned char*pic = new unsigned char[width*height];
1491       RGBA pal[256];
1492       GfxRGB rgb;
1493       state->getFillRGB(&rgb);
1494       memset(pal,255,sizeof(pal));
1495       pal[0].r = (int)(rgb.r*255); pal[0].g = (int)(rgb.g*255); 
1496       pal[0].b = (int)(rgb.b*255); pal[0].a = 255;
1497       pal[1].r = 0; pal[1].g = 0; pal[1].b = 0; pal[1].a = 0;
1498       int numpalette = 2;
1499       xid += pal[1].r*3 + pal[1].g*11 + pal[1].b*17;
1500       yid += pal[1].r*7 + pal[1].g*5 + pal[1].b*23;
1501       int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
1502       int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
1503       for (y = 0; y < height; ++y)
1504       for (x = 0; x < width; ++x)
1505       {
1506             imgStr->getPixel(buf);
1507             if(invert) 
1508                 buf[0]=1-buf[0];
1509             pic[width*y+x] = buf[0];
1510             xid+=x*buf[0]+1;
1511             yid+=y*buf[0]*3+1;
1512       }
1513       
1514       /* the size of the drawn image is added to the identifier
1515          as the same image may require different bitmaps if displayed
1516          at different sizes (due to antialiasing): */
1517       if(type3active) {
1518           xid += realwidth;
1519           yid += realheight;
1520       }
1521       int t,found = -1;
1522       for(t=0;t<picpos;t++)
1523       {
1524           if(pic_xids[t] == xid &&
1525              pic_yids[t] == yid) {
1526               /* if the image was antialiased, the size has changed: */
1527               width = pic_width[t];
1528               height = pic_height[t];
1529               found = t;break;
1530           }
1531       }
1532       if(found<0) {
1533           if(type3active) {
1534               numpalette = 16;
1535               unsigned char*pic2 = 0;
1536               
1537               pic2 = antialize(pic,width,height,realwidth,realheight, numpalette);
1538
1539               if(pic2) {
1540                   width = realwidth;
1541                   height = realheight;
1542                   free(pic);
1543                   pic = pic2;
1544                   /* make a black/white palette */
1545                   int t;
1546                   GfxRGB rgb2;
1547                   rgb2.r = 1 - rgb.r;
1548                   rgb2.g = 1 - rgb.g;
1549                   rgb2.b = 1 - rgb.b;
1550
1551                   float r = 255/(numpalette-1);
1552                   for(t=0;t<numpalette;t++) {
1553                       /*pal[t].r = (U8)(t*r*rgb.r+(numpalette-1-t)*r*rgb2.r);
1554                       pal[t].g = (U8)(t*r*rgb.g+(numpalette-1-t)*r*rgb2.g);
1555                       pal[t].b = (U8)(t*r*rgb.b+(numpalette-1-t)*r*rgb2.b);
1556                       pal[t].a = 255; */
1557                       pal[t].r = (U8)(255*rgb.r);
1558                       pal[t].g = (U8)(255*rgb.g);
1559                       pal[t].b = (U8)(255*rgb.b);
1560                       pal[t].a = (U8)(t*r);
1561                   }
1562               }
1563           }
1564           pic_ids[picpos] = swfoutput_drawimagelosslessN(&output, pic, pal, width, height, 
1565                   x1,y1,x2,y2,x3,y3,x4,y4, numpalette);
1566           pic_xids[picpos] = xid;
1567           pic_yids[picpos] = yid;
1568           pic_width[picpos] = width;
1569           pic_height[picpos] = height;
1570           if(picpos<1024)
1571               picpos++;
1572       } else {
1573           swfoutput_drawimageagain(&output, pic_ids[found], width, height,
1574                   x1,y1,x2,y2,x3,y3,x4,y4);
1575       }
1576       free(pic);
1577       delete imgStr;
1578       return;
1579   } 
1580
1581   int x,y;
1582   
1583   if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT)
1584   {
1585       RGBA*pic=new RGBA[width*height];
1586       int xid = 0;
1587       int yid = 0;
1588       for (y = 0; y < height; ++y) {
1589         for (x = 0; x < width; ++x) {
1590           int r,g,b,a;
1591           imgStr->getPixel(pixBuf);
1592           colorMap->getRGB(pixBuf, &rgb);
1593           pic[width*y+x].r = r = (U8)(rgb.r * 255 + 0.5);
1594           pic[width*y+x].g = g = (U8)(rgb.g * 255 + 0.5);
1595           pic[width*y+x].b = b = (U8)(rgb.b * 255 + 0.5);
1596           pic[width*y+x].a = a = 255;//(U8)(rgb.a * 255 + 0.5);
1597           xid += x*r+x*b*3+x*g*7+x*a*11;
1598           yid += y*r*3+y*b*17+y*g*19+y*a*11;
1599         }
1600       }
1601       int t,found = -1;
1602       for(t=0;t<picpos;t++)
1603       {
1604           if(pic_xids[t] == xid &&
1605              pic_yids[t] == yid) {
1606               found = t;break;
1607           }
1608       }
1609       if(found<0) {
1610           if(str->getKind()==strDCT)
1611               pic_ids[picpos] = swfoutput_drawimagejpeg(&output, pic, width, height, 
1612                       x1,y1,x2,y2,x3,y3,x4,y4);
1613           else
1614               pic_ids[picpos] = swfoutput_drawimagelossless(&output, pic, width, height, 
1615                       x1,y1,x2,y2,x3,y3,x4,y4);
1616           pic_xids[picpos] = xid;
1617           pic_yids[picpos] = yid;
1618           pic_width[picpos] = width;
1619           pic_height[picpos] = height;
1620           if(picpos<1024)
1621               picpos++;
1622       } else {
1623           swfoutput_drawimageagain(&output, pic_ids[found], width, height,
1624                   x1,y1,x2,y2,x3,y3,x4,y4);
1625       }
1626       delete pic;
1627       delete imgStr;
1628       return;
1629   }
1630   else
1631   {
1632       U8*pic = new U8[width*height];
1633       RGBA pal[256];
1634       int t;
1635       int xid=0,yid=0;
1636       for(t=0;t<256;t++)
1637       {
1638           int r,g,b,a;
1639           pixBuf[0] = t;
1640           colorMap->getRGB(pixBuf, &rgb);
1641           pal[t].r = r = (U8)(rgb.r * 255 + 0.5);
1642           pal[t].g = g = (U8)(rgb.g * 255 + 0.5);
1643           pal[t].b = b = (U8)(rgb.b * 255 + 0.5);
1644           pal[t].a = a = 255;//(U8)(rgb.b * 255 + 0.5);
1645           xid += t*r+t*b*3+t*g*7+t*a*11;
1646           xid += (~t)*r+t*b*3+t*g*7+t*a*11;
1647       }
1648       for (y = 0; y < height; ++y) {
1649         for (x = 0; x < width; ++x) {
1650           imgStr->getPixel(pixBuf);
1651           pic[width*y+x] = pixBuf[0];
1652           xid += x*pixBuf[0]*7;
1653           yid += y*pixBuf[0]*3;
1654         }
1655       }
1656       int found = -1;
1657       for(t=0;t<picpos;t++)
1658       {
1659           if(pic_xids[t] == xid &&
1660              pic_yids[t] == yid) {
1661               found = t;break;
1662           }
1663       }
1664       if(found<0) {
1665           pic_ids[picpos] = swfoutput_drawimagelosslessN(&output, pic, pal, width, height, 
1666                   x1,y1,x2,y2,x3,y3,x4,y4,256);
1667           pic_xids[picpos] = xid;
1668           pic_yids[picpos] = yid;
1669           pic_width[picpos] = width;
1670           pic_height[picpos] = height;
1671           if(picpos<1024)
1672               picpos++;
1673       } else {
1674           swfoutput_drawimageagain(&output, pic_ids[found], width, height,
1675                   x1,y1,x2,y2,x3,y3,x4,y4);
1676       }
1677       delete pic;
1678       delete imgStr;
1679       return;
1680   }
1681 }
1682
1683 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
1684                                    int width, int height, GBool invert,
1685                                    GBool inlineImg) 
1686 {
1687   msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
1688   drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1);
1689 }
1690
1691 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
1692                          int width, int height, GfxImageColorMap *colorMap,
1693                          int *maskColors, GBool inlineImg)
1694 {
1695   msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height, 
1696           colorMap?"colorMap":"no colorMap", 
1697           maskColors?"maskColors":"no maskColors",
1698           inlineImg);
1699   if(colorMap)
1700       msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
1701               colorMap->getBits(),colorMap->getColorSpace()->getMode());
1702   drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0);
1703 }
1704
1705 SWFOutputDev*output = 0; 
1706
1707 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
1708   Object obj;
1709   GString *s1, *s2;
1710   int i;
1711
1712   if (infoDict->lookup(key, &obj)->isString()) {
1713     s1 = obj.getString();
1714     if ((s1->getChar(0) & 0xff) == 0xfe &&
1715         (s1->getChar(1) & 0xff) == 0xff) {
1716       s2 = new GString();
1717       for (i = 2; i < obj.getString()->getLength(); i += 2) {
1718         if (s1->getChar(i) == '\0') {
1719           s2->append(s1->getChar(i+1));
1720         } else {
1721           delete s2;
1722           s2 = new GString("<unicode>");
1723           break;
1724         }
1725       }
1726       printf(fmt, s2->getCString());
1727       delete s2;
1728     } else {
1729       printf(fmt, s1->getCString());
1730     }
1731   }
1732   obj.free();
1733 }
1734
1735 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
1736   Object obj;
1737   char *s;
1738
1739   if (infoDict->lookup(key, &obj)->isString()) {
1740     s = obj.getString()->getCString();
1741     if (s[0] == 'D' && s[1] == ':') {
1742       s += 2;
1743     }
1744     printf(fmt, s);
1745   }
1746   obj.free();
1747 }
1748
1749 void pdfswf_init(char*filename, char*userPassword) 
1750 {
1751   GString *fileName = new GString(filename);
1752   GString *userPW;
1753   Object info;
1754
1755   // read config file
1756   globalParams = new GlobalParams("");
1757
1758   // open PDF file
1759   if (userPassword && userPassword[0]) {
1760     userPW = new GString(userPassword);
1761   } else {
1762     userPW = NULL;
1763   }
1764   doc = new PDFDoc(fileName, userPW);
1765   if (userPW) {
1766     delete userPW;
1767   }
1768   if (!doc->isOk()) {
1769     exit(1);
1770   }
1771
1772   // print doc info
1773   doc->getDocInfo(&info);
1774   if (info.isDict() &&
1775     (screenloglevel>=LOGLEVEL_NOTICE)) {
1776     printInfoString(info.getDict(), "Title",        "Title:        %s\n");
1777     printInfoString(info.getDict(), "Subject",      "Subject:      %s\n");
1778     printInfoString(info.getDict(), "Keywords",     "Keywords:     %s\n");
1779     printInfoString(info.getDict(), "Author",       "Author:       %s\n");
1780     printInfoString(info.getDict(), "Creator",      "Creator:      %s\n");
1781     printInfoString(info.getDict(), "Producer",     "Producer:     %s\n");
1782     printInfoDate(info.getDict(),   "CreationDate", "CreationDate: %s\n");
1783     printInfoDate(info.getDict(),   "ModDate",      "ModDate:      %s\n");
1784     printf("Pages:        %d\n", doc->getNumPages());
1785     printf("Linearized:   %s\n", doc->isLinearized() ? "yes" : "no");
1786     printf("Encrypted:    ");
1787     if (doc->isEncrypted()) {
1788       printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
1789              doc->okToPrint() ? "yes" : "no",
1790              doc->okToCopy() ? "yes" : "no",
1791              doc->okToChange() ? "yes" : "no",
1792              doc->okToAddNotes() ? "yes" : "no");
1793     } else {
1794       printf("no\n");
1795     }
1796   }
1797   info.free();
1798
1799   numpages = doc->getNumPages();
1800   if (doc->isEncrypted()) {
1801         /*ERROR: This pdf is encrypted, and disallows copying.
1802           Due to the DMCA, paragraph 1201, (2) A-C, circumventing
1803           a technological measure that efficively controls access to
1804           a protected work is violating American law. 
1805           See www.eff.org for more information about DMCA issues.
1806          */
1807         if(!doc->okToCopy()) {
1808             printf("PDF disallows copying. Bailing out.\n");
1809             exit(1); //bail out
1810         }
1811         if(!doc->okToChange() || !doc->okToAddNotes())
1812             swfoutput_setprotected();
1813   }
1814
1815   output = new SWFOutputDev();
1816   output->startDoc(doc->getXRef());
1817 }
1818
1819 void pdfswf_setparameter(char*name, char*value)
1820 {
1821     if(!strcmp(name, "drawonlyshapes")) {
1822         drawonlyshapes = atoi(value);
1823     } else if(!strcmp(name, "ignoredraworder")) {
1824         ignoredraworder = atoi(value);
1825     } else if(!strcmp(name, "linksopennewwindow")) {
1826         opennewwindow = atoi(value);
1827     } else if(!strcmp(name, "storeallcharacters")) {
1828         storeallcharacters = atoi(value);
1829     } else if(!strcmp(name, "enablezlib")) {
1830         enablezlib = atoi(value);
1831     } else if(!strcmp(name, "insertstop")) {
1832         insertstoptag = atoi(value);
1833     } else if(!strcmp(name, "flashversion")) {
1834         flashversion = atoi(value);
1835     } else if(!strcmp(name, "jpegquality")) {
1836         int val = atoi(value);
1837         if(val<0) val=0;
1838         if(val>100) val=100;
1839         jpegquality = val;
1840     } else if(!strcmp(name, "outputfilename")) {
1841         swffilename = value;
1842     } else if(!strcmp(name, "caplinewidth")) {
1843         caplinewidth = atof(value);
1844     } else if(!strcmp(name, "splinequality")) {
1845         int v = atoi(value);
1846         v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
1847         if(v<1) v = 1;
1848         splinemaxerror = v;
1849     } else if(!strcmp(name, "fontquality")) {
1850         int v = atoi(value);
1851         v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
1852         if(v<1) v = 1;
1853         fontsplinemaxerror = v;
1854     } else {
1855         fprintf(stderr, "unknown parameter: %s (=%s)\n", name, value);
1856     }
1857 }
1858
1859 void pdfswf_drawonlyshapes()
1860 {
1861     drawonlyshapes = 1;
1862 }
1863
1864 void pdfswf_ignoredraworder()
1865 {
1866     ignoredraworder = 1;
1867 }
1868
1869 void pdfswf_linksopennewwindow()
1870 {
1871     opennewwindow = 1;
1872 }
1873
1874 void pdfswf_storeallcharacters()
1875 {
1876     storeallcharacters = 1;
1877 }
1878
1879 void pdfswf_enablezlib()
1880 {
1881     enablezlib = 1;
1882 }
1883
1884 void pdfswf_jpegquality(int val)
1885 {
1886     if(val<0) val=0;
1887     if(val>100) val=100;
1888     jpegquality = val;
1889 }
1890
1891 void pdfswf_setoutputfilename(char*_filename)
1892 {
1893     swffilename = _filename;
1894 }
1895
1896 void pdfswf_insertstop()
1897 {
1898     insertstoptag = 1;
1899 }
1900
1901 void pdfswf_setversion(int n)
1902 {
1903     flashversion = n;
1904 }
1905
1906
1907 void pdfswf_convertpage(int page)
1908 {
1909     if(!pages)
1910     {
1911         pages = (int*)malloc(1024*sizeof(int));
1912         pagebuflen = 1024;
1913     } else {
1914         if(pagepos == pagebuflen)
1915         {
1916             pagebuflen+=1024;
1917             pages = (int*)realloc(pages, pagebuflen);
1918         }
1919     }
1920     pages[pagepos++] = page;
1921 }
1922
1923 void pdfswf_performconversion()
1924 {
1925     int t;
1926     for(t=0;t<pagepos;t++)
1927     {
1928        currentpage = pages[t];
1929        doc->displayPage((OutputDev*)output, currentpage, /*dpi*/72, /*rotate*/0, /*doLinks*/(int)1);
1930     }
1931 }
1932
1933 int pdfswf_numpages()
1934 {
1935   return doc->getNumPages();
1936 }
1937 int closed=0;
1938 void pdfswf_close()
1939 {
1940     msg("<debug> pdfswf.cc: pdfswf_close()");
1941     delete output;
1942     delete doc;
1943     //freeParams();
1944     // check for memory leaks
1945     Object::memCheck(stderr);
1946     gMemReport(stderr);
1947 }
1948
1949