#include "HGPng.h" #include "../base/HGInc.h" #include "png.h" #include "pngstruct.h" #include "pnginfo.h" #include "pngpriv.h" HGResult HGAPI HGImgFmt_CheckPngFile(const HGChar* fileName, HGBool* isPng) { if (NULL == fileName || NULL == isPng) { return HGBASE_ERR_INVALIDARG; } HGPngLoadInfo info; HGResult ret = HGImgFmt_LoadPngImage(fileName, &info, 0, 0, NULL); *isPng = (HGBASE_ERR_OK == ret ? HGTRUE : HGFALSE); return HGBASE_ERR_OK; } HGResult HGAPI HGImgFmt_LoadPngImage(const HGChar* fileName, HGPngLoadInfo* 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 (HGBASE_IMGORIGIN_TOP != imgOrigin && HGBASE_IMGORIGIN_BOTTOM != imgOrigin) { return HGBASE_ERR_INVALIDARG; } } FILE* file = fopen(fileName, "rb"); if (NULL == file) { return HGBASE_ERR_ACCESSDENIED; } png_byte buf[8] = { 0 }; if (fread(buf, 1, 8, file) != 8) { fclose(file); file = NULL; return HGBASE_ERR_FAIL; } if (0 != png_sig_cmp(buf, 0, 8)) { fclose(file); file = NULL; return HGBASE_ERR_FAIL; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (NULL == png_ptr) { fclose(file); file = NULL; return HGBASE_ERR_FAIL; } png_infop info_ptr = png_create_info_struct(png_ptr); if (NULL == info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(file); file = NULL; return HGBASE_ERR_FAIL; } uint8_t* buffer = NULL; uint8_t** rowPointers = NULL; HGImage image2 = NULL; int jmpResult = setjmp(png_jmpbuf(png_ptr)); if (0 != jmpResult) { HGBase_DestroyImage(image2); image2 = NULL; free(rowPointers); rowPointers = NULL; free(buffer); buffer = NULL; png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(file); file = NULL; return (HGResult)jmpResult; } #if defined(HG_CMP_MSC) _fseeki64(file, 0, SEEK_SET); #else fseeko64(file, 0, SEEK_SET); #endif png_init_io(png_ptr, file); png_read_info(png_ptr, info_ptr); if (NULL != info) { info->width = info_ptr->width; info->height = info_ptr->height; info->bitDepth = info_ptr->bit_depth; info->colorType = info_ptr->color_type; info->channels = info_ptr->channels; info->filterType = info_ptr->filter_type; info->InterlaceType = info_ptr->interlace_type; info->compressionType = info_ptr->compression_type; info->pixelDepth = info_ptr->pixel_depth; info->physUnitType = info_ptr->phys_unit_type; info->xPixelsPerUnit = info_ptr->x_pixels_per_unit; info->yPixelsPerUnit = info_ptr->y_pixels_per_unit; } if (NULL != image) { png_set_scale_16(png_ptr); png_set_expand(png_ptr); png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); buffer = (uint8_t*)malloc((uintptr_t)info_ptr->rowbytes * (uintptr_t)info_ptr->height); if (NULL == buffer) { longjmp(png_jmpbuf(png_ptr), (int)HGBASE_ERR_FAIL); } rowPointers = (uint8_t**)malloc(info_ptr->height * sizeof(png_bytep)); if (NULL == rowPointers) { longjmp(png_jmpbuf(png_ptr), (int)HGBASE_ERR_FAIL); } //#pragma omp parallel for for (png_int_32 i = 0; i < (png_int_32)info_ptr->height; ++i) { rowPointers[i] = buffer + (uintptr_t)i * (uintptr_t)info_ptr->rowbytes; } png_read_image(png_ptr, rowPointers); png_read_end(png_ptr, info_ptr); if (0 == imgType) { imgType = HGBASE_IMGTYPE_RGB; if (PNG_COLOR_TYPE_GRAY_ALPHA == info_ptr->color_type || PNG_COLOR_TYPE_RGB_ALPHA == info_ptr->color_type) { imgType = HGBASE_IMGTYPE_RGBA; } else if (PNG_COLOR_TYPE_GRAY == info_ptr->color_type) { imgType = HGBASE_IMGTYPE_GRAY; } } if (HGBASE_ERR_OK != HGBase_CreateImage(info_ptr->width, info_ptr->height, HGBASE_IMGTYPE_RGBA, HGBASE_IMGORIGIN_TOP, &image2)) { longjmp(png_jmpbuf(png_ptr), (int)HGBASE_ERR_FAIL); } if (PNG_RESOLUTION_METER == info_ptr->phys_unit_type) { uint32_t xDpi = (uint32_t)((double)info_ptr->x_pixels_per_unit / 39.3700787 + 0.5); uint32_t yDpi = (uint32_t)((double)info_ptr->y_pixels_per_unit / 39.3700787 + 0.5); HGBase_SetImageDpi(image2, xDpi, yDpi); } uint8_t* data; HGBase_GetImageData(image2, &data); HGImageInfo imgInfo; HGBase_GetImageInfo(image2, &imgInfo); if (PNG_COLOR_TYPE_GRAY == info_ptr->color_type) { //#pragma omp parallel for for (png_int_32 i = 0; i < (png_int_32)info_ptr->height; i++) { uint8_t* pEx = rowPointers[i]; uint8_t* pExEnd = pEx + info_ptr->width; uint8_t* pDestEx = data + (HGSize)i * (HGSize)imgInfo.widthStep; while (pEx < pExEnd) { uint8_t v = *pEx; *((uint32_t*)pDestEx) = (v & 0x000000FF) | ((v << 8) & 0x0000FF00) | ((v << 16) & 0x00FF0000) | 0xFF000000; ++pEx; pDestEx += 4; } } } else if (PNG_COLOR_TYPE_RGB == info_ptr->color_type) { //#pragma omp parallel for for (png_int_32 i = 0; i < (png_int_32)info_ptr->height; i++) { uint8_t* pEx = rowPointers[i]; uint8_t* pExEnd = pEx + info_ptr->width * 3; uint8_t* pDestEx = data + (HGSize)i * (HGSize)imgInfo.widthStep; while (pEx < pExEnd) { uint8_t r = pEx[0]; uint8_t g = pEx[1]; uint8_t b = pEx[2]; *((uint32_t*)pDestEx) = (r & 0x000000FF) | ((g << 8) & 0x0000FF00) | ((b << 16) & 0x00FF0000) | 0xFF000000; pEx += 3; pDestEx += 4; } } } else if (PNG_COLOR_TYPE_GRAY_ALPHA == info_ptr->color_type) { //#pragma omp parallel for for (png_int_32 i = 0; i < (png_int_32)info_ptr->height; i++) { uint8_t* pEx = rowPointers[i]; uint8_t* pExEnd = pEx + info_ptr->width * 2; uint8_t* pDestEx = data + (HGSize)i * (HGSize)imgInfo.widthStep; while (pEx < pExEnd) { uint8_t v = pEx[0]; uint8_t alpha = pEx[1]; *((uint32_t*)pDestEx) = (v & 0x000000FF) | ((v << 8) & 0x0000FF00) | ((v << 16) & 0x00FF0000) | ((alpha << 24) & 0xFF000000); pEx += 2; pDestEx += 4; } } } else { assert(PNG_COLOR_TYPE_RGB_ALPHA == info_ptr->color_type); //#pragma omp parallel for for (png_int_32 i = 0; i < (png_int_32)info_ptr->height; i++) { uint8_t* pEx = rowPointers[i]; uint8_t* pDestEx = data + (HGSize)i * (HGSize)imgInfo.widthStep; memcpy(pDestEx, pEx, info_ptr->width * 4); } } if (HGBASE_ERR_OK != HGBase_CloneImage(image2, imgType, imgOrigin, image)) { longjmp(png_jmpbuf(png_ptr), (int)HGBASE_ERR_FAIL); } } HGBase_DestroyImage(image2); image2 = NULL; free(rowPointers); rowPointers = NULL; free(buffer); buffer = NULL; png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(file); file = NULL; return HGBASE_ERR_OK; } HGResult HGAPI HGImgFmt_SavePngImage(HGImage image, const HGPngSaveInfo* info, const HGChar* fileName) { if (NULL == image || NULL == fileName) { return HGBASE_ERR_INVALIDARG; } if (NULL != info) { // 判断合法性 } FILE* file = fopen(fileName, "wb"); if (NULL == file) { return HGBASE_ERR_ACCESSDENIED; } png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (NULL == png_ptr) { fclose(file); file = NULL; return HGBASE_ERR_FAIL; } png_infop info_ptr = png_create_info_struct(png_ptr); if (NULL == info_ptr) { png_destroy_write_struct(&png_ptr, NULL); fclose(file); file = NULL; return HGBASE_ERR_FAIL; } uint8_t** rowPointers = NULL; HGImage image2 = NULL; HGImageRoi roi; HGBase_GetImageROI(image, &roi); int jmpResult = setjmp(png_jmpbuf(png_ptr)); if (0 != jmpResult) { HGBase_SetImageROI(image, &roi); HGBase_DestroyImage(image2); image2 = NULL; free(rowPointers); rowPointers = NULL; png_destroy_write_struct(&png_ptr, &info_ptr); fclose(file); file = NULL; return (HGResult)jmpResult; } png_init_io(png_ptr, file); HGBase_ResetImageROI(image); HGImageInfo imgInfo; HGBase_GetImageInfo(image, &imgInfo); if (HGBASE_IMGTYPE_BGR == imgInfo.type) { if (HGBASE_ERR_OK != HGBase_CloneImage(image, HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2)) { longjmp(png_jmpbuf(png_ptr), (int)HGBASE_ERR_FAIL); } } else if (HGBASE_IMGTYPE_BGRA == imgInfo.type) { if (HGBASE_ERR_OK != HGBase_CloneImage(image, HGBASE_IMGTYPE_RGBA, HGBASE_IMGORIGIN_TOP, &image2)) { longjmp(png_jmpbuf(png_ptr), (int)HGBASE_ERR_FAIL); } } else if (HGBASE_IMGTYPE_BINARY == imgInfo.type) { if (HGBASE_ERR_OK != HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, HGBASE_IMGORIGIN_TOP, &image2)) { longjmp(png_jmpbuf(png_ptr), (int)HGBASE_ERR_FAIL); } } else { if (HGBASE_ERR_OK != HGBase_CloneImage(image, imgInfo.type, HGBASE_IMGORIGIN_TOP, &image2)) { longjmp(png_jmpbuf(png_ptr), (int)HGBASE_ERR_FAIL); } } HGBase_GetImageInfo(image2, &imgInfo); uint32_t width = imgInfo.width; uint32_t height = imgInfo.height; uint32_t widthStep = imgInfo.widthStep; uint32_t type = imgInfo.type; uint32_t origin = imgInfo.origin; uint8_t* data; HGBase_GetImageData(image2, &data); int color_type = -1; if (HGBASE_IMGTYPE_GRAY == type) color_type = PNG_COLOR_TYPE_GRAY; else if (HGBASE_IMGTYPE_RGB == type) color_type = PNG_COLOR_TYPE_RGB; else if (HGBASE_IMGTYPE_RGBA == type) color_type = PNG_COLOR_TYPE_RGB_ALPHA; assert(-1 != color_type); png_set_IHDR(png_ptr, info_ptr, width, height, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); if (NULL != info) { info_ptr->phys_unit_type = info->physUnitType; info_ptr->x_pixels_per_unit = info->xPixelsPerUnit; info_ptr->y_pixels_per_unit = info->yPixelsPerUnit; info_ptr->valid |= PNG_INFO_pHYs; } else { HGUInt xDpi, yDpi; HGBase_GetImageDpi(image2, &xDpi, &yDpi); info_ptr->phys_unit_type = PNG_RESOLUTION_METER; info_ptr->x_pixels_per_unit = (uint32_t)((double)xDpi * 39.3700787 + 0.5); info_ptr->y_pixels_per_unit = (uint32_t)((double)yDpi * 39.3700787 + 0.5); info_ptr->valid |= PNG_INFO_pHYs; } png_write_info(png_ptr, info_ptr); rowPointers = (uint8_t**)malloc(height * sizeof(png_bytep)); if (NULL == rowPointers) { longjmp(png_jmpbuf(png_ptr), (int)HGBASE_ERR_FAIL); } //#pragma omp parallel for for (int32_t i = 0; i < (int32_t)height; ++i) { rowPointers[i] = data + (HGSize)i * (HGSize)widthStep; } png_write_image(png_ptr, rowPointers); png_write_end(png_ptr, info_ptr); HGBase_SetImageROI(image, &roi); HGBase_DestroyImage(image2); image2 = NULL; free(rowPointers); rowPointers = NULL; png_destroy_write_struct(&png_ptr, &info_ptr); fclose(file); file = NULL; return HGBASE_ERR_OK; }