winamp/Src/gif/GIFWriter.cpp

127 lines
3.5 KiB
C++
Raw Normal View History

2024-09-24 14:54:57 +02:00
#include "GIFWriter.h"
#include "api__gif.h"
#include <wchar.h>
#include <bfc/platform/strcmp.h>
extern "C" {
#include "gif_lib.h"
};
// valid items include "quality" for jpeg files with value "0" to "100"
// return value is 1 if the config item is supported, 0 if it is not.
int GIFWriter::setConfig(const wchar_t * item, const wchar_t * value) {
return 0; // no config yet
}
// 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 GIFWriter::getConfig(const wchar_t * item, wchar_t * value, int valuelen) {
if(!_wcsicmp(item,L"lossless")) lstrcpynW(value,L"0",valuelen);
else return 0;
return 1;
}
// returns 1 if the bit depth is supported (eg 32 for ARGB32, 24 for RGB24)
// ARGB32 MUST be supported
int GIFWriter::bitDepthSupported(int depth) {
if(depth == 32 || depth == 24) return 1;
return 0;
}
typedef struct {
BYTE * data;
unsigned int len;
unsigned int alloc;
} writeStruct;
extern "C" int MyOutputFunc(GifFileType * gif, const GifByteType * data, int len) {
writeStruct * p = (writeStruct *)gif->UserData;
while (len + p->len > p->alloc) { // allocate more memory
int d = ((p->alloc / 4) & 0xffffff00) + 0x100;
if(d < 4096) d = 4096;
p->alloc+=d;
p->data = (BYTE*)WASABI_API_MEMMGR->sysRealloc(p->data,p->alloc);
}
memcpy(p->data+p->len,data,len);
p->len += len;
return len;
}
// returns the image in our format, free the returned buffer with api_memmgr::sysFree()
void * GIFWriter::convert(const void *pixels, int bitDepth, int w, int h, int *length) {
// split into planes
BYTE *redplane, *blueplane, *greenplane;
redplane = (BYTE *)malloc(w*h*sizeof(BYTE));
greenplane = (BYTE *)malloc(w*h*sizeof(BYTE));
blueplane = (BYTE *)malloc(w*h*sizeof(BYTE));
BYTE * px = (BYTE *)pixels;
BYTE * end = px + (w * h * (bitDepth/8));
int i=0;
if(bitDepth == 24) {
while(px < end) {
blueplane[i] = *(px++);
greenplane[i] = *(px++);
redplane[i] = *(px++);
i++;
}
} else if(bitDepth == 32) {
while(px < end) {
blueplane[i] = *(px++);
greenplane[i] = *(px++);
redplane[i] = *(px++);
px++;
i++;
}
}
// make a color map
int colormapsize = 256;
ColorMapObject * OutputColorMap = GifMakeMapObject(colormapsize, NULL);
BYTE* OutputBuffer = (GifByteType *) malloc(w * h * sizeof(GifByteType));
// this is actually kinda crappy
GifQuantizeBuffer(w,h,&colormapsize,redplane,greenplane,blueplane,OutputBuffer,OutputColorMap->Colors);
unsigned int alloc = ((w*h / 3) & 0xffffff00) + 0x100; // guess at output file size
if(alloc < 4096) alloc = 4096;
writeStruct write = {(BYTE*)WASABI_API_MEMMGR->sysMalloc(alloc),0,alloc};
bool succeeded=false;
// write the file out
int* l_error = NULL;
GifFileType *gif = EGifOpen(&write,MyOutputFunc, l_error);
if(gif) {
if(EGifPutScreenDesc(gif,w, h, 8, 0, OutputColorMap)) {
if(EGifPutImageDesc(gif, 0, 0, w, h, FALSE, NULL)) {
BYTE * p = OutputBuffer;
succeeded=true;
for (int i = 0; i < h; i++) {
if(!EGifPutLine(gif, p, w)) {succeeded=false; break;}
p+=w;
}
}
}
EGifCloseFile(gif, l_error);
}
// done!
free(OutputBuffer);
free(redplane);
free(greenplane);
free(blueplane);
if(succeeded) {
*length = write.len;
return write.data;
} else return 0;
}
#define CBCLASS GIFWriter
START_DISPATCH;
CB(GETIMAGETYPENAME, getImageTypeName);
CB(GETEXTENSIONS, getExtensions);
CB(SETCONFIG, setConfig);
CB(GETCONFIG, getConfig);
CB(BITDEPTHSUPPORTED, bitDepthSupported);
CB(CONVERT, convert);
END_DISPATCH;
#undef CBCLASS