2 implements a pdf output device (OutputDev).
4 This file is part of swftools.
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.
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.
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 */
25 #include "../config.h"
26 #ifdef HAVE_FONTCONFIG_H
27 #include <fontconfig.h>
43 #include "OutputDev.h"
46 #include "CharCodeToUnicode.h"
47 #include "NameToUnicodeTable.h"
48 #include "GlobalParams.h"
53 #include "FoFiType1C.h"
54 #include "FoFiTrueType.h"
56 #include "SWFOutputDev.h"
58 //swftools header files
59 #include "swfoutput.h"
60 #include "../lib/log.h"
64 typedef struct _fontfile
71 static fontfile_t fonts[2048];
72 static int fontnum = 0;
75 // TODO: move into pdf_doc_t
77 static int pagebuflen = 0;
78 static int pagepos = 0;
81 static double caplinewidth = 3.0;
82 static int zoom = 72; /* xpdf: 86 */
84 static void printInfoString(Dict *infoDict, char *key, char *fmt);
85 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
91 {"Times-Roman", "n021003l"},
92 {"Times-Italic", "n021023l"},
93 {"Times-Bold", "n021004l"},
94 {"Times-BoldItalic", "n021024l"},
95 {"Helvetica", "n019003l"},
96 {"Helvetica-Oblique", "n019023l"},
97 {"Helvetica-Bold", "n019004l"},
98 {"Helvetica-BoldOblique", "n019024l"},
99 {"Courier", "n022003l"},
100 {"Courier-Oblique", "n022023l"},
101 {"Courier-Bold", "n022004l"},
102 {"Courier-BoldOblique", "n022024l"},
103 {"Symbol", "s050000l"},
104 {"ZapfDingbats", "d050000l"}};
106 class SWFOutputDev: public OutputDev {
107 struct swfoutput output;
115 virtual ~SWFOutputDev() ;
117 void setMove(int x,int y);
118 void setClip(int x1,int y1,int x2,int y2);
120 int save(char*filename);
122 //----- get info about output device
124 // Does this device use upside-down coordinates?
125 // (Upside-down means (0,0) is the top left corner of the page.)
126 virtual GBool upsideDown();
128 // Does this device use drawChar() or drawString()?
129 virtual GBool useDrawChar();
131 // Can this device draw gradients?
132 virtual GBool useGradients();
134 virtual GBool interpretType3Chars() {return gTrue;}
136 //----- initialization and control
138 void setXRef(PDFDoc*doc, XRef *xref);
141 virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
144 virtual void drawLink(Link *link, Catalog *catalog) ;
146 //----- save/restore graphics state
147 virtual void saveState(GfxState *state) ;
148 virtual void restoreState(GfxState *state) ;
150 //----- update graphics state
152 virtual void updateFont(GfxState *state);
153 virtual void updateFillColor(GfxState *state);
154 virtual void updateStrokeColor(GfxState *state);
155 virtual void updateLineWidth(GfxState *state);
156 virtual void updateLineJoin(GfxState *state);
157 virtual void updateLineCap(GfxState *state);
159 virtual void updateAll(GfxState *state)
162 updateFillColor(state);
163 updateStrokeColor(state);
164 updateLineWidth(state);
165 updateLineJoin(state);
166 updateLineCap(state);
169 //----- path painting
170 virtual void stroke(GfxState *state) ;
171 virtual void fill(GfxState *state) ;
172 virtual void eoFill(GfxState *state) ;
174 //----- path clipping
175 virtual void clip(GfxState *state) ;
176 virtual void eoClip(GfxState *state) ;
179 virtual void beginString(GfxState *state, GString *s) ;
180 virtual void endString(GfxState *state) ;
181 virtual void drawChar(GfxState *state, double x, double y,
182 double dx, double dy,
183 double originX, double originY,
184 CharCode code, Unicode *u, int uLen);
186 //----- image drawing
187 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
188 int width, int height, GBool invert,
190 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
191 int width, int height, GfxImageColorMap *colorMap,
192 int *maskColors, GBool inlineImg);
194 virtual GBool beginType3Char(GfxState *state,
195 CharCode code, Unicode *u, int uLen);
196 virtual void endType3Char(GfxState *state);
199 void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
200 int width, int height, GfxImageColorMap*colorMap, GBool invert,
201 GBool inlineImg, int mask);
210 char* searchFont(char*name);
211 char* substituteFont(GfxFont*gfxFont, char*oldname);
212 char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
214 int jpeginfo; // did we write "File contains jpegs" yet?
215 int pbminfo; // did we write "File contains jpegs" yet?
216 int linkinfo; // did we write "File contains links" yet?
217 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
218 int gradientinfo; // did we write "File contains Gradients yet?
220 int type3active; // are we between beginType3()/endType3()?
228 int pic_height[1024];
233 char* substitutetarget[256];
234 char* substitutesource[256];
237 int user_movex,user_movey;
238 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
241 static char*getFontID(GfxFont*font);
243 class InfoOutputDev: public OutputDev
257 virtual ~InfoOutputDev()
260 virtual GBool upsideDown() {return gTrue;}
261 virtual GBool useDrawChar() {return gTrue;}
262 virtual GBool useGradients() {return gTrue;}
263 virtual GBool interpretType3Chars() {return gTrue;}
264 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
267 state->transform(crop_x1,crop_y1,&x1,&y1);
268 state->transform(crop_x2,crop_y2,&x2,&y2);
269 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
270 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
276 virtual void drawLink(Link *link, Catalog *catalog)
280 virtual void updateFont(GfxState *state)
282 GfxFont*font = state->getFont();
285 char*id = getFontID(font);
289 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
290 int width, int height, GBool invert,
295 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
296 int width, int height, GfxImageColorMap *colorMap,
297 int *maskColors, GBool inlineImg)
303 SWFOutputDev::SWFOutputDev()
311 clipping[clippos] = 0;
324 memset(&output, 0, sizeof(output));
325 // printf("SWFOutputDev::SWFOutputDev() \n");
328 void SWFOutputDev::setMove(int x,int y)
330 this->user_movex = x;
331 this->user_movey = y;
334 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
336 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
337 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
339 this->user_clipx1 = x1;
340 this->user_clipy1 = y1;
341 this->user_clipx2 = x2;
342 this->user_clipy2 = y2;
345 static char*getFontID(GfxFont*font)
347 GString*gstr = font->getName();
348 char* fontname = gstr==0?0:gstr->getCString();
352 sprintf(buf, "UFONT%d", r->num);
355 return strdup(fontname);
358 static char*getFontName(GfxFont*font)
360 char*fontid = getFontID(font);
362 char* plus = strchr(fontid, '+');
363 if(plus && plus < &fontid[strlen(fontid)-1]) {
364 fontname = strdup(plus+1);
366 fontname = strdup(fontid);
372 static char mybuf[1024];
373 static char* gfxstate2str(GfxState *state)
377 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
384 if(state->getX1()!=0.0)
385 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
386 if(state->getY1()!=0.0)
387 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
388 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
389 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
390 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
391 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
392 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
393 state->getFillColor()->c[0], state->getFillColor()->c[1]);
394 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
395 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
396 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
397 state->getFillColor()->c[0], state->getFillColor()->c[1],
398 state->getFillColor()->c[2], state->getFillColor()->c[3],
399 state->getFillColor()->c[4], state->getFillColor()->c[5],
400 state->getFillColor()->c[6], state->getFillColor()->c[7]);
401 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
402 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
403 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
404 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
405 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
406 state->getFillRGB(&rgb);
407 if(rgb.r || rgb.g || rgb.b)
408 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
409 state->getStrokeRGB(&rgb);
410 if(rgb.r || rgb.g || rgb.b)
411 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
412 if(state->getFillColorSpace()->getNComps()>1)
413 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
414 if(state->getStrokeColorSpace()->getNComps()>1)
415 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
416 if(state->getFillPattern())
417 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
418 if(state->getStrokePattern())
419 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
421 if(state->getFillOpacity()!=1.0)
422 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
423 if(state->getStrokeOpacity()!=1.0)
424 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
426 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
431 state->getLineDash(&dash, &length, &start);
435 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
436 for(t=0;t<length;t++) {
437 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
439 bufpos+=sprintf(bufpos,"]");
442 if(state->getFlatness()!=1)
443 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
444 if(state->getLineJoin()!=0)
445 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
446 if(state->getLineJoin()!=0)
447 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
448 if(state->getLineJoin()!=0)
449 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
451 if(state->getFont() && getFontID(state->getFont()))
452 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
453 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
454 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
455 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
456 if(state->getCharSpace())
457 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
458 if(state->getWordSpace())
459 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
460 if(state->getHorizScaling()!=1.0)
461 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
462 if(state->getLeading())
463 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
465 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
466 if(state->getRender())
467 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
468 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
469 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
470 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
471 if(state->getLineX())
472 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
473 if(state->getLineY())
474 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
475 bufpos+=sprintf(bufpos," ");
479 static void dumpFontInfo(char*loglevel, GfxFont*font);
480 static int lastdumps[1024];
481 static int lastdumppos = 0;
486 static void showFontError(GfxFont*font, int nr)
490 for(t=0;t<lastdumppos;t++)
491 if(lastdumps[t] == r->num)
495 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
496 lastdumps[lastdumppos++] = r->num;
498 msg("<warning> The following font caused problems:");
500 msg("<warning> The following font caused problems (substituting):");
502 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
503 dumpFontInfo("<warning>", font);
506 static void dumpFontInfo(char*loglevel, GfxFont*font)
508 char* name = getFontID(font);
509 Ref* r=font->getID();
510 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, getFontName(font), r->num,r->gen);
512 GString*gstr = font->getTag();
514 msg("%s| Tag: %s\n", loglevel, name);
516 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
518 GfxFontType type=font->getType();
520 case fontUnknownType:
521 msg("%s| Type: unknown\n",loglevel);
524 msg("%s| Type: 1\n",loglevel);
527 msg("%s| Type: 1C\n",loglevel);
530 msg("%s| Type: 3\n",loglevel);
533 msg("%s| Type: TrueType\n",loglevel);
536 msg("%s| Type: CIDType0\n",loglevel);
539 msg("%s| Type: CIDType0C\n",loglevel);
542 msg("%s| Type: CIDType2\n",loglevel);
547 GBool embedded = font->getEmbeddedFontID(&embRef);
548 if(font->getEmbeddedFontName())
549 name = font->getEmbeddedFontName()->getCString();
551 msg("%s| Embedded name: %s id: %d\n",loglevel, FIXNULL(name), embRef.num);
553 gstr = font->getExtFontFile();
555 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
557 // Get font descriptor flags.
558 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
559 if(font->isSerif()) msg("%s| is serif\n", loglevel);
560 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
561 if(font->isItalic()) msg("%s| is italic\n", loglevel);
562 if(font->isBold()) msg("%s| is bold\n", loglevel);
565 //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");}
566 //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");}
568 static void free_outline(SWF_OUTLINE*outline)
571 SWF_OUTLINE*next = outline->link;
577 static void dump_outline(SWF_OUTLINE*outline)
581 double lastx=x,lasty=y;
582 x += (outline->dest.x/(float)0xffff);
583 y += (outline->dest.y/(float)0xffff);
584 if(outline->type == SWF_PATHTYPE_MOVE) {
585 msg("<trace> | moveto %f,%f", x,y);
586 } else if(outline->type == SWF_PATHTYPE_LINE) {
587 msg("<trace> | lineto: %f,%f\n",x,y);
588 } else if(outline->type == SWF_PATHTYPE_BEZIER) {
589 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
590 float x1 = o2->C.x/(float)0xffff+lastx;
591 float y1 = o2->C.y/(float)0xffff+lasty;
592 float x2 = o2->B.x/(float)0xffff+lastx;
593 float y2 = o2->B.y/(float)0xffff+lasty;
594 msg("<trace> | spline: %f,%f -> %f,%f -> %f,%f\n",x1,y1,x2,y2,x,y);
596 outline = outline->link;
600 SWF_OUTLINE* gfxPath_to_SWF_OUTLINE(GfxState*state, GfxPath*path)
602 int num = path->getNumSubpaths();
604 bezierpathsegment*start,*last=0;
605 bezierpathsegment*outline = start = (bezierpathsegment*)malloc(sizeof(bezierpathsegment));
607 double lastx=0,lasty=0;
609 msg("<warning> empty path");
610 outline->type = SWF_PATHTYPE_MOVE;
614 return (SWF_OUTLINE*)outline;
616 for(t = 0; t < num; t++) {
617 GfxSubpath *subpath = path->getSubpath(t);
618 int subnum = subpath->getNumPoints();
620 for(s=0;s<subnum;s++) {
622 state->transform(subpath->getX(s),subpath->getY(s),&nx,&ny);
623 int x = (int)((nx-lastx)*0xffff);
624 int y = (int)((ny-lasty)*0xffff);
628 outline->type = SWF_PATHTYPE_MOVE;
631 outline->link = (SWF_OUTLINE*)malloc(sizeof(bezierpathsegment));
632 outline = (bezierpathsegment*)outline->link;
637 else if(subpath->getCurve(s) && !cpos)
643 else if(subpath->getCurve(s) && cpos)
654 outline->type = cpos?SWF_PATHTYPE_BEZIER:SWF_PATHTYPE_LINE;
655 outline->link = (SWF_OUTLINE*)malloc(sizeof(bezierpathsegment));
656 outline = (bezierpathsegment*)outline->link;
663 if(last->link) {free(last->link);}
666 return (SWF_OUTLINE*)start;
668 /*----------------------------------------------------------------------------
669 * Primitive Graphic routines
670 *----------------------------------------------------------------------------*/
672 void SWFOutputDev::stroke(GfxState *state)
674 GfxPath * path = state->getPath();
675 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
676 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
677 double miterLimit = state->getMiterLimit();
678 double width = state->getTransformedLineWidth();
681 double opaq = state->getStrokeOpacity();
682 state->getStrokeRGB(&rgb);
684 m.m11 = 1; m.m21 = 0; m.m22 = 1;
685 m.m12 = 0; m.m13 = 0; m.m23 = 0;
686 SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
688 if(screenloglevel >= LOGLEVEL_TRACE) {
689 msg("<trace> stroke\n");
690 dump_outline(outline);
693 lineJoin = 1; // other line joins are not yet supported by the swf encoder
694 // TODO: support bevel joints
696 if(((lineCap==1) && (lineJoin==1)) || width<=caplinewidth) {
697 /* FIXME- if the path is smaller than 2 segments, we could ignore
699 swfoutput_setdrawmode(&output, DRAWMODE_STROKE);
700 swfoutput_drawpath(&output, outline, &m);
702 swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255),
703 (char)(rgb.b*255), (char)(opaq*255));
705 //swfoutput_setlinewidth(&output, 1.0); //only for debugging
706 //swfoutput_setstrokecolor(&output, 0, 255, 0, 255); //likewise, see below
707 //swfoutput_setfillcolor(&output, 255, 0, 0, 255); //likewise, see below
709 swfoutput_drawpath2poly(&output, outline, &m, lineJoin, lineCap, width, miterLimit);
710 updateLineWidth(state); //reset
711 updateStrokeColor(state); //reset
712 updateFillColor(state); //reset
714 free_outline(outline);
716 void SWFOutputDev::fill(GfxState *state)
718 GfxPath * path = state->getPath();
720 m.m11 = 1; m.m21 = 0; m.m22 = 1;
721 m.m12 = 0; m.m13 = 0; m.m23 = 0;
722 SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
724 if(screenloglevel >= LOGLEVEL_TRACE) {
725 msg("<trace> fill\n");
726 dump_outline(outline);
729 swfoutput_setdrawmode(&output, DRAWMODE_FILL);
730 swfoutput_drawpath(&output, outline, &m);
731 free_outline(outline);
733 void SWFOutputDev::eoFill(GfxState *state)
735 GfxPath * path = state->getPath();
737 m.m11 = 1; m.m21 = 0; m.m22 = 1;
738 m.m12 = 0; m.m13 = 0; m.m23 = 0;
739 SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
741 if(screenloglevel >= LOGLEVEL_TRACE) {
742 msg("<trace> eofill\n");
743 dump_outline(outline);
746 swfoutput_setdrawmode(&output, DRAWMODE_EOFILL);
747 swfoutput_drawpath(&output, outline, &m);
748 free_outline(outline);
750 void SWFOutputDev::clip(GfxState *state)
752 GfxPath * path = state->getPath();
754 m.m11 = 1; m.m22 = 1;
755 m.m12 = 0; m.m21 = 0;
756 m.m13 = 0; m.m23 = 0;
757 SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
759 if(screenloglevel >= LOGLEVEL_TRACE) {
760 msg("<trace> clip\n");
761 dump_outline(outline);
764 swfoutput_startclip(&output, outline, &m);
765 clipping[clippos] ++;
766 free_outline(outline);
768 void SWFOutputDev::eoClip(GfxState *state)
770 GfxPath * path = state->getPath();
772 m.m11 = 1; m.m21 = 0; m.m22 = 1;
773 m.m12 = 0; m.m13 = 0; m.m23 = 0;
774 SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
776 if(screenloglevel >= LOGLEVEL_TRACE) {
777 msg("<trace> eoclip\n");
778 dump_outline(outline);
781 swfoutput_startclip(&output, outline, &m);
782 clipping[clippos] ++;
783 free_outline(outline);
785 int SWFOutputDev::save(char*filename)
787 return swfoutput_save(&output, filename);
790 SWFOutputDev::~SWFOutputDev()
792 swfoutput_destroy(&output);
795 GBool SWFOutputDev::upsideDown()
797 msg("<debug> upsidedown? yes");
800 GBool SWFOutputDev::useDrawChar()
804 GBool SWFOutputDev::useGradients()
808 msg("<notice> File contains gradients");
814 void SWFOutputDev::beginString(GfxState *state, GString *s)
816 double m11,m21,m12,m22;
817 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
818 state->getFontTransMat(&m11, &m12, &m21, &m22);
819 m11 *= state->getHorizScaling();
820 m21 *= state->getHorizScaling();
821 swfoutput_setfontmatrix(&output, m11, -m21, m12, -m22);
824 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
825 double dx, double dy,
826 double originX, double originY,
827 CharCode c, Unicode *_u, int uLen)
829 // check for invisible text -- this is used by Acrobat Capture
830 if ((state->getRender() & 3) == 3)
833 GfxFont*font = state->getFont();
835 if(font->getType() == fontType3) {
836 /* type 3 chars are passed as graphics */
842 state->transform(x, y, &x1, &y1);
848 /* find out the character name */
850 if(font->isCIDFont() && u) {
851 GfxCIDFont*cfont = (GfxCIDFont*)font;
853 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
854 /* todo: should be precomputed */
855 if(nameToUnicodeTab[t].u == u) {
856 name = nameToUnicodeTab[t].name;
862 font8 = (Gfx8BitFont*)font;
863 char**enc=font8->getEncoding();
868 msg("<debug> drawChar(%f,%f,c='%c' (%d),u=%d <%d>) CID=%d name=\"%s\"\n",x,y,(c&127)>=32?c:'?',c,u, uLen, font->isCIDFont(), FIXNULL(name));
870 /*x1 = (int)(x1+0.5);
871 y1 = (int)(y1+0.5);*/
873 int ret = swfoutput_drawchar(&output, x1, y1, name, c, u);
876 void SWFOutputDev::endString(GfxState *state) {
880 GBool SWFOutputDev::beginType3Char(GfxState *state,
881 CharCode code, Unicode *u, int uLen)
883 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
885 /* the character itself is going to be passed using
887 return gFalse; /* gTrue= is_in_cache? */
890 void SWFOutputDev::endType3Char(GfxState *state)
893 msg("<debug> endType3Char");
896 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
898 this->currentpage = pageNum;
900 int rot = doc->getPageRotate(1);
902 msg("<verbose> startPage %d (%f,%f,%f,%f)\n", pageNum, crop_x1, crop_y1, crop_x2, crop_y2);
904 msg("<verbose> page is rotated %d degrees\n", rot);
906 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
907 state->transform(state->getX2(),state->getY2(),&x2,&y2);
908 Use CropBox, not MediaBox, as page size
915 state->transform(crop_x1,crop_y1,&x1,&y1);
916 state->transform(crop_x2,crop_y2,&x2,&y2);
918 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
919 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
921 /* apply user clip box */
922 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
923 if(user_clipx1 > x1) x1 = user_clipx1;
924 if(user_clipx2 < x2) x2 = user_clipx2;
925 if(user_clipy1 > y1) y1 = user_clipy1;
926 if(user_clipy2 < y2) y2 = user_clipy2;
930 msg("<verbose> Bounding box is (%f,%f)-(%f,%f)", x1,y1,x2,y2);
931 swfoutput_init(&output);
935 swfoutput_newpage(&output, pageNum, user_movex, user_movey, (int)x1, (int)y1, (int)x2, (int)y2);
938 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
940 msg("<debug> drawlink\n");
941 double x1, y1, x2, y2, w;
947 link->getBorder(&x1, &y1, &x2, &y2, &w);
949 link->getRect(&x1, &y1, &x2, &y2);
954 cvtUserToDev(x1, y1, &x, &y);
955 points[0].x = points[4].x = (int)x;
956 points[0].y = points[4].y = (int)y;
957 cvtUserToDev(x2, y1, &x, &y);
958 points[1].x = (int)x;
959 points[1].y = (int)y;
960 cvtUserToDev(x2, y2, &x, &y);
961 points[2].x = (int)x;
962 points[2].y = (int)y;
963 cvtUserToDev(x1, y2, &x, &y);
964 points[3].x = (int)x;
965 points[3].y = (int)y;
967 LinkAction*action=link->getAction();
974 switch(action->getKind())
978 LinkGoTo *ha=(LinkGoTo *)link->getAction();
980 if (ha->getDest()==NULL)
981 dest=catalog->findDest(ha->getNamedDest());
982 else dest=ha->getDest();
984 if (dest->isPageRef()){
985 Ref pageref=dest->getPageRef();
986 page=catalog->findPage(pageref.num,pageref.gen);
988 else page=dest->getPageNum();
989 sprintf(buf, "%d", page);
996 LinkGoToR*l = (LinkGoToR*)action;
997 GString*g = l->getNamedDest();
999 s = strdup(g->getCString());
1004 LinkNamed*l = (LinkNamed*)action;
1005 GString*name = l->getName();
1007 s = strdup(name->lowerCase()->getCString());
1008 named = name->getCString();
1011 if(strstr(s, "next") || strstr(s, "forward"))
1013 page = currentpage + 1;
1015 else if(strstr(s, "prev") || strstr(s, "back"))
1017 page = currentpage - 1;
1019 else if(strstr(s, "last") || strstr(s, "end"))
1021 page = pagepos>0?pages[pagepos-1]:0;
1023 else if(strstr(s, "first") || strstr(s, "top"))
1031 case actionLaunch: {
1033 LinkLaunch*l = (LinkLaunch*)action;
1034 GString * str = new GString(l->getFileName());
1035 str->append(l->getParams());
1036 s = strdup(str->getCString());
1042 LinkURI*l = (LinkURI*)action;
1043 GString*g = l->getURI();
1045 url = g->getCString();
1050 case actionUnknown: {
1052 LinkUnknown*l = (LinkUnknown*)action;
1057 msg("<error> Unknown link type!\n");
1061 if(!s) s = strdup("-?-");
1063 if(!linkinfo && (page || url))
1065 msg("<notice> File contains links");
1071 for(t=0;t<pagepos;t++)
1075 swfoutput_linktopage(&output, t, points);
1079 swfoutput_linktourl(&output, url, points);
1083 swfoutput_namedlink(&output, named, points);
1085 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1089 void SWFOutputDev::saveState(GfxState *state) {
1090 msg("<debug> saveState\n");
1095 msg("<error> Too many nested states in pdf.");
1096 clipping[clippos] = 0;
1099 void SWFOutputDev::restoreState(GfxState *state) {
1100 msg("<debug> restoreState\n");
1102 while(clipping[clippos]) {
1103 swfoutput_endclip(&output);
1104 clipping[clippos]--;
1109 char* SWFOutputDev::searchFont(char*name)
1113 int is_standard_font = 0;
1115 msg("<verbose> SearchFont(%s)", name);
1117 /* see if it is a pdf standard font */
1118 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1120 if(!strcmp(name, pdf2t1map[i].pdffont))
1122 name = pdf2t1map[i].filename;
1123 is_standard_font = 1;
1127 /* look in all font files */
1128 for(i=0;i<fontnum;i++)
1130 if(strstr(fonts[i].filename, name))
1132 if(!fonts[i].used) {
1135 if(!is_standard_font)
1136 msg("<notice> Using %s for %s", fonts[i].filename, name);
1138 return strdup(fonts[i].filename);
1144 void SWFOutputDev::updateLineWidth(GfxState *state)
1146 double width = state->getTransformedLineWidth();
1147 swfoutput_setlinewidth(&output, width);
1150 void SWFOutputDev::updateLineCap(GfxState *state)
1152 int c = state->getLineCap();
1155 void SWFOutputDev::updateLineJoin(GfxState *state)
1157 int j = state->getLineJoin();
1160 void SWFOutputDev::updateFillColor(GfxState *state)
1163 double opaq = state->getFillOpacity();
1164 state->getFillRGB(&rgb);
1166 swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255),
1167 (char)(rgb.b*255), (char)(opaq*255));
1170 void SWFOutputDev::updateStrokeColor(GfxState *state)
1173 double opaq = state->getStrokeOpacity();
1174 state->getStrokeRGB(&rgb);
1176 swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255),
1177 (char)(rgb.b*255), (char)(opaq*255));
1180 void FoFiWrite(void *stream, char *data, int len)
1182 fwrite(data, len, 1, (FILE*)stream);
1185 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1187 char*tmpFileName = NULL;
1193 Object refObj, strObj;
1195 tmpFileName = mktmpname(namebuf);
1198 ret = font->getEmbeddedFontID(&embRef);
1200 msg("<verbose> Didn't get embedded font id");
1201 /* not embedded- the caller should now search the font
1202 directories for this font */
1206 f = fopen(tmpFileName, "wb");
1208 msg("<error> Couldn't create temporary Type 1 font file");
1212 /*if(font->isCIDFont()) {
1213 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1214 GString c = cidFont->getCollection();
1215 msg("<notice> Collection: %s", c.getCString());
1218 if (font->getType() == fontType1C ||
1219 font->getType() == fontCIDType0C) {
1220 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1222 msg("<error> Couldn't read embedded font file");
1226 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1227 cvt->convertToType1(f);
1229 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1230 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1232 //cvt->convertToCIDType0("test", f);
1233 //cvt->convertToType0("test", f);
1236 } else if(font->getType() == fontTrueType) {
1237 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1238 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1240 msg("<error> Couldn't read embedded font file");
1244 TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1247 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1248 cvt->writeTTF(FoFiWrite, f);
1253 font->getEmbeddedFontID(&embRef);
1254 refObj.initRef(embRef.num, embRef.gen);
1255 refObj.fetch(ref, &strObj);
1257 strObj.streamReset();
1262 f4[t] = strObj.streamGetChar();
1263 f4c[t] = (char)f4[t];
1268 if(!strncmp(f4c, "true", 4)) {
1269 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1270 Change this on the fly */
1271 f4[0] = f4[2] = f4[3] = 0;
1279 while ((c = strObj.streamGetChar()) != EOF) {
1283 strObj.streamClose();
1288 return strdup(tmpFileName);
1291 char* searchForSuitableFont(GfxFont*gfxFont)
1293 char*name = getFontName(gfxFont);
1297 #ifdef HAVE_FONTCONFIG
1298 FcPattern *pattern, *match;
1302 static int fcinitcalled = false;
1304 // call init ony once
1305 if (!fcinitcalled) {
1306 fcinitcalled = true;
1310 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1311 if (gfxFont->isItalic()) // check for italic
1312 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1313 if (gfxFont->isBold()) // check for bold
1314 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1316 // configure and match using the original font name
1317 FcConfigSubstitute(0, pattern, FcMatchPattern);
1318 FcDefaultSubstitute(pattern);
1319 match = FcFontMatch(0, pattern, &result);
1321 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1322 // if we get an exact match
1323 if (strcmp((char *)v, name) == 0) {
1324 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1325 filename = strdup((char*)v);
1326 char *nfn = strrchr(filename, '/');
1327 if(nfn) fontname = strdup(nfn+1);
1328 else fontname = filename;
1331 // initialize patterns
1332 FcPatternDestroy(pattern);
1333 FcPatternDestroy(match);
1335 // now match against serif etc.
1336 if (gfxFont->isSerif()) {
1337 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1338 } else if (gfxFont->isFixedWidth()) {
1339 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1341 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1345 if (gfxFont->isItalic()) {
1346 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1349 if (gfxFont->isBold()) {
1350 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1353 // configure and match using serif etc
1354 FcConfigSubstitute (0, pattern, FcMatchPattern);
1355 FcDefaultSubstitute (pattern);
1356 match = FcFontMatch (0, pattern, &result);
1358 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1359 filename = strdup((char*)v);
1360 char *nfn = strrchr(filename, '/');
1361 if(nfn) fontname = strdup(nfn+1);
1362 else fontname = filename;
1367 //printf("FONTCONFIG: pattern");
1368 //FcPatternPrint(pattern);
1369 //printf("FONTCONFIG: match");
1370 //FcPatternPrint(match);
1372 FcPatternDestroy(pattern);
1373 FcPatternDestroy(match);
1375 pdfswf_addfont(filename);
1382 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1384 char*fontname = 0, *filename = 0;
1385 msg("<notice> subsituteFont(%s)", oldname);
1387 if(!(fontname = searchForSuitableFont(gfxFont))) {
1388 fontname = "Times-Roman";
1390 filename = searchFont(fontname);
1392 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1393 msg("<fatal> Too many fonts in file.");
1397 substitutesource[substitutepos] = oldname;
1398 substitutetarget[substitutepos] = fontname;
1399 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1402 return strdup(filename);
1405 void unlinkfont(char* filename)
1412 if(!strncmp(&filename[l-4],".afm",4)) {
1413 memcpy(&filename[l-4],".pfb",4);
1415 memcpy(&filename[l-4],".pfa",4);
1417 memcpy(&filename[l-4],".afm",4);
1420 if(!strncmp(&filename[l-4],".pfa",4)) {
1421 memcpy(&filename[l-4],".afm",4);
1423 memcpy(&filename[l-4],".pfa",4);
1426 if(!strncmp(&filename[l-4],".pfb",4)) {
1427 memcpy(&filename[l-4],".afm",4);
1429 memcpy(&filename[l-4],".pfb",4);
1434 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1441 void SWFOutputDev::updateFont(GfxState *state)
1443 GfxFont*gfxFont = state->getFont();
1448 char * fontid = getFontID(gfxFont);
1451 /* first, look if we substituted this font before-
1452 this way, we don't initialize the T1 Fonts
1454 for(t=0;t<substitutepos;t++) {
1455 if(!strcmp(fontid, substitutesource[t])) {
1456 fontid = substitutetarget[t];
1461 /* second, see if swfoutput already has this font
1462 cached- if so, we are done */
1463 if(swfoutput_queryfont(&output, fontid))
1465 swfoutput_setfont(&output, fontid, 0);
1467 msg("<debug> updateFont(%s) [cached]", fontid);
1471 // look for Type 3 font
1472 if (gfxFont->getType() == fontType3) {
1474 type3Warning = gTrue;
1475 showFontError(gfxFont, 2);
1480 /* now either load the font, or find a substitution */
1483 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1488 (gfxFont->getType() == fontType1 ||
1489 gfxFont->getType() == fontType1C ||
1490 //gfxFont->getType() == fontCIDType0C ||
1491 gfxFont->getType() == fontTrueType ||
1492 gfxFont->getType() == fontCIDType2
1495 fileName = writeEmbeddedFontToFile(xref, gfxFont);
1496 if(!fileName) showFontError(gfxFont,0);
1499 char * fontname = getFontName(gfxFont);
1500 fileName = searchFont(fontname);
1501 if(!fileName) showFontError(gfxFont,0);
1504 char * fontname = getFontName(gfxFont);
1505 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
1506 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
1507 fileName = substituteFont(gfxFont, fontid);
1508 if(fontid) { fontid = substitutetarget[substitutepos-1]; /*ugly hack*/};
1509 msg("<notice> Font is now %s (%s)", fontid, fileName);
1513 msg("<error> Couldn't set font %s\n", fontid);
1517 msg("<verbose> updateFont(%s) -> %s", fontid, fileName);
1518 dumpFontInfo("<verbose>", gfxFont);
1520 swfoutput_setfont(&output, fontid, fileName);
1523 unlinkfont(fileName);
1528 #define SQR(x) ((x)*(x))
1530 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1532 if((newwidth<2 || newheight<2) ||
1533 (width<=newwidth || height<=newheight))
1535 unsigned char*newdata;
1537 newdata= (unsigned char*)malloc(newwidth*newheight);
1539 double fx = (double)(width)/newwidth;
1540 double fy = (double)(height)/newheight;
1542 int blocksize = (int)(8192/(fx*fy));
1543 int r = 8192*256/palettesize;
1544 for(x=0;x<newwidth;x++) {
1545 double ex = px + fx;
1546 int fromx = (int)px;
1548 int xweight1 = (int)(((fromx+1)-px)*256);
1549 int xweight2 = (int)((ex-tox)*256);
1551 for(y=0;y<newheight;y++) {
1552 double ey = py + fy;
1553 int fromy = (int)py;
1555 int yweight1 = (int)(((fromy+1)-py)*256);
1556 int yweight2 = (int)((ey-toy)*256);
1559 for(xx=fromx;xx<=tox;xx++)
1560 for(yy=fromy;yy<=toy;yy++) {
1561 int b = 1-data[width*yy+xx];
1563 if(xx==fromx) weight = (weight*xweight1)/256;
1564 if(xx==tox) weight = (weight*xweight2)/256;
1565 if(yy==fromy) weight = (weight*yweight1)/256;
1566 if(yy==toy) weight = (weight*yweight2)/256;
1569 //if(a) a=(palettesize-1)*r/blocksize;
1570 newdata[y*newwidth+x] = (a*blocksize)/r;
1578 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
1579 int width, int height, GfxImageColorMap*colorMap, GBool invert,
1580 GBool inlineImg, int mask)
1585 double x1,y1,x2,y2,x3,y3,x4,y4;
1586 ImageStream *imgStr;
1593 ncomps = colorMap->getNumPixelComps();
1594 bits = colorMap->getBits();
1596 imgStr = new ImageStream(str, width, ncomps,bits);
1599 if(!width || !height || (height<=1 && width<=1))
1601 msg("<verbose> Ignoring %d by %d image", width, height);
1602 unsigned char buf[8];
1604 for (y = 0; y < height; ++y)
1605 for (x = 0; x < width; ++x) {
1606 imgStr->getPixel(buf);
1612 state->transform(0, 1, &x1, &y1);
1613 state->transform(0, 0, &x2, &y2);
1614 state->transform(1, 0, &x3, &y3);
1615 state->transform(1, 1, &x4, &y4);
1617 if(!pbminfo && !(str->getKind()==strDCT)) {
1619 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
1623 msg("<verbose> drawing %d by %d masked picture\n", width, height);
1625 if(!jpeginfo && (str->getKind()==strDCT)) {
1626 msg("<notice> file contains jpeg pictures");
1632 unsigned char buf[8];
1636 unsigned char*pic = new unsigned char[width*height];
1639 state->getFillRGB(&rgb);
1640 memset(pal,255,sizeof(pal));
1641 pal[0].r = (int)(rgb.r*255); pal[0].g = (int)(rgb.g*255);
1642 pal[0].b = (int)(rgb.b*255); pal[0].a = 255;
1643 pal[1].r = 0; pal[1].g = 0; pal[1].b = 0; pal[1].a = 0;
1645 xid += pal[1].r*3 + pal[1].g*11 + pal[1].b*17;
1646 yid += pal[1].r*7 + pal[1].g*5 + pal[1].b*23;
1647 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
1648 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
1649 for (y = 0; y < height; ++y)
1650 for (x = 0; x < width; ++x)
1652 imgStr->getPixel(buf);
1655 pic[width*y+x] = buf[0];
1660 /* the size of the drawn image is added to the identifier
1661 as the same image may require different bitmaps if displayed
1662 at different sizes (due to antialiasing): */
1668 for(t=0;t<picpos;t++)
1670 if(pic_xids[t] == xid &&
1671 pic_yids[t] == yid) {
1672 /* if the image was antialiased, the size has changed: */
1673 width = pic_width[t];
1674 height = pic_height[t];
1681 unsigned char*pic2 = 0;
1683 pic2 = antialize(pic,width,height,realwidth,realheight, numpalette);
1687 height = realheight;
1690 /* make a black/white palette */
1697 float r = 255/(numpalette-1);
1698 for(t=0;t<numpalette;t++) {
1699 /*pal[t].r = (U8)(t*r*rgb.r+(numpalette-1-t)*r*rgb2.r);
1700 pal[t].g = (U8)(t*r*rgb.g+(numpalette-1-t)*r*rgb2.g);
1701 pal[t].b = (U8)(t*r*rgb.b+(numpalette-1-t)*r*rgb2.b);
1703 pal[t].r = (U8)(255*rgb.r);
1704 pal[t].g = (U8)(255*rgb.g);
1705 pal[t].b = (U8)(255*rgb.b);
1706 pal[t].a = (U8)(t*r);
1710 pic_ids[picpos] = swfoutput_drawimagelosslessN(&output, pic, pal, width, height,
1711 x1,y1,x2,y2,x3,y3,x4,y4, numpalette);
1712 pic_xids[picpos] = xid;
1713 pic_yids[picpos] = yid;
1714 pic_width[picpos] = width;
1715 pic_height[picpos] = height;
1719 swfoutput_drawimageagain(&output, pic_ids[found], width, height,
1720 x1,y1,x2,y2,x3,y3,x4,y4);
1729 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT)
1731 RGBA*pic=new RGBA[width*height];
1734 for (y = 0; y < height; ++y) {
1735 for (x = 0; x < width; ++x) {
1737 imgStr->getPixel(pixBuf);
1738 colorMap->getRGB(pixBuf, &rgb);
1739 pic[width*y+x].r = r = (U8)(rgb.r * 255 + 0.5);
1740 pic[width*y+x].g = g = (U8)(rgb.g * 255 + 0.5);
1741 pic[width*y+x].b = b = (U8)(rgb.b * 255 + 0.5);
1742 pic[width*y+x].a = a = 255;//(U8)(rgb.a * 255 + 0.5);
1743 xid += x*r+x*b*3+x*g*7+x*a*11;
1744 yid += y*r*3+y*b*17+y*g*19+y*a*11;
1748 for(t=0;t<picpos;t++)
1750 if(pic_xids[t] == xid &&
1751 pic_yids[t] == yid) {
1756 if(str->getKind()==strDCT)
1757 pic_ids[picpos] = swfoutput_drawimagejpeg(&output, pic, width, height,
1758 x1,y1,x2,y2,x3,y3,x4,y4);
1760 pic_ids[picpos] = swfoutput_drawimagelossless(&output, pic, width, height,
1761 x1,y1,x2,y2,x3,y3,x4,y4);
1762 pic_xids[picpos] = xid;
1763 pic_yids[picpos] = yid;
1764 pic_width[picpos] = width;
1765 pic_height[picpos] = height;
1769 swfoutput_drawimageagain(&output, pic_ids[found], width, height,
1770 x1,y1,x2,y2,x3,y3,x4,y4);
1778 U8*pic = new U8[width*height];
1786 colorMap->getRGB(pixBuf, &rgb);
1787 pal[t].r = r = (U8)(rgb.r * 255 + 0.5);
1788 pal[t].g = g = (U8)(rgb.g * 255 + 0.5);
1789 pal[t].b = b = (U8)(rgb.b * 255 + 0.5);
1790 pal[t].a = a = 255;//(U8)(rgb.b * 255 + 0.5);
1791 xid += t*r+t*b*3+t*g*7+t*a*11;
1792 xid += (~t)*r+t*b*3+t*g*7+t*a*11;
1794 for (y = 0; y < height; ++y) {
1795 for (x = 0; x < width; ++x) {
1796 imgStr->getPixel(pixBuf);
1797 pic[width*y+x] = pixBuf[0];
1798 xid += x*pixBuf[0]*7;
1799 yid += y*pixBuf[0]*3;
1803 for(t=0;t<picpos;t++)
1805 if(pic_xids[t] == xid &&
1806 pic_yids[t] == yid) {
1811 pic_ids[picpos] = swfoutput_drawimagelosslessN(&output, pic, pal, width, height,
1812 x1,y1,x2,y2,x3,y3,x4,y4,256);
1813 pic_xids[picpos] = xid;
1814 pic_yids[picpos] = yid;
1815 pic_width[picpos] = width;
1816 pic_height[picpos] = height;
1820 swfoutput_drawimageagain(&output, pic_ids[found], width, height,
1821 x1,y1,x2,y2,x3,y3,x4,y4);
1829 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
1830 int width, int height, GBool invert,
1833 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
1834 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1);
1837 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
1838 int width, int height, GfxImageColorMap *colorMap,
1839 int *maskColors, GBool inlineImg)
1841 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
1842 colorMap?"colorMap":"no colorMap",
1843 maskColors?"maskColors":"no maskColors",
1846 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
1847 colorMap->getBits(),colorMap->getColorSpace()->getMode());
1848 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0);
1851 SWFOutputDev*output = 0;
1853 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
1858 if (infoDict->lookup(key, &obj)->isString()) {
1859 s1 = obj.getString();
1860 if ((s1->getChar(0) & 0xff) == 0xfe &&
1861 (s1->getChar(1) & 0xff) == 0xff) {
1863 for (i = 2; i < obj.getString()->getLength(); i += 2) {
1864 if (s1->getChar(i) == '\0') {
1865 s2->append(s1->getChar(i+1));
1868 s2 = new GString("<unicode>");
1872 printf(fmt, s2->getCString());
1875 printf(fmt, s1->getCString());
1881 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
1885 if (infoDict->lookup(key, &obj)->isString()) {
1886 s = obj.getString()->getCString();
1887 if (s[0] == 'D' && s[1] == ':') {
1895 void pdfswf_setparameter(char*name, char*value)
1897 if(!strcmp(name, "caplinewidth")) {
1898 caplinewidth = atof(value);
1899 } else if(!strcmp(name, "zoom")) {
1902 swfoutput_setparameter(name, value);
1905 void pdfswf_addfont(char*filename)
1908 memset(&f, 0, sizeof(fontfile_t));
1909 f.filename = filename;
1910 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
1911 fonts[fontnum++] = f;
1913 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
1917 typedef struct _pdf_doc_internal
1921 } pdf_doc_internal_t;
1922 typedef struct _pdf_page_internal
1924 } pdf_page_internal_t;
1925 typedef struct _swf_output_internal
1927 SWFOutputDev*outputDev;
1928 } swf_output_internal_t;
1930 pdf_doc_t* pdf_init(char*filename, char*userPassword)
1932 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
1933 memset(pdf_doc, 0, sizeof(pdf_doc_t));
1934 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
1935 memset(i, 0, sizeof(pdf_doc_internal_t));
1936 pdf_doc->internal = i;
1938 GString *fileName = new GString(filename);
1943 globalParams = new GlobalParams("");
1946 if (userPassword && userPassword[0]) {
1947 userPW = new GString(userPassword);
1951 i->doc = new PDFDoc(fileName, userPW);
1955 if (!i->doc->isOk()) {
1960 i->doc->getDocInfo(&info);
1961 if (info.isDict() &&
1962 (screenloglevel>=LOGLEVEL_NOTICE)) {
1963 printInfoString(info.getDict(), "Title", "Title: %s\n");
1964 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
1965 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
1966 printInfoString(info.getDict(), "Author", "Author: %s\n");
1967 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
1968 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
1969 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
1970 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
1971 printf("Pages: %d\n", i->doc->getNumPages());
1972 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
1973 printf("Encrypted: ");
1974 if (i->doc->isEncrypted()) {
1975 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
1976 i->doc->okToPrint() ? "yes" : "no",
1977 i->doc->okToCopy() ? "yes" : "no",
1978 i->doc->okToChange() ? "yes" : "no",
1979 i->doc->okToAddNotes() ? "yes" : "no");
1986 pdf_doc->num_pages = i->doc->getNumPages();
1988 if (i->doc->isEncrypted()) {
1989 if(!i->doc->okToCopy()) {
1990 printf("PDF disallows copying.\n");
1993 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2000 void pdfswf_preparepage(int page)
2004 pages = (int*)malloc(1024*sizeof(int));
2007 if(pagepos == pagebuflen)
2010 pages = (int*)realloc(pages, pagebuflen);
2013 pages[pagepos++] = page;
2020 delete globalParams;
2021 Object::memCheck(stderr);
2026 void pdf_destroy(pdf_doc_t*pdf_doc)
2028 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2030 msg("<debug> pdfswf.cc: pdfswf_close()");
2031 delete i->doc; i->doc=0;
2033 free(pages); pages = 0; //FIXME
2035 free(pdf_doc->internal);pdf_doc->internal=0;
2036 free(pdf_doc);pdf_doc=0;
2039 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2041 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2043 if(page < 1 || page > pdf_doc->num_pages)
2046 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2047 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2048 memset(pi, 0, sizeof(pdf_page_internal_t));
2049 pdf_page->internal = pi;
2051 pdf_page->parent = pdf_doc;
2052 pdf_page->nr = page;
2056 void pdf_page_destroy(pdf_page_t*pdf_page)
2058 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2059 free(pdf_page->internal);pdf_page->internal = 0;
2060 free(pdf_page);pdf_page=0;
2063 swf_output_t* swf_output_init()
2065 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2066 memset(swf_output, 0, sizeof(swf_output_t));
2067 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2068 memset(i, 0, sizeof(swf_output_internal_t));
2069 swf_output->internal = i;
2071 i->outputDev = new SWFOutputDev();
2075 void swf_output_setparameter(swf_output_t*swf_output, char*name, char*value)
2078 pdfswf_setparameter(name, value);
2081 int swf_output_save(swf_output_t*swf, char*filename)
2083 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2084 return i->outputDev->save(filename);
2087 void swf_output_destroy(swf_output_t*output)
2089 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2090 delete i->outputDev; i->outputDev=0;
2091 free(output->internal);output->internal=0;
2095 void pdf_page_render2(pdf_page_t*page, swf_output_t*output)
2097 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2098 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2101 swfoutput_setparameter("protect", "1");
2103 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2105 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2107 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2111 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2113 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2114 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2116 si->outputDev->setMove(x,y);
2117 if((x1|y1|x2|y2)==0) x2++;
2118 si->outputDev->setClip(x1,y1,x2,y2);
2120 pdf_page_render2(page, output);
2122 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2124 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2125 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2127 si->outputDev->setMove(0,0);
2128 si->outputDev->setClip(0,0,0,0);
2130 pdf_page_render2(page, output);
2134 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2136 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2137 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2138 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2139 memset(info, 0, sizeof(pdf_page_info_t));
2141 InfoOutputDev*output = new InfoOutputDev;
2144 pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2146 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2149 info->xMin = output->x1;
2150 info->yMin = output->y1;
2151 info->xMax = output->x2;
2152 info->yMax = output->y2;
2153 info->number_of_images = output->num_images;
2154 info->number_of_links = output->num_links;
2155 info->number_of_fonts = output->num_fonts;
2162 void pdf_page_info_destroy(pdf_page_info_t*info)