#include "../lib/rfxswf.h"
#include "../lib/args.h"
#include "reloc.h"
+#include "zlib.h"
char * filename = 0;
char * destfilename = "output.swf";
char* extractids = 0;
char* extractframes = 0;
char* extractjpegids = 0;
+char* extractpngids = 0;
char* extractname = 0;
{"v","verbose"},
{"i","id"},
{"j","jpegs"},
+ {"p","pngs"},
{"n","name"},
{"f","frame"},
{"V","version"},
extractjpegids = val;
return 1;
}
+ else if(!strcmp(name, "p")) {
+ if(extractpngids) {
+ fprintf(stderr, "Only one --pngs argument is allowed. (Try to use a range, e.g. -p 1,2,3)\n");
+ exit(1);
+ }
+ extractpngids = val;
+ return 1;
+ }
else if(!strcmp(name, "f")) {
extractframes = val;
return 1;
printf("\t-o , --output filename\t\t set output filename\n");
printf("\t-n , --name name\t\t instance name of the object to extract\n");
printf("\t-i , --id IDs\t\t\t ID of the object to extract\n");
- printf("\t-j , --jpeg IDs\t\t\t IDs of the jpeg pictures to extract\n");
+ printf("\t-j , --jpeg IDs\t\t\t IDs of the JPEG pictures to extract\n");
+ printf("\t-p , --pngs IDs\t\t\t IDs of the PNG pictures to extract\n");
printf("\t-f , --frame frames\t\t frame numbers to extract\n");
printf("\t-w , --hollow\t\t\t hollow mode: don't remove empty frames (use with -f)\n");
printf("\t-V , --version\t\t\t Print program version and exit\n");
char first;
int t;
int frame = 0;
- char*names[] = {"Shapes","MovieClips","JPEGs","Sounds","Frames"};
+ char*names[] = {"Shapes","MovieClips","JPEGs","PNGs","Sounds","Frames"};
printf("Objects in file %s:\n",filename);
- for(t=0;t<5;t++) {
+ for(t=0;t<6;t++) {
tag = swf->firstTag;
first = 1;
while(tag) {
sprintf(text,"%d", swf_GetDefineID(tag));
}
- if(t == 3 && (tag->id == ST_DEFINESOUND)) {
+ if(t == 3 && (tag->id == ST_DEFINEBITSLOSSLESS ||
+ tag->id == ST_DEFINEBITSLOSSLESS2)) {
+ show = 1;
+ sprintf(text,"%d", swf_GetDefineID(tag));
+ }
+
+
+ if(t == 4 && (tag->id == ST_DEFINESOUND)) {
show = 1;
sprintf(text,"%d", swf_GetDefineID(tag));
}
- if(t == 4 && (tag->id == ST_SHOWFRAME)) {
+ if(t == 5 && (tag->id == ST_SHOWFRAME)) {
show = 1;
sprintf(text,"%d", frame);
frame ++;
}
}
+static U32 mycrc32;
+
+static U32*crc32_table = 0;
+static void make_crc32_table(void)
+{
+ int t;
+ if(crc32_table)
+ return;
+ crc32_table = (U32*)malloc(1024);
+
+ for (t = 0; t < 256; t++) {
+ U32 c = t;
+ int s;
+ for (s = 0; s < 8; s++) {
+ c = (0xedb88320L*(c&1)) ^ (c >> 1);
+ }
+ crc32_table[t] = c;
+ }
+}
+static void png_write_byte(FILE*fi, U8 byte)
+{
+ fwrite(&byte,1,1,fi);
+ mycrc32 = crc32_table[(mycrc32 ^ byte) & 0xff] ^ (mycrc32 >> 8);
+}
+static void png_start_chunk(FILE*fi, char*type, int len)
+{
+ U8 mytype[4]={0,0,0,0};
+ U32 mylen = REVERSESWAP32(len);
+ memcpy(mytype,type,strlen(type));
+ fwrite(&mylen, 4, 1, fi);
+ mycrc32=0xffffffff;
+ png_write_byte(fi,mytype[0]);
+ png_write_byte(fi,mytype[1]);
+ png_write_byte(fi,mytype[2]);
+ png_write_byte(fi,mytype[3]);
+}
+static void png_write_bytes(FILE*fi, U8*bytes, int len)
+{
+ int t;
+ for(t=0;t<len;t++)
+ png_write_byte(fi,bytes[t]);
+}
+static void png_write_dword(FILE*fi, U32 dword)
+{
+ png_write_byte(fi,dword>>24);
+ png_write_byte(fi,dword>>16);
+ png_write_byte(fi,dword>>8);
+ png_write_byte(fi,dword);
+}
+static void png_end_chunk(FILE*fi)
+{
+ U32 tmp = REVERSESWAP32((mycrc32^0xffffffff));
+ fwrite(&tmp,4,1,fi);
+}
+
+
+/* extract a lossless image (png) out of a tag
+ This routine was originally meant to be a one-pager. I just
+ didn't know png is _that_ much fun. :) -mk
+ */
+void handlelossless(TAG*tag)
+{
+ char name[80];
+ FILE*fi;
+ int width, height;
+ int crc;
+ int id;
+ int t;
+ U8 bpp = 1;
+ U8 format;
+ U8 tmp;
+ U8* data=0;
+ U8* data2=0;
+ U8* data3=0;
+ U32 datalen;
+ U32 datalen2;
+ U32 datalen3;
+ U8 head[] = {137,80,78,71,13,10,26,10};
+ int cols;
+ char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
+ RGBA* palette;
+ int pos;
+ int error;
+ U32 tmp32;
+
+ make_crc32_table();
+
+ if(tag->id != ST_DEFINEBITSLOSSLESS &&
+ tag->id != ST_DEFINEBITSLOSSLESS2)
+ return;
+
+ id =swf_GetU16(tag);
+ format = swf_GetU8(tag);
+ if(format == 3) bpp = 8;
+ if(format == 4) bpp = 16;
+ if(format == 5) bpp = 32;
+ if(format!=3 && format!=5) {
+ if(format==4)
+ fprintf(stderr, "Can't handle 16-bit palette images yet (image %d)\n",id);
+ else
+ fprintf(stderr, "Unknown image type %d in image %d\n", format, id);
+ return;
+ }
+ width = swf_GetU16(tag);
+ height = swf_GetU16(tag);
+ if(format == 3) cols = swf_GetU8(tag) + 1;
+// this is what format means according to the flash specification. (which is
+// clearly wrong)
+// if(format == 4) cols = swf_GetU16(tag) + 1;
+// if(format == 5) cols = swf_GetU32(tag) + 1;
+ else cols = 0;
+
+ logf("<verbose> Width %d", width);
+ logf("<verbose> Height %d", height);
+ logf("<verbose> Format %d", format);
+ logf("<verbose> Cols %d", cols);
+ logf("<verbose> Bpp %d", bpp);
+
+ datalen = (width*height*bpp/8+cols*8);
+ do {
+ if(data)
+ free(data);
+ datalen+=4096;
+ data = malloc(datalen);
+ error = uncompress (data, &datalen, &tag->data[tag->pos], tag->len-tag->pos);
+ } while(error == Z_BUF_ERROR);
+ if(error != Z_OK) {
+ fprintf(stderr, "Zlib error %d (image %d)\n", error, id);
+ return;
+ }
+ logf("<verbose> Uncompressed image is %d bytes (%d colormap)", datalen, (3+alpha)*cols);
+ pos = 0;
+ datalen2 = datalen;
+ data2 = malloc(datalen2);
+ palette = (RGBA*)malloc(cols*sizeof(RGBA));
+
+ for(t=0;t<cols;t++) {
+ palette[t].r = data[pos++];
+ palette[t].g = data[pos++];
+ palette[t].b = data[pos++];
+ if(alpha) {
+ palette[t].a = data[pos++];
+ }
+ }
+
+ sprintf(name, "pic%d.png", id);
+ fi = save_fopen(name, "wb");
+ fwrite(head,sizeof(head),1,fi);
+
+ png_start_chunk(fi, "IHDR", 13);
+ png_write_dword(fi,width);
+ png_write_dword(fi,height);
+ png_write_byte(fi,8);
+ if(format == 3)
+ png_write_byte(fi,3); //indexed
+ else if(format == 5)
+ png_write_byte(fi,2); //rgb
+ else return;
+
+ png_write_byte(fi,0); //compression mode
+ png_write_byte(fi,0); //filter mode
+ png_write_byte(fi,0); //interlace mode
+ png_end_chunk(fi);
+
+ if(format == 3) {
+ png_start_chunk(fi, "PLTE", 768);
+ for(t=0;t<256;t++) {
+ png_write_byte(fi,palette[t].r);
+ png_write_byte(fi,palette[t].g);
+ png_write_byte(fi,palette[t].b);
+ }
+ png_end_chunk(fi);
+ }
+ {
+ int pos2 = 0;
+ int x,y;
+ int srcwidth = width * (bpp/8);
+ datalen3 = width*height*4;
+ data3 = (U8*)malloc(datalen3);
+ for(y=0;y<height;y++)
+ {
+ data3[pos2++]=0; //filter type
+ if(bpp==32) {
+ // 32 bit to 24 bit "conversion"
+ for(x=0;x<width;x++) {
+ data3[pos2++]=data[pos+1];
+ data3[pos2++]=data[pos+2];
+ data3[pos2++]=data[pos+3];
+ pos+=4; //ignore padding byte
+ }
+ }
+ else {
+ for(x=0;x<srcwidth;x++)
+ data3[pos2++]=data[pos++];
+ }
+
+ pos+=((srcwidth+3)&~3)-srcwidth; //align
+ }
+ datalen3=pos2;
+ }
+
+ if(compress (data2, &datalen2, data3, datalen3) != Z_OK) {
+ fprintf(stderr, "zlib error in pic %d\n", id);
+ return;
+ }
+ logf("<verbose> Compressed data is %d bytes", datalen2);
+ png_start_chunk(fi, "IDAT", datalen2);
+ png_write_bytes(fi,data2,datalen2);
+ png_end_chunk(fi);
+ png_start_chunk(fi, "IEND", 0);
+ png_end_chunk(fi);
+
+ free(data);
+ free(data2);
+ free(data3);
+}
+
int main (int argc,char ** argv)
{
TAG*tag;
char listavailable = 0;
processargs(argc, argv);
- if(!extractframes && !extractids && ! extractname && !extractjpegids)
+ if(!extractframes && !extractids && ! extractname && !extractjpegids && !extractpngids)
listavailable = 1;
if(!filename)
if(extractjpegids && is_in_range(id, extractjpegids)) {
handlejpeg(tag);
}
+ if(extractpngids && is_in_range(id, extractpngids)) {
+ handlelossless(tag);
+ }
}
else if (tag->id == ST_SETBACKGROUNDCOLOR) {
mainr = tag->data[0];