+static boolean file_empty_output_buffer(j_compress_ptr cinfo)
+{
+ JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
+ struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
+
+ if(fmgr->fi)
+ fwrite(fmgr->buffer, OUTBUFFER_SIZE, 1, fmgr->fi);
+
+ dmgr->next_output_byte = fmgr->buffer;
+ dmgr->free_in_buffer = OUTBUFFER_SIZE;
+ return 1;
+}
+
+static void file_term_destination(j_compress_ptr cinfo)
+{
+ JPEGFILEMGR*fmgr = (JPEGFILEMGR*)(cinfo->dest);
+ struct jpeg_destination_mgr*dmgr = &fmgr->mgr;
+
+ if(fmgr->fi)
+ fwrite(fmgr->buffer, OUTBUFFER_SIZE-dmgr->free_in_buffer, 1, fmgr->fi);
+
+ rfx_free(fmgr->buffer);
+ fmgr->buffer = 0;
+ dmgr->free_in_buffer = 0;
+ dmgr->next_output_byte = 0;
+}
+
+void swf_SaveJPEG(char*filename, RGBA*pixels, int width, int height, int quality)
+{
+ JPEGFILEMGR fmgr;
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ unsigned char*data2 = 0;
+ int y;
+
+ FILE*fi = fopen(filename, "wb");
+ if(!fi) {
+ char buf[256];
+ sprintf(buf, "rfxswf: Couldn't create %s", filename);
+ perror(buf);
+ return;
+ }
+ data2 = (unsigned char *)rfx_calloc(width*3);
+
+ memset(&cinfo, 0, sizeof(cinfo));
+ memset(&jerr, 0, sizeof(jerr));
+ memset(&fmgr, 0, sizeof(fmgr));
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cinfo);
+
+ fmgr.mgr.init_destination = file_init_destination;
+ fmgr.mgr.empty_output_buffer = file_empty_output_buffer;
+ fmgr.mgr.term_destination = file_term_destination;
+ fmgr.fi = fi;
+ fmgr.cinfo = &cinfo;
+ fmgr.jerr = &jerr;
+ cinfo.dest = (struct jpeg_destination_mgr*)&fmgr;
+
+ // init compression
+
+ cinfo.image_width = width;
+ cinfo.image_height = height;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+ jpeg_set_defaults(&cinfo);
+ cinfo.dct_method = JDCT_IFAST;
+ jpeg_set_quality(&cinfo,quality,TRUE);
+
+ //jpeg_write_tables(&cinfo);
+ //jpeg_suppress_tables(&cinfo, TRUE);
+ jpeg_start_compress(&cinfo, FALSE);
+
+ for(y=0;y<height;y++) {
+ int x;
+ RGBA*src = &pixels[y*width];
+ for(x=0;x<width;x++) {
+ data2[x*3+0] = src[x].r;
+ data2[x*3+1] = src[x].g;
+ data2[x*3+2] = src[x].b;
+ }
+ jpeg_write_scanlines(&cinfo, &data2, 1);
+ }
+ rfx_free(data2);
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+
+ fclose(fi);
+}
+
+/* jpeg_source_mgr functions */
+static void tag_init_source(struct jpeg_decompress_struct *cinfo)
+{
+ TAG *tag = (TAG *) cinfo->client_data;
+ 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)
+{
+ TAG *tag = (TAG *) cinfo->client_data;
+ if (tag->pos + 4 <= tag->len &&
+ tag->data[tag->pos + 0] == 0xff &&
+ tag->data[tag->pos + 1] == 0xd9 &&
+ tag->data[tag->pos + 2] == 0xff &&
+ tag->data[tag->pos + 3] == 0xd8) {
+ tag->pos += 4;
+ }
+ if (tag->pos >= tag->len) {
+ cinfo->src->next_input_byte = 0;
+ cinfo->src->bytes_in_buffer = 0;
+ return 0;
+ }
+ cinfo->src->next_input_byte = &tag->data[tag->pos];
+ cinfo->src->bytes_in_buffer = 1; //tag->len - tag->pos;
+ tag->pos += 1;
+ return 1;
+}
+static void tag_skip_input_data(struct jpeg_decompress_struct *cinfo, long count)
+{
+ TAG *tag = (TAG *) cinfo->client_data;
+ cinfo->src->next_input_byte = 0;
+ cinfo->src->bytes_in_buffer = 0;
+ tag->pos += count;
+}
+static boolean tag_resync_to_restart(struct jpeg_decompress_struct *cinfo, int desired)
+{
+ return jpeg_resync_to_restart(cinfo, desired);
+}
+static void tag_term_source(struct jpeg_decompress_struct *cinfo)
+{
+ TAG *tag = (TAG *) cinfo->client_data;
+}
+RGBA *swf_JPEG2TagToImage(TAG * tag, int *width, int *height)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ 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\n");
+ return 0;
+ }
+ if (tag->id == ST_DEFINEBITSJPEG3) {
+#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_create_decompress(&cinfo);
+
+ cinfo.client_data = (void *) tag;
+ cinfo.src = &mgr;
+ cinfo.src->init_source = tag_init_source;
+ cinfo.src->fill_input_buffer = tag_fill_input_buffer;
+ cinfo.src->skip_input_data = tag_skip_input_data;
+ cinfo.src->resync_to_restart = jpeg_resync_to_restart;
+ cinfo.src->term_source = tag_term_source;
+ cinfo.out_color_space = JCS_RGB;
+
+ jpeg_read_header(&cinfo, TRUE);
+ *width = cinfo.image_width;
+ *height = cinfo.image_height;
+ dest = (RGBA*)
+ rfx_alloc(sizeof(RGBA) * cinfo.image_width * cinfo.image_height);
+
+ jpeg_start_decompress(&cinfo);
+ for (y = 0; y < cinfo.output_height; y++) {
+ RGBA *line = &dest[y * cinfo.image_width];
+ U8 *to = (U8 *) line;
+ int x;
+ jpeg_read_scanlines(&cinfo, &to, 1);
+ for (x = cinfo.output_width - 1; x >= 0; --x) {
+ int r = to[x * 3 + 0];
+ int g = to[x * 3 + 1];
+ int b = to[x * 3 + 2];
+ line[x].r = r;
+ line[x].g = g;
+ line[x].b = b;
+ line[x].a = 255;
+ }
+ }
+
+ jpeg_finish_decompress(&cinfo);
+
+ jpeg_destroy_decompress(&cinfo);
+
+#ifdef HAVE_ZLIB
+ if(offset) {
+ uLongf 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;
+}
+
+#endif // HAVE_JPEGLIB