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 SWFOutputState {
123 this->textRender = 0;
127 class SWFOutputDev: public OutputDev {
129 struct swfoutput output;
136 virtual ~SWFOutputDev() ;
138 void setMove(int x,int y);
139 void setClip(int x1,int y1,int x2,int y2);
141 int save(char*filename);
145 void getDimensions(int*x1,int*y1,int*x2,int*y2);
147 //----- get info about output device
149 // Does this device use upside-down coordinates?
150 // (Upside-down means (0,0) is the top left corner of the page.)
151 virtual GBool upsideDown();
153 // Does this device use drawChar() or drawString()?
154 virtual GBool useDrawChar();
156 // Can this device draw gradients?
157 virtual GBool useGradients();
159 virtual GBool interpretType3Chars() {return gTrue;}
161 //----- initialization and control
163 void setXRef(PDFDoc*doc, XRef *xref);
166 virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
169 virtual void drawLink(Link *link, Catalog *catalog) ;
171 //----- save/restore graphics state
172 virtual void saveState(GfxState *state) ;
173 virtual void restoreState(GfxState *state) ;
175 //----- update graphics state
177 virtual void updateFont(GfxState *state);
178 virtual void updateFillColor(GfxState *state);
179 virtual void updateStrokeColor(GfxState *state);
180 virtual void updateLineWidth(GfxState *state);
181 virtual void updateLineJoin(GfxState *state);
182 virtual void updateLineCap(GfxState *state);
184 virtual void updateAll(GfxState *state)
187 updateFillColor(state);
188 updateStrokeColor(state);
189 updateLineWidth(state);
190 updateLineJoin(state);
191 updateLineCap(state);
194 //----- path painting
195 virtual void stroke(GfxState *state) ;
196 virtual void fill(GfxState *state) ;
197 virtual void eoFill(GfxState *state) ;
199 //----- path clipping
200 virtual void clip(GfxState *state) ;
201 virtual void eoClip(GfxState *state) ;
204 virtual void beginString(GfxState *state, GString *s) ;
205 virtual void endString(GfxState *state) ;
206 virtual void endTextObject(GfxState *state);
207 virtual void drawChar(GfxState *state, double x, double y,
208 double dx, double dy,
209 double originX, double originY,
210 CharCode code, Unicode *u, int uLen);
212 //----- image drawing
213 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
214 int width, int height, GBool invert,
216 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
217 int width, int height, GfxImageColorMap *colorMap,
218 int *maskColors, GBool inlineImg);
220 virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
221 virtual void endType3Char(GfxState *state);
223 virtual void type3D0(GfxState *state, double wx, double wy);
224 virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
227 void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
228 int width, int height, GfxImageColorMap*colorMap, GBool invert,
229 GBool inlineImg, int mask, int *maskColors);
230 SWFOutputState states[64];
238 char* searchFont(char*name);
239 char* substituteFont(GfxFont*gfxFont, char*oldname);
240 char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
242 int jpeginfo; // did we write "File contains jpegs" yet?
243 int pbminfo; // did we write "File contains jpegs" yet?
244 int linkinfo; // did we write "File contains links" yet?
245 int ttfinfo; // did we write "File contains TrueType Fonts" yet?
246 int gradientinfo; // did we write "File contains Gradients yet?
248 int type3active; // are we between beginType3()/endType3()?
254 char* substitutetarget[256];
255 char* substitutesource[256];
258 int user_movex,user_movey;
259 int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
262 static char*getFontID(GfxFont*font);
264 class InfoOutputDev: public OutputDev
278 virtual ~InfoOutputDev()
281 virtual GBool upsideDown() {return gTrue;}
282 virtual GBool useDrawChar() {return gTrue;}
283 virtual GBool useGradients() {return gTrue;}
284 virtual GBool interpretType3Chars() {return gTrue;}
285 virtual void startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
288 state->transform(crop_x1,crop_y1,&x1,&y1);
289 state->transform(crop_x2,crop_y2,&x2,&y2);
290 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
291 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
297 virtual void drawLink(Link *link, Catalog *catalog)
301 virtual void updateFont(GfxState *state)
303 GfxFont*font = state->getFont();
306 /*char*id = getFontID(font);*/
310 virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
311 int width, int height, GBool invert,
316 virtual void drawImage(GfxState *state, Object *ref, Stream *str,
317 int width, int height, GfxImageColorMap *colorMap,
318 int *maskColors, GBool inlineImg)
324 SWFOutputDev::SWFOutputDev()
342 memset(&output, 0, sizeof(output));
343 // printf("SWFOutputDev::SWFOutputDev() \n");
346 void SWFOutputDev::setMove(int x,int y)
348 this->user_movex = x;
349 this->user_movey = y;
352 void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
354 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
355 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
357 this->user_clipx1 = x1;
358 this->user_clipy1 = y1;
359 this->user_clipx2 = x2;
360 this->user_clipy2 = y2;
362 void SWFOutputDev::getDimensions(int*x1,int*y1,int*x2,int*y2)
364 return swfoutput_getdimensions(&output, x1,y1,x2,y2);
367 static char*getFontID(GfxFont*font)
369 GString*gstr = font->getName();
370 char* fontname = gstr==0?0:gstr->getCString();
374 sprintf(buf, "UFONT%d", r->num);
377 return strdup(fontname);
380 static char*getFontName(GfxFont*font)
382 char*fontid = getFontID(font);
384 char* plus = strchr(fontid, '+');
385 if(plus && plus < &fontid[strlen(fontid)-1]) {
386 fontname = strdup(plus+1);
388 fontname = strdup(fontid);
394 static char mybuf[1024];
395 static char* gfxstate2str(GfxState *state)
399 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
406 if(state->getX1()!=0.0)
407 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
408 if(state->getY1()!=0.0)
409 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
410 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
411 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
412 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
413 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
414 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
415 state->getFillColor()->c[0], state->getFillColor()->c[1]);
416 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
417 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
418 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
419 state->getFillColor()->c[0], state->getFillColor()->c[1],
420 state->getFillColor()->c[2], state->getFillColor()->c[3],
421 state->getFillColor()->c[4], state->getFillColor()->c[5],
422 state->getFillColor()->c[6], state->getFillColor()->c[7]);
423 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
424 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
425 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
426 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
427 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
428 state->getFillRGB(&rgb);
429 if(rgb.r || rgb.g || rgb.b)
430 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
431 state->getStrokeRGB(&rgb);
432 if(rgb.r || rgb.g || rgb.b)
433 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
434 if(state->getFillColorSpace()->getNComps()>1)
435 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
436 if(state->getStrokeColorSpace()->getNComps()>1)
437 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
438 if(state->getFillPattern())
439 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
440 if(state->getStrokePattern())
441 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
443 if(state->getFillOpacity()!=1.0)
444 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
445 if(state->getStrokeOpacity()!=1.0)
446 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
448 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
453 state->getLineDash(&dash, &length, &start);
457 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
458 for(t=0;t<length;t++) {
459 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
461 bufpos+=sprintf(bufpos,"]");
464 if(state->getFlatness()!=1)
465 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
466 if(state->getLineJoin()!=0)
467 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
468 if(state->getLineJoin()!=0)
469 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
470 if(state->getLineJoin()!=0)
471 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
473 if(state->getFont() && getFontID(state->getFont()))
474 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
475 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
476 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
477 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
478 if(state->getCharSpace())
479 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
480 if(state->getWordSpace())
481 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
482 if(state->getHorizScaling()!=1.0)
483 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
484 if(state->getLeading())
485 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
487 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
488 if(state->getRender())
489 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
490 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
491 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
492 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
493 if(state->getLineX())
494 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
495 if(state->getLineY())
496 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
497 bufpos+=sprintf(bufpos," ");
501 static void dumpFontInfo(char*loglevel, GfxFont*font);
502 static int lastdumps[1024];
503 static int lastdumppos = 0;
508 static void showFontError(GfxFont*font, int nr)
512 for(t=0;t<lastdumppos;t++)
513 if(lastdumps[t] == r->num)
517 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
518 lastdumps[lastdumppos++] = r->num;
520 msg("<warning> The following font caused problems:");
522 msg("<warning> The following font caused problems (substituting):");
524 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
525 dumpFontInfo("<warning>", font);
528 static void dumpFontInfo(char*loglevel, GfxFont*font)
530 char* id = getFontID(font);
531 char* name = getFontName(font);
532 Ref* r=font->getID();
533 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
535 GString*gstr = font->getTag();
537 msg("%s| Tag: %s\n", loglevel, id);
539 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
541 GfxFontType type=font->getType();
543 case fontUnknownType:
544 msg("%s| Type: unknown\n",loglevel);
547 msg("%s| Type: 1\n",loglevel);
550 msg("%s| Type: 1C\n",loglevel);
553 msg("%s| Type: 3\n",loglevel);
556 msg("%s| Type: TrueType\n",loglevel);
559 msg("%s| Type: CIDType0\n",loglevel);
562 msg("%s| Type: CIDType0C\n",loglevel);
565 msg("%s| Type: CIDType2\n",loglevel);
570 GBool embedded = font->getEmbeddedFontID(&embRef);
572 if(font->getEmbeddedFontName()) {
573 embeddedName = font->getEmbeddedFontName()->getCString();
576 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
578 gstr = font->getExtFontFile();
580 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
582 // Get font descriptor flags.
583 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
584 if(font->isSerif()) msg("%s| is serif\n", loglevel);
585 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
586 if(font->isItalic()) msg("%s| is italic\n", loglevel);
587 if(font->isBold()) msg("%s| is bold\n", loglevel);
593 //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");}
594 //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");}
597 void dump_outline(gfxline_t*line)
600 if(line->type == gfx_moveTo) {
601 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
602 } else if(line->type == gfx_lineTo) {
603 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
604 } else if(line->type == gfx_splineTo) {
605 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
611 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed)
613 int num = path->getNumSubpaths();
616 double lastx=0,lasty=0,posx=0,posy=0;
619 msg("<warning> empty path");
623 gfxdrawer_target_gfxline(&draw);
625 for(t = 0; t < num; t++) {
626 GfxSubpath *subpath = path->getSubpath(t);
627 int subnum = subpath->getNumPoints();
628 double bx=0,by=0,cx=0,cy=0;
630 for(s=0;s<subnum;s++) {
632 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
634 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
635 draw.lineTo(&draw, lastx, lasty);
637 draw.moveTo(&draw, x,y);
642 } else if(subpath->getCurve(s) && cpos==0) {
646 } else if(subpath->getCurve(s) && cpos==1) {
654 draw.lineTo(&draw, x,y);
656 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y);
663 /* fix non-closed lines */
664 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
665 draw.lineTo(&draw, lastx, lasty);
667 gfxline_t*result = (gfxline_t*)draw.result(&draw);
671 /*----------------------------------------------------------------------------
672 * Primitive Graphic routines
673 *----------------------------------------------------------------------------*/
675 void SWFOutputDev::stroke(GfxState *state)
677 GfxPath * path = state->getPath();
678 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
679 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
680 double miterLimit = state->getMiterLimit();
681 double width = state->getTransformedLineWidth();
684 double opaq = state->getStrokeOpacity();
686 state->getFillRGB(&rgb);
688 state->getStrokeRGB(&rgb);
690 col.r = (unsigned char)(rgb.r*255);
691 col.g = (unsigned char)(rgb.g*255);
692 col.b = (unsigned char)(rgb.b*255);
693 col.a = (unsigned char)(opaq*255);
695 gfx_capType capType = gfx_capRound;
696 if(lineCap == 0) capType = gfx_capButt;
697 else if(lineCap == 1) capType = gfx_capRound;
698 else if(lineCap == 2) capType = gfx_capSquare;
700 gfx_joinType joinType = gfx_joinRound;
701 if(lineJoin == 0) joinType = gfx_joinMiter;
702 else if(lineJoin == 1) joinType = gfx_joinRound;
703 else if(lineJoin == 2) joinType = gfx_joinBevel;
705 gfxline_t*line= gfxPath_to_gfxline(state, path, 0);
708 double dashphase = 0;
710 state->getLineDash(&ldash, &dashnum, &dashphase);
712 if(dashnum && ldash) {
713 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
717 msg("<trace> %d dashes", dashnum);
718 msg("<trace> | phase: %f", dashphase);
719 for(t=0;t<dashnum;t++) {
721 msg("<trace> | d%-3d: %f", t, ldash[t]);
724 if(getLogLevel() >= LOGLEVEL_TRACE) {
728 gfxline_t*line2 = gfxtool_dash_line(line, dash, dashphase);
731 msg("<trace> After dashing:");
734 if(getLogLevel() >= LOGLEVEL_TRACE) {
736 state->getStrokeGray(&gray);
737 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n",
739 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
740 lineCap==0?"butt": (lineJoin==1?"round":"square"),
742 col.r,col.g,col.b,col.a,
748 swfoutput_drawgfxline(&output, line, width, &col, capType, joinType, miterLimit);
751 void SWFOutputDev::fill(GfxState *state)
753 GfxPath * path = state->getPath();
754 double opaq = state->getFillOpacity();
756 state->getFillRGB(&rgb);
758 col.r = (unsigned char)(rgb.r*255);
759 col.g = (unsigned char)(rgb.g*255);
760 col.b = (unsigned char)(rgb.b*255);
761 col.a = (unsigned char)(opaq*255);
763 gfxline_t*line= gfxPath_to_gfxline(state, path, 1);
765 if(getLogLevel() >= LOGLEVEL_TRACE) {
766 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
770 swfoutput_fillgfxline(&output, line, &col);
773 void SWFOutputDev::eoFill(GfxState *state)
775 GfxPath * path = state->getPath();
776 double opaq = state->getFillOpacity();
778 state->getFillRGB(&rgb);
780 col.r = (unsigned char)(rgb.r*255);
781 col.g = (unsigned char)(rgb.g*255);
782 col.b = (unsigned char)(rgb.b*255);
783 col.a = (unsigned char)(opaq*255);
785 gfxline_t*line= gfxPath_to_gfxline(state, path, 1);
787 if(getLogLevel() >= LOGLEVEL_TRACE) {
788 msg("<trace> eofill\n");
792 swfoutput_fillgfxline(&output, line, &col);
795 void SWFOutputDev::clip(GfxState *state)
797 GfxPath * path = state->getPath();
798 gfxline_t*line = gfxPath_to_gfxline(state, path, 1);
800 if(getLogLevel() >= LOGLEVEL_TRACE) {
801 msg("<trace> clip\n");
805 swfoutput_startclip(&output, line);
806 states[statepos].clipping++;
809 void SWFOutputDev::eoClip(GfxState *state)
811 GfxPath * path = state->getPath();
812 gfxline_t*line = gfxPath_to_gfxline(state, path, 1);
814 if(getLogLevel() >= LOGLEVEL_TRACE) {
815 msg("<trace> eoclip\n");
819 swfoutput_startclip(&output, line);
820 states[statepos].clipping++;
824 /* pass through functions for swf_output */
825 int SWFOutputDev::save(char*filename)
827 return swfoutput_save(&output, filename);
829 void SWFOutputDev::pagefeed()
831 swfoutput_pagefeed(&output);
833 void* SWFOutputDev::getSWF()
835 return (void*)swfoutput_get(&output);
838 SWFOutputDev::~SWFOutputDev()
840 swfoutput_destroy(&output);
843 GBool SWFOutputDev::upsideDown()
845 msg("<debug> upsidedown? yes");
848 GBool SWFOutputDev::useDrawChar()
852 GBool SWFOutputDev::useGradients()
856 msg("<notice> File contains gradients");
862 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
863 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
865 static char tmp_printstr[4096];
866 char* makeStringPrintable(char*str)
868 int len = strlen(str);
883 tmp_printstr[len++] = '.';
884 tmp_printstr[len++] = '.';
885 tmp_printstr[len++] = '.';
887 tmp_printstr[len] = 0;
891 void SWFOutputDev::beginString(GfxState *state, GString *s)
893 int render = state->getRender();
894 msg("<trace> beginString(%s) render=%d", s->getCString(), render);
895 double m11,m21,m12,m22;
896 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
897 state->getFontTransMat(&m11, &m12, &m21, &m22);
898 m11 *= state->getHorizScaling();
899 m21 *= state->getHorizScaling();
900 swfoutput_setfontmatrix(&output, m11, -m21, m12, -m22);
901 if(render != 3 && render != 0)
902 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));
903 states[statepos].textRender = render;
906 static int textCount = 0;
908 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
909 double dx, double dy,
910 double originX, double originY,
911 CharCode c, Unicode *_u, int uLen)
915 int render = state->getRender();
916 // check for invisible text -- this is used by Acrobat Capture
920 if(states[statepos].textRender != render)
921 msg("<error> Internal error: drawChar.render!=beginString.render");
924 double opaq = state->getFillOpacity();
925 state->getFillRGB(&rgb);
927 col.r = (unsigned char)(rgb.r*255);
928 col.g = (unsigned char)(rgb.g*255);
929 col.b = (unsigned char)(rgb.b*255);
930 col.a = (unsigned char)(opaq*255);
932 Gushort *CIDToGIDMap = 0;
933 GfxFont*font = state->getFont();
935 if(font->getType() == fontType3) {
936 /* type 3 chars are passed as graphics */
937 msg("<debug> type3 char at %f/%f", x, y);
943 state->transform(x, y, &x1, &y1);
952 /* find out char name from unicode index
953 TODO: should be precomputed
955 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
956 if(nameToUnicodeTab[t].u == u) {
957 name = nameToUnicodeTab[t].name;
964 if(font->isCIDFont()) {
965 GfxCIDFont*cfont = (GfxCIDFont*)font;
967 if(font->getType() == fontCIDType2)
968 CIDToGIDMap = cfont->getCIDToGID();
971 font8 = (Gfx8BitFont*)font;
972 char**enc=font8->getEncoding();
978 msg("<debug> drawChar(%f, %f, c='%c' (%d), GID=%d, u=%d <%d>) CID=%d name=\"%s\" render=%d\n", x, y, (c&127)>=32?c:'?', c, CIDToGIDMap[c], u, uLen, font->isCIDFont(), FIXNULL(name), render);
979 swfoutput_drawchar(&output, x1, y1, name, CIDToGIDMap[c], u, &col);
981 msg("<debug> drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d name=\"%s\" render=%d\n",x,y,(c&127)>=32?c:'?',c,u, uLen, font->isCIDFont(), FIXNULL(name), render);
982 swfoutput_drawchar(&output, x1, y1, name, c, u, &col);
986 void SWFOutputDev::endString(GfxState *state)
988 msg("<trace> endString()");
991 void SWFOutputDev::endTextObject(GfxState *state)
993 msg("<trace> endTextObject()");
996 /* the logic seems to be as following:
997 first, beginType3Char is called, with the charcode and the coordinates.
998 if this function returns true, it already knew about the char and has now drawn it.
999 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1000 the all draw operations until endType3Char are part of the char (which in this moment is
1001 at the position first passed to beginType3Char). the char ends with endType3Char.
1003 The drawing operations between beginType3Char and endType3Char are somewhat different to
1004 the normal ones. For example, the fillcolor equals the stroke color.
1007 GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1009 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1011 /* the character itself is going to be passed using the draw functions */
1012 return gFalse; /* gTrue= is_in_cache? */
1015 void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
1016 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1018 void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1019 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1023 void SWFOutputDev::endType3Char(GfxState *state)
1026 msg("<debug> endType3Char");
1029 void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1031 this->currentpage = pageNum;
1033 int rot = doc->getPageRotate(1);
1035 msg("<verbose> startPage %d (%f,%f,%f,%f)\n", pageNum, crop_x1, crop_y1, crop_x2, crop_y2);
1037 msg("<verbose> page is rotated %d degrees\n", rot);
1039 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1040 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1041 Use CropBox, not MediaBox, as page size
1048 state->transform(crop_x1,crop_y1,&x1,&y1);
1049 state->transform(crop_x2,crop_y2,&x2,&y2);
1051 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1052 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1054 /* apply user clip box */
1055 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1056 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1057 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1058 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1059 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1062 if(!outputstarted) {
1063 msg("<verbose> Bounding box is (%f,%f)-(%f,%f)", x1,y1,x2,y2);
1064 swfoutput_init(&output);
1068 swfoutput_newpage(&output, pageNum, user_movex, user_movey, (int)x1, (int)y1, (int)x2, (int)y2);
1071 void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
1073 msg("<debug> drawlink\n");
1074 double x1, y1, x2, y2, w;
1080 link->getBorder(&x1, &y1, &x2, &y2, &w);
1082 link->getRect(&x1, &y1, &x2, &y2);
1087 cvtUserToDev(x1, y1, &x, &y);
1088 points[0].x = points[4].x = (int)x;
1089 points[0].y = points[4].y = (int)y;
1090 cvtUserToDev(x2, y1, &x, &y);
1091 points[1].x = (int)x;
1092 points[1].y = (int)y;
1093 cvtUserToDev(x2, y2, &x, &y);
1094 points[2].x = (int)x;
1095 points[2].y = (int)y;
1096 cvtUserToDev(x1, y2, &x, &y);
1097 points[3].x = (int)x;
1098 points[3].y = (int)y;
1100 LinkAction*action=link->getAction();
1107 switch(action->getKind())
1111 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1112 LinkDest *dest=NULL;
1113 if (ha->getDest()==NULL)
1114 dest=catalog->findDest(ha->getNamedDest());
1115 else dest=ha->getDest();
1117 if (dest->isPageRef()){
1118 Ref pageref=dest->getPageRef();
1119 page=catalog->findPage(pageref.num,pageref.gen);
1121 else page=dest->getPageNum();
1122 sprintf(buf, "%d", page);
1129 LinkGoToR*l = (LinkGoToR*)action;
1130 GString*g = l->getNamedDest();
1132 s = strdup(g->getCString());
1137 LinkNamed*l = (LinkNamed*)action;
1138 GString*name = l->getName();
1140 s = strdup(name->lowerCase()->getCString());
1141 named = name->getCString();
1144 if(strstr(s, "next") || strstr(s, "forward"))
1146 page = currentpage + 1;
1148 else if(strstr(s, "prev") || strstr(s, "back"))
1150 page = currentpage - 1;
1152 else if(strstr(s, "last") || strstr(s, "end"))
1154 page = pagepos>0?pages[pagepos-1]:0;
1156 else if(strstr(s, "first") || strstr(s, "top"))
1164 case actionLaunch: {
1166 LinkLaunch*l = (LinkLaunch*)action;
1167 GString * str = new GString(l->getFileName());
1168 str->append(l->getParams());
1169 s = strdup(str->getCString());
1175 LinkURI*l = (LinkURI*)action;
1176 GString*g = l->getURI();
1178 url = g->getCString();
1183 case actionUnknown: {
1185 LinkUnknown*l = (LinkUnknown*)action;
1190 msg("<error> Unknown link type!\n");
1194 if(!s) s = strdup("-?-");
1196 if(!linkinfo && (page || url))
1198 msg("<notice> File contains links");
1204 for(t=0;t<pagepos;t++)
1208 swfoutput_linktopage(&output, t, points);
1212 swfoutput_linktourl(&output, url, points);
1216 swfoutput_namedlink(&output, named, points);
1218 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1222 void SWFOutputDev::saveState(GfxState *state) {
1223 msg("<trace> saveState\n");
1226 msg("<error> Too many nested states in pdf.");
1230 states[statepos].clipping = 0; //? shouldn't this be the current value?
1231 states[statepos].textRender = states[statepos-1].textRender;
1234 void SWFOutputDev::restoreState(GfxState *state) {
1235 msg("<trace> restoreState\n");
1237 while(states[statepos].clipping) {
1238 swfoutput_endclip(&output);
1239 states[statepos].clipping--;
1244 char* SWFOutputDev::searchFont(char*name)
1248 int is_standard_font = 0;
1250 msg("<verbose> SearchFont(%s)", name);
1252 /* see if it is a pdf standard font */
1253 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1255 if(!strcmp(name, pdf2t1map[i].pdffont))
1257 name = pdf2t1map[i].filename;
1258 is_standard_font = 1;
1262 /* look in all font files */
1263 for(i=0;i<fontnum;i++)
1265 if(strstr(fonts[i].filename, name))
1267 if(!fonts[i].used) {
1270 if(!is_standard_font)
1271 msg("<notice> Using %s for %s", fonts[i].filename, name);
1273 return strdup(fonts[i].filename);
1279 void SWFOutputDev::updateLineWidth(GfxState *state)
1281 double width = state->getTransformedLineWidth();
1282 //swfoutput_setlinewidth(&output, width);
1285 void SWFOutputDev::updateLineCap(GfxState *state)
1287 int c = state->getLineCap();
1290 void SWFOutputDev::updateLineJoin(GfxState *state)
1292 int j = state->getLineJoin();
1295 void SWFOutputDev::updateFillColor(GfxState *state)
1298 double opaq = state->getFillOpacity();
1299 state->getFillRGB(&rgb);
1301 //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1304 void SWFOutputDev::updateStrokeColor(GfxState *state)
1307 double opaq = state->getStrokeOpacity();
1308 state->getStrokeRGB(&rgb);
1309 //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
1312 void FoFiWrite(void *stream, char *data, int len)
1314 fwrite(data, len, 1, (FILE*)stream);
1317 char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1319 char*tmpFileName = NULL;
1325 Object refObj, strObj;
1327 tmpFileName = mktmpname(namebuf);
1330 ret = font->getEmbeddedFontID(&embRef);
1332 msg("<verbose> Didn't get embedded font id");
1333 /* not embedded- the caller should now search the font
1334 directories for this font */
1338 f = fopen(tmpFileName, "wb");
1340 msg("<error> Couldn't create temporary Type 1 font file");
1344 /*if(font->isCIDFont()) {
1345 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1346 GString c = cidFont->getCollection();
1347 msg("<notice> Collection: %s", c.getCString());
1350 if (font->getType() == fontType1C) {
1351 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1353 msg("<error> Couldn't read embedded font file");
1357 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
1359 cvt->convertToType1(f);
1361 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1363 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1365 //cvt->convertToCIDType0("test", f);
1366 //cvt->convertToType0("test", f);
1369 } else if(font->getType() == fontTrueType) {
1370 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1371 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1373 msg("<error> Couldn't read embedded font file");
1377 TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
1380 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1381 cvt->writeTTF(FoFiWrite, f);
1386 font->getEmbeddedFontID(&embRef);
1387 refObj.initRef(embRef.num, embRef.gen);
1388 refObj.fetch(ref, &strObj);
1390 strObj.streamReset();
1395 f4[t] = strObj.streamGetChar();
1396 f4c[t] = (char)f4[t];
1401 if(!strncmp(f4c, "true", 4)) {
1402 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1403 Change this on the fly */
1404 f4[0] = f4[2] = f4[3] = 0;
1412 while ((c = strObj.streamGetChar()) != EOF) {
1416 strObj.streamClose();
1421 return strdup(tmpFileName);
1424 char* searchForSuitableFont(GfxFont*gfxFont)
1426 char*name = getFontName(gfxFont);
1430 if(!config_use_fontconfig)
1433 #ifdef HAVE_FONTCONFIG
1434 FcPattern *pattern, *match;
1438 static int fcinitcalled = false;
1440 msg("<debug> searchForSuitableFont(%s)", name);
1442 // call init ony once
1443 if (!fcinitcalled) {
1444 msg("<debug> Initializing FontConfig...");
1445 fcinitcalled = true;
1447 msg("<debug> FontConfig Initialization failed. Disabling.");
1448 config_use_fontconfig = 0;
1451 msg("<debug> ...initialized FontConfig");
1454 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1455 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1456 if (gfxFont->isItalic()) // check for italic
1457 msg("<debug> FontConfig: Adding Italic Slant");
1458 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1459 if (gfxFont->isBold()) // check for bold
1460 msg("<debug> FontConfig: Adding Bold Weight");
1461 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1463 msg("<debug> FontConfig: Try to match...");
1464 // configure and match using the original font name
1465 FcConfigSubstitute(0, pattern, FcMatchPattern);
1466 FcDefaultSubstitute(pattern);
1467 match = FcFontMatch(0, pattern, &result);
1469 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1470 msg("<debug> FontConfig: family=%s", (char*)v);
1471 // if we get an exact match
1472 if (strcmp((char *)v, name) == 0) {
1473 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1474 filename = strdup((char*)v); // mem leak
1475 char *nfn = strrchr(filename, '/');
1476 if(nfn) fontname = strdup(nfn+1);
1477 else fontname = filename;
1479 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1481 // initialize patterns
1482 FcPatternDestroy(pattern);
1483 FcPatternDestroy(match);
1485 // now match against serif etc.
1486 if (gfxFont->isSerif()) {
1487 msg("<debug> FontConfig: Create Serif Family Pattern");
1488 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1489 } else if (gfxFont->isFixedWidth()) {
1490 msg("<debug> FontConfig: Create Monospace Family Pattern");
1491 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1493 msg("<debug> FontConfig: Create Sans Family Pattern");
1494 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1498 if (gfxFont->isItalic()) {
1499 msg("<debug> FontConfig: Adding Italic Slant");
1500 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1503 if (gfxFont->isBold()) {
1504 msg("<debug> FontConfig: Adding Bold Weight");
1505 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1508 msg("<debug> FontConfig: Try to match... (2)");
1509 // configure and match using serif etc
1510 FcConfigSubstitute (0, pattern, FcMatchPattern);
1511 FcDefaultSubstitute (pattern);
1512 match = FcFontMatch (0, pattern, &result);
1514 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1515 filename = strdup((char*)v); // mem leak
1516 char *nfn = strrchr(filename, '/');
1517 if(nfn) fontname = strdup(nfn+1);
1518 else fontname = filename;
1520 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1524 //printf("FONTCONFIG: pattern");
1525 //FcPatternPrint(pattern);
1526 //printf("FONTCONFIG: match");
1527 //FcPatternPrint(match);
1529 FcPatternDestroy(pattern);
1530 FcPatternDestroy(match);
1532 pdfswf_addfont(filename);
1539 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1541 char*fontname = 0, *filename = 0;
1542 msg("<notice> subsituteFont(%s)", oldname);
1544 if(!(fontname = searchForSuitableFont(gfxFont))) {
1545 fontname = "Times-Roman";
1547 filename = searchFont(fontname);
1549 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1553 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1554 msg("<fatal> Too many fonts in file.");
1558 substitutesource[substitutepos] = strdup(oldname); //mem leak
1559 substitutetarget[substitutepos] = fontname;
1560 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1563 return strdup(filename); //mem leak
1566 void unlinkfont(char* filename)
1573 if(!strncmp(&filename[l-4],".afm",4)) {
1574 memcpy(&filename[l-4],".pfb",4);
1576 memcpy(&filename[l-4],".pfa",4);
1578 memcpy(&filename[l-4],".afm",4);
1581 if(!strncmp(&filename[l-4],".pfa",4)) {
1582 memcpy(&filename[l-4],".afm",4);
1584 memcpy(&filename[l-4],".pfa",4);
1587 if(!strncmp(&filename[l-4],".pfb",4)) {
1588 memcpy(&filename[l-4],".afm",4);
1590 memcpy(&filename[l-4],".pfb",4);
1595 void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1602 void SWFOutputDev::updateFont(GfxState *state)
1604 GfxFont*gfxFont = state->getFont();
1609 char * fontid = getFontID(gfxFont);
1612 /* first, look if we substituted this font before-
1613 this way, we don't initialize the T1 Fonts
1615 for(t=0;t<substitutepos;t++) {
1616 if(!strcmp(fontid, substitutesource[t])) {
1617 free(fontid);fontid=0;
1618 fontid = strdup(substitutetarget[t]);
1623 /* second, see if swfoutput already has this font
1624 cached- if so, we are done */
1625 if(swfoutput_queryfont(&output, fontid))
1627 swfoutput_setfont(&output, fontid, 0);
1629 msg("<debug> updateFont(%s) [cached]", fontid);
1634 // look for Type 3 font
1635 if (gfxFont->getType() == fontType3) {
1637 type3Warning = gTrue;
1638 showFontError(gfxFont, 2);
1644 /* now either load the font, or find a substitution */
1647 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1652 (gfxFont->getType() == fontType1 ||
1653 gfxFont->getType() == fontType1C ||
1654 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
1655 gfxFont->getType() == fontTrueType ||
1656 gfxFont->getType() == fontCIDType2
1659 fileName = writeEmbeddedFontToFile(xref, gfxFont);
1660 if(!fileName) showFontError(gfxFont,0);
1663 char * fontname = getFontName(gfxFont);
1664 fileName = searchFont(fontname);
1665 if(!fileName) showFontError(gfxFont,0);
1668 char * fontname = getFontName(gfxFont);
1669 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
1670 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
1671 fileName = substituteFont(gfxFont, fontid);
1672 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
1673 msg("<notice> Font is now %s (%s)", fontid, fileName);
1677 msg("<error> Couldn't set font %s\n", fontid);
1682 msg("<verbose> updateFont(%s) -> %s", fontid, fileName);
1683 dumpFontInfo("<verbose>", gfxFont);
1685 swfoutput_setfont(&output, fontid, fileName);
1688 unlinkfont(fileName);
1694 #define SQR(x) ((x)*(x))
1696 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1698 if((newwidth<2 || newheight<2) ||
1699 (width<=newwidth || height<=newheight))
1701 unsigned char*newdata;
1703 newdata= (unsigned char*)malloc(newwidth*newheight);
1705 double fx = (double)(width)/newwidth;
1706 double fy = (double)(height)/newheight;
1708 int blocksize = (int)(8192/(fx*fy));
1709 int r = 8192*256/palettesize;
1710 for(x=0;x<newwidth;x++) {
1711 double ex = px + fx;
1712 int fromx = (int)px;
1714 int xweight1 = (int)(((fromx+1)-px)*256);
1715 int xweight2 = (int)((ex-tox)*256);
1717 for(y=0;y<newheight;y++) {
1718 double ey = py + fy;
1719 int fromy = (int)py;
1721 int yweight1 = (int)(((fromy+1)-py)*256);
1722 int yweight2 = (int)((ey-toy)*256);
1725 for(xx=fromx;xx<=tox;xx++)
1726 for(yy=fromy;yy<=toy;yy++) {
1727 int b = 1-data[width*yy+xx];
1729 if(xx==fromx) weight = (weight*xweight1)/256;
1730 if(xx==tox) weight = (weight*xweight2)/256;
1731 if(yy==fromy) weight = (weight*yweight1)/256;
1732 if(yy==toy) weight = (weight*yweight2)/256;
1735 //if(a) a=(palettesize-1)*r/blocksize;
1736 newdata[y*newwidth+x] = (a*blocksize)/r;
1744 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
1745 int width, int height, GfxImageColorMap*colorMap, GBool invert,
1746 GBool inlineImg, int mask, int*maskColors)
1751 double x1,y1,x2,y2,x3,y3,x4,y4;
1752 ImageStream *imgStr;
1759 ncomps = colorMap->getNumPixelComps();
1760 bits = colorMap->getBits();
1762 imgStr = new ImageStream(str, width, ncomps,bits);
1765 if(!width || !height || (height<=1 && width<=1))
1767 msg("<verbose> Ignoring %d by %d image", width, height);
1768 unsigned char buf[8];
1770 for (y = 0; y < height; ++y)
1771 for (x = 0; x < width; ++x) {
1772 imgStr->getPixel(buf);
1778 state->transform(0, 1, &x1, &y1);
1779 state->transform(0, 0, &x2, &y2);
1780 state->transform(1, 0, &x3, &y3);
1781 state->transform(1, 1, &x4, &y4);
1783 if(!pbminfo && !(str->getKind()==strDCT)) {
1785 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
1789 msg("<verbose> drawing %d by %d masked picture\n", width, height);
1791 if(!jpeginfo && (str->getKind()==strDCT)) {
1792 msg("<notice> file contains jpeg pictures");
1798 unsigned char buf[8];
1800 unsigned char*pic = new unsigned char[width*height];
1803 state->getFillRGB(&rgb);
1805 memset(pal,255,sizeof(pal));
1806 pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
1807 pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
1808 pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
1809 pal[0].a = 255; pal[1].a = 0;
1812 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
1813 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
1814 for (y = 0; y < height; ++y)
1815 for (x = 0; x < width; ++x)
1817 imgStr->getPixel(buf);
1820 pic[width*y+x] = buf[0];
1823 /* the size of the drawn image is added to the identifier
1824 as the same image may require different bitmaps if displayed
1825 at different sizes (due to antialiasing): */
1828 unsigned char*pic2 = 0;
1831 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
1840 height = realheight;
1844 /* make a black/white palette */
1849 float r = 255/(numpalette-1);
1851 for(t=0;t<numpalette;t++) {
1852 pal[t].r = (U8)(255*rgb.r);
1853 pal[t].g = (U8)(255*rgb.g);
1854 pal[t].b = (U8)(255*rgb.b);
1855 pal[t].a = (U8)(t*r);
1859 RGBA*pic2 = new RGBA[width*height];
1860 for (y = 0; y < height; ++y) {
1861 for (x = 0; x < width; ++x) {
1862 pic2[width*y+x] = pal[pic[y*width+x]];
1865 swfoutput_drawimagelossless(&output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1874 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
1875 RGBA*pic=new RGBA[width*height];
1876 for (y = 0; y < height; ++y) {
1877 for (x = 0; x < width; ++x) {
1878 imgStr->getPixel(pixBuf);
1879 colorMap->getRGB(pixBuf, &rgb);
1880 pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
1881 pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
1882 pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
1883 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
1886 if(str->getKind()==strDCT)
1887 swfoutput_drawimagejpeg(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1889 swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1894 RGBA*pic=new RGBA[width*height];
1897 for(t=0;t<256;t++) {
1899 colorMap->getRGB(pixBuf, &rgb);
1900 /*if(maskColors && *maskColors==t) {
1901 msg("<notice> Color %d is transparent", t);
1902 if (imgData->maskColors) {
1904 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
1905 if (pix[i] < imgData->maskColors[2*i] ||
1906 pix[i] > imgData->maskColors[2*i+1]) {
1921 pal[t].r = (U8)(rgb.r * 255 + 0.5);
1922 pal[t].g = (U8)(rgb.g * 255 + 0.5);
1923 pal[t].b = (U8)(rgb.b * 255 + 0.5);
1924 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
1927 for (y = 0; y < height; ++y) {
1928 for (x = 0; x < width; ++x) {
1929 imgStr->getPixel(pixBuf);
1930 pic[width*y+x] = pal[pixBuf[0]];
1933 swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
1941 void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
1942 int width, int height, GBool invert,
1945 if(states[statepos].textRender & 4) //clipped
1947 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
1948 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
1951 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
1952 int width, int height, GfxImageColorMap *colorMap,
1953 int *maskColors, GBool inlineImg)
1955 if(states[statepos].textRender & 4) //clipped
1958 msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height,
1959 colorMap?"colorMap":"no colorMap",
1960 maskColors?"maskColors":"no maskColors",
1963 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
1964 colorMap->getBits(),colorMap->getColorSpace()->getMode());
1965 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
1968 SWFOutputDev*output = 0;
1970 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
1975 if (infoDict->lookup(key, &obj)->isString()) {
1976 s1 = obj.getString();
1977 if ((s1->getChar(0) & 0xff) == 0xfe &&
1978 (s1->getChar(1) & 0xff) == 0xff) {
1980 for (i = 2; i < obj.getString()->getLength(); i += 2) {
1981 if (s1->getChar(i) == '\0') {
1982 s2->append(s1->getChar(i+1));
1985 s2 = new GString("<unicode>");
1989 printf(fmt, s2->getCString());
1992 printf(fmt, s1->getCString());
1998 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
2002 if (infoDict->lookup(key, &obj)->isString()) {
2003 s = obj.getString()->getCString();
2004 if (s[0] == 'D' && s[1] == ':') {
2015 void pdfswf_setparameter(char*name, char*value)
2017 msg("<verbose> setting parameter %s to \"%s\"", name, value);
2018 if(!strcmp(name, "caplinewidth")) {
2019 caplinewidth = atof(value);
2020 } else if(!strcmp(name, "zoom")) {
2023 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2024 swfoutput_setparameter("jpegsubpixels", buf);
2025 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2026 swfoutput_setparameter("ppmsubpixels", buf);
2027 } else if(!strcmp(name, "jpegdpi")) {
2029 jpeg_dpi = atoi(value);
2030 sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
2031 swfoutput_setparameter("jpegsubpixels", buf);
2032 } else if(!strcmp(name, "ppmdpi")) {
2034 ppm_dpi = atoi(value);
2035 sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
2036 swfoutput_setparameter("ppmsubpixels", buf);
2037 } else if(!strcmp(name, "forceType0Fonts")) {
2038 forceType0Fonts = atoi(value);
2039 } else if(!strcmp(name, "fontdir")) {
2040 pdfswf_addfontdir(value);
2041 } else if(!strcmp(name, "languagedir")) {
2042 pdfswf_addlanguagedir(value);
2043 } else if(!strcmp(name, "fontconfig")) {
2044 config_use_fontconfig = atoi(value);
2046 swfoutput_setparameter(name, value);
2049 void pdfswf_addfont(char*filename)
2052 memset(&f, 0, sizeof(fontfile_t));
2053 f.filename = filename;
2054 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2055 fonts[fontnum++] = f;
2057 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2061 static char* dirseparator()
2070 void pdfswf_addlanguagedir(char*dir)
2073 globalParams = new GlobalParams("");
2075 msg("<notice> Adding %s to language pack directories", dir);
2079 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
2080 strcpy(config_file, dir);
2081 strcat(config_file, dirseparator());
2082 strcat(config_file, "add-to-xpdfrc");
2084 fi = fopen(config_file, "rb");
2086 msg("<error> Could not open %s", config_file);
2089 globalParams->parseFile(new GString(config_file), fi);
2093 void pdfswf_addfontdir(char*dirname)
2095 #ifdef HAVE_DIRENT_H
2096 msg("<notice> Adding %s to font directories", dirname);
2097 DIR*dir = opendir(dirname);
2099 msg("<warning> Couldn't open directory %s\n", dirname);
2104 ent = readdir (dir);
2108 char*name = ent->d_name;
2114 if(!strncasecmp(&name[l-4], ".pfa", 4))
2116 if(!strncasecmp(&name[l-4], ".pfb", 4))
2118 if(!strncasecmp(&name[l-4], ".ttf", 4))
2122 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2123 strcpy(fontname, dirname);
2124 strcat(fontname, dirseparator());
2125 strcat(fontname, name);
2126 msg("<verbose> Adding %s to fonts", fontname);
2127 pdfswf_addfont(fontname);
2132 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2137 typedef struct _pdf_doc_internal
2141 } pdf_doc_internal_t;
2142 typedef struct _pdf_page_internal
2144 } pdf_page_internal_t;
2145 typedef struct _swf_output_internal
2147 SWFOutputDev*outputDev;
2148 } swf_output_internal_t;
2150 pdf_doc_t* pdf_init(char*filename, char*userPassword)
2152 pdf_doc_t*pdf_doc = (pdf_doc_t*)malloc(sizeof(pdf_doc_t));
2153 memset(pdf_doc, 0, sizeof(pdf_doc_t));
2154 pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
2155 memset(i, 0, sizeof(pdf_doc_internal_t));
2156 pdf_doc->internal = i;
2158 GString *fileName = new GString(filename);
2164 globalParams = new GlobalParams("");
2167 if (userPassword && userPassword[0]) {
2168 userPW = new GString(userPassword);
2172 i->doc = new PDFDoc(fileName, userPW);
2176 if (!i->doc->isOk()) {
2181 i->doc->getDocInfo(&info);
2182 if (info.isDict() &&
2183 (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
2184 printInfoString(info.getDict(), "Title", "Title: %s\n");
2185 printInfoString(info.getDict(), "Subject", "Subject: %s\n");
2186 printInfoString(info.getDict(), "Keywords", "Keywords: %s\n");
2187 printInfoString(info.getDict(), "Author", "Author: %s\n");
2188 printInfoString(info.getDict(), "Creator", "Creator: %s\n");
2189 printInfoString(info.getDict(), "Producer", "Producer: %s\n");
2190 printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n");
2191 printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n");
2192 printf("Pages: %d\n", i->doc->getNumPages());
2193 printf("Linearized: %s\n", i->doc->isLinearized() ? "yes" : "no");
2194 printf("Encrypted: ");
2195 if (i->doc->isEncrypted()) {
2196 printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
2197 i->doc->okToPrint() ? "yes" : "no",
2198 i->doc->okToCopy() ? "yes" : "no",
2199 i->doc->okToChange() ? "yes" : "no",
2200 i->doc->okToAddNotes() ? "yes" : "no");
2207 pdf_doc->num_pages = i->doc->getNumPages();
2209 if (i->doc->isEncrypted()) {
2210 if(!i->doc->okToCopy()) {
2211 printf("PDF disallows copying.\n");
2214 if(!i->doc->okToChange() || !i->doc->okToAddNotes())
2221 void pdfswf_preparepage(int page)
2225 pages = (int*)malloc(1024*sizeof(int));
2228 if(pagepos == pagebuflen)
2231 pages = (int*)realloc(pages, pagebuflen);
2234 pages[pagepos++] = page;
2241 delete globalParams;globalParams=0;
2242 Object::memCheck(stderr);
2247 void pdf_destroy(pdf_doc_t*pdf_doc)
2249 pdf_doc_internal_t*i= (pdf_doc_internal_t*)pdf_doc->internal;
2251 msg("<debug> pdfswf.cc: pdfswf_close()");
2252 delete i->doc; i->doc=0;
2254 free(pages); pages = 0; //FIXME
2256 free(pdf_doc->internal);pdf_doc->internal=0;
2257 free(pdf_doc);pdf_doc=0;
2260 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
2262 pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
2264 if(page < 1 || page > pdf_doc->num_pages)
2267 pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
2268 pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
2269 memset(pi, 0, sizeof(pdf_page_internal_t));
2270 pdf_page->internal = pi;
2272 pdf_page->parent = pdf_doc;
2273 pdf_page->nr = page;
2277 void pdf_page_destroy(pdf_page_t*pdf_page)
2279 pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
2280 free(pdf_page->internal);pdf_page->internal = 0;
2281 free(pdf_page);pdf_page=0;
2284 swf_output_t* swf_output_init()
2286 swf_output_t*swf_output = (swf_output_t*)malloc(sizeof(swf_output_t));
2287 memset(swf_output, 0, sizeof(swf_output_t));
2288 swf_output_internal_t*i= (swf_output_internal_t*)malloc(sizeof(swf_output_internal_t));
2289 memset(i, 0, sizeof(swf_output_internal_t));
2290 swf_output->internal = i;
2292 i->outputDev = new SWFOutputDev();
2296 void swf_output_setparameter(swf_output_t*swf_output, char*name, char*value)
2299 pdfswf_setparameter(name, value);
2302 void swf_output_pagefeed(swf_output_t*swf)
2304 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2305 i->outputDev->pagefeed();
2306 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2309 int swf_output_save(swf_output_t*swf, char*filename)
2311 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2312 int ret = i->outputDev->save(filename);
2313 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2317 void* swf_output_get(swf_output_t*swf)
2319 swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
2320 void* ret = i->outputDev->getSWF();
2321 i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2325 void swf_output_destroy(swf_output_t*output)
2327 swf_output_internal_t*i = (swf_output_internal_t*)output->internal;
2328 delete i->outputDev; i->outputDev=0;
2329 free(output->internal);output->internal=0;
2333 void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
2335 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2336 swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
2339 swfoutput_setparameter("protect", "1");
2341 si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
2343 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2345 pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2347 si->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
2350 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
2352 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2353 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2355 si->outputDev->setMove(x,y);
2356 if((x1|y1|x2|y2)==0) x2++;
2357 si->outputDev->setClip(x1,y1,x2,y2);
2359 pdf_page_render2(page, output);
2361 void pdf_page_render(pdf_page_t*page, swf_output_t*output)
2363 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2364 swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
2366 si->outputDev->setMove(0,0);
2367 si->outputDev->setClip(0,0,0,0);
2369 pdf_page_render2(page, output);
2373 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
2375 pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
2376 pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
2377 pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
2378 memset(info, 0, sizeof(pdf_page_info_t));
2380 InfoOutputDev*output = new InfoOutputDev;
2383 pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
2385 pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
2388 info->xMin = output->x1;
2389 info->yMin = output->y1;
2390 info->xMax = output->x2;
2391 info->yMax = output->y2;
2392 info->number_of_images = output->num_images;
2393 info->number_of_links = output->num_links;
2394 info->number_of_fonts = output->num_fonts;
2401 void pdf_page_info_destroy(pdf_page_info_t*info)