- First commit of an old reworked project
This commit is contained in:
commit
a3e62c5720
|
@ -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/>.
|
|
@ -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/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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']);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue