<?php

/* EAN13 barcode renderer
 * Copyright 2012 Joel Yliluoma - http://iki.fi/bisqwit/
 */

class EAN13render
{
  // These are the different barcode patterns for each digit (7 bit each).
  // '1' represents a black line, '0' represents white (no line).
  static $Rcodes = Array('1110010','1100110','1101100','1000010','1011100',
                         '1001110','1010000','1000100','1001000','1110100');

  // The EAN13 defines three groups of bit patterns.
  // The 'R' pattern group, as above.
  // The 'G' group, which is a mirror of R (bits scanned in opposite order).
  // And the 'L' group, which is an inverse of R (0 becomes 1, 1 becomes 0).
  // Rather than defining them as arrays, we'll synthesize them at runtime.
  
  // This array describes which group to use for each digit,
  // depending on the first digit of the EAN code.
  static $groups = Array('LLLLLL','LLGLGG','LLGGLG','LLGGGL','LGLLGG',
                         'LGGLLG','LGGGLL','LGLGLG','LGLGGL','LGGLGL');

  public static function Render($barcode)
  {
    $w = 123; $h = 78; // Size of our barcode image.
    $im = ImageCreateTrueColor($w,$h);
    ImageFilledRectangle($im, 0,0, $w,$h, 0xFFFFFF); // Fill the image with white
    $xpos = 19;

    // This function renders bit patterns.
    $synth = function($pattern, $transformation, $height) use(&$im,&$xpos)
    {
      $b = strlen($pattern);
      for($a=0; $a<$b; ++$a)
      {
        $index = $a;
        
        // If the group is 'G', mirror the code.
        if($transformation == 'G') $index = ($b-1) - $index;

        // Choose the bit from the pattern.
        $bit = (int) $pattern[$index];
        
        // Oh. For anyone wondering, this editor is actually
        // Joe. It is not the same editor I have used for many
        // of my videos. That's because now I'm making a Linux program.
        // Anyway.
        
        // If the group is 'L', invert the bit.
        if($transformation == 'L') $bit = 1-$bit;
        
        // If the bit is '1', draw a vertical line in black color.
        if($bit == 1)
          ImageLine($im, $xpos,0, $xpos,$height, 0x000000);
        ++$xpos;
      }
    };
    
    // Define the lengths of the barcode lines.
    $normal_height    = $h-12;
    $separator_height = $h-7;
    
    $font = './arial.ttf';
    
    // First, produce a begin separator (two thin bars).
    $synth('101', 'R', $separator_height);
    
    $charlimit=strlen($barcode);
    $midpos = $charlimit >> 1;
    
    for($n=0; $n<$charlimit; ++$n)
    {
      $digit = (int) $barcode[$n];
      
      if($n == 0)
      {
        // Print the first digit separately (in black color)
        // Unless 0, which stands for UPC
        if($digit != 0)
          ImageTTFtext($im, 8,0, $xpos-10,$h-1, 0x000000, $font, $digit);
      }
      else
      {
        // Print the digit (in black color)
        ImageTTFtext($im, 8,0, $xpos,$h-1, 0x000000, $font, $digit);
        
        // Produce the pattern.
        $code   = EAN13render::$Rcodes[$digit];
        $select = 'R';
        if($n <= $midpos)
        {
          // Choose the patterns for the left side digits based
          // on the first digit of the barcode.
          $select = EAN13render::$groups[ (int)$barcode[0] ][ $n-1 ];
        }
        
        $synth($code, $select, $normal_height);
        
        if($n == $midpos)
        {
          // Produce the middle separator. Two thin bars, again.
          $synth('01010', 'R', $separator_height);
        }
      }
    }
    
    // Last, produce the end separator.
    // Which looks the same as the begin separator.
    $synth('101', 'R', $separator_height);
    
    return $im;
  }
};

// This is my sample EAN-13 barcode (6425081281317):
#$barcode = sprintf('64%s', base_convert('BISQWIT',36,10));
#$barcode = '9780201633719';
$barcode = '0'. '332960073452';
#$barcode = '020296124';

$im = EAN13render::Render($barcode);
ImagePNG($im, 'test.png');