- First commit of an old reworked project

This commit is contained in:
Dave M. 2022-05-16 01:22:47 +00:00
commit a3e62c5720
11 changed files with 1100 additions and 0 deletions

14
LICENSE Normal file
View File

@ -0,0 +1,14 @@
Copyright (C) 2017 Dave Mc Nicoll
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

21
composer.json Normal file
View File

@ -0,0 +1,21 @@
{
"name": "mcnd/imagine",
"description": "A simple image processor using GD extension.",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Dave Mc Nicoll",
"email": "mcndave@gmail.com"
}
],
"require": {
"php": "^7.4",
"ext-gd": "*"
},
"autoload": {
"psr-4": {
"Imagine\\": "src/"
}
}
}

306
src/Canvas.php Normal file
View File

@ -0,0 +1,306 @@
<?php
namespace Imagine;
class Canvas {
public int $width;
public int $height;
public /*\resource*/ $image; /* actual img resource */
public /*\resource*/ $parent;
public array $layers = [];
public array $font = [];
public Colors $colors;
public function __construct($width = 0, $height = 0) {
if ( $width && $height ) {
$this->create($width, $height);
}
}
public function __destruct() {
$this->destroy();
}
public function destroy() : self
{
\is_resource($this->image) && \imagedestroy($this->image);
return $this;
}
public function create(int $width, int $height) : self
{
$this->width = $width;
$this->height = $height;
$image = \imagecreatetruecolor($width, $height);
$colors = new Colors($image);
$colors['fore'] = empty($this->colors['fore']) ? Colors::allocate($image, "000000") : Colors::allocate($image, $this->colors['fore']);
$colors['brush'] = empty($this->colors['brush']) ? Colors::allocate($image, "FFFFFF:0.0") : Colors::allocate($image, $this->colors['brush']);
$colors['back'] = empty($this->colors['back']) ? Colors::allocate($image, ":0.0") : Colors::allocate($image, $this->colors['back']);
$colors['text'] = empty($this->colors['text']) ? Colors::allocate($image, "000000") : Colors::allocate($image, $this->colors['text']);
$this->colors = $colors;
if ( empty($this->font['id']) ) {
$this->font['id'] = 1;
}
\imagesavealpha($image, true);
\imagealphablending($image, true);
\imagefill($image, 0, 0, IMG_COLOR_TRANSPARENT);
$this->image($image);
return $this;
}
/* Getters / Setters */
public function parent($set = null) {
return $set === null ? $this->parent : $this->parent = $set;
}
public function width($set = null) {
return $set === null ? $this->width : $this->width = $set;
}
public function height($set = null) {
return $set === null ? $this->height : $this->height = $set;
}
public function & image($set = null) {
if ( $set ) {
$this->image = $set;
};
return $this->image;
}
public function layers($name = null, $replace = null) {
return $name ? ( $replace ? $this->layers[$name] = $replace : $this->layers[$name] ) : $this->layers;
}
public function addLayer($name, $param = array()) : Layer
{
$param = $param + [
'width' => $this->width,
'height' => $this->height,
'parent' => $this
];
return $this->layers[$name] = Layer::make($param)->onTop($this);
}
/*
* Assign a color to the current image resource
*
* @param array $colors = [
* 'color' => "aacc22:0.4"
* 'background' => ':0.0" # transparency
* ]
*
*/
public function colors($colors) : ? Colors
{
if ($colors && is_array($colors)) {
$colorobj = Colors::make($this->image());
foreach($colors as $key => $value) {
$colorobj[$key] = $value;
}
return $colorobj;
}
return null;
}
public function measureText(string $text) : int
{
return Text::measure($text, $this->font['id']);
}
public function drawText(string $text, int $x, int $y, array $colors = []) : bool
{
return Text::draw($this->image(), $colors ?: $this->colors, $this->font['id'], $text, $x, $y);
}
public function polygonLabel($labels, $spacing, $x, $y, $size, $angle = 0) : array
{
$vertexcount = count($labels);
$r = $size / 2;
$x = $x;
$y = $y;
$coord = [];
$points = Polygon::polygonCoord($vertexcount, $x, $y, $size, $angle);
for ($i = 0; $i < $vertexcount; $i++) {
$textsize = $this->measureText($labels[$i]);
$tx = $points["x$i"];
$ty = $points["y$i"];
# processing X
# we are in the center of the poly width
if ( ! \bccomp($tx, $x) ) {
$coord["x$i"] = $x - $textsize['width'] / 2;
}
else if ($tx > $x) {
$coord["x$i"] = $tx + $spacing;
}
else {
#echo $x . " = " . $tx . " <br>";
$coord["x$i"] = $tx - $spacing - $textsize['width'];
}
# processing Y
if ( ! \bccomp($ty, $y) ) {
$coord["y$i"] = $y - $textsize['height'] / 2;
}
elseif ($ty > $y) {
$coord["y$i"] = $ty + $spacing;
}
else {
$coord["y$i"] = $ty - $textsize['height'] - $spacing;
}
}
return $coord;
}
public function fillBorder($x, $y, $colors = null) : bool
{
return \imagefilltoborder($this->image(), $x, $y, $colors ? $colors['fore'] : $this->colors['fore'], $colors ? $colors['brush'] : $this->colors['brush']);
}
public function merge(resource $image, int $x = 0, int $y = 0, int $srcX = 0, int $srcY = 0) : self
{
Merge::simple($this->image(), $image, $x, $y, $srcX, $srcY);
return $this;
}
public function grabImageResource(Canvas $src) : void
{
$this->destroy();
$this->image($src->image());
unset($src->image);
}
public function constrain(int $width, int $height, bool $immutable = true) : self
{
if ( ($this->width > $width) || ($this->height > $height) ) {
if ($this->width > $this->height) {
$height = $this->height * ( $width / $this->width );
}
else {
$width = $this->width * ( $height / $this->height );
}
$new = ( new static() )->create($width, $height);
$this->copyTo( $new );
if ( ! $immutable ) {
$this->grabImageResource($new);
$this->width = $width;
$this->height = $height;
}
else {
return $new;
}
}
return $this;
}
public function copyTo(Canvas $dest, int $dst_x = 0, int $dst_y = 0, int $src_x = 0, int $src_y = 0, int $dst_w = 0, int $dst_h = 0, int $src_w = 0, int $src_h = 0) : self
{
if ( ! \imagecopyresampled($dest->image(), $this->image(), $dst_x, $dst_y, $src_x, $src_y, $dst_w ?: $dest->width, $dst_h ?: $dest->height, $src_w ?: $this->width, $src_h ?: $this->height) ) {
trigger_error('Given image was not resampled : an error occured', \E_USER_ERROR);
}
return $this;
}
public function drawLine(int $x1, int $y1, int $x2, int $y2, array $colors = []) : bool
{
return Draw::line($this->image(), $x1, $y1, $x2, $y2, $colors ? : $this->colors);
}
public function drawRectangle(int $x1, int $y1, int $width, int $height, array $colors = []) : bool
{
return Polygon::drawRectangle($this->image(), $x1, $y1, $x1 + $width, $y1 + $height, $colors ? $colors : $this->colors);
}
public function drawIrregularPolygon(array $points, int $x, int $y, $angle = 0, array $colors = []) : bool
{
return Polygon::drawIrregular($this->image(), $colors ? : $this->colors, $points, $x, $y, $angle);
}
public function drawPolygon(int $vertexcount, int $x, int $y, int $size, $angle = 0, $colors = []) : bool
{
return Polygon::draw($this->image(), $colors ? : $this->colors, $vertexcount, $x, $y, $size, $angle);
}
public function drawCircle(int $x, int $y, int $size, array $colors = []) : bool
{
return Polygon::drawEllipse($this->image(), $colors ? : $this->colors, $x, $y, $size, $size);
}
public function drawEllipse(int $x, int $y, int $width, int $height, array $colors = []) : bool
{
return Polygon::drawEllipse($this->image(), $colors ? : $this->colors, $x, $y, $width, $height);
}
public function drawTriangle(int $posX, int $posY, int $size, $angle = 0, array $colors = []) : bool
{
return Polygon::draw($this->image(), $colors ? : $this->colors, 3, $posX, $posY, $size, $angle);
}
public function drawQuadrilateral(int $posX, int $posY, int $size, $angle = 0, array $colors = []) : bool
{
return Polygon::draw($this->image(), $colors ? : $this->colors, 4, $posX, $posY, $size, $angle);
}
public function drawPentagon(int $posX, int $posY, $size, $angle = 0, array $colors = []) : bool
{
return Polygon::draw($this->image(), $colors ? : $this->colors, 5, $posX, $posY, $size, $angle);
}
public function drawHexagon(int $posX, int $posY, int $size, $angle = 0, array $colors = []) : bool
{
return Polygon::draw($this->image(), $colors ? : $this->colors, 6, $posX, $posY, $size, $angle);
}
public function drawHeptagon(int $posX, int $posY, int $size, $angle = 0, array $colors = []) : bool
{
return Polygon::draw($this->image(), $colors ? : $this->colors, 7, $posX, $posY, $size, $angle);
}
public function drawOctagon(int $posX, int $posY, int $size, $angle = 0, array $colors = []) : bool
{
return Polygon::draw($this->image(), $colors ? : $this->colors, 8, $posX, $posY, $size, $angle);
}
public function drawNonagon(int $posX, int $posY, int $size, $angle = 0, array $colors = []) : bool
{
return Polygon::draw($this->image(), $colors ? : $this->colors, 9, $posX, $posY, $size, $angle);
}
public function drawDecagon(int $posX, int $posY, int $size, $angle = 0, array $colors = []) : bool
{
return Polygon::draw($this->image(), $colors ? : $this->colors, 10, $posX, $posY, $size, $angle);
}
}

84
src/Colors.php Normal file
View File

@ -0,0 +1,84 @@
<?php
namespace Imagine;
class Colors extends \ArrayObject {
use arrayobject;
protected $image;
public static function make($image = null) {
return new static($image);
}
public function __construct($image) {
parent::__construct();
$this->image = $image;
}
public static function convertHexToRGB($hex) {
return [
'r' => (int) base_convert(substr($hex, 0, 2), 16, 10),
'g' => (int) base_convert(substr($hex, 2, 2), 16, 10),
'b' => (int) base_convert(substr($hex, 4, 2), 16, 10),
];
}
function compare($c1, $c2, $tolerance = 35) {
$c1 = is_array($c1) ? $c1 : [
"r" => hexdec(substr($c1, 0, 2)),
"g" => hexdec(substr($c1, 2, 2)),
"b" => hexdec(substr($c1, 4, 2))
];
$c2 = is_array($c2) ? $c2 : [
"r" => hexdec(substr($c2, 0, 2)),
"g" => hexdec(substr($c2, 2, 2)),
"b" => hexdec(substr($c2, 4, 2))
];
return ($c1['r'] >= $c2['r'] - $tolerance && $c1['r'] <= $c2['r'] + $tolerance) &&
($c1['g'] >= $c2['g'] - $tolerance && $c1['g'] <= $c2['g'] + $tolerance) &&
($c1['b'] >= $c2['b'] - $tolerance && $c1['b'] <= $c2['b'] + $tolerance);
}
/* *
* @param mixed $color :
array = [ int r, int g, int b, int a ],
string = "hex:alpha" ( ex: "1bd4a9:94" )
*
*/
public static function allocate(&$img, $color = null) {
if ( $color !== null ) {
# If we've received an Hex color , we must convert it into rgb(a).
if ( is_string($color) ) {
$hex = explode(':', $color);
$color = self::convertHexToRGB($hex[0]);
$color['a'] = isset($hex[1]) ? (float)$hex[1] : null;
}
$colors['a'] = isset($colors['a']) ? $colors['a'] : null;
return $color['a'] !== null ? \imagecolorallocatealpha($img, $color['r'], $color['g'], $color['b'], (1 - $color['a']) * 127) : \imagecolorallocate($img, $color['r'], $color['g'], $color['b']);
}
return null;
}
public function offsetSet($offset, $value) {
if ( is_null($offset) ) {
$this->_container[] = self::allocate($this->image, $value);
} else {
if (is_string($value)) {
$this->_container[$offset] = self::allocate($this->image, $value);
}
else {
$this->_container[$offset] = $value;
}
}
}
}

32
src/Draw.php Normal file
View File

@ -0,0 +1,32 @@
<?php
namespace Imagine;
class Draw {
// http://php.net/imageline
public static function line($image, $x1, $y1, $x2, $y2, $colors, $thickness = 1) {
if ( $thickness == 1 ) {
return \imageline($image, $x1, $y1, $x2, $y2, $colors['fore'] );
}
$t = $thickness / 2 - 0.5;
if ($x1 == $x2 || $y1 == $y2) {
return \imagefilledrectangle($image, round(min($x1, $x2) - $t), round(min($y1, $y2) - $t), round(max($x1, $x2) + $t), round(max($y1, $y2) + $t), $colors['fore']);
}
$k = ($y2 - $y1) / ($x2 - $x1); //y = kx + q
$a = $t / sqrt(1 + pow($k, 2));
$points = [
round($x1 - (1+$k)*$a), round($y1 + (1-$k)*$a),
round($x1 - (1-$k)*$a), round($y1 - (1+$k)*$a),
round($x2 + (1+$k)*$a), round($y2 - (1-$k)*$a),
round($x2 + (1-$k)*$a), round($y2 + (1+$k)*$a)
];
\imagefilledpolygon($image, $points, 4, $color);
return \imagepolygon($image, $points, 4, $color);
}
}

202
src/Image.php Normal file
View File

@ -0,0 +1,202 @@
<?php
namespace Imagine;
class Image extends Canvas {
const DEFAULT_QUALITY = 80;
protected $filename = "";
protected $type = "image/jpeg";
public function __construct(/* resource|string */ $image = null)
{
if ( is_string( $image ) ) {
$this->filename = $image;
$this->fromFile($image);
}
elseif ( is_resource($image) ) {
$this->image = $image;
}
else {
parent::__construct();
}
}
public function type($set = null) {
return $set === null ? $this->type : $this->type = $set;
}
public function fromFile($filename) {
switch ( \exif_imagetype($filename) ) {
case 1 :
$this->forceType('image/gif')->image(\imagecreatefromgif($filename));
break;
case 2 :
$this->forceType('image/jpeg')->image($this->loadJpeg($filename));
break;
case 3 :
$this->forceType('image/png')->image(\imagecreatefrompng($filename));
break;
case 6 :
$this->forceType('image/bmp')->image(\imagecreatefrombmp($filename));
break;
case 18:
$this->forceType('image/webp')->image(\imagecreatefromwebp($filename));
break;
}
$this->width = \imagesx($this->image);
$this->height = \imagesy($this->image);
return $this;
}
public function fromString($content) {
$this->image( \imagecreatefromstring($content) );
$info = \getimagesizefromstring($content);
$this->width = $info[0];
$this->height = $info[1];
$this->forceType($info['mime']);
return $this;
}
public function forceType(string $type) {
$this->type = $type;
return $this;
}
public function loadJpeg(string $filename) {
$img = \imagecreatefromjpeg($filename);
$exif = @\exif_read_data($filename);
if ( $img && !empty($exif['Orientation']) ) {
switch($exif['Orientation']){
case 6:
case 5:
$img = \imagerotate($img, 270, null);
break;
case 3:
case 4:
$img = \imagerotate($img, 180, null);
break;
case 7:
case 8:
$img = \imagerotate($img, 90, null);
break;
/*
case 4:
case 5:
case 7:
\imageflip($img, \IMG_FLIP_HORIZONTAL);
break;
*/
}
}
return $img;
}
public function save(int $quality = null, $filters = null) : bool
{
return $this->render($this->filename, $quality, $filters);
}
public function render(string $path = null, int $quality = null, $filters = null) # : bool
{
$layers = $this->layers();
if ($path === null) {
$path = fopen("php://memory", "w+");
}
usort($layers, function($e1, $e2) {
return $e1->order() <=> $e2->order();
});
foreach($layers as $item) {
$this->merge( $item->image() );
}
switch( $this->type ) {
case "image/gif":
$retval = \imagegif($this->image(), $path);
break;
case "image/webp":
$retval = \imagewebp($this->image(), $path, $quality ?: static::DEFAULT_QUALITY);
break;
case "image/png":
\imagealphablending($this->image, true);
\imagesavealpha($this->image, true);
$retval = \imagepng($this->image(), $path, $quality === null ? round( static::DEFAULT_QUALITY / 10, 0) : $this->normalizeQuality($quality), $filters);
break;
default:
case "image/jpeg":
case "image/jpg":
$retval = \imagejpeg($this->image(), $path, $quality ?: static::DEFAULT_QUALITY);
break;
}
if ( is_resource($path) ) {
rewind($path);
$retval = stream_get_contents($path);
}
return $retval ?? null;
}
public function readExif() : array
{
return \exif_read_data($this->filename, 0, true);
}
public function remove_exif($old, $new) {
$f1 = fopen($old, 'rb');
$f2 = fopen($new, 'wb');
// Find EXIF marker
while ( $s = fread($f1, 2) ) {
$word = unpack('ni', $s)['i'];
if ($word == 0xFFE1) {
// Read length (includes the word used for the length)
$s = fread($f1, 2);
$len = unpack('ni', $s)['i'];
// Skip the EXIF info
fread($f1, $len - 2);
break;
} else {
fwrite($f2, $s, 2);
}
}
// Write the rest of the file
while ( $s = fread($f1, 4096) ) {
fwrite($f2, $s, strlen($s));
}
fclose($f1);
fclose($f2);
}
protected function normalizeQuality($quality) {
switch($this->type()) {
case "image/png":
return round($quality / 100, 0);
default:
return $quality;
}
}
}

42
src/Layer.php Normal file
View File

@ -0,0 +1,42 @@
<?php
namespace Imagine;
class Layer extends Canvas {
public string $name;
public int $order;
public int $position;
public function moveUp() {
$this->order = ($this->order-- === 0) ? 0 : $this->order;
return $this;
}
public function moveDown() {
$this->order++;
return $this;
}
/* Setting current layer on top, based on every other layers */
public function onTop() {
$max = 0;
foreach ($this->parent->layers() as $value) {
$max = max($max, $value->order());
}
$this->order = $max + 1;
return $this;
}
public function order($set = null) {
return $set ? ($this->order = $set) : $this->order;
}
}

77
src/Merge.php Normal file
View File

@ -0,0 +1,77 @@
<?php
namespace Imagine;
class Merge {
public static function simple(resource &$destImg, resource $srcImg, int $destPosX = 0, int $destPosY = 0, int $srcPosX = 0, int $srcPosY = 0) : bool
{
return \imagecopy($destImg, $srcImg, $destPosX, $destPosY, $srcPosX, $srcPosY, \imageSX($srcImg), \imageSY($srcImg));
}
public static function alpha(resource &$destImg, resource &$srcImg, int $destX, itn $destY, int $srcX, int $srcY, int $srcW, int $srcH, int $percentage = 0) : bool
{
$destW = \imagesx($destImg);
$destH = \imagesy($destImg);
for ($y = 0; $y < $srcH + $srcY; $y++) {
for ($x = 0; $x < $srcW + $srcX; $x++) {
if ($x + $destX >= 0 && $x + $destX < $destW && $x + $srcX >= 0 && $x + $srcX < $srcW && $y + $destY >= 0 && $y + $destY < $destH && $y + $srcY >= 0 && $y + $srcY < $srcH) {
$destPixel = \imagecolorsforindex($destImg, \imagecolorat($destImg, $x + $destX, $y + $destY));
$srcImgColorat = \imagecolorat($srcImg, $x + $srcX, $y + $srcY);
if ($srcImgColorat >= 0) {
$srcPixel = \imagecolorsforindex($srcImg, $srcImgColorat);
$srcAlpha = 1 - ($srcPixel['alpha'] / 127);
$destAlpha = 1 - ($destPixel['alpha'] / 127);
$opacity = $srcAlpha * $pct / 100;
if ($destAlpha >= $opacity) {
$alpha = $destAlpha;
}
if ($destAlpha < $opacity) {
$alpha = $opacity;
}
if ($alpha > 1) {
$alpha = 1;
}
if ($opacity > 0) {
$destRed = round((($destPixel['red'] * $destAlpha * (1 - $opacity))));
$destGreen = round((($destPixel['green'] * $destAlpha * (1 - $opacity))));
$destBlue = round((($destPixel['blue'] * $destAlpha * (1 - $opacity))));
$srcRed = round((($srcPixel['red'] * $opacity)));
$srcGreen = round((($srcPixel['green'] * $opacity)));
$srcBlue = round((($srcPixel['blue'] * $opacity)));
$red = round(($destRed + $srcRed ) / ($destAlpha * (1 - $opacity) + $opacity));
$green = round(($destGreen + $srcGreen) / ($destAlpha * (1 - $opacity) + $opacity));
$blue = round(($destBlue + $srcBlue ) / ($destAlpha * (1 - $opacity) + $opacity));
if ($red > 255) {
$red = 255;
}
if ($green > 255) {
$green = 255;
}
if ($blue > 255) {
$blue = 255;
}
$alpha = round((1 - $alpha) * 127);
$color = \imagecolorallocatealpha($destImg, $red, $green, $blue, $alpha);
\imagesetpixel($destImg, $x + $destX, $y + $destY, $color);
}
}
}
}
}
return true;
}
}

113
src/Polygon.php Normal file
View File

@ -0,0 +1,113 @@
<?php
namespace Imagine;
class Polygon {
static $mode = "rad";
const sqrt_2 = 1.41421356237;
public static function draw(resource $image, $colors, $vertexcount, int $x, int $y, $size, $angle = 0) : array
{
$coord = self::polygonCoord($vertexcount, $x, $y, $size, $angle);
$data = array_values($coord);
if ( $colors['brush'] ) {
\imagefilledpolygon($image, $data, count($data) / 2, $colors['brush']);
}
return [
"return" => \imagepolygon($image, $data, count($data) / 2, $colors['fore']),
"points" => $data,
"coord" => $coord
];
}
public static function polygonCoord($vertexcount, $x, $y, $size, $angle = 0) : array
{
$n = 0;
$r = $size / 2;
$pi2 = M_PI * 2;
$points = [];
while ( $n < $vertexcount ) {
$points["x$n"] = $r * cos($pi2 * $n / $vertexcount + $angle) + $x;
$points["y$n"] = $r * sin($pi2 * $n / $vertexcount + $angle) + $y;
$n++;
}
return $points;
}
public static function rotatePoint($theta, int $x, int $y, int $px, int $py) : array
{
$cos = cos($theta);
$sin = sin($theta);
return [
'x' => $cos * ($x - $px) - $sin * ($y - $py) + $px,
'y' => $sin * ($x - $px) + $cos * ($y - $py) + $py
];
}
public function dist(int $x1, int $y1, int $x2, int $y2) : float
{
return sqrt( ($x1 - $x2) * ($x1 - $x2) + ($y1 - $y2) * ($y1 - $y2) );
}
/*
** Calculate the angle between 2 points, where Xc,Yc is the center of a circle
** and x,y is a point on its circumference. All angles are relative to
** the 3 O'Clock position. Result returned in radians
*/
public function angle($xc, $yc, $x1, $y1) : float
{
# calculate distance between two points
$d = $this->distBetween($xc, $yc, $x1, $y1);
if ($d != 0)
if ( asin( ($y1-$yc)/$d ) >= 0 )
$a1 = acos( ($x1-$xc)/$d );
else
$a1 = 2 * pi() - acos( ($x1-$xc)/$d );
else
$a1 = 0;
return $a1;
}
public static function drawRectangle(resource $image, int $x1, int $y1, int $x2, int $y2, array $colors) : bool
{
if ( $colors['brush'] ) {
\imagefilledrectangle($image, $x1, $y1, $x2, $y2, $colors['brush']);
}
return \imagerectangle ( $image , $x1 , $y1 , $x2 , $y2 , $colors['fore'] );
}
public static function drawIrregular(resource $image, array $colors, array $points) : array
{
$data = array_values($points);
if ( $colors['brush'] ) {
\imagefilledpolygon($image, $data, count($data) / 2, $colors['brush']);
}
return [
"return" => \imagepolygon($image, $data, count($data) / 2, $colors['fore']),
"points" => $data
];
}
public static function drawEllipse(resource $image, array $colors, int $posX, int $posY, int $width, int $height) : bool
{
if ( $colors['brush'] ) {
\imagefilledellipse($image, $posX, $posY, $width, $height, $colors['brush']);
}
return \imageellipse($image, $posX, $posY, $width, $height, $colors['fore']);
}
}

20
src/Text.php Normal file
View File

@ -0,0 +1,20 @@
<?php
namespace Imagine;
class Text {
public static function draw($image, $colors, $fontid, $text, $x, $y)
{
return \imagestring($image, $fontid, $x, $y, $text, $colors['text']);
}
public static function measure($text, $fontid)
{
return [
"width" => \imagefontwidth($fontid) * strlen(utf8_decode($text)),
"height" => \imagefontheight($fontid)
];
}
}

189
src/arrayobject.php Normal file
View File

@ -0,0 +1,189 @@
<?php
namespace Imagine;
trait arrayobject {
protected $pointer = null;
protected $container = [];
protected $changed = [];
protected $selected = false;
public function count() {
return count( $this->container() );
}
public function contains($term, $strict = false) {
return (array_search($term, $this->container(), $strict) !== false) ;
}
public function &arrayobjectCurrent() {
if ( !is_null($this->pointer) ) {
$var = &$this->container()[$this->pointer] ?: [];
$var || ( $var = [] );
return $var;
}
if ( $this->selected !== false ){
$ret = &$this->selected ?: [];
return $ret;
}
# Restoring integrity of container since it could be nullified
is_array($this->container()) || $this->container([]);
return $this->container();
}
public function offsetSet($offset, $value, $changed = null) {
if ( $changed && (!isset($this->arrayobjectCurrent()[$offset]) || ($this->arrayobjectCurrent()[$offset] !== $value) ) ) {
$this->changed($offset, true);
}
return is_null($offset) ? $this->arrayobject_current()[] = $value : $this->arrayobject_current()[$offset] = $value;
}
public function arrayobjectSetPointer($pointer) {
# $pointer could nullify obj pointer
if ( $this->pointer = $pointer ) {
# Creating dataset whenever we have a new one
if ( !isset($this->container()[$this->pointer]) ) {
$this->container()[$this->pointer] = [];
$this->changed[$this->pointer] = [];
}
}
return $this;
}
public function arrayobjectSelect($selection, $purge = true) {
if ( is_bool($selection) ) {
return $this->selected = $selection;
}
$purge && ( $this->selected = [] );
foreach($selection as $pointer) {
$this->selected[$pointer] = &$this->container[$pointer];
}
return true;
}
public function arrayobjectExist($pointer) {
return isset( $this->container()[$pointer] );
}
public function arrayobjectFlushChanged() {
! is_null($this->pointer) ?
$this->changed[$this->pointer] = []
:
$this->changed = []
;
}
public function changed($offset = null, $set = null) {
if ($offset) {
if ($set !== null) {
! is_null($this->pointer) ?
( $this->changed[$this->pointer][$offset] = $set )
:
( $this->changed[$offset] = $set );
}
return !is_null($this->pointer) ? $this->changed[$this->pointer][$offset] : $this->changed[$offset];
}
return array_keys( !is_null($this->pointer)
? $this->changed[$this->pointer] ?? []
: $this->changed) ?? [];
}
public function arrayobjectRemove($pointer) {
if ( isset($this->container()[$pointer]) ) {
unset( $this->container()[$pointer], $this->changed[$pointer]);
}
}
public function arrayobjectIterate($callback) {
if ( $callback && is_callable($callback) ) {
$pointer = $this->pointer;
foreach($this->container() as $key => $value) {
$this->arrayobjectSetPointer($key);
$callback($key, $this);
}
$this->arrayobjectSetPointer($pointer);
}
return $this;
}
public function offsetGet($offset) {
if ( !is_null($this->pointer) ) {
return isset($this->container()[$this->pointer][$offset]) ? $this->container()[$this->pointer][$offset] : null;
}
else {
return isset($this->container()[$offset]) ? $this->container()[$offset] : null;
}
}
public function offsetExists($offset) {
return array_key_exists($offset, $this->arrayobjectCurrent() );
}
public function offsetUnset($offset) {
if ( !is_null($this->pointer)) {
unset($this->container()[$this->pointer][$offset]);
}
else {
unset($this->container()[$offset]) ;
}
}
public function sort($field, $order = 'ASC') {
# Arrayobj::order_by($this->container(), $field);
# $order === 'DESC' && array_reverse($this->arrayobject_current());
}
public function rewind() {
reset( $this->container() );
# Rewinding will also reset the pointer
$this->arrayobjectSetPointer(key($this->container()));
return $this;
}
public function current() {
return $this->arrayobjectSetPointer( $this->key() );
}
public function key() {
$var = key( $this->container() );
return $var;
}
public function next() {
$var = next( $this->container() );
return $var;
}
public function valid() {
$key = $this->key();
return ( $key !== NULL ) && ( $key !== FALSE );
}
protected function &container($set = null) {
if ( $set !== null ) {
$this->container = $set;
}
if ( $this->selected !== false ) {
return $this->selected;
}
return $this->container;
}
}