1
0
mirror of https://github.com/mosbth/cimage.git synced 2025-08-27 09:34:30 +02:00

Compare commits

...

46 Commits

Author SHA1 Message Date
Mikael Roos
80610b31b9 generated new bundles 2015-10-21 01:13:36 +02:00
Mikael Roos
b639220d05 prepare to tag v0.7.7 2015-10-21 01:13:18 +02:00
Mikael Roos
ee9fdb8474 One can now add a HTTP header for Cache-Control in the config file, #109. 2015-10-21 01:12:10 +02:00
Mikael Roos
db5ce71926 Added hook in img,php before CImage is called, #123. 2015-10-21 00:51:56 +02:00
Mikael Roos
1bf57fe8ef Added hook in img,php before CImage is called, #123. 2015-10-21 00:51:48 +02:00
Mikael Roos
8c89166967 Added configuration for default jpeg quality and png compression in the config file, #107. 2015-10-21 00:30:01 +02:00
Mikael Roos
ce8ec325d3 Strip comments and whitespace in imgs.php. 2015-10-21 00:13:56 +02:00
Mikael Roos
ca9b4a4ce6 webroot/img/issue117/img.php?src=issue117%2Ftri_original.png 2015-10-21 00:05:14 +02:00
Mikael Roos
7c0f37628f Adding option &status to get an overview of the installed ond configured utilities, #116. 2015-10-21 00:04:37 +02:00
Mikael Roos
5fe8e399a1 * Added option to decide if resample or resize when copying images internally. &no-resample makes resize, instead of resample as is default.
* Verbose now correctly states if transparent color is detected.
* Removed that source png-files, containing less than 255 colors, is always saved as palette images since this migth depend on processing of the image.
2015-10-20 13:46:01 +02:00
Mikael Roos
9620c1eb75 Adding testcase for issue #117 2015-10-20 13:45:16 +02:00
Mikael Roos
f721ef4b35 Adding save-as as part of the generated cache filename, #121. 2015-10-20 10:26:09 +02:00
Mikael Roos
37b39fbecf Add extra fileds to json-response, #114. 2015-10-20 10:04:37 +02:00
Mikael Roos
553d2f3db1 Add header for Content-Length, #111. 2015-10-18 18:34:42 +02:00
Mikael Roos
9e2bd27c6e Add check for postprocessing tools in path in webroot/check_system.php, #104. 2015-10-18 18:13:12 +02:00
Mikael Roos
1bd6fc8a2c improving dummy image 2015-10-18 17:15:14 +02:00
Mikael Roos
39b6078d84 travis working again, unintentionally removed the cache dirs 2015-10-18 16:25:50 +02:00
Mikael Roos
e7e73fc38c testin travis 2015-10-18 16:22:42 +02:00
Mikael Roos
fa77908616 testin travis 2015-10-18 16:13:45 +02:00
Mikael Roos
0f05cd06e5 testin travis 2015-10-18 16:11:59 +02:00
Mikael Roos
3d773b502d testint travis 2015-10-18 16:04:48 +02:00
Mikael Roos
575c712bd0 testint travis 2015-10-18 16:02:27 +02:00
Mikael Roos
cdd159e142 testing travis 2015-10-18 15:52:06 +02:00
Mikael Roos
f21cd923f3 testing travis 2015-10-18 15:50:22 +02:00
Mikael Roos
18fb271961 add writable cache dir 2015-10-18 15:48:11 +02:00
Mikael Roos
1fdc701f3d prepare to test v0.7.5 2015-10-18 15:43:43 +02:00
Mikael Roos
dc6e9a8708 test tag 2015-10-18 14:52:17 +02:00
Mikael Roos
d9947251ab prepare to merge 2015-10-18 14:44:27 +02:00
Mikael Roos
0fb00df972 adding feature for creating dummy images, #101 2015-09-17 11:24:30 +02:00
Mikael Roos
f00b2e0cd3 adding feature for creating dummy images, #101 2015-09-17 11:22:50 +02:00
Mikael Roos
fd2ddadc44 Add png compression to generated cache filename, fix #103. 2015-09-16 09:51:04 +02:00
Mikael Roos
ea4794f4a2 remove commented code 2015-09-16 09:19:46 +02:00
Mikael Roos
7af0b6ef8a remove commented code 2015-09-16 09:18:51 +02:00
Mikael Roos
850fb76c8b cleanup unused variables 2015-09-16 09:09:30 +02:00
Mikael Roos
49f5f66ad3 calling setSource(null) should unset imageSrc and pathToImage 2015-09-16 08:26:28 +02:00
Mikael Roos
a787593533 Removing unneded internal variable this->imageFolder 2015-09-16 08:21:32 +02:00
Mikael Roos
8d6a8a452e Prepare to tag v0.7.4 2015-09-15 17:26:04 +02:00
Mikael Roos
1907feffc8 Rewriting some comments 2015-09-15 17:24:10 +02:00
Mikael Roos
afff3589dc Generate filename with filters, does not work on Windows, fix #100. 2015-09-15 17:23:22 +02:00
Mikael Roos
76bc09f2ee Add CAsciiArt.php to composer for autoloading, fix #102. 2015-09-15 17:19:29 +02:00
Mikael Roos
c4d3f7cdf6 prepare to tag 2015-09-01 17:02:11 +02:00
Mikael Roos
a50aab9d8e Prepare to test asciiart 2015-09-01 16:53:19 +02:00
Mikael Roos
de942268c9 Updating version information 2015-09-01 16:53:02 +02:00
Mikael Roos
d8090e7531 Merge branch 'master' into ascii 2015-09-01 16:49:30 +02:00
Mikael Roos
c94027a752 Prepare to generate bundles with asciiart 2015-09-01 16:46:44 +02:00
Mikael Roos
2959f11f33 Adding support for AsciiArt of an image. 2015-09-01 16:45:10 +02:00
24 changed files with 2887 additions and 4527 deletions

212
CAsciiArt.php Normal file
View File

@@ -0,0 +1,212 @@
<?php
/**
* Create an ASCII version of an image.
*
*/
class CAsciiArt
{
/**
* Character set to use.
*/
private $characterSet = array(
'one' => "#0XT|:,.' ",
'two' => "@%#*+=-:. ",
'three' => "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. "
);
/**
* Current character set.
*/
private $characters = null;
/**
* Length of current character set.
*/
private $charCount = null;
/**
* Scale of the area to swap to a character.
*/
private $scale = null;
/**
* Strategy to calculate luminance.
*/
private $luminanceStrategy = null;
/**
* Constructor which sets default options.
*/
public function __construct()
{
$this->setOptions();
}
/**
* Add a custom character set.
*
* @param string $key for the character set.
* @param string $value for the character set.
*
* @return $this
*/
public function addCharacterSet($key, $value)
{
$this->characterSet[$key] = $value;
return $this;
}
/**
* Set options for processing, defaults are available.
*
* @param array $options to use as default settings.
*
* @return $this
*/
public function setOptions($options = array())
{
$default = array(
"characterSet" => 'two',
"scale" => 14,
"luminanceStrategy" => 3,
"customCharacterSet" => null,
);
$default = array_merge($default, $options);
if (!is_null($default['customCharacterSet'])) {
$this->addCharacterSet('custom', $default['customCharacterSet']);
$default['characterSet'] = 'custom';
}
$this->scale = $default['scale'];
$this->characters = $this->characterSet[$default['characterSet']];
$this->charCount = strlen($this->characters);
$this->luminanceStrategy = $default['luminanceStrategy'];
return $this;
}
/**
* Create an Ascii image from an image file.
*
* @param string $filename of the image to use.
*
* @return string $ascii with the ASCII image.
*/
public function createFromFile($filename)
{
$img = imagecreatefromstring(file_get_contents($filename));
list($width, $height) = getimagesize($filename);
$ascii = null;
$incY = $this->scale;
$incX = $this->scale / 2;
for ($y = 0; $y < $height - 1; $y += $incY) {
for ($x = 0; $x < $width - 1; $x += $incX) {
$toX = min($x + $this->scale / 2, $width - 1);
$toY = min($y + $this->scale, $height - 1);
$luminance = $this->luminanceAreaAverage($img, $x, $y, $toX, $toY);
$ascii .= $this->luminance2character($luminance);
}
$ascii .= PHP_EOL;
}
return $ascii;
}
/**
* Get the luminance from a region of an image using average color value.
*
* @param string $img the image.
* @param integer $x1 the area to get pixels from.
* @param integer $y1 the area to get pixels from.
* @param integer $x2 the area to get pixels from.
* @param integer $y2 the area to get pixels from.
*
* @return integer $luminance with a value between 0 and 100.
*/
public function luminanceAreaAverage($img, $x1, $y1, $x2, $y2)
{
$numPixels = ($x2 - $x1 + 1) * ($y2 - $y1 + 1);
$luminance = 0;
for ($x = $x1; $x <= $x2; $x++) {
for ($y = $y1; $y <= $y2; $y++) {
$rgb = imagecolorat($img, $x, $y);
$red = (($rgb >> 16) & 0xFF);
$green = (($rgb >> 8) & 0xFF);
$blue = ($rgb & 0xFF);
$luminance += $this->getLuminance($red, $green, $blue);
}
}
return $luminance / $numPixels;
}
/**
* Calculate luminance value with different strategies.
*
* @param integer $red The color red.
* @param integer $green The color green.
* @param integer $blue The color blue.
*
* @return float $luminance with a value between 0 and 1.
*/
public function getLuminance($red, $green, $blue)
{
switch($this->luminanceStrategy) {
case 1:
$luminance = ($red * 0.2126 + $green * 0.7152 + $blue * 0.0722) / 255;
break;
case 2:
$luminance = ($red * 0.299 + $green * 0.587 + $blue * 0.114) / 255;
break;
case 3:
$luminance = sqrt(0.299 * pow($red, 2) + 0.587 * pow($green, 2) + 0.114 * pow($blue, 2)) / 255;
break;
case 0:
default:
$luminance = ($red + $green + $blue) / (255 * 3);
}
return $luminance;
}
/**
* Translate the luminance value to a character.
*
* @param string $position a value between 0-100 representing the
* luminance.
*
* @return string with the ascii character.
*/
public function luminance2character($luminance)
{
$position = (int) round($luminance * ($this->charCount - 1));
$char = $this->characters[$position];
return $char;
}
}

View File

@@ -63,6 +63,13 @@ class CImage
/**
* Add HTTP headers for outputing image.
*/
private $HTTPHeader = array();
/**
* Default background color, red, green, blue, alpha.
*
@@ -113,13 +120,6 @@ class CImage
/**
* The root folder of images (only used in constructor to create $pathToImage?).
*/
private $imageFolder;
/**
* Image filename, may include subdirectory, relative from $imageFolder
*/
@@ -193,6 +193,7 @@ class CImage
* Path to command for filter optimize, for example optipng or null.
*/
private $pngFilter;
private $pngFilterCmd;
@@ -200,13 +201,16 @@ class CImage
* Path to command for deflate optimize, for example pngout or null.
*/
private $pngDeflate;
private $pngDeflateCmd;
/**
* Path to command to optimize jpeg images, for example jpegtran or null.
*/
private $jpegOptimize;
private $jpegOptimize;
private $jpegOptimizeCmd;
/**
@@ -282,6 +286,56 @@ class CImage
private $fillToFit;
/**
* To store value for option scale.
*/
private $scale;
/**
* To store value for option.
*/
private $rotateBefore;
/**
* To store value for option.
*/
private $rotateAfter;
/**
* To store value for option.
*/
private $autoRotate;
/**
* To store value for option.
*/
private $sharpen;
/**
* To store value for option.
*/
private $emboss;
/**
* To store value for option.
*/
private $blur;
/**
* Used with option area to set which parts of the image to use.
*/
@@ -334,6 +388,22 @@ class CImage
/*
* Output to ascii can take som options as an array.
*/
private $asciiOptions = array();
/*
* Image copy strategy, defaults to RESAMPLE.
*/
const RESIZE = 1;
const RESAMPLE = 2;
private $copyStrategy = NULL;
/**
* Properties, the class is mutable and the method setOptions()
* decides (partly) what properties are created.
@@ -348,9 +418,7 @@ class CImage
public $crop_x;
public $crop_y;
public $filters;
private $type; // Calculated from source image
private $attr; // Calculated from source image
private $useOriginal; // Use original image if possible
@@ -407,9 +475,7 @@ class CImage
/**
* Use cache or not.
*
* @todo clean up how $this->noCache is used in other methods.
*
* @param string $use true or false to use cache.
* @param boolean $use true or false to use cache.
*
* @return $this
*/
@@ -421,6 +487,27 @@ class CImage
/**
* Create and save a dummy image. Use dimensions as stated in
* $this->newWidth, or $width or default to 100 (same for height.
*
* @param integer $width use specified width for image dimension.
* @param integer $height use specified width for image dimension.
*
* @return $this
*/
public function createDummyImage($width = null, $height = null)
{
$this->newWidth = $this->newWidth ?: $width ?: 100;
$this->newHeight = $this->newHeight ?: $height ?: 100;
$this->image = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight);
return $this;
}
/**
* Allow or disallow remote image download.
*
@@ -529,6 +616,26 @@ class CImage
/**
* Normalize the file extension.
*
* @param string $extension of image file or skip to use internal.
*
* @return string $extension as a normalized file extension.
*/
private function normalizeFileExtension($extension = null)
{
$extension = strtolower($extension ? $extension : $this->extension);
if ($extension == 'jpeg') {
$extension = 'jpg';
}
return $extension;
}
/**
* Download a remote image and return path to its local copy.
*
@@ -571,16 +678,18 @@ class CImage
/**
* Set src file.
* Set source file to use as image source.
*
* @param string $src of image.
* @param string $dir as base directory where images are.
* @param string $dir as optional base directory where images are.
*
* @return $this
*/
public function setSource($src, $dir = null)
{
if (!isset($src)) {
$this->imageSrc = null;
$this->pathToImage = null;
return $this;
}
@@ -594,9 +703,9 @@ class CImage
$src = basename($src);
}
$this->imageSrc = ltrim($src, '/');
$this->imageFolder = rtrim($dir, '/');
$this->pathToImage = $this->imageFolder . '/' . $this->imageSrc;
$this->imageSrc = ltrim($src, '/');
$imageFolder = rtrim($dir, '/');
$this->pathToImage = $imageFolder . '/' . $this->imageSrc;
return $this;
}
@@ -607,23 +716,23 @@ class CImage
* Set target file.
*
* @param string $src of target image.
* @param string $dir as base directory where images are stored.
* @param string $dir as optional base directory where images are stored.
* Uses $this->saveFolder if null.
*
* @return $this
*/
public function setTarget($src = null, $dir = null)
{
if (!(isset($src) && isset($dir))) {
if (!isset($src)) {
$this->cacheFileName = null;
return $this;
}
$this->saveFolder = $dir;
$this->cacheFileName = $dir . '/' . $src;
if (isset($dir)) {
$this->saveFolder = rtrim($dir, '/');
}
/* Allow readonly cache
is_writable($this->saveFolder)
or $this->raiseError('Target directory is not writable.');
*/
$this->cacheFileName = $this->saveFolder . '/' . $src;
// Sanitize filename
$this->cacheFileName = preg_replace('/^a-zA-Z0-9\.-_/', '', $this->cacheFileName);
@@ -634,6 +743,18 @@ class CImage
/**
* Get filename of target file.
*
* @return Boolean|String as filename of target or false if not set.
*/
public function getTarget()
{
return $this->cacheFileName;
}
/**
* Set options to use when processing image.
*
@@ -681,11 +802,6 @@ class CImage
// Output format
'outputFormat' => null,
'dpr' => 1,
// Options for saving
//'quality' => null,
//'compress' => null,
//'saveAs' => null,
);
// Convert crop settings from string to array
@@ -1179,13 +1295,15 @@ class CImage
/**
* Generate filename to save file in cache.
*
* @param string $base as basepath for storing file.
* @param string $base as optional basepath for storing file.
* @param boolean $useSubdir use or skip the subdir part when creating the
* filename.
*
* @return $this
*/
public function generateFilename($base)
public function generateFilename($base = null, $useSubdir = true)
{
$parts = pathinfo($this->pathToImage);
$filename = basename($this->pathToImage);
$cropToFit = $this->cropToFit ? '_cf' : null;
$fillToFit = $this->fillToFit ? '_ff' : null;
$crop_x = $this->crop_x ? "_x{$this->crop_x}" : null;
@@ -1197,6 +1315,14 @@ class CImage
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
$saveAs = $this->normalizeFileExtension();
$saveAs = $saveAs ? "_$saveAs" : null;
$copyStrat = null;
if ($this->copyStrategy === self::RESIZE) {
$copyStrat = "_rs";
}
$width = $this->newWidth;
$height = $this->newHeight;
@@ -1214,7 +1340,7 @@ class CImage
if (is_array($filter)) {
$filters .= "_f{$filter['id']}";
for ($i=1; $i<=$filter['argc']; $i++) {
$filters .= ":".$filter["arg{$i}"];
$filters .= "-".$filter["arg{$i}"];
}
}
}
@@ -1227,16 +1353,6 @@ class CImage
$autoRotate = $this->autoRotate ? 'ar' : null;
$this->extension = isset($this->extension)
? $this->extension
: (isset($parts['extension'])
? $parts['extension']
: null);
$extension = empty($this->extension)
? null
: "." . $this->extension;
$optimize = $this->jpegOptimize ? 'o' : null;
$optimize .= $this->pngFilter ? 'f' : null;
$optimize .= $this->pngDeflate ? 'd' : null;
@@ -1251,14 +1367,20 @@ class CImage
$upscale = '_nu';
}
$subdir = str_replace('/', '-', dirname($this->imageSrc));
$subdir = ($subdir == '.') ? '_.' : $subdir;
$file = $subdir . '_' . $parts['filename'] . '_' . $width . '_'
$subdir = null;
if ($useSubdir === true) {
$subdir = str_replace('/', '-', dirname($this->imageSrc));
$subdir = ($subdir == '.') ? '_.' : $subdir;
$subdir .= '_';
}
$file = $subdir . $filename . '_' . $width . '_'
. $height . $offset . $crop . $cropToFit . $fillToFit
. $crop_x . $crop_y . $upscale
. $quality . $filters . $sharpen . $emboss . $blur . $palette . $optimize
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor . $convolve
. $extension;
. $quality . $filters . $sharpen . $emboss . $blur . $palette
. $optimize . $compress
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
. $convolve . $copyStrat . $saveAs;
return $this->setTarget($file, $base);
}
@@ -1323,6 +1445,7 @@ class CImage
throw new Exception("Could not load image.");
}
/* Removed v0.7.7
if (image_type_to_mime_type($this->fileType) == 'image/png') {
$type = $this->getPngType();
$hasFewColors = imagecolorstotal($this->image);
@@ -1334,14 +1457,15 @@ class CImage
$this->palette = true;
}
}
*/
if ($this->verbose) {
$this->log("Image successfully loaded from file.");
$this->log("### Image successfully loaded from file.");
$this->log(" imageistruecolor() : " . (imageistruecolor($this->image) ? 'true' : 'false'));
$this->log(" imagecolorstotal() : " . imagecolorstotal($this->image));
$this->log(" Number of colors in image = " . $this->colorsTotal($this->image));
$index = imagecolortransparent($this->image);
$this->log(" Detected transparent color = " . ($index > 0 ? implode(", ", imagecolorsforindex($this->image, $index)) : "NONE") . " at index = $index");
$this->log(" Detected transparent color = " . ($index >= 0 ? implode(", ", imagecolorsforindex($this->image, $index)) : "NONE") . " at index = $index");
}
return $this;
@@ -1352,44 +1476,80 @@ class CImage
/**
* Get the type of PNG image.
*
* @param string $filename to use instead of default.
*
* @return int as the type of the png-image
*
*/
private function getPngType()
public function getPngType($filename = null)
{
$pngType = ord(file_get_contents($this->pathToImage, false, null, 25, 1));
$filename = $filename ? $filename : $this->pathToImage;
$pngType = ord(file_get_contents($filename, false, null, 25, 1));
if ($this->verbose) {
$this->log("Checking png type of: " . $filename);
$this->log($this->getPngTypeAsString($pngType));
}
return $pngType;
}
/**
* Get the type of PNG image as a verbose string.
*
* @param integer $type to use, default is to check the type.
* @param string $filename to use instead of default.
*
* @return int as the type of the png-image
*
*/
private function getPngTypeAsString($pngType = null, $filename = null)
{
if ($filename || !$pngType) {
$pngType = $this->getPngType($filename);
}
$index = imagecolortransparent($this->image);
$transparent = null;
if ($index != -1) {
$transparent = " (transparent)";
}
switch ($pngType) {
case self::PNG_GREYSCALE:
$this->log("PNG is type 0, Greyscale.");
$text = "PNG is type 0, Greyscale$transparent";
break;
case self::PNG_RGB:
$this->log("PNG is type 2, RGB");
$text = "PNG is type 2, RGB$transparent";
break;
case self::PNG_RGB_PALETTE:
$this->log("PNG is type 3, RGB with palette");
$text = "PNG is type 3, RGB with palette$transparent";
break;
case self::PNG_GREYSCALE_ALPHA:
$this->Log("PNG is type 4, Greyscale with alpha channel");
$text = "PNG is type 4, Greyscale with alpha channel";
break;
case self::PNG_RGB_ALPHA:
$this->Log("PNG is type 6, RGB with alpha channel (PNG 32-bit)");
$text = "PNG is type 6, RGB with alpha channel (PNG 32-bit)";
break;
default:
$this->Log("PNG is UNKNOWN type, is it really a PNG image?");
$text = "PNG is UNKNOWN type, is it really a PNG image?";
}
return $pngType;
return $text;
}
/**
* Calculate number of colors in an image.
*
@@ -1425,7 +1585,7 @@ class CImage
*/
public function preResize()
{
$this->log("Pre-process before resizing");
$this->log("### Pre-process before resizing");
// Rotate image
if ($this->rotateBefore) {
@@ -1458,6 +1618,39 @@ class CImage
/**
* Resize or resample the image while resizing.
*
* @param int $strategy as CImage::RESIZE or CImage::RESAMPLE
*
* @return $this
*/
public function setCopyResizeStrategy($strategy)
{
$this->copyStrategy = $strategy;
return $this;
}
/**
* Resize and or crop the image.
*
* @return void
*/
public function imageCopyResampled($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h)
{
if($this->copyStrategy == self::RESIZE) {
$this->log("Copy by resize");
imagecopyresized($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
} else {
$this->log("Copy by resample");
imagecopyresampled($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
}
}
/**
* Resize and or crop the image.
*
@@ -1466,7 +1659,7 @@ class CImage
public function resize()
{
$this->log("Starting to Resize()");
$this->log("### Starting to Resize()");
$this->log("Upscale = '$this->upscale'");
// Only use a specified area of the image, $this->offset is defining the area to use
@@ -1526,7 +1719,7 @@ class CImage
$cropY = round(($this->cropHeight/2) - ($this->newHeight/2));
$imgPreCrop = $this->CreateImageKeepTransparency($this->cropWidth, $this->cropHeight);
$imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight);
imagecopyresampled($imgPreCrop, $this->image, 0, 0, 0, 0, $this->cropWidth, $this->cropHeight, $this->width, $this->height);
$this->imageCopyResampled($imgPreCrop, $this->image, 0, 0, 0, 0, $this->cropWidth, $this->cropHeight, $this->width, $this->height);
imagecopy($imageResized, $imgPreCrop, 0, 0, $cropX, $cropY, $this->newWidth, $this->newHeight);
}
@@ -1565,7 +1758,7 @@ class CImage
} else {
$imgPreFill = $this->CreateImageKeepTransparency($this->fillWidth, $this->fillHeight);
$imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight);
imagecopyresampled($imgPreFill, $this->image, 0, 0, 0, 0, $this->fillWidth, $this->fillHeight, $this->width, $this->height);
$this->imageCopyResampled($imgPreFill, $this->image, 0, 0, 0, 0, $this->fillWidth, $this->fillHeight, $this->width, $this->height);
imagecopy($imageResized, $imgPreFill, $posX, $posY, 0, 0, $this->fillWidth, $this->fillHeight);
}
@@ -1611,7 +1804,7 @@ class CImage
}
} else {
$imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight);
imagecopyresampled($imageResized, $this->image, 0, 0, 0, 0, $this->newWidth, $this->newHeight, $this->width, $this->height);
$this->imageCopyResampled($imageResized, $this->image, 0, 0, 0, 0, $this->newWidth, $this->newHeight, $this->width, $this->height);
$this->image = $imageResized;
$this->width = $this->newWidth;
$this->height = $this->newHeight;
@@ -1630,7 +1823,7 @@ class CImage
*/
public function postResize()
{
$this->log("Post-process after resizing");
$this->log("### Post-process after resizing");
// Rotate image
if ($this->rotateAfter) {
@@ -2026,7 +2219,10 @@ class CImage
imagealphablending($img, false);
imagesavealpha($img, true);
$index = imagecolortransparent($this->image);
$index = $this->image
? imagecolortransparent($this->image)
: -1;
if ($index != -1) {
imagealphablending($img, true);
@@ -2087,10 +2283,11 @@ class CImage
*/
protected function getTargetImageExtension()
{
// switch on mimetype
if (isset($this->extension)) {
return strtolower($this->extension);
} else {
return image_type_to_extension($this->fileType);
return substr(image_type_to_extension($this->fileType), 1);
}
}
@@ -2099,21 +2296,29 @@ class CImage
/**
* Save image.
*
* @param string $src as target filename.
* @param string $base as base directory where to store images.
* @param string $src as target filename.
* @param string $base as base directory where to store images.
* @param boolean $overwrite or not, default to always overwrite file.
*
* @return $this or false if no folder is set.
*/
public function save($src = null, $base = null)
public function save($src = null, $base = null, $overwrite = true)
{
if (isset($src)) {
$this->setTarget($src, $base);
}
if ($overwrite === false && is_file($this->cacheFileName)) {
$this->Log("Not overwriting file since its already exists and \$overwrite if false.");
return;
}
is_writable($this->saveFolder)
or $this->raiseError('Target directory is not writable.');
switch($this->getTargetImageExtension()) {
$type = $this->getTargetImageExtension();
$this->Log("Saving image as " . $type);
switch($type) {
case 'jpeg':
case 'jpg':
@@ -2207,8 +2412,6 @@ class CImage
return $this;
}
$alias = $alias . "." . $this->getTargetImageExtension();
if (is_readable($alias)) {
unlink($alias);
}
@@ -2226,11 +2429,28 @@ class CImage
/**
* Add HTTP header for putputting together with image.
*
* @param string $type the header type such as "Cache-Control"
* @param string $value the value to use
*
* @return void
*/
public function addHTTPHeader($type, $value)
{
$this->HTTPHeader[$type] = $value;
}
/**
* Output image to browser using caching.
*
* @param string $file to read and output, default is to use $this->cacheFileName
* @param string $format set to json to output file as json object with details
* @param string $file to read and output, default is to
* use $this->cacheFileName
* @param string $format set to json to output file as json
* object with details
*
* @return void
*/
@@ -2250,6 +2470,10 @@ class CImage
header('Content-type: application/json');
echo $this->json($file);
exit;
} elseif ($format == 'ascii') {
header('Content-type: text/plain');
echo $this->ascii($file);
exit;
}
$this->log("Outputting image: $file");
@@ -2263,6 +2487,10 @@ class CImage
header('Last-Modified: ' . $gmdate . " GMT");
}
foreach($this->HTTPHeader as $key => $val) {
header("$key: $val");
}
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $lastModified) {
if ($this->verbose) {
@@ -2275,8 +2503,16 @@ class CImage
} else {
// Get details on image
$info = getimagesize($file);
!empty($info) or $this->raiseError("The file doesn't seem to be an image.");
$mime = $info['mime'];
$size = filesize($file);
if ($this->verbose) {
$this->log("Last modified: " . $gmdate . " GMT");
$this->log("Last-Modified: " . $gmdate . " GMT");
$this->log("Content-type: " . $mime);
$this->log("Content-length: " . $size);
$this->verboseOutput();
if (is_null($this->verboseFileName)) {
@@ -2284,12 +2520,8 @@ class CImage
}
}
// Get details on image
$info = getimagesize($file);
!empty($info) or $this->raiseError("The file doesn't seem to be an image.");
$mime = $info['mime'];
header('Content-type: ' . $mime);
header("Content-type: $mime");
header("Content-length: $size");
readfile($file);
}
@@ -2330,6 +2562,18 @@ class CImage
$details['aspectRatio'] = round($this->width / $this->height, 3);
$details['size'] = filesize($file);
$details['colors'] = $this->colorsTotal($this->image);
$details['includedFiles'] = count(get_included_files());
$details['memoryPeek'] = round(memory_get_peak_usage()/1024/1024, 3) . " MB" ;
$details['memoryCurrent'] = round(memory_get_usage()/1024/1024, 3) . " MB";
$details['memoryLimit'] = ini_get('memory_limit');
if (isset($_SERVER['REQUEST_TIME_FLOAT'])) {
$details['loadTime'] = (string) round((microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']), 3) . "s";
}
if ($details['mimeType'] == 'image/png') {
$details['pngType'] = $this->getPngTypeAsString(null, $file);
}
$options = null;
if (defined("JSON_PRETTY_PRINT") && defined("JSON_UNESCAPED_SLASHES")) {
@@ -2341,6 +2585,38 @@ class CImage
/**
* Set options for creating ascii version of image.
*
* @param array $options empty to use default or set options to change.
*
* @return void.
*/
public function setAsciiOptions($options = array())
{
$this->asciiOptions = $options;
}
/**
* Create an ASCII version from the image details.
*
* @param string $file the file to output.
*
* @return string ASCII representation of the image.
*/
public function ascii($file = null)
{
$file = $file ? $file : $this->cacheFileName;
$asciiArt = new CAsciiArt();
$asciiArt->setOptions($this->asciiOptions);
return $asciiArt->createFromFile($file);
}
/**
* Log an event if verbose mode.
*

View File

@@ -45,14 +45,14 @@ There are several ways of installing. You either install the whole project which
The [sourcode is available on GitHub](https://github.com/mosbth/cimage). Clone, fork or [download as zip](https://github.com/mosbth/cimage/archive/master.zip).
**Latest stable version is v0.7.1 released 2015-07-25.**
**Latest stable version is v0.7.6 released 2015-10-18.**
I prefer cloning like this. Do switch to the latest stable version.
```bash
git clone git://github.com/mosbth/cimage.git
cd cimage
git checkout v0.7.1
git checkout v0.7.6
```
Make the cache-directory writable by the webserver.
@@ -75,7 +75,7 @@ There are some all-included bundles of `img.php` that can be downloaded and used
Dowload the version of your choice like this.
```bash
wget https://github.com/mosbth/cimage/tree/v0.7.1/webroot/imgp.php
wget https://github.com/mosbth/cimage/tree/v0.7.6/webroot/imgp.php
```
Open up the file in your editor and edit the array `$config`. Ensure that the paths to the image directory and the cache directory matches your environment, or create an own config-file for the script.

View File

@@ -5,6 +5,57 @@ Revision history
[![Build Status](https://scrutinizer-ci.com/g/mosbth/cimage/badges/build.png?b=master)](https://scrutinizer-ci.com/g/mosbth/cimage/build-status/master)
v0.7.7 (2015-10-21)
-------------------------------------
* One can now add a HTTP header for Cache-Control in the config file, #109.
* Added hook in img,php before CImage is called, #123.
* Added configuration for default jpeg quality and png compression in the config file, #107.
* Strip comments and whitespace in imgs.php, #115.
* Bundle imgs.php did not have the correct mode.
* Adding option &status to get an overview of the installed on configured utilities, #116.
* Bug, all files saved as png-files, when not saving as specific file.
* Removed saving filename extension for alias images.
* Added option to decide if resample or resize when copying images internally. `&no-resample` makes resize, instead of resample as is default.
* Verbose now correctly states if transparent color is detected.
* Compare-tool now supports 6 images.
* Added option for dark background in the compare-tool.
* Removed that source png-files, containing less than 255 colors, is always saved as palette images since this migth depend on processing of the image.
* Adding save-as as part of the generated cache filename, #121.
* Add extra fields to json-response, #114.
* Add header for Content-Length, #111.
* Add check for postprocessing tools in path in `webroot/check_system.php`, #104.
v0.7.6 (2015-10-18)
-------------------------------------
* Adding testpage for dummy images `webroot/test/test_issue101-dummy.php`.
* Adding width and height when creating dummy image.
v0.7.5 (2015-10-18)
-------------------------------------
* Adding feature for creating dummy images `src=dummy`, #101.
* Add png compression to generated cache filename, fix #103.
* Removed file prefix from storing images in cache, breaking filenamestructure for cache images.
* Code cleaning in `CImage.php`.
v0.7.4 (2015-09-15)
-------------------------------------
* Add CAsciiArt.php to composer for autoloading, fix #102.
* Generate filename with filters, does not work on Windows, fix #100.
v0.7.3 (2015-09-01)
-------------------------------------
* Support output of ascii images, #67.
v0.7.2 (2015-08-17)
-------------------------------------

View File

@@ -37,6 +37,7 @@ $ECHO "\n webroot/img_header.php"
$ECHO "\n CHttpGet.php"
$ECHO "\n CRemoteImage.php"
$ECHO "\n CWhitelist.php"
$ECHO "\n CAsciiArt.php"
$ECHO "\n CImage.php"
$ECHO "\n webroot/img.php"
$ECHO "\n"
@@ -54,7 +55,7 @@ read answer
#
cat webroot/img_header.php > $TARGET_P
cat webroot/img_header.php | sed "s|//'mode' => 'production',|'mode' => 'development',|" > $TARGET_D
cat webroot/img_header.php | sed "s|//'mode' => 'production',|'mode' => 'development',|" > $TARGET_S
cat webroot/img_header.php | sed "s|//'mode' => 'production',|'mode' => 'strict',|" > $TARGET_S
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
@@ -64,15 +65,20 @@ $ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
tail -n +2 CRemoteImage.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
tail -n +2 CImage.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
tail -n +2 CWhitelist.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
tail -n +2 CWhitelist.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
tail -n +2 CAsciiArt.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
tail -n +2 CImage.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
tail -n +2 webroot/img.php | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
$ECHO "$NEWLINES" | tee -a $TARGET_D $TARGET_P $TARGET_S > /dev/null
php -w $TARGET_S > tmp && mv tmp $TARGET_S
$ECHO "\nDone."
$ECHO "\n"
$ECHO "\n"

1
cache/README.md vendored
View File

@@ -1 +0,0 @@
This directory must be writable by the webserver.

0
cache/dummy/README.md vendored Normal file
View File

View File

@@ -25,12 +25,8 @@
"CImage.php",
"CHttpGet.php",
"CRemoteImage.php",
"CWhitelist.php"
"CWhitelist.php",
"CAsciiArt.php"
]
},
"extra": {
"branch-alias": {
"dev-master": "0.7.x-dev"
}
}
}

49
test/CImageDummyTest.php Normal file
View File

@@ -0,0 +1,49 @@
<?php
/**
* A testclass
*
*/
class CImageDummyTest extends \PHPUnit_Framework_TestCase
{
/**
* Test
*
* @return void
*/
public function testCreate1()
{
$img = new CImage();
$img->setSaveFolder(CACHE_PATH . "/dummy");
$img->setSource('dummy', CACHE_PATH . "/dummy");
$img->createDummyImage();
$img->generateFilename(null, false);
$img->save(null, null, false);
$filename = $img->getTarget();
$this->assertEquals(basename($filename), "dummy_100_100", "Filename not as expected on dummy image.");
}
/**
* Test
*
* @return void
*/
public function testCreate2()
{
$img = new CImage();
$img->setSaveFolder(CACHE_PATH . "/dummy");
$img->setSource('dummy', CACHE_PATH . "/dummy");
$img->createDummyImage(200, 400);
$img->generateFilename(null, false);
$img->save(null, null, false);
$filename = $img->getTarget();
$this->assertEquals(basename($filename), "dummy_200_400", "Filename not as expected on dummy image.");
}
}

View File

@@ -4,3 +4,6 @@
*
*/
require __DIR__ . "/../autoload.php";
define('IMAGE_PATH', __DIR__ . '/../webroot/img/');
define('CACHE_PATH', __DIR__ . '/../cache/');

View File

@@ -4,6 +4,12 @@ echo 'Current PHP version: ' . phpversion() . '<br><br>';
echo 'Running on: ' . $_SERVER['SERVER_SOFTWARE'] . '<br><br>';
$no = extension_loaded('exif') ? null : 'NOT';
echo "Extension exif is $no loaded.<br>";
$no = extension_loaded('curl') ? null : 'NOT';
echo "Extension curl is $no loaded.<br>";
$no = extension_loaded('gd') ? null : 'NOT';
echo "Extension gd is $no loaded.<br>";
@@ -11,8 +17,13 @@ if (!$no) {
echo "<pre>", var_dump(gd_info()), "</pre>";
}
$no = extension_loaded('exif') ? null : 'NOT';
echo "Extension exif is $no loaded.<br>";
echo "<strong>Checking path for postprocessing tools</strong>";
$no = extension_loaded('curl') ? null : 'NOT';
echo "Extension curl is $no loaded.<br>";
echo "<br>optipng: ";
system("which optipng");
echo "<br>pngout: ";
system("which pngout");
echo "<br>jpegtran: ";
system("which jpegtran");

View File

@@ -29,7 +29,12 @@ input[type=text] {
.area {
float: left;
padding: 1em;
background-color: #fff;
background-color: #eee;
}
.invert {
background-color: #666;
color: white;
}
.json {
@@ -45,7 +50,7 @@ input[type=text] {
<body>
<h1>Compare images</h1>
<p>Add link to images and visually compare them. Change the link och press return to load the image. <a href="http://dbwebb.se/opensource/cimage">Read more...</a></p>
<p>Add link to images and visually compare them. Change the link och press return to load the image. Add <code>&amp;black</code> to the querystring to get a black background. <a href="http://dbwebb.se/opensource/cimage">Read more...</a></p>
<p><a id="permalink" href="?">Direct link to this setup.</a></p>
@@ -55,8 +60,11 @@ input[type=text] {
<label>Image 2: <input type="text" id="input2" data-id="2"></label> <img id="thumb2"></br>
<label>Image 3: <input type="text" id="input3" data-id="3"></label> <img id="thumb3"></br>
<label>Image 4: <input type="text" id="input4" data-id="4"></label> <img id="thumb4"></br>
<label>Image 5: <input type="text" id="input5" data-id="5"></label> <img id="thumb5"></br>
<label>Image 6: <input type="text" id="input6" data-id="6"></label> <img id="thumb6"></br>
<label><input type="checkbox" id="viewDetails">Show image details</label><br/>
<label><input type="checkbox" id="stack">Stack images?</label>
<label><input type="checkbox" id="stack">Stack images?</label><br/>
<label><input type="checkbox" id="bg">Dark background?</label>
</p>
</form>
@@ -65,6 +73,8 @@ input[type=text] {
<button id="button2" class="button" data-id="2">Image 2</button>
<button id="button3" class="button" data-id="3">Image 3</button>
<button id="button4" class="button" data-id="4">Image 4</button>
<button id="button5" class="button" data-id="5">Image 5</button>
<button id="button6" class="button" data-id="6">Image 6</button>
</div>
<div id="wrap">
@@ -93,6 +103,18 @@ input[type=text] {
<pre id="json4" class="json hidden"></pre>
</div>
<div id="area5" class="area">
<code>Image 5</code><br>
<img id="img5">
<pre id="json5" class="json hidden"></pre>
</div>
<div id="area6" class="area">
<code>Image 6</code><br>
<img id="img6">
<pre id="json6" class="json hidden"></pre>
</div>
</div>
@@ -110,8 +132,11 @@ if (isset($_GET['input1'])) {
"input2": "<?=$_GET['input2']?>",
"input3": "<?=$_GET['input3']?>",
"input4": "<?=$_GET['input4']?>",
"input5": "<?=$_GET['input5']?>",
"input6": "<?=$_GET['input6']?>",
"json": <?=$_GET['json']?>,
"stack": <?=$_GET['stack']?>
"stack": <?=$_GET['stack']?>,
"bg": <?=$_GET['bg']?>
});
<?php
} elseif (isset($script)) {

View File

@@ -0,0 +1,16 @@
<?php
$script = <<<EOD
CImage.compare({
"input1": "../img.php?src=issue117/tri_original.png",
"input2": "../img.php?src=issue117/tri_imageresizing.png",
"input3": "../img.php?src=issue117/tri_cimage.png",
"input4": "../img.php?src=issue117/tri_imagemagick.png",
"input5": "../img.php?src=issue117/tri_original.png&w=190",
"input6": "../img.php?src=issue117/tri_original.png&w=190&no-resample",
"json": true,
"stack": false,
"bg": true
});
EOD;
include __DIR__ . "/compare.php";

View File

@@ -8,12 +8,12 @@
*
*/
$version = "v0.7.2 (2015-08-17)";
$version = "v0.7.7 (2015-10-21)";
/**
* Default configuration options, can be overridden in own config-file.
* Display error message.
*
* @param string $msg to display.
*
@@ -157,6 +157,13 @@ verbose("img.php version = $version");
/**
* status - do a verbose dump of the configuration
*/
$status = getDefined('status', true, false);
/**
* Set mode as strict, production or development.
* Default is production environment.
@@ -178,6 +185,7 @@ if ($mode == 'strict') {
ini_set('display_errors', 0);
ini_set('log_errors', 1);
$verbose = false;
$status = false;
$verboseFile = false;
} elseif ($mode == 'production') {
@@ -186,6 +194,7 @@ if ($mode == 'strict') {
ini_set('display_errors', 0);
ini_set('log_errors', 1);
$verbose = false;
$status = false;
$verboseFile = false;
} elseif ($mode == 'development') {
@@ -373,10 +382,20 @@ $imagePath = getConfig('image_path', __DIR__ . '/img/');
$imagePathConstraint = getConfig('image_path_constraint', true);
$validFilename = getConfig('valid_filename', '#^[a-z0-9A-Z-/_ \.:]+$#');
// Dummy image feature
$dummyEnabled = getConfig('dummy_enabled', true);
$dummyFilename = getConfig('dummy_filename', 'dummy');
$dummyImage = false;
preg_match($validFilename, $srcImage)
or errorPage('Filename contains invalid characters.');
if ($allowRemote && $img->isRemoteSource($srcImage)) {
if ($dummyEnabled && $srcImage === $dummyFilename) {
// Prepare to create a dummy image and use it as the source image.
$dummyImage = true;
} elseif ($allowRemote && $img->isRemoteSource($srcImage)) {
// If source is a remote file, ignore local file checks.
@@ -548,6 +567,19 @@ verbose("bgColor = $bgColor");
/**
* Do or do not resample image when resizing.
*/
$resizeStrategy = getDefined(array('no-resample'), true, false);
if ($resizeStrategy) {
$img->setCopyResizeStrategy($img::RESIZE);
verbose("Setting = Resize instead of resample");
}
/**
* fill-to-fit, ff - affecting the resulting image width, height and resize options
*/
@@ -617,11 +649,16 @@ verbose("use cache = $useCache");
* quality, q - set level of quality for jpeg images
*/
$quality = get(array('quality', 'q'));
$qualityDefault = getConfig('jpg_quality', null);
is_null($quality)
or ($quality > 0 and $quality <= 100)
or errorPage('Quality out of range');
if (is_null($quality) && !is_null($qualityDefault)) {
$quality = $qualityDefault;
}
verbose("quality = $quality");
@@ -630,12 +667,16 @@ verbose("quality = $quality");
* compress, co - what strategy to use when compressing png images
*/
$compress = get(array('compress', 'co'));
$compressDefault = getConfig('png_compression', null);
is_null($compress)
or ($compress > 0 and $compress <= 9)
or errorPage('Compress out of range');
if (is_null($compress) && !is_null($compressDefault)) {
$compress = $compressDefault;
}
verbose("compress = $compress");
@@ -754,11 +795,51 @@ verbose("filters = " . print_r($filters, 1));
/**
* json - output the image as a JSON object with details on the image.
* json - output the image as a JSON object with details on the image.
* ascii - output the image as ASCII art.
*/
$outputFormat = getDefined('json', 'json', null);
$outputFormat = getDefined('ascii', 'ascii', $outputFormat);
verbose("outputformat = $outputFormat");
if ($outputFormat == 'ascii') {
$defaultOptions = getConfig(
'ascii-options',
array(
"characterSet" => 'two',
"scale" => 14,
"luminanceStrategy" => 3,
"customCharacterSet" => null,
)
);
$options = get('ascii');
$options = explode(',', $options);
if (isset($options[0]) && !empty($options[0])) {
$defaultOptions['characterSet'] = $options[0];
}
if (isset($options[1]) && !empty($options[1])) {
$defaultOptions['scale'] = $options[1];
}
if (isset($options[2]) && !empty($options[2])) {
$defaultOptions['luminanceStrategy'] = $options[2];
}
if (count($options) > 3) {
// Last option is custom character string
unset($options[0]);
unset($options[1]);
unset($options[2]);
$characterString = implode($options);
$defaultOptions['customCharacterSet'] = $characterString;
}
$img->setAsciiOptions($defaultOptions);
}
verbose("json = $outputFormat");
@@ -847,6 +928,146 @@ $cachePath = getConfig('cache_path', __DIR__ . '/../cache/');
/**
* Get the cachepath from config.
*/
$cacheControl = getConfig('cache_control', null);
if ($cacheControl) {
verbose("cacheControl = $cacheControl");
$img->addHTTPHeader("Cache-Control", $cacheControl);
}
/**
* Prepare a dummy image and use it as source image.
*/
$dummyDir = getConfig('dummy_dir', $cachePath. "/" . $dummyFilename);
if ($dummyImage === true) {
is_writable($dummyDir)
or verbose("dummy dir not writable = $dummyDir");
$img->setSaveFolder($dummyDir)
->setSource($dummyFilename, $dummyDir)
->setOptions(
array(
'newWidth' => $newWidth,
'newHeight' => $newHeight,
'bgColor' => $bgColor,
)
)
->setJpegQuality($quality)
->setPngCompression($compress)
->createDummyImage()
->generateFilename(null, false)
->save(null, null, false);
$srcImage = $img->getTarget();
$imagePath = null;
verbose("src (updated) = $srcImage");
}
/**
* Display status
*/
if ($status) {
$text = "img.php version = $version\n";
$text .= "PHP version = " . PHP_VERSION . "\n";
$text .= "Running on: " . $_SERVER['SERVER_SOFTWARE'] . "\n";
$text .= "Allow remote images = $allowRemote\n";
$text .= "Cache writable = " . is_writable($cachePath) . "\n";
$text .= "Cache dummy writable = " . is_writable($dummyDir) . "\n";
$text .= "Alias path writable = " . is_writable($aliasPath) . "\n";
$no = extension_loaded('exif') ? null : 'NOT';
$text .= "Extension exif is $no loaded.<br>";
$no = extension_loaded('curl') ? null : 'NOT';
$text .= "Extension curl is $no loaded.<br>";
$no = extension_loaded('gd') ? null : 'NOT';
$text .= "Extension gd is $no loaded.<br>";
if (!$no) {
$text .= print_r(gd_info(), 1);
}
echo <<<EOD
<!doctype html>
<html lang=en>
<meta charset=utf-8>
<title>CImage status</title>
<pre>$text</pre>
EOD;
exit;
}
/**
* Log verbose details to file
*/
if ($verboseFile) {
$img->setVerboseToFile("$cachePath/log.txt");
}
/**
* Hook after img.php configuration and before processing with CImage
*/
$hookBeforeCImage = getConfig('hook_before_CImage', null);
if (is_callable($hookBeforeCImage)) {
verbose("hookBeforeCImage activated");
$allConfig = $hookBeforeCImage($img, array(
// Options for calculate dimensions
'newWidth' => $newWidth,
'newHeight' => $newHeight,
'aspectRatio' => $aspectRatio,
'keepRatio' => $keepRatio,
'cropToFit' => $cropToFit,
'fillToFit' => $fillToFit,
'crop' => $crop,
'area' => $area,
'upscale' => $upscale,
// Pre-processing, before resizing is done
'scale' => $scale,
'rotateBefore' => $rotateBefore,
'autoRotate' => $autoRotate,
// General processing options
'bgColor' => $bgColor,
// Post-processing, after resizing is done
'palette' => $palette,
'filters' => $filters,
'sharpen' => $sharpen,
'emboss' => $emboss,
'blur' => $blur,
'convolve' => $convolve,
'rotateAfter' => $rotateAfter,
// Output format
'outputFormat' => $outputFormat,
'dpr' => $dpr,
// Other
'postProcessing' => $postProcessing,
));
verbose(print_r($allConfig, 1));
extract($allConfig);
}
/**
* Display image if verbose mode
*/
@@ -874,7 +1095,7 @@ if ($verbose) {
window.getDetails = function (url, id) {
$.getJSON(url, function(data) {
element = document.getElementById(id);
element.innerHTML = "filename: " + data.filename + "\\nmime type: " + data.mimeType + "\\ncolors: " + data.colors + "\\nsize: " + data.size + "\\nwidth: " + data.width + "\\nheigh: " + data.height + "\\naspect-ratio: " + data.aspectRatio;
element.innerHTML = "filename: " + data.filename + "\\nmime type: " + data.mimeType + "\\ncolors: " + data.colors + "\\nsize: " + data.size + "\\nwidth: " + data.width + "\\nheigh: " + data.height + "\\naspect-ratio: " + data.aspectRatio + ( data.pngType ? "\\npng-type: " + data.pngType : '');
});
}
</script>
@@ -885,17 +1106,8 @@ EOD;
/**
* Log verbose details to file
* Load, process and output the image
*/
if ($verboseFile) {
$img->setVerboseToFile("$cachePath/log.txt");
}
/**
* Load, process and output the image
*/
$img->log("Incoming arguments: " . print_r(verbose(), 1))
->setSaveFolder($cachePath)
->useCache($useCache)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@@ -13,7 +13,7 @@ return array(
* Default values:
* mode: 'production'
*/
'mode' => 'development',
'mode' => 'development', // 'development', 'strict'
//'mode' => 'production', // 'development', 'strict'
@@ -109,6 +109,69 @@ return array(
/**
* Change the default values for CImage quality and compression used
* when saving images.
*
* Default value:
* jpg_quality: null, integer between 0-100
* png_compression: null, integer between 0-9
*/
//'jpg_quality' => 75,
//'png_compression' => 1,
/**
* A function (hook) can be called after img.php has processed all
* configuration options and before processing the image using CImage.
* The function receives the $img variabel and an array with the
* majority of current settings.
*
* Default value:
* hook_before_CImage: null
*/
/*'hook_before_CImage' => function (CImage $img, Array $allConfig) {
if ($allConfig['newWidth'] > 10) {
$allConfig['newWidth'] *= 2;
}
return $allConfig;
},*/
/**
* Add header for cache control when outputting images.
*
* Default value:
* cache_control: null, or set to string
*/
//'cache_control' => "max-age=86400",
/**
* The name representing a dummy image which is automatically created
* and stored at the defined path. The dummy image can then be used
* inplace of an original image as a placeholder.
* The dummy_dir must be writable and it defaults to a subdir of the
* cache directory.
* Write protect the dummy_dir to prevent creation of new dummy images,
* but continue to use the existing ones.
*
* Default value:
* dummy_enabled: true as default, disable dummy feature by setting
* to false.
* dummy_filename: 'dummy' use this as ?src=dummy to create a dummy image.
* dummy_dir: Defaults to subdirectory of 'cache_path',
* named the same as 'dummy_filename'
*/
//'dummy_enabled' => true,
//'dummy_filename' => 'dummy',
//'dummy_dir' => 'some writable directory',
/**
* Check that the imagefile is a file below 'image_path' using realpath().
* Security constraint to avoid reaching images outside image_path.
@@ -299,4 +362,25 @@ return array(
'golden' => 1.618,
);
},*/
/**
* default options for ascii image.
*
* Default values as specified below in the array.
* ascii-options:
* characterSet: Choose any character set available in CAsciiArt.
* scale: How many pixels should each character
* translate to.
* luminanceStrategy: Choose any strategy available in CAsciiArt.
* customCharacterSet: Define your own character set.
*/
/*'ascii-options' => array(
"characterSet" => 'two',
"scale" => 14,
"luminanceStrategy" => 3,
"customCharacterSet" => null,
);
},*/
);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -25,8 +25,11 @@ window.CImage = (function() {
input2 = document.getElementById("input2"),
input3 = document.getElementById("input3"),
input4 = document.getElementById("input4"),
input5 = document.getElementById("input5"),
input6 = document.getElementById("input6"),
details = document.getElementById("viewDetails"),
stack = document.getElementById("stack"),
bg = document.getElementById("bg"),
permalink = document.getElementById("permalink");
link = "?";
@@ -34,8 +37,11 @@ window.CImage = (function() {
link += "input2=" + encodeURIComponent(input2.value) + "&";
link += "input3=" + encodeURIComponent(input3.value) + "&";
link += "input4=" + encodeURIComponent(input4.value) + "&";
link += "input5=" + encodeURIComponent(input5.value) + "&";
link += "input6=" + encodeURIComponent(input6.value) + "&";
link += "json=" + encodeURIComponent(details.checked) + "&";
link += "stack=" + encodeURIComponent(stack.checked);
link += "stack=" + encodeURIComponent(stack.checked) + "&";
link += "bg=" + encodeURIComponent(bg.checked);
permalink.href = link;
}
@@ -69,7 +75,7 @@ window.CImage = (function() {
area.classList.remove("hidden");
$.getJSON(this.value + "&json", function(data) {
json.innerHTML = "filename: " + data.filename + "\ncolors: " + data.colors + "\nsize: " + data.size + "\nwidth: " + data.width + "\nheigh: " + data.height + "\naspect-ratio: " + data.aspectRatio;
json.innerHTML = "filename: " + data.filename + "\ncolors: " + data.colors + "\nsize: " + data.size + "\nwidth: " + data.width + "\nheigh: " + data.height + "\naspect-ratio: " + data.aspectRatio + "\npng-type: " + data.pngType;
})
.fail(function() {
json.innerHTML = "Details not available."
@@ -95,14 +101,19 @@ window.CImage = (function() {
input2 = document.getElementById("input2"),
input3 = document.getElementById("input3"),
input4 = document.getElementById("input4"),
input5 = document.getElementById("input5"),
input6 = document.getElementById("input6"),
details = document.getElementById("viewDetails"),
stack = document.getElementById("stack"),
bg = document.getElementById("bg"),
buttons = document.getElementById("buttonWrap");
input1.addEventListener("change", compareLoadImage);
input2.addEventListener("change", compareLoadImage);
input3.addEventListener("change", compareLoadImage);
input4.addEventListener("change", compareLoadImage);
input5.addEventListener("change", compareLoadImage);
input6.addEventListener("change", compareLoadImage);
// Toggle json
details.addEventListener("change", function() {
@@ -129,6 +140,23 @@ window.CImage = (function() {
details.dispatchEvent(myEvent);
}
// Toggle background color
bg.addEventListener("change", function() {
var elements = document.querySelectorAll(".area");
forEach(elements, function (index, element) {
element.classList.toggle("invert");
});
});
// Check background
if (options.bg === true) {
bg.setAttribute("checked", "checked");
bg.classList.toggle("invert");
myEvent = new CustomEvent("change");
bg.dispatchEvent(myEvent);
}
// Toggle stack
stack.addEventListener("change", function() {
var element,
@@ -200,11 +228,15 @@ window.CImage = (function() {
input2.value = options.input2 || null;
input3.value = options.input3 || null;
input4.value = options.input4 || null;
input5.value = options.input5 || null;
input6.value = options.input6 || null;
compareLoadImage.call(input1);
compareLoadImage.call(input2);
compareLoadImage.call(input3);
compareLoadImage.call(input4);
compareLoadImage.call(input5);
compareLoadImage.call(input6);
console.log(options);
}

View File

@@ -0,0 +1,36 @@
<?php
// Include config for all testcases
include __DIR__ . "/config.php";
// The title of the test case
$title = "Testing issue 100 - Dummy images";
// Provide a short description of the testcase.
$description = "Create dummy images.";
// Use these images in the test
$images = array(
'dummy',
);
// For each image, apply these testcases
$testcase = array(
'&nc&so',
'&nc&width=300',
'&nc&height=300',
'&nc&width=300&height=300',
'&nc&bgc=006600',
);
// Apply testcases and present results
include __DIR__ . "/template.php";