#include "HGPnm.h" #include "../base/HGInc.h" #include HGResult HGAPI HGImgFmt_CheckPnmFile(const HGChar* fileName, HGBool* isPnm) { if (NULL == fileName || NULL == isPnm) { return HGBASE_ERR_INVALIDARG; } HGPnmLoadInfo info; HGResult ret = HGImgFmt_LoadPnmImage(fileName, &info, 0, 0, NULL); *isPnm = (HGBASE_ERR_OK == ret ? HGTRUE : HGFALSE); return HGBASE_ERR_OK; } static HGResult BnmLoadBinaryInfo(FILE* file, HGChar colorType, HGUInt *width, HGUInt *height, HGUInt *maxColor) { assert(NULL != file && NULL != width && NULL != height && NULL != maxColor); bool getWidth = false; bool getHeight = false; bool getMaxColor = false; std::vector buf; while (1) { HGByte c = 0; if (1 != fread(&c, 1, 1, file)) { return HGBASE_ERR_INVALIDDATA; } if (c == '#' || c == '\n' || c == '\r' || c == '\t' || c == ' ') { if (!buf.empty()) { buf.push_back(0); if (!getWidth) { *width = atoi(&buf[0]); if (*width == 0) return HGBASE_ERR_INVALIDDATA; getWidth = true; } else if (!getHeight) { *height = atoi(&buf[0]); if (*height == 0) return HGBASE_ERR_INVALIDDATA; getHeight = true; } else if (!getMaxColor) { *maxColor = atoi(&buf[0]); if (*maxColor == 0) return HGBASE_ERR_INVALIDDATA; getMaxColor = true; } buf.clear(); } if (c == '#') { while (c != '\n') { if (1 != fread(&c, 1, 1, file)) { return HGBASE_ERR_INVALIDDATA; } } } } else if (c >= '0' && c <= '9') { buf.push_back(c); } else { return HGBASE_ERR_INVALIDDATA; } if ('5' == colorType || '6' == colorType) { if (getMaxColor) { break; } } else { if (getHeight) { break; } } } return HGBASE_ERR_OK; } static HGResult BnmLoadBinaryImage(FILE* file, HGChar colorType, HGPnmLoadInfo* info, HGUInt imgType, HGUInt imgOrigin, HGImage* image) { HGUInt width, height, maxColor; HGResult ret = BnmLoadBinaryInfo(file , colorType, &width, &height, &maxColor); if (HGBASE_ERR_OK != ret) { return ret; } if (NULL != info) { info->width = width; info->height = height; if ('4' == colorType) info->type = HGIMGFMT_PNMTYPE_BINARY_BINARY; else if('5' == colorType) info->type = HGIMGFMT_PNMTYPE_GRAY_BINARY; else info->type = HGIMGFMT_PNMTYPE_RGB_BINARY; } if (NULL != image) { if (imgType == 0) { if ('4' == colorType) imgType = HGBASE_IMGTYPE_BINARY; else if ('5' == colorType) imgType = HGBASE_IMGTYPE_GRAY; else imgType = HGBASE_IMGTYPE_RGB; } if (imgOrigin == 0) { imgOrigin = HGBASE_IMGORIGIN_TOP; } HGImage image2 = NULL; if (colorType == '4') ret = HGBase_CreateImage(width, height, HGBASE_IMGTYPE_BINARY, HGBASE_IMGORIGIN_TOP, &image2); else if (colorType == '5') ret = HGBase_CreateImage(width, height, HGBASE_IMGTYPE_GRAY, HGBASE_IMGORIGIN_TOP, &image2); else ret = HGBase_CreateImage(width, height, HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2); if (HGBASE_ERR_OK != ret) { return ret; } uint8_t* data; HGBase_GetImageData(image2, &data); HGImageInfo imgInfo; HGBase_GetImageInfo(image2, &imgInfo); if ('4' == colorType) { for (HGUInt i = 0; i < height; ++i) { HGUInt lineSize = ((width + 7) & ~7) >> 3; if (lineSize != fread(data + i * imgInfo.widthStep, 1, lineSize, file)) { HGBase_DestroyImage(image2); return HGBASE_ERR_INVALIDDATA; } } if (HGBASE_IMGTYPE_BINARY == imgType && HGBASE_IMGORIGIN_TOP == imgOrigin) { *image = image2; } else { ret = HGBase_CloneImage(image2, imgType, imgOrigin, image); HGBase_DestroyImage(image2); if (HGBASE_ERR_OK != ret) { return ret; } } } else if ('5' == colorType) { for (HGUInt i = 0; i < height; ++i) { if (width != fread(data + i * imgInfo.widthStep, 1, width, file)) { HGBase_DestroyImage(image2); return HGBASE_ERR_INVALIDDATA; } } if (HGBASE_IMGTYPE_GRAY == imgType && HGBASE_IMGORIGIN_TOP == imgOrigin) { *image = image2; } else { ret = HGBase_CloneImage(image2, imgType, imgOrigin, image); HGBase_DestroyImage(image2); if (HGBASE_ERR_OK != ret) { return ret; } } } else { for (HGUInt i = 0; i < height; ++i) { if (width * 3 != fread(data + i * imgInfo.widthStep, 1, width * 3, file)) { HGBase_DestroyImage(image2); return HGBASE_ERR_INVALIDDATA; } } if (HGBASE_IMGTYPE_RGB == imgType && HGBASE_IMGORIGIN_TOP == imgOrigin) { *image = image2; } else { ret = HGBase_CloneImage(image2, imgType, imgOrigin, image); HGBase_DestroyImage(image2); if (HGBASE_ERR_OK != ret) { return ret; } } } if ('4' == colorType) { HGBase_ReverseImage(image2, image2); } } return HGBASE_ERR_OK; } HGResult HGAPI HGImgFmt_LoadPnmImage(const HGChar* fileName, HGPnmLoadInfo* 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; } HGByte magicKey[2] = {0}; if (2 != fread(magicKey, 1, 2, file)) { return HGBASE_ERR_INVALIDDATA; } HGResult ret = HGBASE_ERR_INVALIDDATA; if (magicKey[0] == 'P' && (magicKey[1] == '4' || magicKey[1] == '5' || magicKey[1] == '6')) { HGChar colorType = magicKey[1]; ret = BnmLoadBinaryImage(file, colorType, info, imgType, imgOrigin, image); } fclose(file); return ret; } static HGResult BnmSaveImage(HGImage image, const HGChar* fileName, HGUInt type) { HGImageInfo imgInfo; HGBase_GetImageInfo(image, &imgInfo); FILE* file = fopen(fileName, "wb"); if (NULL == file) { return HGBASE_ERR_ACCESSDENIED; } HGByte* data = NULL; HGBase_GetImageData(image, &data); char magicKey[4] = {0}; if (HGIMGFMT_PNMTYPE_BINARY_BINARY == type) { strcpy(magicKey, "P4\n"); } else if (HGIMGFMT_PNMTYPE_GRAY_BINARY == type) { strcpy(magicKey, "P5\n"); } else if (HGIMGFMT_PNMTYPE_RGB_BINARY == type) { strcpy(magicKey, "P6\n"); } fwrite(magicKey, 1, strlen(magicKey), file); char width[20], height[20]; sprintf(width, "%u\n", imgInfo.width); sprintf(height, "%u\n", imgInfo.height); fwrite(width, 1, strlen(width), file); fwrite(height, 1, strlen(height), file); if (HGIMGFMT_PNMTYPE_GRAY_BINARY == type || HGIMGFMT_PNMTYPE_RGB_BINARY == type) { char maxColor[] = "255\n"; fwrite(maxColor, 1, strlen(maxColor), file); } HGByte* p = data; HGInt step = (HGInt)imgInfo.widthStep; if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) { p = data + (imgInfo.height - 1) * imgInfo.widthStep; step = -(HGInt)imgInfo.widthStep; } if (imgInfo.type == HGBASE_IMGTYPE_BINARY) { HGUInt lineSize = ((imgInfo.width + 7) & ~7) >> 3; HGByte* buf = (HGByte*)malloc(lineSize); assert(NULL != buf); for (HGUInt i = 0; i < imgInfo.height; ++i) { uint8_t* pEx = p + (HGSize)i * (HGSize)step; for (HGUInt j = 0; j < lineSize; ++j) { buf[j] = ~pEx[j]; //黑白反色 } fwrite(buf, 1, lineSize, file); } free(buf); } else if (imgInfo.type == HGBASE_IMGTYPE_GRAY) { for (HGUInt i = 0; i < imgInfo.height; ++i) { uint8_t* pEx = p + (HGSize)i * (HGSize)step; fwrite(pEx, 1, imgInfo.width, file); } } else { for (HGUInt i = 0; i < imgInfo.height; ++i) { uint8_t* pEx = p + (HGSize)i * (HGSize)step; fwrite(pEx, 1, imgInfo.width * 3, file); } } fclose(file); return HGBASE_ERR_OK; } HGResult HGAPI HGImgFmt_SavePnmImage(HGImage image, const HGPnmSaveInfo* info, const HGChar* fileName) { if (NULL == image || NULL == fileName) { return HGBASE_ERR_INVALIDARG; } if (NULL != info) { if (info->type < HGIMGFMT_PNMTYPE_BINARY_ASCII || info->type > HGIMGFMT_PNMTYPE_RGB_BINARY) { return HGBASE_ERR_INVALIDARG; } } HGImageInfo imgInfo; HGBase_GetImageInfo(image, &imgInfo); if (imgInfo.type == HGBASE_IMGTYPE_BGR || imgInfo.type == HGBASE_IMGTYPE_RGBA || imgInfo.type == HGBASE_IMGTYPE_BGRA) { HGUInt imgType = HGBASE_IMGTYPE_RGB; HGUInt pnmType = HGIMGFMT_PNMTYPE_RGB_BINARY; if (NULL != info) { pnmType = info->type; if (info->type == HGIMGFMT_PNMTYPE_BINARY_ASCII || info->type == HGIMGFMT_PNMTYPE_BINARY_BINARY) imgType = HGBASE_IMGTYPE_BINARY; else if (info->type == HGIMGFMT_PNMTYPE_GRAY_ASCII || info->type == HGIMGFMT_PNMTYPE_GRAY_BINARY) imgType = HGBASE_IMGTYPE_GRAY; } HGImage image2 = NULL; HGResult ret = HGBase_CloneImage(image, imgType, HGBASE_IMGORIGIN_TOP, &image2); if (ret != HGBASE_ERR_OK) { return ret; } ret = BnmSaveImage(image2, fileName, pnmType); HGBase_DestroyImage(image2); return ret; } HGImage image2 = NULL; HGUInt pnmType = HGIMGFMT_PNMTYPE_RGB_BINARY; if (HGBASE_IMGTYPE_GRAY == imgInfo.type) pnmType = HGIMGFMT_PNMTYPE_GRAY_BINARY; else if (HGBASE_IMGTYPE_BINARY == imgInfo.type) pnmType = HGIMGFMT_PNMTYPE_BINARY_BINARY; if (NULL != info) { HGUInt imgType = imgInfo.type; pnmType = info->type; if (info->type == HGIMGFMT_PNMTYPE_BINARY_ASCII || info->type == HGIMGFMT_PNMTYPE_BINARY_BINARY) imgType = HGBASE_IMGTYPE_BINARY; else if (info->type == HGIMGFMT_PNMTYPE_GRAY_ASCII || info->type == HGIMGFMT_PNMTYPE_GRAY_BINARY) imgType = HGBASE_IMGTYPE_GRAY; else if (info->type == HGIMGFMT_PNMTYPE_RGB_ASCII || info->type == HGIMGFMT_PNMTYPE_RGB_BINARY) imgType = HGBASE_IMGTYPE_RGB; if (imgInfo.type != imgType) { HGResult ret = HGBase_CloneImage(image, imgType, HGBASE_IMGORIGIN_TOP, &image2); if (ret != HGBASE_ERR_OK) { return ret; } } } if (NULL != image2) { HGResult ret = BnmSaveImage(image2, fileName, pnmType); HGBase_DestroyImage(image2); return ret; } return BnmSaveImage(image, fileName, pnmType); }