bmpdecoderhelper.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. /*
  2. * Copyright 2007, The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. // Author: cevans@google.com (Chris Evans)
  17. #include <memory.h>
  18. #include "bmpdecoderhelper.h"
  19. namespace image_codec {
  20. static const int kBmpHeaderSize = 14;
  21. static const int kBmpInfoSize = 40;
  22. static const int kBmpOS2InfoSize = 12;
  23. static const int kMaxDim = SHRT_MAX / 2;
  24. bool BmpDecoderHelper::DecodeImage(const char* p,
  25. int len,
  26. int max_pixels,
  27. BmpDecoderCallback* callback) {
  28. data_ = reinterpret_cast<const uint8*>(p);
  29. pos_ = 0;
  30. len_ = len;
  31. inverted_ = true;
  32. // Parse the header structure.
  33. if (len < kBmpHeaderSize + 4) {
  34. return false;
  35. }
  36. GetShort(); // Signature.
  37. GetInt(); // Size.
  38. GetInt(); // Reserved.
  39. int offset = GetInt();
  40. // Parse the info structure.
  41. int infoSize = GetInt();
  42. if (infoSize != kBmpOS2InfoSize && infoSize < kBmpInfoSize) {
  43. return false;
  44. }
  45. int cols = 0;
  46. int comp = 0;
  47. int colLen = 4;
  48. if (infoSize >= kBmpInfoSize) {
  49. if (len < kBmpHeaderSize + kBmpInfoSize) {
  50. return false;
  51. }
  52. width_ = GetInt();
  53. height_ = GetInt();
  54. GetShort(); // Planes.
  55. bpp_ = GetShort();
  56. comp = GetInt();
  57. GetInt(); // Size.
  58. GetInt(); // XPPM.
  59. GetInt(); // YPPM.
  60. cols = GetInt();
  61. GetInt(); // Important colours.
  62. } else {
  63. if (len < kBmpHeaderSize + kBmpOS2InfoSize) {
  64. return false;
  65. }
  66. colLen = 3;
  67. width_ = GetShort();
  68. height_ = GetShort();
  69. GetShort(); // Planes.
  70. bpp_ = GetShort();
  71. }
  72. if (height_ < 0) {
  73. height_ = -height_;
  74. inverted_ = false;
  75. }
  76. if (width_ <= 0 || width_ > kMaxDim || height_ <= 0 || height_ > kMaxDim) {
  77. return false;
  78. }
  79. if (width_ * height_ > max_pixels) {
  80. return false;
  81. }
  82. if (cols < 0 || cols > 256) {
  83. return false;
  84. }
  85. // Allocate then read in the colour map.
  86. if (cols == 0 && bpp_ <= 8) {
  87. cols = 1 << bpp_;
  88. }
  89. if (bpp_ <= 8 || cols > 0) {
  90. uint8* colBuf = new uint8[256 * 3];
  91. memset(colBuf, '\0', 256 * 3);
  92. colTab_.reset(colBuf);
  93. }
  94. if (cols > 0) {
  95. if (pos_ + (cols * colLen) > len_) {
  96. return false;
  97. }
  98. for (int i = 0; i < cols; ++i) {
  99. int base = i * 3;
  100. colTab_[base + 2] = GetByte();
  101. colTab_[base + 1] = GetByte();
  102. colTab_[base] = GetByte();
  103. if (colLen == 4) {
  104. GetByte();
  105. }
  106. }
  107. }
  108. // Read in the compression data if necessary.
  109. redBits_ = 0x7c00;
  110. greenBits_ = 0x03e0;
  111. blueBits_ = 0x001f;
  112. bool rle = false;
  113. if (comp == 1 || comp == 2) {
  114. rle = true;
  115. } else if (comp == 3) {
  116. if (pos_ + 12 > len_) {
  117. return false;
  118. }
  119. redBits_ = GetInt() & 0xffff;
  120. greenBits_ = GetInt() & 0xffff;
  121. blueBits_ = GetInt() & 0xffff;
  122. }
  123. redShiftRight_ = CalcShiftRight(redBits_);
  124. greenShiftRight_ = CalcShiftRight(greenBits_);
  125. blueShiftRight_ = CalcShiftRight(blueBits_);
  126. redShiftLeft_ = CalcShiftLeft(redBits_);
  127. greenShiftLeft_ = CalcShiftLeft(greenBits_);
  128. blueShiftLeft_ = CalcShiftLeft(blueBits_);
  129. rowPad_ = 0;
  130. pixelPad_ = 0;
  131. int rowLen;
  132. if (bpp_ == 32) {
  133. rowLen = width_ * 4;
  134. pixelPad_ = 1;
  135. } else if (bpp_ == 24) {
  136. rowLen = width_ * 3;
  137. } else if (bpp_ == 16) {
  138. rowLen = width_ * 2;
  139. } else if (bpp_ == 8) {
  140. rowLen = width_;
  141. } else if (bpp_ == 4) {
  142. rowLen = width_ / 2;
  143. if (width_ & 1) {
  144. rowLen++;
  145. }
  146. } else if (bpp_ == 1) {
  147. rowLen = width_ / 8;
  148. if (width_ & 7) {
  149. rowLen++;
  150. }
  151. } else {
  152. return false;
  153. }
  154. // Round the rowLen up to a multiple of 4.
  155. if (rowLen % 4 != 0) {
  156. rowPad_ = 4 - (rowLen % 4);
  157. rowLen += rowPad_;
  158. }
  159. if (offset > 0 && offset > pos_ && offset < len_) {
  160. pos_ = offset;
  161. }
  162. // Deliberately off-by-one; a load of BMPs seem to have their last byte
  163. // missing.
  164. if (!rle && (pos_ + (rowLen * height_) > len_ + 1)) {
  165. return false;
  166. }
  167. output_ = callback->SetSize(width_, height_);
  168. if (NULL == output_) {
  169. return true; // meaning we succeeded, but they want us to stop now
  170. }
  171. if (rle && (bpp_ == 4 || bpp_ == 8)) {
  172. DoRLEDecode();
  173. } else {
  174. DoStandardDecode();
  175. }
  176. return true;
  177. }
  178. void BmpDecoderHelper::DoRLEDecode() {
  179. static const uint8 RLE_ESCAPE = 0;
  180. static const uint8 RLE_EOL = 0;
  181. static const uint8 RLE_EOF = 1;
  182. static const uint8 RLE_DELTA = 2;
  183. int x = 0;
  184. int y = height_ - 1;
  185. while (pos_ < len_ - 1) {
  186. uint8 cmd = GetByte();
  187. if (cmd != RLE_ESCAPE) {
  188. uint8 pixels = GetByte();
  189. int num = 0;
  190. uint8 col = pixels;
  191. while (cmd-- && x < width_) {
  192. if (bpp_ == 4) {
  193. if (num & 1) {
  194. col = pixels & 0xf;
  195. } else {
  196. col = pixels >> 4;
  197. }
  198. }
  199. PutPixel(x++, y, col);
  200. num++;
  201. }
  202. } else {
  203. cmd = GetByte();
  204. if (cmd == RLE_EOF) {
  205. return;
  206. } else if (cmd == RLE_EOL) {
  207. x = 0;
  208. y--;
  209. if (y < 0) {
  210. return;
  211. }
  212. } else if (cmd == RLE_DELTA) {
  213. if (pos_ < len_ - 1) {
  214. uint8 dx = GetByte();
  215. uint8 dy = GetByte();
  216. x += dx;
  217. if (x > width_) {
  218. x = width_;
  219. }
  220. y -= dy;
  221. if (y < 0) {
  222. return;
  223. }
  224. }
  225. } else {
  226. int num = 0;
  227. int bytesRead = 0;
  228. uint8 val = 0;
  229. while (cmd-- && pos_ < len_) {
  230. if (bpp_ == 8 || !(num & 1)) {
  231. val = GetByte();
  232. bytesRead++;
  233. }
  234. uint8 col = val;
  235. if (bpp_ == 4) {
  236. if (num & 1) {
  237. col = col & 0xf;
  238. } else {
  239. col >>= 4;
  240. }
  241. }
  242. if (x < width_) {
  243. PutPixel(x++, y, col);
  244. }
  245. num++;
  246. }
  247. // All pixel runs must be an even number of bytes - skip a byte if we
  248. // read an odd number.
  249. if ((bytesRead & 1) && pos_ < len_) {
  250. GetByte();
  251. }
  252. }
  253. }
  254. }
  255. }
  256. void BmpDecoderHelper::PutPixel(int x, int y, uint8 col) {
  257. CHECK(x >= 0 && x < width_);
  258. CHECK(y >= 0 && y < height_);
  259. if (!inverted_) {
  260. y = height_ - (y + 1);
  261. }
  262. int base = ((y * width_) + x) * 3;
  263. int colBase = col * 3;
  264. output_[base] = colTab_[colBase];
  265. output_[base + 1] = colTab_[colBase + 1];
  266. output_[base + 2] = colTab_[colBase + 2];
  267. }
  268. void BmpDecoderHelper::DoStandardDecode() {
  269. int row = 0;
  270. uint8 currVal = 0;
  271. for (int h = height_ - 1; h >= 0; h--, row++) {
  272. int realH = h;
  273. if (!inverted_) {
  274. realH = height_ - (h + 1);
  275. }
  276. uint8* line = output_ + (3 * width_ * realH);
  277. for (int w = 0; w < width_; w++) {
  278. if (bpp_ >= 24) {
  279. line[2] = GetByte();
  280. line[1] = GetByte();
  281. line[0] = GetByte();
  282. } else if (bpp_ == 16) {
  283. uint32 val = GetShort();
  284. line[0] = ((val & redBits_) >> redShiftRight_) << redShiftLeft_;
  285. line[1] = ((val & greenBits_) >> greenShiftRight_) << greenShiftLeft_;
  286. line[2] = ((val & blueBits_) >> blueShiftRight_) << blueShiftLeft_;
  287. } else if (bpp_ <= 8) {
  288. uint8 col;
  289. if (bpp_ == 8) {
  290. col = GetByte();
  291. } else if (bpp_ == 4) {
  292. if ((w % 2) == 0) {
  293. currVal = GetByte();
  294. col = currVal >> 4;
  295. } else {
  296. col = currVal & 0xf;
  297. }
  298. } else {
  299. if ((w % 8) == 0) {
  300. currVal = GetByte();
  301. }
  302. int bit = w & 7;
  303. col = ((currVal >> (7 - bit)) & 1);
  304. }
  305. int base = col * 3;
  306. line[0] = colTab_[base];
  307. line[1] = colTab_[base + 1];
  308. line[2] = colTab_[base + 2];
  309. }
  310. line += 3;
  311. for (int i = 0; i < pixelPad_; ++i) {
  312. GetByte();
  313. }
  314. }
  315. for (int i = 0; i < rowPad_; ++i) {
  316. GetByte();
  317. }
  318. }
  319. }
  320. int BmpDecoderHelper::GetInt() {
  321. uint8 b1 = GetByte();
  322. uint8 b2 = GetByte();
  323. uint8 b3 = GetByte();
  324. uint8 b4 = GetByte();
  325. return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
  326. }
  327. int BmpDecoderHelper::GetShort() {
  328. uint8 b1 = GetByte();
  329. uint8 b2 = GetByte();
  330. return b1 | (b2 << 8);
  331. }
  332. uint8 BmpDecoderHelper::GetByte() {
  333. CHECK(pos_ >= 0 && pos_ <= len_);
  334. // We deliberately allow this off-by-one access to cater for BMPs with their
  335. // last byte missing.
  336. if (pos_ == len_) {
  337. return 0;
  338. }
  339. return data_[pos_++];
  340. }
  341. int BmpDecoderHelper::CalcShiftRight(uint32 mask) {
  342. int ret = 0;
  343. while (mask != 0 && !(mask & 1)) {
  344. mask >>= 1;
  345. ret++;
  346. }
  347. return ret;
  348. }
  349. int BmpDecoderHelper::CalcShiftLeft(uint32 mask) {
  350. int ret = 0;
  351. while (mask != 0 && !(mask & 1)) {
  352. mask >>= 1;
  353. }
  354. while (mask != 0 && !(mask & 0x80)) {
  355. mask <<= 1;
  356. ret++;
  357. }
  358. return ret;
  359. }
  360. } // namespace image_codec