<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
 * MaxSite CMS
 * (c) https://max-3000.com/
 * Класс для формирования thumb-изображений
 * указывается url входящего изображения
 * на выходе url нового изображения
 */

class Thumb
{
	protected $file = ''; // исходный файл относительно uploads
	protected $new_file = ''; // конечный файл относительно uploads

	// уточнить видимость полей
	public $new_img = ''; // конечный url полный

	protected $image_info = []; // информация об изображении
	protected $image_quality = 90; // качество изображения — по-умолчанию 90%

	public $init = ''; // возврат при инициализации
	// true - есть готовое новое изображение (в кэше)
	// false - ошибка 
	// всё остальное - можно сделать новый файл

	public function __construct($url, $postfix = '-thumb', $replace_file = false, $subdir = '', $quality = 90)
	{
		// хук где можно обработать входящий url
		$url = mso_hook('thumb_in_url', $url);

		// если get-ключ thumb_in_url == true, то орбабатываем входящий url
		if (mso_get_val('thumb_in_url', true)) {
			// если есть вхождение http в начале адреса, то «выравниваем» протоколы
			if (strpos($url, 'http') === 0) {
				$url = getinfo('site_protocol') . str_replace(array('http://', 'https://'), '', $url);
			} else {
				// это относительный адрес, добавляем адрес сайта

				// если ведущий /, то его нужно удалить
				if (strpos($url, '/') === 0) $url = substr($url, 1);

				$url = getinfo('site_url') . $url;
			}
		}

		// проверим входящий url
		if (strpos($url, getinfo('uploads_url')) === false) {
			// входящий адрес чужой
			$this->init = false;
			return;
		}

		// файл и путь файла относительно uploads
		$this->file = str_replace(getinfo('uploads_url'), '', $url);

		// расширение файла
		$ext = strtolower(substr(strrchr($this->file, '.'), 1));

		if (!in_array($ext, array('jpg', 'jpeg', 'png', 'gif', 'webp'))) {
			$this->init = false; // если это не картинка, то выходим
			return;
		}

		// теперь только имя без расширения
		$name = substr($this->file, 0, strlen($this->file) - strlen($ext) - 1);

		// если указан $subdir — подкаталог для нового файла, то добавлем его к новому имени 
		// $subdir = 'mini' => uploads/mini/

		// pr($name);

		if ($subdir) {
			$name = substr_replace($name, '/' . $subdir . '/', strrpos($name, '/'), 0);
		}

		// удаляем возможные лишние слеши
		$name = str_replace('//', '/', $name); // двойной слеш
		$pos_sl = strpos($name, '/'); // в начале имени
		if ($pos_sl !== false and $pos_sl === 0) $name = substr($name, 1);

		// pr($name);

		// новое имя

		// проверим постфикс если false то без постфикса
		if ($postfix === false) $postfix = '';
		elseif (!$postfix) $postfix = '-thumb';

		$this->new_file = $name . $postfix . '.' . $ext;

		// может новый файл уже есть?
		// нужно ли заменять уже существующий файл
		if (!$replace_file and file_exists(getinfo('uploads_dir') . $this->new_file)) {
			// есть, отдаем его url
			$this->init = true;
			$this->new_img = getinfo('uploads_url') . $this->new_file;

			return;
		}

		if (!file_exists(getinfo('uploads_dir') . $this->file)) {
			$this->init = false; // нет исходного файла

			return;
		}

		// проверим картинка ли исходный файл
		$this->image_info = GetImageSize(getinfo('uploads_dir') . $this->file);

		if (!$this->image_info) {
			$this->init = false; // это не изображение - ошибка

			return;
		}

		$this->image_quality = $quality;

		// проверим существование mini-каталога нового файла
		// если его нет, попробуем создать
		$new_dir = dirname(getinfo('uploads_dir') . $this->new_file);

		if (!is_dir($new_dir)) @mkdir($new_dir, 0777);

		// сразу сформируем новый адрес
		$this->new_img = getinfo('uploads_url') . $this->new_file;
	}

	// пропорциональное уменьшение
	// если высота = 0, то она вычисляется автоматом. Аналогично и ширина
	public function resize($width = 200, $height = 0, $file = false, $new_file = false)
	{
		$CI = &get_instance();
		$CI->load->library('image_lib');
		$CI->image_lib->clear();

		// функция может принимать произвольне файлы
		if ($file === false) $file = $this->file;
		if ($new_file === false) $new_file = $this->new_file;

		// параметры для image_lib - начальные
		$r_conf = [
			'source_image' => getinfo('uploads_dir') . $file,
			'new_image' => getinfo('uploads_dir') . $new_file,
			'maintain_ratio' => false, // размеры по пропорции вычислим сами
			'quality' => $this->image_quality,
		];

		// пропорции
		$image_info = GetImageSize(getinfo('uploads_dir') . $file); // информация о файле исходном

		// отрицательные значения интепретируем как положительные
		$width = abs($width);
		$height = abs($height);

		// если задана только ширина, то высоту расчитываем пропорцией от исходного файла
		if ($height === 0) {
			//$image_info[0] - ширина  $image_info[1] - высота
			$ratio = $image_info[0] / $image_info[1]; // w/h
			$height = ceil($width / $ratio);
		}

		// аналогично расчитываем ширину, если она = 0
		if ($width === 0) {
			$ratio = $image_info[1] / $image_info[0]; // h/w
			$width = ceil($height / $ratio);
		}

		$r_conf['width'] = $width;
		$r_conf['height'] = $height;

		$CI->image_lib->initialize($r_conf);

		if (!$CI->image_lib->resize()) return false; // произошла какая-то ошибка

		// $this->preview(); // сделаем превьюшку 100х100 в _mso_i - а нужно ли?

		return getinfo('uploads_url') . $new_file;
	}

	// пропорциональное уменьшение от ширины
	public function resize_w($width = 0, $height = 0, $x = 0, $y = 0)
	{
		$width = ($width > 0) ? $width : 1;

		return $this->resize($width, 0);
	}

	// пропорциональное уменьшение от высоты
	public function resize_h($width = 0, $height = 0, $x = 0, $y = 0)
	{
		$height = ($height > 0) ? $height : 1;

		return $this->resize(0, $height);
	}

	// кроп 
	// x и y - точка координат от верхнего левого угла
	public function crop($width = 0, $height = 0, $x = 0, $y = 0, $file = false, $new_file = false)
	{
		$CI = &get_instance();
		$CI->load->library('image_lib');
		$CI->image_lib->clear();

		if ($file === false) $file = $this->file;
		if ($new_file === false) $new_file = $this->new_file;

		// параметры для image_lib - начальные
		$r_conf = array(
			'source_image' => getinfo('uploads_dir') . $file,
			'new_image' => getinfo('uploads_dir') . $new_file,
			'maintain_ratio' => false, // размеры по пропорции вычислим сами
			'quality' => $this->image_quality,
		);

		$r_conf['x_axis'] = $x;
		$r_conf['y_axis'] = $y;

		if ($width > 0) $r_conf['width'] = $width;
		if ($height > 0) $r_conf['height'] = $height;

		$CI->image_lib->initialize($r_conf);

		if (!$CI->image_lib->crop()) return false; // произошла какая-то ошибка

		return getinfo('uploads_url') . $new_file;
	}

	// кроп по центру изображения 
	public function crop_center($width = 0, $height = 0)
	{
		$width = ($width > 0) ? $width : 1;
		$height = ($height > 0) ? $height : 1;

		$x = round($this->image_info[0] / 2 - $width / 2);
		$y = round($this->image_info[1] / 2 - $height / 2);

		return $this->crop($width, $height, $x, $y);
	}

	// кроп по центру, где высота определяется пропорцией
	// если $ratio = 0, то пропорция высоты от самого изображения
	public function crop_center_ratio($width = 0, $ratio = 0)
	{
		$width = ($width > 0) ? $width : 1;

		if ($ratio == 0) {
			$ratio = $this->image_info[0] / $this->image_info[1]; // w/h
			$height = ceil($width / $ratio);
		} else {
			$height = ceil($width / $ratio);
		}

		return $this->crop_center($width, $height);
	}

	// вначале пропорциональная ширина
	// после обрезка кроп до указанных размеров
	public function resize_crop($width = 0, $height = 0, $x = 0, $y = 0)
	{
		$this->resize($width, 0);

		return $this->crop($width, $height, $x, $y, $this->new_file, $this->new_file);
	}

	// вначале пропорциональная ширина
	// после обрезка кроп до указанных размеров по центру
	public function resize_crop_center($width = 0, $height = 0)
	{
		$width = ($width > 0) ? $width : 1;
		$height = ($height > 0) ? $height : 1;

		$this->resize($width, 0);

		$image_info = GetImageSize(getinfo('uploads_dir') . $this->new_file);
		$x = round($image_info[0] / 2 - $width / 2);
		$y = round($image_info[1] / 2 - $height / 2);

		return $this->crop($width, $height, $x, $y, $this->new_file, $this->new_file);
	}

	// вначале пропорциональная высота(!)
	// после обрезка кроп до указанных размеров по центру
	public function resize_h_crop_center($width = 0, $height = 0)
	{
		$width = ($width > 0) ? $width : 1;
		$height = ($height > 0) ? $height : 1;

		$this->resize(0, $height);

		$image_info = GetImageSize(getinfo('uploads_dir') . $this->new_file);
		$x = round($image_info[0] / 2 - $width / 2);
		$y = round($image_info[1] / 2 - $height / 2);

		return $this->crop($width, $height, $x, $y, $this->new_file, $this->new_file);
	}

	// вначале пропорциональная высота/ширина 
	// после обрезка кроп до указанных размеров по центру
	// высота или ширина выбирается та, что больше, чтобы не было пустот в итоге
	public function resize_full_crop_center($width = 0, $height = 0)
	{

		$width = ($width > 0) ? $width : 1;
		$height = ($height > 0) ? $height : 1;

		// определяем пропорции реальные к требуемым
		// от них и скачем
		$w = $this->image_info[0] / $width;
		$h = $this->image_info[1] / $height;

		if ($w > $h) {
			$this->resize(0, $height);
		} else {
			$this->resize($width, 0);
		}

		$image_info = GetImageSize(getinfo('uploads_dir') . $this->new_file);
		$x = round($image_info[0] / 2 - $width / 2);
		$y = round($image_info[1] / 2 - $height / 2);

		return $this->crop($width, $height, $x, $y, $this->new_file, $this->new_file);
	}

	// аналогично resize_full_crop_center, но кроп от верхнего левого угла
	public function resize_full_crop_top_left($width = 0, $height = 0)
	{
		$width = ($width > 0) ? $width : 1;
		$height = ($height > 0) ? $height : 1;

		// определяем пропорции реальные к требуемым
		// от них и скачем
		$w = $this->image_info[0] / $width;
		$h = $this->image_info[1] / $height;

		if ($w > $h)
			$this->resize(0, $height);
		else
			$this->resize($width, 0);


		// $image_info = GetImageSize(getinfo('uploads_dir') . $this->new_file);
		$x = 0;
		$y = 0;

		return $this->crop($width, $height, $x, $y, $this->new_file, $this->new_file);
	}

	// аналогично resize_full_crop_center, но кроп от верхнего центра
	public function resize_full_crop_top_center($width = 0, $height = 0)
	{
		$width = ($width > 0) ? $width : 1;
		$height = ($height > 0) ? $height : 1;

		// определяем пропорции реальные к требуемым
		// от них и скачем
		$w = $this->image_info[0] / $width;
		$h = $this->image_info[1] / $height;

		if ($w > $h) {
			$this->resize(0, $height);
		} else {
			$this->resize($width, 0);
		}

		$image_info = GetImageSize(getinfo('uploads_dir') . $this->new_file);
		$x = round($image_info[0] / 2 - $width / 2);
		$y = 0;

		return $this->crop($width, $height, $x, $y, $this->new_file, $this->new_file);
	}

	// пропорциональное изменение размеров в процентах
	public function zoom($zoom = 50)
	{
		$zoom = ($zoom > 0) ? $zoom : 100;

		$w = $this->image_info[0] * $zoom / 100;
		$h = $this->image_info[1] * $zoom / 100;

		return $this->resize($w, $h);
	}

	// комбинация zoom и crop_center_ratio
	public function zoom_crop_center($zoom, $width, $ratio = 0)
	{
		$fu = $this->zoom($zoom); // результат url нового файла

		// вторая операция отдельно, поскольку это уже новый файл

		if (!$fu) return false;

		$fi = getinfo('uploads_dir') . str_replace(getinfo('uploads_url'), '', $fu);

		$image_info = GetImageSize($fi);
		$w = $image_info[0]; // ширина текущего

		// если размер меньше требуемого, то отдаем как есть без кропа
		if ($w < $width) return $fu;

		$h = $image_info[1]; // высота текущего

		if ($ratio == 0) $ratio = $w / $h;

		$height = ceil($width / $ratio); // конечная высота

		// смещение к центру
		$x = round($w / 2 - $width / 2);
		$y = round($h / 2 - $height / 2);

		// параметры для image_lib - начальные
		$r_conf = [
			'source_image' => $fi,
			'new_image' => $fi,
			'maintain_ratio' => false, // размеры по пропорции вычислим сами
			'quality' => $this->image_quality,
			'x_axis' => $x,
			'y_axis' => $y,
			'width' => $width,
			'height' => $height
		];

		$CI = &get_instance();
		$CI->load->library('image_lib');
		$CI->image_lib->clear();
		$CI->image_lib->initialize($r_conf);

		if (!$CI->image_lib->crop()) return false; // произошла какая-то ошибка

		return $fu;
	}

	// функция готовит превьюшку в _mso_i 
	public function preview()
	{
		// возможно файл в подкаталоге
		$e = strrpos($this->new_file, '/');

		if ($e !== false)
			$n = substr($this->new_file, $e + 1); // вычлиним только имя
		else
			$n = $this->new_file;

		$prev_file = str_replace($n, '_mso_i/' . $n, $this->new_file);

		$CI = &get_instance();
		$CI->load->library('image_lib');
		$CI->image_lib->clear();

		// параметры для image_lib - начальные
		$r_conf = [
			'source_image' => getinfo('uploads_dir') . $this->file,
			'new_image' => getinfo('uploads_dir') . $prev_file,
			'maintain_ratio' => false, // размеры по пропорции вычислим сами
			'width' => 100,
			'height' => 100,
			'quality' => $this->image_quality,
		];

		$CI->image_lib->initialize($r_conf);
		$CI->image_lib->resize();
	}
}

# end of file
