Files
AtomicOld/api/Image.php
2026-02-14 19:34:54 +03:00

568 lines
24 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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;
}
}