khanat-code-old/code/nel/tools/3d/tile_edit/PIC/Pic_JPG.cpp
2015-03-02 19:52:39 +01:00

160 lines
4.1 KiB
C++

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <string.h>
#include <jpeglib.h>
#include "pic_private.h"
#include "pic.h"
// ----------------------------------------------------------------------------------------------------------------------------------
struct my_error_mgr
{
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
};
typedef struct my_error_mgr * my_error_ptr;
// ----------------------------------------------------------------------------------------------------------------------------------
static unsigned char error;
// ----------------------------------------------------------------------------------------------------------------------------------
void my_error_exit(j_common_ptr cinfo)
{
my_error_ptr myerr = (my_error_ptr) cinfo->err;
error=1;
longjmp(myerr->setjmp_buffer, 1);
}
// ----------------------------------------------------------------------------------------------------------------------------------
unsigned long Pic_JPG_Read(const char *FileName, char **ppPal, char **ppDatas, unsigned long *w, unsigned long *h)
{
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
FILE *file;
JSAMPARRAY buffer;
int row_stride,i;
char *pDatas,*pPal;
unsigned long ptr;
error=0;
ptr=0;
file=fopen(FileName, "rb");
if (!file)
{
Pic_SetError("JPG_Read, unable to open %s",FileName);
return(0);
}
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
setjmp(jerr.setjmp_buffer);
if (error)
{
Pic_SetError("JPG_Read, internal decompression error");
jpeg_destroy_decompress(&cinfo);
return(0);
}
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, file);
(void) jpeg_read_header(&cinfo, TRUE);
*w=cinfo.image_width;
*h=cinfo.image_height;
if (!ppPal)
{
pDatas=(char*)Pic_calloc(1,(*w)*(*h)*3);
}
else
{
pDatas=(char*)Pic_calloc(1,(*w)*(*h));
pPal=(char*)Pic_calloc(1,256*3);
if (!pPal)
{
Pic_SetError("JPG_Read, not enough memory for palette");
return(0);
}
cinfo.desired_number_of_colors = 256;
cinfo.quantize_colors = TRUE;
cinfo.dither_mode = JDITHER_ORDERED;
}
if (!pDatas)
{
Pic_SetError("JPG_Read, not enough memory for pic");
return(0);
}
(void) jpeg_start_decompress(&cinfo);
row_stride = cinfo.output_width * cinfo.output_components;
buffer = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
while (cinfo.output_scanline < cinfo.output_height)
{
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
memcpy(&pDatas[ptr],buffer[0],row_stride);
ptr+=row_stride;
}
*ppDatas=pDatas;
if (ppPal)
{
for(i=0 ; i<256 ; i++)
{
pPal[i*3+0]=cinfo.colormap[2][i];
pPal[i*3+1]=cinfo.colormap[1][i];
pPal[i*3+2]=cinfo.colormap[0][i];
}
*ppPal=pPal;
}
(void) jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(file);
return(1);
}
// ----------------------------------------------------------------------------------------------------------------------------------
unsigned long Pic_JPG_Write(const char *FileName, unsigned long Qual, char *pDatas, unsigned long w, unsigned long h)
{
struct jpeg_compress_struct cinfo;
struct my_error_mgr jerr;
FILE *file;
JSAMPROW row_pointer[1];
int row_stride;
error=0;
file=fopen(FileName,"wb");
if (!file)
{
Pic_SetError("JPG_Write, unable to open %s",FileName);
return(0);
}
jpeg_create_compress(&cinfo);
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
setjmp(jerr.setjmp_buffer);
if (error)
{
Pic_SetError("JPG_Write, internal compression error");
jpeg_destroy_compress(&cinfo);
return(0);
}
jpeg_stdio_dest(&cinfo, file);
cinfo.image_width = w;
cinfo.image_height = h;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, Qual, TRUE);
jpeg_start_compress(&cinfo, TRUE);
row_stride = w * 3;
while(cinfo.next_scanline<cinfo.image_height)
{
row_pointer[0] = (JSAMPROW)& pDatas[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
fclose(file);
jpeg_destroy_compress(&cinfo);
return(1);
}