#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; }