<?php

/**
 * 指定ディレクトリに含まれる画像パス一覧を取得。
 */
function getPicPathList($dir, $img_ext) {
  $IMG_EXT = strtoupper($img_ext);
  $cmd = "find {$dir} | grep '{$img_ext}\\|{$IMG_EXT}'";
  exec($cmd, $output, $res);
  return $output;
}

class ImageConverter {
  public $imagick_path = '/usr/local/imagick/bin/convert';

  function getImageSize($path) {
    $s = getimagesize($path);
    $w = $s[0];
    $h = $s[1];
    return array($w, $h);
  }

  /**
   * 短辺が$minピクセルになるように画像を縮小し、同じファイル名で$dirのディレクトリに保存。
   *
   */
  function createResizedImage($src, $dir, $min) {
    list($sw, $sh) = $this->getImageSize($src);
  
    if ($sw <= $sh) {
      $dw = $min;
      $dh = intval($sh * $min / $sw);
    } else {
      $dw = intval($sw * $min / $sh);
      $dh = $min;
    }
  
    $dest = $dir .'/'. basename($src);
  
    $cmd = $this->imagick_path ." -geometry {$dw}x{$dh} {$src} {$dest}";
    exec($cmd);
  }

  /**
   * 画像を指定した幅、高さで中央から切り出し、指定したファイルパスまたはディレクトリに保存。
   *
   */
  function cropImage($src, $dest, $w, $h) {
    list($sw, $sh) = $this->getImageSize($src);

    if ($w < $sw) {
      $sx = intval(($sw - $w) / 2);
    } else {
      $sx = 0;
    }

    if ($h < $sh) {
      $sy = intval(($sh - $h) / 2);
    } else {
      $sy = 0;
    }

    if (is_dir($dest)) {
      $dest = $dest .'/'. basename($src);
    }
    $this->crop($w, $h, $sx, $sy, $src, $dest);
  }

  /**
   * 画像を指定した幅、高さで切り分け、指定したディレクトリに保存。
   *
   */
  function splitImage($src, $dir, $w, $h) {
    list($sw, $sh) = $this->getImageSize($src);

    if ($sw % $w || $sh % $h) {
      return false;
    }

    for ($i = 0; $i < $sw / $w; $i++) {
      for ($j = 0; $j < $sh / $h; $j++) {
        $dest = $dir .'/'. sprintf('%s_%s.jpg', $i, $j);
        $this->crop($w, $h, $i * $w, $j * $h, $src, $dest);
      }
    }
  }

  function crop($w, $h, $sx, $sy, $src, $dest) {
    $cmd = $this->imagick_path ." -crop {$w}x{$h}+{$sx}+{$sy} {$src} {$dest}";
    exec($cmd);
  }
}


class Image {
  public $img;
  public $src;
  public $w;
  public $h;
  public $histgram;
  public $color_level = 5;

  function __construct($src) {
    $this->src = $src;
    $this->img = imagecreatefromjpeg($src);

    for ($i = 0; $i < $this->color_level; $i++) {
      for ($j = 0; $j < $this->color_level; $j++) {
        for ($k = 0; $k < $this->color_level; $k++) {
          $this->histgram[$i][$j][$k] = 0;
        } 
      }
    }
    $conv = new ImageConverter();
    list($this->w, $this->h) = $conv->getImageSize($src);
  }

  /** 
   * 指定したピクセルのRGBを取得。
   */
  function getColorAt($x, $y) {
    $rgb = imagecolorat($this->img, $x, $y);
    $r = ($rgb >> 16) & 0xFF;
    $g = ($rgb >> 8) & 0xFF;
    $b = $rgb & 0xFF;
    return array($r, $g, $b);
  }

  /**
   * 最大255のRGBを、最大$color_levelに直す。
   */
  function convertColorLevel($rgb) {
    foreach ($rgb as $key => $c) {
      $l = intval($c / 255 * $this->color_level);
      if ($l == $this->color_level) {
        $l--;
      }
      $ret[$key] = $l;
    }
    return $ret;
  }

  /**
   * 指定したピクセルのカラーレベルを取得。
   */
  function getColorLevelAt($x, $y) {
    return $this->convertColorLevel($this->getColorAt($x, $y));
  }

  /**
   * 画像に含まれる各ピクセルのカラーレベルの分布を作成。
   */
  function createHistgram() {
    for ($i = 0; $i < $this->w; $i++) {
      for ($j = 0; $j < $this->h; $j++) {
        $lv = $this->getColorLevelAt($i, $j);
        $this->histgram[$lv[0]][$lv[1]][$lv[2]]++;
      }
    }
  }

  /**
   * 画像を比較し、カラーレベルの分布から類似度を計算して取得。
   */
  function getResebleValue($comp_img) {
    $sum = 0;

    for ($i = 0; $i < $this->color_level; $i++) {
      for ($j = 0; $j < $this->color_level; $j++) {
        for ($k = 0; $k < $this->color_level; $k++) {
          $sum += min($this->histgram[$i][$j][$k], $comp_img->histgram[$i][$j][$k]);
        }
      }
    }
    return $sum / $this->w / $this->h;
  }
}
