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 font->getType() == fontCIDType0C) {
1284 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1286 msg("<error> Couldn't read embedded font file");
1290 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1292 cvt->convertToType1(f);
1294 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1296 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1298 //cvt->convertToCIDType0("test", f);
1299 //cvt->convertToType0("test", f);
1302 } else if(font->getType() == fontTrueType) {
1303 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1304 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1306 msg("<error> Couldn't read embedded font file");
1310 TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1313 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1314 cvt->writeTTF(FoFiWrite, f);
1319 font->getEmbeddedFontID(&embRef);
1320 refObj.initRef(embRef.num, embRef.gen);
1321 refObj.fetch(ref, &strObj);
1323 strObj.streamReset();
1328 f4[t] = strObj.streamGetChar();
1329 f4c[t] = (char)f4[t];
1334 if(!strncmp(f4c, "true", 4)) {
1335 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1336 Change this on the fly */
1337 f4[0] = f4[2] = f4[3] = 0;
1345 while ((c = strObj.streamGetChar()) != EOF) {
1349 strObj.streamClose();
1354 return strdup(tmpFileName);
1357 char* searchForSuitableFont(GfxFont*gfxFont)
1359 char*name = getFontName(gfxFont);
1363 if(!config_use_fontconfig)
1366 #ifdef HAVE_FONTCONFIG
1367 FcPattern *pattern, *match;
1371 static int fcinitcalled = false;
1373 msg("<debug> searchForSuitableFont(%s)", name);
1375 // call init ony once
1376 if (!fcinitcalled) {
1377 msg("<debug> Initializing FontConfig...");
1378 fcinitcalled = true;
1380 msg("<debug> FontConfig Initialization failed. Disabling.");
1381 config_use_fontconfig = 0;
1384 msg("<debug> ...initialized FontConfig");
1387 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1388 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1389 if (gfxFont->isItalic()) // check for italic
1390 msg("<debug> FontConfig: Adding Italic Slant");
1391 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1392 if (gfxFont->isBold()) // check for bold
1393 msg("<debug> FontConfig: Adding Bold Weight");
1394 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1396 msg("<debug> FontConfig: Try to match...");
1397 // configure and match using the original font name
1398 FcConfigSubstitute(0, pattern, FcMatchPattern);
1399 FcDefaultSubstitute(pattern);
1400 match = FcFontMatch(0, pattern, &result);
1402 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1403 msg("<debug> FontConfig: family=%s", (char*)v);
1404 // if we get an exact match
1405 if (strcmp((char *)v, name) == 0) {
1406 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1407 filename = strdup((char*)v);
1408 char *nfn = strrchr(filename, '/');
1409 if(nfn) fontname = strdup(nfn+1);
1410 else fontname = filename;
1412 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1414 // initialize patterns
1415 FcPatternDestroy(pattern);
1416 FcPatternDestroy(match);
1418 // now match against serif etc.
1419 if (gfxFont->isSerif()) {
1420 msg("<debug> FontConfig: Create Serif Family Pattern");
1421 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1422 } else if (gfxFont->isFixedWidth()) {
1423 msg("<debug> FontConfig: Create Monospace Family Pattern");
1424 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1426 msg("<debug> FontConfig: Create Sans Family Pattern");
1427 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1431 if (gfxFont->isItalic()) {
1432 msg("<debug> FontConfig: Adding Italic Slant");
1433 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1436 if (gfxFont->isBold()) {
1437 msg("<debug> FontConfig: Adding Bold Weight");
1438 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1441 msg("<debug> FontConfig: Try to match... (2)");
1442 // configure and match using serif etc
1443 FcConfigSubstitute (0, pattern, FcMatchPattern);
1444 FcDefaultSubstitute (pattern);
1445 match = FcFontMatch (0, pattern, &result);
1447 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1448 filename = strdup((char*)v);
1449 char *nfn = strrchr(filename, '/');
1450 if(nfn) fontname = strdup(nfn+1);
1451 else fontname = filename;
1453 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1457 //printf("FONTCONFIG: pattern");
1458 //FcPatternPrint(pattern);
1459 //printf("FONTCONFIG: match");
1460 //FcPatternPrint(match);
1462 FcPatternDestroy(pattern);
1463 FcPatternDestroy(match);
1465 pdfswf_addfont(filename);
1472 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1474 char*fontname = 0, *filename = 0;
1475 msg("<notice> subsituteFont(%s)", oldname);
1477 if(!(fontname = searchForSuitableFont(gfxFont))) {
1478 fontname = "Times-Roman";
1480 filename = searchFont(fontname);
1482 msg("<error> Couldn't find font %s- did you install the default fonts?");
1486 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1487 msg("<fatal> Too many fonts in file.");
1491 substitutesource[substitutepos] = oldname;
1492 substitutetarget[substitutepos] = fontname;
1493 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1496 return strdup(filename);
1499 void unlinkfont(char* filename)
1506 if(!strncmp(&filename[l-4],".afm",4)) {
1507 memcpy(&filename[l-4],".pfb",4);
1509 memcpy(&filename[l-4],".pfa",4);
1511 memcpy(&filename[l-4],".afm",4);
1514 if(!strncmp(&filename[l-4],".pfa",4)) {
1515 memcpy(&filename[l-4],".afm",4);
1517 memcpy(&filename[l-4],".pfa",4);
1520 if(!strncmp(&filename[l-4],".pfb",4)) {
1521 memcpy(&filename[l-4],".afm",4);
1523 memcpy(&filename[l-4],".pfb",4);
1528 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1535 void SWFOutputDev::updateFont(GfxState *state)
1537 GfxFont*gfxFont = state->getFont();
1542 char * fontid = getFontID(gfxFont);
1545 /* first, look if we substituted this font before-
1546 this way, we don't initialize the T1 Fonts
1548 for(t=0;t<substitutepos;t++) {
1549 if(!strcmp(fontid, substitutesource[t])) {
1550 fontid = substitutetarget[t];
1555 /* second, see if swfoutput already has this font
1556 cached- if so, we are done */
1557 if(swfoutput_queryfont(&output, fontid))
1559 swfoutput_setfont(&output, fontid, 0);
1561 msg("<debug> updateFont(%s) [cached]", fontid);
1565 // look for Type 3 font
1566 if (gfxFont->getType() == fontType3) {
1568 type3Warning = gTrue;
1569 showFontError(gfxFont, 2);
1574 /* now either load the font, or find a substitution */
1577 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1582 (gfxFont->getType() == fontType1 ||
1583 gfxFont->getType() == fontType1C ||
1584 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
1585 gfxFont->getType() == fontTrueType ||
1586 gfxFont->getType() == fontCIDType2
1589 fileName = writeEmbeddedFontToFile(xref, gfxFont);
1590 if(!fileName) showFontError(gfxFont,0);
1593 char * fontname = getFontName(gfxFont);
1594 fileName = searchFont(fontname);
1595 if(!fileName) showFontError(gfxFont,0);
1598 char * fontname = getFontName(gfxFont);
1599 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
1600 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
1601 fileName = substituteFont(gfxFont, fontid);
1602 if(fontid) { fontid = substitutetarget[substitutepos-1]; /*ugly hack*/};
1603 msg("<notice> Font is now %s (%s)", fontid, fileName);
1607 msg("<error> Couldn't set font %s\n", fontid);
1611 msg("<verbose> updateFont(%s) -> %s", fontid, fileName);
1612 dumpFontInfo("<verbose>", gfxFont);
1614 swfoutput_setfont(&output, fontid, fileName);
1617 unlinkfont(fileName);
1622 #define SQR(x) ((x)*(x))
1624 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1626 if((newwidth<2 || newheight<2) ||
1627 (width<=newwidth || height<=newheight))
1629 unsigned char*newdata;
1631 newdata= (unsigned char*)malloc(newwidth*newheight);
1633 double fx = (double)(width)/newwidth;
1634 double fy = (double)(height)/newheight;
1636 int blocksize = (int)(8192/(fx*fy));
1637 int r = 8192*256/palettesize;
1638 for(x=0;x<newwidth;x++) {
1639 double ex = px + fx;
1640 int fromx = (int)px;
1642 int xweight1 = (int)(((fromx+1)-px)*256);
1643 int xweight2 = (int)((ex-tox)*256);
1645 for(y=0;y<newheight;y++) {
1646 double ey = py + fy;
1647 int fromy = (int)py;
1649 int yweight1 = (int)(((fromy+1)-py)*256);
1650 int yweight2 = (int)((ey-toy)*256);
1653 for(xx=fromx;xx<=tox;xx++)
1654 for(yy=fromy;yy<=toy;yy++) {
1655 int b = 1-data[width*yy+xx];
1657 if(xx==fromx) weight = (weight*xweight1)/256;
1658 if(xx==tox) weight = (weight*xweight2)/256;
1659 if(yy==fromy) weight = (weight*yweight1)/256;
1660 if(yy==toy) weight = (weight*yweight2)/256;
1663 //if(a) a=(palettesize-1)*r/blocksize;
1664 newdata[y*newwidth+x] = (a*blocksize)/r;
1672 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
1673 int width, int height, GfxImageColorMap*colorMap, GBool invert,
1674 GBool inlineImg, int mask, int*maskColors)
1679 double x1,y1,x2,y2,x3,y3,x4,y4;
1680 ImageStream *imgStr;
1687 ncomps = colorMap->getNumPixelComps();
1688 bits = colorMap->getBits();
1690 imgStr = new ImageStream(str, width, ncomps,bits);
1693 if(!width || !height || (height<=1 && width<=1))
1695 msg("<verbose> Ignoring %d by %d image", width, height);
1696 unsigned char buf[8];
1698 for (y = 0; y < height; ++y)
1699 for (x = 0; x < width; ++x) {
1700 imgStr->getPixel(buf);
1706 state->transform(0, 1, &x1, &y1);
1707 state->transform(0, 0, &x2, &y2);
1708 state->transform(1, 0, &x3, &y3);
1709 state->transform(1, 1, &x4, &y4);
1711 if(!pbminfo && !(str->getKind()==strDCT)) {
1713 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
1717 msg("<verbose> drawing %d by %d masked picture\n", width, height);
1719 if(!jpeginfo && (str->getKind()==strDCT)) {
1720 msg("<notice> file contains jpeg pictures");
1726 unsigned char buf[8];
1728 unsigned char*pic = new unsigned char[width*height];
1731 state->getFillRGB(&rgb);
1733 memset(pal,255,sizeof(pal));
1734 pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
1735 pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
1736 pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
1737 pal[0].a = 255; pal[1].a = 0;
1740 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
1741 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
1742 for (y = 0; y < height; ++y)
1743 for (x = 0; x < width; ++x)
1745 imgStr->getPixel(buf);
1748 pic[width*y+x] = buf[0];
1751 /* the size of the drawn image is added to the identifier
1752 as the same image may require different bitmaps if displayed
1753 at different sizes (due to antialiasing): */
1756 unsigned char*pic2 = 0;
1759 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
1768 height = realheight;
1772 /* make a black/white palette */
1777 float r = 255/(numpalette-1);
1779 for(t=0;t<numpalette;t++) {
1780 pal[t].r = (U8)(255*rgb.r);
1781 pal[t].g = (U8)(255*rgb.g);
1782 pal[t].b = (U8)(255*rgb.b);
1783 pal[t].a = (U8)(t*r);
1787 RGBA*pic2 = new RGBA[width*height];
1788 for (y = 0; y < height; ++y) {
1789 for (x = 0; x < width; ++x) {
1790 pic2[width*y+x] = pal[pic[y*width+x]];
1793 swfoutput_drawimagelossless(&output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1802 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
1803 RGBA*pic=new RGBA[width*height];
1804 for (y = 0; y < height; ++y) {
1805 for (x = 0; x < width; ++x) {
1806 imgStr->getPixel(pixBuf);
1807 colorMap->getRGB(pixBuf, &rgb);
1808 pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
1809 pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
1810 pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
1811 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
1814 if(str->getKind()==strDCT)
1815 swfoutput_drawimagejpeg(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1817 swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1822 RGBA*pic=new RGBA[width*height];
1825 for(t=0;t<256;t++) {
1827 colorMap->getRGB(pixBuf, &rgb);
1828 /*if(maskColors && *maskColors==t) {
1829 msg("<notice> Color %d is transparent", t);
1830 if (imgData->maskColors) {
1832 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
1833 if (pix[i] < imgData->maskColors[2*i] ||
1834 pix[i] > imgData->maskColors[2*i+1]) {
1849 pal[t].r = (U8)(rgb.r * 255 + 0.5);
1850 pal[t].g = (U8)(rgb.g * 255 + 0.5);
1851 pal[t].b = (U8)(rgb.b * 255 + 0.5);
1852 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
1855 for (y = 0; y < height; ++y) {
1856 for (x = 0; x < width; ++x) {
1857 imgStr->getPixel(pixBuf);
1858 pic[width*y+x] = pal[pixBuf[0]];
1861 swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1869 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
1870 int width, int height, GBool invert,
1873 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
1874 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
1877 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
1878 int width, int height, GfxImageColorMap *colorMap,
1879 int *maskColors, GBool inlineImg)
1881 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
1882 colorMap?"colorMap":"no colorMap",
1883 maskColors?"maskColors":"no maskColors",
1886 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
1887 colorMap->getBits(),colorMap->getColorSpace()->getMode());
1888 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
1891 SWFOutputDev*output = 0;
1893 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
1898 if (infoDict->lookup(key, &obj)->isString()) {
1899 s1 = obj.getString();
1900 if ((s1->getChar(0) & 0xff) == 0xfe &&
1901 (s1->getChar(1) & 0xff) == 0xff) {
1903 for (i = 2; i < obj.getString()->getLength(); i += 2) {
1904 if (s1->getChar(i) == '\0') {
1905 s2->append(s1->getChar(i+1));
1908 s2 = new GString("<unicode>");
1912 printf(fmt, s2->getCString());
1915 printf(fmt, s1->getCString());
1921 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
1925 if (infoDict->lookup(key, &obj)->isString()) {
1926 s = obj.getString()->getCString();
1927 if (s[0] == 'D' && s[1] == ':') {
1938 void pdfswf_setparameter(char*name, char*value)
1940 msg("<verbose> setting parameter %s to \"%s\"", name, value);
1941 if(!strcmp(name, "caplinewidth")) {
1942 caplinewidth = atof(value);
1943 } else if(!strcmp(name, "zoom")) {
1946 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
1947 swfoutput_setparameter("jpegsubpixels", buf);
1948 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
1949 swfoutput_setparameter("ppmsubpixels", buf);
1950 } else if(!strcmp(name, "jpegdpi")) {
1952 jpeg_dpi = atoi(value);
1953 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
1954 swfoutput_setparameter("jpegsubpixels", buf);
1955 } else if(!strcmp(name, "ppmdpi")) {
1957 ppm_dpi = atoi(value);
1958 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
1959 swfoutput_setparameter("ppmsubpixels", buf);
1960 } else if(!strcmp(name, "forceType0Fonts")) {
1961 forceType0Fonts = atoi(value);
1962 } else if(!strcmp(name, "fontdir")) {
1963 pdfswf_addfontdir(value);
1964 } else if(!strcmp(name, "languagedir")) {
1965 pdfswf_addlanguagedir(value);
1966 } else if(!strcmp(name, "fontconfig")) {
1967 config_use_fontconfig = atoi(value);
1969 swfoutput_setparameter(name, value);
1972 void pdfswf_addfont(char*filename)
1975 memset(&f, 0, sizeof(fontfile_t));
1976 f.filename = filename;
1977 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
1978 fonts[fontnum++] = f;
1980 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
1984 static char* dirseparator()
1993 void pdfswf_addlanguagedir(char*dir)
1996 globalParams = new GlobalParams("");
1998 msg("<notice> Adding %s to language pack directories", dir);
2002 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2003 strcpy(config_file, dir);
2004 strcat(config_file, dirseparator());
2005 strcat(config_file, "add-to-xpdfrc");
2007 fi = fopen(config_file, "rb");
2009 msg("<error> Could not open %s", config_file);
2012 globalParams->parseFile(new GString(config_file), fi);
2016 void pdfswf_addfontdir(char*dirname)
2018 #ifdef HAVE_DIRENT_H
2019 msg("<notice> Adding %s to font directories", dirname);
2020 DIR*dir = opendir(dirname);
2022 msg("<warning> Couldn't open directory %s\n", dirname);
2027 ent = readdir (dir);
2031 char*name = ent->d_name;
2037 if(!strncasecmp(&name[l-4], ".pfa", 4))
2039 if(!strncasecmp(&name[l-4], ".pfb", 4))
2041 if(!strncasecmp(&name[l-4], ".ttf", 4))
2045 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2046 strcpy(fontname, dirname);
2047 strcat(fontname, dirseparator());
2048 strcat(fontname, name);
2049 msg("<verbose> Adding %s to fonts", fontname);
2050 pdfswf_addfont(fontname);
2055 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2060 typedef struct _pdf_doc_internal
2064 } pdf_doc_internal_t;
2065 typedef struct _pdf_page_internal
2067 } pdf_page_internal_t;
2068 typedef struct _swf_output_internal
2070 SWFOutputDev*outputDev;
2071 } swf_output_internal_t;
2073 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2075 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2076 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2077 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2078 memset(i, 0, sizeof(pdf_doc_internal_t));
2079 pdf_doc->internal = i;
2081 GString *fileName = new GString(filename);
2087 globalParams = new GlobalParams("");
2090 if (userPassword && userPassword[0]) {
2091 userPW = new GString(userPassword);
2095 i->doc = new PDFDoc(fileName, userPW);
2099 if (!i->doc->isOk()) {
2104 i->doc->getDocInfo(&info);
2105 if (info.isDict() &&
2106 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2107 printInfoString(info.getDict(), "Title", "Title: %s\n");
2108 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2109 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2110 printInfoString(info.getDict(), "Author", "Author: %s\n");
2111 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2112 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2113 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2114 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2115 printf("Pages: %d\n", i->doc->getNumPages());
2116 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2117 printf("Encrypted: ");
2118 if (i->doc->isEncrypted()) {
2119 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2120 i->doc->okToPrint() ? "yes" : "no",
2121 i->doc->okToCopy() ? "yes" : "no",
2122 i->doc->okToChange() ? "yes" : "no",
2123 i->doc->okToAddNotes() ? "yes" : "no");
2130 pdf_doc->num_pages = i->doc->getNumPages();
2132 if (i->doc->isEncrypted()) {
2133 if(!i->doc->okToCopy()) {
2134 printf("PDF disallows copying.\n");
2137 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2144 void pdfswf_preparepage(int page)
2148 pages = (int*)malloc(1024*sizeof(int));
2151 if(pagepos == pagebuflen)
2154 pages = (int*)realloc(pages, pagebuflen);
2157 pages[pagepos++] = page;
2164 delete globalParams;globalParams=0;
2165 Object::memCheck(stderr);
2170 void pdf_destroy(pdf_doc_t*pdf_doc)
2172 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2174 msg("<debug> pdfswf.cc: pdfswf_close()");
2175 delete i->doc; i->doc=0;
2177 free(pages); pages = 0; //FIXME
2179 free(pdf_doc->internal);pdf_doc->internal=0;
2180 free(pdf_doc);pdf_doc=0;
2183 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2185 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2187 if(page < 1 || page > pdf_doc->num_pages)
2190 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2191 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2192 memset(pi, 0, sizeof(pdf_page_internal_t));
2193 pdf_page->internal = pi;
2195 pdf_page->parent = pdf_doc;
2196 pdf_page->nr = page;
2200 void pdf_page_destroy(pdf_page_t*pdf_page)
2202 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2203 free(pdf_page->internal);pdf_page->internal = 0;
2204 free(pdf_page);pdf_page=0;
2207 swf_output_t* swf_output_init()
2209 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2210 memset(swf_output, 0, sizeof(swf_output_t));
2211 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2212 memset(i, 0, sizeof(swf_output_internal_t));
2213 swf_output->internal = i;
2215 i->outputDev = new SWFOutputDev();
2219 void swf_output_setparameter(swf_output_t*swf_output, char*name, char*value)
2222 pdfswf_setparameter(name, value);
2225 void swf_output_pagefeed(swf_output_t*swf)
2227 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2228 i->outputDev->pagefeed();
2229 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2232 int swf_output_save(swf_output_t*swf, char*filename)
2234 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2235 int ret = i->outputDev->save(filename);
2236 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2240 void* swf_output_get(swf_output_t*swf)
2242 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2243 void* ret = i->outputDev->getSWF();
2244 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2248 void swf_output_destroy(swf_output_t*output)
2250 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2251 delete i->outputDev; i->outputDev=0;
2252 free(output->internal);output->internal=0;
2256 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2258 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2259 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2262 swfoutput_setparameter("protect", "1");
2264 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2266 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2268 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2270 si->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2273 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2275 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2276 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2278 si->outputDev->setMove(x,y);
2279 if((x1|y1|x2|y2)==0) x2++;
2280 si->outputDev->setClip(x1,y1,x2,y2);
2282 pdf_page_render2(page, output);
2284 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2286 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2287 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2289 si->outputDev->setMove(0,0);
2290 si->outputDev->setClip(0,0,0,0);
2292 pdf_page_render2(page, output);
2296 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2298 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2299 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2300 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2301 memset(info, 0, sizeof(pdf_page_info_t));
2303 InfoOutputDev*output = new InfoOutputDev;
2306 pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2308 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2311 info->xMin = output->x1;
2312 info->yMin = output->y1;
2313 info->xMax = output->x2;
2314 info->yMax = output->y2;
2315 info->number_of_images = output->num_images;
2316 info->number_of_links = output->num_links;
2317 info->number_of_fonts = output->num_fonts;
2324 void pdf_page_info_destroy(pdf_page_info_t*info)