initial commit
initial commit

file:b/composer.json (new)
  {
  "name": "photo collage",
  "description": "create photo collages with php",
  "homepage": "http://git.razvi.ro",
  "type": "library",
  "license": "private",
  "authors": [
  {
  "name": "Razvan Stanga",
  "email": "git@razvi.ro"
  }
  ],
  "support": {
  "email": "git@razvi.ro"
  },
  "require": {
  "php": ">=5.4.16"
  },
  "require-dev": {
  },
  "autoload": {
  "psr-4": {
  "razvanstanga\\photocollage": "src"
  }
  },
  "autoload-dev": {
  },
  "minimum-stability": "dev",
  "prefer-stable": true
  }
 
  <?php
 
  namespace razvanstanga\photocollage;
 
  /**
  * Photo collage
  */
 
  class PhotoCollage {
  protected $background = [];
  protected $photos = [];
  protected $texts = [];
  protected $allowedExtensions = ["png", "jpg", "jpeg", "gif", "bmp"];
 
  /**
  * Create the photo collage
  *
  * @param string $path photo path
  * @param string $filename photo filename
  * @return string filename
  */
  public function create($path, $filename)
  {
  $background = imagecreatetruecolor($this->background['width'], $this->background['height']);
  if ($this->background['transparent']) {
  imagesavealpha($background, true);
  $trans_colour = imagecolorallocatealpha($background, 0, 0, 0, 127);
  imagefill($background, 0, 0, $trans_colour);
  }
  foreach ($this->photos as $photo) {
  if (file_exists($photo['path']) && $photo['path']) {
  $_imageData = $this->checkImage($photo['path']);
  if ($photo['resize'] && $photo['size']) {
  $_imageData['image'] = $this->processImage($_imageData['image'], $_imageData['width'], $_imageData['height'], $photo['size'], $photo['resize']);
  }
  imagecopyresampled($background, $_imageData['image'], $photo['left'], $photo['top'], 0, 0, $photo['width'], $photo['height'], $photo['width'], $photo['height']);
  } elseif(filter_var($photo['path'], FILTER_VALIDATE_URL)) {
  $_image = file_get_contents($photo['path']);
  $_image = imagecreatefromstring ($_image);
  if ($_image && $photo['resize'] && $photo['size']) {
  $_image = $this->processImage($_image, null, null, $photo['size'], $photo['resize']);
  }
  if ($_image) {
  imagecopyresampled($background, $_image, $photo['left'], $photo['top'], 0, 0, $photo['width'], $photo['height'], $photo['width'], $photo['height']);
  }
  }
  }
  foreach ($this->texts as $text) {
  if (isset($text['wrap'])) {
  $textLines = $this->wrapText ($text['text'], $text['wrap']);
  foreach ( $textLines as $line => $_text ) {
  $charDetails = imageftbbox ($text['size'], 0, $text['font'], $_text, array());
  $_width = abs($charDetails[0]) + abs($charDetails[2]);
  $_height = abs($charDetails[1]) + abs($charDetails[5]);
  if ($text['center']) {
  $text['left'] = intval($text['left'] - $_width/2);
  }
  $color = imagecolorallocate($background, $text['color']['r'], $text['color']['g'], $text['color']['b']);
  imagefttext ($background, $text['size'], 0, $text['left'], $text['top'], $color, $text['font'], $_text);
  $text['top'] += $_height + 3;
  }
  } else {
  $charDetails = imageftbbox ($text['size'], 0, $text['font'], $text['text'], []);
  $_width = abs($charDetails[0]) + abs($charDetails[2]);
  $_height = abs($charDetails[1]) + abs($charDetails[5]);
  if ($text['center']) {
  $text['left'] = intval($text['left'] - $_width/2);
  }
  $color = imagecolorallocate($background, $text['color']['r'], $text['color']['g'], $text['color']['b']);
  imagefttext ($background, $text['size'], 0, $text['left'], $text['top'], $color, $text['font'], $text['text']);
  }
  }
 
  imagepng($background, $path . $filename, 9);
 
  return $filename;
  }
 
  /**
  * Photo background
  *
  * @param int $width photo width
  * @param int $height photo height
  * @param boolean $transparent transparent background
  */
  public function setBackground($width, $height, $transparent = false)
  {
  $this->background = ['width' => $width, 'height' => $height, 'transparent' => $transparent];
  }
 
  /**
  * Adds photo to collage
  *
  * @param string $path path to photo
  * @param array $position photo position in collage
  * @param array $size photo size
  * @param array $resize photo resize details
  */
  public function addPhoto($path, array $position, array $size, array $resize = [])
  {
  $this->photos[] = ['path' => $path, 'top' => $position['top'], 'left' => $position['left'], 'width' => $size['width'], 'height' => $size['height'], 'resize' => $resize['resize'], 'size' => $resize['size']];
  }
 
  /**
  * Adds text to collage
  *
  * @param string $text text
  * @param string $font path to font
  * @param int $size font size
  * @param array $position text position
  * @param array $color text rgb color
  */
  public function addText($text, $font, $size, array $position, array $color)
  {
  $this->texts[] = ['text' => $text, 'font' => $font, 'size' => $size, 'left' => $position['left'], 'top' => $position['top'], 'center' => $position['center'], 'wrap' => $position['wrap'], 'color' => $color];
  }
 
  /**
  * Resizes image
  *
  * @param image $srcImage image source
  * @param int $srcWidth image source width
  * @param int $srcHeight image source height
  * @param int $newSize resize to newsize
  * @param string $resize resize by "bigger", "smaller", "width", "height"
  * @return image resized image
  */
  public function processImage($srcImage, $srcWidth, $srcHeight, $newSize, $resize = "bigger")
  {
  $resizes = ["bigger", "smaller", "width", "height"];
  if ( !in_array ($resize, $resizes) ) {
  $resize = "bigger";
  }
  $srcWidth = $srcWidth ? $srcWidth : imagesx($srcImage);
  $srcHeight = $srcHeight ? $srcHeight : imagesy($srcImage);
  if ($resize == "bigger") {
  if ($srcWidth >= $srcHeight) {
  $resize = "width";
  } else {
  $resize = "height";
  }
  } elseif ($resize == "smaller") {
  if ($srcWidth <= $srcHeight) {
  $resize = "width";
  } else {
  $resize = "height";
  }
  }
 
  if ($resize == "width") {
  $destWidth = $newSize;
  $destHeight = ceil($destWidth / ($srcWidth / $srcHeight));
  } elseif ( $resize == "height" ) {
  $destHeight = $newSize;
  $destWidth = ceil($destHeight / ($srcHeight/$srcWidth));
  }
 
  $crop = [];
  $crop['x'] = 0;
  $crop['y'] = 0;
  $crop['w'] = $srcWidth;
  $crop['h'] = $srcHeight;
 
  $destImage = imagecreatetruecolor($destWidth, $destHeight);
  imagecopyresampled($destImage, $srcImage, 0, 0, $crop['x'], $crop['y'], $destWidth, $destHeight, $crop['w'], $crop['h']);
  imagedestroy($srcImage);
 
  return $destImage;
  }
 
  /**
  * Validates image
  *
  * @param string $file path to file
  * @return array|bool
  */
  public function checkImage($file)
  {
  $ext = $this->getFileext($file);
  if (!in_array($ext, $this->allowedExtensions)) {
  return false;
  }
  $size = getimagesize($file);
  $size['ext'] = $ext;
  if ( !is_array ($size) || $size[0] < 1 || $size[1] < 2 ) {
  return false;
  }
  if ($ext == "jpg" || $ext == "jpeg") {
  $image = @imagecreatefromjpeg($file);
  } elseif ($ext == "gif") {
  $image = @imagecreatefromgif($file);
  } elseif ($ext == "png") {
  $image = @imagecreatefrompng($file);
  } elseif ($ext == "bmp") {
  $image = $this->imagecreatefrombmp($file);
  }
  if ($image == false) {
  return false;
  }
  $size['image'] = $image;
  return $size;
  }
 
  /**
  * Get file extension
  *
  * @param string $file path to file
  * @return string extension
  */
  public function getFileext($file)
  {
  return strtolower(substr(strrchr($file,"."),1));
  }
 
  /**
  * [wrapText description]
  * @param string $text text wo wrap
  * @param integer $chars wrap to chars
  * @return array
  */
  public function wrapText($text, $chars = 42) {
  return explode ("\n", wordwrap($text, $chars, "\n", true));
  }
 
  /**
  * Creates image instance from .bmp files
  *
  * @param string $filename path to file
  * @return image|bool
  */
  public function imagecreatefrombmp($filename) {
  $tmp_name = tempnam("/tmp", "GD_" . uniqid());
  if($this->ConvertBMP2GD($filename, $tmp_name)) {
  $img = imagecreatefromgd($tmp_name);
  unlink($tmp_name);
  return $img;
  }
  return false;
  }
 
  /**
  * ConvertBMP2GD
  *
  * @param image $src image instance
  * @param boolean $dest temporary file
  */
  protected function ConvertBMP2GD($src, $dest = false)
  {
  if(!($src_f = fopen($src, "rb"))) {
  return false;
  }
  if(!($dest_f = fopen($dest, "wb"))) {
  return false;
  }
  $header = unpack("vtype/Vsize/v2reserved/Voffset", fread($src_f, 14));
  $info = unpack("Vsize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vncolor/Vimportant",
  fread($src_f, 40));
  extract($info);
  extract($header);
  if($type != 0x4D42) { // signature "BM"
  return false;
  }
 
  $palette_size = $offset - 54;
  $ncolor = $palette_size / 4;
  $gd_header = "";
  // true-color vs. palette
  $gd_header .= ($palette_size == 0) ? "\xFF\xFE" : "\xFF\xFF";
  $gd_header .= pack("n2", $width, $height);
  $gd_header .= ($palette_size == 0) ? "\x01" : "\x00";
  if($palette_size) {
  $gd_header .= pack("n", $ncolor);
  }
  // no transparency
  $gd_header .= "\xFF\xFF\xFF\xFF";
 
  fwrite($dest_f, $gd_header);
 
  if($palette_size) {
  $palette = fread($src_f, $palette_size);
  $gd_palette = "";
  $j = 0;
  while($j < $palette_size) {
  $b = $palette{$j++};
  $g = $palette{$j++};
  $r = $palette{$j++};
  $a = $palette{$j++};
  $gd_palette .= "$r$g$b$a";
  }
  $gd_palette .= str_repeat("\x00\x00\x00\x00", 256 - $ncolor);
  fwrite($dest_f, $gd_palette);
  }
 
  $scan_line_size = (($bits * $width) + 7) >> 3;
  $scan_line_align = ($scan_line_size & 0x03) ? 4 - ($scan_line_size & 0x03) : 0;
 
  for($i = 0, $l = $height - 1; $i < $height; $i++, $l--) {
  // BMP stores scan lines starting from bottom
  fseek($src_f, $offset + (($scan_line_size + $scan_line_align) * $l));
  $scan_line = fread($src_f, $scan_line_size);
  if($bits == 24) {
  $gd_scan_line = "";
  $j = 0;
  while($j < $scan_line_size) {
  $b = $scan_line{$j++};
  $g = $scan_line{$j++};
  $r = $scan_line{$j++};
  $gd_scan_line .= "\x00$r$g$b";
  }
  } else if($bits == 8) {
  $gd_scan_line = $scan_line;
  } else if($bits == 4) {
  $gd_scan_line = "";
  $j = 0;
  while($j < $scan_line_size) {
  $byte = ord($scan_line{$j++});
  $p1 = chr($byte >> 4);
  $p2 = chr($byte & 0x0F);
  $gd_scan_line .= "$p1$p2";
  } $gd_scan_line = substr($gd_scan_line, 0, $width);
  } else if($bits == 1) {
  $gd_scan_line = "";
  $j = 0;
  while($j < $scan_line_size) {
  $byte = ord($scan_line{$j++});
  $p1 = chr((int) (($byte & 0x80) != 0));
  $p2 = chr((int) (($byte & 0x40) != 0));
  $p3 = chr((int) (($byte & 0x20) != 0));
  $p4 = chr((int) (($byte & 0x10) != 0));
  $p5 = chr((int) (($byte & 0x08) != 0));
  $p6 = chr((int) (($byte & 0x04) != 0));
  $p7 = chr((int) (($byte & 0x02) != 0));
  $p8 = chr((int) (($byte & 0x01) != 0));
  $gd_scan_line .= "$p1$p2$p3$p4$p5$p6$p7$p8";
  }
  $gd_scan_line = substr($gd_scan_line, 0, $width);
  }
 
  fwrite($dest_f, $gd_scan_line);
  }
  fclose($src_f);
  fclose($dest_f);
  return true;
  }
  }
 
comments