+ swf_SetRect(i->tag,&r);
+ swf_SetShapeStyles(i->tag,i->shape);
+ swf_ShapeCountBits(i->shape,NULL,NULL);
+ swf_SetShapeBits(i->tag,i->shape);
+ swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,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);
+ swf_ShapeSetEnd(i->tag);
+
+ /* shape2 */
+ myshapeid2 = ++i->currentswfid;
+ i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE3);
+ swf_ShapeNew(&i->shape);
+ rgb.r = rgb.b = rgb.a = rgb.g = 255;
+ rgb.a = 40;
+ fsid = swf_ShapeAddSolidFillStyle(i->shape,&rgb);
+ swf_SetU16(i->tag, myshapeid2);
+ r.xmin = (int)(xmin*20);
+ r.ymin = (int)(ymin*20);
+ r.xmax = (int)(xmax*20);
+ r.ymax = (int)(ymax*20);
+ swf_SetRect(i->tag,&r);
+ swf_SetShapeStyles(i->tag,i->shape);
+ swf_ShapeCountBits(i->shape,NULL,NULL);
+ swf_SetShapeBits(i->tag,i->shape);
+ swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,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);
+ swf_ShapeSetEnd(i->tag);
+
+ if(!mouseover)
+ {
+ i->tag = swf_InsertTag(i->tag,ST_DEFINEBUTTON);
+ swf_SetU16(i->tag,buttonid); //id
+ swf_ButtonSetFlags(i->tag, 0); //menu=no
+ swf_ButtonSetRecord(i->tag,0x01,myshapeid,i->depth,0,0);
+ swf_ButtonSetRecord(i->tag,0x02,myshapeid2,i->depth,0,0);
+ swf_ButtonSetRecord(i->tag,0x04,myshapeid2,i->depth,0,0);
+ swf_ButtonSetRecord(i->tag,0x08,myshapeid,i->depth,0,0);
+ swf_SetU8(i->tag,0);
+ swf_ActionSet(i->tag,actions1);
+ swf_SetU8(i->tag,0);
+ }
+ else
+ {
+ i->tag = swf_InsertTag(i->tag,ST_DEFINEBUTTON2);
+ swf_SetU16(i->tag,buttonid); //id
+ swf_ButtonSetFlags(i->tag, 0); //menu=no
+ swf_ButtonSetRecord(i->tag,0x01,myshapeid,i->depth,0,0);
+ swf_ButtonSetRecord(i->tag,0x02,myshapeid2,i->depth,0,0);
+ swf_ButtonSetRecord(i->tag,0x04,myshapeid2,i->depth,0,0);
+ swf_ButtonSetRecord(i->tag,0x08,myshapeid,i->depth,0,0);
+ swf_SetU8(i->tag,0); // end of button records
+ swf_ButtonSetCondition(i->tag, BC_IDLE_OVERUP);
+ swf_ActionSet(i->tag,actions1);
+ if(actions2) {
+ swf_ButtonSetCondition(i->tag, BC_OVERUP_IDLE);
+ swf_ActionSet(i->tag,actions2);
+ swf_SetU8(i->tag,0);
+ swf_ButtonPostProcess(i->tag, 2);
+ } else {
+ swf_SetU8(i->tag,0);
+ swf_ButtonPostProcess(i->tag, 1);
+ }
+ }
+
+ i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
+
+ if(posx!=0 || posy!=0) {
+ SPOINT p;
+ p.x = (int)(posx*20);
+ p.y = (int)(posy*20);
+ p = swf_TurnPoint(p, &i->page_matrix);
+ MATRIX m;
+ m = i->page_matrix;
+ m.tx = p.x;
+ m.ty = p.y;
+ swf_ObjectPlace(i->tag, buttonid, i->depth++,&m,0,0);
+ }
+ else {
+ swf_ObjectPlace(i->tag, buttonid, i->depth++,&i->page_matrix,0,0);
+ }
+}
+
+
+///////////
+/*
+for(t=0;t<picpos;t++)
+ {
+ if(pic_xids[t] == xid &&
+ pic_yids[t] == yid) {
+ width = pic_width[t];
+ height = pic_height[t];
+ found = t;break;
+ }
+ }
+ pic_ids[picpos] = swfoutput_drawimagelosslessN(&output, pic, pal, width, height, x1,y1,x2,y2,x3,y3,x4,y4, numpalette);
+ pic_xids[picpos] = xid;
+ pic_yids[picpos] = yid;
+ pic_width[picpos] = width;
+ pic_height[picpos] = height;
+ if(picpos<1024)
+ picpos++;
+ pic[width*y+x] = buf[0];
+ xid+=x*buf[0]+1;
+ yid+=y*buf[0]*3+1;
+
+ xid += pal[1].r*3 + pal[1].g*11 + pal[1].b*17;
+ yid += pal[1].r*7 + pal[1].g*5 + pal[1].b*23;
+
+ int xid = 0;
+ int yid = 0;
+ xid += x*r+x*b*3+x*g*7+x*a*11;
+ yid += y*r*3+y*b*17+y*g*19+y*a*11;
+ int t,found = -1;
+ for(t=0;t<picpos;t++)
+ {
+ if(pic_xids[t] == xid &&
+ pic_yids[t] == yid) {
+ found = t;break;
+ }
+ }
+ if(found<0) {
+*/
+///////////
+
+/* gfxtools.c */
+
+gfxbbox_t gfxbbox_expand_to_point(gfxbbox_t box, gfxcoord_t x, gfxcoord_t y)
+{
+ if(box.xmin==0 || box.ymin==0 || box.xmax==0 || box.ymax==0) {
+ box.xmin = x;
+ box.ymin = y;
+ box.xmax = x;
+ box.ymax = y;
+ if(x==0 && y==0) box.xmax = 0.0000001;
+ return box;
+ }
+ if(x < box.xmin)
+ box.xmin = x;
+ if(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;
+ while(line) {
+ if(line->type == 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("<warning> CXForm not SWF-compatible");
+
+ 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;
+
+ 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;
+
+ 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("<verbose> 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 */
+ int myshapeid = ++i->currentswfid;
+ i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE);
+ SHAPE*shape;
+ swf_ShapeNew(&shape);
+ int fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
+ SRECT r;
+ swf_SetU16(i->tag, myshapeid);
+ 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,/*ls*/0,fsid,0);
+ i->swflastx = i->swflasty = 0;
+ drawgfxline(obj, line);
+ swf_ShapeSetEnd(i->tag);
+ swf_ShapeFree(shape);
+
+ i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
+ CXFORM cxform2 = gfxcxform_to_cxform(cxform);
+ swf_ObjectPlace(i->tag,myshapeid,/*depth*/i->depth++,&i->page_matrix,&cxform2,NULL);
+}
+
+#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, int type)
+{
+ swfoutput_internal*i = (swfoutput_internal*)obj->internal;
+
+ 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");
+
+ i->device.fillbitmap(&i->device, &p1, &img, &m, 0);
+}
+
+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_drawimage(obj,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
+}
+
+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_drawimage(obj,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
+}
+
+int swf_setparameter(gfxdevice_t*dev, const char*key, const char*value)
+{
+ if(!strcmp(key, "next_bitmap_is_jpeg")) {
+ ((swfoutput_internal*)dev->internal)->jpeg = 1;
+ return 1;
+ }
+ return 0;
+}
+
+void swfoutput_setparameter(char*name, char*value)
+{
+ 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);
+ } else if(!strcmp(name, "filloverlap")) {
+ config_filloverlap = atoi(value);
+ } else if(!strcmp(name, "linksopennewwindow")) {
+ config_opennewwindow = atoi(value);
+ } else if(!strcmp(name, "opennewwindow")) {
+ config_opennewwindow = atoi(value);
+ } else if(!strcmp(name, "storeallcharacters")) {
+ config_storeallcharacters = atoi(value);
+ } else if(!strcmp(name, "enablezlib")) {
+ config_enablezlib = atoi(value);
+ } else if(!strcmp(name, "insertstop")) {
+ config_insertstoptag = atoi(value);
+ } else if(!strcmp(name, "protected")) {
+ config_protect = atoi(value);
+ } else if(!strcmp(name, "flashversion")) {
+ config_flashversion = atoi(value);
+ } else if(!strcmp(name, "minlinewidth")) {
+ config_minlinewidth = atof(value);
+ } else if(!strcmp(name, "jpegquality")) {
+ int val = atoi(value);
+ if(val<0) val=0;
+ if(val>100) val=100;
+ config_jpegquality = val;
+ } else if(!strcmp(name, "splinequality")) {
+ int v = atoi(value);
+ v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
+ if(v<1) v = 1;
+ config_splinemaxerror = v;
+ } else if(!strcmp(name, "fontquality")) {
+ int v = atoi(value);
+ v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
+ if(v<1) v = 1;
+ config_fontsplinemaxerror = v;
+ } else {
+ fprintf(stderr, "unknown parameter: %s (=%s)\n", name, value);
+ }