code_app/modules/imgfmt/HGJpeg.cpp

539 lines
13 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "HGJpeg.h"
#include "../base/HGInc.h"
#include "../base/HGInfo.h"
extern "C"
{
#include "jpeglib.h"
#include "jmemsys.h"
};
struct my_error_mgr
{
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
};
METHODDEF(void) my_error_exit(j_common_ptr cinfo)
{
my_error_mgr* myerr = (my_error_mgr*)cinfo->err;
(*cinfo->err->output_message)(cinfo);
longjmp(myerr->setjmp_buffer, (int)HGIMGFMT_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);
if (HGBASE_ERR_OK != ret)
{
return ret;
}
*isJpeg = HGTRUE;
return ret;
}
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)
{
return HGBASE_ERR_INVALIDARG;
}
if (0 != imgOrigin && HGBASE_IMGORIGIN_TOP != imgOrigin && HGBASE_IMGORIGIN_BOTTOM != imgOrigin)
{
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;
}
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;
jpeg_start_decompress(&cinfo);
HGResult ret = HGBase_CreateImage(cinfo.output_width, cinfo.output_height,
HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2);
if (HGBASE_ERR_OK != ret)
{
longjmp(jerr.setjmp_buffer, (int)ret);
}
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);
}
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;
jpeg_read_scanlines(&cinfo, &pEx, 1);
}
jpeg_finish_decompress(&cinfo);
ret = HGBase_CloneImage(image2, imgType, imgOrigin, image);
if (HGBASE_ERR_OK != ret)
{
longjmp(jerr.setjmp_buffer, (int)ret);
}
}
HGBase_DestroyImage(image2);
image2 = NULL;
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)
{
return HGBASE_ERR_INVALIDARG;
}
if (0 != imgOrigin && 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)
imgType = HGBASE_IMGTYPE_RGB;
else
imgType = HGBASE_IMGTYPE_GRAY;
}
if (0 == imgOrigin)
{
imgOrigin = HGBASE_IMGORIGIN_TOP;
}
cinfo.out_color_space = JCS_RGB;
jpeg_start_decompress(&cinfo);
HGResult ret = HGBase_CreateImage(cinfo.output_width, cinfo.output_height,
HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2);
if (HGBASE_ERR_OK != ret)
{
longjmp(jerr.setjmp_buffer, (int)ret);
}
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);
}
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;
jpeg_read_scanlines(&cinfo, &pEx, 1);
}
jpeg_finish_decompress(&cinfo);
ret = HGBase_CloneImage(image2, imgType, imgOrigin, image);
if (HGBASE_ERR_OK != ret)
{
longjmp(jerr.setjmp_buffer, (int)ret);
}
}
HGBase_DestroyImage(image2);
image2 = NULL;
jpeg_destroy_decompress(&cinfo);
return HGBASE_ERR_OK;
}
HGResult HGAPI HGImgFmt_SaveJpegImage(HGImage image, const HGJpegSaveInfo* info, const HGChar* fileName)
{
if (NULL == image || NULL == fileName)
{
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);
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);
int jmpResult = setjmp(jerr.setjmp_buffer);
if (0 != jmpResult)
{
HGBase_SetImageROI(image, &roi);
HGBase_DestroyImage(image2);
image2 = NULL;
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)
{
HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, HGBASE_IMGORIGIN_TOP, &image2);
if (HGBASE_ERR_OK != ret)
longjmp(jerr.setjmp_buffer, (int)ret);
}
else
{
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);
uint32_t width = imgInfo.width;
uint32_t height = imgInfo.height;
uint32_t type = imgInfo.type;
uint32_t widthStep = imgInfo.widthStep;
uint8_t* data;
HGBase_GetImageData(image2, &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);
int quality;
if (NULL != info)
{
quality = info->quality;
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;
}
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;
jpeg_write_scanlines(&cinfo, &pEx, 1);
}
jpeg_finish_compress(&cinfo);
HGBase_SetImageROI(image, &roi);
HGBase_DestroyImage(image2);
image2 = NULL;
jpeg_destroy_compress(&cinfo);
fclose(file);
file = NULL;
return HGBASE_ERR_OK;
}
HGResult HGAPI HGImgFmt_SaveJpegImageToBuffer(HGImage image, const HGJpegSaveInfo* info, HGBuffer* buffer)
{
if (NULL == image || NULL == buffer)
{
return HGBASE_ERR_INVALIDARG;
}
if (NULL != info)
{
// 判断info参数的合法性
}
unsigned char* outbuffer = NULL;
unsigned long 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;
HGImage image2 = NULL;
HGImageRoi roi;
HGBase_GetImageROI(image, &roi);
int jmpResult = setjmp(jerr.setjmp_buffer);
if (0 != jmpResult)
{
HGBase_SetImageROI(image, &roi);
HGBase_DestroyImage(image2);
image2 = NULL;
jpeg_destroy_compress(&cinfo);
// 只有libjpeg为静态库的时候才能用free
// 否则应该使用jpeg_free_large(NULL, outbuffer, 0);
jpeg_free_large(NULL, outbuffer, 0);
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)
{
HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, HGBASE_IMGORIGIN_TOP, &image2);
if (HGBASE_ERR_OK != ret)
longjmp(jerr.setjmp_buffer, (int)ret);
}
else
{
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);
uint32_t width = imgInfo.width;
uint32_t height = imgInfo.height;
uint32_t type = imgInfo.type;
uint32_t widthStep = imgInfo.widthStep;
uint8_t* data;
HGBase_GetImageData(image2, &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);
int quality;
if (NULL != info)
{
quality = info->quality;
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;
}
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;
jpeg_write_scanlines(&cinfo, &pEx, 1);
}
jpeg_finish_compress(&cinfo);
HGBase_SetImageROI(image, &roi);
HGBase_DestroyImage(image2);
image2 = NULL;
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;
}