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