#include "main.h" #include "writer_jpg.h" #include "api__jpeg.h" #include #include #include /*BIG BIG THING TO NOTE I have modified jmorecfg.h line 319 to specify 4 bytes per pixel with RGB. it is normally three. */ extern "C" { #undef FAR #include "jpeglib.h" }; JpgWrite::JpgWrite() : quality(80) {} // valid items include "quality" for jpeg files with value "0" to "100", "lossless" returns "1" if it is "0" otherwise // return value is 1 if the config item is supported, 0 if it is not. int JpgWrite::setConfig(const wchar_t * item, const wchar_t * value) { if(!_wcsicmp(item,L"quality")) quality = _wtoi(value); else return 0; return 1; } int JpgWrite::getConfig(const wchar_t * item, wchar_t * value, int valuelen) { if(!_wcsicmp(item,L"lossless")) lstrcpynW(value,L"0",valuelen); else if(!_wcsicmp(item,L"quality")) StringCchPrintfW(value,valuelen,L"%d",quality); else return 0; return 1; } int JpgWrite::bitDepthSupported(int depth) { if(depth == 32 || depth == 24) return 1; return 0; } extern "C" { typedef struct { jpeg_destination_mgr pub; BYTE *buf; int len; } my_destination_mgr; void init_destination(j_compress_ptr cinfo){} boolean empty_output_buffer(j_compress_ptr cinfo) { my_destination_mgr* m = (my_destination_mgr*)cinfo->dest; int used = m->len; int d = ((m->len / 4) & 0xffffff00) + 0x100; if(d < 4096) d = 4096; m->len+=d; m->buf = (BYTE*)WASABI_API_MEMMGR->sysRealloc(m->buf,m->len); m->pub.next_output_byte = m->buf + used; m->pub.free_in_buffer = d; return TRUE; } void term_destination(j_compress_ptr cinfo){} }; // returns the image in our format, free the returned buffer with api_memmgr::sysFree() void * JpgWrite::convert(const void *pixels, int bitDepth, int w, int h, int *length) { if(bitDepth != 32 && bitDepth != 24) return 0; jpeg_compress_struct cinfo={0}; jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); // a guess at the final size... int allocsize = (int(double(w*h)*0.2) & 0xffffff00) + 0x100; if (allocsize < 4096) allocsize = 4096; // set up our output stream my_destination_mgr dest = {{0,(size_t)allocsize,init_destination,empty_output_buffer,term_destination},0,allocsize}; dest.buf = (BYTE*)WASABI_API_MEMMGR->sysMalloc(allocsize); dest.pub.next_output_byte = dest.buf; cinfo.dest = (jpeg_destination_mgr*)&dest; // image parameters cinfo.image_width = w; cinfo.image_height = h; cinfo.input_components = 4; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); jpeg_start_compress(&cinfo, TRUE); int row_stride = w * 4; BYTE * scanline = (BYTE *)malloc(row_stride); if(bitDepth == 32) { const ARGB32 * p = ((const ARGB32*)pixels);// + (h * w); while (cinfo.next_scanline < cinfo.image_height) { //p-=w; memcpy(scanline,p,row_stride); for(unsigned int i=0; i < cinfo.image_width; i++) ((ARGB32*)scanline)[i] = ((p[i] & 0x0000ff) << 16) | (p[i] & 0x00ff00) | ((p[i] & 0xff0000) >> 16); jpeg_write_scanlines(&cinfo, &scanline, 1); p+=w; } } else if(bitDepth == 24) { // FUCKO: untested const BYTE * p = ((const BYTE*)pixels);// + (h * w * 3); while (cinfo.next_scanline < cinfo.image_height) { //p-=w*3; memcpy(scanline,p,row_stride); int l = cinfo.image_width * 4; for(int i=0,j=0; j < l; i+=3,j+=4) { scanline[j] = p[i+2]; scanline[j+1] = p[i+1]; scanline[j+2] = p[i]; } jpeg_write_scanlines(&cinfo, &scanline, 1); p+=w*3; } } free(scanline); jpeg_finish_compress(&cinfo); if(length) *length = int(dest.len - dest.pub.free_in_buffer); jpeg_destroy_compress(&cinfo); return dest.buf; } #define CBCLASS JpgWrite START_DISPATCH; CB(GETIMAGETYPENAME, getImageTypeName); CB(GETEXTENSIONS, getExtensions); CB(SETCONFIG, setConfig); CB(GETCONFIG, getConfig); CB(BITDEPTHSUPPORTED, bitDepthSupported); CB(CONVERT, convert); END_DISPATCH; #undef CBCLASS