#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_GRAY != imgType && HGBASE_IMGTYPE_RGB != imgType && HGBASE_IMGTYPE_RGBA != imgType && HGBASE_IMGTYPE_BGR != imgType && HGBASE_IMGTYPE_BGRA != 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; } HGImage image2 = NULL; uint8_t* buffer = NULL; uint8_t** rowPointers = NULL; int jmpResult = setjmp(png_jmpbuf(png_ptr)); if (0 != jmpResult) { free(rowPointers); rowPointers = NULL; free(buffer); buffer = NULL; HGBase_DestroyImage(image2); image2 = 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) { 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; } else { assert(PNG_COLOR_TYPE_RGB == info_ptr->color_type); imgType = HGBASE_IMGTYPE_RGB; } } if (HGBASE_ERR_OK != HGBase_CreateImage(info_ptr->width, info_ptr->height, imgType, imgOrigin, &image2)) { longjmp(png_jmpbuf(png_ptr), (int)HGBASE_ERR_FAIL); } if (1 == 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); HGByte* dest = data; HGSize destStep = (HGSize)imgInfo.widthStep; if (HGBASE_IMGORIGIN_BOTTOM == imgOrigin) { dest = data + (HGUSize)(imgInfo.height - 1) * (HGUSize)imgInfo.widthStep; destStep = -(HGSize)imgInfo.widthStep; } if (HGBASE_IMGTYPE_GRAY == imgType) { 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* pDestEx = dest + (HGSize)i * (HGSize)destStep; memcpy(pDestEx, pEx, info_ptr->width); } } 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 = dest + (HGSize)i * (HGSize)destStep; while (pEx < pExEnd) { uint8_t value = (pEx[0] * 76 + pEx[1] * 150 + pEx[2] * 30) >> 8; *pDestEx = value; pEx += 3; ++pDestEx; } } } 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 = dest + (HGSize)i * (HGSize)destStep; while (pEx < pExEnd) { *pDestEx = *pEx; pEx += 2; ++pDestEx; } } } 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* pExEnd = pEx + info_ptr->width * 4; uint8_t* pDestEx = dest + (HGSize)i * (HGSize)destStep; while (pEx < pExEnd) { uint8_t value = (pEx[0] * 76 + pEx[1] * 150 + pEx[2] * 30) >> 8; *pDestEx = value; pEx += 4; ++pDestEx; } } } } else if (HGBASE_IMGTYPE_RGB == imgType) { 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 = dest + (HGSize)i * (HGSize)destStep; while (pEx < pExEnd) { pDestEx[0] = pDestEx[1] = pDestEx[2] = *pEx; ++pEx; pDestEx += 3; } } } 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* pDestEx = dest + (HGSize)i * (HGSize)destStep; memcpy(pDestEx, pEx, info_ptr->width * 3); } } 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 = dest + (HGSize)i * (HGSize)destStep; while (pEx < pExEnd) { pDestEx[0] = pDestEx[1] = pDestEx[2] = *pEx; pEx += 2; pDestEx += 3; } } } 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* pExEnd = pEx + info_ptr->width * 4; uint8_t* pDestEx = dest + (HGSize)i * (HGSize)destStep; while (pEx < pExEnd) { pDestEx[0] = pEx[0]; pDestEx[1] = pEx[1]; pDestEx[2] = pEx[2]; pEx += 4; pDestEx += 3; } } } } else if (HGBASE_IMGTYPE_BGR == imgType) { 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 = dest + (HGSize)i * (HGSize)destStep; while (pEx < pExEnd) { pDestEx[0] = pDestEx[1] = pDestEx[2] = *pEx; ++pEx; pDestEx += 3; } } } 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 = dest + (HGSize)i * (HGSize)destStep; while (pEx < pExEnd) { pDestEx[0] = pEx[2]; pDestEx[1] = pEx[1]; pDestEx[2] = pEx[0]; pEx += 3; pDestEx += 3; } } } 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 = dest + (HGSize)i * (HGSize)destStep; while (pEx < pExEnd) { pDestEx[0] = pDestEx[1] = pDestEx[2] = *pEx; pEx += 2; pDestEx += 3; } } } 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* pExEnd = pEx + info_ptr->width * 4; uint8_t* pDestEx = dest + (HGSize)i * (HGSize)destStep; while (pEx < pExEnd) { pDestEx[0] = pEx[2]; pDestEx[1] = pEx[1]; pDestEx[2] = pEx[0]; pEx += 4; pDestEx += 3; } } } } else if (HGBASE_IMGTYPE_BGRA == imgType) { 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 = dest + (HGSize)i * (HGSize)destStep; 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 = dest + (HGSize)i * (HGSize)destStep; while (pEx < pExEnd) { uint8_t r = pEx[0]; uint8_t g = pEx[1]; uint8_t b = pEx[2]; *((uint32_t*)pDestEx) = (b & 0x000000FF) | ((g << 8) & 0x0000FF00) | ((r << 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 = dest + (HGSize)i * (HGSize)destStep; 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* pExEnd = pEx + info_ptr->width * 4; uint8_t* pDestEx = dest + (HGSize)i * (HGSize)destStep; while (pEx < pExEnd) { pDestEx[0] = pEx[2]; pDestEx[1] = pEx[1]; pDestEx[2] = pEx[0]; pDestEx[3] = pEx[3]; pEx += 4; pDestEx += 4; } } } } else { assert(HGBASE_IMGTYPE_RGBA == imgType); 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 = dest + (HGSize)i * (HGSize)destStep; 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 = dest + (HGSize)i * (HGSize)destStep; 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 = dest + (HGSize)i * (HGSize)destStep; 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 = dest + (HGSize)i * (HGSize)destStep; memcpy(pDestEx, pEx, info_ptr->width * 4); } } } free(rowPointers); rowPointers = NULL; free(buffer); buffer = NULL; *image = image2; } 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) { // 判断合法性 } HGImageInfo imgInfo; HGBase_GetImageInfo(image, &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; if (HGBASE_IMGTYPE_GRAY != type && HGBASE_IMGTYPE_RGB != type && HGBASE_IMGTYPE_RGBA != type) { return HGBASE_ERR_INVALIDARG; } 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; int jmpResult = setjmp(png_jmpbuf(png_ptr)); if (0 != jmpResult) { 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); uint8_t* data; HGBase_GetImageData(image, &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); HGUInt xDpi, yDpi; HGBase_GetImageDpi(image, &xDpi, &yDpi); info_ptr->phys_unit_type = 1; 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; 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; } 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); } HGByte* p = data; HGSize step = (HGSize)widthStep; if (HGBASE_IMGORIGIN_BOTTOM == origin) { p = data + (HGUSize)(height - 1) * (HGUSize)widthStep; step = -(HGSize)widthStep; } //#pragma omp parallel for for (int32_t i = 0; i < (int32_t)height; ++i) { rowPointers[i] = p + (HGSize)i * (HGSize)step; } png_write_image(png_ptr, rowPointers); png_write_end(png_ptr, info_ptr); free(rowPointers); rowPointers = NULL; png_destroy_write_struct(&png_ptr, &info_ptr); fclose(file); file = NULL; return HGBASE_ERR_OK; }