Your IP : 216.73.216.62


Current Path : /proc/thread-self/root/proc/thread-self/root/proc/1908984/root/proc/1147586/cwd/
Upload File :
Current File : //proc/thread-self/root/proc/thread-self/root/proc/1908984/root/proc/1147586/cwd/Image.php.tar

home/digilove/public_html/libraries/src/Image/Image.php000064400000004014152346153750017132 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Image;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Log\Log;

/**
 * Class to manipulate an image.
 *
 * @since  1.7.3
 */
class Image extends \Joomla\Image\Image
{
	/**
	 * Class constructor.
	 *
	 * @param   mixed  $source  Either a file path for a source image or a GD resource handler for an image.
	 *
	 * @since   1.7.3
	 * @throws  \RuntimeException
	 */
	public function __construct($source = null)
	{
		// Inject the PSR-3 compatible logger in for forward compatibility
		$this->setLogger(Log::createDelegatedLogger());

		parent::__construct($source);
	}

	/**
	 * Method to get an image filter instance of a specified type.
	 *
	 * @param   string  $type  The image filter type to get.
	 *
	 * @return  ImageFilter
	 *
	 * @since   1.7.3
	 * @throws  \RuntimeException
	 */
	protected function getFilterInstance($type)
	{
		try
		{
			return parent::getFilterInstance($type);
		}
		catch (\RuntimeException $e)
		{
			// Ignore, filter is probably not namespaced
		}

		// Sanitize the filter type.
		$type = strtolower(preg_replace('#[^A-Z0-9_]#i', '', $type));

		// Verify that the filter type exists.
		$className = 'JImageFilter' . ucfirst($type);

		if (!class_exists($className))
		{
			Log::add('The ' . ucfirst($type) . ' image filter is not available.', Log::ERROR);
			throw new \RuntimeException('The ' . ucfirst($type) . ' image filter is not available.');
		}

		// Instantiate the filter object.
		$instance = new $className($this->getHandle());

		// Verify that the filter type is valid.
		if (!($instance instanceof ImageFilter))
		{
			// @codeCoverageIgnoreStart
			Log::add('The ' . ucfirst($type) . ' image filter is not valid.', Log::ERROR);
			throw new \RuntimeException('The ' . ucfirst($type) . ' image filter is not valid.');

			// @codeCoverageIgnoreEnd
		}

		return $instance;
	}
}
home/digilove/public_html/libraries/regularlabs/src/Image.php000064400000026325152346260470020422 0ustar00<?php
/**
 * @package         Regular Labs Library
 * @version         23.7.24631
 * 
 * @author          Peter van Westen <info@regularlabs.com>
 * @link            https://regularlabs.com
 * @copyright       Copyright © 2023 Regular Labs All Rights Reserved
 * @license         GNU General Public License version 2 or later
 */

namespace RegularLabs\Library;

defined('_JEXEC') or die;

use Exception;
use Joomla\CMS\Filesystem\Folder as JFolder;
use Joomla\CMS\Uri\Uri as JUri;
use Joomla\Image\Image as JImage;

class Image
{
    public static function cleanPath($source)
    {
        $source = ltrim(str_replace(JUri::root(), '', $source), '/');
        $source = strtok($source, '?');

        return $source;
    }

    public static function getDimensions($source)
    {
        $empty = (object) [
            'width'  => 0,
            'height' => 0,
        ];

        $image = self::getImageObject(JPATH_SITE . '/' . $source);

        if (is_null($image))
        {
            return $empty;
        }

        return (object) [
            'width'  => $image->getWidth(),
            'height' => $image->getHeight(),
        ];
    }

    public static function getHeight($source)
    {
        $dimensions = self::getDimensions($source);

        return $dimensions->height;
    }

    public static function getImageObject($source)
    {
        if (File::isExternal($source))
        {
            return null;
        }

        if ( ! file_exists($source))
        {
            return null;
        }

        if ( ! getimagesize($source))
        {
            return null;
        }

        try
        {
            $image = new JImage($source);
        }
        catch (Exception $e)
        {
            return null;
        }

        if ( ! ($image instanceof JImage))
        {
            return null;
        }

        if ( ! $image->isLoaded())
        {
            return null;
        }

        return $image;
    }

    public static function getJpgQuality($quality = 'medium')
    {
        switch ($quality)
        {
            case 'low':
                return 50;

            case 'high':
                return 90;

            case 'medium':
            default:
                return 70;
        }
    }

    public static function getNewPath($source, $width, $height, $destination_folder = '')
    {
        $clean_source = self::cleanPath($source);

        $source_parts = pathinfo($clean_source);

        $destination_folder = ltrim($destination_folder ?: File::getDirName($clean_source));
        $destination_file   = File::getFileName($clean_source) . '_' . $width . 'x' . $height . '.' . $source_parts['extension'];

        JFolder::create(JPATH_SITE . '/' . $destination_folder);

        return ltrim($destination_folder . '/' . $destination_file);
    }

    public static function getQuality($type, $quality = 'medium')
    {
        switch ($type)
        {
            case IMAGETYPE_JPEG:
                return min(max(self::getJpgQuality($quality), 0), 100);

            case IMAGETYPE_PNG:
                return 9;

            default:
                return '';
        }
    }

    public static function getResize($source, $width, $height, $folder = 'resized', $resize = true, $quality = 'medium')
    {
        $destination_folder = File::getDirName($source) . '/' . $folder;

        $override = File::getDirName($source) . '/' . $folder . '/' . File::getBaseName($source);

        if (file_exists(JPATH_SITE . '/' . $override))
        {
            $source = $override;
        }

        if ( ! self::setNewDimensions($source, $width, $height))
        {
            return $source;
        }

        if ( ! $width && ! $height)
        {
            return $source;
        }

        $destination = self::getNewPath(
            $source,
            $width,
            $height,
            $destination_folder
        );

        if ( ! file_exists(JPATH_SITE . '/' . $destination) && $resize)
        {
            // Create new resized image
            $destination = self::resize(
                $source,
                $width,
                $height,
                $destination_folder,
                $quality
            );
        }

        if ( ! file_exists(JPATH_SITE . '/' . $destination))
        {
            return $source;
        }

        return $destination;
    }

    public static function getUrls($source, $width, $height, $folder = 'resized', $resize = true, $quality = 'medium', $possible_suffix = '')
    {
        $image = self::isResized($source, $folder, $possible_suffix);

        if ($image)
        {
            $source = $image;
        }

        $original = $source;
        $resized  = self::getResize($source, $width, $height, $folder, $resize, $quality);

        return (object) compact('original', 'resized');
    }

    public static function getWidth($source)
    {
        $dimensions = self::getDimensions($source);

        return $dimensions->width;
    }

    public static function isResized($file, $folder = 'resized', $possible_suffix = '')
    {
        if (File::isExternal($file))
        {
            return false;
        }

        if ( ! file_exists($file))
        {
            return false;
        }

        $main_image = self::isResizedWithFolder($file, $folder);

        if ($main_image)
        {
            return $main_image;
        }

        if ( ! $possible_suffix)
        {
            return false;
        }

        return (bool) self::isResizedWithSuffix($file, $possible_suffix);
    }

    public static function isResizedWithSuffix($file, $suffix = '_t')
    {
        // Remove the suffix from the file
        // image_t.jpg => image.jpg
        $main_file = RegEx::replace(
            RegEx::quote($suffix) . '(\.[^.]+)$',
            '\1',
            $file
        );

        // Nothing removed, so not a resized image
        if ($main_file == $file)
        {
            return false;
        }

        if ( ! file_exists(JPATH_SITE . '/' . utf8_decode($main_file)))
        {
            return false;
        }

        return $main_file;
    }

    public static function resize($source, &$width, &$height, $destination_folder = '', $quality = 'medium', $overwrite = false)
    {
        if (File::isExternal($source))
        {
            return $source;
        }

        $clean_source = self::cleanPath($source);
        $source_path  = JPATH_SITE . '/' . $clean_source;

        $destination_folder = ltrim($destination_folder ?: File::getDirName($clean_source));
        $destination_folder = self::cleanPath($destination_folder);

        $image = self::getImageObject($source_path);

        if (is_null($image))
        {
            return $source;
        }

        self::fixRotation($image);

        if ( ! self::setNewDimensionsByImageObject($image, $width, $height))
        {
            return $source;
        }

        if ( ! $width && ! $height)
        {
            return $source;
        }

        $destination      = self::getNewPath($source, $width, $height, $destination_folder);
        $destination_path = JPATH_SITE . '/' . $destination;

        if (file_exists($destination_path) && ! $overwrite)
        {
            return $destination;
        }

        JFolder::create(JPATH_SITE . '/' . $destination_folder);

        try
        {
            $info = JImage::getImageFileProperties($source_path);

            $options = ['quality' => self::getQuality($info->type, $quality)];

            $image->cropResize($width, $height, false)
                ->toFile($destination_path, $info->type, $options);

            return $destination;
        }
        catch (Exception $e)
        {
            return $source;
        }
    }

    private static function fixRotation(&$image)
    {
        if ( ! function_exists('exif_read_data'))
        {
            return;
        }

        $exif = exif_read_data($image->getPath());

        if (empty($exif['Orientation']))
        {
            return;
        }

        switch ($exif['Orientation'])
        {

            case 2:
                $image->flip(IMG_FLIP_HORIZONTAL, false);
                break;

            case 3:
                $image->rotate(180, -1, false);
                break;

            case 4:
                $image->rotate(180, -1, false)->flip(IMG_FLIP_HORIZONTAL, false);
                break;

            case 5:
                $image->rotate(270, -1, false)->flip(IMG_FLIP_HORIZONTAL, false);
                break;

            case 6:
                $image->rotate(270, -1, false);
                break;

            case 7:
                $image->rotate(90, -1, false)->flip(IMG_FLIP_HORIZONTAL, false);
                break;

            case 8:
                $image->rotate(90, -1, false);
                break;

            default:
                break;
        }
    }

    public static function setNewDimensions($source, &$width, &$height)
    {
        if ( ! $width && ! $height)
        {
            return false;
        }

        if (File::isExternal($source))
        {
            return false;
        }

        $clean_source = self::cleanPath($source);
        $source_path  = JPATH_SITE . '/' . $clean_source;

        $image = self::getImageObject($source_path);

        if (is_null($image))
        {
            return false;
        }

        return self::setNewDimensionsByImageObject($image, $width, $height);
    }

    public static function setNewDimensionsByImageObject($image, &$width, &$height)
    {
        if ( ! ($image instanceof JImage) || ! $image->isLoaded())
        {
            return false;
        }

        if ( ! $width && ! $height)
        {
            return false;
        }

        try
        {
            $original_width  = $image->getWidth();
            $original_height = $image->getHeight();

            $width  = $width ?: round($original_width / $original_height * $height);
            $height = $height ?: round($original_height / $original_width * $width);
        }
        catch (Exception $e)
        {
            return false;
        }

        if ($width == $original_width && $height == $original_height)
        {
            return false;
        }

        return true;
    }

    private static function isResizedWithFolder($file, $resize_folder = 'resized')
    {
        $folder             = File::getDirName($file);
        $file               = File::getBaseName($file);
        $parent_folder_name = File::getBaseName($folder);
        $parent_folder      = File::getDirName($folder);

        // Image is not inside the resize folder
        if ($parent_folder_name != $resize_folder)
        {
            return false;
        }

        // Check if image with same name exists in parent folder
        if (file_exists(JPATH_SITE . '/' . $parent_folder . '/' . utf8_decode($file)))
        {
            return $parent_folder . '/' . $file;
        }

        // Remove any dimensions from the file
        // image_300x200.jpg => image.jpg
        $file = RegEx::replace(
            '_[0-9]+x[0-9]*(\.[^.]+)$',
            '\1',
            $file
        );

        // Check again if image with same name (but without dimensions) exists in parent folder
        if (file_exists(JPATH_SITE . '/' . $parent_folder . '/' . utf8_decode($file)))
        {
            return $parent_folder . '/' . $file;
        }

        return false;
    }
}
home/digilove/public_html/plugins/system/nrframework/NRFramework/Image.php000064400000047524152410022740023103 0ustar00<?php

/**
 * @author          Tassos Marinos <info@tassos.gr>
 * @link            https://www.tassos.gr
 * @copyright       Copyright © 2024 Tassos All Rights Reserved
 * @license         GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/

namespace NRFramework;

// No direct access
defined('_JEXEC') or die;

use NRFramework\Mimes;
use NRFramework\File;
use Joomla\CMS\Image\Image as JoomlaImage;
use Joomla\Filesystem\Path;
use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;

class Image
{
	/**
	 * Resize an image.
	 * 
	 * @param   string   $source
	 * @param   string   $width
	 * @param   string   $height
	 * @param   integer  $quality
	 * @param   string   $mode
	 * @param   boolean  $unique_filename
	 * @param   boolean  $fix_orientation
	 * @param   string 	 $gif_mode			If the uploaded image is a GIF image, how will it be copied? Options: "copy" source, "resize" source
	 * 
	 * @return  mixed
	 */
	public static function resize($source, $width, $height, $quality = 70, $mode = 'crop', $destination = '', $unique_filename = false, $fix_orientation = true, $gif_mode = 'copy')
	{
		$width = (int) $width;
		$height = (int) $height;

		// Destination file name
		$destination = empty($destination) ? $source : $destination;

		// size must be WIDTHxHEIGHT
		$size = $width . 'x' . $height;

		switch ($mode)
		{
			// Crop and Resize
			case 'crop':
				$mode = 5;
				break;
			// Scale Fill
			case 'stretch':
				$mode = 1;
				break;
			// Fit, will fill empty space with black
			case 'fit':
				$mode = 6;
				break;
			default:
				$mode = 5;
				break;
		}

		try {
			$image = new JoomlaImage($source);

			$origWidth = $image->getWidth();
			$origHeight = $image->getHeight();

			/**
			 * If the image width is less than the given width,
			 * set the image width we are resizing to the image's width.
			 */
			if ($origWidth < $width)
			{
				$size = $origWidth . 'x';

				if ($origHeight < $height)
				{
					$size .= $origHeight;
				}
				else
				{
					$size .= $height;
				}
			}
			else if ($origHeight < $height)
			{
				$prefix = $width;

				if ($origWidth < $width)
				{
					$prefix = $origWidth;
				}
				
				$size = $prefix . 'x' . $origHeight;
			}

			// Fix orientation
			if ($fix_orientation)
			{
				self::fixOrientation($image);
			}

			// Determine the MIME of the original file to get the proper type
			$mime = Mimes::detectFileType($source);
			
			// PNG images should not have a quality value
			$options = $mime == 'image/png' ? ['quality' => 9] : ['quality' => $quality];
			
			// Get the image type
			$image_type = self::getImageType($mime);

			if ($unique_filename)
			{
				// Make destination file unique
				File::uniquefy($destination);
			}

			$destination = Path::clean($destination);

			// Resize image
			if ($mime === 'image/gif')
			{
				if ($gif_mode === 'copy')
				{
					File::copy($source, $destination, true);
				}
				else
				{
					foreach ($image->generateThumbs($size, $mode) as $thumb)
					{
						$thumb->toFile($destination, $image_type, $options);
					}
				}
			}
			else
			{
				foreach ($image->generateThumbs($size, $mode) as $thumb)
				{
					$thumb->toFile($destination, $image_type, $options);
				}
			}

			return $destination;
		} catch(\Exception $e) {}

		return false;
	}

	/**
	 * Resizes an image by height.
	 * 
	 * @param   string  $src
	 * @param   string  $height
	 * @param   string  $destination
	 * @param   int	 	$quality
	 * @param   bool 	$unique_filename
	 * @param   bool 	$fix_orientation
	 * @param   string 	$gif_mode			If the uploaded image is a GIF image, how will it be copied? Options: "copy" source, "resize" source
	 * 
	 * @return  bool
	 */
	public static function resizeByHeight($src, $height, $destination = null, $quality = 70, $unique_filename = false, $fix_orientation = true, $gif_mode = 'copy')
	{
		$height = (int) $height;
		
		// Create a new JImage object from the source image path
		$image = new JoomlaImage($src);

		// Fix orientation
		if ($fix_orientation)
		{
			self::fixOrientation($image);
		}
	  
		// Determine the MIME of the original file to get the proper type
		$mime = Mimes::detectFileType($src);

		// Get the image type
		$image_type = self::getImageType($mime);

		// Output file name
		$destination = empty($destination) ? $src : $destination;
		
		if ($unique_filename)
		{
			// Make destination file unique
			File::uniquefy($destination);
		}

		$destination = Path::clean($destination);
		
		// PNG images should not have a quality value
		$options = $mime == 'image/png' ? ['quality' => 9] : ['quality' => $quality];

		// Get the original width and height of the image
		$origWidth = $image->getWidth();
		$origHeight = $image->getHeight();
	  
		// Calculate the new width based on the desired height
		$newWidth = ($origWidth / $origHeight) * $height;

		// Resize image
		if ($mime === 'image/gif')
		{
			if ($gif_mode === 'copy')
			{
				File::copy($source, $destination, true);
			}
			else
			{
				$resizedImage = $image->resize($newWidth, $height);
				$resizedImage->toFile($destination, $image_type, $options);
			}
		}
		else
		{
			$resizedImage = $image->resize($newWidth, $height);
			$resizedImage->toFile($destination, $image_type, $options);
		}
	  
		// Return true if the image was successfully resized and saved, false otherwise
		return $destination;
	}

	/**
	 * Resizes an image by keeping the aspect ratio
	 * 
	 * @param   string   $source
	 * @param   array    $width
	 * @param   integer  $quality
	 * @param   array    $destination
	 * @param   boolean  $unique_filename
	 * @param   boolean  $fix_orientation
	 * @param   string 	 $gif_mode			If the uploaded image is a GIF image, how will it be copied? Options: "copy" source, "resize" source
	 * 
	 * @return  boolean
	 */
	public static function resizeAndKeepAspectRatio($source, $width, $quality = 70, $destination = '', $unique_filename = false, $fix_orientation = true, $gif_mode = 'copy')
	{
		// Ensure we have received valid image dimensions
		if (!count($image_dimensions = getimagesize($source)))
		{
			return false;
		}

		// Get the image width
		if (!$uploaded_image_width = (int) $image_dimensions[0])
		{
			return false;
		}

		// Get the image height
		if (!$uploaded_image_height = (int) $image_dimensions[1])
		{
			return false;
		}

		$width = (int) $width;

		/**
		 * If the image width is less than the given width,
		 * set the image width we are resizing to the image's width.
		 */
		if ($uploaded_image_width < (int) $width)
		{
			$width = $uploaded_image_width;
		}

		// Determine the MIME of the original file to get the proper type
		$mime = Mimes::detectFileType($source);

		// PNG images should not have a quality value
		$options = $mime == 'image/png' ? ['quality' => 9] : ['quality' => $quality];

		// Get the image type
		$image_type = self::getImageType($mime);

		try {
			// Get image object
			$image = new JoomlaImage($source);

			// Fix orientation
			if ($fix_orientation)
			{
				self::fixOrientation($image);
			}

			// Calculate aspect ratio
			$ratio = $uploaded_image_width / $uploaded_image_height;
	
			// Get new height based on aspect ratio
			$targetHeight = $width / $ratio;
	
			// Output file name
			$destination = empty($destination) ? $source : $destination;

			if ($unique_filename)
			{
				// Make destination file unique
				File::uniquefy($destination);
			}
	
			$destination = Path::clean($destination);
			
			// Resize image
			if ($mime === 'image/gif')
			{
				if ($gif_mode === 'copy')
				{
					File::copy($source, $destination, true);
				}
				else
				{
					$resizedImage = $image->resize($width, $targetHeight, true);
					$resizedImage->toFile($destination, $image_type, $options);
				}
			}
			else
			{
				$resizedImage = $image->resize($width, $targetHeight, true);
				$resizedImage->toFile($destination, $image_type, $options);
			}

			return $destination;
		} catch(\Exception $e) {}

		return false;
	}

	public static function resizeByWidthOrHeight($source, $width, $height, $quality = 80, $destination = '', $resize_method = 'crop', $unique_filename = false, $fix_orientation = true)
	{
		$resized_image = null;
		
		// If width is null, and we have height set, we are resizing by height
		if (is_null($width) && $height && !is_null($height))
		{
			$resized_image = Image::resizeByHeight($source, $height, $destination, 80, $unique_filename, $fix_orientation);
		}
		else
		{
			/**
			 * If height is zero, then we suppose we want to keep aspect ratio.
			 * 
			 * Resize with width & height: If height is not set
			 * Resize and keep aspect ratio: If height is set
			 */
			$resized_image = $height && !is_null($height)
				?
				Image::resize($source, $width, $height, 80, $resize_method, $destination, $unique_filename, $fix_orientation)
				:
				Image::resizeAndKeepAspectRatio($source, $width, 80, $destination, $unique_filename, $fix_orientation);

		}

		return $resized_image;
	}

	/**
	 * Returns the orientation of the image.
	 * 
	 * @param   string  $path
	 * 
	 * @return  int
	 */
	public static function getOrientation($path)
	{
		if (!$exif = @exif_read_data($path))
		{
			return;
		}

		return intval(@$exif['Orientation']);
	}

	/**
	 * Fixes the orientation of the generated image and ensures it appears with the same orientation as the source.
	 * 
	 * @param    string  $path
	 * @param    int     $orientation
	 * 
	 * @return   void
	 */
	public static function fixOrientation(&$image, $orientation = null)
	{
		$orientation = self::getOrientation($image->getPath());
		
		if(!in_array($orientation, [3, 6, 8]))
		{
			return;
		}

		switch ($orientation)
		{
            case 3:
                $image->rotate(180, -1, false);
                break;

            case 6:
                $image->rotate(270, -1, false);
                break;

            case 8:
                $image->rotate(90, -1, false);
                break;
		}

		return true;
	}

	/**
	 * Returns the image type based on its mime type
	 * 
	 * @param   string  $mime
	 * 
	 * @return  int
	 */
	public static function getImageType($mime)
	{
		switch ($mime)
		{
			case 'image/png':
				return IMAGETYPE_PNG;
				break;
			case 'image/gif':
				return IMAGETYPE_GIF;
				break;
			case 'image/webp':
				return IMAGETYPE_WEBP;
				break;
			case 'image/jpeg':
			default:
				return IMAGETYPE_JPEG;
				break;
		}
	}

	/**
	 * Creates a watermark from text.
	 * 
	 * @param   string   $text
	 * @param   integer  $font_size
	 * @param   integer  $opacity
	 * @param   string   $color
	 * @param   integer  $originalWidth
	 * @param   integer  $originalHeight
	 * 
	 * @return  object
	 */
	public static function createWatermarkText($text = '', $_font_size = 30, $opacity = 60, $color = '#ffffff', $originalWidth = null, $originalHeight = null)
	{
		$font = implode(DIRECTORY_SEPARATOR, [JPATH_SITE, 'media', 'plg_system_nrframework', 'font', 'arial.ttf']);

		// Scale down font size based on the original image width or height
		$dimension = $originalWidth > $originalHeight ? $originalWidth : $originalHeight;
		$font_size = $dimension ? $_font_size * ($dimension / 1000) * 1.2 : $_font_size;

		if ($font_size > $_font_size)
		{
			$font_size = $_font_size;
		}

		if ($font_size < 14)
		{
			$font_size = 14;
		}

		$TextSize = @ImageTTFBBox($font_size, 0, $font, $text) or die;
		$TextWidth = abs($TextSize[2]) + abs($TextSize[0]);
		$TextHeight = abs($TextSize[7]) + abs($TextSize[1]);

		$watermarkImage = imagecreatetruecolor($TextWidth, $TextHeight);

		imagealphablending($watermarkImage, false);
		imagesavealpha($watermarkImage, true);
		$bgText = imagecolorallocatealpha($watermarkImage, 255, 255, 255, 127);
		imagefill($watermarkImage, 0, 0, $bgText);
		$wmTransp = 127 - ($opacity * 1.27);
		$rgb = self::hex2rgb($color, false);
		$colorResource = imagecolorallocatealpha($watermarkImage, $rgb[0], $rgb[1], $rgb[2], $wmTransp);
		
		// Create watermark
		imagettftext($watermarkImage, $font_size, 0, 0, abs($TextSize[5]), $colorResource, $font, $text);

		return $watermarkImage;
	}

	/**
	 * Apply the watermark.
	 * 
	 * @param   array  $opts
	 * 
	 * @return  void
	 */
	public static function applyWatermark($opts = [])
	{
		$defaults = [
			'source' => null,
			'destination' => null,
			'preset' => 'custom',
			'type' => 'text',
			'text' => null,
			'position' => 'bottom-right',
			'angle' => 0,
			'opacity' => 50,
			'size' => 30,
			'color' => '#fff'
		];

		$opts = array_merge($defaults, $opts);

		if (!$opts['source'])
		{
			return false;
		}

		if (!is_file($opts['source']))
		{
			return false;
		}

		$destination = $opts['destination'] ? $opts['destination'] : $opts['source'];

		$originalImage = new JoomlaImage($opts['source']);

		// Get the dimensions of the original image
		$originalWidth = $originalImage->getWidth();
		$originalHeight = $originalImage->getHeight();

		$watermarkSource = null;

		switch ($opts['type'])
		{
			case 'image':
				$watermarkSource = $opts['image'];
				break;
			
			case 'text':
			default:
				if (!$watermarkText = self::getWatermarkText($opts['text_preset'], $opts['text'], $destination))
				{
					return;
				}

				$watermarkSource = self::createWatermarkText($watermarkText, (int) $opts['size'], 100, $opts['color'], $originalWidth, $originalHeight);
				break;
		}

		if (!$watermarkSource)
		{
			return;
		}

		$original_image_mime = $originalImage->getImageFileProperties($opts['source'])->mime;

		// Create the final image
		$finalImage = imagecreatetruecolor($originalWidth, $originalHeight);

		$watermarkOpacity = (int) $opts['opacity'];

		// Add a black background color if the image is PNG and watermark opacity is not 100, as imagecopymerge() doesn't work with transparent PNG images
		if ($original_image_mime === 'image/png')
		{
			if ($watermarkOpacity === 100)
			{
				imagesavealpha($finalImage, true);
				$trans_background = imagecolorallocatealpha($finalImage, 0, 0, 0, 127);
				imagefill($finalImage, 0, 0, $trans_background);
			}
			else
			{
				$black = imagecolorallocate($finalImage, 0, 0, 0);
				imagefill($finalImage, 0, 0, $black);
			}
		}

		// Copy original image to the final image
		imagecopy($finalImage, $originalImage->getHandle(), 0, 0, 0, 0, $originalWidth, $originalHeight);

		// Get watermark image
		$watermarkImage = new JoomlaImage($watermarkSource);

		// Rotate it
		if ($opts['angle'])
		{
			$angle = $opts['angle'] ? 360 - (int) $opts['angle'] : 0;
			$watermarkImage->rotate($angle, -1, false);
		}

		// Get the dimensions of the watermark image
		$watermarkWidth = $watermarkImage->getWidth();
		$watermarkHeight = $watermarkImage->getHeight();

		if (!$watermarkWidth || !$watermarkHeight)
		{
			return false;
		}

		// Final watermark width/height
		$width = $watermarkWidth;
		$height = $watermarkHeight;

		// Scale watermark image
		if ($opts['type'] === 'image')
		{
			$scaleFactor = min($originalWidth / $watermarkWidth, $originalHeight / $watermarkHeight);

			// Calculate the new dimensions of the watermark image
			$width = $watermarkWidth * $scaleFactor;
			$height = $watermarkHeight * $scaleFactor;

			if ($width > $watermarkWidth)
			{
				$width = $watermarkWidth;
				$height = $watermarkHeight;
			}
		}
		
		$width = (int) $width;
		$height = (int) $height;

		list($dest_x, $dest_y) = self::getWatermarkPosition($opts['position'], $originalWidth, $originalHeight, $width, $height);

		// Resize watermark image before applying it into the final image
		$watermarkImage = $watermarkImage->resize($width, $height);

		// Copy the watermark image into the final image
		if ($watermarkOpacity === 100)
		{
			imagecopy($finalImage, $watermarkImage->getHandle(), round($dest_x), round($dest_y), 0, 0, $width, $height);
		}
		else
		{
			self::imagecopymerge_alpha($finalImage, $watermarkImage->getHandle(), round($dest_x), round($dest_y), 0, 0, $width, $height, $watermarkOpacity);
		}

		// Save final image
		switch ($original_image_mime)
		{
			case 'image/gif':
				imagegif($finalImage, $destination);
				break;
			
			case 'image/webp':
				imagewebp($finalImage, $destination, 70);
				break;

			case 'image/png':
				imagepng($finalImage, $destination, 6);
				break;

			default:
				imagejpeg($finalImage, $destination, 70);
				break;
		}

		imagedestroy($finalImage);
		$originalImage->destroy();
		$watermarkImage->destroy();
	}

	/**
	 * imagecopy but with alpha channel support.
	 * 
	 * @param   object   $dst_im
	 * @param   object   $src_im
	 * @param   integer  $dst_x
	 * @param   integer  $dst_y
	 * @param   integer  $src_x
	 * @param   integer  $src_y
	 * @param   integer  $src_w
	 * 
	 * @return  void
	 */
	public static function imagecopymerge_alpha($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct)
	{
		$cut = imagecreatetruecolor($src_w, $src_h);
		
        // copying relevant section from background to the cut resource
        imagecopy($cut, $dst_im, 0, 0, $dst_x, $dst_y, $src_w, $src_h);
		
        // copying relevant section from watermark to the cut resource
        imagecopy($cut, $src_im, 0, 0, $src_x, $src_y, $src_w, $src_h);

        // insert cut resource to destination image
        imagecopymerge($dst_im, $cut, $dst_x, $dst_y, 0, 0, $src_w, $src_h, $pct);
    }

	/**
	 * Returns the watermark position.
	 * 
	 * @param   string   $position
	 * @param   integer  $originalWidth
	 * @param   integer  $originalHeight
	 * @param   integer  $width
	 * @param   integer  $height
	 * 
	 * @return  array
	 */
	public static function getWatermarkPosition($position, $originalWidth, $originalHeight, $width, $height)
	{
		/**
		 * Position watermark based on given position.
		 * 
		 * top-left
		 * top-center
		 * top-right
		 * center-left
		 * center-center
		 * center-right
		 * bottom-left
		 * bottom-center
		 * bottom-right
		 */
		$position = explode('-', $position);

		// Padding from corner
		$yPOS = $xPOS = 10;
		$dest_x = $dest_y = 0;
		
		if (isset($position[0]))
		{
			switch ($position[0])
			{
				case 'top':
					$dest_y = 0 + $yPOS;
					break;
				case 'center':
					$dest_y = round($originalHeight / 2) - round($height / 2);
					break;
				case 'bottom':
					$dest_y = $originalHeight - $height - $yPOS;
					break;
			}
		}

		if (isset($position[1]))
		{
			switch ($position[1])
			{
				case 'left':
					$dest_x = 0 + $xPOS;
					break;
				case 'center':
					$dest_x = round($originalWidth / 2) - round($width / 2);
					break;
				case 'right':
					$dest_x = $originalWidth - $width - $xPOS;
					break;
			}
		}

		return [$dest_x, $dest_y];
	}

	/**
	 * Returns the watermark text.
	 * 
	 * @param   string  $preset
	 * @param   string  $text
	 * @param   string  $filename
	 * 
	 * @return  string
	 */
	public static function getWatermarkText($preset = '', $text = '', $filename = '')
	{
		switch ($preset)
		{
			case 'site_name':
				$text = Factory::getApplication()->get('sitename');
				break;
			
			case 'site_url':
				$text = Uri::root();
				break;

			case 'custom':
				$st = new \NRFramework\SmartTags();

				// Add file Smart Tags
				$file_data = File::pathinfo($filename);
				$source_basename = $file_data['basename'];
				$file_data['filename'] = $file_data['filename'];
				$file_data['basename'] = $source_basename;

				$st->add($file_data, 'file.');

				
				$text = $st->replace($text);
				break;
		}

		return $text;
	}

	/**
	 * Converts hexidecimal color value to rgb values and returns as array/string
	 *
	 * @param   string 		  $hex
	 * @param   bool		  $asString
	 * 
	 * @return  array|string
	 */
	public static function hex2rgb($hex, $asString = false)
	{
        // strip off any leading #
        if (0 === strpos($hex, '#'))
		{
           $hex = substr($hex, 1);
        }
		else if (0 === strpos($hex, '&H'))
		{
           $hex = substr($hex, 2);
        }

        // break into hex 3-tuple
        $cutpoint = ceil(strlen($hex) / 2)-1;
        $rgb = explode(':', wordwrap($hex, $cutpoint, ':', $cutpoint), 3);

        // convert each tuple to decimal
        $rgb[0] = (isset($rgb[0]) ? hexdec($rgb[0]) : 0);
        $rgb[1] = (isset($rgb[1]) ? hexdec($rgb[1]) : 0);
        $rgb[2] = (isset($rgb[2]) ? hexdec($rgb[2]) : 0);

        return ($asString ? "{$rgb[0]} {$rgb[1]} {$rgb[2]}" : $rgb);
    }
}