to_bmp.c 8.9 KB

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