Files
AtomicOld/api/Image.php

568 lines
24 KiB
PHP
Raw Permalink Normal View History

2026-02-14 19:34:54 +03:00
<?php
/**
* Simpla CMS
*
* @copyright 2011 Denis Pikusov
* @link http://simplacms.ru
* @author Denis Pikusov
*
*/
require_once ('Simpla.php');
if(!class_exists('SimpleImage')) include $_SERVER['DOCUMENT_ROOT'].'/api/SimpleImage.php';
class Image extends Simpla
{
private $allowed_extentions = array(
'png',
'gif',
'jpg',
'jpeg',
'ico');
public function __construct()
{
parent::__construct();
}
/**
* Создание превью изображения
* @param $filename файл с изображением (без пути к файлу)
* @param max_w максимальная ширина
* @param max_h максимальная высота
* @return $string имя файла превью
*/
function resizepost($filename)
{
list($source_file, $width, $height, $set_watermark) = $this->get_resize_params($filename);
// Если вайл удаленный (http://), зальем его себе
if (substr($source_file, 0, 7) == 'http://')
{
// Имя оригинального файла
if (!$original_file = $this->download_image($source_file))
return false;
$resized_file = $this->add_resize_params($original_file, $width, $height, $set_watermark);
}
else
{
$original_file = $source_file;
}
$resized_file = $this->add_resize_params($original_file, $width, $height, $set_watermark);
// Пути к папкам с картинками
$originals_dir = $this->config->root_dir . $this->config->original_images_dir;
$preview_dir = $this->config->root_dir . $this->config->post_images_dir;
if (class_exists('Imagick') && $this->config->use_imagick)
$this->image_constrain_imagick($originals_dir . $original_file, $preview_dir . $resized_file, $width, $height);
else
$this->image_constrain_gd($originals_dir . $original_file, $preview_dir . $resized_file, $width, $height);
return $preview_dir . $resized_file;
}
function resizepage($filename)
{
list($source_file, $width, $height, $set_watermark) = $this->get_resize_params($filename);
// Если вайл удаленный (http://), зальем его себе
if (substr($source_file, 0, 7) == 'http://')
{
// Имя оригинального файла
if (!$original_file = $this->download_image($source_file))
return false;
$resized_file = $this->add_resize_params($original_file, $width, $height, $set_watermark);
}
else
{
$original_file = $source_file;
}
$resized_file = $this->add_resize_params($original_file, $width, $height, $set_watermark);
// Пути к папкам с картинками
$originals_dir = $this->config->root_dir . $this->config->original_images_dir;
$preview_dir = $this->config->root_dir . $this->config->page_images_dir;
if (class_exists('Imagick') && $this->config->use_imagick)
$this->image_constrain_imagick($originals_dir . $original_file, $preview_dir . $resized_file, $width, $height);
else
$this->image_constrain_gd($originals_dir . $original_file, $preview_dir . $resized_file, $width, $height);
return $preview_dir . $resized_file;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function resizecat($filename)
{
//list($source_file, $width , $height, $set_watermark) = $this->get_resize_params($filename); //echo $source_file;exit;
// Если вайл удаленный (http://), зальем его себе
/*
if(substr($source_file, 0, 7) == 'http://')
{
// Имя оригинального файла
if(!$original_file = $this->download_image($source_file))
return false;
$resized_file = $this->add_resize_params($original_file, $width, $height, $set_watermark);
}
else
{
$original_file = $source_file;
}
$resized_file = $this->add_resize_params($original_file, $width, $height, $set_watermark);
*/
$width = 252;
$height = 252;
$original_file = $filename;
$resized_file = $this->add_resize_params($filename, $width, $height, $set_watermark);
// Пути к папкам с картинками
$originals_dir = $this->config->root_dir . $this->config->categories_images_dir;
$preview_dir = $this->config->root_dir . $this->config->categories_images_dir;
if (class_exists('Imagick') && $this->config->use_imagick)
$this->image_constrain_imagick($originals_dir . $original_file, $preview_dir . $resized_file, $width, $height);
else
$this->image_constrain_gd($originals_dir . $original_file, $preview_dir . $resized_file, $width, $height);
return $preview_dir . $resized_file;
//echo $preview_dir .'999'. $resized_file;
}
function resizeArticle($filename, $width, $height)
{
$original_file = $filename;
$resized_file = $this->add_resize_params($filename, $width, $height, $set_watermark);
// Пути к папкам с картинками
$originals_dir = $this->config->root_dir . 'files/article_photo/';
$preview_dir = $this->config->root_dir . 'files/article_photo/';
if(is_file($preview_dir . $resized_file)) return '/files/article_photo/' . $resized_file;
$img = new SimpleImage($originals_dir . $filename);
if($width == $height) $img->square_crop($width)->save($preview_dir . $resized_file);
else $img->best_fit($width, $height)->save($preview_dir . $resized_file);
return '/files/article_photo/' . $resized_file;
//echo $preview_dir .'999'. $resized_file;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function resize($filename, $imgs_dir = '')
{
$imgs_dir = $imgs_dir ? $imgs_dir : $this->config->resized_images_dir;
$orig_dir = $imgs_dir ? $imgs_dir : $this->config->original_images_dir;
list($source_file, $width, $height, $set_watermark) = $this->get_resize_params($filename);
// Если вайл удаленный (http://), зальем его себе
if (substr($source_file, 0, 7) == 'http://')
{
// Имя оригинального файла
if (!$original_file = $this->download_image($source_file))
return false;
$resized_file = $this->add_resize_params($original_file, $width, $height, $set_watermark);
}
else
{
$original_file = $source_file;
} echo $original_file;
$resized_file = $this->add_resize_params($original_file, $width, $height, $set_watermark);
// Пути к папкам с картинками
$originals_dir = $this->config->root_dir . $this->config->original_images_dir;
$preview_dir = $this->config->root_dir . $this->config->resized_images_dir;
$watermark_offet_x = $this->settings->watermark_offset_x;
$watermark_offet_y = $this->settings->watermark_offset_y;
$sharpen = min(100, $this->settings->images_sharpen) / 100;
$watermark_transparency = 1 - min(100, $this->settings->watermark_transparency) / 100;
if ($set_watermark && is_file($this->config->watermark_file))
$watermark = $this->config->root_dir . $this->config->watermark_file;
else
$watermark = null;
if (class_exists('Imagick') && $this->config->use_imagick)
$this->image_constrain_imagick($originals_dir . $original_file, $preview_dir . $resized_file, $width, $height, $watermark, $watermark_offet_x, $watermark_offet_y, $watermark_transparency, $sharpen);
else
$this->image_constrain_gd($originals_dir . $original_file, $preview_dir . $resized_file, $width, $height, $watermark, $watermark_offet_x, $watermark_offet_y, $watermark_transparency);
//echo $preview_dir . '1'. $resized_file;
return $preview_dir . $resized_file;
}
public function add_resize_params($filename, $width = 0, $height = 0, $set_watermark = false)
{
if ('.' != ($dirname = pathinfo($filename, PATHINFO_DIRNAME)))
$file = $dirname . '/' . pathinfo($filename, PATHINFO_FILENAME);
else
$file = pathinfo($filename, PATHINFO_FILENAME);
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if ($width > 0 || $height > 0)
$resized_filename = $file . '.' . ($width > 0 ? $width : '') . 'x' . ($height > 0 ? $height : '') . ($set_watermark ? 'w' : '') . '.' . $ext;
else
$resized_filename = $file . '.' . ($set_watermark ? 'w.' : '') . $ext;
return $resized_filename;
}
public function get_resize_params($filename)
{
// Определаяем параметры ресайза
if (!preg_match('/(.+)\.([0-9]*)x([0-9]*)(w)?\.([^\.]+)$/', $filename, $matches))
return false;
$file = $matches[1]; // имя запрашиваемого файла
$width = $matches[2]; // ширина будущего изображения
$height = $matches[3]; // высота будущего изображения
$set_watermark = $matches[4] == 'w'; // ставить ли водяной знак
$ext = $matches[5]; // расширение файла
return array(
$file . '.' . $ext,
$width,
$height,
$set_watermark);
}
public function download_image($filename)
{
// Заливаем только есть такой файл есть в базе
$this->db->query('SELECT 1 FROM __images WHERE filename=? LIMIT 1', $filename);
if (!$this->db->result())
return false;
// Имя оригинального файла
$uploaded_file = array_shift(explode('?', pathinfo($filename, PATHINFO_BASENAME)));
$uploaded_file = array_shift(explode('&', pathinfo($filename, PATHINFO_BASENAME)));
$base = urldecode(pathinfo($uploaded_file, PATHINFO_FILENAME));
$ext = pathinfo($uploaded_file, PATHINFO_EXTENSION);
// Если такой файл существует, нужно придумать другое название
$new_name = urldecode($uploaded_file);
while (file_exists($this->config->root_dir . $this->config->original_images_dir . $new_name))
{
$new_base = pathinfo($new_name, PATHINFO_FILENAME);
if (preg_match('/_([0-9]+)$/', $new_base, $parts))
$new_name = $base . '_' . ($parts[1] + 1) . '.' . $ext;
else
$new_name = $base . '_1.' . $ext;
}
$this->db->query('UPDATE __images SET filename=? WHERE filename=?', $new_name, $filename);
// Перед долгим копированием займем это имя
fclose(fopen($this->config->root_dir . $this->config->original_images_dir . $new_name, 'w'));
copy($filename, $this->config->root_dir . $this->config->original_images_dir . $new_name);
return $new_name;
}
public function upload_image($filename, $name)
{
// Имя оригинального файла
$uploaded_file = $new_name = pathinfo($name, PATHINFO_BASENAME);
//$uploaded_file = $new_name = $this->rus_lat($new_name);
$uploaded_file = $new_name = $this->translateStr($new_name);
$base = pathinfo($uploaded_file, PATHINFO_FILENAME);
$ext = pathinfo($uploaded_file, PATHINFO_EXTENSION);
if (in_array(strtolower($ext), $this->allowed_extentions))
{
while (file_exists($this->config->root_dir . $this->config->original_images_dir . $new_name))
{
$new_base = pathinfo($new_name, PATHINFO_FILENAME);
if (preg_match('/_([0-9]+)$/', $new_base, $parts))
$new_name = $base . '_' . ($parts[1] + 1) . '.' . $ext;
else
$new_name = $base . '_1.' . $ext;
}
if (move_uploaded_file($filename, $this->config->root_dir . $this->config->original_images_dir . $new_name)){
$img = new SimpleImage($this->config->root_dir . $this->config->original_images_dir . $new_name);
$img->best_fit(1200, 1200)->save($this->config->root_dir . $this->config->original_images_dir . $new_name); //echo '---'.$this->config->root_dir . $this->config->original_images_dir . $new_name;
return $new_name;
}else{
//die($filename . '='.$this->config->root_dir . $this->config->original_images_dir . $new_name);
}
}else{
//die('bad image');
}
return false;
}
function rus_lat($name){
$rus = array('','а','б','в','г','д','е','ё','Ё','ж','з','и','й','к',
'л','м','н','о','п','р','с','т','у','ф','х','ц','ч','ш','щ','ъ','ы','ь','э','ю','я');
$eng = array('','a','b','v','g','d','e','e','e','zh','z','i','j','k',
'l','m','n','o','p','r','s','t','u','f','h','c','ch','sh','shch','','y','','e','yu','ya');
$name = mb_strtolower($name,"UTF-8");
$name = str_replace(array('"',"'"),'',$name);
$name = str_replace(array(',',':',';','/','{','}','[',']'),'',$name);
$name = str_replace(array(' '),'_',$name);
$res = '';
$arr = $this->str_split_unicode($name);
foreach($arr as $key){
if($key == '_'){
$res .= '_';
continue;
}
if (!preg_match("/[а-я]/i", $key)){
$res .= $key;
continue;
}
$k = array_search($key,$rus);
if($k){
$res .= $eng[$k];
}
}
return $res;
}
function str_split_unicode($str, $l = 0) {
if ($l > 0) {
$ret = array();
$len = mb_strlen($str, "UTF-8");
for ($i = 0; $i < $len; $i += $l) {
$ret[] = mb_substr($str, $i, $l, "UTF-8");
}
return $ret;
}
return preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY);
}
/**
* Создание превью средствами gd
* @param $src_file исходный файл
* @param $dst_file файл с результатом
* @param max_w максимальная ширина
* @param max_h максимальная высота
* @return bool
*/
function image_constrain_gd($src_file, $dst_file, $max_w, $max_h, $watermark = null, $watermark_offet_x = 0, $watermark_offet_y = 0, $watermark_opacity = 1)
{
$quality = 100;
// Параметры исходного изображения
@list($src_w, $src_h, $src_type) = array_values(getimagesize($src_file));
$src_type = image_type_to_mime_type($src_type);
// if($src_type == 'application/octet-stream') $src_type = 'image/jpeg';
if (empty($src_w) || empty($src_h) || empty($src_type))
return false;
// Нужно ли обрезать?
if (!$watermark && ($src_w <= $max_w) && ($src_h <= $max_h))
{
// Нет - просто скопируем файл
if (!copy($src_file, $dst_file))
return false;
return true;
}
// Размеры превью при пропорциональном уменьшении
@list($dst_w, $dst_h) = $this->calc_contrain_size($src_w, $src_h, $max_w, $max_h);
// Читаем изображение
switch ($src_type)
{
case 'image/jpeg':
$src_img = imageCreateFromJpeg($src_file);
break;
case 'image/gif':
$src_img = imageCreateFromGif($src_file);
break;
case 'image/png':
$src_img = imageCreateFromPng($src_file);
imagealphablending($src_img, true);
break;
default:
return false;
}
if (empty($src_img))
return false;
$src_colors = imagecolorstotal($src_img);
// create destination image (indexed, if possible)
if ($src_colors > 0 && $src_colors <= 256)
$dst_img = imagecreate($dst_w, $dst_h);
else
$dst_img = imagecreatetruecolor($dst_w, $dst_h);
if (empty($dst_img))
return false;
$transparent_index = imagecolortransparent($src_img);
if ($transparent_index >= 0 && $transparent_index <= 128)
{
$t_c = imagecolorsforindex($src_img, $transparent_index);
$transparent_index = imagecolorallocate($dst_img, $t_c['red'], $t_c['green'], $t_c['blue']);
if ($transparent_index === false)
return false;
if (!imagefill($dst_img, 0, 0, $transparent_index))
return false;
imagecolortransparent($dst_img, $transparent_index);
}
// or preserve alpha transparency for png
elseif ($src_type === 'image/png')
{
if (!imagealphablending($dst_img, false))
return false;
$transparency = imagecolorallocatealpha($dst_img, 0, 0, 0, 127);
if (false === $transparency)
return false;
if (!imagefill($dst_img, 0, 0, $transparency))
return false;
if (!imagesavealpha($dst_img, true))
return false;
}
// resample the image with new sizes
if (!imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $dst_w, $dst_h, $src_w, $src_h))
return false;
// Watermark
if (!empty($watermark) && is_readable($watermark))
{
$overlay = imagecreatefrompng($watermark);
// Get the size of overlay
$owidth = imagesx($overlay);
$oheight = imagesy($overlay);
$watermark_x = min(($dst_w - $owidth) * $watermark_offet_x / 100, $dst_w);
$watermark_y = min(($dst_h - $oheight) * $watermark_offet_y / 100, $dst_h);
imagecopy($dst_img, $overlay, $watermark_x, $watermark_y, 0, 0, $owidth, $oheight);
//imagecopymerge($dst_img, $overlay, $watermark_x, $watermark_y, 0, 0, $owidth, $oheight, $watermark_opacity*100);
}
// recalculate quality value for png image
if ('image/png' === $src_type)
{
$quality = round(($quality / 100) * 10);
if ($quality < 1)
$quality = 1;
elseif ($quality > 10)
$quality = 10;
$quality = 10 - $quality;
}
// Сохраняем изображение
switch ($src_type)
{
case 'image/jpeg':
return imageJpeg($dst_img, $dst_file, $quality);
case 'image/gif':
return imageGif($dst_img, $dst_file, $quality);
case 'image/png':
imagesavealpha($dst_img, true);
return imagePng($dst_img, $dst_file, $quality);
default:
return false;
}
}
/**
* Создание превью средствами imagick
* @param $src_file исходный файл
* @param $dst_file файл с результатом
* @param max_w максимальная ширина
* @param max_h максимальная высота
* @return bool
*/
function image_constrain_imagick($src_file, $dst_file, $max_w, $max_h, $watermark = null, $watermark_offet_x = 0, $watermark_offet_y = 0, $watermark_opacity = 1, $sharpen = 0.2)
{
$thumb = new Imagick();
// Читаем изображение
if (!$thumb->readImage($src_file))
return false;
// Размеры исходного изображения
$src_w = $thumb->getImageWidth();
$src_h = $thumb->getImageHeight();
// Нужно ли обрезать?
if (!$watermark && ($src_w <= $max_w) && ($src_h <= $max_h))
{
// Нет - просто скопируем файл
if (!copy($src_file, $dst_file))
return false;
return true;
}
// Размеры превью при пропорциональном уменьшении
list($dst_w, $dst_h) = $this->calc_contrain_size($src_w, $src_h, $max_w, $max_h);
// Уменьшаем
$thumb->thumbnailImage($dst_w, $dst_h);
// Устанавливаем водяной знак
if ($watermark && is_readable($watermark))
{
$overlay = new Imagick($watermark);
//$overlay->setImageOpacity($watermark_opacity);
//$overlay_compose = $overlay->getImageCompose();
$overlay->evaluateImage(Imagick::EVALUATE_MULTIPLY, $watermark_opacity, Imagick::CHANNEL_ALPHA);
// Get the size of overlay
$owidth = $overlay->getImageWidth();
$oheight = $overlay->getImageHeight();
$watermark_x = min(($dst_w - $owidth) * $watermark_offet_x / 100, $dst_w);
$watermark_y = min(($dst_h - $oheight) * $watermark_offet_y / 100, $dst_h);
}
// Анимированные gif требуют прохода по фреймам
foreach ($thumb as $frame)
{
// Уменьшаем
$frame->thumbnailImage($dst_w, $dst_h);
/* Set the virtual canvas to correct size */
$frame->setImagePage($dst_w, $dst_h, 0, 0);
// Наводим резкость
if ($sharpen > 0)
$thumb->adaptiveSharpenImage($sharpen, $sharpen);
if (isset($overlay) && is_object($overlay))
{
// $frame->compositeImage($overlay, $overlay_compose, $watermark_x, $watermark_y, imagick::COLOR_ALPHA);
$frame->compositeImage($overlay, imagick::COMPOSITE_OVER, $watermark_x, $watermark_y, imagick::COLOR_ALPHA);
}
}
// Убираем комменты и т.п. из картинки
$thumb->stripImage();
// $thumb->setImageCompressionQuality(100);
// Записываем картинку
if (!$thumb->writeImages($dst_file, true))
return false;
// Уборка
$thumb->destroy();
if (isset($overlay) && is_object($overlay))
$overlay->destroy();
return true;
}
/**
* Вычисляет размеры изображения, до которых нужно его пропорционально уменьшить, чтобы вписать в квадрат $max_w x $max_h
* @param src_w ширина исходного изображения
* @param src_h высота исходного изображения
* @param max_w максимальная ширина
* @param max_h максимальная высота
* @return array(w, h)
*/
function calc_contrain_size($src_w, $src_h, $max_w = 0, $max_h = 0)
{
if ($src_w == 0 || $src_h == 0)
return false;
$dst_w = $src_w;
$dst_h = $src_h;
if ($src_w > $max_w && $max_w > 0)
{
$dst_h = $src_h * ($max_w / $src_w);
$dst_w = $max_w;
}
if ($dst_h > $max_h && $max_h > 0)
{
$dst_w = $dst_w * ($max_h / $dst_h);
$dst_h = $max_h;
}
return array($dst_w, $dst_h);
}
private function files_identical($fn1, $fn2)
{
$buffer_len = 1024;
if (!$fp1 = fopen($fn1, 'rb'))
return false;
if (!$fp2 = fopen($fn2, 'rb'))
{
fclose($fp1);
return false;
}
$same = true;
while (!feof($fp1) and !feof($fp2))
if (fread($fp1, $buffer_len) !== fread($fp2, $buffer_len))
{
$same = false;
break;
}
if (feof($fp1) !== feof($fp2))
$same = false;
fclose($fp1);
fclose($fp2);
return $same;
}
}