code_app/imgfmt/HGJpeg.cpp

509 lines
12 KiB
C++
Raw 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"
};
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);
}
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);
}
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)
{
if (NULL == image || 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);
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(image, &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);
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)
{
if (NULL == image || 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);
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(image, &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);
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;
}