to_bmp.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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 "esp_spiram.h"
  18. #include "soc/efuse_reg.h"
  19. #include "esp_heap_caps.h"
  20. #include "yuv.h"
  21. #include "sdkconfig.h"
  22. #include "esp_jpg_decode.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. return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
  57. }
  58. //output buffer and image width
  59. static bool _rgb_write(void * arg, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t *data)
  60. {
  61. rgb_jpg_decoder * jpeg = (rgb_jpg_decoder *)arg;
  62. if(!data){
  63. if(x == 0 && y == 0){
  64. //write start
  65. jpeg->width = w;
  66. jpeg->height = h;
  67. //if output is null, this is BMP
  68. if(!jpeg->output){
  69. jpeg->output = (uint8_t *)_malloc((w*h*3)+jpeg->data_offset);
  70. if(!jpeg->output){
  71. return false;
  72. }
  73. }
  74. } else {
  75. //write end
  76. }
  77. return true;
  78. }
  79. size_t jw = jpeg->width*3;
  80. size_t t = y * jw;
  81. size_t b = t + (h * jw);
  82. size_t l = x * 3;
  83. uint8_t *out = jpeg->output+jpeg->data_offset;
  84. uint8_t *o = out;
  85. size_t iy, ix;
  86. w = w * 3;
  87. for(iy=t; iy<b; iy+=jw) {
  88. o = out+iy+l;
  89. for(ix=0; ix<w; ix+= 3) {
  90. o[ix] = data[ix+2];
  91. o[ix+1] = data[ix+1];
  92. o[ix+2] = data[ix];
  93. }
  94. data+=w;
  95. }
  96. return true;
  97. }
  98. //input buffer
  99. static uint32_t _jpg_read(void * arg, size_t index, uint8_t *buf, size_t len)
  100. {
  101. rgb_jpg_decoder * jpeg = (rgb_jpg_decoder *)arg;
  102. if(buf) {
  103. memcpy(buf, jpeg->input + index, len);
  104. }
  105. return len;
  106. }
  107. static bool jpg2rgb888(const uint8_t *src, size_t src_len, uint8_t * out, jpg_scale_t scale)
  108. {
  109. rgb_jpg_decoder jpeg;
  110. jpeg.width = 0;
  111. jpeg.height = 0;
  112. jpeg.input = src;
  113. jpeg.output = out;
  114. jpeg.data_offset = 0;
  115. if(esp_jpg_decode(src_len, scale, _jpg_read, _rgb_write, (void*)&jpeg) != ESP_OK){
  116. return false;
  117. }
  118. return true;
  119. }
  120. bool jpg2bmp(const uint8_t *src, size_t src_len, uint8_t ** out, size_t * out_len)
  121. {
  122. rgb_jpg_decoder jpeg;
  123. jpeg.width = 0;
  124. jpeg.height = 0;
  125. jpeg.input = src;
  126. jpeg.output = NULL;
  127. jpeg.data_offset = BMP_HEADER_LEN;
  128. if(esp_jpg_decode(src_len, JPG_SCALE_NONE, _jpg_read, _rgb_write, (void*)&jpeg) != ESP_OK){
  129. return false;
  130. }
  131. size_t output_size = jpeg.width*jpeg.height*3;
  132. jpeg.output[0] = 'B';
  133. jpeg.output[1] = 'M';
  134. bmp_header_t * bitmap = (bmp_header_t*)&jpeg.output[2];
  135. bitmap->reserved = 0;
  136. bitmap->filesize = output_size+BMP_HEADER_LEN;
  137. bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN;
  138. bitmap->dibheadersize = 40;
  139. bitmap->width = jpeg.width;
  140. bitmap->height = -jpeg.height;//set negative for top to bottom
  141. bitmap->planes = 1;
  142. bitmap->bitsperpixel = 24;
  143. bitmap->compression = 0;
  144. bitmap->imagesize = output_size;
  145. bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI
  146. bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI
  147. bitmap->numcolorspallette = 0;
  148. bitmap->mostimpcolor = 0;
  149. *out = jpeg.output;
  150. *out_len = output_size+BMP_HEADER_LEN;
  151. return true;
  152. }
  153. bool fmt2rgb888(const uint8_t *src_buf, size_t src_len, pixformat_t format, uint8_t * rgb_buf)
  154. {
  155. int pix_count = 0;
  156. if(format == PIXFORMAT_JPEG) {
  157. return jpg2rgb888(src_buf, src_len, rgb_buf, JPG_SCALE_NONE);
  158. } else if(format == PIXFORMAT_RGB888) {
  159. memcpy(rgb_buf, src_buf, src_len);
  160. } else if(format == PIXFORMAT_RGB565) {
  161. int i;
  162. uint8_t hb, lb;
  163. pix_count = src_len / 2;
  164. for(i=0; i<pix_count; i++) {
  165. hb = *src_buf++;
  166. lb = *src_buf++;
  167. *rgb_buf++ = (lb & 0x1F) << 3;
  168. *rgb_buf++ = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
  169. *rgb_buf++ = hb & 0xF8;
  170. }
  171. } else if(format == PIXFORMAT_GRAYSCALE) {
  172. int i;
  173. uint8_t b;
  174. pix_count = src_len;
  175. for(i=0; i<pix_count; i++) {
  176. b = *src_buf++;
  177. *rgb_buf++ = b;
  178. *rgb_buf++ = b;
  179. *rgb_buf++ = b;
  180. }
  181. } else if(format == PIXFORMAT_YUV422) {
  182. int i, maxi = pix_count / 2;
  183. uint8_t y0, y1, u, v;
  184. uint8_t r, g, b;
  185. pix_count = src_len / 2;
  186. for(i=0; i<maxi; i++) {
  187. y0 = *src_buf++;
  188. u = *src_buf++;
  189. y1 = *src_buf++;
  190. v = *src_buf++;
  191. yuv2rgb(y0, u, v, &r, &g, &b);
  192. *rgb_buf++ = b;
  193. *rgb_buf++ = g;
  194. *rgb_buf++ = r;
  195. yuv2rgb(y1, u, v, &r, &g, &b);
  196. *rgb_buf++ = b;
  197. *rgb_buf++ = g;
  198. *rgb_buf++ = r;
  199. }
  200. }
  201. return true;
  202. }
  203. 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)
  204. {
  205. if(format == PIXFORMAT_JPEG) {
  206. return jpg2bmp(src, src_len, out, out_len);
  207. }
  208. *out = NULL;
  209. *out_len = 0;
  210. int pix_count = width*height;
  211. size_t out_size = (pix_count * 3) + BMP_HEADER_LEN;
  212. uint8_t * out_buf = (uint8_t *)_malloc(out_size);
  213. if(!out_buf) {
  214. ESP_LOGE(TAG, "_malloc failed! %u", out_size);
  215. return false;
  216. }
  217. out_buf[0] = 'B';
  218. out_buf[1] = 'M';
  219. bmp_header_t * bitmap = (bmp_header_t*)&out_buf[2];
  220. bitmap->reserved = 0;
  221. bitmap->filesize = out_size;
  222. bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN;
  223. bitmap->dibheadersize = 40;
  224. bitmap->width = width;
  225. bitmap->height = -height;//set negative for top to bottom
  226. bitmap->planes = 1;
  227. bitmap->bitsperpixel = 24;
  228. bitmap->compression = 0;
  229. bitmap->imagesize = pix_count * 3;
  230. bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI
  231. bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI
  232. bitmap->numcolorspallette = 0;
  233. bitmap->mostimpcolor = 0;
  234. uint8_t * rgb_buf = out_buf + BMP_HEADER_LEN;
  235. uint8_t * src_buf = src;
  236. //convert data to RGB888
  237. if(format == PIXFORMAT_RGB888) {
  238. memcpy(rgb_buf, src_buf, pix_count*3);
  239. } else if(format == PIXFORMAT_RGB565) {
  240. int i;
  241. uint8_t hb, lb;
  242. for(i=0; i<pix_count; i++) {
  243. hb = *src_buf++;
  244. lb = *src_buf++;
  245. *rgb_buf++ = (lb & 0x1F) << 3;
  246. *rgb_buf++ = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
  247. *rgb_buf++ = hb & 0xF8;
  248. }
  249. } else if(format == PIXFORMAT_GRAYSCALE) {
  250. int i;
  251. uint8_t b;
  252. for(i=0; i<pix_count; i++) {
  253. b = *src_buf++;
  254. *rgb_buf++ = b;
  255. *rgb_buf++ = b;
  256. *rgb_buf++ = b;
  257. }
  258. } else if(format == PIXFORMAT_YUV422) {
  259. int i, maxi = pix_count / 2;
  260. uint8_t y0, y1, u, v;
  261. uint8_t r, g, b;
  262. for(i=0; i<maxi; i++) {
  263. y0 = *src_buf++;
  264. u = *src_buf++;
  265. y1 = *src_buf++;
  266. v = *src_buf++;
  267. yuv2rgb(y0, u, v, &r, &g, &b);
  268. *rgb_buf++ = b;
  269. *rgb_buf++ = g;
  270. *rgb_buf++ = r;
  271. yuv2rgb(y1, u, v, &r, &g, &b);
  272. *rgb_buf++ = b;
  273. *rgb_buf++ = g;
  274. *rgb_buf++ = r;
  275. }
  276. }
  277. *out = out_buf;
  278. *out_len = out_size;
  279. return true;
  280. }
  281. bool frame2bmp(camera_fb_t * fb, uint8_t ** out, size_t * out_len)
  282. {
  283. return fmt2bmp(fb->buf, fb->len, fb->width, fb->height, fb->format, out, out_len);
  284. }