HTML emails the easy/wrong way

In a press conference that stunned the world, custarddoughnuts today announced that the time of building HTML emails "was over" thanks to their new HTML email generating software. Speaking from his underground bunker beneath New Mexico, CEO Lewis Crankled said "Why spend time trying to get your email to look pixel perfect on every email client when you can just generate it in HTML, without even needing images?"

Oh, I do make myself laugh sometimes.

I'm sure someone's already thought of doing this, but it's fun nonetheless. The other day I was building some HTML emails when all of a sudden a thought popped into my head. "Would it be possible" - said the thought, thoughtfully - "to write a script that reads the pixels of an image (an email design) and then generates a HTML table that perfectly matches this structure?"

I had a quick check and sure enough, PHP allows you to read the colour values of pixels in an image. From there, it's a simple matter of turning each pixel value into a 1x1 table cell with that pixel colour as the background and putting each cell into a row of the right width. Here's the code:

    //create image to read from, based on original upload
    $im = imagecreatefrompng($file_image);
    //start the output
    $output = '<table width="'.$width.'" cellpadding="0" cellspacing="0">';
    $nextcol = '';
    $size = 1;

    for($y = 0; $y < $height; $y++){
        $output .= "<tr>";
        $output .= "<td>";
        $output .= '<table width="100%" cellpadding="0" cellspacing="0">';
        $output .= "<tr>";

        for($x = 0; $x < $width; $x++){
            $rgb = imagecolorat($im, $x, $y);
            $r = ($rgb >> 16) & 0xFF;
            $g = ($rgb >> 8) & 0xFF;
            $b = $rgb & 0xFF;
            //the colour of the current pixel
            $color = $r.','.$g.','.$b;

            //now check the next colour
            $next = $x + 1;

            if($next < $width){
                $nrgb = imagecolorat($im, $next, $y);
                $nr = ($nrgb >> 16) & 0xFF;
                $ng = ($nrgb >> 8) & 0xFF;
                $nb = $nrgb & 0xFF;
                $nextcol = $nr.','.$ng.','.$nb;

                //if the next pixel is the same colour as this one, 
                //extend this cell's width to save markup
                if($color == $nextcol){
                else {
                    $output .= '<td width="'.$size.'" height="1" style="font-size:0;line-height:0;background-color:rgb('.$color.')"></td>';
                    $output .= "\n";
                    $size = 1;
            else {
                $output .= '<td width="'.$size.'" height="1" style="font-size:0;line-height:0;background-color:rgb('.$color.')"></td>';
        $size = 1; //reset the cell width for a new row
        $output .= "</tr>";
        $output .= "</table>";
        $output .= "</td>";
        $output .= "</tr>";
    $output .= '</table>';

    file_put_contents($outputdir."output.html", $output);
    echo "File written";

There's a bit of cleverness in the middle to check the next pixel in the row to see if it's the same colour as this one. If it is, the code simply extends the length of the current table cell until it reaches another colour. It's your basic image compression, implemented in HTML. It's also pretty essential - without it, rendering the table on the fly takes longer than PHP's built in execution limit, and storing it in memory exceeds the memory limit. Either way, it brings even the mighty Chrome to its knees.

So, this code generates a HTML table that perfectly mimics the original image, pixel for pixel, without needing any images whatsoever. Don't believe me? Here's an example.

Now obviously this can't be used for actual emails (sadly). Here's why not:

  • The output contains no actual text - any text, like the rest of the image, is turned into 1x1 table cells.
  • Consequently it's impossible to put any kind of links into the HTML - you'd have to know the areas that needed to be links and put 1x1 link tags into every one of the table cells within those areas, which could run to hundreds of links, just to produce 'one' link.

The other drawback is that an 800x2000 px image with a file size of 516 KB gets converted into a HTML file that's 27 MB. Cough.

Fun but useless, then. I did consider using this to add very small images to a site, but there are better ways of doing non-image images these days.


This article is tagged with