+int swf_SetLosslessBitsIndexed(TAG * t, U16 width, U16 height, U8 * bitmap, RGBA * palette, U16 ncolors)
+{
+ RGBA *pal = palette;
+ int bps = BYTES_PER_SCANLINE(width);
+ int res = 0;
+
+ if (!pal) // create default palette for grayscale images
+ {
+ int i;
+ pal = rfx_alloc(256 * sizeof(RGBA));
+ for (i = 0; i < 256; i++) {
+ pal[i].r = pal[i].g = pal[i].b = i;
+ pal[i].a = 0xff;
+ }
+ ncolors = 256;
+ }
+
+ if ((ncolors < 2) || (ncolors > 256) || (!t)) {
+ fprintf(stderr, "rfxswf: unsupported number of colors: %d\n",
+ ncolors);
+ return -1; // parameter error
+ }
+
+ swf_SetU8(t, BMF_8BIT);
+ swf_SetU16(t, width);
+ swf_SetU16(t, height);
+ swf_SetU8(t, ncolors - 1); // number of pal entries
+
+ {
+ z_stream zs;
+
+ memset(&zs, 0x00, sizeof(z_stream));
+ zs.zalloc = Z_NULL;
+ zs.zfree = Z_NULL;
+
+ if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) == Z_OK) {
+ U8 *zpal; // compress palette
+ if ((zpal = rfx_alloc(ncolors * 4))) {
+ U8 *pp = zpal;
+ int i;
+
+ /* be careful with ST_DEFINEBITSLOSSLESS2, because
+ the Flash player produces great bugs if you use too many
+ alpha colors in your palette. The only sensible result that
+ can be archeived is setting one color to r=0,b=0,g=0,a=0 to
+ make transparent parts in sprites. That's the cause why alpha
+ handling is implemented in lossless routines of rfxswf.
+
+ Indeed: I haven't understood yet how flash player handles
+ alpha values different from 0 and 0xff in lossless bitmaps...
+ */
+
+ if (swf_GetTagID(t) == ST_DEFINEBITSLOSSLESS2) // have alpha channel?
+ {
+ for (i = 0; i < ncolors; i++) {
+ pp[0] = pal[i].r;
+ pp[1] = pal[i].g;
+ pp[2] = pal[i].b;
+ pp[3] = pal[i].a;
+ pp += 4;
+ }
+ zs.avail_in = 4 * ncolors;
+ } else {
+ for (i = 0; i < ncolors; i++) // pack RGBA structures to RGB
+ {
+ pp[0] = pal[i].r;
+ pp[1] = pal[i].g;
+ pp[2] = pal[i].b;
+ pp += 3;
+ }
+ zs.avail_in = 3 * ncolors;
+ }
+
+ zs.next_in = zpal;
+
+ if (RFXSWF_deflate_wraper(t, &zs, FALSE) < 0)
+ res = -3;
+
+ // compress bitmap
+ zs.next_in = bitmap;
+ zs.avail_in = (bps * height * sizeof(U8));
+
+ if (RFXSWF_deflate_wraper(t, &zs, TRUE) < 0)
+ res = -3;
+
+ deflateEnd(&zs);
+
+ rfx_free(zpal);
+ } else
+ res = -2; // memory error
+ } else
+ res = -3; // zlib error
+ }
+
+ if (!palette)
+ rfx_free(pal);
+
+ return res;
+}
+
+int swf_SetLosslessBitsGrayscale(TAG * t, U16 width, U16 height, U8 * bitmap)
+{
+ 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;
+ swf_PreMultiplyAlpha(data, width, height);
+ }
+ num = swf_ImageGetNumberOfPaletteEntries(data, width, height, 0);
+ if(num>1 && num<=256) {
+ RGBA*palette = (RGBA*)malloc(sizeof(RGBA)*num);
+ 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];
+ for(x=0;x<width;x++) {
+ RGBA col = src[x];
+ for(r=0;r<num;r++) {
+ if(*(U32*)&col == *(U32*)&palette[r]) {
+ dest[x] = r;
+ break;
+ }
+ }
+ if(r==num) {
+ fprintf(stderr, "Internal error: Couldn't find color %02x%02x%02x%02x in palette (%d entries)\n",
+ col.r, col.g, col.b, col.a, num);
+ dest[x] = 0;
+ }
+ }
+ }
+ swf_SetLosslessBitsIndexed(tag, width, height, data2, palette, num);
+ free(data2);
+ free(palette);
+ } else {
+ swf_SetLosslessBits(tag, width, height, data, BMF_32BIT);
+ }