esp32 http_server html how to show image from sd card

Solution 1:

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 i.e. 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: simplified example of the transaction

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;
}