#include "../lib/rfxswf.h"
}
+int ignoredraworder=0;
+int drawonlyshapes=0;
+int jpegquality=85;
+static int flag_protected = 0;
+
typedef unsigned char u8;
typedef unsigned short int u16;
typedef unsigned long int u32;
static int fi;
-static int flag_protected;
+static char* filename = 0;
static SWF swf;
static TAG *tag;
-static int shapeid = -1;
-static int shapecount = 0;
+static int currentswfid = 0;
+static int depth = 1;
+static int startdepth = 1;
+
static SHAPE* shape;
+static int shapeid = -1;
+static int textid = -1;
+
+static int drawmode = -1;
+static char storefont = 0;
static int fillstyleid;
static int linestyleid;
static int swflastx=0;
static int swflasty=0;
static int lastwasfill = 0;
-static char* filename = 0;
+static char fill = 0;
static int sizex;
static int sizey;
-static char fill = 0;
-static int depth = 1;
-static int startdepth = 1;
TAG* cliptags[128];
int clipshapes[128];
u32 clipdepths[128];
int clippos = 0;
+int CHARMIDX = 0;
+int CHARMIDY = 0;
+
void startshape(struct swfoutput* obj);
+void starttext(struct swfoutput* obj);
+void endshape();
+void endtext();
// matrix multiplication. changes p0
void transform (plotxy*p0,struct swfmatrix*m)
}
// write a move-to command into the swf
-void moveto(plotxy p0)
+void moveto(TAG*tag, plotxy p0)
{
int rx = (int)(p0.x*20);
int ry = (int)(p0.y*20);
}
// write a line-to command into the swf
-void lineto(plotxy p0)
+void lineto(TAG*tag, plotxy p0)
{
int rx = ((int)(p0.x*20)-swflastx);
int ry = ((int)(p0.y*20)-swflasty);
}
// write a spline-to command into the swf
-void splineto(plotxy control,plotxy end)
+void splineto(TAG*tag, plotxy control,plotxy end)
{
int cx = ((int)(control.x*20)-swflastx);
int cy = ((int)(control.y*20)-swflasty);
/* write a line, given two points and the transformation
matrix. */
-void line(plotxy p0, plotxy p1, struct swfmatrix*m)
+void line(TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
{
transform(&p0,m);
transform(&p1,m);
- moveto(p0);
- lineto(p1);
+ moveto(tag, p0);
+ lineto(tag, p1);
}
/* write a cubic (!) spline. This involves calling the approximate()
function out of spline.cc to convert it to a quadratic spline. */
-void spline(plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
+void spline(TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
{
double d;
struct qspline q[16];
num = approximate(p0,p1,p2,p3,q);
for(t=0;t<num;t++) {
- moveto(q[t].start);
- splineto(q[t].control, q[t].end);
+ moveto(tag,q[t].start);
+ splineto(tag,q[t].control, q[t].end);
}
}
-/* Adds an outline to a font. Applies only the 2x2 component of the transformation matrix.
- */
-void addtofont(T1_OUTLINE*outline, struct swfmatrix*m, char*namehint)
-{
-}
-
/* draw a T1 outline. These are generated by pdf2swf and by t1lib.
(representing characters) */
-void drawpath(T1_OUTLINE*outline, struct swfmatrix*m, char*namehint)
+void drawpath(TAG*tag, T1_OUTLINE*outline, struct swfmatrix*m)
{
+ if(tag->id != ST_DEFINEFONT &&
+ tag->id != ST_DEFINESHAPE &&
+ tag->id != ST_DEFINESHAPE2 &&
+ tag->id != ST_DEFINESHAPE3)
+ {
+ logf("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
+ exit(1);
+ }
+ int log = 0;
+
double x=0,y=0;
double lastx=0,lasty=0;
+ double firstx=0,firsty=0;
+ int init=1;
while (outline)
{
- logf("<debug> Pathtype:%s",outline->type == T1_PATHTYPE_MOVE?"MOVE":
- (outline->type == T1_PATHTYPE_LINE?"LINE"
- :"BEZIER"));
- logf("<debug> relative coordinates: %08x,%08x", outline->dest.x, outline->dest.y);
x += (outline->dest.x/(float)0xffff);
y += (outline->dest.y/(float)0xffff);
- logf("<debug> coordinates: %f,%f", x, y);
if(outline->type == T1_PATHTYPE_MOVE)
{
+ if(((int)(lastx*20) != (int)(firstx*20) ||
+ (int)(lasty*20) != (int)(firsty*20)) &&
+ fill && !init)
+ {
+ plotxy p0;
+ plotxy p1;
+ p0.x=lastx;
+ p0.y=lasty;
+ p1.x=firstx;
+ p1.y=firsty;
+ if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
+ line(tag, p0, p1, m);
+ }
+ firstx=x;
+ firsty=y;
+ init = 0;
}
else if(outline->type == T1_PATHTYPE_LINE)
{
p0.y=lasty;
p1.x=x;
p1.y=y;
- line(p0,p1,m);
+ if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
+ line(tag, p0,p1,m);
}
else if(outline->type == T1_PATHTYPE_BEZIER)
{
p2.y=o2->B.y/(float)0xffff+lasty;
p3.x=lastx;
p3.y=lasty;
- spline(p0,p1,p2,p3,m);
+ if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
+ spline(tag,p0,p1,p2,p3,m);
}
else {
logf("<error> drawpath: unknown outline type:%d\n", outline->type);
lasty=y;
outline = outline->link;
}
+ if(((int)(lastx*20) != (int)(firstx*20) ||
+ (int)(lasty*20) != (int)(firsty*20)) &&
+ fill)
+ {
+ plotxy p0;
+ plotxy p1;
+ p0.x=lastx;
+ p0.y=lasty;
+ p1.x=firstx;
+ p1.y=firsty;
+ if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
+ line(tag, p0, p1, m);
+ }
}
- //logf("<debug> Font name is %s", T1_GetFontFileName(t1fontindex));
- //logf("<debug> char 0x%02x is named %s\n",character,charname);
- //logf("<debug> bbox: %d %d %d %d\n",bbox.llx,bbox.lly,bbox.urx,bbox.ury);
- //char*charname = T1_GetCharName(t1fontindex, character);
-/* process a character. */
-void drawchar(struct swfoutput*obj, SWFFont*font, char*character, swfmatrix*m)
+int colorcompare(RGBA*a,RGBA*b)
{
- T1_OUTLINE*outline = font->getOutline(character);
- char* charname = character;
- if(!outline) {
- logf("Didn't find %s in current charset", character);
- return;
+ if(a->r!=b->r ||
+ a->g!=b->g ||
+ a->b!=b->b ||
+ a->a!=b->a) {
+ return 0;
}
-
- swfmatrix m2=*m;
- m2.m11/=100;
- m2.m21/=100;
- m2.m12/=100;
- m2.m22/=100;
+ return 1;
+}
- if(shapeid<0)
- startshape(obj);
+static const int CHARDATAMAX = 1024;
+struct chardata {
+ int charid;
+ int fontid;
+ int x;
+ int y;
+ int size;
+ RGBA color;
+} chardata[CHARDATAMAX];
+int chardatapos = 0;
+
+void putcharacters(TAG*tag)
+{
+ int t;
+ SWFFONT font;
+ RGBA color;
+ color.r = chardata[0].color.r^255;
+ color.g = 0;
+ color.b = 0;
+ color.a = 0;
+ int lastfontid;
+ int lastx;
+ int lasty;
+ int lastsize;
+ int charids[128];
+ int charadvance[128];
+ int charstorepos;
+ int pass;
+ int glyphbits=1; //TODO: can this be zero?
+ int advancebits=1;
+
+ if(tag->id != ST_DEFINETEXT &&
+ tag->id != ST_DEFINETEXT2) {
+ logf("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
+ exit(1);
+ }
+ if(!chardatapos) {
+ logf("<warning> putcharacters called with zero characters");
+ }
- if(!lastwasfill)
- ShapeSetStyle(tag,shape,0x8000,fillstyleid,0);
- lastwasfill = 1;
+ for(pass = 0; pass < 2; pass++)
+ {
+ charstorepos = 0;
+ lastfontid = -1;
+ lastx = CHARMIDX;
+ lasty = CHARMIDY;
+ lastsize = -1;
+
+ if(pass==1)
+ {
+ advancebits++; // add sign bit
+ SetU8(tag, glyphbits);
+ SetU8(tag, advancebits);
+ }
+
+ for(t=0;t<=chardatapos;t++)
+ {
+ if(lastfontid != chardata[t].fontid ||
+ lastx!=chardata[t].x ||
+ lasty!=chardata[t].y ||
+ !colorcompare(&color, &chardata[t].color) ||
+ charstorepos==127 ||
+ lastsize != chardata[t].size ||
+ t == chardatapos)
+ {
+ if(charstorepos && pass==0)
+ {
+ int s;
+ for(s=0;s<charstorepos;s++)
+ {
+ while(charids[s]>=(1<<glyphbits))
+ glyphbits++;
+ while(charadvance[s]>=(1<<advancebits))
+ advancebits++;
+ }
+ }
+ if(charstorepos && pass==1)
+ {
+ tag->bitcount = 0;
+ SetBits(tag, 0, 1); // GLYPH Record
+ SetBits(tag, charstorepos, 7); // number of glyphs
+ int s;
+ for(s=0;s<charstorepos;s++)
+ {
+ SetBits(tag, charids[s], glyphbits);
+ SetBits(tag, charadvance[s], advancebits);
+ }
+ }
+ charstorepos = 0;
+
+ if(pass == 1 && t<chardatapos)
+ {
+ RGBA*newcolor=0;
+ SWFFONT*newfont=0;
+ int newx = 0;
+ int newy = 0;
+ if(lastx != chardata[t].x ||
+ lasty != chardata[t].y)
+ {
+ newx=chardata[t].x;
+ newy=chardata[t].y;
+ }
+ if(!colorcompare(&color, &chardata[t].color))
+ {
+ color = chardata[t].color;
+ newcolor = &color;
+ }
+ font.id = chardata[t].fontid;
+ if(lastfontid != chardata[t].fontid || lastsize != chardata[t].size)
+ newfont = &font;
+
+ tag->bitcount = 0;
+ TextSetInfoRecord(tag, newfont, chardata[t].size, newcolor, newx,newy);
+ }
+
+ lastfontid = chardata[t].fontid;
+ lastx = chardata[t].x;
+ lasty = chardata[t].y;
+ lastsize = chardata[t].size;
+ }
+
+ if(t==chardatapos)
+ break;
+
+ int advance;
+ int nextt = t==chardatapos-1?t:t+1;
+ int rel = chardata[nextt].x-chardata[t].x;
+ if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
+ advance = rel;
+ lastx=chardata[nextt].x;
+ }
+ else {
+ advance = 0;
+ lastx=chardata[t].x;
+ }
+ charids[charstorepos] = chardata[t].charid;
+ charadvance[charstorepos] = advance;
+ charstorepos ++;
+ }
+ }
+ chardatapos = 0;
+}
- drawpath(outline, &m2, charname);
+void putcharacter(struct swfoutput*obj, int fontid, int charid,
+ int x,int y, int size)
+{
+ if(chardatapos == CHARDATAMAX)
+ {
+ endtext();
+ starttext(obj);
+ }
+ chardata[chardatapos].fontid = fontid;
+ chardata[chardatapos].charid = charid;
+ chardata[chardatapos].x = x;
+ chardata[chardatapos].y = y;
+ chardata[chardatapos].color = obj->fillrgb;
+ chardata[chardatapos].size = size;
+ chardatapos++;
+}
+
+
+/* process a character. */
+void drawchar(struct swfoutput*obj, SWFFont*font, char*character, swfmatrix*m)
+{
+ int usefonts=1;
+ if(m->m12!=0 || m->m21!=0)
+ usefonts=0;
+ if(m->m11 != m->m22)
+ usefonts=0;
+
+ if(usefonts && ! drawonlyshapes)
+ {
+ int charid = font->getSWFCharID(character);
+ if(shapeid>=0)
+ endshape();
+ if(textid<0)
+ starttext(obj);
+ putcharacter(obj, font->swfid, charid,(int)(m->m13*20),(int)(m->m23*20),
+ (int)(m->m11*20/2+0.5)); //where does the /2 come from?
+ }
+ else
+ {
+ T1_OUTLINE*outline = font->getOutline(character);
+ char* charname = character;
+
+ if(!outline) {
+ logf("<warning> Didn't find %s in current charset (%s)",
+ character,font->getName());
+ return;
+ }
+
+ swfmatrix m2=*m;
+ m2.m11/=100;
+ m2.m21/=100;
+ m2.m12/=100;
+ m2.m22/=100;
+
+ if(textid>=0)
+ endtext();
+ if(shapeid<0)
+ startshape(obj);
+
+ if(!lastwasfill)
+ ShapeSetStyle(tag,shape,0x8000,fillstyleid,0);
+ lastwasfill = 1;
+
+ int lf = fill;
+ fill = 1;
+ drawpath(tag, outline, &m2);
+ fill = lf;
+ }
}
/* draw a curved polygon. */
-void swfoutput_drawpath(swfoutput*output, T1_OUTLINE*outline, struct swfmatrix*m)
+void swfoutput_drawpath(swfoutput*output, T1_OUTLINE*outline,
+ struct swfmatrix*m)
{
+ if(textid>=0)
+ endtext();
if(shapeid<0)
startshape(output);
lastwasfill = 1;
}
- drawpath(outline,m, 0);
+ drawpath(tag, outline,m);
}
+/* SWFFont: copy all t1 font outlines to a local
+ array. */
SWFFont::SWFFont(char*name, int id, char*filename)
{
if(!T1_GetFontName(id))
this->charnum = t;
if(!t)
return;
- logf("<notice> Font %s(%d): Storing %d outlines.\n", name, id, t);
+ logf("<verbose> Font %s(%d): Storing %d outlines.\n", name, id, t);
outline = (T1_OUTLINE**)malloc(t*sizeof(T1_OUTLINE*));
charname = (char**)malloc(t*sizeof(char*));
+ used = (char*)malloc(t*sizeof(char));
+ char2swfcharid = (U16*)malloc(t*2);
+ swfcharid2char = (U16*)malloc(t*2);
+ swfcharpos = 0;
+
+ memset(used,0,t*sizeof(char));
+
+ this->swfid = ++currentswfid;
+
t=0;
while(*a)
}
}
+/* free all tables, write out definefont tags */
+SWFFont::~SWFFont()
+{
+ int t,usednum=0;
+ int*ptr = (int*)malloc(swfcharpos*sizeof(int));
+
+ for(t=0;t<charnum;t++)
+ if(used[t]) usednum++;
+
+ if(usednum && !drawonlyshapes)
+ {
+ logf("<verbose> Font %s has %d used characters",fontid, usednum);
+ TAG*ftag = InsertTag(swf.FirstTag,ST_DEFINEFONT);
+ SetU16(ftag, this->swfid);
+ int initpos = GetDataSize(ftag);
+ swfmatrix m;
+ m.m11 = m.m22 = 1;
+ m.m21 = m.m12 = 0;
+ m.m13 = CHARMIDX;
+ m.m23 = CHARMIDY;
+ for(t=0;t<swfcharpos;t++)
+ {
+ ptr[t] = GetDataSize(ftag);
+ SetU16(ftag, 0x1234);
+ }
+ for(t=0;t<swfcharpos;t++)
+ {
+ *(U16*)&ftag->data[ptr[t]] = GetDataSize(ftag)-initpos;
+ swflastx=0;
+ swflasty=0;
+ SetU8(ftag,0x10); //0 fill bits, 0 linestyle bits
+ SHAPE s;
+ s.bits.fill = 1;
+ s.bits.line = 0;
+ ShapeSetStyle(ftag,&s,0,1,0);
+ int lastfill = fill;
+ fill = 1;
+ storefont = 1;
+ drawpath(ftag, outline[swfcharid2char[t]],&m);
+ storefont = 0;
+ fill = lastfill;
+ ShapeSetEnd(ftag);
+ }
+ }
+
+ free(ptr);
+ free(outline);
+ for(t=0;t<charnum;t++)
+ free(charname[t]);
+ free(charname);
+ free(used);
+ free(swfcharid2char);
+ free(char2swfcharid);
+}
+
T1_OUTLINE*SWFFont::getOutline(char*name)
{
int t;
for(t=0;t<this->charnum;t++) {
- if(!strcmp(this->charname[t],name))
+ if(!strcmp(this->charname[t],name)) {
+ if(!used[t])
+ {
+ swfcharid2char[swfcharpos] = t;
+ char2swfcharid[t] = swfcharpos;
+ swfcharpos++;
+ used[t] = 1;
+ }
return outline[t];
+ }
}
return 0;
}
+int SWFFont::getSWFCharID(char*name)
+{
+ int t;
+ for(t=0;t<this->charnum;t++) {
+ if(!strcmp(this->charname[t],name)) {
+ if(!used[t])
+ {
+ swfcharid2char[swfcharpos] = t;
+ char2swfcharid[t] = swfcharpos++;
+ used[t] = 1;
+ }
+ return char2swfcharid[t];
+ }
+ }
+ logf("<warning> Didn't find character '%s' in font '%s'", name, this->name);
+ return 0;
+}
+
char*SWFFont::getName()
{
return this->name;
void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
double m21,double m22)
{
+ if(obj->fontm11 == m11 &&
+ obj->fontm12 == m12 &&
+ obj->fontm21 == m21 &&
+ obj->fontm22 == m22)
+ return;
+// if(textid>=0)
+// endtext();
obj->fontm11 = m11;
obj->fontm12 = m12;
obj->fontm21 = m21;
memset(&swf,0x00,sizeof(SWF));
swf.FileVersion = 4;
-// swf.FrameRate = 0x1900;
swf.FrameRate = 0x0040; // 1 frame per 4 seconds
swf.MovieSize.xmax = 20*sizex;
swf.MovieSize.ymax = 20*sizey;
{
RGBA rgb;
SRECT r;
+
+ if(textid>=0)
+ endtext();
+
tag = InsertTag(tag,ST_DEFINESHAPE);
NewShape(&shape);
rgb.b = obj->fillrgb.b;
fillstyleid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
- shapeid = ++shapecount;
+ shapeid = ++currentswfid;
SetU16(tag,shapeid); // ID
r.xmin = 0;
lastwasfill = 0;
}
+void starttext(struct swfoutput*obj)
+{
+ SRECT r;
+ MATRIX m;
+ if(shapeid>=0)
+ endshape();
+ tag = InsertTag(tag,ST_DEFINETEXT);
+ textid = ++currentswfid;
+ SetU16(tag, textid);
+
+ r.xmin = 0;
+ r.ymin = 0;
+ r.xmax = 20*sizex;
+ r.ymax = 20*sizey;
+
+ SetRect(tag,&r);
+
+ m.sx = 65536;
+ m.sy = 65536;
+ m.r0 = 0;
+ m.r1 = 0;
+ m.tx = 0;
+ m.ty = 0;
+
+ SetMatrix(tag,&m);
+ swflastx=swflasty=0;
+}
+
void endshape()
{
if(shapeid<0)
shapeid = -1;
}
+void endtext()
+{
+ if(textid<0)
+ return;
+ putcharacters(tag);
+ SetU8(tag,0);
+ tag = InsertTag(tag,ST_PLACEOBJECT2);
+ ObjectPlace(tag,textid,/*depth*/depth++,NULL,NULL,NULL);
+ textid = -1;
+}
+
void endpage(struct swfoutput*obj)
{
if(shapeid>=0)
endshape();
+ if(textid>=0)
+ endtext();
while(clippos)
swfoutput_endclip(obj);
tag = InsertTag(tag,ST_SHOWFRAME);
void swfoutput_destroy(struct swfoutput* obj)
{
endpage(obj);
+ fontlist_t *tmp,*iterator = fontlist;
+ while(iterator) {
+ delete iterator->font;
+ iterator->font = 0;
+ tmp = iterator;
+ iterator = iterator->next;
+ delete tmp;
+ }
T1_CloseLib();
if(!filename)
logf("<error> WriteSWF() failed.\n");
if(filename)
close(fi);
- printf("SWF written\n");
+ logf("<notice> SWF written\n");
}
void swfoutput_setdrawmode(swfoutput* obj, int mode)
{
+ drawmode = mode;
if(mode == DRAWMODE_FILL)
fill = 1;
else if(mode == DRAWMODE_EOFILL)
obj->fillrgb.b == b &&
obj->fillrgb.a == a) return;
- if(shape>=0)
+ if(shapeid>=0)
endshape();
obj->fillrgb.r = r;
obj->fillrgb.g = g;
obj->strokergb.b == b &&
obj->strokergb.a == a) return;
- if(shape>=0)
+ if(shapeid>=0)
endshape();
obj->strokergb.r = r;
obj->strokergb.g = g;
if(obj->linewidth == (u16)(linewidth*20))
return;
- if(shape>=0)
+ if(shapeid>=0)
endshape();
obj->linewidth = (u16)(linewidth*20);
}
void swfoutput_startclip(swfoutput*obj, T1_OUTLINE*outline, struct swfmatrix*m)
{
- if(shape>=0)
+ if(textid>=0)
+ endtext();
+ if(shapeid>=0)
endshape();
if(clippos >= 127)
logf("<warning> Too many clip levels.");
clippos --;
}
-
+
startshape(obj);
-
+ int olddrawmode = drawmode;
swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
swfoutput_drawpath(obj, outline, m);
-
ShapeSetEnd(tag);
+ swfoutput_setdrawmode(obj, olddrawmode);
+
tag = InsertTag(tag,ST_PLACEOBJECT2);
cliptags[clippos] = tag;
clipshapes[clippos] = shapeid;
void swfoutput_endclip(swfoutput*obj)
{
- if(shape>=0)
+ if(textid>=0)
+ endtext();
+ if(shapeid>=0)
endshape();
if(!clippos) {
PlaceObject(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++);
}
-void swfoutput_drawimagefile(struct swfoutput*, char*filename, int sizex,int sizey,
+
+void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
double x1,double y1,
double x2,double y2,
double x3,double y3,
SRECT r;
int lsid=0;
int fsid;
- int bitid;
struct plotxy p1,p2,p3,p4;
int myshapeid;
double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
m.tx = (int)(x1*20);
m.ty = (int)(y1*20);
-
- if(shape>=0)
- endshape();
-
- bitid = ++shapecount;
- /* bitmap */
- tag = InsertTag(tag,ST_DEFINEBITSJPEG2);
- SetU16(tag, bitid);
- SetJPEGBits(tag, filename, 85);
-
/* shape */
- myshapeid = ++shapecount;
+ myshapeid = ++currentswfid;
tag = InsertTag(tag,ST_DEFINESHAPE);
NewShape(&shape);
//lsid = ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
SetShapeBits(tag,shape);
ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
swflastx = swflasty = 0;
- moveto(p1);
- lineto(p2);
- lineto(p3);
- lineto(p4);
- lineto(p1);
+ moveto(tag, p1);
+ lineto(tag, p2);
+ lineto(tag, p3);
+ lineto(tag, p4);
+ lineto(tag, p1);
/*
ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
ShapeSetLine (tag, shape, (int)(x1*20);
ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL);
}
+int swfoutput_drawimagejpeg(struct swfoutput*obj, char*filename, int sizex,int sizey,
+ double x1,double y1,
+ double x2,double y2,
+ double x3,double y3,
+ double x4,double y4)
+{
+ if(shapeid>=0)
+ endshape();
+ if(textid>=0)
+ endtext();
+
+ int bitid = ++currentswfid;
+ tag = InsertTag(tag,ST_DEFINEBITSJPEG2);
+ SetU16(tag, bitid);
+ SetJPEGBits(tag, filename, jpegquality);
+
+ drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
+ return bitid;
+}
+
+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)
+{
+ if(shapeid>=0)
+ endshape();
+ if(textid>=0)
+ endtext();
+
+ int bitid = ++currentswfid;
+ tag = InsertTag(tag,ST_DEFINEBITSLOSSLESS);
+ SetU16(tag, bitid);
+ SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT);
+
+ drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
+ return bitid;
+}
+
+int swfoutput_drawimagelossless256(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)
+{
+ if(shapeid>=0)
+ endshape();
+ if(textid>=0)
+ endtext();
+
+ int bitid = ++currentswfid;
+ tag = InsertTag(tag,ST_DEFINEBITSLOSSLESS2);
+ SetU16(tag, bitid);
+ SetLosslessBitsIndexed(tag,sizex,sizey,mem, pal, 256);
+
+ 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)
+{
+ if(shapeid>=0)
+ endshape();
+ if(textid>=0)
+ endtext();
+
+ drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
+}
+