X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=pdf2swf%2Fswfoutput.cc;h=19db1a85c01f3c22bbb2f9a6ea6afa40aa186920;hb=d190c41fbaa26ed2af61ec11f304cbed263a06c7;hp=b8b96e94221259613f36843aa6d4b7b62acbf9c5;hpb=5ca580d4583834edd01e83a901d1ec416c3033a1;p=swftools.git diff --git a/pdf2swf/swfoutput.cc b/pdf2swf/swfoutput.cc index b8b96e9..19db1a8 100644 --- a/pdf2swf/swfoutput.cc +++ b/pdf2swf/swfoutput.cc @@ -35,6 +35,7 @@ extern "C" { #include "../lib/log.h" #include "../lib/rfxswf.h" +#include "../lib/gfxdevice.h" } #define CHARDATAMAX 8192 @@ -56,6 +57,8 @@ struct fontlist_t fontlist_t*next; }; +double config_ppmsubpixels=0; +double config_jpegsubpixels=0; int config_opennewwindow=0; int config_ignoredraworder=0; int config_drawonlyshapes=0; @@ -72,6 +75,10 @@ float config_minlinewidth=0.05; typedef struct _swfoutput_internal { + swfoutput*obj; // the swfoutput object where this internal struct resides + + SWF swf; + fontlist_t* fontlist; char storefont; @@ -83,7 +90,6 @@ typedef struct _swfoutput_internal int depth; int startdepth; int linewidth; - SRECT lastpagesize; SHAPE* shape; int shapeid; @@ -96,28 +102,51 @@ typedef struct _swfoutput_internal int lastwasfill; int shapeisempty; char fill; - int sizex; - int sizey; + int min_x,max_x; + int min_y,max_y; TAG* cliptags[128]; int clipshapes[128]; U32 clipdepths[128]; int clippos; + + /* image cache */ + int pic_xids[1024]; + int pic_yids[1024]; + int pic_ids[1024]; + int pic_width[1024]; + int pic_height[1024]; + int picpos; + + int frameno; + int lastframeno; char fillstylechanged; + + int jpeg; //next image type int bboxrectpos; SRECT bboxrect; + + TAG*cliptag; chardata_t chardata[CHARDATAMAX]; int chardatapos; int firstpage; + char pagefinished; + + /* during the transition to the gfxdevice interface: + a device which uses this swfoutput as target */ + gfxdevice_t device; + } swfoutput_internal; + +void swf_fillbitmap(struct _gfxdevice*driver, gfxline_t*line, gfximage_t*img, gfxmatrix_t*move, gfxcxform_t*cxform); +int swf_setparameter(struct _gfxdevice*driver, const char*key, const char*value); static swfoutput_internal* init_internal_struct() { swfoutput_internal*i = (swfoutput_internal*)malloc(sizeof(swfoutput_internal)); memset(i, 0, sizeof(swfoutput_internal)); - i->storefont = 0; i->currentswfid = 0; @@ -126,6 +155,8 @@ static swfoutput_internal* init_internal_struct() i->linewidth = 0; i->shapeid = -1; i->textid = -1; + i->frameno = 0; + i->lastframeno = 0; i->fillstyleid; i->linestyleid; @@ -141,6 +172,11 @@ static swfoutput_internal* init_internal_struct() i->bboxrectpos = -1; i->chardatapos = 0; i->firstpage = 1; + i->pagefinished = 1; + + i->device.internal = (void*)i; + i->device.fillbitmap = swf_fillbitmap; + i->device.setparameter = swf_setparameter; return i; }; @@ -630,15 +666,15 @@ void drawShortPathWithEnds(struct swfoutput*obj, double x, double y, struct swfm if(dir) { /* FIXME: box should be smaller */ q0.x = 0; q0.y = 0; - q1.x = i->sizex; q1.y = 0; - q2.x = i->sizex; q2.y = i->sizey; - q3.x = 0; q3.y = i->sizey; + q1.x = i->max_x; q1.y = 0; + q2.x = i->max_x; q2.y = i->max_y; + q3.x = 0; q3.y = i->max_y; } else { /* FIXME: box should be smaller */ - q0.x = i->sizex; q0.y = i->sizey; - q1.x = 0; q1.y = i->sizey; + q0.x = i->max_x; q0.y = i->max_y; + q1.x = 0; q1.y = i->max_y; q2.x = 0; q2.y = 0; - q3.x = i->sizex; q3.y = 0; + q3.x = i->max_x; q3.y = 0; } q4.x = p0.x; q4.y = p0.y; @@ -798,12 +834,18 @@ void drawpath2poly(struct swfoutput *obj, SWF_OUTLINE*outline, struct swfmatrix* tmp->last = 0; while(1) { + double previousx = x, previousy = y; if(tmp) { x += (tmp->dest.x/(float)0xffff); y += (tmp->dest.y/(float)0xffff); } if(!tmp || tmp->type == SWF_PATHTYPE_MOVE) { if(valid && last) { + if(fabs(lastx-previousx)<0.001 && fabs(lasty-previousy)<0.001) { + /* endpoints match- the path is closed. + Don't bother to draw endings */ + drawShortPath(obj, lastx, lasty, m, last); + } if(last->type == SWF_PATHTYPE_LINE && t1linelen(obj,last)>line_width*2 && lastwasline && line_cap != LINE_CAP_ROUND) drawShortPathWithStraightEnds(obj, lastx, lasty, m, last, valid, line_cap, line_join, line_width); @@ -818,7 +860,7 @@ void drawpath2poly(struct swfoutput *obj, SWF_OUTLINE*outline, struct swfmatrix* lasty = y; } else { if(!last) - last = tmp; + last = tmp; //remember last stroke start (first segment after moveto) valid++; } @@ -1150,7 +1192,7 @@ static void endtext(swfoutput*obj) swf_SetRect(i->tag,&r); MATRIX m; - swf_GetMatrix(0, &m); + swf_GetMatrix(0, &m); /* set unit matrix- the real matrix is in the placeobject */ swf_SetMatrix(i->tag,&m); putcharacters(obj, i->tag); @@ -1226,7 +1268,7 @@ int getCharID(SWFFONT *font, int charnr, char *charname, int u) } } - if(u>0) { + if(u>0 && font->encoding != 255) { /* try to use the unicode id */ if(u>=0 && umaxascii && font->ascii2glyph[u]>=0) { msg(" Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->ascii2glyph[u]); @@ -1292,10 +1334,31 @@ void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename) msg(" Couldn't load font %s (%s)", fontid, filename); swffont = swf_LoadFont(0); } + + if(swffont->glyph2ascii) { + int t; + int bad = 0; + /* check whether the Unicode indices look o.k. + If they don't, disable the unicode lookup by setting + the encoding to 255 */ + for(t=0;tnumchars;t++) { + int c = swffont->glyph2ascii[t]; + if(c && c < 32 && swffont->glyph[t].shape->bitlen > 16) { + // the character maps into the unicode control character range + // between 0001-001f. Yet it is not empty. Treat the one + // mapping as broken, and look how many of those we find. + bad ++; + } + } + if(bad>5) { + msg(" Font %s has bad unicode mapping", fontid); + swffont->encoding = 255; + } + } swf_FontSetID(swffont, ++i->currentswfid); - if(screenloglevel >= LOGLEVEL_DEBUG) { + if(getScreenLogLevel() >= LOGLEVEL_DEBUG) { // print font information msg(" Font %s (%s)",swffont->name, filename); msg(" | ID: %d", swffont->id); @@ -1397,6 +1460,15 @@ static void endpage(struct swfoutput*obj) endtext(obj); while(i->clippos) swfoutput_endclip(obj); + i->pagefinished = 1; +} + +void swfoutput_pagefeed(struct swfoutput*obj) +{ + swfoutput_internal*i = (swfoutput_internal*)obj->internal; + + if(!i->pagefinished) + endpage(obj); if(config_insertstoptag) { ActionTAG*atag=0; @@ -1406,81 +1478,91 @@ static void endpage(struct swfoutput*obj) swf_ActionSet(i->tag,atag); } i->tag = swf_InsertTag(i->tag,ST_SHOWFRAME); + i->frameno ++; + + for(i->depth--;i->depth>=i->startdepth;i->depth--) { + i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2); + swf_SetU16(i->tag,i->depth); + } + i->depth = i->startdepth; +} + +static void setBackground(struct swfoutput*obj, int x1, int y1, int x2, int y2) +{ + swfoutput_internal*i = (swfoutput_internal*)obj->internal; + RGBA rgb; + rgb.a = rgb.r = rgb.g = rgb.b = 0xff; + SRECT r; + SHAPE* s; + int ls1=0,fs1=0; + int shapeid = ++i->currentswfid; + r.xmin = x1; + r.ymin = y1; + r.xmax = x2; + r.ymax = y2; + i->tag = swf_InsertTag(i->tag, ST_DEFINESHAPE); + swf_ShapeNew(&s); + fs1 = swf_ShapeAddSolidFillStyle(s, &rgb); + swf_SetU16(i->tag,shapeid); + swf_SetRect(i->tag,&r); + swf_SetShapeHeader(i->tag,s); + swf_ShapeSetAll(i->tag,s,x1,y1,ls1,fs1,0); + swf_ShapeSetLine(i->tag,s,(x2-x1),0); + swf_ShapeSetLine(i->tag,s,0,(y2-y1)); + swf_ShapeSetLine(i->tag,s,(x1-x2),0); + swf_ShapeSetLine(i->tag,s,0,(y1-y2)); + swf_ShapeSetEnd(i->tag); + swf_ShapeFree(s); + i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2); + swf_ObjectPlace(i->tag,shapeid,i->depth++,0,0,0); + i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2); + swf_ObjectPlaceClip(i->tag,shapeid,i->depth++,0,0,0,65535); + i->cliptag = i->tag; } void swfoutput_newpage(struct swfoutput*obj, int pageNum, int movex, int movey, int x1, int y1, int x2, int y2) { swfoutput_internal*i = (swfoutput_internal*)obj->internal; - if(!i->firstpage) + if(!i->firstpage && !i->pagefinished) endpage(obj); swf_GetMatrix(0, &i->page_matrix); - i->page_matrix.tx = movex; - i->page_matrix.ty = movey; - - for(i->depth--;i->depth>=i->startdepth;i->depth--) { - i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2); - swf_SetU16(i->tag,i->depth); - } - i->depth = i->startdepth = 3; /* leave room for clip and background rectangle */ + i->page_matrix.tx = movex*20; + i->page_matrix.ty = movey*20; + + if(i->cliptag && i->frameno == i->lastframeno) { + SWFPLACEOBJECT obj; + swf_GetPlaceObject(i->cliptag, &obj); + obj.clipdepth = i->depth++; + swf_ResetTag(i->cliptag, i->cliptag->id); + swf_SetPlaceObject(i->cliptag, &obj); + swf_PlaceObjectFree(&obj); + } + + i->min_x = x1; + i->min_y = y1; + i->max_x = x2; + i->max_y = y2; + + msg(" processing page %d (%dx%d:%d:%d)", pageNum,x2-x1,y2-y1, x1, y1); - i->sizex = x2; - i->sizey = y2; x1*=20;y1*=20;x2*=20;y2*=20; - if(i->lastpagesize.xmin != x1 || - i->lastpagesize.xmax != x2 || - i->lastpagesize.ymin != y1 || - i->lastpagesize.ymax != y2) - {/* add white clipping rectangle */ - msg(" processing page %d (%dx%d)", pageNum,i->sizex,i->sizey); - - if(!i->firstpage) { - msg(" Page has a different size than previous ones"); - i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2); - swf_SetU16(i->tag,1); - i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2); - swf_SetU16(i->tag,2); - } - - RGBA rgb; - rgb.a = rgb.r = rgb.g = rgb.b = 0xff; - SRECT r; - SHAPE* s; - int ls1=0,fs1=0; - int shapeid = ++i->currentswfid; - r.xmin = x1; - r.ymin = y1; - r.xmax = x2; - r.ymax = y2; - i->tag = swf_InsertTag(i->tag, ST_DEFINESHAPE); - swf_ShapeNew(&s); - fs1 = swf_ShapeAddSolidFillStyle(s, &rgb); - swf_SetU16(i->tag,shapeid); - swf_SetRect(i->tag,&r); - swf_SetShapeHeader(i->tag,s); - swf_ShapeSetAll(i->tag,s,x1,y1,ls1,fs1,0); - swf_ShapeSetLine(i->tag,s,(x2-x1),0); - swf_ShapeSetLine(i->tag,s,0,(y2-y1)); - swf_ShapeSetLine(i->tag,s,(x1-x2),0); - swf_ShapeSetLine(i->tag,s,0,(y1-y2)); - swf_ShapeSetEnd(i->tag); - swf_ShapeFree(s); - i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2); - swf_ObjectPlace(i->tag,shapeid,/*depth*/1,0,0,0); - i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2); - swf_ObjectPlaceClip(i->tag,shapeid,/*depth*/2,0,0,0,65535); - } else { - msg(" processing page %d", pageNum); - } + /* set clipping/background rectangle */ + /* TODO: this should all be done in SWFOutputDev */ + setBackground(obj, x1, y1, x2, y2); - i->lastpagesize.xmin = x1; - i->lastpagesize.xmax = x2; - i->lastpagesize.ymin = y1; - i->lastpagesize.ymax = y2; - swf_ExpandRect2(&obj->swf.movieSize, &i->lastpagesize); + /* increase SWF's bounding box */ + SRECT r; + r.xmin = x1; + r.ymin = y1; + r.xmax = x2; + r.ymax = y2; + swf_ExpandRect2(&i->swf.movieSize, &r); + i->lastframeno = i->frameno; i->firstpage = 0; + i->pagefinished = 0; } /* initialize the swf writer */ @@ -1488,33 +1570,33 @@ void swfoutput_init(struct swfoutput* obj) { memset(obj, 0, sizeof(struct swfoutput)); obj->internal = init_internal_struct(); + ((swfoutput_internal*)obj->internal)->obj = obj; swfoutput_internal*i = (swfoutput_internal*)obj->internal; SRECT r; RGBA rgb; - msg(" initializing swf output for size %d*%d\n", i->sizex,i->sizey); + msg(" initializing swf output for size %d*%d\n", i->max_x,i->max_y); obj->swffont = 0; obj->drawmode = -1; - memset(&obj->swf,0x00,sizeof(SWF)); - memset(&i->lastpagesize,0x00,sizeof(SRECT)); - - obj->swf.fileVersion = config_flashversion; - obj->swf.frameRate = 0x0040; // 1 frame per 4 seconds - obj->swf.movieSize.xmin = 0; - obj->swf.movieSize.ymin = 0; - obj->swf.movieSize.xmax = 0; - obj->swf.movieSize.ymax = 0; + memset(&i->swf,0x00,sizeof(SWF)); + + i->swf.fileVersion = config_flashversion; + i->swf.frameRate = 0x0040; // 1 frame per 4 seconds + i->swf.movieSize.xmin = 0; + i->swf.movieSize.ymin = 0; + i->swf.movieSize.xmax = 0; + i->swf.movieSize.ymax = 0; - obj->swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR); - i->tag = obj->swf.firstTag; + i->swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR); + i->tag = i->swf.firstTag; rgb.a = rgb.r = rgb.g = rgb.b = 0xff; swf_SetRGB(i->tag,&rgb); - i->startdepth = i->depth = 0; + i->startdepth = i->depth = 3; /* leave room for clip and background rectangle */ if(config_protect) i->tag = swf_InsertTag(i->tag, ST_PROTECT); @@ -1523,7 +1605,6 @@ void swfoutput_init(struct swfoutput* obj) static void startshape(struct swfoutput*obj) { swfoutput_internal*i = (swfoutput_internal*)obj->internal; - RGBA rgb; SRECT r; if(i->textid>=0) @@ -1533,19 +1614,17 @@ static void startshape(struct swfoutput*obj) swf_ShapeNew(&i->shape); i->linestyleid = swf_ShapeAddLineStyle(i->shape,i->linewidth,&obj->strokergb); - rgb.r = obj->fillrgb.r; - rgb.g = obj->fillrgb.g; - rgb.b = obj->fillrgb.b; i->fillstyleid = swf_ShapeAddSolidFillStyle(i->shape,&obj->fillrgb); i->shapeid = ++i->currentswfid; swf_SetU16(i->tag,i->shapeid); // ID i->bboxrectpos = i->tag->len; + /* changed later */ r.xmin = 0; r.ymin = 0; - r.xmax = 20*i->sizex; - r.ymax = 20*i->sizey; + r.xmax = 20*i->max_x; + r.ymax = 20*i->max_y; swf_SetRect(i->tag,&r); memset(&i->bboxrect, 0, sizeof(i->bboxrect)); @@ -1671,8 +1750,9 @@ static void endshape(swfoutput*obj, int clipdepth) fixAreas(obj); if(i->shapeisempty || + /*bbox empty?*/ (i->bboxrect.xmin == i->bboxrect.xmax && - i->bboxrect.ymin == i->bboxrect.ymax)) + i->bboxrect.ymin == i->bboxrect.ymax)) { // delete the shape again, we didn't do anything cancelshape(obj); @@ -1696,13 +1776,20 @@ static void endshape(swfoutput*obj, int clipdepth) i->bboxrectpos = -1; } -int swfoutput_save(struct swfoutput* obj, char*filename) +void swfoutput_finalize(struct swfoutput*obj) { swfoutput_internal*i = (swfoutput_internal*)obj->internal; + + if(i->tag && i->tag->id == ST_END) + return; //already done + + if(i->frameno == i->lastframeno) // fix: add missing pagefeed + swfoutput_pagefeed(obj); + endpage(obj); fontlist_t *tmp,*iterator = i->fontlist; while(iterator) { - TAG*mtag = obj->swf.firstTag; + TAG*mtag = i->swf.firstTag; if(iterator->swffont) { mtag = swf_InsertTag(mtag, ST_DEFINEFONT2); /*if(!storeallcharacters) @@ -1712,8 +1799,42 @@ int swfoutput_save(struct swfoutput* obj, char*filename) iterator = iterator->next; } - int fi; + i->tag = swf_InsertTag(i->tag,ST_END); + TAG* tag = i->tag->prev; + + /* remove the removeobject2 tags between the last ST_SHOWFRAME + and the ST_END- they confuse the flash player */ + while(tag->id == ST_REMOVEOBJECT2) { + TAG* prev = tag->prev; + swf_DeleteTag(tag); + tag = prev; + } +} + +SWF* swfoutput_get(struct swfoutput*obj) +{ + swfoutput_internal*i = (swfoutput_internal*)obj->internal; + + swfoutput_finalize(obj); + + return swf_CopySWF(&i->swf); +} + +void swfoutput_getdimensions(struct swfoutput*obj, int*x1, int*y1, int*x2, int*y2) +{ + swfoutput_internal*i = (swfoutput_internal*)obj->internal; + if(x1) *x1 = i->swf.movieSize.xmin/20; + if(y1) *y1 = i->swf.movieSize.ymin/20; + if(x2) *x2 = i->swf.movieSize.xmax/20; + if(y2) *y2 = i->swf.movieSize.ymax/20; +} + +int swfoutput_save(struct swfoutput* obj, char*filename) +{ + swfoutput_internal*i = (swfoutput_internal*)obj->internal; + swfoutput_finalize(obj); + int fi; if(filename) fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777); else @@ -1723,14 +1844,12 @@ int swfoutput_save(struct swfoutput* obj, char*filename) msg(" Could not create \"%s\". ", FIXNULL(filename)); return 0; } - - i->tag = swf_InsertTag(i->tag,ST_END); - + if(config_enablezlib || config_flashversion>=6) { - if FAILED(swf_WriteSWC(fi,&obj->swf)) + if FAILED(swf_WriteSWC(fi,&i->swf)) msg(" WriteSWC() failed.\n"); } else { - if FAILED(swf_WriteSWF(fi,&obj->swf)) + if FAILED(swf_WriteSWF(fi,&i->swf)) msg(" WriteSWF() failed.\n"); } @@ -1758,7 +1877,7 @@ void swfoutput_destroy(struct swfoutput* obj) iterator = iterator->next; delete tmp; } - swf_FreeTags(&obj->swf); + swf_FreeTags(&i->swf); free(i);i=0; memset(obj, 0, sizeof(swfoutput)); @@ -1990,7 +2109,7 @@ static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions if(points[t].x box.xmax) + box.xmax = x; + if(y < box.ymin) + box.ymin = y; + if(y > box.ymax) + box.ymax = y; + return box; +} + +gfxbbox_t gfxline_getbbox(gfxline_t*line) +{ + gfxcoord_t x=0,y=0; + gfxbbox_t bbox = {0,0,0,0}; + char last = 0; + while(line) { + if(line->type == gfx_moveTo) { + last = 1; + } else if(line->type == gfx_lineTo) { + if(last) bbox = gfxbbox_expand_to_point(bbox, x, y); + bbox = gfxbbox_expand_to_point(bbox, line->x, line->y); + last = 0; + } else if(line->type == gfx_splineTo) { + if(last) bbox = gfxbbox_expand_to_point(bbox, x, y); + bbox = gfxbbox_expand_to_point(bbox, line->sx, line->sy); + bbox = gfxbbox_expand_to_point(bbox, line->x, line->y); + last = 0; + } + x = line->x; + y = line->x; + line = line->next; + } + return bbox; +} +/* ---------- */ + +static void drawgfxline(struct swfoutput*obj, gfxline_t*line) { swfoutput_internal*i = (swfoutput_internal*)obj->internal; - RGBA rgb; - SRECT r; - int lsid=0; - int fsid; - struct plotxy p1,p2,p3,p4; - int myshapeid; - double xmax=x1,ymax=y1,xmin=x1,ymin=y1; - if(x2>xmax) xmax=x2; - if(y2>ymax) ymax=y2; - if(x2xmax) xmax=x3; - if(y3>ymax) ymax=y3; - if(x3xmax) xmax=x4; - if(y4>ymax) ymax=y4; - if(x4type == gfx_moveTo) { + moveto(obj, i->tag, line->x, line->y); + } if(line->type == gfx_lineTo) { + lineto(obj, i->tag, line->x, line->y); + } else if(line->type == gfx_splineTo) { + plotxy s,p; + s.x = line->sx;p.x = line->x; + s.y = line->sy;p.y = line->y; + splineto(obj, i->tag, s, p); + } + line = line->next; + } +} +static CXFORM gfxcxform_to_cxform(gfxcxform_t* c) +{ + CXFORM cx; + swf_GetCXForm(0, &cx, 1); + if(!c) + return cx; + if(c->rg!=0 || c->rb!=0 || c->ra!=0 || + c->gr!=0 || c->gb!=0 || c->ga!=0 || + c->br!=0 || c->bg!=0 || c->ba!=0 || + c->ar!=0 || c->ag!=0 || c->ab!=0) + msg(" CXForm not SWF-compatible"); - {p1.x = (int)(p1.x*20)/20.0; - p1.y = (int)(p1.y*20)/20.0; - p2.x = (int)(p2.x*20)/20.0; - p2.y = (int)(p2.y*20)/20.0; - p3.x = (int)(p3.x*20)/20.0; - p3.y = (int)(p3.y*20)/20.0; - p4.x = (int)(p4.x*20)/20.0; - p4.y = (int)(p4.y*20)/20.0;} + cx.a0 = (S16)(c->aa*256); + cx.r0 = (S16)(c->rr*256); + cx.g0 = (S16)(c->gg*256); + cx.b0 = (S16)(c->bb*256); + cx.a1 = c->t.a; + cx.r1 = c->t.r; + cx.g1 = c->t.g; + cx.b1 = c->t.b; + return cx; +} + +static int add_image(swfoutput_internal*i, gfximage_t*img, int targetwidth, int targetheight, int* newwidth, int* newheight) +{ + RGBA*newpic = 0; + RGBA*mem = (RGBA*)img->data; + int bitid = ++i->currentswfid; - MATRIX m; - m.sx = (int)(65536*20*(p4.x-p1.x)/sizex); - m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex); - m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey); - m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey); + int sizex = img->width; + int sizey = img->height; + int num_colors = swf_ImageGetNumberOfPaletteEntries(mem,sizex,sizey,0); + int has_alpha = swf_ImageHasAlpha(mem,sizex,sizey); + int is_jpeg = i->jpeg; + i->jpeg = 0; - m.tx = (int)(p1.x*20); - m.ty = (int)(p1.y*20); + int newsizex=sizex, newsizey=sizey; + + /// { + if(is_jpeg && config_jpegsubpixels) { + newsizex = (int)(targetwidth*config_jpegsubpixels+0.5); + newsizey = (int)(targetheight*config_jpegsubpixels+0.5); + } else if(!is_jpeg && config_ppmsubpixels) { + newsizex = (int)(targetwidth*config_ppmsubpixels+0.5); + newsizey = (int)(targetheight*config_ppmsubpixels+0.5); + } + /// } + + *newwidth = newsizex; + *newheight = newsizey; + + + /* TODO: cache images */ + + msg(" Drawing %dx%d %s%simage at size %dx%d (%dx%d), %s%d colors", + sizex, sizey, + has_alpha?(has_alpha==2?"semi-transparent ":"transparent "):"", + is_jpeg?"jpeg-":"", + newsizex, newsizey, + targetwidth, targetheight, + /*newsizex, newsizey,*/ + num_colors>256?">":"", num_colors>256?256:num_colors); + + if(newsizex!=sizex || newsizey!=sizey) { + newpic = swf_ImageScale(mem, sizex, sizey, newsizex, newsizey); + sizex = newsizex; + sizey = newsizey; + mem = newpic; + } + + if(has_alpha) { + if(num_colors<=256 || sizex<8 || sizey<8) { + i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSLOSSLESS2); + swf_SetU16(i->tag, bitid); + swf_SetLosslessImage(i->tag,mem,sizex,sizey); + } else { + /*TODO: check what is smaller */ + i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSJPEG3); + swf_SetU16(i->tag, bitid); + swf_SetJPEGBits3(i->tag,sizex,sizey,mem,config_jpegquality); + //swf_SetLosslessImage(i->tag,mem,sizex,sizey); + } + } else { + if(num_colors<=256 || sizex<8) { + i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSLOSSLESS); + swf_SetU16(i->tag, bitid); + swf_SetLosslessImage(i->tag,mem,sizex,sizey); + } else { + /*TODO: check what is smaller */ + i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSJPEG2); + swf_SetU16(i->tag, bitid); + swf_SetJPEGBits2(i->tag,sizex,sizey,mem,config_jpegquality); + //swf_SetLosslessImage(i->tag,mem,sizex,sizey); + } + } + + if(newpic) + free(newpic); + + return bitid; +} + +void swf_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform) +{ + swfoutput_internal*i = (swfoutput_internal*)dev->internal; + swfoutput*obj = i->obj; + + if(i->shapeid>=0) + endshape(obj,0); + if(i->textid>=0) + endtext(obj); + + gfxbbox_t bbox = gfxline_getbbox(line); + + int targetx = (int)(sqrt(matrix->m00*matrix->m00 + matrix->m01*matrix->m01)*img->width); + int targety = (int)(sqrt(matrix->m10*matrix->m10 + matrix->m11*matrix->m11)*img->height); + + int newwidth=0,newheight=0; + int bitid = add_image(i, img, targetx, targety, &newwidth, &newheight); + double fx = (double)img->width / (double)newwidth; + double fy = (double)img->height / (double)newheight; + + MATRIX m; + float m00,m10,tx; + float m01,m11,ty; + m.sx = (int)(65536*20*matrix->m00*fx); + m.r0 = (int)(65536*20*matrix->m01*fx); + m.r1 = (int)(65536*20*matrix->m10*fy); + m.sy = (int)(65536*20*matrix->m11*fy); + m.tx = (int)(matrix->tx*20); + m.ty = (int)(matrix->ty*20); /* shape */ - myshapeid = ++i->currentswfid; + int myshapeid = ++i->currentswfid; i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE); SHAPE*shape; swf_ShapeNew(&shape); - //lsid = ShapeAddLineStyle(shape,linewidth,&obj->strokergb); - //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb); - fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1); + int fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1); + SRECT r; swf_SetU16(i->tag, myshapeid); - r.xmin = (int)(xmin*20); - r.ymin = (int)(ymin*20); - r.xmax = (int)(xmax*20); - r.ymax = (int)(ymax*20); + r.xmin = (int)(bbox.xmin*20); + r.ymin = (int)(bbox.ymin*20); + r.xmax = (int)(bbox.xmax*20); + r.ymax = (int)(bbox.ymax*20); swf_SetRect(i->tag,&r); swf_SetShapeStyles(i->tag,shape); swf_ShapeCountBits(shape,NULL,NULL); swf_SetShapeBits(i->tag,shape); - swf_ShapeSetAll(i->tag,shape,/*x*/0,/*y*/0,lsid,fsid,0); + swf_ShapeSetAll(i->tag,shape,/*x*/0,/*y*/0,/*ls*/0,fsid,0); i->swflastx = i->swflasty = 0; - moveto(obj, i->tag, p1); - lineto(obj, i->tag, p2); - lineto(obj, i->tag, p3); - lineto(obj, i->tag, p4); - lineto(obj, i->tag, p1); - /* - ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20)); - ShapeSetLine (tag, shape, (int)(x1*20); - ShapeSetLine (tag, shape, x*20,0); - ShapeSetLine (tag, shape, 0,-y*20); - ShapeSetLine (tag, shape, -x*20,0);*/ + drawgfxline(obj, line); swf_ShapeSetEnd(i->tag); swf_ShapeFree(shape); - /* instance */ i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2); - - swf_ObjectPlace(i->tag,myshapeid,/*depth*/i->depth++,&i->page_matrix,NULL,NULL); + CXFORM cxform2 = gfxcxform_to_cxform(cxform); + swf_ObjectPlace(i->tag,myshapeid,/*depth*/i->depth++,&i->page_matrix,&cxform2,NULL); } -int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey, +#define IMAGE_TYPE_JPEG 0 +#define IMAGE_TYPE_LOSSLESS 1 + +static void swfoutput_drawimage(struct swfoutput*obj, RGBA* data, int sizex,int sizey, double x1,double y1, double x2,double y2, double x3,double y3, - double x4,double y4) + double x4,double y4, int type) { swfoutput_internal*i = (swfoutput_internal*)obj->internal; - TAG*oldtag; - if(i->shapeid>=0) - endshape(obj,0); - if(i->textid>=0) - endtext(obj); - int bitid = ++i->currentswfid; - oldtag = i->tag; - i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSJPEG2); - swf_SetU16(i->tag, bitid); - if(swf_SetJPEGBits(i->tag, filename, config_jpegquality)<0) { - swf_DeleteTag(i->tag); - i->tag = oldtag; - return -1; + RGBA*newpic=0; + + double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1)); + double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)); + + gfxline_t p1,p2,p3,p4,p5; + p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2; + p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3; + p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4; + p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5; + p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0; + + {p1.x = (int)(p1.x*20)/20.0; + p1.y = (int)(p1.y*20)/20.0; + p2.x = (int)(p2.x*20)/20.0; + p2.y = (int)(p2.y*20)/20.0; + p3.x = (int)(p3.x*20)/20.0; + p3.y = (int)(p3.y*20)/20.0; + p4.x = (int)(p4.x*20)/20.0; + p4.y = (int)(p4.y*20)/20.0; + p5.x = (int)(p5.x*20)/20.0; + p5.y = (int)(p5.y*20)/20.0; } + + float m00,m10,tx; + float m01,m11,ty; + + gfxmatrix_t m; + m.m00 = (p4.x-p1.x)/sizex; + m.m01 = (p1.x-p2.x)/sizey; + m.m10 = -(p4.y-p1.y)/sizex; + m.m11 = -(p1.y-p2.y)/sizey; + m.tx = p1.x - 0.5; + m.ty = p1.y - 0.5; + + gfximage_t img; + img.data = (gfxcolor_t*)data; + img.width = sizex; + img.height = sizey; + + if(type == IMAGE_TYPE_JPEG) + /* TODO: pass image_dpi to device instead */ + i->device.setparameter(&i->device, "next_bitmap_is_jpeg", "1"); - drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4); - return bitid; + i->device.fillbitmap(&i->device, &p1, &img, &m, 0); } -int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey, - double x1,double y1, - double x2,double y2, - double x3,double y3, - double x4,double y4) +void swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey, + double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4) { - swfoutput_internal*i = (swfoutput_internal*)obj->internal; - TAG*oldtag; - JPEGBITS*jpeg; - - if(i->shapeid>=0) - endshape(obj,0); - if(i->textid>=0) - endtext(obj); - - int bitid = ++i->currentswfid; - oldtag = i->tag; - i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSJPEG2); - swf_SetU16(i->tag, bitid); - swf_SetJPEGBits2(i->tag,sizex,sizey,mem,config_jpegquality); - drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4); - return bitid; + swfoutput_drawimage(obj,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG); } -int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey, - double x1,double y1, - double x2,double y2, - double x3,double y3, - double x4,double y4) +void swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey, + double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4) { - swfoutput_internal*i = (swfoutput_internal*)obj->internal; - TAG*oldtag; - if(i->shapeid>=0) - endshape(obj,0); - if(i->textid>=0) - endtext(obj); - - int bitid = ++i->currentswfid; - oldtag = i->tag; - i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSLOSSLESS); - swf_SetU16(i->tag, bitid); - if(swf_SetLosslessBits(i->tag,sizex,sizey,mem, BMF_32BIT)<0) { - swf_DeleteTag(i->tag); - i->tag = oldtag; - return -1; - } - - drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4); - return bitid; + swfoutput_drawimage(obj,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS); } -int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey, - double x1,double y1, - double x2,double y2, - double x3,double y3, - double x4,double y4, int n) +int swf_setparameter(gfxdevice_t*dev, const char*key, const char*value) { - swfoutput_internal*i = (swfoutput_internal*)obj->internal; - TAG*oldtag; - U8*mem2 = 0; - if(i->shapeid>=0) - endshape(obj,0); - if(i->textid>=0) - endtext(obj); - - if(sizex&3) - { - /* SWF expects scanlines to be 4 byte aligned */ - int x,y; - U8*ptr; - mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey); - ptr = mem2; - for(y=0;yinternal)->jpeg = 1; + return 1; } - - int bitid = ++i->currentswfid; - oldtag = i->tag; - i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSLOSSLESS2); - swf_SetU16(i->tag, bitid); - if(swf_SetLosslessBitsIndexed(i->tag,sizex,sizey,mem, pal, n)<0) { - swf_DeleteTag(i->tag); - i->tag = oldtag; - return -1; - } - if(mem2) - free(mem2); - - drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4); - return bitid; -} - -void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey, - double x1,double y1, - double x2,double y2, - double x3,double y3, - double x4,double y4) -{ - swfoutput_internal*i = (swfoutput_internal*)obj->internal; - if(id<0) return; - if(i->shapeid>=0) - endshape(obj,0); - if(i->textid>=0) - endtext(obj); - - drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4); + return 0; } void swfoutput_setparameter(char*name, char*value) { - if(!strcmp(name, "drawonlyshapes")) { + if(!strcmp(name, "jpegsubpixels")) { + config_jpegsubpixels = atof(value); + } else if(!strcmp(name, "ppmsubpixels")) { + config_ppmsubpixels = atof(value); + } else if(!strcmp(name, "drawonlyshapes")) { config_drawonlyshapes = atoi(value); } else if(!strcmp(name, "ignoredraworder")) { config_ignoredraworder = atoi(value);