ConLite/conlite/includes/functions.api.images.php

690 Zeilen
22 KiB
PHP

<?php
/**
* Project:
* Contenido Content Management System
*
* Description:
* Contenido Image API functions
*
* Requirements:
* @con_php_req 5.0
*
*
* @package Contenido Backend includes
* @version 1.4.3
* @author Timo A. Hummel
* @copyright four for business AG <www.4fb.de>
* @license http://www.contenido.org/license/LIZENZ.txt
* @link http://www.4fb.de
* @link http://www.contenido.org
* @since file available since contenido release <= 4.6
*
* {@internal
* created 2003-08-08
* modified 2008-06-25, Frederic Schneider, add security fix
*
* $Id$:
* }}
*
*/
if (!defined('CON_FRAMEWORK')) {
die('Illegal call');
}
/* Info:
* This file contains Contenido Image API functions.
*
* If you are planning to add a function, please make sure that:
* 1.) The function is in the correct place
* 2.) The function is documented
* 3.) The function makes sense and is generically usable
*
*/
/**
* capiImgScaleGetMD5CacheFile: Returns the MD5 Filename used
* for caching.
*
* @return string Path to the resulting image
*/
function capiImgScaleGetMD5CacheFile($sImg, $iMaxX, $iMaxY, $bCrop, $bExpand) {
if (!file_exists($sImg)) {
return false;
}
$iFilesize = filesize($sImg);
if (function_exists("md5_file")) {
$sMD5 = md5(implode("", array(
$sImg,
md5_file($sImg),
$iFilesize,
$iMaxX,
$iMaxY,
$bCrop,
$bExpand)));
} else {
$sMD5 = md5(implode("", array(
$sImg,
$iFilesize,
$iMaxX,
$iMaxY,
$bCrop,
$bExpand)));
}
return $sMD5;
}
/**
* capiImgScaleLQ: Scales (or crops) an image.
* If scaling, the aspect ratio is maintained.
*
* Returns the path to the scaled temporary image.
*
* Note that this function does some very poor caching;
* it calculates an md5 hash out of the image plus the
* maximum X and Y sizes, and uses that as the file name.
* If the file is older than 10 minutes, regenerate it.
*
* @param string $img The path to the image (relative to the frontend)
* @param int $maxX The maximum size in x-direction
* @param int $maxY The maximum size in y-direction
* @param boolean $crop If true, the image is cropped and not scaled.
* @param boolean $expand If true, the image is expanded (e.g. really scaled).
* If false, the image will only be made smaller.
* @param int $cacheTime The number of minutes to cache the image, use 0 for unlimited
* @param int $quality The quality of the output file
* @param boolean $keepType If true and a png file is source, output file is also png
*
* @return string !!!URL!!! to the resulting image (http://...
*/
function capiImgScaleLQ($img, $maxX, $maxY, $crop = false, $expand = false, $cacheTime = 10, $quality = 75, $keepType = false) {
global $cfgClient, $lang, $client;
$filename = $img;
$cacheTime = (int) $cacheTime;
$quality = (int) $quality;
if ($quality <= 0 || $quality > 100) {
$quality = 75;
}
$filetype = substr($filename, strlen($filename) - 4, 4);
$filesize = filesize($img);
$md5 = capiImgScaleGetMD5CacheFile($img, $maxX, $maxY, $crop, $expand);
// Create the target file names for web and server
if ($keepType) { // Should we keep the file type?
switch (strtolower($filetype)) { // Just using switch if someone likes to add other types
case ".png":
$cfileName = $md5 . ".png";
break;
default:
$cfileName = $md5 . ".jpg";
}
} else { // No... use .jpg
$cfileName = $md5 . ".jpg";
}
$cacheFile = $cfgClient[$client]["path"]["frontend"] . "cache/" . $cfileName;
$webFile = $cfgClient[$client]["path"]["htmlpath"] . "cache/" . $cfileName;
// Check if the file exists. If it does, check if the file is valid.
if (file_exists($cacheFile)) {
if ($cacheTime == 0) {
// Do not check expiration date
return $webFile;
} else if (!function_exists("md5_file")) { // TODO: Explain why this is still needed ... or remove it
if ((filemtime($cacheFile) + (60 * $cacheTime)) < time()) {
/* Cache time expired, unlink the file */
unlink($cacheFile);
} else {
/* Return the web file name */
return $webFile;
}
} else {
return $webFile;
}
}
/* Get out which file we have */
switch (strtolower($filetype)) {
case ".gif": $function = "imagecreatefromgif";
break;
case ".png": $function = "imagecreatefrompng";
break;
case ".jpg": $function = "imagecreatefromjpeg";
break;
case "jpeg": $function = "imagecreatefromjpeg";
break;
default: return false;
}
if (function_exists($function)) {
$imageHandle = @$function($filename);
}
/* If we can't open the image, return false */
if (!$imageHandle) {
return false;
}
$x = imagesx($imageHandle);
$y = imagesy($imageHandle);
/* Calculate the aspect ratio */
$aspectXY = $x / $y;
$aspectYX = $y / $x;
if (($maxX / $x) < ($maxY / $y)) {
$targetY = $y * ($maxX / $x);
$targetX = round($maxX);
// force wished height
if ($targetY < $maxY) {
$targetY = ceil($targetY);
} else {
$targetY = floor($targetY);
}
} else {
$targetX = $x * ($maxY / $y);
$targetY = round($maxY);
// force wished width
if ($targetX < $maxX) {
$targetX = ceil($targetX);
} else {
$targetX = floor($targetX);
}
}
if ($expand == false && (($targetX > $x) || ($targetY > $y))) {
$targetX = $x;
$targetY = $y;
}
$targetX = ($targetX != 0) ? $targetX : 1;
$targetY = ($targetY != 0) ? $targetY : 1;
/* Create the target image with the target size, resize it afterwards. */
if ($crop) {
/* Create the target image with the max size, crop it afterwards. */
$targetImage = imagecreate($maxX, $maxY);
imagecopy($targetImage, $imageHandle, 0, 0, 0, 0, $maxX, $maxY);
} else {
/* Create the target image with the target size, resize it afterwards. */
$targetImage = imagecreate($targetX, $targetY);
imagecopyresized($targetImage, $imageHandle, 0, 0, 0, 0, $targetX, $targetY, $x, $y);
}
// Output the file
if ($keepType) {
switch (strtolower($filetype)) {
case ".png":
imagepng($targetImage, $cacheFile); // no quality option available
break;
default:
imagejpeg($targetImage, $cacheFile, $quality);
}
} else {
imagejpeg($targetImage, $cacheFile, $quality);
}
return ($webFile);
}
/**
* capiImgScaleHQ: Scales (or crops) an image in high quality.
* If scaling, the aspect ratio is maintained.
*
* Note: GDLib 2.x is required!
*
* Returns the path to the scaled temporary image.
*
* Note that this function does some very poor caching;
* it calculates an md5 hash out of the image plus the
* maximum X and Y sizes, and uses that as the file name.
* If the file is older than the specified cache time, regenerate it.
*
* @param string $img The path to the image (relative to the frontend)
* @param int $maxX The maximum size in x-direction
* @param int $maxY The maximum size in y-direction
* @param boolean $crop If true, the image is cropped and not scaled.
* @param boolean $expand If true, the image is expanded (e.g. really scaled).
* If false, the image will only be made smaller.
* @param int $cacheTime The number of minutes to cache the image, use 0 for unlimited
* @param int $quality The quality of the output file
* @param boolean $keepType If true and a png file is source, output file is also png
*
* @return string !!!URL!!! to the resulting image (http://...)
*/
function capiImgScaleHQ($img, $maxX, $maxY, $crop = false, $expand = false, $cacheTime = 10, $quality = 75, $keepType = false) {
global $cfgClient, $lang, $client;
$filename = $img;
$cacheTime = (int) $cacheTime;
$quality = (int) $quality;
if ($quality <= 0 || $quality > 100) {
$quality = 75;
}
$filetype = substr($filename, strlen($filename) - 4, 4);
$filesize = filesize($img);
$md5 = capiImgScaleGetMD5CacheFile($img, $maxX, $maxY, $crop, $expand);
/* Create the target file names for web and server */
if ($keepType) { // Should we keep the file type?
switch (strtolower($filetype)) { // Just using switch if someone likes to add other types
case ".png":
$cfileName = $md5 . ".png";
break;
default:
$cfileName = $md5 . ".jpg";
}
} else { // No... use .jpg
$cfileName = $md5 . ".jpg";
}
$cacheFile = $cfgClient[$client]["path"]["frontend"] . "cache/" . $cfileName;
$webFile = $cfgClient[$client]["path"]["htmlpath"] . "cache/" . $cfileName;
/* Check if the file exists. If it does, check if the file is valid. */
if (file_exists($cacheFile)) {
if ($cacheTime == 0) {
// Do not check expiration date
return $webFile;
} else if (!function_exists("md5_file")) { // TODO: Explain why this is still needed ... or remove it
if ((filemtime($cacheFile) + (60 * $cacheTime)) < time()) {
/* Cache time expired, unlink the file */
unlink($cacheFile);
} else {
/* Return the web file name */
return $webFile;
}
} else {
return $webFile;
}
}
/* Get out which file we have */
switch (strtolower($filetype)) {
case ".gif": $function = "imagecreatefromgif";
break;
case ".png": $function = "imagecreatefrompng";
break;
case ".jpg": $function = "imagecreatefromjpeg";
break;
case "jpeg": $function = "imagecreatefromjpeg";
break;
default: return false;
}
if (function_exists($function)) {
$imageHandle = @$function($filename);
}
/* If we can't open the image, return false */
if (!$imageHandle) {
return false;
}
$x = imagesx($imageHandle);
$y = imagesy($imageHandle);
/* Calculate the aspect ratio */
$aspectXY = $x / $y;
$aspectYX = $y / $x;
if (($maxX / $x) < ($maxY / $y)) {
$targetY = $y * ($maxX / $x);
$targetX = round($maxX);
// force wished height
if ($targetY < $maxY) {
$targetY = ceil($targetY);
} else {
$targetY = floor($targetY);
}
} else {
$targetX = $x * ($maxY / $y);
$targetY = round($maxY);
// force wished width
if ($targetX < $maxX) {
$targetX = ceil($targetX);
} else {
$targetX = floor($targetX);
}
}
if ($expand == false && (($targetX > $x) || ($targetY > $y))) {
$targetX = $x;
$targetY = $y;
}
$targetX = ($targetX != 0) ? $targetX : 1;
$targetY = ($targetY != 0) ? $targetY : 1;
/* Create the target image with the target size, resize it afterwards. */
if ($crop) {
/* Create the target image with the max size, crop it afterwards. */
$targetImage = imagecreatetruecolor($maxX, $maxY);
imagecopy($targetImage, $imageHandle, 0, 0, 0, 0, $maxX, $maxY);
} else {
/* Create the target image with the target size, resize it afterwards. */
$targetImage = imagecreatetruecolor($targetX, $targetY);
imagecopyresampled($targetImage, $imageHandle, 0, 0, 0, 0, $targetX, $targetY, $x, $y);
}
// Output the file
if ($keepType) {
switch (strtolower($filetype)) {
case ".png":
imagepng($targetImage, $cacheFile); // no quality option available
break;
default:
imagejpeg($targetImage, $cacheFile, $quality);
}
} else {
imagejpeg($targetImage, $cacheFile, $quality);
}
return ($webFile);
}
/**
* capiImgScaleImageMagick: Scales (or crops) an image using ImageMagick.
* If scaling, the aspect ratio is maintained.
*
* Note: ImageMagick is required!
*
* Returns the path to the scaled temporary image.
*
* Note that this function does some very poor caching;
* it calculates an md5 hash out of the image plus the
* maximum X and Y sizes, and uses that as the file name.
* If the file is older than the specified cache time, regenerate it.
*
* @param string $img The path to the image (relative to the frontend)
* @param int $maxX The maximum size in x-direction
* @param int $maxY The maximum size in y-direction
* @param boolean $crop If true, the image is cropped and not scaled.
* @param boolean $expand If true, the image is expanded (e.g. really scaled).
* If false, the image will only be made smaller.
* @param int $cacheTime The number of minutes to cache the image, use 0 for unlimited
* @param int $quality The quality of the output file
* @param boolean $keepType If true and a png file is source, output file is also png
*
* @return string !!!URL!!! to the resulting image (http://...)
*/
function capiImgScaleImageMagick($img, $maxX, $maxY, $crop = false, $expand = false, $cacheTime = 10, $quality = 75, $keepType = false) {
global $cfgClient, $lang, $client;
$filename = $img;
$cacheTime = (int) $cacheTime;
$quality = (int) $quality;
if ($quality <= 0 || $quality > 100) {
$quality = 75;
}
$filetype = substr($filename, strlen($filename) - 4, 4);
$filesize = filesize($img);
$md5 = capiImgScaleGetMD5CacheFile($img, $maxX, $maxY, $crop, $expand);
/* Create the target file names for web and server */
if ($keepType) { // Should we keep the file type?
switch (strtolower($filetype)) { // Just using switch if someone likes to add other types
case ".png":
$cfileName = $md5 . ".png";
break;
default:
$cfileName = $md5 . ".jpg";
}
} else { // No... use .jpg
$cfileName = $md5 . ".jpg";
}
$cacheFile = $cfgClient[$client]["path"]["frontend"] . "cache/" . $cfileName;
$webFile = $cfgClient[$client]["path"]["htmlpath"] . "cache/" . $cfileName;
/* Check if the file exists. If it does, check if the file is valid. */
if (file_exists($cacheFile)) {
if ($cacheTime == 0) {
// Do not check expiration date
return $webFile;
} else if (!function_exists("md5_file")) { // TODO: Explain why this is still needed ... or remove it
if ((filemtime($cacheFile) + (60 * $cacheTime)) < time()) {
/* Cache time expired, unlink the file */
unlink($cacheFile);
} else {
/* Return the web file name */
return $webFile;
}
} else {
return $webFile;
}
}
list($x, $y) = @getimagesize($filename);
if ($x == 0 || $y == 0) {
return false;
}
/* Calculate the aspect ratio */
$aspectXY = $x / $y;
$aspectYX = $y / $x;
if (($maxX / $x) < ($maxY / $y)) {
$targetY = $y * ($maxX / $x);
$targetX = round($maxX);
// force wished height
if ($targetY < $maxY) {
$targetY = ceil($targetY);
} else {
$targetY = floor($targetY);
}
} else {
$targetX = $x * ($maxY / $y);
$targetY = round($maxY);
// force wished width
if ($targetX < $maxX) {
$targetX = ceil($targetX);
} else {
$targetX = floor($targetX);
}
}
if ($expand == false && (($targetX > $x) || ($targetY > $y))) {
$targetX = $x;
$targetY = $y;
}
$targetX = ($targetX != 0) ? $targetX : 1;
$targetY = ($targetY != 0) ? $targetY : 1;
// if is animated gif resize first frame
if ($filetype == ".gif") {
if (isAnimGif($filename)) {
$filename .= "[0]";
}
}
/* Try to execute convert */
$output = array();
$retVal = 0;
if ($crop) {
exec("convert -gravity center -quality " . $quality . " -crop {$maxX}x{$maxY}+1+1 \"$filename\" $cacheFile", $output, $retVal);
} else {
exec("convert -quality " . $quality . " -geometry {$targetX}x{$targetY} \"$filename\" $cacheFile", $output, $retVal);
}
if (!file_exists($cacheFile)) {
return false;
} else {
return ($webFile);
}
}
/**
* check if gif is animated
*
* @param string file path
*
* @return boolean true (gif is animated)/ false (single frame gif)
*/
function isAnimGif($sFile) {
$output = array();
$retval = 0;
exec('identify ' . $sFile, $output, $retval);
if (count($output) == 1) {
return false;
}
return true;
}
/**
* capiImgScale: Scales (or crops) an image.
* If scaling, the aspect ratio is maintained.
*
* This function chooses the best method to scale, depending on
* the system environment and/or the parameters.
*
* Returns the path to the scaled temporary image.
*
* Note that this function does some very poor caching;
* it calculates an md5 hash out of the image plus the
* maximum X and Y sizes, and uses that as the file name.
* If the file is older than 10 minutes, regenerate it.
*
* @param string $img The path to the image (relative to the frontend)
* @param int $maxX The maximum size in x-direction
* @param int $maxY The maximum size in y-direction
* @param boolean $crop If true, the image is cropped and not scaled.
* @param boolean $expand If true, the image is expanded (e.g. really scaled).
* If false, the image will only be made smaller.
* @param int $cacheTime The number of minutes to cache the image, use 0 for unlimited
* @param boolean $wantHQ If true, try to force high quality mode
* @param int $quality The quality of the output file
* @param boolean $keepType If true and a png file is source, output file is also png
*
* @return string !!!URL!!! to the resulting image (http://...)
*
* @return string Path to the resulting image
*/
function capiImgScale($img, $maxX, $maxY, $crop = false, $expand = false, $cacheTime = 10, $wantHQ = false, $quality = 75, $keepType = false) {
global $client, $db, $cfg, $cfgClient;
$deleteAfter = false;
$sRelativeImg = str_replace($cfgClient[$client]["upl"]["path"], "", $img);
if (is_dbfs($sRelativeImg)) {
// This check should be faster than a file existance check
$dbfs = new DBFSCollection;
$file = basename($sRelativeImg);
$dbfs->writeToFile($sRelativeImg, $cfgClient[$client]["path"]["frontend"] . "cache/" . $file);
$img = $cfgClient[$client]["path"]["frontend"] . "cache/" . $file;
$deleteAfter = true;
} else if (!file_exists($img)) {
/* Try with upload string */
if (file_exists($cfgClient[$client]["upl"]["path"] . $img) && !is_dir($cfgClient[$client]["upl"]["path"] . $img)) {
$img = $cfgClient[$client]["upl"]["path"] . $img;
} else {
/* No, it's neither in the upload directory nor in the dbfs. return. */
return false;
}
}
$filename = $img;
$filetype = substr($filename, strlen($filename) - 4, 4);
$mxdAvImgEditingPosibility = checkImageEditingPosibility();
switch ($mxdAvImgEditingPosibility) {
case '1': // gd1
$method = 'gd1';
if (!function_exists('imagecreatefromgif') && $filetype == '.gif') {
$method = 'failure';
}
break;
case '2': //gd2
$method = 'gd2';
if (!function_exists('imagecreatefromgif') && $filetype == '.gif') {
$method = 'failure';
}
break;
case 'im': //imagemagick
$method = 'im';
break;
case '0':
$method = 'failure';
break;
default:
$method = 'failure';
break;
}
switch ($method) {
case 'gd1':
$return = capiImgScaleLQ($img, $maxX, $maxY, $crop, $expand, $cacheTime, $quality, $keepType);
break;
case 'gd2':
$return = capiImgScaleHQ($img, $maxX, $maxY, $crop, $expand, $cacheTime, $quality, $keepType);
break;
case 'im':
$return = capiImgScaleImageMagick($img, $maxX, $maxY, $crop, $expand, $cacheTime, $quality, $keepType);
break;
case 'failure':
$return = str_replace($cfgClient[$client]["path"]["frontend"], $cfgClient[$client]["path"]["htmlpath"], $img);
break;
}
if ($deleteAfter == true) {
unlink($img);
}
return $return;
}
/**
* check possible image editing functionality
*
* return mixed information about installed image editing extensions/tools
*/
function checkImageEditingPosibility() {
if (isImageMagickAvailable()) {
return 'im';
} else {
if (extension_loaded('gd')) {
if (function_exists('gd_info')) {
$arrGDInformations = gd_info();
if (preg_match('#([0-9\.])+#', $arrGDInformations['GD Version'], $strGDVersion)) {
if ($strGDVersion[0] >= '2') {
return '2';
}
return '1';
}
return '1';
}
return '1';
}
return '0';
}
}
?>