diff --git a/modules/imgfmt/HGPnm.cpp b/modules/imgfmt/HGPnm.cpp index c0d0ff50..1a6061fc 100644 --- a/modules/imgfmt/HGPnm.cpp +++ b/modules/imgfmt/HGPnm.cpp @@ -1,7 +1,25 @@ -#include "HGPnm.h" +#include "HGPnm.h" #include "../base/HGInc.h" #include +static inline HGByte GetBit(const HGByte* data, HGUInt index) +{ + HGUInt byteIndex = index / 8; + HGUInt bitIndex = index % 8; + return (data[byteIndex] >> (7 - bitIndex)) & 0x01; +} + +static inline void SetBit(HGByte* data, HGUInt index, HGByte value) +{ + assert(0 == value || 1 == value); + HGUInt byteIndex = index / 8; + HGUInt bitIndex = index % 8; + if (1 == value) + data[byteIndex] |= (1 << (7 - bitIndex)); + else + data[byteIndex] &= ~(1 << (7 - bitIndex)); +} + HGResult HGAPI HGImgFmt_CheckPnmFile(const HGChar* fileName, HGBool* isPnm) { if (NULL == fileName || NULL == isPnm) @@ -15,7 +33,7 @@ HGResult HGAPI HGImgFmt_CheckPnmFile(const HGChar* fileName, HGBool* isPnm) return HGBASE_ERR_OK; } -static HGResult BnmLoadBinaryInfo(FILE* file, HGChar colorType, HGUInt *width, HGUInt *height, HGUInt *maxColor) +static HGResult BnmLoadInfo(FILE* file, HGUInt pnmType, HGUInt *width, HGUInt *height, HGUInt *maxColor) { assert(NULL != file && NULL != width && NULL != height && NULL != maxColor); @@ -83,7 +101,7 @@ static HGResult BnmLoadBinaryInfo(FILE* file, HGChar colorType, HGUInt *width, H return HGBASE_ERR_INVALIDDATA; } - if ('5' == colorType || '6' == colorType) + if (pnmType != HGIMGFMT_PNMTYPE_BINARY_ASCII && pnmType != HGIMGFMT_PNMTYPE_BINARY_BINARY) { if (getMaxColor) { @@ -102,37 +120,37 @@ static HGResult BnmLoadBinaryInfo(FILE* file, HGChar colorType, HGUInt *width, H return HGBASE_ERR_OK; } -static HGResult BnmLoadBinaryImage(FILE* file, HGChar colorType, HGPnmLoadInfo* info, HGUInt imgType, HGUInt imgOrigin, HGImage* image) +static HGResult BnmLoadImage(FILE* file, HGUInt pnmType, HGPnmLoadInfo* info, HGUInt imgType, HGUInt imgOrigin, HGImage* image) { HGUInt width, height, maxColor; - HGResult ret = BnmLoadBinaryInfo(file , colorType, &width, &height, &maxColor); + HGResult ret = BnmLoadInfo(file , pnmType, &width, &height, &maxColor); if (HGBASE_ERR_OK != ret) { return ret; } + if (pnmType != HGIMGFMT_PNMTYPE_BINARY_ASCII && pnmType != HGIMGFMT_PNMTYPE_BINARY_BINARY) + { + if (maxColor > 255 || maxColor < 0) + return HGBASE_ERR_INVALIDDATA; + } + 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; + info->type = pnmType; } if (NULL != image) { if (imgType == 0) { - if ('4' == colorType) + if (pnmType == HGIMGFMT_PNMTYPE_BINARY_ASCII || pnmType == HGIMGFMT_PNMTYPE_BINARY_BINARY) imgType = HGBASE_IMGTYPE_BINARY; - else if ('5' == colorType) + else if (pnmType == HGIMGFMT_PNMTYPE_GRAY_ASCII || pnmType == HGIMGFMT_PNMTYPE_GRAY_BINARY) imgType = HGBASE_IMGTYPE_GRAY; - else + else if (pnmType == HGIMGFMT_PNMTYPE_RGB_ASCII || pnmType == HGIMGFMT_PNMTYPE_RGB_BINARY) imgType = HGBASE_IMGTYPE_RGB; } @@ -143,11 +161,11 @@ static HGResult BnmLoadBinaryImage(FILE* file, HGChar colorType, HGPnmLoadInfo* HGImage image2 = NULL; - if (colorType == '4') + if (pnmType == HGIMGFMT_PNMTYPE_BINARY_ASCII || pnmType == HGIMGFMT_PNMTYPE_BINARY_BINARY) ret = HGBase_CreateImage(width, height, HGBASE_IMGTYPE_BINARY, HGBASE_IMGORIGIN_TOP, &image2); - else if (colorType == '5') + else if (pnmType == HGIMGFMT_PNMTYPE_GRAY_ASCII || pnmType == HGIMGFMT_PNMTYPE_GRAY_BINARY) ret = HGBase_CreateImage(width, height, HGBASE_IMGTYPE_GRAY, HGBASE_IMGORIGIN_TOP, &image2); - else + else if (pnmType == HGIMGFMT_PNMTYPE_RGB_ASCII || pnmType == HGIMGFMT_PNMTYPE_RGB_BINARY) ret = HGBase_CreateImage(width, height, HGBASE_IMGTYPE_RGB, HGBASE_IMGORIGIN_TOP, &image2); if (HGBASE_ERR_OK != ret) @@ -155,12 +173,13 @@ static HGResult BnmLoadBinaryImage(FILE* file, HGChar colorType, HGPnmLoadInfo* return ret; } + std::vector buf; uint8_t* data; HGBase_GetImageData(image2, &data); HGImageInfo imgInfo; HGBase_GetImageInfo(image2, &imgInfo); - if ('4' == colorType) + if (pnmType == HGIMGFMT_PNMTYPE_BINARY_BINARY) { for (HGUInt i = 0; i < height; ++i) { @@ -188,7 +207,7 @@ static HGResult BnmLoadBinaryImage(FILE* file, HGChar colorType, HGPnmLoadInfo* } } - else if ('5' == colorType) + else if (pnmType == HGIMGFMT_PNMTYPE_GRAY_BINARY) { for (HGUInt i = 0; i < height; ++i) { @@ -214,7 +233,7 @@ static HGResult BnmLoadBinaryImage(FILE* file, HGChar colorType, HGPnmLoadInfo* } } } - else + else if(pnmType == HGIMGFMT_PNMTYPE_RGB_BINARY) { for (HGUInt i = 0; i < height; ++i) { @@ -240,8 +259,119 @@ static HGResult BnmLoadBinaryImage(FILE* file, HGChar colorType, HGPnmLoadInfo* } } } + else if (pnmType == HGIMGFMT_PNMTYPE_BINARY_ASCII || pnmType == HGIMGFMT_PNMTYPE_GRAY_ASCII || pnmType == HGIMGFMT_PNMTYPE_RGB_ASCII) + { + HGByte* p = data; + HGUInt idx = 0; - if ('4' == colorType) + while (1) + { + HGByte c = 0; + if (1 != fread(&c, 1, 1, file)) + { + if (!buf.empty()) + { + buf.push_back(0); + HGInt pixel = atoi(&buf[0]); + + if (pnmType != HGIMGFMT_PNMTYPE_BINARY_ASCII && pnmType != HGIMGFMT_PNMTYPE_BINARY_BINARY) + { + if (pixel > 255 || pixel < 0) + return HGBASE_ERR_INVALIDDATA; + } + else + { + if (pixel > 1 || pixel < 0) + return HGBASE_ERR_INVALIDDATA; + } + + p[idx] = pixel; + ++idx; + if (idx == width * 3) + { + p += imgInfo.widthStep; + idx = 0; + } + + buf.clear(); + } + + break; + } + + if (c == '#' || c == '\n' || c == '\r' || c == '\t' || c == ' ') + { + if (!buf.empty()) + { + buf.push_back(0); + HGInt pixel = atoi(&buf[0]); + + if (pnmType != HGIMGFMT_PNMTYPE_BINARY_ASCII && pnmType != HGIMGFMT_PNMTYPE_BINARY_BINARY) + { + if (pixel > 255 || pixel < 0) + return HGBASE_ERR_INVALIDDATA; + } + else + { + if (pixel > 1 || pixel < 0) + return HGBASE_ERR_INVALIDDATA; + } + + + p[idx] = pixel; + ++idx; + if (idx == width * 3) + { + p += imgInfo.widthStep; + idx = 0; + } + + 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 (p == data + height * imgInfo.widthStep) + { + break; + } + } + + 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 (pnmType == HGIMGFMT_PNMTYPE_BINARY_ASCII || pnmType == HGIMGFMT_PNMTYPE_BINARY_BINARY) { HGBase_ReverseImage(image2, image2); } @@ -293,11 +423,37 @@ HGResult HGAPI HGImgFmt_LoadPnmImage(const HGChar* fileName, HGPnmLoadInfo* info } HGResult ret = HGBASE_ERR_INVALIDDATA; - if (magicKey[0] == 'P' && (magicKey[1] == '4' || magicKey[1] == '5' || magicKey[1] == '6')) + HGUInt pnmType = 0; + if (magicKey[0] == 'P' && (magicKey[1] == '1')) { - HGChar colorType = magicKey[1]; - ret = BnmLoadBinaryImage(file, colorType, info, imgType, imgOrigin, image); + pnmType = HGIMGFMT_PNMTYPE_BINARY_ASCII; } + else if (magicKey[0] == 'P' && (magicKey[1] == '2')) + { + pnmType = HGIMGFMT_PNMTYPE_GRAY_ASCII; + } + else if (magicKey[0] == 'P' && (magicKey[1] == '3')) + { + pnmType = HGIMGFMT_PNMTYPE_RGB_ASCII; + } + else if (magicKey[0] == 'P' && (magicKey[1] == '4')) + { + pnmType = HGIMGFMT_PNMTYPE_BINARY_BINARY; + } + else if (magicKey[0] == 'P' && (magicKey[1] == '5')) + { + pnmType = HGIMGFMT_PNMTYPE_GRAY_BINARY; + } + else if (magicKey[0] == 'P' && (magicKey[1] == '6')) + { + pnmType = HGIMGFMT_PNMTYPE_RGB_BINARY; + } + else + { + return HGBASE_ERR_INVALIDARG; + } + + ret = BnmLoadImage(file, pnmType, info, imgType, imgOrigin, image); fclose(file); return ret; @@ -318,7 +474,19 @@ static HGResult BnmSaveImage(HGImage image, const HGChar* fileName, HGUInt type) HGBase_GetImageData(image, &data); char magicKey[4] = {0}; - if (HGIMGFMT_PNMTYPE_BINARY_BINARY == type) + if (HGIMGFMT_PNMTYPE_BINARY_ASCII == type) + { + strcpy(magicKey, "P1\n"); + } + else if (HGIMGFMT_PNMTYPE_GRAY_ASCII == type) + { + strcpy(magicKey, "P2\n"); + } + else if (HGIMGFMT_PNMTYPE_RGB_ASCII == type) + { + strcpy(magicKey, "P3\n"); + } + else if (HGIMGFMT_PNMTYPE_BINARY_BINARY == type) { strcpy(magicKey, "P4\n"); } @@ -339,7 +507,7 @@ static HGResult BnmSaveImage(HGImage image, const HGChar* fileName, HGUInt type) fwrite(width, 1, strlen(width), file); fwrite(height, 1, strlen(height), file); - if (HGIMGFMT_PNMTYPE_GRAY_BINARY == type || HGIMGFMT_PNMTYPE_RGB_BINARY == type) + if (HGIMGFMT_PNMTYPE_BINARY_ASCII != type && HGIMGFMT_PNMTYPE_BINARY_BINARY != type) { char maxColor[] = "255\n"; fwrite(maxColor, 1, strlen(maxColor), file); @@ -353,7 +521,7 @@ static HGResult BnmSaveImage(HGImage image, const HGChar* fileName, HGUInt type) step = -(HGInt)imgInfo.widthStep; } - if (imgInfo.type == HGBASE_IMGTYPE_BINARY) + if (type == HGIMGFMT_PNMTYPE_BINARY_BINARY) { HGUInt lineSize = ((imgInfo.width + 7) & ~7) >> 3; HGByte* buf = (HGByte*)malloc(lineSize); @@ -372,7 +540,7 @@ static HGResult BnmSaveImage(HGImage image, const HGChar* fileName, HGUInt type) free(buf); } - else if (imgInfo.type == HGBASE_IMGTYPE_GRAY) + else if (type == HGIMGFMT_PNMTYPE_GRAY_BINARY) { for (HGUInt i = 0; i < imgInfo.height; ++i) { @@ -380,7 +548,7 @@ static HGResult BnmSaveImage(HGImage image, const HGChar* fileName, HGUInt type) fwrite(pEx, 1, imgInfo.width, file); } } - else + else if (type == HGIMGFMT_PNMTYPE_RGB_BINARY) { for (HGUInt i = 0; i < imgInfo.height; ++i) { @@ -388,6 +556,48 @@ static HGResult BnmSaveImage(HGImage image, const HGChar* fileName, HGUInt type) fwrite(pEx, 1, imgInfo.width * 3, file); } } + else if (type == HGIMGFMT_PNMTYPE_RGB_ASCII || type == HGIMGFMT_PNMTYPE_GRAY_ASCII || type == HGIMGFMT_PNMTYPE_BINARY_ASCII) + { + char buf[72] = {0}; + int bufSize = 0; + HGUInt imgWidth = 0; + + if (HGIMGFMT_PNMTYPE_RGB_ASCII == type) + imgWidth = imgInfo.width * 3; + else if (HGIMGFMT_PNMTYPE_GRAY_ASCII == type || HGIMGFMT_PNMTYPE_BINARY_ASCII == type) + imgWidth = imgInfo.width; + + for (HGUInt i = 0; i < imgInfo.height; ++i) + { + uint8_t* pEx = p + (HGSize)i * (HGSize)step; + for (HGUInt j = 0; j < imgWidth; ++j) + { + char buf2[6]; + if (type == HGIMGFMT_PNMTYPE_BINARY_ASCII) + sprintf(buf2, "%d ", (0 == GetBit(pEx, j)) ? 1 : 0); + else + sprintf(buf2, "%d ", pEx[j]); + + if (bufSize + strlen(buf2) >= 70) + { + strcat(buf, "\n"); + fwrite(buf, 1, strlen(buf), file); + buf[0] = 0; + bufSize = 0; + } + + strcat(buf, buf2); + bufSize += strlen(buf2); + } + } + + if (0 != bufSize) + { + fwrite(buf, 1, strlen(buf), file); + buf[0] = 0; + bufSize = 0; + } + } fclose(file); return HGBASE_ERR_OK; diff --git a/modules/imgfmt/HGPnm.h b/modules/imgfmt/HGPnm.h index c066c3fa..426e391b 100644 --- a/modules/imgfmt/HGPnm.h +++ b/modules/imgfmt/HGPnm.h @@ -1,4 +1,4 @@ -#ifndef __HGPNM_H__ +#ifndef __HGPNM_H__ #define __HGPNM_H__ #include "../base/HGDef.h"