简体   繁体   中英

esp32 http_server html how to show image from sd card

I am using esp32cam module with sdcard interface. The image I am able to save in the sdcard. This image opens in Windows PC. Next thing, I have done is to add http_server and in the html page I wanted to access the image from sdcard and using in src attrtibute of img tag. But the html does not display image and in the teraterm log it says it cannot find the file.

 httpd_uri: httpd_uri: URI '/sdcard/fnb1.jpg' not found

The code to serve the html request is as follows:

1   static esp_err_t hello_get_handler(httpd_req_t *req) {  
2   strcpy(ret_homepage,"<!DOCTYPE html><html><head><title>SwitchControl</title>"); 
3   strcat(ret_homepage, "</head><body>");  
4   strcat(ret_homepage, "<div>");  
5   strcat(ret_homepage, "Picture1:");  
6   strcat(ret_homepage,"<img src=\"/sdcard/fnb1.jpg\" width=\"500\" height=\"600\">"); 
7   strcat(ret_homepage, "</div>"); 
8       
9   strcat(ret_homepage, "</body>");    
10  strcat(ret_homepage, "</html>");    
11      
12  /* Set some custom headers */   
13  httpd_resp_set_hdr(req, "Connection", "close"); 
14  httpd_resp_set_hdr(req, "Cache-Control", "no-cache");   
15      
16  /* Send response with custom headers and body set as the    
17   * string passed in user context*/  
18  const char *resp_str = (const char*) ret_homepage;  
19      
20  httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);  
21      
22  ESP_LOGI(TAG, "Response sent for home page request.Time:%s",esp_log_system_timestamp());    
23      
24  return ESP_OK;  
25  }

Here at the line#6

strcat(ret_homepage,"<img src=\"/sdcard/fnb1.jpg\" width=\"500\" height=\"600\">");

the http_server seems not able to access the mount_point "/sdcard" and consequently not able to access fbn1.jpg.

The mount of SD Card I have done like below. This mount is working fine as the file written is readable from windows PC. Next thing is why the above line does not read it? Probably it needs to do register to Virtual File System (VFS), If so, then after "esp_vfs_fat_sdspi_mount"? line#37 do I have to do "esp_vfs_fat_register" to make it work? Can anyone advice here please?

#define MOUNT_POINT "/sdcard"
....
1   void mount_sdcard(){    
2       esp_err_t ret;
3       esp_vfs_fat_sdmmc_mount_config_t mount_config = {
4       #ifdef CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED
5               .format_if_mount_failed = true,
6       #else
7               .format_if_mount_failed = false,
8       #endif // EXAMPLE_FORMAT_IF_MOUNT_FAILED
9               .max_files = 5, .allocation_unit_size = 16 * 1024
10          };
11          sdmmc_card_t* card;
12          const char mount_point[] = MOUNT_POINT;
13          ESP_LOGI(TAG, "Initializing SD card");
14      #ifndef USE_SPI_MODE
15          ESP_LOGI(TAG, "Using SDMMC peripheral");
16          sdmmc_host_t host = SDMMC_HOST_DEFAULT();
17          sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
18      
19          // GPIOs 15, 2, 4, 12, 13 should have external 10k pull-ups.
20          gpio_set_pull_mode(15, GPIO_PULLUP_ONLY);   // CMD, needed in 4- and 1- line modes
21          //... omitted for brevity
22          gpio_set_pull_mode(13, GPIO_PULLUP_ONLY);   // D3, needed in 4- and 1-line modes
23          ret = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &card);
24      #else
25          ESP_LOGI(TAG, "Using SPI peripheral");
26      
27          sdmmc_host_t host = SDSPI_HOST_DEFAULT();
28          spi_bus_config_t bus_cfg = {  .mosi_io_num = PIN_NUM_MOSI,.miso_io_num = PIN_NUM_MISO,.sclk_io_num = PIN_NUM_CLK,.quadwp_io_num = -1, .quadhd_io_num = -1, .max_transfer_sz = 4000,  };
29          ret = spi_bus_initialize(host.slot, &bus_cfg, SPI_DMA_CHAN);
30          if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to initialize bus.");return;   }
31      
32          // This initializes the slot without card detect (CD) and write protect (WP) signals.
33          // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
34          sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
35          slot_config.gpio_cs = PIN_NUM_CS;slot_config.host_id = host.slot;
36      
37          ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card);
38      #endif //USE_SPI_MODE
39      
40          if (ret != ESP_OK) {   //...
41              return;
42          }
43      
44          // Card has been initialized, print its properties
45          sdmmc_card_print_info(stdout, card);
46  }

You need to understand what you are doing before doing anything.

You are using the ESP32 HTTP Server API. Have you checked its documentation ? It even has an example program.

Now, you have registered a handler for some URI. It probably looks something like this? :) (Or perhaps you changed the uri.)

static const httpd_uri_t hello = {
    .uri       = "/hello",
    .method    = HTTP_GET,
    .handler   = hello_get_handler,
    /* Let's pass response string in user
     * context to demonstrate it's usage */
    .user_ctx  = NULL 
};

...

httpd_register_uri_handler(server, &hello);

Which means that if your server receives a HTTP GET request for /hello, your program calls the hello_get_handler() which then responds with the HTML document you have written in your handler.

The HTML document is all there. The browser only receives the text you send, nothing more. See the source code in your browser. In other words the src=\"/sdcard/fnb1.jpg\" is not replaced with the image at this point (or ever).

The <img> tag/element is just an instruction for the browser to display the resource pointed by 'src' at that place, with the given parameters. The 'src' could even be a resource on another server, like for example:

<img src=\"http://cdn.sstatic.net/Img/teams/teams-illo-free-sidebar-promo.svg\">

(Try it with some known address to an image.) An exception: the image could also be a Base64 encoded string of the entire image file. However it cannot be the actual file itself ie the jpeg as a binary blob. If you really want to embed the image to the document, you could use the Base64 approach , but that's not what you are trying to do here.

So to reiterate, the image itself is not transferred here . Only the HTML code describing the image element. Pure text.

The browser will make a separate HTTP GET request for the image resource itself. You have defined a relative URI, so the browser tries to get it from <your_server>/sdcard/fnb1.jpg .

Your code doesn't have a handler capable of responding to the GET, so the image is not displayed.

So once more, let's assume your ESP32 gets the IP 192.168.1.42, this is basically what happens: 交易的简化示例

So what you need to do is implement and register another handle that can serve the image as well. At this point it can be a handler that handlers the one image specifically. Just make up some URI and embed it to your <img> . The URI can of course remain as /sdcard/fnb1.jpg - it doesn't matter. Just understand that this is the URI in your HTTP server. It has no relation at all to the filesystem path for your image in the SD card.

Respond with a HTTP 200 OK response, with at least the header 'content-type: image/jpeg'. As per the documentation of httpd_resp_send :

... If no status code and content-type were set, by default this will send 200 OK status code and content type as text/html. ... httpd_resp_set_type() - for setting the Content Type...

So only the content type needs to be set by you ( "image/jpeg" ).

Once again: You need to define a response handler that can handle the GET request to your image. At minimum it can be a hardcoded URI to the one specific image. In the handler you need to use httpd_resp_send to send the file from the SD card (or wherever) and set the content-type header to be "image/jpeg" with httpd_resp_set_type . So something like:

static const httpd_uri_t img_example = {
    .uri       = "/img/example.jpg",
    .method    = HTTP_GET,
    .handler   = img_example_get_handler,
    .user_ctx  = NULL 
};

static esp_err_t img_example_get_handler(httpd_req_t *req)
{
  // 1. get a pointer to your image file
  // 2. httpd_resp_set_type to set the correct content type header
  //    esp_err_t httpd_resp_set_type(httpd_req_t *r, const char *type)
  //      Parameters
  //        [in] r: The request being responded to
  //        [in] type: The Content Type of the response
  // 3. httpd_resp_send to send the response, with the image file as buf
  //    esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, ssize_t buf_len)
  //      Parameters
  //        [in] r: The request being responded to
  //        [in] buf: Buffer from where the content is to be fetched
  //        [in] buf_len: Length of the buffer, HTTPD_RESP_USE_STRLEN to use strlen()

  return ESP_OK;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM