// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include "img_converters.h" #include "soc/efuse_reg.h" #include "esp_heap_caps.h" #include "yuv.h" #include "sdkconfig.h" #include "esp_jpg_decode.h" #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) #include "esp32-hal-log.h" #define TAG "" #else #include "esp_log.h" static const char* TAG = "to_bmp"; #endif static const int BMP_HEADER_LEN = 54; typedef struct { uint32_t filesize; uint32_t reserved; uint32_t fileoffset_to_pixelarray; uint32_t dibheadersize; int32_t width; int32_t height; uint16_t planes; uint16_t bitsperpixel; uint32_t compression; uint32_t imagesize; uint32_t ypixelpermeter; uint32_t xpixelpermeter; uint32_t numcolorspallette; uint32_t mostimpcolor; } bmp_header_t; typedef struct { uint16_t width; uint16_t height; uint16_t data_offset; const uint8_t *input; uint8_t *output; } rgb_jpg_decoder; static void *_malloc(size_t size) { return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); } //output buffer and image width static bool _rgb_write(void * arg, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t *data) { rgb_jpg_decoder * jpeg = (rgb_jpg_decoder *)arg; if(!data){ if(x == 0 && y == 0){ //write start jpeg->width = w; jpeg->height = h; //if output is null, this is BMP if(!jpeg->output){ jpeg->output = (uint8_t *)_malloc((w*h*3)+jpeg->data_offset); if(!jpeg->output){ return false; } } } else { //write end } return true; } size_t jw = jpeg->width*3; size_t t = y * jw; size_t b = t + (h * jw); size_t l = x * 3; uint8_t *out = jpeg->output+jpeg->data_offset; uint8_t *o = out; size_t iy, ix; w = w * 3; for(iy=t; iyinput + index, len); } return len; } static bool jpg2rgb888(const uint8_t *src, size_t src_len, uint8_t * out, jpg_scale_t scale) { rgb_jpg_decoder jpeg; jpeg.width = 0; jpeg.height = 0; jpeg.input = src; jpeg.output = out; jpeg.data_offset = 0; if(esp_jpg_decode(src_len, scale, _jpg_read, _rgb_write, (void*)&jpeg) != ESP_OK){ return false; } return true; } bool jpg2bmp(const uint8_t *src, size_t src_len, uint8_t ** out, size_t * out_len) { rgb_jpg_decoder jpeg; jpeg.width = 0; jpeg.height = 0; jpeg.input = src; jpeg.output = NULL; jpeg.data_offset = BMP_HEADER_LEN; if(esp_jpg_decode(src_len, JPG_SCALE_NONE, _jpg_read, _rgb_write, (void*)&jpeg) != ESP_OK){ return false; } size_t output_size = jpeg.width*jpeg.height*3; jpeg.output[0] = 'B'; jpeg.output[1] = 'M'; bmp_header_t * bitmap = (bmp_header_t*)&jpeg.output[2]; bitmap->reserved = 0; bitmap->filesize = output_size+BMP_HEADER_LEN; bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN; bitmap->dibheadersize = 40; bitmap->width = jpeg.width; bitmap->height = -jpeg.height;//set negative for top to bottom bitmap->planes = 1; bitmap->bitsperpixel = 24; bitmap->compression = 0; bitmap->imagesize = output_size; bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI bitmap->numcolorspallette = 0; bitmap->mostimpcolor = 0; *out = jpeg.output; *out_len = output_size+BMP_HEADER_LEN; return true; } bool fmt2rgb888(const uint8_t *src_buf, size_t src_len, pixformat_t format, uint8_t * rgb_buf) { int pix_count = 0; if(format == PIXFORMAT_JPEG) { return jpg2rgb888(src_buf, src_len, rgb_buf, JPG_SCALE_NONE); } else if(format == PIXFORMAT_RGB888) { memcpy(rgb_buf, src_buf, src_len); } else if(format == PIXFORMAT_RGB565) { int i; uint8_t hb, lb; pix_count = src_len / 2; for(i=0; i> 3; *rgb_buf++ = hb & 0xF8; } } else if(format == PIXFORMAT_GRAYSCALE) { int i; uint8_t b; pix_count = src_len; for(i=0; ireserved = 0; bitmap->filesize = out_size; bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN; bitmap->dibheadersize = 40; bitmap->width = width; bitmap->height = -height;//set negative for top to bottom bitmap->planes = 1; bitmap->bitsperpixel = 24; bitmap->compression = 0; bitmap->imagesize = pix_count * 3; bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI bitmap->numcolorspallette = 0; bitmap->mostimpcolor = 0; uint8_t * rgb_buf = out_buf + BMP_HEADER_LEN; uint8_t * src_buf = src; //convert data to RGB888 if(format == PIXFORMAT_RGB888) { memcpy(rgb_buf, src_buf, pix_count*3); } else if(format == PIXFORMAT_RGB565) { int i; uint8_t hb, lb; for(i=0; i> 3; *rgb_buf++ = hb & 0xF8; } } else if(format == PIXFORMAT_GRAYSCALE) { int i; uint8_t b; for(i=0; ibuf, fb->len, fb->width, fb->height, fb->format, out, out_len); }