code_app/modules/imgfmt/HGJpeg.cpp

516 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"
};
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)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_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;
}
}
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);
if (HGBASE_ERR_OK != HGBase_CreateImage(cinfo.output_width, cinfo.output_height,
HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &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);
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);
if (HGBASE_ERR_OK != HGBase_CloneImage(image2, imgType, imgOrigin, image))
{
longjmp(jerr.setjmp_buffer, (int)HGBASE_ERR_FAIL);
}
}
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);
if (HGBASE_ERR_OK != HGBase_CreateImage(cinfo.output_width, cinfo.output_height,
HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &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);
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);
if (HGBASE_ERR_OK != HGBase_CloneImage(image2, imgType, imgOrigin, image))
{
longjmp(jerr.setjmp_buffer, (int)HGBASE_ERR_FAIL);
}
}
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)
{
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)
{
if (HGBASE_ERR_OK != HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, HGBASE_IMGORIGIN_TOP, &image2))
longjmp(jerr.setjmp_buffer, (int)HGBASE_ERR_FAIL);
}
else
{
if (HGBASE_ERR_OK != HGBase_CloneImage(image, HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2))
longjmp(jerr.setjmp_buffer, (int)HGBASE_ERR_FAIL);
}
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;
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;
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)
{
if (HGBASE_ERR_OK != HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, HGBASE_IMGORIGIN_TOP, &image2))
longjmp(jerr.setjmp_buffer, (int)HGBASE_ERR_FAIL);
}
else
{
if (HGBASE_ERR_OK != HGBase_CloneImage(image, HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2))
longjmp(jerr.setjmp_buffer, (int)HGBASE_ERR_FAIL);
}
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;
}