Starting Electronics Needs Your Help!
It is that time of the year when we need to pay for web hosting and buy new components and equipment for new tutorials. You can help by making a donation. Contribute to this website by clicking the Donate button. The total will be updated once daily. (You may need to clear your browser cache to see the updates.)

Target Amount: $2000
Amount Raised: $495

Donations Received

Top Donor: D.C. $30

X

Arduino SD Card Web Server – Displaying Images

Created on: 7 March 2013

Part 11 of the Arduino Ethernet Shield Web Server Tutorial

A page hosted by the Arduino web server on the SD card contains an image. This tutorial shows how to insert a JPEG image into a HTML web page and how to send the image to the web browser when an HTTP request for the image is received by the web server.

Uses the Arduino Uno with Ethernet shield and micro SD card.

This video shows the example for this part of the tutorial in operation:

Can't see the video? View on YouTube →

HTML for Displaying an Image

The HTML <img> tag is used to insert an image into a web page. The web pages from the previous part of this tutorial series are used again. The index.htm file is modified to add an image – the HTML for this file is shown below.

<!DOCTYPE html>
<html>
    <head>
        <title>Arduino SD Card Web Page</title>
    </head>
    <body>
        <h1>Arduino SD Card Page with Image and Link</h1>
        <img src="pic.jpg" />
        <p>Go to <a href="page2.htm">page 2</a>.</p>
    </body>
</html>

In the above HTML code, an image called pic.jpg is inserted into the web page using the following line of HTML code:

<img src="pic.jpg" />

The src attribute is used to specify the name of the image to display.

Source Code

The three files for this example can be downloaded and copied to a micro SD card that will be inserted into the card slot of the Arduino Ethernet shield.

SD_card_image.zip (8.2 kB) – contains index.htm, page2.htm and pic.jpg used in this part of the tutorial.

HTTP Requests

When connecting to the Arduino web server in this example, the web browser will first send an HTTP request to the server as normal. After the web browser has received the web page, it will find that the web page contains an image. It will then send a second HTTP request for the image.

Amazon.com

Amazon.co.uk

Arduino Sketch

The Arduino sketch for this example is called eth_websrv_SD_image and is shown below. It is a modified version of the sketch from the previous part of this tutorial series.

/*--------------------------------------------------------------
  Program:      eth_websrv_SD_image

  Description:  Arduino web server that serves up a basic web
                page that displays an image.
  
  Hardware:     Arduino Uno and official Arduino Ethernet
                shield. Should work with other Arduinos and
                compatible Ethernet shields.
                2Gb micro SD card formatted FAT16
                
  Software:     Developed using Arduino 1.0.5 software
                Should be compatible with Arduino 1.0 +
                
                Requires index.htm, page2.htm and pic.jpg to be
                on the micro SD card in the Ethernet shield
                micro SD card socket.
  
  References:   - WebServer example by David A. Mellis and 
                  modified by Tom Igoe
                - SD card examples by David A. Mellis and
                  Tom Igoe
                - Ethernet library documentation:
                  http://arduino.cc/en/Reference/Ethernet
                - SD Card library documentation:
                  http://arduino.cc/en/Reference/SD

  Date:         7 March 2013
  Modified:     17 June 2013
 
  Author:       W.A. Smith, http://startingelectronics.org
--------------------------------------------------------------*/

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>

// size of buffer used to capture HTTP requests
#define REQ_BUF_SZ   20

// MAC address from Ethernet shield sticker under board
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 20); // IP address, may need to change depending on network
EthernetServer server(80);  // create a server at port 80
File webFile;
char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
char req_index = 0;              // index into HTTP_req buffer

void setup()
{
    // disable Ethernet chip
    pinMode(10, OUTPUT);
    digitalWrite(10, HIGH);
    
    Serial.begin(9600);       // for debugging
    
    // initialize SD card
    Serial.println("Initializing SD card...");
    if (!SD.begin(4)) {
        Serial.println("ERROR - SD card initialization failed!");
        return;    // init failed
    }
    Serial.println("SUCCESS - SD card initialized.");
    // check for index.htm file
    if (!SD.exists("index.htm")) {
        Serial.println("ERROR - Can't find index.htm file!");
        return;  // can't find index file
    }
    Serial.println("SUCCESS - Found index.htm file.");
    
    Ethernet.begin(mac, ip);  // initialize Ethernet device
    server.begin();           // start to listen for clients
}

void loop()
{
    EthernetClient client = server.available();  // try to get client

    if (client) {  // got client?
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // client data available to read
                char c = client.read(); // read 1 byte (character) from client
                // buffer first part of HTTP request in HTTP_req array (string)
                // leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
                if (req_index < (REQ_BUF_SZ - 1)) {
                    HTTP_req[req_index] = c;          // save HTTP request character
                    req_index++;
                }
                // print HTTP request character to serial monitor
                Serial.print(c);
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    // open requested web page file
                    if (StrContains(HTTP_req, "GET / ")
                                 || StrContains(HTTP_req, "GET /index.htm")) {
                        client.println("HTTP/1.1 200 OK");
                        client.println("Content-Type: text/html");
                        client.println("Connnection: close");
                        client.println();
                        webFile = SD.open("index.htm");        // open web page file
                    }
                    else if (StrContains(HTTP_req, "GET /page2.htm")) {
                        client.println("HTTP/1.1 200 OK");
                        client.println("Content-Type: text/html");
                        client.println("Connnection: close");
                        client.println();
                        webFile = SD.open("page2.htm");        // open web page file
                    }
                    else if (StrContains(HTTP_req, "GET /pic.jpg")) {
                        webFile = SD.open("pic.jpg");
                        if (webFile) {
                            client.println("HTTP/1.1 200 OK");
                            client.println();
                        }
                    }
                    if (webFile) {
                        while(webFile.available()) {
                            client.write(webFile.read()); // send web page to client
                        }
                        webFile.close();
                    }
                    // reset buffer index and all buffer elements to 0
                    req_index = 0;
                    StrClear(HTTP_req, REQ_BUF_SZ);
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
}

// sets every element of str to 0 (clears array)
void StrClear(char *str, char length)
{
    for (int i = 0; i < length; i++) {
        str[i] = 0;
    }
}

// searches for the string sfind in the string str
// returns 1 if string found
// returns 0 if string not found
char StrContains(char *str, char *sfind)
{
    char found = 0;
    char index = 0;
    char len;

    len = strlen(str);
    
    if (strlen(sfind) > len) {
        return 0;
    }
    while (index < len) {
        if (str[index] == sfind[found]) {
            found++;
            if (strlen(sfind) == found) {
                return 1;
            }
        }
        else {
            found = 0;
        }
        index++;
    }

    return 0;
}

The sketch works the same way as the sketch from the previous part of this tutorial, except for the following code which handles the JPEG image:

 else if (StrContains(HTTP_req, "GET /pic.jpg")) {
    webFile = SD.open("pic.jpg");
    if (webFile) {
        client.println("HTTP/1.1 200 OK");
        client.println();
    }
}

This code checks to see if the HTTP request from the web browser is requesting the JPEG image pic.jpg.

If the request for the image is received and it can be opened from the SD card, a OK response is sent back to the web browser. The JPEG file is then sent using the same code that sends back an HTML page.

Again, as in the previous part of this tutorial, the code was made very basic for teaching purposes. It does not handle cases where the resource (HTML file or image file) can't be found on the SD card. It also specifically only handles an image with the name "pic.jpg".

For practical use, it would be better to obtain the requested HTML page name or image file name from the HTTP request and then try to find it on the SD card. Code should be in place to handle the case where the file can not be found on the SD card.

← Go back to Part 10Go to Part 12 →