}
return hasalpha;
}
-
-int swf_ImageGetNumberOfPaletteEntries(RGBA*img, int width, int height, RGBA*palette)
+
+int swf_ImageGetNumberOfPaletteEntries2(RGBA*_img, int width, int height)
+{
+ int len = width*height;
+ int t;
+ U32* img = (U32*)_img;
+ U32 color1 = img[0];
+ U32 color2 = 0;
+ for(t=1;t<len;t++) {
+ if(img[t] != color1) {
+ color2 = img[t];
+ break;
+ }
+ }
+ if(t==len)
+ return 1;
+
+ for(;t<len;t++) {
+ if(img[t] != color1 && img[t] != color2) {
+ return width*height;
+ }
+ }
+ return 2;
+}
+
+/*int swf_ImageGetNumberOfPaletteEntries(RGBA*img, int width, int height, RGBA*palette)
{
int len = width*height;
int t;
int palsize = 0;
- RGBA pal[256];
+ RGBA pal[512];
+ U32*pal32=(U32*)pal;
int palette_overflow = 0;
- for(t=0;t<len;t++) {
+ U32 lastcol32 = 0;
+
+ if(sizeof(RGBA)!=sizeof(U32))
+ fprintf(stderr, "rfxswf: sizeof(RGBA)!=sizeof(U32))");
+
+ lastcol32 = pal32[palsize++] = *(U32*)&img[0];
+
+ for(t=1;t<len;t++) {
RGBA col = img[t];
U32 col32 = *(U32*)&img[t];
- int i=0;
+ int i;
+ if(col32==lastcol32)
+ continue;
for(i=0;i<palsize;i++) {
- if(col32 == *(U32*)&pal[i])
+ if(col32 == pal32[i])
break;
}
if(i==palsize) {
- if(palsize==256) {
+ if(palsize==512) {
palette_overflow = 1;
break;
}
- pal[palsize++] = col;
+ pal32[palsize++] = col32;
}
+ lastcol32 = col32;
}
if(palette_overflow)
return width*height;
if(palette)
memcpy(palette, pal, palsize*sizeof(RGBA));
return palsize;
+}*/
+
+int swf_ImageGetNumberOfPaletteEntries(RGBA*img, int width, int height, RGBA*palette)
+{
+ int len = width*height;
+ int t;
+ int palsize = 0;
+ U32* pal;
+ int size[256];
+ int palette_overflow = 0;
+ U32 lastcol32 = 0;
+
+ pal = malloc(65536*sizeof(U32));
+
+ memset(size, 0, sizeof(size));
+
+ if(sizeof(RGBA)!=sizeof(U32))
+ fprintf(stderr, "rfxswf: sizeof(RGBA)!=sizeof(U32))");
+
+ lastcol32 = (*(U32*)&img[0])^0xffffffff; // don't match
+
+ for(t=0;t<len;t++) {
+ RGBA col = img[t];
+ U32 col32 = *(U32*)&img[t];
+ int i;
+ int csize;
+ U32 hash;
+ U32* cpal;
+ if(col32 == lastcol32)
+ continue;
+ hash = (col32 >> 17) ^ col32;
+ hash ^= ((hash>>8) + 1) ^ hash;
+ hash &= 255;
+
+ csize = size[hash];
+ cpal = &pal[hash*256];
+ for(i=0;i<csize;i++) {
+ if(col32 == cpal[i])
+ break;
+ }
+ if(i==csize) {
+ if(palsize==256) {
+ palette_overflow = 1;
+ break;
+ }
+ cpal[size[hash]++] = col32;
+ palsize++;
+ }
+ lastcol32 = col32;
+ }
+ if(palette_overflow) {
+ free(pal);
+ return width*height;
+ }
+ if(palette) {
+ int i = 0;
+ for(t=0;t<256;t++) {
+ int s;
+ int csize = size[t];
+ U32* cpal = &pal[t*256];
+ for(s=0;s<csize;s++)
+ palette[i++] = *(RGBA*)(&cpal[s]);
+ }
+ }
+ free(pal);
+ return palsize;
}
+
+
#ifdef HAVE_JPEGLIB
typedef struct _JPEGDESTMGR {
static void tag_init_source(struct jpeg_decompress_struct *cinfo)
{
TAG *tag = (TAG *) cinfo->client_data;
- swf_SetTagPos(tag, 2);
+ if (tag->id == ST_DEFINEBITSJPEG3) {
+ swf_SetTagPos(tag, 6);
+ } else {
+ swf_SetTagPos(tag, 2);
+ }
cinfo->src->bytes_in_buffer = 0;
}
static boolean tag_fill_input_buffer(struct jpeg_decompress_struct *cinfo)
struct jpeg_source_mgr mgr;
RGBA *dest;
int y;
+ int offset = 0;
+ int oldtaglen = 0;
*width = 0;
*height = 0;
if (tag->id == ST_DEFINEBITSJPEG) {
- fprintf(stderr,
- "rfxswf: extracting from definebitsjpeg not yet supported");
+ fprintf(stderr, "rfxswf: extracting from definebitsjpeg not yet supported\n");
return 0;
}
if (tag->id == ST_DEFINEBITSJPEG3) {
- fprintf(stderr,
- "rfxswf: extracting from definebitsjpeg3 not yet supported");
+#ifdef HAVE_ZLIB
+ offset = swf_GetU32(tag);
+ oldtaglen = tag->len;
+ tag->len = offset+6;
+#else
+ fprintf(stderr, "rfxswf: extracting from definebitsjpeg3 not possible: no zlib\n");
return 0;
+#endif
}
cinfo.err = jpeg_std_error(&jerr);
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
+
+#ifdef HAVE_ZLIB
+ if(offset) {
+ U32 datalen = cinfo.output_width*cinfo.output_height;
+ U8* alphadata = (U8*)rfx_alloc(datalen);
+ int error;
+ tag->len = oldtaglen;
+ swf_SetTagPos(tag, 6+offset);
+ error = uncompress(alphadata, &datalen, &tag->data[tag->pos], tag->len - tag->pos);
+ if (error != Z_OK) {
+ fprintf(stderr, "rfxswf: Zlib error %d while extracting definejpeg3\n", error);
+ return 0;
+ }
+ for(y=0;y<cinfo.output_height;y++) {
+ RGBA*line = &dest[y*cinfo.output_width];
+ U8*aline = &alphadata[y*cinfo.output_width];
+ int x;
+ for(x=0;x<cinfo.output_width;x++) {
+ line[x].a = aline[x];
+ }
+ }
+ free(alphadata);
+ }
+#endif
return dest;
}
return swf_SetLosslessBitsIndexed(t, width, height, bitmap, NULL, 256);
}
+void swf_PreMultiplyAlpha(RGBA*data, int width, int height)
+{
+ int num = width*height;
+ int t;
+ for(t=0;t<num;t++) {
+ data[t].r = ((int)data[t].r*data[t].a)/255;
+ data[t].g = ((int)data[t].g*data[t].a)/255;
+ data[t].b = ((int)data[t].b*data[t].a)/255;
+ }
+}
+
void swf_SetLosslessImage(TAG*tag, RGBA*data, int width, int height)
{
int hasalpha = swf_ImageHasAlpha(data, width, height);
+ int num;
if(!hasalpha) {
tag->id = ST_DEFINEBITSLOSSLESS;
} else {
tag->id = ST_DEFINEBITSLOSSLESS2;
- /* TODO: premultiply alpha? */
+ swf_PreMultiplyAlpha(data, width, height);
}
- int num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
+ num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
if(num>1 && num<=256) {
RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
- swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
int width2 = BYTES_PER_SCANLINE(width);
U8*data2 = (U8*)malloc(width2*height);
int len = width*height;
int x,y;
int r;
+ swf_ImageGetNumberOfPaletteEntries(data, width, height, palette);
for(y=0;y<height;y++) {
RGBA*src = &data[width*y];
U8*dest = &data2[width2*y];
palette[t].b = data[pos++];
if (alpha) {
palette[t].a = data[pos++];
+ } else {
+ palette[t].a = 255;
}
}
}
}
} else {
for (x = 0; x < width; x++) {
- /* TODO: un-premultiply alpha? */
- dest[pos2].r = data[pos + 1];
- dest[pos2].g = data[pos + 2];
- dest[pos2].b = data[pos + 3];
+ /* TODO: is un-premultiplying alpha the right thing to do?
+ dest[pos2].r = data[pos + 1];
+ dest[pos2].g = data[pos + 2];
+ dest[pos2].b = data[pos + 3];*/
+ int alpha = data[pos+0];
+ if(alpha) {
+ dest[pos2].r = ((int)data[pos + 1]*255)/alpha;
+ dest[pos2].g = ((int)data[pos + 2]*255)/alpha;
+ dest[pos2].b = ((int)data[pos + 3]*255)/alpha;
+ } else {
+ dest[pos2].r = data[pos + 1];
+ dest[pos2].g = data[pos + 2];
+ dest[pos2].b = data[pos + 3];
+ }
dest[pos2].a = data[pos + 0]; //alpha
pos2++;
pos += 4;
rfx_free(data);
return 0;
}
+
+TAG* swf_AddImage(TAG*tag, int bitid, RGBA*mem, int width, int height, int quality)
+{
+ TAG *tag1 = 0, *tag2 = 0;
+ int has_alpha = swf_ImageHasAlpha(mem,width,height);
+
+ /* try lossless image */
+ tag1 = swf_InsertTag(0, /*ST_DEFINEBITSLOSSLESS1/2*/0);
+ swf_SetU16(tag1, bitid);
+ swf_SetLosslessImage(tag1, mem, width, height);
+
+ /* try jpeg image */
+ if(has_alpha) {
+ tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG3);
+ swf_SetU16(tag2, bitid);
+ swf_SetJPEGBits3(tag2, width, height, mem, quality);
+ } else {
+ tag2 = swf_InsertTag(0, ST_DEFINEBITSJPEG2);
+ swf_SetU16(tag2, bitid);
+ swf_SetJPEGBits2(tag2, width, height, mem, quality);
+ }
+
+ if(tag1 && tag1->len < tag2->len) {
+ /* use the zlib version- it's smaller */
+ tag1->prev = tag;
+ if(tag) tag->next = tag1;
+ tag = tag1;
+ swf_DeleteTag(tag2);
+ } else {
+ /* use the jpeg version- it's smaller */
+ tag2->prev = tag;
+ if(tag) tag->next = tag2;
+ tag = tag2;
+ swf_DeleteTag(tag1);
+ }
+ return tag;
+}
+
#endif
RGBA *swf_ExtractImage(TAG * tag, int *dwidth, int *dheight)
{
RGBA *img;
+
+ swf_SetTagPos(tag, 2); // id is 2 bytes
+
if (tag->id == ST_DEFINEBITSJPEG ||
tag->id == ST_DEFINEBITSJPEG2 || tag->id == ST_DEFINEBITSJPEG3) {
#ifdef HAVE_JPEGLIB
tag = swf->firstTag;
while (tag) {
if (tag->id == ST_DEFINEBITSJPEG) {
- void *data = rfx_alloc(tag->len);
+ int len = tag->len;
+ void *data = rfx_alloc(len);
swf_GetBlock(tag, data, tag->len);
swf_ResetTag(tag, ST_DEFINEBITSJPEG2);
+ swf_SetBlock(tag, &((U8*)data)[0], 2); //id
swf_SetBlock(tag, tables_tag->data, tables_tag->len);
- swf_SetBlock(tag, data, tag->len);
+ swf_SetBlock(tag, &((U8*)data)[2], len-2);
free(data);
}
tag = tag->next;
if(newwidth<=width) {
for(x=0;x<newwidth;x++) {
- lblockx[x] = p_x;
double ex = px + fx;
int fromx = (int)px;
int tox = (int)ex;
int xweight = (int)(rem*256/fx);
int xx;
int w = 0;
+ lblockx[x] = p_x;
if(tox>=width) tox = width-1;
for(xx=fromx;xx<=tox;xx++) {
if(xx==fromx && xx==tox) p_x->weight = 256;
}
} else {
for(x=0;x<newwidth;x++) {
- lblockx[x] = p_x;
int ix1 = (int)px;
int ix2 = ((int)px)+1;
- if(ix2>=width) ix2=width-1;
double r = px-ix1;
+ if(ix2>=width) ix2=width-1;
+ lblockx[x] = p_x;
if(bicubic)
r = -2*r*r*r+3*r*r;
p_x[0].weight = (int)(256*(1-r));
lblockx[newwidth] = p_x;
return lblockx;
}
-
RGBA* swf_ImageScale(RGBA*data, int width, int height, int newwidth, int newheight)
{
- if(newwidth<2 || newheight<2)
- return 0;
int x,y;
- RGBA* newdata= (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
+ RGBA* newdata;
scale_lookup_t *p, **lblockx,**lblocky;
- rgba_int_t*tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
+ rgba_int_t*tmpline;
+
+ if(newwidth<1 || newheight<1)
+ return 0;
+
+ /* this is bad because this scaler doesn't yet handle monochrome
+ images with 2 colors in a way that the final image hasn't more
+ than 256 colors */
+ if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2)
+ fprintf(stderr, "Warning: scaling monochrome image\n");
+
+ tmpline = (rgba_int_t*)malloc(width*sizeof(rgba_int_t));
+ newdata = (RGBA*)malloc(newwidth*newheight*sizeof(RGBA));
lblockx = make_scale_lookup(width, newwidth);
lblocky = make_scale_lookup(height, newheight);
/* create lookup table for y */
rgba_int_t*l = tmpline;
- scale_lookup_t*p_y;
+ scale_lookup_t*p_y,*p_x;
memset(tmpline, 0, width*sizeof(rgba_int_t));
for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
RGBA*line = &data[p_y->pos];
}
/* process x direction */
- scale_lookup_t*p_x = lblockx[0];
+ p_x = lblockx[0];
for(x=0;x<newwidth;x++) {
unsigned int r=0,g=0,b=0,a=0;
scale_lookup_t*p_x_to = lblockx[x+1];