to_bmp.c 11 KB

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