Images over HTTP

I have a thermal printer and have managed to get it to print some simple bitmaps (converted using Processing bitmapImageConvert).

I’d like to create a HTML5 canvas element that will save an image into a format that the Arduino + Ethernet shield can request and then print.

I am capable of the HTML5 part, but am unsure of how to convert the canvas data (JPEG) into the image array, and then how to request/read this data over a web connection.

I guess the first test would be to try and create the image data with PHP and then see if I can manually copy that into an image.h file and load it with my exiting code. I don’t quite know how to convert this code:

  // Generate body of array
  for(i=n=y=0; y<img.height; y++) { // Each row...
    output.print("\n  ");
    for(x=0; x<rowBytes; x++) { // Each 8-pixel block within row...
      lastBit = (x < rowBytes - 1) ? 1 : (1 << (rowBytes * 8 - img.width));
      sum     = 0; // Clear accumulated 8 bits
      for(b=128; b>=lastBit; b >>= 1) { // Each pixel within block...
        if((img.pixels[i++] & 1) == 0) sum |= b; // If black pixel, set bit
      }
      output.format("0x%02X", sum); // Write accumulated bits
      if(++n < totalBytes) output.print(',');
    }
  }

Any advice would be welcome.
Thanks

I'm not sure I follow you - does the image originate in the web browser, or the web server? How does it get from there to the Arduino?

The below downloads slider1.jpg and spits it out (not all printable characters) to the serial monitor. The arduino can also upload image files from an SD card. Not sure just what you are looking for.

//zoomkat 9-22-12
//simple client test
//for use with IDE 1.0.1
//with DNS, DHCP, and Host
//open serial monitor and send an e to test
//for use with W5100 based ethernet shields
//remove SD card if inserted

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address

char serverName[] = "web.comporium.net"; // zoomkat's test web page server
EthernetClient client;

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

void setup(){

  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    while(true);
  }

  Serial.begin(9600); 
  Serial.println("Better client test 9/22/12"); // so I can keep track of what is loaded
  Serial.println("Send an e in serial monitor to test"); // what to do to test
}

void loop(){
  // check for serial input
  if (Serial.available() > 0) //if something in serial buffer
  {
    byte inChar; // sets inChar as a byte
    inChar = Serial.read(); //gets byte from buffer
    if(inChar == 'e') // checks to see byte is an e
    {
      sendGET(); // call sendGET function below when byte is an e
    }
  }  
} 

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

void sendGET() //client function to send/receive GET request data.
{
  if (client.connect(serverName, 80)) {  //starts client connection, checks for connection
    Serial.println("connected");
    client.println("GET /~shb//pix/slider1.jpg HTTP/1.0"); //download text
    client.println("Host: web.comporium.net");
    client.println(); //end of get request
  } 
  else {
    Serial.println("connection failed"); //error message if no client connect
    Serial.println();
  }

  while(client.connected() && !client.available()) delay(1); //waits for data
  while (client.connected() || client.available()) { //connected or data available
    char c = client.read(); //gets byte from ethernet buffer
    Serial.print(c); //prints byte to serial monitor 
  }

  Serial.println();
  Serial.println("disconnecting.");
  Serial.println("==================");
  Serial.println();
  client.stop(); //stop client

}

Hello, sorry for not being clear enough.

I want to create the image in my browser. I click save and this sends the image data back to my web server as base_64 encoded data. I want the server to convert this into image data (image.h).

The Arduino + Ethernet will be checking the server every few minutes for a new image. If one is available on the server, it will need to download the image data and output it to my thermal printer.

Forgive me if there is a better way to do this. I did wonder if I could download the original image and then have the Arduino process it before printing.

tl:dr - make arduino print image from interwebs on my thermal printer!

It sounds as if you have got some elements of this solution working, but I'm not clear what. Obviously it would make sense to build on them.

When you have printed images in the past, is this by connecting the thermal printer to the Arduino? If so, that implies that you know how to control the printer and know what image format it requires.

You mentioned the Arduino having an Ethernet interface. Are you envisaging hosting the web site on the Arduino? That would make things much harder. If it's practical to host the web app on a PC and then send printing commands and data to the Arduino, that would be better. And if you can make the PC/Arduino interface identical to the Arduino/printer interface so that the Arduino just acts as a bridge and doesn't need to store or convert large quantities of data, that would be even better.

I'm puzzled by your reference to 'image.h'. In the context of Arduino, the .h suffix implies a C/C++ header file. Do you mean this to be a binary data file containing an image, or is there something else implied here?

Hi Peter,

Sorry for still not being clear :~

I have the Arduino and thermal printer connected and I can print text and images from the “binary data file” that I create using a Processing sketch (pass in an image and it generates the binary data)

I would like to host the website on an external web server (not on the arduino or on my local network). I am able to use the Ethernet library and read data using GET.

At the moment, the Arduino is connected to my Mac (Internet sharing enabled) but I’d like it to be able to run standalone and not rely on scripts doing the grunt work.

Is this possible to do? Should I get PHP to process my image into binary data for the Arduino to read, or shall I make the Arduino do the work?

Thanks,
Alex

It sounds as if you have figured out how to convert the original image into a format that the printer will accept, and the only issue now is where to implement each part of that processing pipeline.

If you can connect the Arduino to the host that the web server is running on, the simplest option would be to create a web app which receives the base_64 encoded image and converts that to the command/data sequence that the printer requires, and send it to the Arduino via the USB serial connection. Presumably you already have a web app providing the HTML5 application and I'd aim to put this image handling/encoding in that.

If you don't have a USB connection available but do have an Ethernet connection then I'd use a similar architecture but send the command / data byte stream over a TCP socket (Arduino acting as TCP server, web app acting as TCP client).

So far you haven't mentioned any requirements relating to security or providing feedback about the status of the printer and jobs submitted to it, so I will assume there aren't any.

The solution above doesn't provide any buffering or flow control and would simply wait for the Arduino/printer to complete one job before it could accept the next one. If you want to implement some sort of spooling, I'd have the web app front end handler write the image to disk, and have a back-end thread that pulls jobs off the disk and sends them on to the Arduino as fast as the Arduino will accept them. That's more complicated, though, and you might want to leave that out of the first version.

Hi Peter, You are correct - the first thing I an stuck with is how to convert the image into the "data sequence".

The server is external so I can only send the data over a HTTP connection. Would I just use the Arduino to read in a start character like # and then read the image data sequence into a variable ready to print?

I think these are the 2 main parts that I am stuck with.

Your question is more a programming question than anything specifically Arduino. At any rate, converting a JPEG to a bitmap format will be quite difficult if not impossible.

The full blown JPEG library, which would typically be used to decode a jpeg, is 200KB compiled (won't fit!). The smallest library I'm aware of is nanojpeg which compiles to 6KB, but it won't work with all jpeg encoding formats (too many problems with incompatibility).

If you have control over the image file format you should use an XBM (black and white) or XPM (color) format. Both are non-binary formats (you can read them with a text editor) and would be compatible with any web browser. I believe the XBM format is nearly identical to what your thermal printer uses. Any decent image conversion utility should allow an XBM output, but if you're stuck I'd suggest ImageMagick.

I can convert the jpeg (or whatever other format) into a bitmap with little problem on the server using a couple of lines of PHP.

From my current thinking, I will do any image conversion / scaling etc on the server and then my Arduino will make a request for the next available block of image data.

My current sketch imports this image.h data file:

#ifndef _img_h_
#define _img_h_

#define img_width  75
#define img_height 75

static PROGMEM prog_uchar img_data[] = {
  0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0x00,0x00,0x00,
  ... several lines of this ...
  0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x00,0x00,0x00
};

I am using the Adafruit Thermal library - calling printer.printBitmap(img_width,img_height,img_data);

I need to work out how to:

  • Get PHP to generate this data
  • Get the Arduino to read this from an HTTP request and send it to the printer

I'll try and look at the Processing code (see first post) and attempt to convert this into a PHP script, but I'd really welcome any help with these two points.

Thanks

[quote author=Alex Holsgrove link=topic=161141.msg1207822#msg1207822 date=1366372529] You are correct - the first thing I an stuck with is how to convert the image into the "data sequence". [/quote]

I thought you had already solved that problem.

I can do the conversion using the Processing sketch (in my original post) but I want to convert this into PHP code somehow so that I can perform the conversion on my server rather than the Arduino. It would look like this:

== SERVER == HTML Canvas -> base_64 encoded jpeg -> PHP script -> "image data sequence" -> store on server

== Arduino == Makes a request to the server and receives the "image data sequence" and then sends this to the thermal printer.

So your only remaining problem is porting that (Java-ish) image processing code to PHP? PHP supports similar control structures so it shouldn't be too hard to port it.

Yes - but that is what I am stuck with. I got most of the code to work, but can't seem to get the right output.

I also need to know how best to get this data from the server and into memory. As a test, I have uploaded the image data that was output from the Processing sketch to the server - how would I best read this into the Arduino?

Do you have a test case with known input and expected output that you can use to test your image conversion implementation?

I don't think you ever said how you're going to connect your Arduino to the web server. The obvious options are USB Serial or TCP/IP. Have you decided that yet?

Hi Peter, I said that I have an Ethernet shield and want to use an HTTP connection rather than USB. I can't get my PHP code to mimic that Procesing script (see code in first post) but I will try to first test a working image data file that was generated using the Processing sketch. I can upload this to my server and see if the Arduino can print. As you say - this would be a good test to do.

I am still most stuck trying to get the PHP script working - can you help me at all with that please?

Many thanks

The (Processing?) code you included in the original post just seems to take an image consisting of a byte array with width/height attributes, and encode that as a line of text for each line of the image, with the line containing a comma separated sequence of hex values. Is that the format you need to output to your printer? If so, you need to convert your JPG image to a bitmap format and then encode it using the bit-map-to-text algorithm in the original post. I haven't done anything like that in PHP but Google suggests that PHP supports ImageMagick which enables you to access image attributes and pixels, so you should have access to get the pixel data used by your conversion algorithm.

I guess the scheme would be that your PHP web app saves the image file in a spool directory as you have already suggested, and a background thread detects the presence of the file, reads it and converts it into your textual format and uses an HTTP post or similar to push that chunk of ascii to the Arduino. The Arduino would send it on to the printer.

If you don't need the ability to spool images and print them in the background, you could simplify this and have the PHP web app encode the image to text within the HTTP request handler and perform the HTTP post or similar to get it printed. In this scheme you'd want to provide some sort of mutex in the PHP web app so that it only processes one image at a time.

Here is my 2 cents;-

Plan A: Since OP make Processing+Arduino+Printer works, here is the route load Apache Tomcat at server and put Processing into server either head or headless. then write jsp wrapper for Processing code.

== BROWSER == Html5 canvas -> canvas.toDataURL -> ajax post base64encoded image to jsp server

== JSP SERVER == get post payload -> base64decoded -> Processing -> log file on server -> sends this to Arduino

== Arduino == sends image to the thermal printer -> log print image file.

OP finished 80%+ job, now just needed write jsp wrapper.

before we go through Plan B, few thing might need to review;-

  1. use HTTP post, say no to HTTP get, the reason is HTTP get has size limit, only few K.
  2. move all the cpu intensive task out of Arduino.
  3. set up enough log/debug point.
  4. no HTTP POST binary, post base64 only.
  5. SD Card Shield for Arduino, for log print image file.

Plan B: Apache php

== BROWSER == Html5 canvas -> canvas.toDataURL -> ajax post base64encoded image to php server

== Apache SERVER == get post payload -> base64decoded -> get width,height -> ImageMagick convert to bitmap -> save file on server( debug point) -> open file on server -> base64encoded -> cURL post width,height,base64 payload to Arduino

== Arduino web server == get post payload -> base64decoded -> sends image to the thermal printer -> log print image file.

Html5 canvas PHP

Arduino-based Web Server library

Arduino base64 en/decode library

You can do all of what sonnyyu said :roll_eyes: or just use a PHP script like this:

<?php

header('Content-Type: text/plain');

$url = $_GET['url'];

/* Open the URL and create an image; change to "fromjpeg", "frompng", etc. as necessary */
$image = imagecreatefromgif($url);

if ($image) {
  $height = imagesy($image);
  $width = imagesx($image);

  print "URL: $url\n";
  print "Height: $height\n";
  print "Width: $width\n";

  imagefilter($image, IMG_FILTER_GRAYSCALE);

  for ($y = 0; $y <= $height; $y++) {
    for ($x = 0; $x <= $width; $x++) {
      $rgb = imagecolorsforindex($image, imagecolorat($image, $x, $y));

      if ($rgb['red'] > 88) {
        print "X";
      } else {
        print " ";
      }
    }
    print "\n";
  }
} else {
  print "Crap! Didn't load the image\n";
}

?>

Be warned that I’m a novice PHP programmer. Also, this requires the GD library but that should be default with any PHP install.

Try with a URL like:
http://www.mysite.com/myscriptname.php?url=http://arduino.cc/forum/Themes/arduinoWide/images/home_icon.gif

For output like:

URL: http://arduino.cc/forum/Themes/arduinoWide/images/home_icon.gif
Height: 11
Width: 9
XXXX XXXX 
XXX   XXX 
XX     XX 
X       X 
          
X XX    X 
X XX    X 
X       X 
X       X 
XXXXXXXXX

You’ll want to adjust the output so it’s more practical for reading it by the Arduino, but hopefully you get the idea how to manipulate the image pixel by pixel. Adjusting from a color image to black and white for the thermal printer is kinda tricky; you’ll probably want to play with that part as well.