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