PlatformIO Community

Png-files in SPIFFS using in HTML

I would like to show a picture in HTML wich resides in SPIFFS.
I tried:
<img src=spiffss, ‘BulbOn.png’ alt=‘BulbOn’>

Any idea ?

as a source you just specify a filename, say, “BulbOn.png”. The WebServer library for ESP32 then has a general way of resolving a filename, or any path which is not explictily registered, to grab that from SPIFFS.


What I tried was not displayed correctly

Below my snippet:

      client.println("    <img src='BulbOn.png' alt='BulbOn'>");
      client.println("    <img src='/spiffs/BulbOn.png' alt='BulbOn'>");
      client.println("    <img src= SPIFFS, '/BulbOn.png' alt='BulbOn'>");

How can i refer to a file in spiffs from HTML ?

Any idea ?

Just use their bare filename, BulbOn.png, it’s the easiest way. The code and library above will look in the root of the SPIFFS partition (which technically is /spiffs) and find the file in there if it exists. No need to give it the full path.


Sorry, I can’t get it work.
At start of my program I list the content of spiffs:
FILE: /BulbOff.png
FILE: /BulbOn.png

By viewing the webpage I can see the placeholder.
Examining the link of this: “

I really appriciate your help,


The correct workings of this depends on the code and used libraries. Please show your platformio.ini and your code.

How to send my source-files to you ?

You can just post them here, formatted as Code in Markdown, along with the platformio.ini.

My platformio.ini:

; PlatformIO Project Configuration File
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
; Please visit documentation for the other options and examples

platform = espressif32
board = esp32doit-devkit-v1
framework = arduino
lib_deps = adafruit/Adafruit BME280 Library@^2.2.2

My code:

  Board:  ESP32 DevKit ESP32-WROOM
  BME280: GPIO22 = SCL;  GPIO21 = SDA;  I2c-address = 0x76

// Load Wi-Fi library
#include <WiFi.h>
#include <Wire.h>
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
#include <SPIFFS.h>

Adafruit_BME280 bme; // I2C

// Replace with your network credentials
const char* ssidH     = "HenksKamer";
const char* passwordH = "XXXXXXXXXXXXX";
const char* ssidR     = "Rijpaard";
const char* passwordR = "XXXXXXXXXXXXXXXX";

// Set web server port number to 80
WiFiServer server(80);

// Variable to store the HTTP request
String header;

// Auxiliar variables to store the current output State
String Led_Groen_Stat = "uit";
String Led_Rood_Stat = "uit";

// Assign GPIO pins
const int Led_Groen = 26;
const int Led_Rood = 27;
const int Switch_Ssid = 14;

// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0; 
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;

void listAllFilesInSPIFFS() {
  Serial.println("SPIFFS File list: ");
  File root ="/");
  File file = root.openNextFile();
  while(file) {
    Serial.print("FILE: ");
    file = root.openNextFile();
  Serial.println(" Done.");

void Format_SPIFFS() {
  Serial.print("SPIFFS Formatting ...");

void setup() {

  // Initialize I/O
  pinMode(Led_Groen, OUTPUT);
  pinMode(Led_Rood, OUTPUT);
  pinMode(Switch_Ssid, INPUT_PULLUP);
  digitalWrite(Led_Groen, LOW);
  digitalWrite(Led_Rood, LOW);

if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  if (digitalRead(Switch_Ssid) == HIGH) {
    WiFi.begin(ssidH, passwordH);
  else {
    WiFi.begin(ssidR, passwordR);
  while (WiFi.status() != WL_CONNECTED) {
  // Print local IP address and start web server
  Serial.println("WiFi connected.");
  Serial.print("IP address: ");

  if(!SPIFFS.begin()) {
    Serial.println("An Error has occurred while mounting SPIFFS");

void loop(){
  WiFiClient client = server.available();   // Listen for incoming clients

  if (client) {                             // If client connects,
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("New Client.");          // print a message out in the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected() && currentTime - previousTime <= timeoutTime) {  // loop while the client's connected
      currentTime = millis();
      if (client.available()) {             // if there are bytes to read from the client,
        char c =;             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Connection: close");
            // turns the GPIOs aan en uit
            if (header.indexOf("GET /Groen/aan") >= 0) {
              Serial.println("Groen aan");
              Led_Groen_Stat = "aan";
              digitalWrite(Led_Groen, HIGH);
            } else if (header.indexOf("GET /Groen/uit") >= 0) {
              Serial.println("Groen uit");
              Led_Groen_Stat = "uit";
              digitalWrite(Led_Groen, LOW);
            } else if (header.indexOf("GET /Rood/aan") >= 0) {
              Serial.println("Rood aan");
              Led_Rood_Stat = "aan";
              digitalWrite(Led_Rood, HIGH);
            } else if (header.indexOf("GET /Rood/uit") >= 0) {
              Serial.println("Rood uit");
              Led_Rood_Stat = "uit";
              digitalWrite(Led_Rood, LOW);

            // Display the HTML web page
            client.println("<!DOCTYPE html>");
            // Web Page Heading
            client.println("  <head>");
            client.println("    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("    <link rel=\"icon\" href=\"data:,\">");
            // CSS to style the aan/uit buttons 
            client.println("    <style>");
            client.println("      html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
            client.println("      .button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
            client.println("      text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
            client.println("      .button2 {background-color: #555555;}");
            client.println("    </style>");
            client.println("  </head>");
            client.println("  <body>");
            client.println("    <h1>ESP32 with BME280 en aan/uit buttons</h1>");
          client.println("    <p><img src='BulbOn.png'</p>");
//          client.println("    <p><img src='/BulbOn.png' alt='BulbOn'></p>");
            client.println("    Temperatuur = ");
            client.println(     bme.readTemperature());
            client.println("    Celsius");  
            // Display current Stat, and aan/uit buttons for GPIO 26  
            client.println("    <p>Groen " + Led_Groen_Stat + "</p>");
            // If the Led_Groen_Stat is uit, it displays the aan button       
            if (Led_Groen_Stat=="uit")
              client.println("  <p><a href=\"/Groen/aan\"><button class=\"button\">AAN</button></a></p>");
              client.println("  <p><a href=\"/Groen/uit\"><button class=\"button button2\">UIT</button></a></p>");
            // Display current Stat, and aan/uit buttons for GPIO 27  
            client.println("    <p>Rood " + Led_Rood_Stat + "</p>");
            // If the Led_Rood_Stat is uit, it displays the ON button       
            if (Led_Rood_Stat=="uit")
              client.println("  <p><a href=\"/Rood/aan\"><button class=\"button\">AAN</button></a></p>");
              client.println("  <p><a href=\"/Rood/uit\"><button class=\"button button2\">UIT</button></a></p>");
            client.println("  </body>");
            // The HTTP response ends with another blank line
            break; // Break out of the while loop
          else { 
            currentLine = "";
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
    // Clear the header variable
    header = "";
    // Close the connection
    Serial.println("Client disconnected.");

Looks like you didn’t close the img tag… missing a “>” character after the file name.

I don’t see anything in the server code that would handle the URL:

It handles these URLs:

Nothing that says what to do with “BulbOn.png” like a
server.streamFile(file, contentType);
or something.

Also adding:
server.on(); and server.onNotFound(); would be useful…

@devon_heron: You are right but inserting the “>” did not help.

@solaria8: No, You are right, that code is not implemented.
Lower in the code, where the HTML-page resides, is an outdented line which should reflect my test.

I strongly suggest against using the raw WiFiSever and WiFIClient classes to implement a HTTP server. This is 1. extremely error prone and 2. waaaay to complicated to implement once the logic grows bigger. You should use the WebServer.h library I’ve linked above through which you can construct a WebServer server(80); object and handle HTTP requests, especially those which can then be routed to the SPIFFS, more easily.

I can also create a reference project.

Do you mean this?

All that does is tell the client (your browser) to send a request to URL’ for an image. The server needs to do something with that request. Something like this should work:

void httpDownload() {
  File capture = SDcardOpen("BulbOn.png");
  server.streamFile(capture, "image/png");


…assuming server.on ("BulbOn.png", httpDownload);

edit: except using SPIFFS instead of SDcard…

Still not found a solution about:

Why will show up flat text:
client.println(" <p>Led_Rood uit</p>");
and why does not show a image from spiffs root:
client.println(" <p><img src='BulbOff.png'></p>");

<p> is just a paragraph text with plain text inside. (If you don’t do special CSS styling with it).

You need to have code logic that handles a request to the PNG file.

Let me construct a quick example of how things should be done with the library I mentioned.