removed the embedded cache, as the swfoutput font cache now does the job,
[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 "GString.h"
27 #include "gmem.h"
28 #include "Object.h"
29 #include "Stream.h"
30 #include "Array.h"
31 #include "Dict.h"
32 #include "XRef.h"
33 #include "Catalog.h"
34 #include "Page.h"
35 #include "PDFDoc.h"
36 #include "Params.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 }
48
49 static char* swffilename = 0;
50
51 static void printInfoString(Dict *infoDict, char *key, char *fmt);
52 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
53
54 static char userPassword[33] = "";
55 static GBool printVersion = gFalse;
56 static GBool printHelp = gFalse;
57
58 double fontsizes[] = 
59 {
60  0.833,0.833,0.889,0.889,0.788,0.722,0.833,0.778,0.600,0.600,0.600,0.600,0.576,0.576,0.576,0.576
61 };
62 char*fontnames[]={
63 "Helvetica",             
64 "Helvetica-Bold",        
65 "Helvetica-BoldOblique", 
66 "Helvetica-Oblique",     
67 "Times-Roman",           
68 "Times-Bold",            
69 "Times-BoldItalic",      
70 "Times-Italic",          
71 "Courier",               
72 "Courier-Bold",          
73 "Courier-BoldOblique",   
74 "Courier-Oblique",       
75 "Symbol",                
76 "Symbol",                
77 "Symbol",                
78 "Symbol",
79 "ZapfDingBats"
80 };
81
82 struct mapping {
83     char*pdffont;
84     char*filename;
85     int id;
86 } pdf2t1map[] ={
87 {"Times-Roman",           "n021003l.pfb"},
88 {"Times-Italic",          "n021023l.pfb"},
89 {"Times-Bold",            "n021004l.pfb"},
90 {"Times-BoldItalic",      "n021024l.pfb"},
91 {"Helvetica",             "n019003l.pfb"},
92 {"Helvetica-Oblique",     "n019023l.pfb"},
93 {"Helvetica-Bold",        "n019004l.pfb"},
94 {"Helvetica-BoldOblique", "n019024l.pfb"},
95 {"Courier",               "n022003l.pfb"},
96 {"Courier-Oblique",       "n022023l.pfb"},
97 {"Courier-Bold",          "n022004l.pfb"},
98 {"Courier-BoldOblique",   "n022024l.pfb"},
99 {"Symbol",                "s050000l.pfb"},
100 {"ZapfDingbats",          "d050000l.pfb"}};
101
102 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
103   Object obj;
104   GString *s1, *s2;
105   int i;
106
107   if (infoDict->lookup(key, &obj)->isString()) {
108     s1 = obj.getString();
109     if ((s1->getChar(0) & 0xff) == 0xfe &&
110         (s1->getChar(1) & 0xff) == 0xff) {
111       s2 = new GString();
112       for (i = 2; i < obj.getString()->getLength(); i += 2) {
113         if (s1->getChar(i) == '\0') {
114           s2->append(s1->getChar(i+1));
115         } else {
116           delete s2;
117           s2 = new GString("<unicode>");
118           break;
119         }
120       }
121       printf(fmt, s2->getCString());
122       delete s2;
123     } else {
124       printf(fmt, s1->getCString());
125     }
126   }
127   obj.free();
128 }
129
130 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
131   Object obj;
132   char *s;
133
134   if (infoDict->lookup(key, &obj)->isString()) {
135     s = obj.getString()->getCString();
136     if (s[0] == 'D' && s[1] == ':') {
137       s += 2;
138     }
139     printf(fmt, s);
140   }
141   obj.free();
142 }
143
144 class GfxState;
145 class GfxImageColorMap;
146
147 class SWFOutputDev:  public OutputDev {
148   struct swfoutput output;
149   int outputstarted;
150 public:
151
152   // Constructor.
153   SWFOutputDev();
154
155   // Destructor.
156   virtual ~SWFOutputDev() ;
157
158   //----- get info about output device
159
160   // Does this device use upside-down coordinates?
161   // (Upside-down means (0,0) is the top left corner of the page.)
162   virtual GBool upsideDown();
163
164   // Does this device use drawChar() or drawString()?
165   virtual GBool useDrawChar();
166
167   //----- initialization and control
168
169   // Start a page.
170   virtual void startPage(int pageNum, GfxState *state) ;
171
172   //----- link borders
173   virtual void drawLink(Link *link, Catalog *catalog) ;
174
175   //----- save/restore graphics state
176   virtual void saveState(GfxState *state) ;
177   virtual void restoreState(GfxState *state) ;
178
179   //----- update graphics state
180
181   virtual void updateFont(GfxState *state);
182   virtual void updateFillColor(GfxState *state);
183   virtual void updateStrokeColor(GfxState *state);
184   virtual void updateLineWidth(GfxState *state);
185   
186   virtual void updateAll(GfxState *state) 
187   {
188       updateFont(state);
189       updateFillColor(state);
190       updateStrokeColor(state);
191       updateLineWidth(state);
192   };
193
194   //----- path painting
195   virtual void stroke(GfxState *state) ;
196   virtual void fill(GfxState *state) ;
197   virtual void eoFill(GfxState *state) ;
198
199   //----- path clipping
200   virtual void clip(GfxState *state) ;
201   virtual void eoClip(GfxState *state) ;
202
203   //----- text drawing
204   virtual void beginString(GfxState *state, GString *s) ;
205   virtual void endString(GfxState *state) ;
206   virtual void drawChar(GfxState *state, double x, double y,
207                         double dx, double dy, Guchar c) ;
208   virtual void drawChar16(GfxState *state, double x, double y,
209                           double dx, double dy, int c) ;
210
211   //----- image drawing
212   virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
213                              int width, int height, GBool invert,
214                              GBool inlineImg);
215   virtual void drawImage(GfxState *state, Object *ref, Stream *str,
216                          int width, int height, GfxImageColorMap *colorMap,
217                          GBool inlineImg);
218
219   private:
220   int clipping[32];
221   int clippos;
222
223   int setT1Font(char*name,FontEncoding*enc);
224   int t1id;
225 };
226
227 char mybuf[1024];
228 char* gfxstate2str(GfxState *state)
229 {
230   char*bufpos = mybuf;
231   GfxRGB rgb;
232   bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
233                                     state->getCTM()[0],
234                                     state->getCTM()[1],
235                                     state->getCTM()[2],
236                                     state->getCTM()[3],
237                                     state->getCTM()[4],
238                                     state->getCTM()[5]);
239   if(state->getX1()!=0.0)
240   bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
241   if(state->getY1()!=0.0)
242   bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
243   bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
244   bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
245   bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
246   bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
247   /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
248           state->getFillColor()->c[0], state->getFillColor()->c[1]);
249   bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
250           state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
251 /*  bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
252           state->getFillColor()->c[0], state->getFillColor()->c[1],
253           state->getFillColor()->c[2], state->getFillColor()->c[3],
254           state->getFillColor()->c[4], state->getFillColor()->c[5],
255           state->getFillColor()->c[6], state->getFillColor()->c[7]);
256   bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
257           state->getStrokeColor()->c[0], state->getFillColor()->c[1],
258           state->getStrokeColor()->c[2], state->getFillColor()->c[3],
259           state->getStrokeColor()->c[4], state->getFillColor()->c[5],
260           state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
261   state->getFillRGB(&rgb);
262   if(rgb.r || rgb.g || rgb.b)
263   bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
264   state->getStrokeRGB(&rgb);
265   if(rgb.r || rgb.g || rgb.b)
266   bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
267   if(state->getFillColorSpace()->getNComps()>1)
268   bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
269   if(state->getStrokeColorSpace()->getNComps()>1)
270   bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
271   if(state->getFillPattern())
272   bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
273   if(state->getStrokePattern())
274   bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
275  
276   if(state->getFillOpacity()!=1.0)
277   bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
278   if(state->getStrokeOpacity()!=1.0)
279   bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
280
281   bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
282  
283   double * dash;
284   int length;
285   double start;
286   state->getLineDash(&dash, &length, &start);
287   int t;
288   if(length)
289   {
290       bufpos+=sprintf(bufpos,"DASH%.1f[",start);
291       for(t=0;t<length;t++) {
292           bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
293       }
294       bufpos+=sprintf(bufpos,"]");
295   }
296
297   if(state->getFlatness()!=1)
298   bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
299   if(state->getLineJoin()!=0)
300   bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
301   if(state->getLineJoin()!=0)
302   bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
303   if(state->getLineJoin()!=0)
304   bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
305
306   if(state->getFont() && state->getFont()->getName() && state->getFont()->getName()->getCString())
307   bufpos+=sprintf(bufpos,"F\"%s\" ",((state->getFont())->getName())->getCString());
308   bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
309   bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
310                                    state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
311   if(state->getCharSpace())
312   bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
313   if(state->getWordSpace())
314   bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
315   if(state->getHorizScaling()!=1.0)
316   bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
317   if(state->getLeading())
318   bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
319   if(state->getRise())
320   bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
321   if(state->getRender())
322   bufpos+=sprintf(bufpos,"R%d ", state->getRender());
323   bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
324   bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
325   bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
326   if(state->getLineX())
327   bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
328   if(state->getLineY())
329   bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
330   bufpos+=sprintf(bufpos," ");
331   return mybuf;
332 }
333
334 void dumpFontInfo(char*loglevel, GfxFont*font);
335 int lastdumps[1024];
336 int lastdumppos = 0;
337 /* nr = 0  unknown
338    nr = 1  substituting
339    nr = 2  type 3
340  */
341 void showFontError(GfxFont*font, int nr) 
342 {  
343     Ref r=font->getID();
344     int t;
345     for(t=0;t<lastdumppos;t++)
346         if(lastdumps[t] == r.num)
347             break;
348     if(t < lastdumppos)
349       return;
350     if(lastdumppos<sizeof(lastdumps)/sizeof(int))
351     lastdumps[lastdumppos++] = r.num;
352     if(nr == 0)
353       logf("<error> The following font caused problems:");
354     else if(nr == 1)
355       logf("<error> The following font caused problems (substituting):");
356     else if(nr == 2)
357       logf("<error> This document contains Type 3 Fonts: (some text may be incorrectly displayed)");
358
359     dumpFontInfo("<error>", font);
360 }
361
362 void dumpFontInfo(char*loglevel, GfxFont*font)
363 {
364   GString *gstr;
365   char*name;
366   gstr = font->getName();
367   Ref r=font->getID();
368   logf("%s=========== %s (ID:%d,%d) ==========\n", loglevel, gstr?gstr->getCString():"(unknown font)", r.num,r.gen);
369
370   gstr  = font->getTag();
371   if(gstr) 
372    logf("%sTag: %s\n", loglevel, gstr->getCString());
373   if(font->is16Bit()) logf("%sis 16 bit\n", loglevel);
374
375   GfxFontType type=font->getType();
376   switch(type) {
377     case fontUnknownType:
378      logf("%sType: unknown\n",loglevel);
379     break;
380     case fontType0:
381      logf("%sType: 0\n",loglevel);
382     break;
383     case fontType1:
384      logf("%sType: 1\n",loglevel);
385     break;
386     case fontType1C:
387      logf("%sType: 1C\n",loglevel);
388     break;
389     case fontType3:
390      logf("%sType: 3\n",loglevel);
391     break;
392     case fontTrueType:
393      logf("%sType: TrueType\n",loglevel);
394     break;
395   }
396   
397   Ref embRef;
398   GBool embedded = font->getEmbeddedFontID(&embRef);
399   name = font->getEmbeddedFontName();
400   if(embedded)
401    logf("%sEmbedded name: %s id: %d\n",loglevel, name, embRef.num);
402
403   gstr = font->getExtFontFile();
404   if(gstr)
405    logf("%sExternal Font file: %s\n", loglevel, gstr->getCString());
406
407   // Get font descriptor flags.
408   if(font->isFixedWidth()) logf("%sis fixed width\n", loglevel);
409   if(font->isSerif()) logf("%sis serif\n", loglevel);
410   if(font->isSymbolic()) logf("%sis symbolic\n", loglevel);
411   if(font->isItalic()) logf("%sis italic\n", loglevel);
412   if(font->isBold()) logf("%sis bold\n", loglevel);
413 }
414
415 //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");}
416 //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");}
417
418 SWFOutputDev::SWFOutputDev() 
419 {
420     clippos = 0;
421     clipping[clippos] = 0;
422     outputstarted = 0;
423 //    printf("SWFOutputDev::SWFOutputDev() \n");
424 };
425
426 T1_OUTLINE* gfxPath_to_T1_OUTLINE(GfxState*state, GfxPath*path)
427 {
428     int num = path->getNumSubpaths();
429     int s,t;
430     bezierpathsegment*start,*last;
431     bezierpathsegment*outline = start = new bezierpathsegment();
432     int cpos = 0;
433     double lastx=0,lasty=0;
434     for(t = 0; t < num; t++) {
435         GfxSubpath *subpath = path->getSubpath(t);
436         int subnum = subpath->getNumPoints();
437
438         for(s=0;s<subnum;s++) {
439            double nx,ny;
440            state->transform(subpath->getX(s),subpath->getY(s),&nx,&ny);
441            int x = (int)((nx-lastx)*0xffff);
442            int y = (int)((ny-lasty)*0xffff);
443            if(s==0) 
444            {
445                 last = outline;
446                 outline->type = T1_PATHTYPE_MOVE;
447                 outline->dest.x = x;
448                 outline->dest.y = y;
449                 outline->link = (T1_OUTLINE*)new bezierpathsegment();
450                 outline = (bezierpathsegment*)outline->link;
451                 cpos = 0;
452                 lastx = nx;
453                 lasty = ny;
454            }
455            else if(subpath->getCurve(s) && !cpos)
456            {
457                 outline->B.x = x;
458                 outline->B.y = y;
459                 cpos = 1;
460            } 
461            else if(subpath->getCurve(s) && cpos)
462            {
463                 outline->C.x = x;
464                 outline->C.y = y;
465                 cpos = 2;
466            }
467            else
468            {
469                 last = outline;
470                 outline->dest.x = x;
471                 outline->dest.y = y;
472                 outline->type = cpos?T1_PATHTYPE_BEZIER:T1_PATHTYPE_LINE;
473                 outline->link = 0;
474                 outline->link = (T1_OUTLINE*)new bezierpathsegment();
475                 outline = (bezierpathsegment*)outline->link;
476                 cpos = 0;
477                 lastx = nx;
478                 lasty = ny;
479            }
480         }
481     }
482     last->link = 0;
483     return (T1_OUTLINE*)start;
484 }
485 /*----------------------------------------------------------------------------
486  * Primitive Graphic routines
487  *----------------------------------------------------------------------------*/
488
489 void SWFOutputDev::stroke(GfxState *state) 
490 {
491     logf("<debug> %s stroke\n",gfxstate2str(state));
492     GfxPath * path = state->getPath();
493     struct swfmatrix m;
494     m.m11 = 1; m.m21 = 0; m.m22 = 1;
495     m.m21 = 0; m.m13 = 0; m.m23 = 0;
496     T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path);
497     swfoutput_setdrawmode(&output, DRAWMODE_STROKE);
498     swfoutput_drawpath(&output, outline, &m);
499 }
500 void SWFOutputDev::fill(GfxState *state) 
501 {
502     logf("<debug> %s fill\n",gfxstate2str(state));
503     GfxPath * path = state->getPath();
504     struct swfmatrix m;
505     m.m11 = 1; m.m21 = 0; m.m22 = 1;
506     m.m21 = 0; m.m13 = 0; m.m23 = 0;
507     T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path);
508     swfoutput_setdrawmode(&output, DRAWMODE_FILL);
509     swfoutput_drawpath(&output, outline, &m);
510 }
511 void SWFOutputDev::eoFill(GfxState *state) 
512 {
513     logf("<debug> %s eofill\n",gfxstate2str(state));
514     GfxPath * path = state->getPath();
515     struct swfmatrix m;
516     m.m11 = 1; m.m21 = 0; m.m22 = 1;
517     m.m21 = 0; m.m13 = 0; m.m23 = 0;
518     T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path);
519     swfoutput_setdrawmode(&output, DRAWMODE_EOFILL);
520     swfoutput_drawpath(&output, outline, &m);
521 }
522 void SWFOutputDev::clip(GfxState *state) 
523 {
524     logf("<debug> %s clip\n",gfxstate2str(state));
525     GfxPath * path = state->getPath();
526     struct swfmatrix m;
527     m.m11 = 1; m.m21 = 0; m.m22 = 1;
528     m.m21 = 0; m.m13 = 0; m.m23 = 0;
529     T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path);
530     swfoutput_startclip(&output, outline, &m);
531     clipping[clippos] = 1;
532 }
533 void SWFOutputDev::eoClip(GfxState *state) 
534 {
535     logf("<debug> %s eoclip\n",gfxstate2str(state));
536     GfxPath * path = state->getPath();
537     struct swfmatrix m;
538     m.m11 = 1; m.m21 = 0; m.m22 = 1;
539     m.m21 = 0; m.m13 = 0; m.m23 = 0;
540     T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path);
541     swfoutput_startclip(&output, outline, &m);
542     clipping[clippos] = 1;
543 }
544
545 SWFOutputDev::~SWFOutputDev() 
546 {
547     swfoutput_destroy(&output);
548     outputstarted = 0;
549 };
550 GBool SWFOutputDev::upsideDown() 
551 {
552     logf("<debug> upsidedown?");
553     return gTrue;
554 };
555 GBool SWFOutputDev::useDrawChar() 
556 {
557     logf("<debug> usedrawchar?");
558     return gTrue;
559 }
560
561 void SWFOutputDev::beginString(GfxState *state, GString *s) 
562
563     double m11,m21,m12,m22;
564     logf("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
565     state->getFontTransMat(&m11, &m12, &m21, &m22);
566     m11 *= state->getHorizScaling();
567     m21 *= state->getHorizScaling();
568     swfoutput_setfontmatrix(&output, m11, -m12, m21, -m22);
569 }
570
571 int charcounter = 0;
572 void SWFOutputDev::drawChar(GfxState *state, double x, double y, double dx, double dy, Guchar c) 
573 {
574     logf("<debug> %s drawChar(%f,%f,%f,%f,'%c')\n",gfxstate2str(state), x,y,dx,dy,c);
575     // check for invisible text -- this is used by Acrobat Capture
576     if ((state->getRender() & 3) != 3)
577     {
578        FontEncoding*enc=state->getFont()->getEncoding();
579
580        double x1,y1;
581        x1 = x;
582        y1 = y;
583        state->transform(x, y, &x1, &y1);
584
585        swfoutput_drawchar(&output, x1, y1, enc->getCharName(c));
586     }
587 }
588
589 void SWFOutputDev::drawChar16(GfxState *state, double x, double y, double dx, double dy, int c) 
590 {
591     printf("<error> %s drawChar16(%f,%f,%f,%f,%08x)\n",gfxstate2str(state), x,y,dx,dy,c);
592     exit(1);
593 }
594
595 void SWFOutputDev::endString(GfxState *state) 
596
597     logf("<debug> %s endstring\n", gfxstate2str(state));
598 }    
599
600 void SWFOutputDev::startPage(int pageNum, GfxState *state) 
601 {
602   double x1,y1,x2,y2;
603   logf("<debug> %s, startPage %d\n", gfxstate2str(state), pageNum);
604   logf("<notice> processing page %d", pageNum);
605
606   state->transform(state->getX1(),state->getY1(),&x1,&y1);
607   state->transform(state->getX2(),state->getY2(),&x2,&y2);
608   if(!outputstarted) {
609     swfoutput_init(&output, swffilename, abs((int)(x2-x1)),abs((int)(y2-y1)));
610     outputstarted = 1;
611   }
612   else
613     swfoutput_newpage(&output);
614 }
615
616 void SWFOutputDev::drawLink(Link *link, Catalog *catalog) 
617 {
618   logf("<debug> drawlink\n");
619   double x1, y1, x2, y2, w;
620   GfxRGB rgb;
621   swfcoord points[5];
622   int x, y;
623
624   link->getBorder(&x1, &y1, &x2, &y2, &w);
625   if (w > 0) {
626     rgb.r = 0;
627     rgb.g = 0;
628     rgb.b = 1;
629     cvtUserToDev(x1, y1, &x, &y);
630     points[0].x = points[4].x = x;
631     points[0].y = points[4].y = y;
632     cvtUserToDev(x2, y1, &x, &y);
633     points[1].x = x;
634     points[1].y = y;
635     cvtUserToDev(x2, y2, &x, &y);
636     points[2].x = x;
637     points[2].y = y;
638     cvtUserToDev(x1, y2, &x, &y);
639     points[3].x = x;
640     points[3].y = y;
641     //PDF: draw rect
642     LinkAction*action=link->getAction();
643     char*s;
644     switch(action->getKind())
645     {
646         case actionGoTo: {
647             LinkGoTo*l = (LinkGoTo*)action;
648             s = l->getNamedDest()->getCString();
649         }
650         break;
651         case actionGoToR: {
652             LinkGoToR*l = (LinkGoToR*)action;
653             s = l->getNamedDest()->getCString();
654         }
655         break;
656         case actionLaunch: {
657             LinkLaunch*l = (LinkLaunch*)action;
658             GString * str = new GString(l->getFileName());
659             str->append(l->getParams());
660             s = str->getCString();
661         }
662         break;
663         case actionURI: {
664             LinkURI*l = (LinkURI*)action;
665             s = l->getURI()->getCString();
666         }
667         break;
668         case actionNamed: {
669             LinkNamed*l = (LinkNamed*)action;
670             s = l->getName()->getCString();
671         }
672         break;
673         case actionUnknown: {
674             LinkUnknown*l = (LinkUnknown*)action;
675             s = "";
676         }
677         break;
678     }
679     logf("<verbose> link to \"%s\"\n", s);
680   }
681 }
682
683 void SWFOutputDev::saveState(GfxState *state) {
684   logf("<debug> %s saveState\n", gfxstate2str(state));
685   updateAll(state);
686   clippos ++;
687   clipping[clippos] = 0;
688 };
689
690 void SWFOutputDev::restoreState(GfxState *state) {
691   logf("<debug> %s restoreState\n", gfxstate2str(state));
692   updateAll(state);
693   if(clipping[clippos])
694       swfoutput_endclip(&output);
695   clippos--;
696 }
697
698 char type3Warning=0;
699
700 int SWFOutputDev::setT1Font(char*name, FontEncoding*encoding) 
701 {       
702     int i;
703     
704     int id=-1;
705     int mapid=-1;
706     char*filename=0;
707     for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++) 
708     {
709         if(!strcmp(name, pdf2t1map[i].pdffont))
710         {
711             filename = pdf2t1map[i].filename;
712             mapid = i;
713         }
714     }
715     if(filename)
716     for(i=0; i<T1_Get_no_fonts(); i++)
717     {
718         char*fontfilename = T1_GetFontFileName (i);
719         if(strstr(fontfilename, filename))
720         {
721                 id = i;
722                 pdf2t1map[i].id = mapid;
723         }
724     }
725     if(id<0)
726      return 0;
727
728     this->t1id = id;
729 }
730
731 void SWFOutputDev::updateLineWidth(GfxState *state)
732 {
733     double width = state->getLineWidth();
734     swfoutput_setlinewidth(&output, width);
735 }
736
737 void SWFOutputDev::updateFillColor(GfxState *state) 
738 {
739     GfxRGB rgb;
740     double opaq = state->getFillOpacity();
741     state->getFillRGB(&rgb);
742
743     swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), 
744                                     (char)(rgb.b*255), (char)(opaq*255));
745 }
746
747 void SWFOutputDev::updateStrokeColor(GfxState *state) 
748 {
749     GfxRGB rgb;
750     double opaq = state->getStrokeOpacity();
751     state->getStrokeRGB(&rgb);
752
753     swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), 
754                                       (char)(rgb.b*255), (char)(opaq*255));
755 }
756
757 char*writeEmbeddedFontToFile(GfxFont*font)
758 {
759       char*tmpFileName = NULL;
760       char*fileName = NULL;
761       FILE *f;
762       int c;
763       char *fontBuf;
764       int fontLen;
765       Type1CFontConverter *cvt;
766       Ref embRef;
767       Object refObj, strObj;
768       tmpFileName = "tmpfont";
769       font->getEmbeddedFontID(&embRef);
770
771       f = fopen(tmpFileName, "wb");
772       if (!f) {
773         logf("<error> Couldn't create temporary Type 1 font file");
774         return 0;
775       }
776       if (font->getType() == fontType1C) {
777         if (!(fontBuf = font->readEmbFontFile(&fontLen))) {
778           fclose(f);
779           logf("<error> Couldn't read embedded font file");
780           return 0;
781         }
782         cvt = new Type1CFontConverter(fontBuf, fontLen, f);
783         cvt->convert();
784         delete cvt;
785         gfree(fontBuf);
786       } else {
787         font->getEmbeddedFontID(&embRef);
788         refObj.initRef(embRef.num, embRef.gen);
789         refObj.fetch(&strObj);
790         refObj.free();
791         strObj.streamReset();
792         while ((c = strObj.streamGetChar()) != EOF) {
793           fputc(c, f);
794         }
795         strObj.streamClose();
796         strObj.free();
797       }
798       fclose(f);
799       fileName = tmpFileName;
800       if(!fileName) {
801           logf("<error> Embedded font writer didn't create a file");
802           return 0;
803       }
804       return fileName;
805 }
806
807 char* gfxFontName(GfxFont* gfxFont)
808 {
809       GString *gstr;
810       gstr = gfxFont->getName();
811       if(gstr) {
812           return gstr->getCString();
813       }
814       else {
815           char buf[32];
816           Ref r=gfxFont->getID();
817           sprintf(buf, "UFONT%d", r.num);
818           return strdup(buf);
819       }
820 }
821
822 void SWFOutputDev::updateFont(GfxState *state) 
823 {
824   double m11, m12, m21, m22;
825   char * fontname = 0;
826   GfxFont*gfxFont = state->getFont();
827   char * fileName = 0;
828
829   if (!gfxFont) {
830     return;
831   }  
832
833   if(swfoutput_queryfont(&output, gfxFontName(gfxFont)))
834   {
835       swfoutput_setfont(&output, gfxFontName(gfxFont), -1, 0);
836       return;
837   }
838
839   // look for Type 3 font
840   if (!type3Warning && gfxFont->getType() == fontType3) {
841     type3Warning = gTrue;
842     showFontError(gfxFont, 2);
843   }
844   //dumpFontInfo ("<notice>", gfxFont);
845
846   Ref embRef;
847   GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
848   if(embedded) {
849     if (!gfxFont->is16Bit() &&
850         (gfxFont->getType() == fontType1 ||
851          gfxFont->getType() == fontType1C)) {
852         
853         fileName = writeEmbeddedFontToFile(gfxFont);
854         if(!fileName)
855           return ;
856     }
857     else {
858         showFontError(gfxFont,0);
859         return ;
860     }
861     
862     t1id = T1_AddFont(fileName);
863   } else {
864     fontname = NULL;
865     if(gfxFont->getName()) {
866       fontname = gfxFont->getName()->getCString();
867       //logf("<notice> Processing font %s", fontname);
868     }
869     if(!fontname || !setT1Font(state->getFont()->getName()->getCString(), gfxFont->getEncoding()))
870     { //substitute font
871       int index;
872       int code;
873       double w,w1,w2;
874       double*fm;
875       double v;
876       showFontError(gfxFont, 1);
877       if (!gfxFont->is16Bit()) {
878         if (gfxFont->isFixedWidth()) {
879           index = 8;
880         } else if (gfxFont->isSerif()) {
881           index = 4;
882         } else {
883           index = 0;
884         }
885         if (gfxFont->isBold())
886           index += 2;
887         if (gfxFont->isItalic())
888           index += 1;
889         fontname = fontnames[index];
890         // get width of 'm' in real font and substituted font
891         if ((code = gfxFont->getCharCode("m")) >= 0)
892           w1 = gfxFont->getWidth(code);
893         else
894           w1 = 0;
895         w2 = fontsizes[index];
896         if (gfxFont->getType() == fontType3) {
897           // This is a hack which makes it possible to substitute for some
898           // Type 3 fonts.  The problem is that it's impossible to know what
899           // the base coordinate system used in the font is without actually
900           // rendering the font.  This code tries to guess by looking at the
901           // width of the character 'm' (which breaks if the font is a
902           // subset that doesn't contain 'm').
903           if (w1 > 0 && (w1 > 1.1 * w2 || w1 < 0.9 * w2)) {
904             w1 /= w2;
905             m11 *= w1;
906             m12 *= w1;
907             m21 *= w1;
908             m22 *= w1;
909           }
910           fm = gfxFont->getFontMatrix();
911           v = (fm[0] == 0) ? 1 : (fm[3] / fm[0]);
912           m21 *= v;
913           m22 *= v;
914         } else if (!gfxFont->isSymbolic()) {
915           // if real font is substantially narrower than substituted
916           // font, reduce the font size accordingly
917           if (w1 > 0.01 && w1 < 0.9 * w2) {
918             w1 /= w2;
919             if (w1 < 0.8) {
920               w1 = 0.8;
921             }
922             m11 *= w1;
923             m12 *= w1;
924             m21 *= w1;
925             m22 *= w1;
926           }
927         }
928       }
929       if(fontname)
930         setT1Font(fontname, gfxFont->getEncoding());
931     }
932   }
933
934   swfoutput_setfont(&output,gfxFontName(gfxFont),t1id, fileName);
935   if(fileName)
936       unlink(fileName);
937 }
938
939 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
940                                    int width, int height, GBool invert,
941                                    GBool inlineImg) {
942   FILE *fi;
943   int c;
944   char fileName[128];
945   double x1,y1,x2,y2,x3,y3,x4,y4;
946   state->transform(0, 1, &x1, &y1);
947   state->transform(0, 0, &x2, &y2);
948   state->transform(1, 0, &x3, &y3);
949   state->transform(1, 1, &x4, &y4);
950
951   if (str->getKind() == strDCT) {
952     sprintf(fileName, "/tmp/tmp%08x.jpg",lrand48());
953     logf("<notice> Found picture. Temporary storage is %s", fileName);
954     if (!(fi = fopen(fileName, "wb"))) {
955       logf("<error> Couldn't open temporary image file '%s'", fileName);
956       return;
957     }
958     str = ((DCTStream *)str)->getRawStream();
959     str->reset();
960     while ((c = str->getChar()) != EOF)
961       fputc(c, fi);
962     fclose(fi);
963     swfoutput_drawimagefile(&output, fileName, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
964     unlink(fileName);
965   } else {
966       logf("<notice> File contains pbm pictures.");
967   }
968 }
969
970 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
971                                int width, int height,
972                                GfxImageColorMap *colorMap, GBool inlineImg) {
973   FILE *fi;
974   int c;
975   char fileName[128];
976   double x1,y1,x2,y2,x3,y3,x4,y4;
977   state->transform(0, 1, &x1, &y1);
978   state->transform(0, 0, &x2, &y2);
979   state->transform(1, 0, &x3, &y3);
980   state->transform(1, 1, &x4, &y4);
981
982   if (str->getKind() == strDCT &&
983       colorMap->getNumPixelComps() == 3) {
984     sprintf(fileName, "/tmp/tmp%08x.jpg", lrand48());
985     logf("<notice> Found picture. Temporary storage is %s", fileName);
986     if (!(fi = fopen(fileName, "wb"))) {
987       error(-1, "Couldn't open temporary image file '%s'", fileName);
988       return;
989     }
990     str = ((DCTStream *)str)->getRawStream();
991     str->reset();
992     while ((c = str->getChar()) != EOF)
993       fputc(c, fi);
994     fclose(fi);
995     swfoutput_drawimagefile(&output, fileName, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
996     unlink(fileName);
997   } else {
998       logf("<notice> File contains pbm pictures.");
999   }
1000 }
1001
1002 PDFDoc*doc = 0;
1003 SWFOutputDev*output = 0; 
1004
1005 void pdfswf_init(char*filename, char*userPassword) 
1006 {
1007   GString *fileName = new GString(filename);
1008   GString *userPW;
1009   Object info;
1010   // init error file
1011   errorInit();
1012
1013   // read config file
1014   initParams(xpdfConfigFile);
1015
1016   // open PDF file
1017   xref = NULL;
1018   if (userPassword && userPassword[0]) {
1019     userPW = new GString(userPassword);
1020   } else {
1021     userPW = NULL;
1022   }
1023   doc = new PDFDoc(fileName, userPW);
1024   if (userPW) {
1025     delete userPW;
1026   }
1027   if (!doc->isOk()) {
1028     exit(1);
1029   }
1030
1031   // print doc info
1032   doc->getDocInfo(&info);
1033   if (info.isDict()) {
1034     printInfoString(info.getDict(), "Title",        "Title:        %s\n");
1035     printInfoString(info.getDict(), "Subject",      "Subject:      %s\n");
1036     printInfoString(info.getDict(), "Keywords",     "Keywords:     %s\n");
1037     printInfoString(info.getDict(), "Author",       "Author:       %s\n");
1038     printInfoString(info.getDict(), "Creator",      "Creator:      %s\n");
1039     printInfoString(info.getDict(), "Producer",     "Producer:     %s\n");
1040     printInfoDate(info.getDict(),   "CreationDate", "CreationDate: %s\n");
1041     printInfoDate(info.getDict(),   "ModDate",      "ModDate:      %s\n");
1042   }
1043   info.free();
1044
1045   // print page count
1046   printf("Pages:        %d\n", doc->getNumPages());
1047   
1048   // print linearization info
1049   printf("Linearized:   %s\n", doc->isLinearized() ? "yes" : "no");
1050
1051   // print encryption info
1052   printf("Encrypted:    ");
1053   if (doc->isEncrypted()) {
1054     printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
1055            doc->okToPrint() ? "yes" : "no",
1056            doc->okToCopy() ? "yes" : "no",
1057            doc->okToChange() ? "yes" : "no",
1058            doc->okToAddNotes() ? "yes" : "no");
1059         /*ERROR: This pdf is encrypted, and disallows copying.
1060           Due to the DMCA, paragraph 1201, (2) A-C, circumventing
1061           a technological measure that efficively controls access to
1062           a protected work is violating American law. 
1063           See www.eff.org for more information about DMCA issues.
1064          */
1065         if(!doc->okToCopy()) {
1066             printf("PDF disallows copying. Bailing out.\n");
1067             exit(1); //bail out
1068         }
1069         if(!doc->okToChange() || !doc->okToAddNotes())
1070             swfoutput_setprotected();
1071     }
1072   else {
1073     printf("no\n");
1074   }
1075
1076
1077   output = new SWFOutputDev();
1078 }
1079
1080 void pdfswf_setoutputfilename(char*_filename)
1081 {
1082     swffilename = _filename;
1083 }
1084
1085 void pdfswf_convertpage(int page)
1086 {
1087     doc->displayPage((OutputDev*)output, page, /*zoom*/100, /*rotate*/0, /*doLinks*/(int)1);
1088 }
1089
1090 int pdfswf_numpages()
1091 {
1092   return doc->getNumPages();
1093 }
1094
1095 void pdfswf_close()
1096 {
1097     delete doc;
1098     delete output;
1099     
1100     freeParams();
1101     // check for memory leaks
1102     Object::memCheck(stderr);
1103     gMemReport(stderr);
1104 }
1105