638 lines
No EOL
12 KiB
C
638 lines
No EOL
12 KiB
C
#include <string.h>
|
|
#include "pic_private.h"
|
|
#include "pic.h"
|
|
|
|
static unsigned long NbPics=0;
|
|
static PIC_PICTURE *HeadPic=NULL;
|
|
|
|
// ----------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
static PIC_PICTURE *GetPic(unsigned long id)
|
|
{
|
|
PIC_PICTURE *pic;
|
|
|
|
for(pic=HeadPic ; pic ; pic=pic->Next)
|
|
{
|
|
if (pic->ID==id)
|
|
{
|
|
return(pic);
|
|
}
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
unsigned long PIC_Load(char* FileName, unsigned char Quantize)
|
|
{
|
|
unsigned char ext[4];
|
|
unsigned long type;
|
|
unsigned long i,taken,id;
|
|
PIC_PICTURE *pic;
|
|
unsigned char *pDatas;
|
|
unsigned char *pPal;
|
|
unsigned long w,h,Depth;
|
|
unsigned long ret;
|
|
|
|
// --- Init
|
|
ret=0;
|
|
type=0;
|
|
id=0;
|
|
taken=0;
|
|
w=0;
|
|
h=0;
|
|
Depth=0;
|
|
pic=NULL;
|
|
pDatas=NULL;
|
|
pPal=NULL;
|
|
// --- Get 1st available ID
|
|
for(i=1 ; i<=NbPics+1 ; i++)
|
|
{
|
|
taken=0;
|
|
for(pic=HeadPic ; pic ; pic=pic->Next)
|
|
{
|
|
if (pic->ID==i)
|
|
{
|
|
taken=1;
|
|
break;
|
|
}
|
|
}
|
|
if (!taken)
|
|
{
|
|
id=i;
|
|
break;
|
|
}
|
|
}
|
|
if (!id)
|
|
{
|
|
Pic_SetError("Load, unable to create ID");
|
|
return(0);
|
|
}
|
|
// --- Load pic
|
|
if (FileName)
|
|
{
|
|
ext[0]=FileName[strlen(FileName)-3];
|
|
ext[1]=FileName[strlen(FileName)-2];
|
|
ext[2]=FileName[strlen(FileName)-1];
|
|
ext[3]=0;
|
|
strupr(ext);
|
|
if ( !strcmp(ext,"JPG") )
|
|
{
|
|
type=1;
|
|
}
|
|
if ( !strcmp(ext,"TGA") )
|
|
{
|
|
type=2;
|
|
}
|
|
if ( !strcmp(ext,"BMP") )
|
|
{
|
|
type=3;
|
|
}
|
|
switch(type)
|
|
{
|
|
// - JPG
|
|
case 1:
|
|
if (!Quantize)
|
|
{
|
|
Depth=24;
|
|
ret=Pic_JPG_Read(FileName,NULL,&pDatas,&w,&h);
|
|
}
|
|
else
|
|
{
|
|
Depth=8;
|
|
ret=Pic_JPG_Read(FileName,&pPal,&pDatas,&w,&h);
|
|
}
|
|
if (!ret)
|
|
{
|
|
Pic_SetError("Load, unable to load JPG file %s",FileName);
|
|
return(0);
|
|
}
|
|
break;
|
|
// - TGA
|
|
case 2:
|
|
ret=Pic_TGA_Read(FileName,&pPal,&pDatas,&w,&h,&Depth);
|
|
if (!ret)
|
|
{
|
|
Pic_SetError("Load, unable to load TGA file %s",FileName);
|
|
return(0);
|
|
}
|
|
break;
|
|
// - BMP
|
|
case 3:
|
|
ret=Pic_BMP_Read(FileName,&pPal,&pDatas,&w,&h,&Depth);
|
|
if (!ret)
|
|
{
|
|
Pic_SetError("Load, unable to load BMP file %s",FileName);
|
|
return(0);
|
|
}
|
|
break;
|
|
// - Unknown
|
|
default:
|
|
Pic_SetError("Load, unknown extension for %s",FileName);
|
|
return(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
}
|
|
// --- Create and place new pic struct
|
|
pic=Pic_calloc(1,sizeof(PIC_PICTURE));
|
|
if (!pic)
|
|
{
|
|
Pic_SetError("Load, not enough memory for internal structure");
|
|
return(0);
|
|
}
|
|
pic->Next=HeadPic;
|
|
HeadPic=pic;
|
|
NbPics++;
|
|
pic->ID=id;
|
|
pic->pDatas=pDatas;
|
|
pic->pPal=pPal;
|
|
pic->Width=w;
|
|
pic->Height=h;
|
|
pic->Depth=Depth;
|
|
return(id);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
unsigned long PIC_Create(unsigned char* pPal, unsigned char* pDatas, unsigned long w, unsigned long h, unsigned long d)
|
|
{
|
|
unsigned long i,taken,id;
|
|
PIC_PICTURE *pic;
|
|
|
|
// --- Init
|
|
id=0;
|
|
taken=0;
|
|
pic=NULL;
|
|
// --- Get 1st available ID
|
|
for(i=1 ; i<=NbPics+1 ; i++)
|
|
{
|
|
taken=0;
|
|
for(pic=HeadPic ; pic ; pic=pic->Next)
|
|
{
|
|
if (pic->ID==i)
|
|
{
|
|
taken=1;
|
|
break;
|
|
}
|
|
}
|
|
if (!taken)
|
|
{
|
|
id=i;
|
|
break;
|
|
}
|
|
}
|
|
if (!id)
|
|
{
|
|
Pic_SetError("Create, unable to create ID");
|
|
return(0);
|
|
}
|
|
// --- Create pic
|
|
if (!pDatas)
|
|
{
|
|
pDatas=Pic_calloc(1,w*h*d/8);
|
|
if (!pDatas)
|
|
{
|
|
Pic_SetError("Create, not enough memory for datas");
|
|
return(0);
|
|
}
|
|
}
|
|
if (d==8)
|
|
{
|
|
if (!pPal)
|
|
{
|
|
pPal=Pic_calloc(1,256*3);
|
|
if (!pPal)
|
|
{
|
|
Pic_SetError("Create, not enough memory for palette");
|
|
return(0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pPal=NULL;
|
|
}
|
|
// --- Create and place new pic struct
|
|
pic=Pic_calloc(1,sizeof(PIC_PICTURE));
|
|
if (!pic)
|
|
{
|
|
Pic_SetError("Create, not enough memory for internal structure");
|
|
return(0);
|
|
}
|
|
pic->Next=HeadPic;
|
|
HeadPic=pic;
|
|
NbPics++;
|
|
pic->ID=id;
|
|
pic->pDatas=pDatas;
|
|
pic->pPal=pPal;
|
|
pic->Width=w;
|
|
pic->Height=h;
|
|
pic->Depth=d;
|
|
return(id);
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
unsigned long PIC_GetInfos( unsigned long id,
|
|
unsigned char* *ppPal, unsigned char* *ppDatas,
|
|
unsigned long *pW, unsigned long *pH, unsigned long *pD)
|
|
{
|
|
PIC_PICTURE *pic;
|
|
|
|
pic=GetPic(id);
|
|
if (!pic)
|
|
{
|
|
Pic_SetError("GetInfos, picture internal structure not found");
|
|
return(0);
|
|
}
|
|
if (ppPal)
|
|
{
|
|
*ppPal=pic->pPal;
|
|
}
|
|
if (ppDatas)
|
|
{
|
|
*ppDatas=pic->pDatas;
|
|
}
|
|
if (pW)
|
|
{
|
|
*pW=pic->Width;
|
|
}
|
|
if (pH)
|
|
{
|
|
*pH=pic->Height;
|
|
}
|
|
if (pD)
|
|
{
|
|
*pD=pic->Depth;
|
|
}
|
|
return(id);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
static char* Conv8To24(unsigned long id)
|
|
{
|
|
PIC_PICTURE *pic;
|
|
unsigned char *buf;
|
|
unsigned long i;
|
|
|
|
pic=GetPic(id);
|
|
if (!pic)
|
|
{
|
|
Pic_SetError("Conv8To24, picture internal structure not found");
|
|
return(NULL);
|
|
}
|
|
buf=Pic_malloc(pic->Width*pic->Height*3);
|
|
if (!buf)
|
|
{
|
|
Pic_SetError("Conv8To24, not enough memory for temporary buffer");
|
|
return(NULL);
|
|
}
|
|
for(i=0 ; i<pic->Width*pic->Height ; i++)
|
|
{
|
|
buf[i*3+0]=pic->pPal[pic->pDatas[i]*3+0];
|
|
buf[i*3+1]=pic->pPal[pic->pDatas[i]*3+1];
|
|
buf[i*3+2]=pic->pPal[pic->pDatas[i]*3+2];
|
|
}
|
|
return(buf);
|
|
}
|
|
|
|
// ----------------------------------------
|
|
static char* Conv8To16(unsigned long id)
|
|
{
|
|
PIC_PICTURE *pic;
|
|
unsigned short *buf;
|
|
unsigned long i;
|
|
unsigned short r,g,b,pix16;
|
|
|
|
pic=GetPic(id);
|
|
if (!pic)
|
|
{
|
|
Pic_SetError("Conv8To24, picture internal structure not found");
|
|
return(NULL);
|
|
}
|
|
buf=(unsigned short*)Pic_malloc(pic->Width*pic->Height*2);
|
|
if (!buf)
|
|
{
|
|
Pic_SetError("Conv8To24, not enough memory for temporary buffer");
|
|
return(NULL);
|
|
}
|
|
for(i=0 ; i<pic->Width*pic->Height ; i++)
|
|
{
|
|
b=pic->pPal[pic->pDatas[i]*3+0];
|
|
g=pic->pPal[pic->pDatas[i]*3+1];
|
|
r=pic->pPal[pic->pDatas[i]*3+2];
|
|
r>>=3;
|
|
g>>=3; g&=0x3E;
|
|
b>>=3;
|
|
pix16=(r<<10)+(g<<5)+b;
|
|
buf[i]=pix16;
|
|
}
|
|
return((unsigned char*)buf);
|
|
}
|
|
|
|
// ----------------------------------------
|
|
|
|
static char* Conv16To24(unsigned long id)
|
|
{
|
|
PIC_PICTURE *pic;
|
|
unsigned short *pDatas;
|
|
unsigned char *buf;
|
|
unsigned long i;
|
|
unsigned short r,g,b;
|
|
|
|
pic=GetPic(id);
|
|
if (!pic)
|
|
{
|
|
Pic_SetError("Conv16To24, picture internal structure not found");
|
|
return(NULL);
|
|
}
|
|
buf=Pic_malloc(pic->Width*pic->Height*3);
|
|
if (!buf)
|
|
{
|
|
Pic_SetError("Conv16To24, not enough memory for temporary buffer");
|
|
return(NULL);
|
|
}
|
|
pDatas=(unsigned short*)pic->pDatas;
|
|
for(i=0 ; i<pic->Width*pic->Height ; i++)
|
|
{
|
|
r=(pDatas[i] & 0x7C00)>>(10-3);
|
|
g=(pDatas[i] & 0x03E0)>>(5-3);
|
|
b=(pDatas[i] & 0x001F)<<3;
|
|
buf[i*3+0]=(unsigned char)r;
|
|
buf[i*3+1]=(unsigned char)g;
|
|
buf[i*3+2]=(unsigned char)b;
|
|
}
|
|
return(buf);
|
|
}
|
|
|
|
// ----------------------------------------
|
|
|
|
static char* Conv24To16(unsigned long id)
|
|
{
|
|
PIC_PICTURE *pic;
|
|
unsigned short *buf;
|
|
unsigned long i;
|
|
unsigned short r,g,b;
|
|
unsigned short pix16;
|
|
|
|
pic=GetPic(id);
|
|
if (!pic)
|
|
{
|
|
Pic_SetError("Conv24To16, picture internal structure not found");
|
|
return(NULL);
|
|
}
|
|
buf=(unsigned short*)Pic_malloc(pic->Width*pic->Height*2);
|
|
if (!buf)
|
|
{
|
|
Pic_SetError("Conv24To16, not enough memory for temporary buffer");
|
|
return(NULL);
|
|
}
|
|
for(i=0 ; i<pic->Width*pic->Height ; i++)
|
|
{
|
|
r=pic->pDatas[i*3+0];
|
|
g=pic->pDatas[i*3+1];
|
|
b=pic->pDatas[i*3+2];
|
|
// r : 5 bits forts (0x7C)
|
|
// g : 5 bits (6e zapped) (0x3E)
|
|
// b : 5 bits faibles (0x1F)
|
|
r>>=3;
|
|
g>>=3; g&=0x3E;
|
|
b>>=3;
|
|
pix16=(r<<10)+(g<<5)+b;
|
|
buf[i]=pix16;
|
|
}
|
|
return((unsigned char*)buf);
|
|
}
|
|
|
|
// ----------------------------------------
|
|
|
|
static char* ConvPic(PIC_PICTURE *pic, unsigned long type, char* pErr)
|
|
{
|
|
unsigned char *buf;
|
|
unsigned long src,dst;
|
|
|
|
*pErr=0;
|
|
buf=NULL;
|
|
src=pic->Depth;
|
|
if (type==PIC_TYPE_TGA8 || type==PIC_TYPE_BMP8)
|
|
{
|
|
dst=8;
|
|
}
|
|
if (type==PIC_TYPE_TGA16)
|
|
{
|
|
dst=16;
|
|
}
|
|
if (type==PIC_TYPE_JPG || type==PIC_TYPE_TGA24 || type==PIC_TYPE_BMP24)
|
|
{
|
|
dst=24;
|
|
}
|
|
// ---
|
|
if (src==dst)
|
|
{
|
|
return(NULL);
|
|
}
|
|
// ---
|
|
if (src==8 && dst==24)
|
|
{
|
|
buf=Conv8To24(pic->ID);
|
|
if (!buf)
|
|
{
|
|
*pErr=1;
|
|
}
|
|
return(buf);
|
|
}
|
|
if (src==8 && dst==16)
|
|
{
|
|
buf=Conv8To16(pic->ID);
|
|
if (!buf)
|
|
{
|
|
*pErr=1;
|
|
}
|
|
return(buf);
|
|
}
|
|
// ---
|
|
if (src==16 && dst==24)
|
|
{
|
|
buf=Conv16To24(pic->ID);
|
|
if (!buf)
|
|
{
|
|
*pErr=1;
|
|
}
|
|
return(buf);
|
|
}
|
|
// ---
|
|
if (src==24 && dst==16)
|
|
{
|
|
buf=Conv24To16(pic->ID);
|
|
if (!buf)
|
|
{
|
|
*pErr=1;
|
|
}
|
|
return(buf);
|
|
}
|
|
// ---
|
|
if (src==24 && dst==8)
|
|
{
|
|
Pic_SetError("ConvPic, downsampling 24 to 8 bits unsupported");
|
|
*pErr=1;
|
|
return(NULL);
|
|
}
|
|
Pic_SetError("ConvPic, conversion %d to %d unsupported",src,dst);
|
|
*pErr=1;
|
|
return(NULL);
|
|
}
|
|
|
|
// ----------------------------------------
|
|
|
|
unsigned long PIC_Save(unsigned long id, char* FileName, unsigned long type, unsigned long qual)
|
|
{
|
|
PIC_PICTURE *pic;
|
|
unsigned char err;
|
|
unsigned char *buf;
|
|
unsigned char *freeit;
|
|
unsigned long depth;
|
|
|
|
freeit=NULL;
|
|
pic=GetPic(id);
|
|
if (!pic)
|
|
{
|
|
Pic_SetError("Save %s, picture internal structure not found",FileName);
|
|
return(0);
|
|
}
|
|
freeit=ConvPic(pic,type,&err);
|
|
if (err)
|
|
{
|
|
Pic_SetError("Save %s, error while converting picture",FileName);
|
|
return(0);
|
|
}
|
|
if (!freeit)
|
|
{
|
|
buf=pic->pDatas;
|
|
}
|
|
else
|
|
{
|
|
buf=freeit;
|
|
}
|
|
err=0;
|
|
switch(type)
|
|
{
|
|
// ---
|
|
case PIC_TYPE_JPG:
|
|
if ( !Pic_JPG_Write(FileName,qual,buf,pic->Width,pic->Height) )
|
|
{
|
|
if (freeit)
|
|
{
|
|
Pic_free(buf);
|
|
}
|
|
Pic_SetError("Save %s, error while saving JPG file",FileName);
|
|
err=1;
|
|
}
|
|
break;
|
|
// ---
|
|
case PIC_TYPE_TGA8:
|
|
case PIC_TYPE_TGA16:
|
|
case PIC_TYPE_TGA24:
|
|
if (type==PIC_TYPE_TGA8)
|
|
{
|
|
depth=8;
|
|
}
|
|
if (type==PIC_TYPE_TGA16)
|
|
{
|
|
depth=16;
|
|
}
|
|
if (type==PIC_TYPE_TGA24)
|
|
{
|
|
depth=24;
|
|
}
|
|
if ( !Pic_TGA_Write(FileName,pic->pPal,buf,pic->Width,pic->Height,depth) )
|
|
{
|
|
if (freeit)
|
|
{
|
|
Pic_free(freeit);
|
|
}
|
|
Pic_SetError("Save %s, error while saving TGA file",FileName);
|
|
err=1;
|
|
}
|
|
break;
|
|
// ---
|
|
case PIC_TYPE_BMP8:
|
|
case PIC_TYPE_BMP24:
|
|
if (type==PIC_TYPE_BMP8)
|
|
{
|
|
depth=8;
|
|
}
|
|
if (type==PIC_TYPE_BMP24)
|
|
{
|
|
depth=24;
|
|
}
|
|
if ( !Pic_BMP_Write(FileName,pic->pPal,buf,pic->Width,pic->Height,depth) )
|
|
{
|
|
if (freeit)
|
|
{
|
|
Pic_free(freeit);
|
|
}
|
|
Pic_SetError("Save %s, error while saving BMP file",FileName);
|
|
err=1;
|
|
}
|
|
break;
|
|
// ---
|
|
default:
|
|
Pic_SetError("Save %s, unknow save format/type",FileName);
|
|
err=1;
|
|
break;
|
|
}
|
|
if (freeit)
|
|
{
|
|
Pic_free(freeit);
|
|
}
|
|
return(err-1);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
unsigned long PIC_Destroy(unsigned long id)
|
|
{
|
|
PIC_PICTURE *prevpic,*pic;
|
|
unsigned long found;
|
|
|
|
prevpic=NULL;
|
|
found=0;
|
|
for(pic=HeadPic ; pic ; pic=pic->Next)
|
|
{
|
|
if (pic->ID==id)
|
|
{
|
|
found=1;
|
|
break;
|
|
}
|
|
prevpic=pic;
|
|
}
|
|
if (!found)
|
|
{
|
|
Pic_SetError("Destroy, picture internal structure not found");
|
|
return(0);
|
|
}
|
|
if (prevpic)
|
|
{
|
|
prevpic->Next=pic->Next;
|
|
}
|
|
if (pic->pDatas)
|
|
{
|
|
Pic_free(pic->pDatas);
|
|
}
|
|
if (pic->pPal)
|
|
{
|
|
Pic_free(pic->pPal);
|
|
}
|
|
if (pic==HeadPic)
|
|
{
|
|
HeadPic=pic->Next;
|
|
}
|
|
Pic_free(pic);
|
|
return(1);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------------------------------------------
|