Images over HTTP

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.

sonnyyu, thank you for your thorough replies. I think your Plan B is best for me because I am sure I can do the first 2 steps easily (HTML Canvas / PHP Server). The main issue I have is getting the image data to print.

For the sake of testing (and because I am happy enough to code the HTML5 and PHP image handling) I can upload an image to my server and pretend this is the one generated from the canvas.

The section I am most stuck with is how to convert my image into a byte array. From what I can see, the processing script scans each row of pixels, and groups them into 8 bits. It then checks to see if these are black (or below a certain threshhold) and then sets the bit. This 8 pixel chunk is then output as a hexadecimal byte.

How can I duplicate this with PHP? I understand how to scan rows and columns - but I don't get the 8 pixel chunk going to the byte array (c++ byte array according to the code comments)

Once I can at least get PHP to dump out the correct byte array to the screen (and manually copy this into my sketch to print out) then I can focus on sending this data to the Arduino via HTTP POST

Thanks for everyone's help this far. I know I am so close to getting this working, but I lack a total understanding of bit / byta array coding

first before go through Plan B, We need Plan C - backup Plan. processing use Java image class to processing Image. we could easily wrote web service via tomcat, and tomcat will be very happily co-exist with apache server. Both have same father. Now your php code call tomcat web service. The job is done. If testing purpose you could even run it through command line. Your php code make system call, It is arguably but works. Plan C will be bought me some time as well. :wink:

Let me think through correct method for Plan B. I need time!

Now I know where you are stuck. the format of processing file.

...This 8 pixel chunk is then output as a hexadecimal byte.

if you see hexadecimal byte image file, then it is base-64 encoded, first you should decode it back to binary image file. Once you have binary image file you could test it with Adobe Photoshop or even download Imagemagick binary releases to identify file format. or upload it to Abode forum or java image forum to ask help.

Download Binary Releases ImageMagick – Download

Command to identify "identify logo.gif"

known well about php image library - GD, ImageMagick, Gmagick. Since they support variant image file format.

after you go through all of above, but fail you still have Plan D and Plan E.

Plan D is using C++ to take care image byte array and write it as PHP extension.

Plan E is use php-java bridge.

if we are in same page, Arduino printing is single thread application, no con-current support is needed. the work around of Plan C is perfect here. Write java command line application is very easy, since you have logic complete. Might need few lines of java code.
then php make system call to command line.

This is all sounding really complex. I see2 main steps to test.

  1. Converting an image into a byte array using PHP

  2. Geting the Arduino to download this data and print it.

So firstly, I want to focus on step 1, and manually test the byte array. I am trying to print the data to the screen using PHP. The image (which would be created with the HTML5 canvas) is already uploaded.

Here are my example files

The image I want to convert: https://dl.dropboxusercontent.com/u/8396442/online/arduino/arduino.png
The correct byte array data: https://dl.dropboxusercontent.com/u/8396442/online/arduino/arduino.h
The original processing script: https://dl.dropboxusercontent.com/u/8396442/online/arduino/bitmapImageConvert.pde
The PHP script I have written so far: https://dl.dropboxusercontent.com/u/8396442/online/arduino/php.txt

I basically want to get to a point where the PHP script is able to output the data that you can see in the arduino.h file

I am sure that my PHP script is scanning the image in the same way as the Processing script - but I can't quite understand the bitwise operations, specifically how to convert this into PHP:

if((img.pixels[i++] & 1) == 0) sum |= b; // If black pixel, set bit

The img.pixels part returns a "Color" datatype: color / Reference / Processing.org

I know in PHP I can use imagecolorat($img,$x,$y); and this returns an array for RGBA

I am certain that once I can get this one line running as PHP then the first (and hardest part) of my project will be complete!

So basically, my question this far is how to convert that line of code into PHP?

Thanks for sticking with me on this one :smiley:

My best work happens after midnight :wink:

I realised that I needed to have a counter in my loop because I wasn't checking each pixel properly. This is the working PHP code. The image is fixed, but I can easily adapt this to read from a file input or from the HTML5 canvas. But anyway, I copied the output from the PHP script (from the browser screen) and copied the byte data into my Arduino sketch and it prints the image perfectly. I'm quite relieved to have worked it out. Have learnt a lot about bitwise operations!

Here's the working code:

<?php

$i = 0;
$n = 0;

$imgPath = "arduino.png";

$im = imagecreatefrompng($imgPath);
imagefilter($im, IMG_FILTER_GRAYSCALE);
imagefilter($im, IMG_FILTER_CONTRAST, -100);

$height = imagesy($im);
$width = imagesx($im);


$rowBytes   = floor(($width + 7)/8);
$totalBytes = $rowBytes * $height;

// Image info
echo '<p>Image: '.$width.'x'.$height.'
';
echo $rowBytes.' rowBytes ('.$totalBytes.' total)';
echo '</p>';

echo '<pre>';

for($y=0;$y<$height;$y++) {
	echo "
";
	for($x=0; $x<$rowBytes; $x++) {
		$lastBit = ($x < $rowBytes - 1) ? 1 : (1 << ($rowBytes * 8 - $width));
		
		$sum = 0; // Clear accumulated 8 bits
		for($b=128; $b>=$lastBit; $b >>= 1) { // Each pixel within block...
			$row = floor($i/$width);
			$col = $i%$width;
			$i++;
			
			$rgb = imagecolorat($im,$col,$row);
			$rVal = ($rgb >> 16) & 0xFF;
			$gVal = ($rgb >> 8) & 0xFF;
			$bVal = $rgb & 0xFF;
			
			if($rVal==0) {
				$sum |= $b;
			}
		}
		echo "0x".sprintf("%02X",$sum);
		
		if(++$n < $totalBytes) {
			echo ",";
		}
	}
}

echo '</pre>';
?>

So step 2, is how to get that code onto the Arduino and into a variable that I can pass to the printer function? I actually need to pass 3 values in the HTTP POST. The image width, the height and also the image data.

This should be the easy bit !

I've finished an HTML canvas drawing tool and this now saves the byte array to my server (into a text document for now).

My Arduino Ethernet shield doesn't have the SD card header - a friend of mine said I could have to stream the data to the printer if the images were too large.

To get the basics working - I need to work out how to download this data to the Arduino memory and them print it. Can anyone offer any tips or advise? Most of the examples I have found tend to save to the SD card first (which I don't have).

Perhaps it's too simple, but can I simply read the bytes into a char* and then pass this to the Thermal.printBitmap()?

Just bumping this thread. I can retrieve the byte array into my serial monitor (using Ethernet librar and client.read()), but not sure of 2 things:

  1. How to ignore the HTML header and other crud and store the image into a variable

  2. How to pass the byte array as a stream into printBitmap (for larger images)

Any pointers to help get me started would be most helpful.

Thank you

My image conversion works correctly - I have tested this by manually copying the output from my server into the Arduino sketch and it prints correctly (see PHP code in my earlier post). My current sketch is able to dump the output from the server (the image data) into the serial monitor. I don't know how to read this data into a string/array and then pass that to the printBitmap() function:

Hi Alex,

If you ever proceeded with this project I would be grateful to know how you ended up doing it.

Best,

Espen