to_bmp.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <stddef.h>
  15. #include <string.h>
  16. #include "img_converters.h"
  17. #include "soc/efuse_reg.h"
  18. #include "esp_heap_caps.h"
  19. #include "yuv.h"
  20. #include "sdkconfig.h"
  21. #include "esp_jpg_decode.h"
  22. #include "esp_system.h"
  23. #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
  24. #include "esp32-hal-log.h"
  25. #define TAG ""
  26. #else
  27. #include "esp_log.h"
  28. static const char* TAG = "to_bmp";
  29. #endif
  30. static const int BMP_HEADER_LEN = 54;
  31. typedef struct {
  32. uint32_t filesize;
  33. uint32_t reserved;
  34. uint32_t fileoffset_to_pixelarray;
  35. uint32_t dibheadersize;
  36. int32_t width;
  37. int32_t height;
  38. uint16_t planes;
  39. uint16_t bitsperpixel;
  40. uint32_t compression;
  41. uint32_t imagesize;
  42. uint32_t ypixelpermeter;
  43. uint32_t xpixelpermeter;
  44. uint32_t numcolorspallette;
  45. uint32_t mostimpcolor;
  46. } bmp_header_t;
  47. typedef struct {
  48. uint16_t width;
  49. uint16_t height;
  50. uint16_t data_offset;
  51. const uint8_t *input;
  52. uint8_t *output;
  53. } rgb_jpg_decoder;
  54. static void *_malloc(size_t size)
  55. {
  56. // check if SPIRAM is enabled and allocate on SPIRAM if allocatable
  57. #if (CONFIG_SPIRAM_SUPPORT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC))
  58. return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
  59. #endif
  60. // try allocating in internal memory
  61. return malloc(size);
  62. }
  63. //output buffer and image width
  64. static bool _rgb_write(void * arg, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t *data)
  65. {
  66. rgb_jpg_decoder * jpeg = (rgb_jpg_decoder *)arg;
  67. if(!data){
  68. if(x == 0 && y == 0){
  69. //write start
  70. jpeg->width = w;
  71. jpeg->height = h;
  72. //if output is null, this is BMP
  73. if(!jpeg->output){
  74. jpeg->output = (uint8_t *)_malloc((w*h*3)+jpeg->data_offset);
  75. if(!jpeg->output){
  76. return false;
  77. }
  78. }
  79. } else {
  80. //write end
  81. }
  82. return true;
  83. }
  84. size_t jw = jpeg->width*3;
  85. size_t t = y * jw;
  86. size_t b = t + (h * jw);
  87. size_t l = x * 3;
  88. uint8_t *out = jpeg->output+jpeg->data_offset;
  89. uint8_t *o = out;
  90. size_t iy, ix;
  91. w = w * 3;
  92. for(iy=t; iy<b; iy+=jw) {
  93. o = out+iy+l;
  94. for(ix=0; ix<w; ix+= 3) {
  95. o[ix] = data[ix+2];
  96. o[ix+1] = data[ix+1];
  97. o[ix+2] = data[ix];
  98. }
  99. data+=w;
  100. }
  101. return true;
  102. }
  103. static bool _rgb565_write(void * arg, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t *data)
  104. {
  105. rgb_jpg_decoder * jpeg = (rgb_jpg_decoder *)arg;
  106. if(!data){
  107. if(x == 0 && y == 0){
  108. //write start
  109. jpeg->width = w;
  110. jpeg->height = h;
  111. //if output is null, this is BMP
  112. if(!jpeg->output){
  113. jpeg->output = (uint8_t *)_malloc((w*h*3)+jpeg->data_offset);
  114. if(!jpeg->output){
  115. return false;
  116. }
  117. }
  118. } else {
  119. //write end
  120. }
  121. return true;
  122. }
  123. size_t jw = jpeg->width*3;
  124. size_t jw2 = jpeg->width*2;
  125. size_t t = y * jw;
  126. size_t t2 = y * jw2;
  127. size_t b = t + (h * jw);
  128. size_t l = x * 2;
  129. uint8_t *out = jpeg->output+jpeg->data_offset;
  130. uint8_t *o = out;
  131. size_t iy, iy2, ix, ix2;
  132. w = w * 3;
  133. for(iy=t, iy2=t2; iy<b; iy+=jw, iy2+=jw2) {
  134. o = out+iy2+l;
  135. for(ix2=ix=0; ix<w; ix+= 3, ix2 +=2) {
  136. uint16_t r = data[ix];
  137. uint16_t g = data[ix+1];
  138. uint16_t b = data[ix+2];
  139. uint16_t c = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
  140. o[ix2+1] = c>>8;
  141. o[ix2] = c&0xff;
  142. }
  143. data+=w;
  144. }
  145. return true;
  146. }
  147. //input buffer
  148. static unsigned int _jpg_read(void * arg, size_t index, uint8_t *buf, size_t len)
  149. {
  150. rgb_jpg_decoder * jpeg = (rgb_jpg_decoder *)arg;
  151. if(buf) {
  152. memcpy(buf, jpeg->input + index, len);
  153. }
  154. return len;
  155. }
  156. static bool jpg2rgb888(const uint8_t *src, size_t src_len, uint8_t * out, jpg_scale_t scale)
  157. {
  158. rgb_jpg_decoder jpeg;
  159. jpeg.width = 0;
  160. jpeg.height = 0;
  161. jpeg.input = src;
  162. jpeg.output = out;
  163. jpeg.data_offset = 0;
  164. if(esp_jpg_decode(src_len, scale, _jpg_read, _rgb_write, (void*)&jpeg) != ESP_OK){
  165. return false;
  166. }
  167. return true;
  168. }
  169. bool jpg2rgb565(const uint8_t *src, size_t src_len, uint8_t * out, jpg_scale_t scale)
  170. {
  171. rgb_jpg_decoder jpeg;
  172. jpeg.width = 0;
  173. jpeg.height = 0;
  174. jpeg.input = src;
  175. jpeg.output = out;
  176. jpeg.data_offset = 0;
  177. if(esp_jpg_decode(src_len, scale, _jpg_read, _rgb565_write, (void*)&jpeg) != ESP_OK){
  178. return false;
  179. }
  180. return true;
  181. }
  182. bool jpg2bmp(const uint8_t *src, size_t src_len, uint8_t ** out, size_t * out_len)
  183. {
  184. rgb_jpg_decoder jpeg;
  185. jpeg.width = 0;
  186. jpeg.height = 0;
  187. jpeg.input = src;
  188. jpeg.output = NULL;
  189. jpeg.data_offset = BMP_HEADER_LEN;
  190. if(esp_jpg_decode(src_len, JPG_SCALE_NONE, _jpg_read, _rgb_write, (void*)&jpeg) != ESP_OK){
  191. return false;
  192. }
  193. size_t output_size = jpeg.width*jpeg.height*3;
  194. jpeg.output[0] = 'B';
  195. jpeg.output[1] = 'M';
  196. bmp_header_t * bitmap = (bmp_header_t*)&jpeg.output[2];
  197. bitmap->reserved = 0;
  198. bitmap->filesize = output_size+BMP_HEADER_LEN;
  199. bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN;
  200. bitmap->dibheadersize = 40;
  201. bitmap->width = jpeg.width;
  202. bitmap->height = -jpeg.height;//set negative for top to bottom
  203. bitmap->planes = 1;
  204. bitmap->bitsperpixel = 24;
  205. bitmap->compression = 0;
  206. bitmap->imagesize = output_size;
  207. bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI
  208. bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI
  209. bitmap->numcolorspallette = 0;
  210. bitmap->mostimpcolor = 0;
  211. *out = jpeg.output;
  212. *out_len = output_size+BMP_HEADER_LEN;
  213. return true;
  214. }
  215. bool fmt2rgb888(const uint8_t *src_buf, size_t src_len, pixformat_t format, uint8_t * rgb_buf)
  216. {
  217. int pix_count = 0;
  218. if(format == PIXFORMAT_JPEG) {
  219. return jpg2rgb888(src_buf, src_len, rgb_buf, JPG_SCALE_NONE);
  220. } else if(format == PIXFORMAT_RGB888) {
  221. memcpy(rgb_buf, src_buf, src_len);
  222. } else if(format == PIXFORMAT_RGB565) {
  223. int i;
  224. uint8_t hb, lb;
  225. pix_count = src_len / 2;
  226. for(i=0; i<pix_count; i++) {
  227. hb = *src_buf++;
  228. lb = *src_buf++;
  229. *rgb_buf++ = (lb & 0x1F) << 3;
  230. *rgb_buf++ = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
  231. *rgb_buf++ = hb & 0xF8;
  232. }
  233. } else if(format == PIXFORMAT_GRAYSCALE) {
  234. int i;
  235. uint8_t b;
  236. pix_count = src_len;
  237. for(i=0; i<pix_count; i++) {
  238. b = *src_buf++;
  239. *rgb_buf++ = b;
  240. *rgb_buf++ = b;
  241. *rgb_buf++ = b;
  242. }
  243. } else if(format == PIXFORMAT_YUV422) {
  244. pix_count = src_len / 2;
  245. int i, maxi = pix_count / 2;
  246. uint8_t y0, y1, u, v;
  247. uint8_t r, g, b;
  248. for(i=0; i<maxi; i++) {
  249. y0 = *src_buf++;
  250. u = *src_buf++;
  251. y1 = *src_buf++;
  252. v = *src_buf++;
  253. yuv2rgb(y0, u, v, &r, &g, &b);
  254. *rgb_buf++ = b;
  255. *rgb_buf++ = g;
  256. *rgb_buf++ = r;
  257. yuv2rgb(y1, u, v, &r, &g, &b);
  258. *rgb_buf++ = b;
  259. *rgb_buf++ = g;
  260. *rgb_buf++ = r;
  261. }
  262. }
  263. return true;
  264. }
  265. bool fmt2bmp(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t ** out, size_t * out_len)
  266. {
  267. if(format == PIXFORMAT_JPEG) {
  268. return jpg2bmp(src, src_len, out, out_len);
  269. }
  270. *out = NULL;
  271. *out_len = 0;
  272. int pix_count = width*height;
  273. // With BMP, 8-bit greyscale requires a palette.
  274. // For a 640x480 image though, that's a savings
  275. // over going RGB-24.
  276. int bpp = (format == PIXFORMAT_GRAYSCALE) ? 1 : 3;
  277. int palette_size = (format == PIXFORMAT_GRAYSCALE) ? 4 * 256 : 0;
  278. size_t out_size = (pix_count * bpp) + BMP_HEADER_LEN + palette_size;
  279. uint8_t * out_buf = (uint8_t *)_malloc(out_size);
  280. if(!out_buf) {
  281. ESP_LOGE(TAG, "_malloc failed! %u", out_size);
  282. return false;
  283. }
  284. out_buf[0] = 'B';
  285. out_buf[1] = 'M';
  286. bmp_header_t * bitmap = (bmp_header_t*)&out_buf[2];
  287. bitmap->reserved = 0;
  288. bitmap->filesize = out_size;
  289. bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN + palette_size;
  290. bitmap->dibheadersize = 40;
  291. bitmap->width = width;
  292. bitmap->height = -height;//set negative for top to bottom
  293. bitmap->planes = 1;
  294. bitmap->bitsperpixel = bpp * 8;
  295. bitmap->compression = 0;
  296. bitmap->imagesize = pix_count * bpp;
  297. bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI
  298. bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI
  299. bitmap->numcolorspallette = 0;
  300. bitmap->mostimpcolor = 0;
  301. uint8_t * palette_buf = out_buf + BMP_HEADER_LEN;
  302. uint8_t * pix_buf = palette_buf + palette_size;
  303. uint8_t * src_buf = src;
  304. if (palette_size > 0) {
  305. // Grayscale palette
  306. for (int i = 0; i < 256; ++i) {
  307. for (int j = 0; j < 3; ++j) {
  308. *palette_buf = i;
  309. palette_buf++;
  310. }
  311. // Reserved / alpha channel.
  312. *palette_buf = 0;
  313. palette_buf++;
  314. }
  315. }
  316. //convert data to RGB888
  317. if(format == PIXFORMAT_RGB888) {
  318. memcpy(pix_buf, src_buf, pix_count*3);
  319. } else if(format == PIXFORMAT_RGB565) {
  320. int i;
  321. uint8_t hb, lb;
  322. for(i=0; i<pix_count; i++) {
  323. hb = *src_buf++;
  324. lb = *src_buf++;
  325. *pix_buf++ = (lb & 0x1F) << 3;
  326. *pix_buf++ = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
  327. *pix_buf++ = hb & 0xF8;
  328. }
  329. } else if(format == PIXFORMAT_GRAYSCALE) {
  330. memcpy(pix_buf, src_buf, pix_count);
  331. } else if(format == PIXFORMAT_YUV422) {
  332. int i, maxi = pix_count / 2;
  333. uint8_t y0, y1, u, v;
  334. uint8_t r, g, b;
  335. for(i=0; i<maxi; i++) {
  336. y0 = *src_buf++;
  337. u = *src_buf++;
  338. y1 = *src_buf++;
  339. v = *src_buf++;
  340. yuv2rgb(y0, u, v, &r, &g, &b);
  341. *pix_buf++ = b;
  342. *pix_buf++ = g;
  343. *pix_buf++ = r;
  344. yuv2rgb(y1, u, v, &r, &g, &b);
  345. *pix_buf++ = b;
  346. *pix_buf++ = g;
  347. *pix_buf++ = r;
  348. }
  349. }
  350. *out = out_buf;
  351. *out_len = out_size;
  352. return true;
  353. }
  354. bool frame2bmp(camera_fb_t * fb, uint8_t ** out, size_t * out_len)
  355. {
  356. return fmt2bmp(fb->buf, fb->len, fb->width, fb->height, fb->format, out, out_len);
  357. }