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