deAi7Thumb.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. #include "deAi7Thumb.h"
  2. #include <atlimage.h>
  3. //! Utility function to convert the argument of any type to a string
  4. template<typename T>
  5. std::string toString(const T& arg)
  6. {
  7. std::ostringstream os;
  8. os << arg;
  9. return os.str();
  10. }
  11. // Decode a Hex string.
  12. string decodeHex(const byte* src, long srcSize)
  13. {
  14. // 00000030h: 00 01 02 03 04 05 06 07 08 09 10 10 10 10 10 10 ;
  15. // 00000040h: 10 0D 0A 0B 0C 0D 0E 0F 10 10 10 10 10 10 10 10 ;
  16. // 00000050h: 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 ;
  17. // 00000060h: 10 10 0D 0A 0B 0C 0D 0E 0F 10 10 10 10 10 10 10 ;
  18. // create decoding table
  19. byte invalid = 16;
  20. byte decodeHexTable[256];
  21. for (long i = 0; i < 256; i++) decodeHexTable[i] = invalid;
  22. for (byte i = 0; i < 10; i++) decodeHexTable[static_cast<byte>('0') + i] = i;
  23. for (byte i = 0; i < 6; i++) decodeHexTable[static_cast<byte>('A') + i] = i + 10;
  24. for (byte i = 0; i < 6; i++) decodeHexTable[static_cast<byte>('a') + i] = i + 10;
  25. // calculate dest size
  26. long validSrcSize = 0;
  27. for (long srcPos = 0; srcPos < srcSize; srcPos++) {
  28. if (decodeHexTable[src[srcPos]] != invalid) validSrcSize++;
  29. }
  30. const long destSize = validSrcSize / 2;
  31. // allocate dest buffer
  32. string dest(destSize, '\0');
  33. // decode
  34. for (long srcPos = 0, destPos = 0; destPos < destSize; destPos++) {
  35. byte buffer = 0;
  36. for (int bufferPos = 1; bufferPos >= 0 && srcPos < srcSize; srcPos++) {
  37. byte srcValue = decodeHexTable[src[srcPos]];
  38. if (srcValue == invalid) continue;
  39. buffer |= srcValue << (bufferPos * 4);
  40. bufferPos--;
  41. }
  42. dest[destPos] = buffer;
  43. }
  44. return dest;
  45. }
  46. // Decode an Illustrator thumbnail that follows after %AI7_Thumbnail.
  47. string decodeAi7Thumbnail(const string& src)
  48. {
  49. const byte* colorTable = (BYTE*)src.c_str();
  50. const long colorTableSize = 256 * 3;
  51. if (src.size() < colorTableSize) {
  52. // Invalid size of AI7 thumbnail: src.size()
  53. return string();
  54. }
  55. const byte* imageData = (BYTE*)src.c_str() + colorTableSize;
  56. const long imageDataSize = src.size() - colorTableSize;
  57. const bool rle = (imageDataSize >= 3 && imageData[0] == 'R' && imageData[1] == 'L' && imageData[2] == 'E');
  58. std::string dest;
  59. for (long i = rle ? 3 : 0; i < imageDataSize;) {
  60. byte num = 1;
  61. byte value = imageData[i++];
  62. if (rle && value == 0xFD) {
  63. if (i >= imageDataSize) {
  64. // Unexpected end of image data at AI7 thumbnail.
  65. return string();
  66. }
  67. value = imageData[i++];
  68. if (value != 0xFD) {
  69. if (i >= imageDataSize) {
  70. // Unexpected end of image data at AI7 thumbnail
  71. return string();
  72. }
  73. num = value;
  74. value = imageData[i++];
  75. }
  76. }
  77. for (; num != 0; num--) {
  78. dest.append(reinterpret_cast<const char*>(colorTable + (3 * value)), 3);
  79. }
  80. }
  81. return string(reinterpret_cast<const char*>(dest.data()), static_cast<long>(dest.size()));
  82. }
  83. // Create a PNM image from raw RGB data.
  84. string makeBmp(size_t width, size_t height, const string& rgb)
  85. {
  86. const long expectedSize = static_cast<long>(width * height * 3);
  87. if (rgb.size() != expectedSize) {
  88. return string();
  89. }
  90. const std::string header = "P6\n" + toString(width) + " " + toString(height) + "\n255\n";
  91. const char* headerBytes = header.data();
  92. string dest(static_cast<long>(header.size() + rgb.size()) , '\0');
  93. std::copy(headerBytes, headerBytes + header.size(), dest.begin());
  94. std::copy(rgb.data(), rgb.data() + rgb.size(), dest.begin() + header.size());
  95. return dest;
  96. }
  97. bool rgb_makeBmp_tofile(string& rgb, size_t width, size_t height, const char* bmpfilename)
  98. {
  99. const long expectedSize = static_cast<long>(width * height * 3);
  100. FILE* bmpfile = fopen(bmpfilename , "wb");
  101. if ((rgb.size() != expectedSize) || (bmpfile == NULL)) {
  102. fclose(bmpfile);
  103. return false;
  104. }
  105. // BMP格式文件头
  106. BITMAPFILEHEADER bmph = {0x4D42, 54 , 0, 0, 54 }; // 14字节 'BM' 文件头
  107. BITMAPINFOHEADER bmpinf = {40, width, height, 1, 24, 0 , 0, 0, 0, 0, 0 }; // 40字节
  108. bmph.bfSize += rgb.size();
  109. fwrite(&bmph , 1, sizeof(bmph), bmpfile);
  110. fwrite(&bmpinf , 1, sizeof(bmpinf), bmpfile);
  111. // 由于前面解码的数据是RGB标准数据,而BMP存储为BGR顺序
  112. // 由于BMP写文件最下面先读写,要翻转
  113. for (size_t i = 0 ; i < rgb.size() -2 ; i += 3) {
  114. std::swap(rgb[i] , rgb[i + 2]);
  115. }
  116. const char* px = rgb.c_str();
  117. for (size_t i = height ; i > 0 ; i--) {
  118. fwrite(px + 3 * i * width , 1 , 3 * width, bmpfile);
  119. }
  120. fclose(bmpfile);
  121. return true;
  122. }
  123. bool decode_Ai7Thumb_toPng(string& AI7Thumb, size_t width, size_t height, const char* pngfilename)
  124. {
  125. // %AI7_Thumbnail: 76 128 8
  126. // %%BeginData: 14580 Hex Bytes
  127. // "%0000330000660000990000CC0033000033330033660033990033CC0033FF\n\r"
  128. // "%0066000066330066660066990066CC0066FF009900009933009966009999\n\r"
  129. // /***** 14580 Hex Bytes *****/
  130. // "%82A783A8A7FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFD8EFFFF\n\r";
  131. string hexbin = decodeHex((BYTE*)AI7Thumb.c_str() , AI7Thumb.size());
  132. string srgb = decodeAi7Thumbnail(hexbin);
  133. char temp_filename[128];
  134. const char* tmpBmpFile = tmpnam(temp_filename);
  135. strcat(temp_filename,".bmp");
  136. // RGB 数据写bmp文件
  137. rgb_makeBmp_tofile(srgb, width, height, tmpBmpFile);
  138. CImage image; // bmp 转换 png ,需要CImage类,头文件 atlimage.h
  139. image.Load(tmpBmpFile);
  140. image.Save(pngfilename);
  141. if (remove(tmpBmpFile) != 0)
  142. perror("Error deleting file");
  143. return true;
  144. }