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"
29 #ifdef HAVE_SYS_STAT_H
32 #ifdef HAVE_FONTCONFIG_H
33 #include <fontconfig.h>
49 #include "OutputDev.h"
52 #include "CharCodeToUnicode.h"
53 #include "NameToUnicodeTable.h"
54 #include "GlobalParams.h"
59 #include "FoFiType1C.h"
60 #include "FoFiTrueType.h"
62 #include "SWFOutputDev.h"
64 //swftools header files
65 #include "swfoutput.h"
66 #include "../lib/log.h"
67 #include "../lib/gfxdevice.h"
72 typedef struct _fontfile
79 static fontfile_t fonts[2048];
80 static int fontnum = 0;
82 static int config_use_fontconfig = 1;
85 // TODO: move into pdf_doc_t
87 static int pagebuflen = 0;
88 static int pagepos = 0;
91 static double caplinewidth = 3.0;
92 static int zoom = 72; /* xpdf: 86 */
93 static int forceType0Fonts = 0;
95 static void printInfoString(Dict *infoDict, char *key, char *fmt);
96 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
102 {"Times-Roman", "n021003l"},
103 {"Times-Italic", "n021023l"},
104 {"Times-Bold", "n021004l"},
105 {"Times-BoldItalic", "n021024l"},
106 {"Helvetica", "n019003l"},
107 {"Helvetica-Oblique", "n019023l"},
108 {"Helvetica-Bold", "n019004l"},
109 {"Helvetica-BoldOblique", "n019024l"},
110 {"Courier", "n022003l"},
111 {"Courier-Oblique", "n022023l"},
112 {"Courier-Bold", "n022004l"},
113 {"Courier-BoldOblique", "n022024l"},
114 {"Symbol", "s050000l"},
115 {"ZapfDingbats", "d050000l"}};
117 class SWFOutputDev: public OutputDev {
119 struct swfoutput output;
126 virtual ~SWFOutputDev() ;
128 void setMove(int x,int y);
129 void setClip(int x1,int y1,int x2,int y2);
131 int save(char*filename);
135 void getDimensions(int*x1,int*y1,int*x2,int*y2);
137 //----- get info about output device
139 // Does this device use upside-down coordinates?
140 // (Upside-down means (0,0) is the top left corner of the page.)
141 virtual GBool upsideDown();
143 // Does this device use drawChar() or drawString()?
144 virtual GBool useDrawChar();
146 // Can this device draw gradients?
147 virtual GBool useGradients();
149 virtual GBool interpretType3Chars() {return gTrue;}
151 //----- initialization and control
153 void setXRef(PDFDoc*doc, XRef *xref);
156 virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
159 virtual void drawLink(Link *link, Catalog *catalog) ;
161 //----- save/restore graphics state
162 virtual void saveState(GfxState *state) ;
163 virtual void restoreState(GfxState *state) ;
165 //----- update graphics state
167 virtual void updateFont(GfxState *state);
168 virtual void updateFillColor(GfxState *state);
169 virtual void updateStrokeColor(GfxState *state);
170 virtual void updateLineWidth(GfxState *state);
171 virtual void updateLineJoin(GfxState *state);
172 virtual void updateLineCap(GfxState *state);
174 virtual void updateAll(GfxState *state)
177 updateFillColor(state);
178 updateStrokeColor(state);
179 updateLineWidth(state);
180 updateLineJoin(state);
181 updateLineCap(state);
184 //----- path painting
185 virtual void stroke(GfxState *state) ;
186 virtual void fill(GfxState *state) ;
187 virtual void eoFill(GfxState *state) ;
189 //----- path clipping
190 virtual void clip(GfxState *state) ;
191 virtual void eoClip(GfxState *state) ;
194 virtual void beginString(GfxState *state, GString *s) ;
195 virtual void endString(GfxState *state) ;
196 virtual void drawChar(GfxState *state, double x, double y,
197 double dx, double dy,
198 double originX, double originY,
199 CharCode code, Unicode *u, int uLen);
201 //----- image drawing
202 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
203 int width, int height, GBool invert,
205 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
206 int width, int height, GfxImageColorMap *colorMap,
207 int *maskColors, GBool inlineImg);
209 virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
210 virtual void endType3Char(GfxState *state);
212 virtual void type3D0(GfxState *state, double wx, double wy);
213 virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
216 void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
217 int width, int height, GfxImageColorMap*colorMap, GBool invert,
218 GBool inlineImg, int mask, int *maskColors);
227 char* searchFont(char*name);
228 char* substituteFont(GfxFont*gfxFont, char*oldname);
229 char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
231 int jpeginfo; // did we write "File contains jpegs" yet?
232 int pbminfo; // did we write "File contains jpegs" yet?
233 int linkinfo; // did we write "File contains links" yet?
234 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
235 int gradientinfo; // did we write "File contains Gradients yet?
237 int type3active; // are we between beginType3()/endType3()?
243 char* substitutetarget[256];
244 char* substitutesource[256];
247 int user_movex,user_movey;
248 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
251 static char*getFontID(GfxFont*font);
253 class InfoOutputDev: public OutputDev
267 virtual ~InfoOutputDev()
270 virtual GBool upsideDown() {return gTrue;}
271 virtual GBool useDrawChar() {return gTrue;}
272 virtual GBool useGradients() {return gTrue;}
273 virtual GBool interpretType3Chars() {return gTrue;}
274 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
277 state->transform(crop_x1,crop_y1,&x1,&y1);
278 state->transform(crop_x2,crop_y2,&x2,&y2);
279 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
280 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
286 virtual void drawLink(Link *link, Catalog *catalog)
290 virtual void updateFont(GfxState *state)
292 GfxFont*font = state->getFont();
295 char*id = getFontID(font);
299 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
300 int width, int height, GBool invert,
305 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
306 int width, int height, GfxImageColorMap *colorMap,
307 int *maskColors, GBool inlineImg)
313 SWFOutputDev::SWFOutputDev()
321 clipping[clippos] = 0;
332 memset(&output, 0, sizeof(output));
333 // printf("SWFOutputDev::SWFOutputDev() \n");
336 void SWFOutputDev::setMove(int x,int y)
338 this->user_movex = x;
339 this->user_movey = y;
342 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
344 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
345 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
347 this->user_clipx1 = x1;
348 this->user_clipy1 = y1;
349 this->user_clipx2 = x2;
350 this->user_clipy2 = y2;
352 void SWFOutputDev::getDimensions(int*x1,int*y1,int*x2,int*y2)
354 return swfoutput_getdimensions(&output, x1,y1,x2,y2);
357 static char*getFontID(GfxFont*font)
359 GString*gstr = font->getName();
360 char* fontname = gstr==0?0:gstr->getCString();
364 sprintf(buf, "UFONT%d", r->num);
367 return strdup(fontname);
370 static char*getFontName(GfxFont*font)
372 char*fontid = getFontID(font);
374 char* plus = strchr(fontid, '+');
375 if(plus && plus < &fontid[strlen(fontid)-1]) {
376 fontname = strdup(plus+1);
378 fontname = strdup(fontid);
384 static char mybuf[1024];
385 static char* gfxstate2str(GfxState *state)
389 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
396 if(state->getX1()!=0.0)
397 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
398 if(state->getY1()!=0.0)
399 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
400 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
401 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
402 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
403 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
404 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
405 state->getFillColor()->c[0], state->getFillColor()->c[1]);
406 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
407 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
408 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
409 state->getFillColor()->c[0], state->getFillColor()->c[1],
410 state->getFillColor()->c[2], state->getFillColor()->c[3],
411 state->getFillColor()->c[4], state->getFillColor()->c[5],
412 state->getFillColor()->c[6], state->getFillColor()->c[7]);
413 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
414 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
415 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
416 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
417 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
418 state->getFillRGB(&rgb);
419 if(rgb.r || rgb.g || rgb.b)
420 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
421 state->getStrokeRGB(&rgb);
422 if(rgb.r || rgb.g || rgb.b)
423 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
424 if(state->getFillColorSpace()->getNComps()>1)
425 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
426 if(state->getStrokeColorSpace()->getNComps()>1)
427 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
428 if(state->getFillPattern())
429 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
430 if(state->getStrokePattern())
431 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
433 if(state->getFillOpacity()!=1.0)
434 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
435 if(state->getStrokeOpacity()!=1.0)
436 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
438 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
443 state->getLineDash(&dash, &length, &start);
447 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
448 for(t=0;t<length;t++) {
449 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
451 bufpos+=sprintf(bufpos,"]");
454 if(state->getFlatness()!=1)
455 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
456 if(state->getLineJoin()!=0)
457 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
458 if(state->getLineJoin()!=0)
459 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
460 if(state->getLineJoin()!=0)
461 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
463 if(state->getFont() && getFontID(state->getFont()))
464 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
465 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
466 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
467 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
468 if(state->getCharSpace())
469 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
470 if(state->getWordSpace())
471 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
472 if(state->getHorizScaling()!=1.0)
473 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
474 if(state->getLeading())
475 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
477 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
478 if(state->getRender())
479 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
480 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
481 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
482 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
483 if(state->getLineX())
484 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
485 if(state->getLineY())
486 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
487 bufpos+=sprintf(bufpos," ");
491 static void dumpFontInfo(char*loglevel, GfxFont*font);
492 static int lastdumps[1024];
493 static int lastdumppos = 0;
498 static void showFontError(GfxFont*font, int nr)
502 for(t=0;t<lastdumppos;t++)
503 if(lastdumps[t] == r->num)
507 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
508 lastdumps[lastdumppos++] = r->num;
510 msg("<warning> The following font caused problems:");
512 msg("<warning> The following font caused problems (substituting):");
514 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
515 dumpFontInfo("<warning>", font);
518 static void dumpFontInfo(char*loglevel, GfxFont*font)
520 char* name = getFontID(font);
521 Ref* r=font->getID();
522 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, getFontName(font), r->num,r->gen);
524 GString*gstr = font->getTag();
526 msg("%s| Tag: %s\n", loglevel, name);
528 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
530 GfxFontType type=font->getType();
532 case fontUnknownType:
533 msg("%s| Type: unknown\n",loglevel);
536 msg("%s| Type: 1\n",loglevel);
539 msg("%s| Type: 1C\n",loglevel);
542 msg("%s| Type: 3\n",loglevel);
545 msg("%s| Type: TrueType\n",loglevel);
548 msg("%s| Type: CIDType0\n",loglevel);
551 msg("%s| Type: CIDType0C\n",loglevel);
554 msg("%s| Type: CIDType2\n",loglevel);
559 GBool embedded = font->getEmbeddedFontID(&embRef);
560 if(font->getEmbeddedFontName())
561 name = font->getEmbeddedFontName()->getCString();
563 msg("%s| Embedded name: %s id: %d\n",loglevel, FIXNULL(name), embRef.num);
565 gstr = font->getExtFontFile();
567 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
569 // Get font descriptor flags.
570 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
571 if(font->isSerif()) msg("%s| is serif\n", loglevel);
572 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
573 if(font->isItalic()) msg("%s| is italic\n", loglevel);
574 if(font->isBold()) msg("%s| is bold\n", loglevel);
577 //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");}
578 //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");}
581 void dump_outline(gfxline_t*line)
584 if(line->type == gfx_moveTo) {
585 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
586 } else if(line->type == gfx_lineTo) {
587 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
588 } else if(line->type == gfx_splineTo) {
589 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
595 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed)
597 int num = path->getNumSubpaths();
600 double lastx=0,lasty=0,posx=0,posy=0;
603 msg("<warning> empty path");
607 gfxdrawer_target_gfxline(&draw);
609 for(t = 0; t < num; t++) {
610 GfxSubpath *subpath = path->getSubpath(t);
611 int subnum = subpath->getNumPoints();
612 double bx=0,by=0,cx=0,cy=0;
614 for(s=0;s<subnum;s++) {
616 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
618 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
619 draw.lineTo(&draw, lastx, lasty);
621 draw.moveTo(&draw, x,y);
626 } else if(subpath->getCurve(s) && cpos==0) {
630 } else if(subpath->getCurve(s) && cpos==1) {
638 draw.lineTo(&draw, x,y);
640 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y);
647 /* fix non-closed lines */
648 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
649 draw.lineTo(&draw, lastx, lasty);
651 gfxline_t*result = (gfxline_t*)draw.result(&draw);
655 /*----------------------------------------------------------------------------
656 * Primitive Graphic routines
657 *----------------------------------------------------------------------------*/
659 void SWFOutputDev::stroke(GfxState *state)
661 GfxPath * path = state->getPath();
662 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
663 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
664 double miterLimit = state->getMiterLimit();
665 double width = state->getTransformedLineWidth();
668 double opaq = state->getStrokeOpacity();
670 state->getFillRGB(&rgb);
672 state->getStrokeRGB(&rgb);
674 col.r = (unsigned char)(rgb.r*255);
675 col.g = (unsigned char)(rgb.g*255);
676 col.b = (unsigned char)(rgb.b*255);
677 col.a = (unsigned char)(opaq*255);
679 gfx_capType capType = gfx_capRound;
680 if(lineCap == 0) capType = gfx_capButt;
681 else if(lineCap == 1) capType = gfx_capRound;
682 else if(lineCap == 2) capType = gfx_capSquare;
684 gfx_joinType joinType = gfx_joinRound;
685 if(lineJoin == 0) joinType = gfx_joinMiter;
686 else if(lineJoin == 1) joinType = gfx_joinRound;
687 else if(lineJoin == 2) joinType = gfx_joinBevel;
689 gfxline_t*line= gfxPath_to_gfxline(state, path, 0);
692 double dashphase = 0;
694 state->getLineDash(&ldash, &dashnum, &dashphase);
696 if(dashnum && ldash) {
697 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
701 msg("<trace> %d dashes", dashnum);
702 msg("<trace> | phase: %f", dashphase);
703 for(t=0;t<dashnum;t++) {
705 msg("<trace> | d%-3d: %f", t, ldash[t]);
708 if(getLogLevel() >= LOGLEVEL_TRACE) {
712 gfxline_t*line2 = gfxtool_dash_line(line, dash, dashphase);
715 msg("<trace> After dashing:");
718 if(getLogLevel() >= LOGLEVEL_TRACE) {
720 state->getStrokeGray(&gray);
721 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n",
723 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
724 lineCap==0?"butt": (lineJoin==1?"round":"square"),
726 col.r,col.g,col.b,col.a,
732 swfoutput_drawgfxline(&output, line, width, &col, capType, joinType, miterLimit);
735 void SWFOutputDev::fill(GfxState *state)
737 GfxPath * path = state->getPath();
738 double opaq = state->getFillOpacity();
740 state->getFillRGB(&rgb);
742 col.r = (unsigned char)(rgb.r*255);
743 col.g = (unsigned char)(rgb.g*255);
744 col.b = (unsigned char)(rgb.b*255);
745 col.a = (unsigned char)(opaq*255);
747 gfxline_t*line= gfxPath_to_gfxline(state, path, 1);
749 if(getLogLevel() >= LOGLEVEL_TRACE) {
750 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
754 swfoutput_fillgfxline(&output, line, &col);
757 void SWFOutputDev::eoFill(GfxState *state)
759 GfxPath * path = state->getPath();
760 double opaq = state->getFillOpacity();
762 state->getFillRGB(&rgb);
764 col.r = (unsigned char)(rgb.r*255);
765 col.g = (unsigned char)(rgb.g*255);
766 col.b = (unsigned char)(rgb.b*255);
767 col.a = (unsigned char)(opaq*255);
769 gfxline_t*line= gfxPath_to_gfxline(state, path, 1);
771 if(getLogLevel() >= LOGLEVEL_TRACE) {
772 msg("<trace> eofill\n");
776 swfoutput_fillgfxline(&output, line, &col);
779 void SWFOutputDev::clip(GfxState *state)
781 GfxPath * path = state->getPath();
782 gfxline_t*line = gfxPath_to_gfxline(state, path, 1);
784 if(getLogLevel() >= LOGLEVEL_TRACE) {
785 msg("<trace> clip\n");
789 swfoutput_startclip(&output, line);
790 clipping[clippos] ++;
793 void SWFOutputDev::eoClip(GfxState *state)
795 GfxPath * path = state->getPath();
796 gfxline_t*line = gfxPath_to_gfxline(state, path, 1);
798 if(getLogLevel() >= LOGLEVEL_TRACE) {
799 msg("<trace> eoclip\n");
803 swfoutput_startclip(&output, line);
804 clipping[clippos] ++;
808 /* pass through functions for swf_output */
809 int SWFOutputDev::save(char*filename)
811 return swfoutput_save(&output, filename);
813 void SWFOutputDev::pagefeed()
815 swfoutput_pagefeed(&output);
817 void* SWFOutputDev::getSWF()
819 return (void*)swfoutput_get(&output);
822 SWFOutputDev::~SWFOutputDev()
824 swfoutput_destroy(&output);
827 GBool SWFOutputDev::upsideDown()
829 msg("<debug> upsidedown? yes");
832 GBool SWFOutputDev::useDrawChar()
836 GBool SWFOutputDev::useGradients()
840 msg("<notice> File contains gradients");
846 void SWFOutputDev::beginString(GfxState *state, GString *s)
848 double m11,m21,m12,m22;
849 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
850 state->getFontTransMat(&m11, &m12, &m21, &m22);
851 m11 *= state->getHorizScaling();
852 m21 *= state->getHorizScaling();
853 swfoutput_setfontmatrix(&output, m11, -m21, m12, -m22);
856 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
857 double dx, double dy,
858 double originX, double originY,
859 CharCode c, Unicode *_u, int uLen)
861 // check for invisible text -- this is used by Acrobat Capture
862 if ((state->getRender() & 3) == 3)
865 double opaq = state->getFillOpacity();
866 state->getFillRGB(&rgb);
868 col.r = (unsigned char)(rgb.r*255);
869 col.g = (unsigned char)(rgb.g*255);
870 col.b = (unsigned char)(rgb.b*255);
871 col.a = (unsigned char)(opaq*255);
873 Gushort *CIDToGIDMap = 0;
874 GfxFont*font = state->getFont();
876 if(font->getType() == fontType3) {
877 /* type 3 chars are passed as graphics */
883 state->transform(x, y, &x1, &y1);
892 /* find out char name from unicode index
893 TODO: should be precomputed
895 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
896 if(nameToUnicodeTab[t].u == u) {
897 name = nameToUnicodeTab[t].name;
904 if(font->isCIDFont()) {
905 GfxCIDFont*cfont = (GfxCIDFont*)font;
907 if(font->getType() == fontCIDType2) {
908 CIDToGIDMap = cfont->getCIDToGID();
912 font8 = (Gfx8BitFont*)font;
913 char**enc=font8->getEncoding();
919 msg("<debug> drawChar(%f, %f, c='%c' (%d), GID=%d, u=%d <%d>) CID=%d name=\"%s\"\n", x, y, (c&127)>=32?c:'?', c, CIDToGIDMap[c], u, uLen, font->isCIDFont(), FIXNULL(name));
920 swfoutput_drawchar(&output, x1, y1, name, CIDToGIDMap[c], u, &col);
922 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));
923 swfoutput_drawchar(&output, x1, y1, name, c, u, &col);
927 void SWFOutputDev::endString(GfxState *state) {
930 /* the logic seems to be as following:
931 first, beginType3Char is called, with the charcode and the coordinates.
932 if this function returns true, it already knew about the char and has now drawn it.
933 if the function returns false, it's a new char, and type3D1 is called with some parameters-
934 the all draw operations until endType3Char are part of the char (which in this moment is
935 at the position first passed to beginType3Char). the char ends with endType3Char.
937 The drawing operations between beginType3Char and endType3Char are somewhat different to
938 the normal ones. For example, the fillcolor equals the stroke color.
941 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
943 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
945 /* the character itself is going to be passed using the draw functions */
946 return gFalse; /* gTrue= is_in_cache? */
949 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
950 msg("<debug> type3D0 width=%f height=%f", wx, wy);
952 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
953 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
957 void SWFOutputDev::endType3Char(GfxState *state)
960 msg("<debug> endType3Char");
963 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
965 this->currentpage = pageNum;
967 int rot = doc->getPageRotate(1);
969 msg("<verbose> startPage %d (%f,%f,%f,%f)\n", pageNum, crop_x1, crop_y1, crop_x2, crop_y2);
971 msg("<verbose> page is rotated %d degrees\n", rot);
973 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
974 state->transform(state->getX2(),state->getY2(),&x2,&y2);
975 Use CropBox, not MediaBox, as page size
982 state->transform(crop_x1,crop_y1,&x1,&y1);
983 state->transform(crop_x2,crop_y2,&x2,&y2);
985 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
986 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
988 /* apply user clip box */
989 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
990 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
991 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
992 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
993 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
997 msg("<verbose> Bounding box is (%f,%f)-(%f,%f)", x1,y1,x2,y2);
998 swfoutput_init(&output);
1002 swfoutput_newpage(&output, pageNum, user_movex, user_movey, (int)x1, (int)y1, (int)x2, (int)y2);
1005 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1007 msg("<debug> drawlink\n");
1008 double x1, y1, x2, y2, w;
1014 link->getBorder(&x1, &y1, &x2, &y2, &w);
1016 link->getRect(&x1, &y1, &x2, &y2);
1021 cvtUserToDev(x1, y1, &x, &y);
1022 points[0].x = points[4].x = (int)x;
1023 points[0].y = points[4].y = (int)y;
1024 cvtUserToDev(x2, y1, &x, &y);
1025 points[1].x = (int)x;
1026 points[1].y = (int)y;
1027 cvtUserToDev(x2, y2, &x, &y);
1028 points[2].x = (int)x;
1029 points[2].y = (int)y;
1030 cvtUserToDev(x1, y2, &x, &y);
1031 points[3].x = (int)x;
1032 points[3].y = (int)y;
1034 LinkAction*action=link->getAction();
1041 switch(action->getKind())
1045 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1046 LinkDest *dest=NULL;
1047 if (ha->getDest()==NULL)
1048 dest=catalog->findDest(ha->getNamedDest());
1049 else dest=ha->getDest();
1051 if (dest->isPageRef()){
1052 Ref pageref=dest->getPageRef();
1053 page=catalog->findPage(pageref.num,pageref.gen);
1055 else page=dest->getPageNum();
1056 sprintf(buf, "%d", page);
1063 LinkGoToR*l = (LinkGoToR*)action;
1064 GString*g = l->getNamedDest();
1066 s = strdup(g->getCString());
1071 LinkNamed*l = (LinkNamed*)action;
1072 GString*name = l->getName();
1074 s = strdup(name->lowerCase()->getCString());
1075 named = name->getCString();
1078 if(strstr(s, "next") || strstr(s, "forward"))
1080 page = currentpage + 1;
1082 else if(strstr(s, "prev") || strstr(s, "back"))
1084 page = currentpage - 1;
1086 else if(strstr(s, "last") || strstr(s, "end"))
1088 page = pagepos>0?pages[pagepos-1]:0;
1090 else if(strstr(s, "first") || strstr(s, "top"))
1098 case actionLaunch: {
1100 LinkLaunch*l = (LinkLaunch*)action;
1101 GString * str = new GString(l->getFileName());
1102 str->append(l->getParams());
1103 s = strdup(str->getCString());
1109 LinkURI*l = (LinkURI*)action;
1110 GString*g = l->getURI();
1112 url = g->getCString();
1117 case actionUnknown: {
1119 LinkUnknown*l = (LinkUnknown*)action;
1124 msg("<error> Unknown link type!\n");
1128 if(!s) s = strdup("-?-");
1130 if(!linkinfo && (page || url))
1132 msg("<notice> File contains links");
1138 for(t=0;t<pagepos;t++)
1142 swfoutput_linktopage(&output, t, points);
1146 swfoutput_linktourl(&output, url, points);
1150 swfoutput_namedlink(&output, named, points);
1152 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1156 void SWFOutputDev::saveState(GfxState *state) {
1157 msg("<debug> saveState\n");
1162 msg("<error> Too many nested states in pdf.");
1163 clipping[clippos] = 0;
1166 void SWFOutputDev::restoreState(GfxState *state) {
1167 msg("<debug> restoreState\n");
1169 while(clipping[clippos]) {
1170 swfoutput_endclip(&output);
1171 clipping[clippos]--;
1176 char* SWFOutputDev::searchFont(char*name)
1180 int is_standard_font = 0;
1182 msg("<verbose> SearchFont(%s)", name);
1184 /* see if it is a pdf standard font */
1185 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1187 if(!strcmp(name, pdf2t1map[i].pdffont))
1189 name = pdf2t1map[i].filename;
1190 is_standard_font = 1;
1194 /* look in all font files */
1195 for(i=0;i<fontnum;i++)
1197 if(strstr(fonts[i].filename, name))
1199 if(!fonts[i].used) {
1202 if(!is_standard_font)
1203 msg("<notice> Using %s for %s", fonts[i].filename, name);
1205 return strdup(fonts[i].filename);
1211 void SWFOutputDev::updateLineWidth(GfxState *state)
1213 double width = state->getTransformedLineWidth();
1214 //swfoutput_setlinewidth(&output, width);
1217 void SWFOutputDev::updateLineCap(GfxState *state)
1219 int c = state->getLineCap();
1222 void SWFOutputDev::updateLineJoin(GfxState *state)
1224 int j = state->getLineJoin();
1227 void SWFOutputDev::updateFillColor(GfxState *state)
1230 double opaq = state->getFillOpacity();
1231 state->getFillRGB(&rgb);
1233 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1236 void SWFOutputDev::updateStrokeColor(GfxState *state)
1239 double opaq = state->getStrokeOpacity();
1240 state->getStrokeRGB(&rgb);
1241 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1244 void FoFiWrite(void *stream, char *data, int len)
1246 fwrite(data, len, 1, (FILE*)stream);
1249 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1251 char*tmpFileName = NULL;
1257 Object refObj, strObj;
1259 tmpFileName = mktmpname(namebuf);
1262 ret = font->getEmbeddedFontID(&embRef);
1264 msg("<verbose> Didn't get embedded font id");
1265 /* not embedded- the caller should now search the font
1266 directories for this font */
1270 f = fopen(tmpFileName, "wb");
1272 msg("<error> Couldn't create temporary Type 1 font file");
1276 /*if(font->isCIDFont()) {
1277 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1278 GString c = cidFont->getCollection();
1279 msg("<notice> Collection: %s", c.getCString());
1282 if (font->getType() == fontType1C) {
1283 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1285 msg("<error> Couldn't read embedded font file");
1289 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1291 cvt->convertToType1(f);
1293 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1295 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1297 //cvt->convertToCIDType0("test", f);
1298 //cvt->convertToType0("test", f);
1301 } else if(font->getType() == fontTrueType) {
1302 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1303 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1305 msg("<error> Couldn't read embedded font file");
1309 TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1312 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1313 cvt->writeTTF(FoFiWrite, f);
1318 font->getEmbeddedFontID(&embRef);
1319 refObj.initRef(embRef.num, embRef.gen);
1320 refObj.fetch(ref, &strObj);
1322 strObj.streamReset();
1327 f4[t] = strObj.streamGetChar();
1328 f4c[t] = (char)f4[t];
1333 if(!strncmp(f4c, "true", 4)) {
1334 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1335 Change this on the fly */
1336 f4[0] = f4[2] = f4[3] = 0;
1344 while ((c = strObj.streamGetChar()) != EOF) {
1348 strObj.streamClose();
1353 return strdup(tmpFileName);
1356 char* searchForSuitableFont(GfxFont*gfxFont)
1358 char*name = getFontName(gfxFont);
1362 if(!config_use_fontconfig)
1365 #ifdef HAVE_FONTCONFIG
1366 FcPattern *pattern, *match;
1370 static int fcinitcalled = false;
1372 msg("<debug> searchForSuitableFont(%s)", name);
1374 // call init ony once
1375 if (!fcinitcalled) {
1376 msg("<debug> Initializing FontConfig...");
1377 fcinitcalled = true;
1379 msg("<debug> FontConfig Initialization failed. Disabling.");
1380 config_use_fontconfig = 0;
1383 msg("<debug> ...initialized FontConfig");
1386 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1387 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1388 if (gfxFont->isItalic()) // check for italic
1389 msg("<debug> FontConfig: Adding Italic Slant");
1390 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1391 if (gfxFont->isBold()) // check for bold
1392 msg("<debug> FontConfig: Adding Bold Weight");
1393 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1395 msg("<debug> FontConfig: Try to match...");
1396 // configure and match using the original font name
1397 FcConfigSubstitute(0, pattern, FcMatchPattern);
1398 FcDefaultSubstitute(pattern);
1399 match = FcFontMatch(0, pattern, &result);
1401 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1402 msg("<debug> FontConfig: family=%s", (char*)v);
1403 // if we get an exact match
1404 if (strcmp((char *)v, name) == 0) {
1405 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1406 filename = strdup((char*)v);
1407 char *nfn = strrchr(filename, '/');
1408 if(nfn) fontname = strdup(nfn+1);
1409 else fontname = filename;
1411 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1413 // initialize patterns
1414 FcPatternDestroy(pattern);
1415 FcPatternDestroy(match);
1417 // now match against serif etc.
1418 if (gfxFont->isSerif()) {
1419 msg("<debug> FontConfig: Create Serif Family Pattern");
1420 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1421 } else if (gfxFont->isFixedWidth()) {
1422 msg("<debug> FontConfig: Create Monospace Family Pattern");
1423 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1425 msg("<debug> FontConfig: Create Sans Family Pattern");
1426 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1430 if (gfxFont->isItalic()) {
1431 msg("<debug> FontConfig: Adding Italic Slant");
1432 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1435 if (gfxFont->isBold()) {
1436 msg("<debug> FontConfig: Adding Bold Weight");
1437 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1440 msg("<debug> FontConfig: Try to match... (2)");
1441 // configure and match using serif etc
1442 FcConfigSubstitute (0, pattern, FcMatchPattern);
1443 FcDefaultSubstitute (pattern);
1444 match = FcFontMatch (0, pattern, &result);
1446 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1447 filename = strdup((char*)v);
1448 char *nfn = strrchr(filename, '/');
1449 if(nfn) fontname = strdup(nfn+1);
1450 else fontname = filename;
1452 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1456 //printf("FONTCONFIG: pattern");
1457 //FcPatternPrint(pattern);
1458 //printf("FONTCONFIG: match");
1459 //FcPatternPrint(match);
1461 FcPatternDestroy(pattern);
1462 FcPatternDestroy(match);
1464 pdfswf_addfont(filename);
1471 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1473 char*fontname = 0, *filename = 0;
1474 msg("<notice> subsituteFont(%s)", oldname);
1476 if(!(fontname = searchForSuitableFont(gfxFont))) {
1477 fontname = "Times-Roman";
1479 filename = searchFont(fontname);
1481 msg("<error> Couldn't find font %s- did you install the default fonts?");
1485 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1486 msg("<fatal> Too many fonts in file.");
1490 substitutesource[substitutepos] = oldname;
1491 substitutetarget[substitutepos] = fontname;
1492 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1495 return strdup(filename);
1498 void unlinkfont(char* filename)
1505 if(!strncmp(&filename[l-4],".afm",4)) {
1506 memcpy(&filename[l-4],".pfb",4);
1508 memcpy(&filename[l-4],".pfa",4);
1510 memcpy(&filename[l-4],".afm",4);
1513 if(!strncmp(&filename[l-4],".pfa",4)) {
1514 memcpy(&filename[l-4],".afm",4);
1516 memcpy(&filename[l-4],".pfa",4);
1519 if(!strncmp(&filename[l-4],".pfb",4)) {
1520 memcpy(&filename[l-4],".afm",4);
1522 memcpy(&filename[l-4],".pfb",4);
1527 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1534 void SWFOutputDev::updateFont(GfxState *state)
1536 GfxFont*gfxFont = state->getFont();
1541 char * fontid = getFontID(gfxFont);
1544 /* first, look if we substituted this font before-
1545 this way, we don't initialize the T1 Fonts
1547 for(t=0;t<substitutepos;t++) {
1548 if(!strcmp(fontid, substitutesource[t])) {
1549 fontid = substitutetarget[t];
1554 /* second, see if swfoutput already has this font
1555 cached- if so, we are done */
1556 if(swfoutput_queryfont(&output, fontid))
1558 swfoutput_setfont(&output, fontid, 0);
1560 msg("<debug> updateFont(%s) [cached]", fontid);
1564 // look for Type 3 font
1565 if (gfxFont->getType() == fontType3) {
1567 type3Warning = gTrue;
1568 showFontError(gfxFont, 2);
1573 /* now either load the font, or find a substitution */
1576 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1581 (gfxFont->getType() == fontType1 ||
1582 gfxFont->getType() == fontType1C ||
1583 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
1584 gfxFont->getType() == fontTrueType ||
1585 gfxFont->getType() == fontCIDType2
1588 fileName = writeEmbeddedFontToFile(xref, gfxFont);
1589 if(!fileName) showFontError(gfxFont,0);
1592 char * fontname = getFontName(gfxFont);
1593 fileName = searchFont(fontname);
1594 if(!fileName) showFontError(gfxFont,0);
1597 char * fontname = getFontName(gfxFont);
1598 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
1599 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
1600 fileName = substituteFont(gfxFont, fontid);
1601 if(fontid) { fontid = substitutetarget[substitutepos-1]; /*ugly hack*/};
1602 msg("<notice> Font is now %s (%s)", fontid, fileName);
1606 msg("<error> Couldn't set font %s\n", fontid);
1610 msg("<verbose> updateFont(%s) -> %s", fontid, fileName);
1611 dumpFontInfo("<verbose>", gfxFont);
1613 swfoutput_setfont(&output, fontid, fileName);
1616 unlinkfont(fileName);
1621 #define SQR(x) ((x)*(x))
1623 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1625 if((newwidth<2 || newheight<2) ||
1626 (width<=newwidth || height<=newheight))
1628 unsigned char*newdata;
1630 newdata= (unsigned char*)malloc(newwidth*newheight);
1632 double fx = (double)(width)/newwidth;
1633 double fy = (double)(height)/newheight;
1635 int blocksize = (int)(8192/(fx*fy));
1636 int r = 8192*256/palettesize;
1637 for(x=0;x<newwidth;x++) {
1638 double ex = px + fx;
1639 int fromx = (int)px;
1641 int xweight1 = (int)(((fromx+1)-px)*256);
1642 int xweight2 = (int)((ex-tox)*256);
1644 for(y=0;y<newheight;y++) {
1645 double ey = py + fy;
1646 int fromy = (int)py;
1648 int yweight1 = (int)(((fromy+1)-py)*256);
1649 int yweight2 = (int)((ey-toy)*256);
1652 for(xx=fromx;xx<=tox;xx++)
1653 for(yy=fromy;yy<=toy;yy++) {
1654 int b = 1-data[width*yy+xx];
1656 if(xx==fromx) weight = (weight*xweight1)/256;
1657 if(xx==tox) weight = (weight*xweight2)/256;
1658 if(yy==fromy) weight = (weight*yweight1)/256;
1659 if(yy==toy) weight = (weight*yweight2)/256;
1662 //if(a) a=(palettesize-1)*r/blocksize;
1663 newdata[y*newwidth+x] = (a*blocksize)/r;
1671 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
1672 int width, int height, GfxImageColorMap*colorMap, GBool invert,
1673 GBool inlineImg, int mask, int*maskColors)
1678 double x1,y1,x2,y2,x3,y3,x4,y4;
1679 ImageStream *imgStr;
1686 ncomps = colorMap->getNumPixelComps();
1687 bits = colorMap->getBits();
1689 imgStr = new ImageStream(str, width, ncomps,bits);
1692 if(!width || !height || (height<=1 && width<=1))
1694 msg("<verbose> Ignoring %d by %d image", width, height);
1695 unsigned char buf[8];
1697 for (y = 0; y < height; ++y)
1698 for (x = 0; x < width; ++x) {
1699 imgStr->getPixel(buf);
1705 state->transform(0, 1, &x1, &y1);
1706 state->transform(0, 0, &x2, &y2);
1707 state->transform(1, 0, &x3, &y3);
1708 state->transform(1, 1, &x4, &y4);
1710 if(!pbminfo && !(str->getKind()==strDCT)) {
1712 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
1716 msg("<verbose> drawing %d by %d masked picture\n", width, height);
1718 if(!jpeginfo && (str->getKind()==strDCT)) {
1719 msg("<notice> file contains jpeg pictures");
1725 unsigned char buf[8];
1727 unsigned char*pic = new unsigned char[width*height];
1730 state->getFillRGB(&rgb);
1732 memset(pal,255,sizeof(pal));
1733 pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
1734 pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
1735 pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
1736 pal[0].a = 255; pal[1].a = 0;
1739 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
1740 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
1741 for (y = 0; y < height; ++y)
1742 for (x = 0; x < width; ++x)
1744 imgStr->getPixel(buf);
1747 pic[width*y+x] = buf[0];
1750 /* the size of the drawn image is added to the identifier
1751 as the same image may require different bitmaps if displayed
1752 at different sizes (due to antialiasing): */
1755 unsigned char*pic2 = 0;
1758 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
1767 height = realheight;
1771 /* make a black/white palette */
1776 float r = 255/(numpalette-1);
1778 for(t=0;t<numpalette;t++) {
1779 pal[t].r = (U8)(255*rgb.r);
1780 pal[t].g = (U8)(255*rgb.g);
1781 pal[t].b = (U8)(255*rgb.b);
1782 pal[t].a = (U8)(t*r);
1786 RGBA*pic2 = new RGBA[width*height];
1787 for (y = 0; y < height; ++y) {
1788 for (x = 0; x < width; ++x) {
1789 pic2[width*y+x] = pal[pic[y*width+x]];
1792 swfoutput_drawimagelossless(&output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1801 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
1802 RGBA*pic=new RGBA[width*height];
1803 for (y = 0; y < height; ++y) {
1804 for (x = 0; x < width; ++x) {
1805 imgStr->getPixel(pixBuf);
1806 colorMap->getRGB(pixBuf, &rgb);
1807 pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
1808 pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
1809 pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
1810 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
1813 if(str->getKind()==strDCT)
1814 swfoutput_drawimagejpeg(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1816 swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1821 RGBA*pic=new RGBA[width*height];
1824 for(t=0;t<256;t++) {
1826 colorMap->getRGB(pixBuf, &rgb);
1827 /*if(maskColors && *maskColors==t) {
1828 msg("<notice> Color %d is transparent", t);
1829 if (imgData->maskColors) {
1831 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
1832 if (pix[i] < imgData->maskColors[2*i] ||
1833 pix[i] > imgData->maskColors[2*i+1]) {
1848 pal[t].r = (U8)(rgb.r * 255 + 0.5);
1849 pal[t].g = (U8)(rgb.g * 255 + 0.5);
1850 pal[t].b = (U8)(rgb.b * 255 + 0.5);
1851 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
1854 for (y = 0; y < height; ++y) {
1855 for (x = 0; x < width; ++x) {
1856 imgStr->getPixel(pixBuf);
1857 pic[width*y+x] = pal[pixBuf[0]];
1860 swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1868 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
1869 int width, int height, GBool invert,
1872 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
1873 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
1876 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
1877 int width, int height, GfxImageColorMap *colorMap,
1878 int *maskColors, GBool inlineImg)
1880 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
1881 colorMap?"colorMap":"no colorMap",
1882 maskColors?"maskColors":"no maskColors",
1885 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
1886 colorMap->getBits(),colorMap->getColorSpace()->getMode());
1887 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
1890 SWFOutputDev*output = 0;
1892 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
1897 if (infoDict->lookup(key, &obj)->isString()) {
1898 s1 = obj.getString();
1899 if ((s1->getChar(0) & 0xff) == 0xfe &&
1900 (s1->getChar(1) & 0xff) == 0xff) {
1902 for (i = 2; i < obj.getString()->getLength(); i += 2) {
1903 if (s1->getChar(i) == '\0') {
1904 s2->append(s1->getChar(i+1));
1907 s2 = new GString("<unicode>");
1911 printf(fmt, s2->getCString());
1914 printf(fmt, s1->getCString());
1920 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
1924 if (infoDict->lookup(key, &obj)->isString()) {
1925 s = obj.getString()->getCString();
1926 if (s[0] == 'D' && s[1] == ':') {
1937 void pdfswf_setparameter(char*name, char*value)
1939 msg("<verbose> setting parameter %s to \"%s\"", name, value);
1940 if(!strcmp(name, "caplinewidth")) {
1941 caplinewidth = atof(value);
1942 } else if(!strcmp(name, "zoom")) {
1945 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
1946 swfoutput_setparameter("jpegsubpixels", buf);
1947 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
1948 swfoutput_setparameter("ppmsubpixels", buf);
1949 } else if(!strcmp(name, "jpegdpi")) {
1951 jpeg_dpi = atoi(value);
1952 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
1953 swfoutput_setparameter("jpegsubpixels", buf);
1954 } else if(!strcmp(name, "ppmdpi")) {
1956 ppm_dpi = atoi(value);
1957 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
1958 swfoutput_setparameter("ppmsubpixels", buf);
1959 } else if(!strcmp(name, "forceType0Fonts")) {
1960 forceType0Fonts = atoi(value);
1961 } else if(!strcmp(name, "fontdir")) {
1962 pdfswf_addfontdir(value);
1963 } else if(!strcmp(name, "languagedir")) {
1964 pdfswf_addlanguagedir(value);
1965 } else if(!strcmp(name, "fontconfig")) {
1966 config_use_fontconfig = atoi(value);
1968 swfoutput_setparameter(name, value);
1971 void pdfswf_addfont(char*filename)
1974 memset(&f, 0, sizeof(fontfile_t));
1975 f.filename = filename;
1976 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
1977 fonts[fontnum++] = f;
1979 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
1983 static char* dirseparator()
1992 void pdfswf_addlanguagedir(char*dir)
1995 globalParams = new GlobalParams("");
1997 msg("<notice> Adding %s to language pack directories", dir);
2001 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2002 strcpy(config_file, dir);
2003 strcat(config_file, dirseparator());
2004 strcat(config_file, "add-to-xpdfrc");
2006 fi = fopen(config_file, "rb");
2008 msg("<error> Could not open %s", config_file);
2011 globalParams->parseFile(new GString(config_file), fi);
2015 void pdfswf_addfontdir(char*dirname)
2017 #ifdef HAVE_DIRENT_H
2018 msg("<notice> Adding %s to font directories", dirname);
2019 DIR*dir = opendir(dirname);
2021 msg("<warning> Couldn't open directory %s\n", dirname);
2026 ent = readdir (dir);
2030 char*name = ent->d_name;
2036 if(!strncasecmp(&name[l-4], ".pfa", 4))
2038 if(!strncasecmp(&name[l-4], ".pfb", 4))
2040 if(!strncasecmp(&name[l-4], ".ttf", 4))
2044 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2045 strcpy(fontname, dirname);
2046 strcat(fontname, dirseparator());
2047 strcat(fontname, name);
2048 msg("<verbose> Adding %s to fonts", fontname);
2049 pdfswf_addfont(fontname);
2054 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2059 typedef struct _pdf_doc_internal
2063 } pdf_doc_internal_t;
2064 typedef struct _pdf_page_internal
2066 } pdf_page_internal_t;
2067 typedef struct _swf_output_internal
2069 SWFOutputDev*outputDev;
2070 } swf_output_internal_t;
2072 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2074 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2075 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2076 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2077 memset(i, 0, sizeof(pdf_doc_internal_t));
2078 pdf_doc->internal = i;
2080 GString *fileName = new GString(filename);
2086 globalParams = new GlobalParams("");
2089 if (userPassword && userPassword[0]) {
2090 userPW = new GString(userPassword);
2094 i->doc = new PDFDoc(fileName, userPW);
2098 if (!i->doc->isOk()) {
2103 i->doc->getDocInfo(&info);
2104 if (info.isDict() &&
2105 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2106 printInfoString(info.getDict(), "Title", "Title: %s\n");
2107 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2108 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2109 printInfoString(info.getDict(), "Author", "Author: %s\n");
2110 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2111 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2112 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2113 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2114 printf("Pages: %d\n", i->doc->getNumPages());
2115 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2116 printf("Encrypted: ");
2117 if (i->doc->isEncrypted()) {
2118 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2119 i->doc->okToPrint() ? "yes" : "no",
2120 i->doc->okToCopy() ? "yes" : "no",
2121 i->doc->okToChange() ? "yes" : "no",
2122 i->doc->okToAddNotes() ? "yes" : "no");
2129 pdf_doc->num_pages = i->doc->getNumPages();
2131 if (i->doc->isEncrypted()) {
2132 if(!i->doc->okToCopy()) {
2133 printf("PDF disallows copying.\n");
2136 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2143 void pdfswf_preparepage(int page)
2147 pages = (int*)malloc(1024*sizeof(int));
2150 if(pagepos == pagebuflen)
2153 pages = (int*)realloc(pages, pagebuflen);
2156 pages[pagepos++] = page;
2163 delete globalParams;globalParams=0;
2164 Object::memCheck(stderr);
2169 void pdf_destroy(pdf_doc_t*pdf_doc)
2171 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2173 msg("<debug> pdfswf.cc: pdfswf_close()");
2174 delete i->doc; i->doc=0;
2176 free(pages); pages = 0; //FIXME
2178 free(pdf_doc->internal);pdf_doc->internal=0;
2179 free(pdf_doc);pdf_doc=0;
2182 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2184 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2186 if(page < 1 || page > pdf_doc->num_pages)
2189 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2190 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2191 memset(pi, 0, sizeof(pdf_page_internal_t));
2192 pdf_page->internal = pi;
2194 pdf_page->parent = pdf_doc;
2195 pdf_page->nr = page;
2199 void pdf_page_destroy(pdf_page_t*pdf_page)
2201 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2202 free(pdf_page->internal);pdf_page->internal = 0;
2203 free(pdf_page);pdf_page=0;
2206 swf_output_t* swf_output_init()
2208 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2209 memset(swf_output, 0, sizeof(swf_output_t));
2210 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2211 memset(i, 0, sizeof(swf_output_internal_t));
2212 swf_output->internal = i;
2214 i->outputDev = new SWFOutputDev();
2218 void swf_output_setparameter(swf_output_t*swf_output, char*name, char*value)
2221 pdfswf_setparameter(name, value);
2224 void swf_output_pagefeed(swf_output_t*swf)
2226 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2227 i->outputDev->pagefeed();
2228 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2231 int swf_output_save(swf_output_t*swf, char*filename)
2233 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2234 int ret = i->outputDev->save(filename);
2235 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2239 void* swf_output_get(swf_output_t*swf)
2241 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2242 void* ret = i->outputDev->getSWF();
2243 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2247 void swf_output_destroy(swf_output_t*output)
2249 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2250 delete i->outputDev; i->outputDev=0;
2251 free(output->internal);output->internal=0;
2255 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2257 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2258 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2261 swfoutput_setparameter("protect", "1");
2263 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2265 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2267 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2269 si->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2272 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2274 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2275 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2277 si->outputDev->setMove(x,y);
2278 if((x1|y1|x2|y2)==0) x2++;
2279 si->outputDev->setClip(x1,y1,x2,y2);
2281 pdf_page_render2(page, output);
2283 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2285 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2286 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2288 si->outputDev->setMove(0,0);
2289 si->outputDev->setClip(0,0,0,0);
2291 pdf_page_render2(page, output);
2295 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2297 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2298 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2299 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2300 memset(info, 0, sizeof(pdf_page_info_t));
2302 InfoOutputDev*output = new InfoOutputDev;
2305 pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2307 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2310 info->xMin = output->x1;
2311 info->yMin = output->y1;
2312 info->xMax = output->x2;
2313 info->yMax = output->y2;
2314 info->number_of_images = output->num_images;
2315 info->number_of_links = output->num_links;
2316 info->number_of_fonts = output->num_fonts;
2323 void pdf_page_info_destroy(pdf_page_info_t*info)