code_app/modules/imgfmt/HGJpeg.cpp

539 lines
13 KiB
C++
Raw Permalink 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"
};
struct my_error_mgr
2022-05-03 10:25:52 +00:00
{
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
};
2022-05-03 10:25:52 +00:00
METHODDEF(void) my_error_exit(j_common_ptr cinfo)
{
my_error_mgr* myerr = (my_error_mgr*)cinfo->err;
2022-05-03 10:25:52 +00:00
(*cinfo->err->output_message)(cinfo);
2022-11-26 02:42:06 +00:00
longjmp(myerr->setjmp_buffer, (int)HGIMGFMT_ERR_FAIL);
2022-05-03 10:25:52 +00:00
}
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);
2022-11-26 02:42:06 +00:00
if (HGBASE_ERR_OK != ret)
{
return ret;
}
*isJpeg = HGTRUE;
return ret;
2022-05-03 10:25:52 +00:00
}
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_BINARY != imgType && HGBASE_IMGTYPE_GRAY != imgType
&& HGBASE_IMGTYPE_BGR != imgType && HGBASE_IMGTYPE_RGB != imgType
&& HGBASE_IMGTYPE_BGRA != imgType && HGBASE_IMGTYPE_RGBA != imgType)
2022-05-03 10:25:52 +00:00
{
return HGBASE_ERR_INVALIDARG;
}
if (0 != imgOrigin && HGBASE_IMGORIGIN_TOP != imgOrigin && HGBASE_IMGORIGIN_BOTTOM != imgOrigin)
2022-05-03 10:25:52 +00:00
{
return HGBASE_ERR_INVALIDARG;
}
}
#if defined(HG_CMP_MSC)
if (0 != _access(fileName, 0))
#else
if (0 != access(fileName, 0))
#endif
{
return HGBASE_ERR_FILENOTEXIST;
}
2022-05-03 10:25:52 +00:00
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)
imgType = HGBASE_IMGTYPE_RGB;
else
imgType = HGBASE_IMGTYPE_GRAY;
}
if (0 == imgOrigin)
{
imgOrigin = HGBASE_IMGORIGIN_TOP;
}
cinfo.out_color_space = JCS_RGB;
2022-05-03 10:25:52 +00:00
jpeg_start_decompress(&cinfo);
2022-11-26 02:42:06 +00:00
HGResult ret = HGBase_CreateImage(cinfo.output_width, cinfo.output_height,
HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2);
if (HGBASE_ERR_OK != ret)
2022-05-03 10:25:52 +00:00
{
2022-11-26 02:42:06 +00:00
longjmp(jerr.setjmp_buffer, (int)ret);
2022-05-03 10:25:52 +00:00
}
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);
while (cinfo.output_scanline < cinfo.output_height)
{
JSAMPROW pEx = data + (HGSize)cinfo.output_scanline * (HGSize)imgInfo.widthStep;
2022-05-03 10:25:52 +00:00
jpeg_read_scanlines(&cinfo, &pEx, 1);
}
jpeg_finish_decompress(&cinfo);
2022-11-26 02:42:06 +00:00
ret = HGBase_CloneImage(image2, imgType, imgOrigin, image);
if (HGBASE_ERR_OK != ret)
{
2022-11-26 02:42:06 +00:00
longjmp(jerr.setjmp_buffer, (int)ret);
}
2022-05-03 10:25:52 +00:00
}
HGBase_DestroyImage(image2);
image2 = NULL;
2022-05-03 10:25:52 +00:00
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_BINARY != imgType && HGBASE_IMGTYPE_GRAY != imgType
&& HGBASE_IMGTYPE_BGR != imgType && HGBASE_IMGTYPE_RGB != imgType
&& HGBASE_IMGTYPE_BGRA != imgType && HGBASE_IMGTYPE_RGBA != imgType)
2022-05-03 10:25:52 +00:00
{
return HGBASE_ERR_INVALIDARG;
}
if (0 != imgOrigin && HGBASE_IMGORIGIN_TOP != imgOrigin && HGBASE_IMGORIGIN_BOTTOM != imgOrigin)
2022-05-03 10:25:52 +00:00
{
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)
imgType = HGBASE_IMGTYPE_RGB;
else
imgType = HGBASE_IMGTYPE_GRAY;
}
if (0 == imgOrigin)
{
imgOrigin = HGBASE_IMGORIGIN_TOP;
}
cinfo.out_color_space = JCS_RGB;
2022-05-03 10:25:52 +00:00
jpeg_start_decompress(&cinfo);
2022-11-26 02:42:06 +00:00
HGResult ret = HGBase_CreateImage(cinfo.output_width, cinfo.output_height,
HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2);
if (HGBASE_ERR_OK != ret)
2022-05-03 10:25:52 +00:00
{
2022-11-26 02:42:06 +00:00
longjmp(jerr.setjmp_buffer, (int)ret);
2022-05-03 10:25:52 +00:00
}
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);
while (cinfo.output_scanline < cinfo.output_height)
{
JSAMPROW pEx = data + (HGSize)cinfo.output_scanline * (HGSize)imgInfo.widthStep;
2022-05-03 10:25:52 +00:00
jpeg_read_scanlines(&cinfo, &pEx, 1);
}
jpeg_finish_decompress(&cinfo);
2022-11-26 02:42:06 +00:00
ret = HGBase_CloneImage(image2, imgType, imgOrigin, image);
if (HGBASE_ERR_OK != ret)
{
2022-11-26 02:42:06 +00:00
longjmp(jerr.setjmp_buffer, (int)ret);
}
2022-05-03 10:25:52 +00:00
}
HGBase_DestroyImage(image2);
image2 = NULL;
2022-05-03 10:25:52 +00:00
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参数的合法性
}
FILE* file = fopen(fileName, "wb");
if (NULL == file)
{
HGBase_WriteInfo(HGBASE_INFOTYPE_ERROR, "HGImgFmt_SaveJpegImage: fopen fail, %s errno=%d", fileName, errno);
2022-05-03 10:25:52 +00:00
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;
HGImage image2 = NULL;
HGImageRoi roi;
HGBase_GetImageROI(image, &roi);
2022-05-03 10:25:52 +00:00
int jmpResult = setjmp(jerr.setjmp_buffer);
if (0 != jmpResult)
{
HGBase_SetImageROI(image, &roi);
HGBase_DestroyImage(image2);
image2 = NULL;
2022-05-03 10:25:52 +00:00
jpeg_destroy_compress(&cinfo);
fclose(file);
file = NULL;
return (HGResult)jmpResult;
}
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, file);
HGBase_ResetImageROI(image);
HGImageInfo imgInfo;
HGBase_GetImageInfo(image, &imgInfo);
if (HGBASE_IMGTYPE_GRAY == imgInfo.type || HGBASE_IMGTYPE_BINARY == imgInfo.type)
{
2022-11-26 02:42:06 +00:00
HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, HGBASE_IMGORIGIN_TOP, &image2);
if (HGBASE_ERR_OK != ret)
longjmp(jerr.setjmp_buffer, (int)ret);
}
else
{
2022-11-26 02:42:06 +00:00
HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2);
if (HGBASE_ERR_OK != ret)
longjmp(jerr.setjmp_buffer, (int)ret);
}
HGBase_GetImageInfo(image2, &imgInfo);
2022-05-03 10:25:52 +00:00
uint32_t width = imgInfo.width;
uint32_t height = imgInfo.height;
uint32_t type = imgInfo.type;
2022-05-03 10:25:52 +00:00
uint32_t widthStep = imgInfo.widthStep;
uint8_t* data;
HGBase_GetImageData(image2, &data);
2022-05-03 10:25:52 +00:00
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);
int quality;
2022-05-03 10:25:52 +00:00
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;
}
else
{
HGUInt xDpi, yDpi;
HGBase_GetImageDpi(image2, &xDpi, &yDpi);
quality = 80;
cinfo.density_unit = 1;
cinfo.X_density = xDpi;
cinfo.Y_density = yDpi;
}
2022-05-03 10:25:52 +00:00
jpeg_set_quality(&cinfo, (int)quality, TRUE);
jpeg_start_compress(&cinfo, TRUE);
while (cinfo.next_scanline < cinfo.image_height)
{
uint8_t* pEx = data + (HGSize)cinfo.next_scanline * (HGSize)imgInfo.widthStep;
2022-05-03 10:25:52 +00:00
jpeg_write_scanlines(&cinfo, &pEx, 1);
}
jpeg_finish_compress(&cinfo);
HGBase_SetImageROI(image, &roi);
HGBase_DestroyImage(image2);
image2 = NULL;
2022-05-03 10:25:52 +00:00
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参数的合法性
}
unsigned char* outbuffer = NULL;
unsigned long outSize = 0;
2022-05-03 10:25:52 +00:00
struct jpeg_compress_struct cinfo;
struct my_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
HGImage image2 = NULL;
HGImageRoi roi;
HGBase_GetImageROI(image, &roi);
2022-05-03 10:25:52 +00:00
int jmpResult = setjmp(jerr.setjmp_buffer);
if (0 != jmpResult)
{
HGBase_SetImageROI(image, &roi);
HGBase_DestroyImage(image2);
image2 = NULL;
2022-05-03 10:25:52 +00:00
jpeg_destroy_compress(&cinfo);
// 只有libjpeg为静态库的时候才能用free
// 否则应该使用jpeg_free_large(NULL, outbuffer, 0);
jpeg_free_large(NULL, outbuffer, 0);
2022-05-03 10:25:52 +00:00
return (HGResult)jmpResult;
}
jpeg_create_compress(&cinfo);
jpeg_mem_dest(&cinfo, &outbuffer, &outSize);
HGBase_ResetImageROI(image);
HGImageInfo imgInfo;
HGBase_GetImageInfo(image, &imgInfo);
if (HGBASE_IMGTYPE_GRAY == imgInfo.type || HGBASE_IMGTYPE_BINARY == imgInfo.type)
{
2022-11-26 02:42:06 +00:00
HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, HGBASE_IMGORIGIN_TOP, &image2);
if (HGBASE_ERR_OK != ret)
longjmp(jerr.setjmp_buffer, (int)ret);
}
else
{
2022-11-26 02:42:06 +00:00
HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2);
if (HGBASE_ERR_OK != ret)
longjmp(jerr.setjmp_buffer, (int)ret);
}
HGBase_GetImageInfo(image2, &imgInfo);
2022-05-03 10:25:52 +00:00
uint32_t width = imgInfo.width;
uint32_t height = imgInfo.height;
uint32_t type = imgInfo.type;
2022-05-03 10:25:52 +00:00
uint32_t widthStep = imgInfo.widthStep;
uint8_t* data;
HGBase_GetImageData(image2, &data);
2022-05-03 10:25:52 +00:00
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);
int quality;
2022-05-03 10:25:52 +00:00
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;
}
else
{
HGUInt xDpi, yDpi;
HGBase_GetImageDpi(image2, &xDpi, &yDpi);
quality = 80;
cinfo.density_unit = 1;
cinfo.X_density = xDpi;
cinfo.Y_density = yDpi;
}
2022-05-03 10:25:52 +00:00
jpeg_set_quality(&cinfo, (int)quality, TRUE);
jpeg_start_compress(&cinfo, TRUE);
while (cinfo.next_scanline < cinfo.image_height)
{
uint8_t* pEx = data + (HGSize)cinfo.next_scanline * (HGSize)imgInfo.widthStep;
2022-05-03 10:25:52 +00:00
jpeg_write_scanlines(&cinfo, &pEx, 1);
}
jpeg_finish_compress(&cinfo);
HGBase_SetImageROI(image, &roi);
HGBase_DestroyImage(image2);
image2 = NULL;
2022-05-03 10:25:52 +00:00
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;
}