499 lines
11 KiB
C++
499 lines
11 KiB
C++
|
#include "HGJpeg.h"
|
|||
|
#include "../base/HGInc.h"
|
|||
|
#include "../base/HGInfo.h"
|
|||
|
extern "C"
|
|||
|
{
|
|||
|
#include "jpeglib.h"
|
|||
|
#include "jmemsys.h"
|
|||
|
};
|
|||
|
|
|||
|
typedef struct my_error_mgr
|
|||
|
{
|
|||
|
struct jpeg_error_mgr pub;
|
|||
|
jmp_buf setjmp_buffer;
|
|||
|
}my_error_mgr, * my_error_mgr_ptr;
|
|||
|
|
|||
|
METHODDEF(void) my_error_exit(j_common_ptr cinfo)
|
|||
|
{
|
|||
|
my_error_mgr_ptr myerr = (my_error_mgr_ptr)cinfo->err;
|
|||
|
(*cinfo->err->output_message)(cinfo);
|
|||
|
longjmp(myerr->setjmp_buffer, (int)HGBASE_ERR_FAIL);
|
|||
|
}
|
|||
|
|
|||
|
HGResult HGAPI HGImgFmt_CheckJpegFile(const HGChar* fileName, HGBool* isJpeg)
|
|||
|
{
|
|||
|
if (NULL == fileName || NULL == isJpeg)
|
|||
|
{
|
|||
|
return HGBASE_ERR_INVALIDARG;
|
|||
|
}
|
|||
|
|
|||
|
HGJpegLoadInfo info;
|
|||
|
HGResult ret = HGImgFmt_LoadJpegImage(fileName, &info, 0, 0, NULL);
|
|||
|
*isJpeg = (HGBASE_ERR_OK == ret ? HGTRUE : HGFALSE);
|
|||
|
return HGBASE_ERR_OK;
|
|||
|
}
|
|||
|
|
|||
|
HGResult HGAPI HGImgFmt_LoadJpegImage(const HGChar* fileName, HGJpegLoadInfo* info,
|
|||
|
HGUInt imgType, HGUInt imgOrigin, HGImage* image)
|
|||
|
{
|
|||
|
if (NULL == fileName)
|
|||
|
{
|
|||
|
return HGBASE_ERR_INVALIDARG;
|
|||
|
}
|
|||
|
|
|||
|
if (NULL == image)
|
|||
|
{
|
|||
|
if (0 != imgType || 0 != imgOrigin)
|
|||
|
{
|
|||
|
return HGBASE_ERR_INVALIDARG;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (0 != imgType && HGBASE_IMGTYPE_GRAY != imgType && HGBASE_IMGTYPE_RGB != imgType)
|
|||
|
{
|
|||
|
return HGBASE_ERR_INVALIDARG;
|
|||
|
}
|
|||
|
|
|||
|
if (HGBASE_IMGORIGIN_TOP != imgOrigin && HGBASE_IMGORIGIN_BOTTOM != imgOrigin)
|
|||
|
{
|
|||
|
return HGBASE_ERR_INVALIDARG;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
FILE* file = fopen(fileName, "rb");
|
|||
|
if (NULL == file)
|
|||
|
{
|
|||
|
HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "(%s) (%s) Open File %s Failed",
|
|||
|
__FILE__, __FUNCTION__, fileName);
|
|||
|
return HGBASE_ERR_ACCESSDENIED;
|
|||
|
}
|
|||
|
|
|||
|
struct jpeg_decompress_struct cinfo;
|
|||
|
struct my_error_mgr jerr;
|
|||
|
cinfo.err = jpeg_std_error(&jerr.pub);
|
|||
|
jerr.pub.error_exit = my_error_exit;
|
|||
|
|
|||
|
HGImage image2 = NULL;
|
|||
|
|
|||
|
int jmpResult = setjmp(jerr.setjmp_buffer);
|
|||
|
if (0 != jmpResult)
|
|||
|
{
|
|||
|
HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "(%s) (%s) Jpeg Error, ErrCode=%u",
|
|||
|
__FILE__, __FUNCTION__, (HGResult)jmpResult);
|
|||
|
HGBase_DestroyImage(image2);
|
|||
|
image2 = NULL;
|
|||
|
jpeg_destroy_decompress(&cinfo);
|
|||
|
fclose(file);
|
|||
|
file = NULL;
|
|||
|
return (HGResult)jmpResult;
|
|||
|
}
|
|||
|
|
|||
|
jpeg_create_decompress(&cinfo);
|
|||
|
jpeg_stdio_src(&cinfo, file);
|
|||
|
jpeg_read_header(&cinfo, TRUE);
|
|||
|
|
|||
|
if (NULL != info)
|
|||
|
{
|
|||
|
info->width = cinfo.image_width;
|
|||
|
info->height = cinfo.image_height;
|
|||
|
info->numComponents = cinfo.num_components;
|
|||
|
info->colorSpace = cinfo.jpeg_color_space;
|
|||
|
|
|||
|
info->densityUnit = cinfo.density_unit;
|
|||
|
info->xDensity = cinfo.X_density;
|
|||
|
info->yDensity = cinfo.Y_density;
|
|||
|
}
|
|||
|
|
|||
|
if (NULL != image)
|
|||
|
{
|
|||
|
if (0 == imgType)
|
|||
|
{
|
|||
|
if (JCS_GRAYSCALE != cinfo.out_color_space)
|
|||
|
{
|
|||
|
cinfo.out_color_space = JCS_RGB;
|
|||
|
imgType = HGBASE_IMGTYPE_RGB;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
imgType = HGBASE_IMGTYPE_GRAY;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (HGBASE_IMGTYPE_GRAY == imgType)
|
|||
|
{
|
|||
|
cinfo.out_color_space = JCS_GRAYSCALE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
assert(HGBASE_IMGTYPE_RGB == imgType);
|
|||
|
cinfo.out_color_space = JCS_RGB;
|
|||
|
}
|
|||
|
|
|||
|
jpeg_start_decompress(&cinfo);
|
|||
|
|
|||
|
if (HGBASE_ERR_OK != HGBase_CreateImage(cinfo.output_width, cinfo.output_height, imgType, imgOrigin, &image2))
|
|||
|
{
|
|||
|
longjmp(jerr.setjmp_buffer, (int)HGBASE_ERR_FAIL);
|
|||
|
}
|
|||
|
|
|||
|
if (1 == cinfo.density_unit)
|
|||
|
{
|
|||
|
HGBase_SetImageDpi(image2, cinfo.X_density, cinfo.Y_density);
|
|||
|
}
|
|||
|
|
|||
|
HGImageInfo imgInfo;
|
|||
|
HGBase_GetImageInfo(image2, &imgInfo);
|
|||
|
uint8_t* data;
|
|||
|
HGBase_GetImageData(image2, &data);
|
|||
|
|
|||
|
uint8_t* p = data;
|
|||
|
HGSize step = (HGSize)imgInfo.widthStep;
|
|||
|
if (HGBASE_IMGORIGIN_BOTTOM == imgOrigin)
|
|||
|
{
|
|||
|
p = data + (HGUSize)(imgInfo.height - 1) * (HGUSize)imgInfo.widthStep;
|
|||
|
step = -(HGSize)imgInfo.widthStep;
|
|||
|
}
|
|||
|
|
|||
|
while (cinfo.output_scanline < cinfo.output_height)
|
|||
|
{
|
|||
|
JSAMPROW pEx = p + (HGSize)cinfo.output_scanline * (HGSize)step;
|
|||
|
jpeg_read_scanlines(&cinfo, &pEx, 1);
|
|||
|
}
|
|||
|
|
|||
|
jpeg_finish_decompress(&cinfo);
|
|||
|
*image = image2;
|
|||
|
}
|
|||
|
|
|||
|
jpeg_destroy_decompress(&cinfo);
|
|||
|
fclose(file);
|
|||
|
file = NULL;
|
|||
|
return HGBASE_ERR_OK;
|
|||
|
}
|
|||
|
|
|||
|
HGResult HGAPI HGImgFmt_LoadJpegImageFromBuffer(HGBuffer buffer, HGJpegLoadInfo* info,
|
|||
|
HGUInt imgType, HGUInt imgOrigin, HGImage* image)
|
|||
|
{
|
|||
|
if (NULL == buffer)
|
|||
|
{
|
|||
|
return HGBASE_ERR_INVALIDARG;
|
|||
|
}
|
|||
|
|
|||
|
if (NULL == image)
|
|||
|
{
|
|||
|
if (0 != imgType || 0 != imgOrigin)
|
|||
|
{
|
|||
|
return HGBASE_ERR_INVALIDARG;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (0 != imgType && HGBASE_IMGTYPE_GRAY != imgType && HGBASE_IMGTYPE_RGB != imgType)
|
|||
|
{
|
|||
|
return HGBASE_ERR_INVALIDARG;
|
|||
|
}
|
|||
|
|
|||
|
if (HGBASE_IMGORIGIN_TOP != imgOrigin && HGBASE_IMGORIGIN_BOTTOM != imgOrigin)
|
|||
|
{
|
|||
|
return HGBASE_ERR_INVALIDARG;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
struct jpeg_decompress_struct cinfo;
|
|||
|
struct my_error_mgr jerr;
|
|||
|
cinfo.err = jpeg_std_error(&jerr.pub);
|
|||
|
jerr.pub.error_exit = my_error_exit;
|
|||
|
|
|||
|
HGImage image2 = NULL;
|
|||
|
|
|||
|
int jmpResult = setjmp(jerr.setjmp_buffer);
|
|||
|
if (0 != jmpResult)
|
|||
|
{
|
|||
|
HGBase_DestroyImage(image2);
|
|||
|
image2 = NULL;
|
|||
|
jpeg_destroy_decompress(&cinfo);
|
|||
|
return (HGResult)jmpResult;
|
|||
|
}
|
|||
|
|
|||
|
HGByte* memAddr = NULL;
|
|||
|
HGBase_GetBufferData(buffer, &memAddr);
|
|||
|
HGUSize size = 0;
|
|||
|
HGBase_GetBufferSize(buffer, &size);
|
|||
|
|
|||
|
jpeg_create_decompress(&cinfo);
|
|||
|
jpeg_mem_src(&cinfo, memAddr, (unsigned long)size);
|
|||
|
jpeg_read_header(&cinfo, TRUE);
|
|||
|
|
|||
|
if (NULL != info)
|
|||
|
{
|
|||
|
info->width = cinfo.image_width;
|
|||
|
info->height = cinfo.image_height;
|
|||
|
info->numComponents = cinfo.num_components;
|
|||
|
info->colorSpace = cinfo.jpeg_color_space;
|
|||
|
|
|||
|
info->densityUnit = cinfo.density_unit;
|
|||
|
info->xDensity = cinfo.X_density;
|
|||
|
info->yDensity = cinfo.Y_density;
|
|||
|
}
|
|||
|
|
|||
|
if (NULL != image)
|
|||
|
{
|
|||
|
if (0 == imgType)
|
|||
|
{
|
|||
|
if (JCS_GRAYSCALE != cinfo.out_color_space)
|
|||
|
{
|
|||
|
cinfo.out_color_space = JCS_RGB;
|
|||
|
imgType = HGBASE_IMGTYPE_RGB;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
imgType = HGBASE_IMGTYPE_GRAY;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (HGBASE_IMGTYPE_GRAY == imgType)
|
|||
|
{
|
|||
|
cinfo.out_color_space = JCS_GRAYSCALE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
assert(HGBASE_IMGTYPE_RGB == imgType);
|
|||
|
cinfo.out_color_space = JCS_RGB;
|
|||
|
}
|
|||
|
|
|||
|
jpeg_start_decompress(&cinfo);
|
|||
|
|
|||
|
if (HGBASE_ERR_OK != HGBase_CreateImage(cinfo.output_width, cinfo.output_height, imgType, imgOrigin, &image2))
|
|||
|
{
|
|||
|
longjmp(jerr.setjmp_buffer, (int)HGBASE_ERR_FAIL);
|
|||
|
}
|
|||
|
|
|||
|
if (1 == cinfo.density_unit)
|
|||
|
{
|
|||
|
HGBase_SetImageDpi(image2, cinfo.X_density, cinfo.Y_density);
|
|||
|
}
|
|||
|
|
|||
|
HGImageInfo imgInfo;
|
|||
|
HGBase_GetImageInfo(image2, &imgInfo);
|
|||
|
uint8_t* data;
|
|||
|
HGBase_GetImageData(image2, &data);
|
|||
|
|
|||
|
uint8_t* p = data;
|
|||
|
HGSize step = (HGSize)imgInfo.widthStep;
|
|||
|
if (HGBASE_IMGORIGIN_BOTTOM == imgOrigin)
|
|||
|
{
|
|||
|
p = data + (HGUSize)(imgInfo.height - 1) * (HGUSize)imgInfo.widthStep;
|
|||
|
step = -(HGSize)imgInfo.widthStep;
|
|||
|
}
|
|||
|
|
|||
|
while (cinfo.output_scanline < cinfo.output_height)
|
|||
|
{
|
|||
|
JSAMPROW pEx = p + (HGSize)cinfo.output_scanline * (HGSize)step;
|
|||
|
jpeg_read_scanlines(&cinfo, &pEx, 1);
|
|||
|
}
|
|||
|
|
|||
|
jpeg_finish_decompress(&cinfo);
|
|||
|
*image = image2;
|
|||
|
}
|
|||
|
|
|||
|
jpeg_destroy_decompress(&cinfo);
|
|||
|
return HGBASE_ERR_OK;
|
|||
|
}
|
|||
|
|
|||
|
HGResult HGAPI HGImgFmt_SaveJpegImage(HGImage image, const HGJpegSaveInfo* info, HGUInt quality, const HGChar* fileName)
|
|||
|
{
|
|||
|
if (NULL == image || quality > 100 || NULL == fileName)
|
|||
|
{
|
|||
|
return HGBASE_ERR_INVALIDARG;
|
|||
|
}
|
|||
|
|
|||
|
if (NULL != info)
|
|||
|
{
|
|||
|
// 判断info参数的合法性
|
|||
|
}
|
|||
|
|
|||
|
HGImageInfo imgInfo;
|
|||
|
HGBase_GetImageInfo(image, &imgInfo);
|
|||
|
uint32_t type = imgInfo.type;
|
|||
|
if (HGBASE_IMGTYPE_GRAY != type && HGBASE_IMGTYPE_RGB != type)
|
|||
|
{
|
|||
|
return HGBASE_ERR_INVALIDDATA;
|
|||
|
}
|
|||
|
|
|||
|
FILE* file = fopen(fileName, "wb");
|
|||
|
if (NULL == file)
|
|||
|
{
|
|||
|
return HGBASE_ERR_ACCESSDENIED;
|
|||
|
}
|
|||
|
|
|||
|
struct jpeg_compress_struct cinfo;
|
|||
|
struct my_error_mgr jerr;
|
|||
|
cinfo.err = jpeg_std_error(&jerr.pub);
|
|||
|
jerr.pub.error_exit = my_error_exit;
|
|||
|
|
|||
|
int jmpResult = setjmp(jerr.setjmp_buffer);
|
|||
|
if (0 != jmpResult)
|
|||
|
{
|
|||
|
jpeg_destroy_compress(&cinfo);
|
|||
|
fclose(file);
|
|||
|
file = NULL;
|
|||
|
return (HGResult)jmpResult;
|
|||
|
}
|
|||
|
|
|||
|
jpeg_create_compress(&cinfo);
|
|||
|
jpeg_stdio_dest(&cinfo, file);
|
|||
|
|
|||
|
uint32_t width = imgInfo.width;
|
|||
|
uint32_t height = imgInfo.height;
|
|||
|
uint32_t widthStep = imgInfo.widthStep;
|
|||
|
uint8_t* data;
|
|||
|
HGBase_GetImageData(image, &data);
|
|||
|
|
|||
|
cinfo.image_width = width;
|
|||
|
cinfo.image_height = height;
|
|||
|
cinfo.input_components = (HGBASE_IMGTYPE_GRAY != type) ? 3 : 1;
|
|||
|
cinfo.in_color_space = (HGBASE_IMGTYPE_GRAY != type) ? JCS_RGB : JCS_GRAYSCALE;
|
|||
|
jpeg_set_defaults(&cinfo);
|
|||
|
|
|||
|
HGUInt xDpi, yDpi;
|
|||
|
HGBase_GetImageDpi(image, &xDpi, &yDpi);
|
|||
|
|
|||
|
cinfo.density_unit = 1;
|
|||
|
cinfo.X_density = xDpi;
|
|||
|
cinfo.Y_density = yDpi;
|
|||
|
|
|||
|
if (NULL != info)
|
|||
|
{
|
|||
|
cinfo.density_unit = info->densityUnit;
|
|||
|
cinfo.X_density = info->xDensity;
|
|||
|
cinfo.Y_density = info->yDensity;
|
|||
|
}
|
|||
|
|
|||
|
if (0 == quality)
|
|||
|
quality = 80;
|
|||
|
jpeg_set_quality(&cinfo, (int)quality, TRUE);
|
|||
|
jpeg_start_compress(&cinfo, TRUE);
|
|||
|
|
|||
|
uint8_t* p = data;
|
|||
|
HGSize step = (HGSize)imgInfo.widthStep;
|
|||
|
if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin)
|
|||
|
{
|
|||
|
p = data + (HGUSize)(imgInfo.height - 1) * (HGUSize)imgInfo.widthStep;
|
|||
|
step = -(HGSize)imgInfo.widthStep;
|
|||
|
}
|
|||
|
|
|||
|
while (cinfo.next_scanline < cinfo.image_height)
|
|||
|
{
|
|||
|
uint8_t* pEx = p + (HGSize)cinfo.next_scanline * (HGSize)step;
|
|||
|
jpeg_write_scanlines(&cinfo, &pEx, 1);
|
|||
|
}
|
|||
|
|
|||
|
jpeg_finish_compress(&cinfo);
|
|||
|
|
|||
|
jpeg_destroy_compress(&cinfo);
|
|||
|
fclose(file);
|
|||
|
file = NULL;
|
|||
|
return HGBASE_ERR_OK;
|
|||
|
}
|
|||
|
|
|||
|
HGResult HGAPI HGImgFmt_SaveJpegImageToBuffer(HGImage image, const HGJpegSaveInfo* info, HGUInt quality, HGBuffer* buffer)
|
|||
|
{
|
|||
|
if (NULL == image || quality > 100 || NULL == buffer)
|
|||
|
{
|
|||
|
return HGBASE_ERR_INVALIDARG;
|
|||
|
}
|
|||
|
|
|||
|
if (NULL != info)
|
|||
|
{
|
|||
|
// 判断info参数的合法性
|
|||
|
}
|
|||
|
|
|||
|
HGImageInfo imgInfo;
|
|||
|
HGBase_GetImageInfo(image, &imgInfo);
|
|||
|
uint32_t type = imgInfo.type;
|
|||
|
if (HGBASE_IMGTYPE_GRAY != type && HGBASE_IMGTYPE_RGB != type)
|
|||
|
{
|
|||
|
return HGBASE_ERR_INVALIDDATA;
|
|||
|
}
|
|||
|
|
|||
|
unsigned char* outbuffer = NULL;
|
|||
|
size_t outSize = 0;
|
|||
|
|
|||
|
struct jpeg_compress_struct cinfo;
|
|||
|
struct my_error_mgr jerr;
|
|||
|
cinfo.err = jpeg_std_error(&jerr.pub);
|
|||
|
jerr.pub.error_exit = my_error_exit;
|
|||
|
|
|||
|
int jmpResult = setjmp(jerr.setjmp_buffer);
|
|||
|
if (0 != jmpResult)
|
|||
|
{
|
|||
|
jpeg_destroy_compress(&cinfo);
|
|||
|
free(outbuffer);
|
|||
|
outbuffer = NULL;
|
|||
|
outSize = 0;
|
|||
|
return (HGResult)jmpResult;
|
|||
|
}
|
|||
|
|
|||
|
jpeg_create_compress(&cinfo);
|
|||
|
jpeg_mem_dest(&cinfo, &outbuffer, &outSize);
|
|||
|
|
|||
|
uint32_t width = imgInfo.width;
|
|||
|
uint32_t height = imgInfo.height;
|
|||
|
uint32_t widthStep = imgInfo.widthStep;
|
|||
|
uint8_t* data;
|
|||
|
HGBase_GetImageData(image, &data);
|
|||
|
|
|||
|
cinfo.image_width = width;
|
|||
|
cinfo.image_height = height;
|
|||
|
cinfo.input_components = (HGBASE_IMGTYPE_GRAY != type) ? 3 : 1;
|
|||
|
cinfo.in_color_space = (HGBASE_IMGTYPE_GRAY != type) ? JCS_RGB : JCS_GRAYSCALE;
|
|||
|
jpeg_set_defaults(&cinfo);
|
|||
|
|
|||
|
HGUInt xDpi, yDpi;
|
|||
|
HGBase_GetImageDpi(image, &xDpi, &yDpi);
|
|||
|
|
|||
|
cinfo.density_unit = 1;
|
|||
|
cinfo.X_density = xDpi;
|
|||
|
cinfo.Y_density = yDpi;
|
|||
|
|
|||
|
if (NULL != info)
|
|||
|
{
|
|||
|
cinfo.density_unit = info->densityUnit;
|
|||
|
cinfo.X_density = info->xDensity;
|
|||
|
cinfo.Y_density = info->yDensity;
|
|||
|
}
|
|||
|
|
|||
|
if (0 == quality)
|
|||
|
quality = 80;
|
|||
|
jpeg_set_quality(&cinfo, (int)quality, TRUE);
|
|||
|
jpeg_start_compress(&cinfo, TRUE);
|
|||
|
|
|||
|
uint8_t* p = data;
|
|||
|
HGSize step = (HGSize)imgInfo.widthStep;
|
|||
|
if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin)
|
|||
|
{
|
|||
|
p = data + (HGUSize)(imgInfo.height - 1) * (HGUSize)imgInfo.widthStep;
|
|||
|
step = -(HGSize)imgInfo.widthStep;
|
|||
|
}
|
|||
|
|
|||
|
while (cinfo.next_scanline < cinfo.image_height)
|
|||
|
{
|
|||
|
uint8_t* pEx = p + (HGSize)cinfo.next_scanline * (HGSize)step;
|
|||
|
jpeg_write_scanlines(&cinfo, &pEx, 1);
|
|||
|
}
|
|||
|
|
|||
|
jpeg_finish_compress(&cinfo);
|
|||
|
jpeg_destroy_compress(&cinfo);
|
|||
|
|
|||
|
HGResult ret = HGBase_CreateBuffer(outSize, buffer);
|
|||
|
if (HGBASE_ERR_OK == ret)
|
|||
|
{
|
|||
|
HGByte* bufferData = NULL;
|
|||
|
HGBase_GetBufferData(*buffer, &bufferData);
|
|||
|
memcpy(bufferData, outbuffer, outSize);
|
|||
|
}
|
|||
|
|
|||
|
// 只有libjpeg为静态库的时候,才能用free
|
|||
|
// 否则应该使用jpeg_free_large(NULL, outbuffer, 0);
|
|||
|
jpeg_free_large(NULL, outbuffer, 0);
|
|||
|
return ret;
|
|||
|
}
|