#include "../devices/ops.h"
#include "../devices/arts.h"
#include "../devices/render.h"
+
+#include "../art/libart.h"
+#include "../devices/artsutils.c"
+
#include "../png.h"
+#include "fonts.h"
#include <math.h>
static char* lastfontdir = 0;
-struct mapping {
+struct fontentry {
char*pdffont;
char*filename;
+ char*afm;
+ int afmlen;
+ char*pfb;
+ int pfblen;
+ char*fullfilename;
} pdf2t1map[] ={
-{"Times-Roman", "n021003l"},
-{"Times-Italic", "n021023l"},
-{"Times-Bold", "n021004l"},
-{"Times-BoldItalic", "n021024l"},
-{"Helvetica", "n019003l"},
-{"Helvetica-Oblique", "n019023l"},
-{"Helvetica-Bold", "n019004l"},
-{"Helvetica-BoldOblique", "n019024l"},
-{"Courier", "n022003l"},
-{"Courier-Oblique", "n022023l"},
-{"Courier-Bold", "n022004l"},
-{"Courier-BoldOblique", "n022024l"},
-{"Symbol", "s050000l"},
-{"ZapfDingbats", "d050000l"}};
-
-static int verbose = 1;
+{"Times-Roman", "n021003l", n021003l_afm, n021003l_afm_len, n021003l_pfb, n021003l_pfb_len},
+{"Times-Italic", "n021023l", n021023l_afm, n021023l_afm_len, n021023l_pfb, n021023l_pfb_len},
+{"Times-Bold", "n021004l", n021004l_afm, n021004l_afm_len, n021004l_pfb, n021004l_pfb_len},
+{"Times-BoldItalic", "n021024l", n021024l_afm, n021024l_afm_len, n021024l_pfb, n021024l_pfb_len},
+{"Helvetica", "n019003l", n019003l_afm, n019003l_afm_len, n019003l_pfb, n019003l_pfb_len},
+{"Helvetica-Oblique", "n019023l", n019023l_afm, n019023l_afm_len, n019023l_pfb, n019023l_pfb_len},
+{"Helvetica-Bold", "n019004l", n019004l_afm, n019004l_afm_len, n019004l_pfb, n019004l_pfb_len},
+{"Helvetica-BoldOblique", "n019024l", n019024l_afm, n019024l_afm_len, n019024l_pfb, n019024l_pfb_len},
+{"Courier", "n022003l", n022003l_afm, n022003l_afm_len, n022003l_pfb, n022003l_pfb_len},
+{"Courier-Oblique", "n022023l", n022023l_afm, n022023l_afm_len, n022023l_pfb, n022023l_pfb_len},
+{"Courier-Bold", "n022004l", n022004l_afm, n022004l_afm_len, n022004l_pfb, n022004l_pfb_len},
+{"Courier-BoldOblique", "n022024l", n022024l_afm, n022024l_afm_len, n022024l_pfb, n022024l_pfb_len},
+{"Symbol", "s050000l", s050000l_afm, s050000l_afm_len, s050000l_pfb, s050000l_pfb_len},
+{"ZapfDingbats", "d050000l", d050000l_afm, d050000l_afm_len, d050000l_pfb, d050000l_pfb_len}};
+
+
+static int verbose = 0;
static int dbgindent = 0;
static void dbg(char*format, ...)
{
} feature_t;
feature_t*featurewarnings = 0;
-static void warnfeature(char*feature,char fully)
+void GFXOutputDev::showfeature(char*feature,char fully, char warn)
{
feature_t*f = featurewarnings;
while(f) {
f->string = strdup(feature);
f->next = featurewarnings;
featurewarnings = f;
- msg("<warning> %s not yet %ssupported!",feature,fully?"fully ":"");
+ if(warn) {
+ msg("<warning> %s not yet %ssupported!",feature,fully?"fully ":"");
+ if(this->config_break_on_warning) {
+ msg("<fatal> Aborting conversion due to unsupported feature");
+ exit(1);
+ }
+ } else {
+ msg("<notice> File contains %s",feature);
+ }
+}
+void GFXOutputDev::warnfeature(char*feature,char fully)
+{
+ showfeature(feature,fully,1);
+}
+void GFXOutputDev::infofeature(char*feature)
+{
+ showfeature(feature,0,0);
}
GFXOutputState::GFXOutputState() {
this->transparencygroup = 0;
this->softmask = 0;
this->grouprecording = 0;
+ this->isolated = 0;
}
GBool GFXOutputDev::interpretType3Chars()
{
- return gTrue;
+ return this->do_interpretType3Chars;
}
typedef struct _drawnchar
{
this->jpeginfo = 0;
this->textmodeinfo = 0;
- this->ttfinfo = 0;
this->linkinfo = 0;
this->pbminfo = 0;
this->type3active = 0;
this->pages = 0;
this->pagebuflen = 0;
this->pagepos = 0;
-
- this->forceType0Fonts=1;
this->config_use_fontconfig=1;
+ this->config_break_on_warning=0;
+ this->do_interpretType3Chars = gTrue;
this->parameters = p;
+
+ memset(states, 0, sizeof(states));
/* configure device */
while(p) {
- if(!strcmp(p->name,"forceType0Fonts")) {
- this->forceType0Fonts = atoi(p->value);
- } else if(!strcmp(p->name,"fontconfig")) {
- this->config_use_fontconfig = atoi(p->value);
- }
+ setParameter(p->name, p->value);
p = p->next;
}
};
+
+void GFXOutputDev::setParameter(char*key, char*value)
+{
+ if(!strcmp(key,"rawtext")) {
+ this->do_interpretType3Chars = atoi(value)^1;
+ } else if(!strcmp(key,"breakonwarning")) {
+ this->config_break_on_warning = atoi(value);
+ } else if(!strcmp(key,"fontconfig")) {
+ this->config_use_fontconfig = atoi(value);
+ } else {
+ msg("<warning> Ignored parameter: %s=%s", key, value);
+ }
+}
void GFXOutputDev::setDevice(gfxdevice_t*dev)
{
parameter_t*p = this->parameters;
- /* TODO: get rid of this */
+ /* pass parameters to output device */
this->device = dev;
if(this->device) {
while(p) {
return result;
}
-/*----------------------------------------------------------------------------
- * Primitive Graphic routines
- *----------------------------------------------------------------------------*/
+GBool GFXOutputDev::useTilingPatternFill()
+{
+ infofeature("tiled patterns");
+ return gFalse;
+}
+
+GBool GFXOutputDev::useShadedFills()
+{
+ infofeature("shaded fills");
+ return gFalse;
+}
-void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
+#define STROKE_FILL 1
+#define STROKE_CLIP 2
+void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line, int flags)
{
int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
);
dump_outline(line);
}
-
- //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
- device->stroke(device, line, width, &col, capType, joinType, miterLimit);
+
+ if(flags&STROKE_FILL) {
+ ArtSVP* svp = gfxstrokeToSVP(line, width, capType, joinType, miterLimit);
+ gfxline_t*gfxline = SVPtogfxline(svp);
+ if(flags&STROKE_CLIP) {
+ device->startclip(device, gfxline);
+ states[statepos].clipping++;
+ } else {
+ device->fill(device, gfxline, &col);
+ }
+ free(gfxline);
+ art_svp_free(svp);
+ } else {
+ if(flags&STROKE_CLIP)
+ msg("<error> Stroke&clip not supported at the same time");
+ device->stroke(device, line, width, &col, capType, joinType, miterLimit);
+ }
if(line2)
gfxline_free(line2);
states[statepos].clipping++;
gfxline_free(line);
}
+void GFXOutputDev::clipToStrokePath(GfxState *state)
+{
+ GfxPath * path = state->getPath();
+ gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex + clipmovex, user_movey + clipmovey);
+ strokeGfxline(state, line, STROKE_FILL|STROKE_CLIP);
+ gfxline_free(line);
+}
void GFXOutputDev::endframe()
{
device->endclip(device);
outer_clip_box = 0;
}
-
- device->endpage(device);
}
void GFXOutputDev::finish()
int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
{
char*uniname = 0;
+ if(!font)
+ return charnr;
if(u>0) {
int t;
/* find out char name from unicode index
gfxmatrix_t m = this->current_font_matrix;
- /*if(render != 3 && render != 0)
- msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
states[statepos].textRender = render;
}
Gushort *CIDToGIDMap = 0;
GfxFont*font = state->getFont();
- if(font->getType() == fontType3) {
+ if(font->getType() == fontType3 && do_interpretType3Chars) {
/* type 3 chars are passed as graphics */
msg("<debug> type3 char at %f/%f", x, y);
return;
current_text_stroke = 0;
} else if((render&3) == RENDER_FILLSTROKE) {
fillGfxLine(state, current_text_stroke);
- strokeGfxline(state, current_text_stroke);
+ strokeGfxline(state, current_text_stroke,0);
gfxline_free(current_text_stroke);
current_text_stroke = 0;
} else if((render&3) == RENDER_STROKE) {
- strokeGfxline(state, current_text_stroke);
+ strokeGfxline(state, current_text_stroke,0);
gfxline_free(current_text_stroke);
current_text_stroke = 0;
}
{
msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
type3active = 1;
+
+ /*int t;
+
+ gfxcolor_t col={255,0,0,0};
+ gfxmatrix_t m = {1,0,0, 0,1,0};
+
+ for(t=0;t<uLen;t++) {
+ device->drawchar(device, 0, u[t], &col, &m);
+ }*/
+
/* the character itself is going to be passed using the draw functions */
return gFalse; /* gTrue= is_in_cache? */
}
device->fill(device, clippath, &white);
}
-void GFXOutputDev::processLink(Link *link, Catalog *catalog)
+
+void GFXOutputDev::processLink(Link *link, Catalog *catalog)
{
double x1, y1, x2, y2, w;
gfxline_t points[5];
statepos--;
}
+char* writeOutStdFont(fontentry* f)
+{
+ FILE*fi;
+ char namebuf1[512];
+ char namebuf2[512];
+ char* tmpFileName = mktmpname(namebuf1);
+
+ sprintf(namebuf2, "%s.afm", tmpFileName);
+ fi = fopen(namebuf2, "wb");
+ if(!fi)
+ return 0;
+ fwrite(f->afm, 1, f->afmlen, fi);
+ fclose(fi);
+
+ sprintf(namebuf2, "%s.pfb", tmpFileName);
+ fi = fopen(namebuf2, "wb");
+ if(!fi)
+ return 0;
+ fwrite(f->pfb, 1, f->pfblen, fi);
+ fclose(fi);
+
+ return strdup(namebuf2);
+}
+
char* GFXOutputDev::searchFont(char*name)
{
int i;
char*filename=0;
- int is_standard_font = 0;
msg("<verbose> SearchFont(%s)", name);
/* see if it is a pdf standard font */
- for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
+ for(i=0;i<sizeof(pdf2t1map)/sizeof(fontentry);i++)
{
if(!strcmp(name, pdf2t1map[i].pdffont))
{
- name = pdf2t1map[i].filename;
- is_standard_font = 1;
- break;
+ if(!pdf2t1map[i].fullfilename) {
+ pdf2t1map[i].fullfilename = writeOutStdFont(&pdf2t1map[i]);
+ if(!pdf2t1map[i].fullfilename) {
+ msg("<error> Couldn't save default font- is the Temp Directory writable?");
+ } else {
+ msg("<verbose> Storing standard PDF font %s at %s", name, pdf2t1map[i].fullfilename);
+ }
+ }
+ return strdup(pdf2t1map[i].fullfilename);
}
}
- /* look in all font files */
+ /* else look in all font files */
for(i=0;i<fontnum;i++)
{
- if(strstr(fonts[i].filename, name))
- {
- if(!fonts[i].used) {
-
- fonts[i].used = 1;
- if(!is_standard_font)
- msg("<notice> Using %s for %s", fonts[i].filename, name);
- }
+ if(strstr(fonts[i].filename, name)) {
return strdup(fonts[i].filename);
}
}
}
FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
if(!cvt) return 0;
- cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
+ cvt->convertToType1(0, NULL, gTrue, FoFiWrite, f);
//cvt->convertToCIDType0("test", f);
//cvt->convertToType0("test", f);
delete cvt;
if(embedded &&
(gfxFont->getType() == fontType1 ||
gfxFont->getType() == fontType1C ||
- (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
+ gfxFont->getType() == fontCIDType0C ||
gfxFont->getType() == fontTrueType ||
gfxFont->getType() == fontCIDType2
))
/* TODO: pass image_dpi to device instead */
dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
- gfxline_show(&p1,stdout);
-
- printf("%.2f %.2f %.2f\n", m.m00, m.m10, m.tx);
- printf("%.2f %.2f %.2f\n", m.m01, m.m11, m.ty);
dev->fillbitmap(dev, &p1, &img, &m, 0);
}
GfxPath * path = state->getPath();
gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex + clipmovex, user_movey + clipmovey);
- strokeGfxline(state, line);
+ strokeGfxline(state, line, 0);
gfxline_free(line);
}
void GFXOutputDev::fill(GfxState *state)
{
- dbg("fill");
+ gfxcolor_t col = getFillColor(state);
+ dbg("fill %02x%02x%02x%02x",col.r,col.g,col.b,col.a);
GfxPath * path = state->getPath();
gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey);
void GFXOutputDev::eoFill(GfxState *state)
{
- dbg("eofill");
-
- GfxPath * path = state->getPath();
gfxcolor_t col = getFillColor(state);
+ dbg("eofill %02x%02x%02x%02x",col.r,col.g,col.b,col.a);
+ GfxPath * path = state->getPath();
gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey);
-
- if(getLogLevel() >= LOGLEVEL_TRACE) {
- msg("<trace> eofill\n");
- dump_outline(line);
- }
-
- device->fill(device, line, &col);
+ fillGfxLine(state, line);
gfxline_free(line);
}
return nbbox;
}
-#if xpdfUpdateVersion >= 16
void GFXOutputDev::beginTransparencyGroup(GfxState *state, double *bbox,
GfxColorSpace *blendingColorSpace,
GBool isolated, GBool knockout,
dbg("beginTransparencyGroup %.1f/%.1f/%.1f/%.1f %s isolated=%d knockout=%d forsoftmask=%d", bbox[0],bbox[1],bbox[2],bbox[3], colormodename, isolated, knockout, forSoftMask);
dbg("using clipping rect %f/%f/%f/%f\n", rect.posx,rect.posy,rect.width,rect.height);
msg("<verbose> beginTransparencyGroup %.1f/%.1f/%.1f/%.1f %s isolated=%d knockout=%d forsoftmask=%d", bbox[0],bbox[1],bbox[2],bbox[3], colormodename, isolated, knockout, forSoftMask);
+
states[statepos].createsoftmask |= forSoftMask;
states[statepos].transparencygroup = !forSoftMask;
- states[statepos].olddevice = this->device;
+ states[statepos].isolated = isolated;
+ states[statepos].olddevice = this->device;
this->device = (gfxdevice_t*)rfx_calloc(sizeof(gfxdevice_t));
gfxdevice_record_init(this->device);
/*if(!forSoftMask) { ////???
state->setFillOpacity(0.0);
}*/
- warnfeature("transparency groups",1);
dbgindent+=2;
}
dbg("paintTransparencyGroup blend=%s softmaskon=%d", blendmodes[state->getBlendMode()], states[statepos].softmask);
msg("<verbose> paintTransparencyGroup blend=%s softmaskon=%d", blendmodes[state->getBlendMode()], states[statepos].softmask);
+
+ if(state->getBlendMode() == gfxBlendNormal)
+ infofeature("transparency groups");
+ else {
+ char buffer[80];
+ sprintf(buffer, "%s blended transparency groups", blendmodes[state->getBlendMode()]);
+ warnfeature(buffer, 0);
+ }
gfxresult_t*grouprecording = states[statepos].grouprecording;
bbox[0], bbox[1], bbox[2], bbox[3], alpha, colToByte(rgb->c[0]), colToByte(rgb->c[1]), colToByte(rgb->c[2]));
msg("<verbose> setSoftMask %.1f/%.1f/%.1f/%.1f alpha=%d backdrop=%02x%02x%02x",
bbox[0], bbox[1], bbox[2], bbox[3], alpha, colToByte(rgb->c[0]), colToByte(rgb->c[1]), colToByte(rgb->c[2]));
- warnfeature("soft masks",0);
+ if(!alpha)
+ infofeature("soft masks");
+ else
+ warnfeature("soft masks from alpha channel",0);
states[statepos].olddevice = this->device;
this->device = (gfxdevice_t*)rfx_calloc(sizeof(gfxdevice_t));
dbg("softmaskrecording is %08x at statepos %d\n", states[statepos].softmaskrecording, statepos);
states[statepos].softmask = 1;
+ states[statepos].softmask_alpha = alpha;
+}
+
+static inline Guchar div255(int x) {
+ return (Guchar)((x + (x >> 8) + 0x80) >> 8);
}
void GFXOutputDev::clearSoftMask(GfxState *state)
#endif
int width = (int)bbox.xmax,height = (int)bbox.ymax;
+ if(width<=0 || height<=0)
+ return;
gfxdevice_t belowrender;
gfxdevice_render_init(&belowrender);
+ if(states[statepos+1].isolated) {
+ belowrender.setparameter(&belowrender, "fillwhite", "1");
+ }
belowrender.setparameter(&belowrender, "antialize", "2");
belowrender.startpage(&belowrender, width, height);
gfxresult_record_replay(below, &belowrender);
belowrender.endpage(&belowrender);
gfxresult_t* belowresult = belowrender.finish(&belowrender);
gfximage_t* belowimg = (gfximage_t*)belowresult->get(belowresult,"page0");
+ //writePNG("below.png", (unsigned char*)belowimg->data, belowimg->width, belowimg->height);
gfxdevice_t maskrender;
gfxdevice_render_init(&maskrender);
gfxcolor_t* l1 = &maskimg->data[maskimg->width*y];
gfxcolor_t* l2 = &belowimg->data[belowimg->width*y];
for(x=0;x<width;x++) {
- l1->a = 255;
- l2->a = (77*l1->r + 151*l1->g + 28*l1->b) >> 8;
+ int alpha;
+ if(states[statepos].softmask_alpha) {
+ alpha = l1->a;
+ } else {
+ alpha = (77*l1->r + 151*l1->g + 28*l1->b) >> 8;
+ }
- /* premultiply alpha... do we need this? (depends on output device)
- l2->r = (l2->a*l2->r) >> 8;
- l2->g = (l2->a*l2->g) >> 8;
- l2->b = (l2->a*l2->b) >> 8;
- */
+ /* premultiply alpha */
+ l2->a = div255(alpha*l2->a);
+ l2->r = div255(alpha*l2->r);
+ l2->g = div255(alpha*l2->g);
+ l2->b = div255(alpha*l2->b);
l1++;
l2++;
belowresult->destroy(belowresult);
states[statepos].softmaskrecording = 0;
}
-#endif
-
+
/*class MemCheck
{
public: ~MemCheck()