File source

<?php
/**
 * Helper functions for encoding screen images to bitmaps
 * compatible with the device
 */


/* Global variable :( */
// @TODO wrap this in Class
$lastBuf = false;

/** Clears buffer **/
function clearBuf(){
  global $lastBuf;
  $lastBuf = false;
}

/** Sends GD image $img to Port $port
 * Sends only different sections if last
 * buffer is available
 **/
function sendImg($img, Port $port){
  global $lastBuf;
  $buf = imgToBuffer($img);
  if(!$lastBuf){
    $port->write("D");
    $port->write(bufferToString($buf));  
  }else{
    $d = divide($buf, $lastBuf);
    foreach($d as $part){
      $len = 1+($part[1] - $part[0]);
      $b = Array(ord("C"), $part[0] & 0xff, ($part[0]>>8) & 0xff, $len & 0xff, ($len >> 8) & 0xff);
      for($i = $part[0]; $i <= $part[1]; $i++){
        $b[] = $buf[$i];
      }
      $port->write(bufferToString($b));
      $port->flush();
    }
  }
  $lastBuf = $buf;
}

/** Finds eqals sections in $buf1 and $buf2,
  beginning with first index $start up
  to index $end.
  Beginning and end indices of equal sections
  are returned in $start and $end variables
  by refference
*/
function findSame($buf1,$buf2,&$start,&$end){
  $len = $end+1;
    // find start
  for($i = $start; $i < $len; $i++){
    if($buf1[$i] !== $buf2[$i]){
      $start = $i;
      break;
    }
  }
  // find end
  for($i = $start; $i < $len; $i++){
    if($buf1[$i] == $buf2[$i]){
      $end = $i;
      break;
    }
  }

}

/** Finds different regions in $buf and $old arrays
 and returns array of Array(start, end) where
 start and end are indices of beginning and end of
 different sections.
 Sections are joined if overhead of sending
 two separate sections is greater than sending them
 together (ie. are close together)
*/
function divide($buf, $old){
  $out = Array();
  $costHead = 20; // cost for sending one section
  $maxlen = 1000; // max. length of section

  $len = count($buf);
  $start = 0;
  $end = $len-1;
  findSame($buf, $old, $start, $end);
  if($end == 0) return $out;
  $start2 = $end+1;
  $end2 = $len-1;
  while($start2 < $len){  
    if($end-$start > $maxlen){
      $out[] = Array($start, $start+$maxlen);
      $start += $maxlen+1;
    }
    $start2 = $end+1;
    $end2 = $len-1;
    findSame($buf,$old,$start2, $end2);

    $costApart = 2*$costHead + ($end-$start) + ($end2-$start2);
    $costTogether = $costHead + ($end2 - $start);
    if($costApart < $costTogether){
      $out[] = Array($start, $end);
      $start = $start2+1;
      $end = $end2;
    }else{
      $end = $end2;
    }
  }
  $out[] = Array($start, $end);
  return $out;
}

/** returns string representation of GD image $img **/
function imgToString($img){
  return bufferToString(imgToBuffer($img));
}

/** returns string representation of byte Array $buff **/
function bufferToString($buff){
  $o = "";
  foreach($buff as $n){
    $o .= chr($n);
  }
  return $o;
}

/** Converts GD image $im to byte Array.
  * Rotates that image by 90 deg
  */
function imgToBuffer($im){
  $buff = Array();
  $buflen=0;

  // first word of buffer = width
  $w = imagesx($im);
  $buff[] = $w & 0xff;
  $buff[] = ($w & 0xff00) >> 8;
  // second word of buffer = height
  $h = imagesy($im);
  $buff[] = $h & 0xff;
  $buff[] = ($h & 0xff00) >> 8;
  
  //each byte codes 8 pixels
  //scan by rows, then cols <= 90 deg rotation
  for($x = $w-1; $x>=0; $x--){
    $buf = 0;
    for($y = 0; $y < $h; $y++){
      $c = imagecolorat($im,$x,$y);
      $rgb = imagecolorsforindex($im, $c);
      $val = 0;
      if( $rgb["red"] > 128){
        $val = 0;
      }else{
        $val = 1;
      }
      // each bit = pixel
      // shift them im
      $buf = $buf << 1;
      $buf |= $val;
      $buflen++;
      //if we have 8, push it to the buffer
      if($buflen >= 8){
        $buff[] = $buf;
        $buf = 0;
        $buflen = 0;
      }
    }
    // if size is not multiple of 8
    if($buflen > 0){
        $buff[] = $buf;
        $buflen = 0;      
    }
  }

  return $buff;
}

/* same as imagettftext, but $x and $y are relative to center of string */
function imagettfcenter($img, $size, $angle, $x, $y, $color, $font, $text){
  $box = imagettfbbox($size, $angle, $font, $text);
  $x-= max(abs($box[0]-$box[2]), abs($box[4]-$box[6]))/2;
  $y+= max(abs($box[1]-$box[3]), abs($box[5]-$box[7]))/2;
  imagettftext($img, $size, $angle, $x, $y, $color, $font, $text);
}

/* returns new empty screen GD image */
function screen(){
 $i = imagecreatetruecolor(160,160);
 $w = imagecolorallocate($i, 255,255,255);
 imagefill($i, 0, 0, $w);
 return $i;
}

/* copy $img to $screen, on $x $y (top, left) */
function paste($screen, $img, $x,$y){
  imagecopy($screen, $img, $x,$y,0,0, imagesx($img), imagesy($img));
}

/* copy $img to $screen, on $x $y (center coordinates) */
function pasteCenter($screen, $img, $x, $y){
  $x-=imagesx($img)/2;
  $y-=imagesy($img)/2;
  imagecopy($screen, $img, $x,$y,0,0,imagesx($img), imagesy($img)); 
}