Go Down

Topic: Loading a picture from SD card to a webpage (Read 7 times) previous topic - next topic

Arm11

Could you advice me, how it's possible to load a picture from SD card to a webpage?

I have tried to make the web with Ethernet library and sdfatlib according to the basic Adafruit's tutorial:

Thanks in advance,
Jiri

robtillaart

Do you have some code to share or the URL of the Tutorial?
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

pluggy

Kind of like emptying a bucket with a drinking straw  to transfer it to an external webpage using an arduino.  Seriously slow (geological time) if the arduino is hosting the website......
http://pluggy.is-a-geek.com/index.html

Arm11

I am using Arduino Mega and a new Ethernet Shield with MicroSD card.
There is my code from a tutorial:

Code: [Select]

// Tutorial is at http://www.ladyada.net/learn/arduino/ethfiles.html

#include <SdFat.h>       // Sdfatlib20101010
#include <SdFatUtil.h>
#include <Ethernet.h>
#include <SPI.h>
/************ ETHERNET STUFF ************/
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x22, 0x54 };
byte ip[] = { 192, 168, 24, 22 };
Server server(80);

/************ SDCARD STUFF ************/
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

// store error strings in flash to save RAM
#define error(s) error_P(PSTR(s))

void error_P(const char* str) {
 PgmPrint("error: ");
 SerialPrintln_P(str);
 if (card.errorCode()) {
   PgmPrint("SD error: ");
   Serial.print(card.errorCode(), HEX);
   Serial.print(',');
   Serial.println(card.errorData(), HEX);
 }
 while(1);
}

void setup() {
 Serial.begin(57600);

 PgmPrint("Free RAM: ");
 Serial.println(FreeRam());  
 
 
 // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
 // breadboards.  use SPI_FULL_SPEED for better performance.
 pinMode(10, OUTPUT);                       // set the SS pin as an output (necessary!)
 digitalWrite(10, HIGH);                    // but turn off the W5100 chip!

 if (!card.init(SPI_HALF_SPEED, 4)) error("card.init failed!");
 
 // initialize a FAT volume
 if (!volume.init(&card)) error("vol.init failed!");

 PgmPrint("Volume is FAT");
 Serial.println(volume.fatType(),DEC);
 Serial.println();
 
 if (!root.openRoot(&volume)) error("openRoot failed");

 // list file in root with date and size
 PgmPrintln("Files found in root:");
 root.ls(LS_DATE | LS_SIZE);
 Serial.println();
 
 // Recursive list of all directories
 PgmPrintln("Files found in all dirs:");
 root.ls(LS_R);
 
 Serial.println();
 PgmPrintln("Done");
 
 // Debugging complete, we start the server!
 Ethernet.begin(mac, ip);
 server.begin();
}
 
void loop()
{
 Client client = server.available();
 if (client) {
   // an http request ends with a blank line
   boolean current_line_is_blank = true;
   while (client.connected()) {
     if (client.available()) {
       char c = client.read();
       // if we've gotten to the end of the line (received a newline
       // character) and the line is blank, the http request has ended,
       // so we can send a reply
       if (c == '\n' && current_line_is_blank) {
         // send a standard http response header
         client.println("HTTP/1.1 200 OK");
         client.println("Content-Type: text/html");
         client.println();
         
       client.println("<h2>Picture:</h2>");
                 
         //================ PROBLEM HERE ==================
 // I need make something like this      
       client.print("<img src='pict1.gif'>");    
         
         
         // print all the files, use a helper to keep it clean
         //ListFiles(client, 0);
         client.println("<h2>Files:</h2>");
         ListFiles(client, 0);
         
         break;
       }
       if (c == '\n') {
         // we're starting a new line
         current_line_is_blank = true;
       } else if (c != '\r') {
         // we've gotten a character on the current line
         current_line_is_blank = false;
       }
     }
   }
   // give the web browser time to receive the data
   delay(1);
   client.stop();
 }
}  
 
 
 void ListFiles(Client client, uint8_t flags) {
 // This code is just copied from SdFile.cpp in the SDFat library
 // and tweaked to print to the client output in html!
 dir_t p;
 
 root.rewind();
 while (root.readDir(p) > 0) {
   // done if past last used entry
   if (p.name[0] == DIR_NAME_FREE) break;

   // skip deleted entry and entries for . and  ..
   if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue;

   // only list subdirectories and files
   if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;
 

   // print file name with possible blank fill
   //root.printDirName(*p, flags & (LS_DATE | LS_SIZE) ? 14 : 0);


   for (uint8_t i = 0; i < 11; i++) {
     if (p.name[i] == ' ') continue;
     if (i == 8) {
       client.print('.');
     }
     client.print(p.name[i]);
   }
   if (DIR_IS_SUBDIR(&p)) {
     client.print('/');
   }

   // print modify date/time if requested
   if (flags & LS_DATE) {
      root.printFatDate(p.lastWriteDate);
      client.print(' ');
      root.printFatTime(p.lastWriteTime);
   }
   // print size if requested
   if (!DIR_IS_SUBDIR(&p) && (flags & LS_SIZE)) {
     client.print(' ');
     client.print(p.fileSize);
   }
   client.println("<br>");
 }
}
 



Kevin Kibbe

But... that doesn't work of course. Anyone with that tiny tiny bit extra that gets the picture onto the web page?

Kevin

Imahilus

#5
Dec 04, 2010, 12:10 am Last Edit: Dec 04, 2010, 12:12 am by Imahilus Reason: 1
Check whether the page being loaded ends with the image extension, if so.. send the headers for image content and send the image as binary data.
Include the image in the page like you normally do for a webpage (tip: relative links are your friend).

Keep in mind that it may indeed be slow, but this does depend a bit on the image.
Tiny icons may be allright, though anything larger than a smiley will probably be too large to transfer through an arduino.

MrFreeze

I've been working on this same problem, and finally got it to work.  The answer lies in defining the correct content type in your code, like this:

Code: [Select]

        client.println("HTTP/1.1 200 OK");
         if (strstr(filename, ".htm") != 0)
            client.println("Content-Type: text/html");
        else if (strstr(filename, ".jpg") != 0)
            client.println("Content-Type: image/jpeg");
        else if (strstr(filename, ".gif") != 0)
            client.println("Content-Type: image/gif");
        else if (strstr(filename, ".3gp") != 0)
            client.println("Content-Type: video/mpeg");
        else
            client.println("Content-Type: text");
        client.println();

I think you should be able to extend this to any MIME type; you can find a comprehensive list with a little surfing.

With the above modification I can successfully load .jpg and .gif images from the SD card to a webpage.  It even works with videos several minutes in length (although this requires a long wait).

Assuming your .gif or .jpg files are stored in the root directory of your SD card, after modifying your sketch as shown above and uploading to the Arduino, your browser "get" request should be in the format 192.168.1.xxx/FILENAME.GIF, and the image should begin to load.

The full code is provided here:

Code: [Select]

#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <Ethernet.h>

/************ ETHERNET STUFF ************/
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 1, 177 };
char rootFileName[] = "index.htm";
Server server(80);

/************ SDCARD STUFF ************/
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

// store error strings in flash to save RAM
#define error(s) error_P(PSTR(s))

void error_P(const char* str) {
 PgmPrint("error: ");
 SerialPrintln_P(str);
 if (card.errorCode()) {
   PgmPrint("SD error: ");
   Serial.print(card.errorCode(), HEX);
   Serial.print(',');
   Serial.println(card.errorData(), HEX);
 }
 while(1);
}

void setup() {
 Serial.begin(115200);

 PgmPrint("Free RAM: ");
 Serial.println(FreeRam());  
 
 // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
 // breadboards.  use SPI_FULL_SPEED for better performance.
 pinMode(10, OUTPUT);                       // set the SS pin as an output (necessary!)
 digitalWrite(10, HIGH);                    // but turn off the W5100 chip!

 if (!card.init(SPI_HALF_SPEED, 4)) error("card.init failed!");
 
 // initialize a FAT volume
 if (!volume.init(&card)) error("vol.init failed!");

 PgmPrint("Volume is FAT");
 Serial.println(volume.fatType(),DEC);
 Serial.println();
 
 if (!root.openRoot(&volume)) error("openRoot failed");

 // list file in root with date and size
 PgmPrintln("Files found in root:");
 root.ls(LS_DATE | LS_SIZE);
 Serial.println();
   
 // Recursive list of all directories
 PgmPrintln("Files found in all dirs:");
 root.ls(LS_R);
 
 Serial.println();
 PgmPrintln("Done");
   
 // Debugging complete, we start the server!
 Ethernet.begin(mac, ip);
 server.begin();
}

// How big our line buffer should be. 100 is plenty!
#define BUFSIZ 100

void loop()
{

 char clientline[BUFSIZ];
 char *filename;
 int index = 0;
 int image = 0;
 
 Client client = server.available();
   if (client) {
   // an http request ends with a blank line
   boolean current_line_is_blank = true;
   
   // reset the input buffer
   index = 0;
   
     while (client.connected()) {
       if (client.available()) {
         char c = client.read();
         
       // If it isn't a new line, add the character to the buffer
       if (c != '\n' && c != '\r') {
         clientline[index] = c;
         index++;
         // are we too big for the buffer? start tossing out data
         if (index >= BUFSIZ)
           index = BUFSIZ -1;
           
         // continue to read more data!
         continue;
       }
         
       // got a \n or \r new line, which means the string is done
       clientline[index] = 0;
       filename = 0;
       
       // Print it out for debugging
       Serial.println(clientline);
       
       // Look for substring such as a request to get the root file
       if (strstr(clientline, "GET / ") != 0) {
         filename = rootFileName;
       }
       if (strstr(clientline, "GET /") != 0) {
         // this time no space after the /, so a sub-file
         
         if (!filename) filename = clientline + 5; // look after the "GET /" (5 chars)
         // a little trick, look for the " HTTP/1.1" string and
         // turn the first character of the substring into a 0 to clear it out.
         (strstr(clientline, " HTTP"))[0] = 0;
         
         // print the file we want
         Serial.println(filename);
         
         if (! file.open(&root, filename, O_READ)) {
           client.println("HTTP/1.1 404 Not Found");
           client.println("Content-Type: text/html");
           client.println();
           client.println("<h2>File Not Found!</h2>");
           break;
         }
         
         Serial.println("Opened!");
         
         client.println("HTTP/1.1 200 OK");
         if (strstr(filename, ".htm") != 0)
            client.println("Content-Type: text/html");
        else if (strstr(filename, ".css") != 0)
            client.println("Content-Type: text/css");
        else if (strstr(filename, ".png") != 0)
            client.println("Content-Type: image/png");
         else if (strstr(filename, ".jpg") != 0)
            client.println("Content-Type: image/jpeg");
        else if (strstr(filename, ".gif") != 0)
            client.println("Content-Type: image/gif");
        else if (strstr(filename, ".3gp") != 0)
            client.println("Content-Type: video/mpeg");
        else if (strstr(filename, ".pdf") != 0)
            client.println("Content-Type: application/pdf");
        else if (strstr(filename, ".js") != 0)
            client.println("Content-Type: application/x-javascript");
        else if (strstr(filename, ".xml") != 0)
            client.println("Content-Type: application/xml");
        else
            client.println("Content-Type: text");

         client.println();
         
         int16_t c;
         while ((c = file.read()) >= 0) {
             // uncomment the serial to debug (slow!)
             //Serial.print((char)c);
             client.print((char)c);
         }
         file.close();
       } else {
         // everything else is a 404
         client.println("HTTP/1.1 404 Not Found");
         client.println("Content-Type: text/html");
         client.println();
         client.println("<h2>File Not Found!</h2>");
          }
       break;
     }
   }
   // give the web browser time to receive the data
   delay(1);
   client.stop();
 }
}


Kevin Kibbe

MrFreeze

Thank you very much for the code and the time to answer. Very nice work!

Take care and enjoy the weekend.
Kevin
VA3SU

Arm11

Thanks everybody, especially MrFreeze, for your answers. I really appreciate it.
Jiri

Go Up