#include "deAi7Thumb.h" #include //! Utility function to convert the argument of any type to a string template std::string toString(const T& arg) { std::ostringstream os; os << arg; return os.str(); } // Decode a Hex string. string decodeHex(const byte* src, long srcSize) { // 00000030h: 00 01 02 03 04 05 06 07 08 09 10 10 10 10 10 10 ; // 00000040h: 10 0D 0A 0B 0C 0D 0E 0F 10 10 10 10 10 10 10 10 ; // 00000050h: 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 ; // 00000060h: 10 10 0D 0A 0B 0C 0D 0E 0F 10 10 10 10 10 10 10 ; // create decoding table byte invalid = 16; byte decodeHexTable[256]; for (long i = 0; i < 256; i++) decodeHexTable[i] = invalid; for (byte i = 0; i < 10; i++) decodeHexTable[static_cast('0') + i] = i; for (byte i = 0; i < 6; i++) decodeHexTable[static_cast('A') + i] = i + 10; for (byte i = 0; i < 6; i++) decodeHexTable[static_cast('a') + i] = i + 10; // calculate dest size long validSrcSize = 0; for (long srcPos = 0; srcPos < srcSize; srcPos++) { if (decodeHexTable[src[srcPos]] != invalid) validSrcSize++; } const long destSize = validSrcSize / 2; // allocate dest buffer string dest(destSize, '\0'); // decode for (long srcPos = 0, destPos = 0; destPos < destSize; destPos++) { byte buffer = 0; for (int bufferPos = 1; bufferPos >= 0 && srcPos < srcSize; srcPos++) { byte srcValue = decodeHexTable[src[srcPos]]; if (srcValue == invalid) continue; buffer |= srcValue << (bufferPos * 4); bufferPos--; } dest[destPos] = buffer; } return dest; } // Decode an Illustrator thumbnail that follows after %AI7_Thumbnail. string decodeAi7Thumbnail(const string& src) { const byte* colorTable = (BYTE*)src.c_str(); const long colorTableSize = 256 * 3; if (src.size() < colorTableSize) { // Invalid size of AI7 thumbnail: src.size() return string(); } const byte* imageData = (BYTE*)src.c_str() + colorTableSize; const long imageDataSize = src.size() - colorTableSize; const bool rle = (imageDataSize >= 3 && imageData[0] == 'R' && imageData[1] == 'L' && imageData[2] == 'E'); std::string dest; for (long i = rle ? 3 : 0; i < imageDataSize;) { byte num = 1; byte value = imageData[i++]; if (rle && value == 0xFD) { if (i >= imageDataSize) { // Unexpected end of image data at AI7 thumbnail. return string(); } value = imageData[i++]; if (value != 0xFD) { if (i >= imageDataSize) { // Unexpected end of image data at AI7 thumbnail return string(); } num = value; value = imageData[i++]; } } for (; num != 0; num--) { dest.append(reinterpret_cast(colorTable + (3 * value)), 3); } } return string(reinterpret_cast(dest.data()), static_cast(dest.size())); } // Create a PNM image from raw RGB data. string makeBmp(size_t width, size_t height, const string& rgb) { const long expectedSize = static_cast(width * height * 3); if (rgb.size() != expectedSize) { return string(); } const std::string header = "P6\n" + toString(width) + " " + toString(height) + "\n255\n"; const char* headerBytes = header.data(); string dest(static_cast(header.size() + rgb.size()) , '\0'); std::copy(headerBytes, headerBytes + header.size(), dest.begin()); std::copy(rgb.data(), rgb.data() + rgb.size(), dest.begin() + header.size()); return dest; } bool rgb_makeBmp_tofile(string& rgb, size_t width, size_t height, const char* bmpfilename) { const long expectedSize = static_cast(width * height * 3); FILE* bmpfile = fopen(bmpfilename , "wb"); if ((rgb.size() != expectedSize) || (bmpfile == NULL)) { fclose(bmpfile); return false; } // BMP格式文件头 BITMAPFILEHEADER bmph = {0x4D42, 54 , 0, 0, 54 }; // 14字节 'BM' 文件头 BITMAPINFOHEADER bmpinf = {40, width, height, 1, 24, 0 , 0, 0, 0, 0, 0 }; // 40字节 bmph.bfSize += rgb.size(); fwrite(&bmph , 1, sizeof(bmph), bmpfile); fwrite(&bmpinf , 1, sizeof(bmpinf), bmpfile); // 由于前面解码的数据是RGB标准数据,而BMP存储为BGR顺序 // 由于BMP写文件最下面先读写,要翻转 for (size_t i = 0 ; i < rgb.size() -2 ; i += 3) { std::swap(rgb[i] , rgb[i + 2]); } const char* px = rgb.c_str(); for (size_t i = height ; i > 0 ; i--) { fwrite(px + 3 * i * width , 1 , 3 * width, bmpfile); } fclose(bmpfile); return true; } bool decode_Ai7Thumb_toPng(string& AI7Thumb, size_t width, size_t height, const char* pngfilename) { // %AI7_Thumbnail: 76 128 8 // %%BeginData: 14580 Hex Bytes // "%0000330000660000990000CC0033000033330033660033990033CC0033FF\n\r" // "%0066000066330066660066990066CC0066FF009900009933009966009999\n\r" // /***** 14580 Hex Bytes *****/ // "%82A783A8A7FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFD8EFFFF\n\r"; string hexbin = decodeHex((BYTE*)AI7Thumb.c_str() , AI7Thumb.size()); string srgb = decodeAi7Thumbnail(hexbin); char temp_filename[128]; const char* tmpBmpFile = tmpnam(temp_filename); strcat(temp_filename,".bmp"); // RGB 数据写bmp文件 rgb_makeBmp_tofile(srgb, width, height, tmpBmpFile); CImage image; // bmp 转换 png ,需要CImage类,头文件 atlimage.h image.Load(tmpBmpFile); image.Save(pngfilename); if (remove(tmpBmpFile) != 0) perror("Error deleting file"); return true; }