code_app/imgfmt/HGJpeg.cpp

505 lines
11 KiB
C++
Raw Normal View History

2022-05-03 10:25:52 +00:00
#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)
{
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_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);
}
else if (2 == cinfo.density_unit)
{
uint32_t xDpi = (uint32_t)(cinfo.X_density / 0.393700787402 + 0.5);
uint32_t yDpi = (uint32_t)(cinfo.Y_density / 0.393700787402 + 0.5);
HGBase_SetImageDpi(image2, xDpi, yDpi);
}
2022-05-03 10:25:52 +00:00
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);
}
else if (2 == cinfo.density_unit)
{
uint32_t xDpi = (uint32_t)(cinfo.X_density / 0.393700787402 + 0.5);
uint32_t yDpi = (uint32_t)(cinfo.Y_density / 0.393700787402 + 0.5);
HGBase_SetImageDpi(image2, xDpi, yDpi);
}
2022-05-03 10:25:52 +00:00
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, const HGChar* fileName)
2022-05-03 10:25:52 +00:00
{
if (NULL == image || NULL == fileName)
2022-05-03 10:25:52 +00:00
{
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);
int quality = 80;
2022-05-03 10:25:52 +00:00
cinfo.density_unit = 1;
cinfo.X_density = xDpi;
cinfo.Y_density = yDpi;
if (NULL != info)
{
quality = info->quality;
2022-05-03 10:25:52 +00:00
cinfo.density_unit = info->densityUnit;
cinfo.X_density = info->xDensity;
cinfo.Y_density = info->yDensity;
}
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, HGBuffer* buffer)
2022-05-03 10:25:52 +00:00
{
if (NULL == image || NULL == buffer)
2022-05-03 10:25:52 +00:00
{
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);
int quality = 80;
2022-05-03 10:25:52 +00:00
cinfo.density_unit = 1;
cinfo.X_density = xDpi;
cinfo.Y_density = yDpi;
if (NULL != info)
{
quality = info->quality;
2022-05-03 10:25:52 +00:00
cinfo.density_unit = info->densityUnit;
cinfo.X_density = info->xDensity;
cinfo.Y_density = info->yDensity;
}
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;
}