TF Learn (Tech Fry) + techfry library 1.3.4; login-gated, no repo -> deployed files. Signed-off-by: LÁZÁR Imre <imre@illusion.hu> Assisted-by: claude-code@claude-opus-4-8
423 lines
11 KiB
PHP
423 lines
11 KiB
PHP
<?php
|
|
/*
|
|
* @package Tech Fry Library
|
|
* @license https://www.gnu.org/licenses/gpl-3.0.en.html
|
|
*/
|
|
|
|
namespace TechFry\Library;
|
|
|
|
defined('_JEXEC') or die;
|
|
|
|
use Joomla\CMS\Factory;
|
|
use Joomla\CMS\Image\Image;
|
|
use Joomla\CMS\Filter\OutputFilter;
|
|
use Joomla\CMS\Filesystem\File;
|
|
use Joomla\CMS\Filesystem\Folder;
|
|
|
|
class TfImg
|
|
{
|
|
public static $image;
|
|
|
|
public static $image_filters = array(
|
|
'GRAYSCALE' => IMG_FILTER_GRAYSCALE,
|
|
'NEGATE' => IMG_FILTER_NEGATE,
|
|
'BRIGHTNESS' => IMG_FILTER_BRIGHTNESS,
|
|
'CONTRAST' => IMG_FILTER_CONTRAST,
|
|
'COLORIZE' => IMG_FILTER_COLORIZE,
|
|
'EDGEDETECT' => IMG_FILTER_EDGEDETECT,
|
|
'EMBOSS' => IMG_FILTER_EMBOSS,
|
|
'GAUSSIAN_BLUR' => IMG_FILTER_GAUSSIAN_BLUR,
|
|
'SELECTIVE_BLUR' => IMG_FILTER_SELECTIVE_BLUR,
|
|
'MEAN_REMOVAL' => IMG_FILTER_MEAN_REMOVAL,
|
|
'SMOOTH' => IMG_FILTER_SMOOTH,
|
|
'PIXELATE' => IMG_FILTER_PIXELATE,
|
|
'SCATTER' => IMG_FILTER_SCATTER
|
|
);
|
|
|
|
// 01. Save image from url to path
|
|
public static function get_img($url, $path)
|
|
{
|
|
$fp = fopen($path, 'wb');
|
|
|
|
$ch = curl_init($url);
|
|
curl_setopt($ch, CURLOPT_FILE, $fp);
|
|
curl_setopt($ch, CURLOPT_HEADER, 0);
|
|
|
|
$data = curl_exec($ch);
|
|
|
|
curl_close($ch);
|
|
|
|
fclose($fp);
|
|
|
|
return $data;
|
|
}
|
|
|
|
// 02. Resize image
|
|
public static function resize_image($path, $width, $total)
|
|
{
|
|
$size = getimagesize($path);
|
|
|
|
$r1 = ($size[0])/($size[1]); // Width to Height Ratio
|
|
|
|
// Calculate desired ratio
|
|
$r2 = ($width * $width)/$total;
|
|
|
|
if ($r1 < $r2)
|
|
{
|
|
$new_width = $width;
|
|
}
|
|
else
|
|
{
|
|
$new_width = ceil(sqrt($total * $r1));
|
|
}
|
|
|
|
// Load image file
|
|
$image = self::load_image($path);
|
|
|
|
// Use imagescale() function to scale the image
|
|
$new_image = imagescale($image, $new_width);
|
|
|
|
// Save image
|
|
self::save_image($new_image, $path);
|
|
|
|
imagedestroy($image);
|
|
|
|
return $new_width;
|
|
}
|
|
|
|
// 03. Returns random image from folder
|
|
public static function reset_image($folder = 'images')
|
|
{
|
|
$images = self::get_images($folder);
|
|
|
|
$i = count($images);
|
|
$random = mt_rand(0, $i - 1);
|
|
|
|
$image = $images[$random];
|
|
|
|
$image_url = $folder . '/' . $image;
|
|
|
|
return $image_url;
|
|
}
|
|
|
|
// 04. Create image
|
|
public static function create_image($title, $options = array(), $img_name = null)
|
|
{
|
|
// $options array - width, height, bg_color, text_color, src_folder, pct, dst_folder, font_base_url, fonttype
|
|
// For adding text from title - add_text, remove_words, fontsize, wordwrap
|
|
|
|
$image_name = OutputFilter::stringURLSafe($title);
|
|
|
|
$width = $options['width'];
|
|
$height = $options['height'];
|
|
|
|
// A. Create image canvas
|
|
self::create_blank_image($width, $height);
|
|
|
|
// B. Background color
|
|
self::image_fill($options['bg_color']);
|
|
|
|
// C. Add random image to canvas
|
|
if (!empty($options['src_folder']))
|
|
{
|
|
$random_image = self::reset_image($options['src_folder']);
|
|
|
|
self::copy_image(JPATH_ROOT . '/' . $random_image, $width, $height, $options['pct']);
|
|
}
|
|
|
|
// D. Add text to image
|
|
if ($options['add_text'])
|
|
{
|
|
// Delete some words
|
|
if (!empty($options['remove_words']))
|
|
{
|
|
$remove_words = explode(',', $options['remove_words']);
|
|
foreach ($remove_words as $word)
|
|
{
|
|
$title = str_ireplace(trim($word), '', $title);
|
|
}
|
|
$title = trim($title);
|
|
|
|
// Image name from new title
|
|
$image_name = OutputFilter::stringURLSafe($title);
|
|
}
|
|
|
|
$title_length = strlen($title);
|
|
$font_size = $options['fontsize'] - $title_length;
|
|
|
|
$word_wrap = floor($options['wordwrap']/$font_size);
|
|
$text = wordwrap($title, $word_wrap);
|
|
|
|
$font = JPATH_ROOT . '/' . $options['font_base_url'] . '/' . $options['fonttype'] . '.ttf';
|
|
|
|
self::image_text($text, $options['text_color'], $font, $font_size);
|
|
}
|
|
|
|
// E. Save image
|
|
// If $img_name is provided, use that instead of creating name from title
|
|
$image_name = $img_name ?? $image_name;
|
|
$dst = JPATH_ROOT . '/' . $options['dst_folder'] . '/' . $image_name . '.jpg';
|
|
|
|
self::save_image(self::$image, $dst);
|
|
|
|
imagedestroy(self::$image);
|
|
|
|
return $image_name;
|
|
}
|
|
|
|
// 05. Filter image
|
|
public static function filter_image($path, $filter = '')
|
|
{
|
|
if (empty($filter))
|
|
{
|
|
return;
|
|
}
|
|
|
|
$filter = strtoupper($filter);
|
|
|
|
$image = self::load_image($path);
|
|
|
|
$result = imagefilter($image, self::$image_filters[$filter]);
|
|
|
|
self::save_image($image, $path);
|
|
|
|
imagedestroy($image);
|
|
|
|
return $result;
|
|
}
|
|
|
|
public static function convert_image_to_webp($image_url)
|
|
{
|
|
$path = pathinfo($image_url);
|
|
|
|
$dest = JPATH_ROOT . '/' . $path['dirname'] . '/' . $path['filename'] . '.webp';
|
|
|
|
$image = self::load_image(JPATH_ROOT . '/' . $image_url);
|
|
|
|
// Create new webp image
|
|
imagewebp($image, $dest);
|
|
|
|
imagedestroy($image);
|
|
|
|
// New image URL with webp
|
|
$new_image_url = $path['dirname'] . '/' . $path['filename'] . '.webp';
|
|
|
|
// Delete original file
|
|
self::delete_image($image_url);
|
|
|
|
return $new_image_url;
|
|
}
|
|
|
|
// Create image canvas
|
|
public static function create_blank_image($width, $height)
|
|
{
|
|
self::$image = imagecreatetruecolor($width, $height);
|
|
|
|
if (self::$image == false)
|
|
{
|
|
self::set_message('Error in creating image');
|
|
}
|
|
}
|
|
|
|
// Fill image with color
|
|
public static function image_fill($color)
|
|
{
|
|
$image_color = self::get_image_color($color);
|
|
|
|
imagefill(self::$image, 0, 0, $image_color);
|
|
}
|
|
|
|
public static function get_image_color($color)
|
|
{
|
|
list($r1, $g1, $b1) = sscanf($color, "#%02x%02x%02x");
|
|
|
|
$image_color = imagecolorallocate(self::$image, $r1, $g1, $b1);
|
|
|
|
return $image_color;
|
|
}
|
|
|
|
public static function copy_image($path, $src_width, $src_height, $pct)
|
|
{
|
|
$src_image = self::load_image($path);
|
|
|
|
$dst_x = 0;
|
|
$dst_y = 0;
|
|
$src_x = 0;
|
|
$src_y = 0;
|
|
|
|
// $result = imagecopy(self::$image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $src_width, $src_height);
|
|
$result = imagecopymerge(self::$image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $src_width, $src_height, $pct);
|
|
|
|
imagedestroy($src_image);
|
|
|
|
if ($result == false)
|
|
{
|
|
self::set_message('Error in copying image');
|
|
}
|
|
}
|
|
|
|
// Add text to image
|
|
public static function image_text($text, $text_color, $font, $font_size)
|
|
{
|
|
if (empty($text))
|
|
{
|
|
return;
|
|
}
|
|
|
|
$tb = self::text_box($text, $font, $font_size);
|
|
|
|
// Center align text
|
|
$width = imagesx(self::$image);
|
|
$height = imagesy(self::$image);
|
|
|
|
$x = ($width - $tb['width'])/2;
|
|
$y = ($height - $tb['height'])/2;
|
|
|
|
$image_color = self::get_image_color($text_color);
|
|
|
|
imagettftext(self::$image, $font_size, 0, $x, $y, $image_color, $font, $text);
|
|
}
|
|
|
|
// Get text box width and height
|
|
public static function text_box($text, $font, $font_size)
|
|
{
|
|
$box = imagettfbbox($font_size, 0, $font, $text);
|
|
|
|
$tb['width'] = abs($box[4] - $box[0]);
|
|
|
|
$tb['height'] = abs($box[5] - $box[1]);
|
|
|
|
return $tb;
|
|
}
|
|
|
|
public static function delete_image($image_url)
|
|
{
|
|
File::delete(JPATH_ROOT . '/' . $image_url);
|
|
}
|
|
|
|
// Load image based on its extension
|
|
public static function load_image($path)
|
|
{
|
|
$ext = pathinfo($path, PATHINFO_EXTENSION);
|
|
|
|
switch ($ext)
|
|
{
|
|
case 'jpeg' :
|
|
$image = imagecreatefromjpeg($path);
|
|
break;
|
|
|
|
case 'jpg' :
|
|
$image = imagecreatefromjpeg($path);
|
|
break;
|
|
|
|
case 'png' :
|
|
$image = imagecreatefrompng($path);
|
|
break;
|
|
|
|
case 'webp' :
|
|
$image = imagecreatefromwebp($path);
|
|
break;
|
|
|
|
case 'gif' :
|
|
$image = imagecreatefromgif($path);
|
|
}
|
|
|
|
if ($image == false)
|
|
{
|
|
self::set_message('Unable to load image: ' . $path);
|
|
}
|
|
|
|
return $image;
|
|
}
|
|
|
|
// Save image based on its extension
|
|
public static function save_image($image, $destination)
|
|
{
|
|
$ext = pathinfo($destination, PATHINFO_EXTENSION);
|
|
|
|
switch ($ext)
|
|
{
|
|
case 'jpeg' :
|
|
$result = imagejpeg($image, $destination);
|
|
break;
|
|
|
|
case 'jpg' :
|
|
$result = imagejpeg($image, $destination);
|
|
break;
|
|
|
|
case 'png' :
|
|
$result = imagepng($image, $destination);
|
|
break;
|
|
|
|
case 'webp' :
|
|
$result = imagewebp($image, $destination);
|
|
break;
|
|
|
|
case 'gif' :
|
|
$result = imagegif($image, $destination);
|
|
}
|
|
|
|
if ($result == false)
|
|
{
|
|
self::set_message('Error in saving image.');
|
|
}
|
|
}
|
|
|
|
// Returns array of image filenames in a folder
|
|
public static function get_images($folder)
|
|
{
|
|
$dir = JPATH_ROOT . '/' . $folder;
|
|
|
|
if (is_dir($dir))
|
|
{
|
|
if ($handle = opendir($dir))
|
|
{
|
|
while (false !== ($file = readdir($handle)))
|
|
{
|
|
if ($file !== '.' && $file !== '..' && $file !== 'index.html')
|
|
{
|
|
$files[] = $file;
|
|
}
|
|
}
|
|
}
|
|
|
|
closedir($handle);
|
|
|
|
$i = 0;
|
|
|
|
foreach ($files as $img)
|
|
{
|
|
if (!is_dir($dir . '/' . $img))
|
|
{
|
|
$images[$i] = $img;
|
|
$i++;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return $images;
|
|
}
|
|
|
|
public static function create_folder($path)
|
|
{
|
|
// $path is: JPATH_SITE . '/images/folder_name';
|
|
|
|
$result = Folder::create($path);
|
|
|
|
return $result;
|
|
}
|
|
|
|
// Get image properties
|
|
public static function get_image_properties($path)
|
|
{
|
|
$data = Image::getImageFileProperties($path);
|
|
|
|
return $data;
|
|
}
|
|
|
|
public static function set_message($message)
|
|
{
|
|
Factory::getApplication()->enqueueMessage($message);
|
|
}
|
|
} |