Help! Web server + Ajax + XML + JPG

Hello,
I have found an interesting article: web server for arduino:

but i am noob with arduino and i have problem to associate the different parts.
I want to associate the example part 15 (analog value on gauge) with example part 11 (web page image).
I try this with no result.
Arduino code:

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

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

// MAC address from Ethernet shield sticker under board
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 7, 83); // IP address, may need to change depending on network
EthernetServer server(80);  // create a server at port 80
File webFile;               // the web page file on the SD card
//File imageFile;
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++;
                }
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    // send a standard http response header
                    client.println("HTTP/1.1 200 OK");
                    // remainder of header follows below, depending on if
                    // web page or XML page is requested
                    // Ajax request - send XML file
                    if (StrContains(HTTP_req, "ajax_inputs")) {
                        Serial.println("open Ajax"); 
                        // send rest of HTTP header
                        client.println("Content-Type: text/xml");
                        client.println("Connection: keep-alive");
                        client.println();
                        // send XML file containing input states
                        XML_response(client);
                    }                    
                    else if (StrContains(HTTP_req, "GET /back.jpg")) {
                      Serial.println("open jpg *************");  
                      webFile = SD.open("back.jpg");
                        if (webFile) {
                          client.println();
                          
                          client.write(webFile.read());
                          /*  
                          while(webFile.available()) {
                              client.write(webFile.read());
                              Serial.println("jpg download");
                          }*/
                          
                          webFile.close();
                        }             
                        Serial.println("close jpg");  
                    }
                    else {  // web page request
                        // send rest of HTTP header
                        Serial.println("open html"); 
                        client.println("Content-Type: text/html");
                        client.println("Connection: keep-alive");
                        client.println();
                        // send web page
                        webFile = SD.open("index.htm");        // open web page file
                        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)
}

// send the XML file containing analog value
void XML_response(EthernetClient cl)
{
    int analog_val;
    
    cl.print("<?xml version = \"1.0\" ?>");
    cl.print("<inputs>");
    // read analog pin A2
    analog_val = analogRead(2);
    cl.print("<analog>");
    cl.print(analog_val);
    cl.print("</analog>");
    cl.print("</inputs>");
}

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

I have take the same html code from example and added a repeat background.
http://startingelectronics.com/tutorials/arduino/ethernet-shield-web-server-tutorial/SD-card-gauge/Arduino_web_gauge.zip
I cant see my background :0
Anybody can help me, please.

You appear to be saying that your changed something in the HTML and now the page doesn't display as you expect.

Did you try it with the original unmodified code, and if so did it work OK. If you have not tried unmodified code I suggest you go back and try that first.

If it works with the old code but not with your new HTML, then the fault is in your HTML

Get your HTML working outside of the arduino first, and when you know its all OK then put it on your SD card.
Debugging HTML problems by repeatedly having to take the SD card in and out of the Arduino is not going to be an efficient way to debug.

yes I have changed the html code. I just added a background image with Dremweaver and tested in my explorer, no problem with this. I put image in same folder.
I think the problem coming from my merged arduino code.
I added and try this:

else if (StrContains(HTTP_req, "GET /back.jpg")) {
                      Serial.println("open jpg *************");  
                      webFile = SD.open("back.jpg");
                        if (webFile) {
                          client.println();                 
                          client.write(webFile.read());     
                          webFile.close();
                        }             
                        Serial.println("close jpg");  
                    }

And also this:

else if (StrContains(HTTP_req, "GET /back.jpg")) {
                      Serial.println("open jpg *************");  
                      webFile = SD.open("back.jpg");
                        if (webFile) {
                          client.println(); 
                          while(webFile.available()) {
                              client.write(webFile.read());
                              Serial.println("jpg download");
                          }           
                          webFile.close();
                        }             
                        Serial.println("close jpg");  
                    }

But I do not see background picture with my arduino !
I think problem coming from wrong html sending message for picture ??

I think problem coming from wrong html sending message for picture ??

I think it's more likely that you are not sending a picture (correctly) in response to the right request. Where is the rest of your code? Where is your serial output? How are you sure that "GET /back.jpg" is the correct string to trigger sending the picture?

Sending the picture one byte per packet (every client.write() sends a packet) is horridly inefficient. You can read more than one byte from the file at a time, and you can send more than one byte at a time to the client. Look for zoomkat's code for sending pictures far more efficiently than you are.

@PaulS I was just about to suggest the same thing

@thedaverman check that the server will serve the file back.jpg

This also sounds a bit like the problem I have with some web server code I wrote, because modern browsers request the images before the html page has finished downloading, its possible for the requests for the linked files get lost because the Arduino is busy sending the original page.

I need to rewrite my own web server to stop this happening, but I've not got around to it yet :frowning:
But at least I know why mine is not working :wink:

you left out the http header for you image

client.println("HTTP/1.1 200 OK");
client.println();

check the example carefully.

Also, you do know that your html will take forever to load with an image right? The arduino is a very simple server not a proper one.

Thank you very much for your answers.
Now it works more or less. The size of my image was too large (280kb), now with a picture of 80Kb it working but it takes more than 10 minutes to download the picture.
So there is a problem because my html file is 12kb size and download it in a second.
Why is it so long to download it ???

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

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

// MAC address from Ethernet shield sticker under board
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 7, 83); // IP address, may need to change depending on network
EthernetServer server(80);  // create a server at port 80
File webFile;               // the web page file on the SD card
//File imageFile;
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++;
                }
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    // send a standard http response header
                    client.println("HTTP/1.1 200 OK");
                    // remainder of header follows below, depending on if
                    // web page or XML page is requested
                    // Ajax request - send XML file
                    if (StrContains(HTTP_req, "ajax_inputs")) {
                        Serial.println("open Ajax"); 
                        // send rest of HTTP header
                        client.println("Content-Type: text/xml");
                        client.println("Connection: keep-alive");
                        client.println();
                        // send XML file containing input states
                        XML_response(client);
                    }                    
                    else if (StrContains(HTTP_req, "GET /back.jpg")) {
                      Serial.println("open jpg *************");  
                      webFile = SD.open("back.jpg");
                        if (webFile) {
                          client.println();
                          while(webFile.available()) {
                              client.write(webFile.read());
                              Serial.println("jpg download");
                          }        
                          webFile.close();
                        }             
                        Serial.println("close jpg");  
                    }
                    else {  // web page request
                        // send rest of HTTP header
                        Serial.println("open html"); 
                        client.println("Content-Type: text/html");
                        client.println("Connection: keep-alive");
                        client.println();
                        // send web page
                        webFile = SD.open("index.htm");        // open web page file
                        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)
}

// send the XML file containing analog value
void XML_response(EthernetClient cl)
{
    int analog_val;
    
    cl.print("<?xml version = \"1.0\" ?>");
    cl.print("<inputs>");
    // read analog pin A2
    analog_val = analogRead(2);
    cl.print("<analog>");
    cl.print(analog_val);
    cl.print("</analog>");
    cl.print("</inputs>");
}

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

Like I said, the arduino is not a computer. It's only a little micro controller. Deal without images or pull the images off the web, not the SD card.

You can also get more than one byte at a time from your sd card. That should help speed things up a little. The code is around somewhere.

Ok, but I do not understand why he take 5 minutes for 18KBytes of binary (picture) and 1 or 2 secondes for 12KBytes of text (my HTML code go fast and take 12kb) ???
I try to play on "REQ_BUF_SZ" but with no success.
There is also a long time before the explorer start to take the picture: 10 to 20 secondes !!!

Do you have an example to take more than one byte at a time.

 byte tBuf[64] = {0};
        int clientCount = 0;
    
        File myFile = SD.open(page);        // open web page file
        if (myFile) {
                 while(myFile.available()) {
                        tBuf[clientCount] = myFile.read();
                        clientCount++;
                        if(clientCount > 63) {
                          client.write((byte*)tBuf,64);
                          clientCount = 0;
                          memset(&tBuf[0], 0, 64);
                        }
    
                }
                      if(clientCount > 0) {
                        client.write((byte*)tBuf,clientCount);
                      }
            memset(&tBuf[0], 0, 64);
            myFile.close();
        }

@mistergreen

I'm curious why you are using

memset(&tBuf[0], 0, 64);

in several places. It seems redundant to me ??

I don't see any point of initilalising the array with a single zero either.

 byte tBuf[64] = {0};

As you code doesn't rely on the array ever being initialized with zeros (as far as I can tell)

Ok, but I do not understand why he take 5 minutes for 18KBytes of binary (picture) and 1 or 2 secondes for 12KBytes of text (my HTML code go fast and take 12kb) ???

The reason is that the below line transmits only one byte of the picture at a time, along with all the tcp/ip packet overhead for each picture byte sent. Bottom is some test code that collects the bytes read from the SD disk into a 64 byte packet, then sends the packet as one tcp/ip packet. Should be about four times faster than single bytes.

client.write(webFile.read()); // send web page to client

packet code

//zoomkat 12/26/12
//SD server test code
//open serial monitor to see what the arduino receives
//address will look like http://192.168.1.102:84 when submited
//for use with W5100 based ethernet shields

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 102 }; // ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(84); //server port
String readString; 

//////////////////////

void setup(){

  Serial.begin(9600);

  // disable w5100 while setting up SD
  pinMode(10,OUTPUT);
  digitalWrite(10,HIGH);
  Serial.print("Starting SD..");
  if(!SD.begin(4)) Serial.println("failed");
  else Serial.println("ok");

  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  //delay(2000);
  server.begin();
  Serial.println("Ready");
}

void loop(){
  // Create a client connection
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //read char by char HTTP request
        if (readString.length() < 100) {
          //store characters to string 
          readString += c; 
          //Serial.print(c);
        } 
        //if HTTP request has ended
        if (c == '\n') {

          ///////////////
          Serial.println(readString); //print to serial monitor for debuging 

          client.println("HTTP/1.1 200 OK"); //send new page
          client.println("Content-Type: image/jpeg");
          client.println();

          File myFile = SD.open("HYPNO.JPG");

          if (myFile) {

            byte clientBuf[64];
            int clientCount = 0;

            while(myFile.available())
            {
              clientBuf[clientCount] = myFile.read();
              clientCount++;

              if(clientCount > 63)
              {
                // Serial.println("Packet");
                client.write(clientBuf,64);
                clientCount = 0;
              }
            }
            //final <64 byte cleanup packet
            if(clientCount > 0) client.write(clientBuf,clientCount);            
            // close the file:
            myFile.close();
          }
          delay(1);
          //stopping client
          client.stop();
          readString="";
        }
      }
    }
  } 
}

Thank you very much for your support.
Now he working nice. I am very happy with the resulting time.

I share the resulting code for community:

/*--------------------------------------------------------------
  Program:      eth_websrv_SD_Ajax_gauge

  Description:  Arduino web server web page displays Arduino
                analog value on a dial gauge.
                The web page is stored on the SD card.
                Ajax is used to update the analog value on the
                web page.
  
  Hardware:     Arduino Uno and official Arduino Ethernet
                shield. Should work with other Arduinos and
                compatible Ethernet shields.
                2Gb micro SD card formatted FAT16.
                Potentiometer interfaced to A2 analog input.
                
  Software:     Developed using Arduino 1.0.5 software
                Should be compatible with Arduino 1.0 +
                SD card contains web page called index.htm
  
  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
                - Gauge from:
                  https://github.com/Mikhus/canv-gauge

  Date:         27 March 2013
  Modified:     19 June 2013
                20 June 2014    Beker D.
 
  Author:       W.A. Smith, http://startingelectronics.com
--------------------------------------------------------------*/


#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, 7, 83); // IP address, may need to change depending on network
EthernetServer server(80);  // create a server at port 80
File webFile;               // the web page file on the SD card
//File imageFile;
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++;
        }
        // last line of client request is blank and ends with \n
        // respond to client only after last line received
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          Serial.println(HTTP_req);
          // Ajax request - send XML file
          if (StrContains(HTTP_req, "ajax_inputs&no")) { 
            // send rest of HTTP header
            client.println("Content-Type: text/xml");
            client.println("Connection: keep-alive");
            client.println();
            // send XML file containing input states
            XML_response(client);
            Serial.println("send Ajax");
          }                 
          else if (StrContains(HTTP_req, "GET /back.jpg")) {
            Serial.println("open jpg");  
            webFile = SD.open("back.jpg");
            delay(100);
            if (webFile) {
              client.println();

              byte clientBuf[64];
              int clientCount = 0;

              while(webFile.available())
              {
                clientBuf[clientCount] = webFile.read();
                clientCount++;

                if(clientCount > 63)
                {
                  // Serial.println("Packet");
                  client.write(clientBuf,64);
                  clientCount = 0;
                }
              }
              //final <64 byte cleanup packet
              if(clientCount > 0) client.write(clientBuf,clientCount);            
              // close the file:
              webFile.close();
              Serial.println("close jpg");
            }
            delay(1);                                       
          }
          else {  // web page request
            // send rest of HTTP header
            Serial.println("*** open html"); 
            client.println("Content-Type: text/html");
            client.println("Connection: keep-alive");
            client.println();
            // send web page
            webFile = SD.open("index.htm");        // open web page file
            if (webFile) {
              while(webFile.available()) {
                client.write(webFile.read()); // send web page to client                         
              }
              webFile.close();
              Serial.println("close html webfile"); 
            }                     
          }
          // 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)
}

// send the XML file containing analog value
void XML_response(EthernetClient cl)
{
  int analog_val;

  cl.print("<?xml version = \"1.0\" ?>");
  cl.print("<inputs>");
  // read analog pin A2
  analog_val = analogRead(2);
  cl.print("<analog>");
  cl.print(analog_val);
  cl.print("</analog>");
  cl.print("</inputs>");
}

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

Thanks a lot.