Version Description
- 2016-07-09 =
- Fix autoloader not finding namespaced classes.
- Updated Grafika from source.
Download this release
Release Info
Developer | kosinix |
Plugin | Cyclone Slider |
Version | 2.12.1 |
Comparing to | |
See all releases |
Code changes from version 2.12.0 to 2.12.1
- README.txt +7 -2
- css/admin.css +1 -1
- cyclone-slider.php +1 -1
- src/CycloneSlider/Data.php +3 -1
- src/CycloneSlider/Grafika/Gd/DrawingObject/Polygon.php +10 -10
- src/CycloneSlider/Grafika/Gd/Editor.php +294 -220
- src/CycloneSlider/Grafika/Imagick/DrawingObject/Polygon.php +13 -9
- src/CycloneSlider/Grafika/Imagick/DrawingObject/Rectangle.php +17 -12
- src/CycloneSlider/Grafika/Imagick/Editor.php +280 -194
- src/CycloneSlider/ImageResizer.php +3 -4
- src/autoloader.php +5 -2
- views/slider-advanced-settings.php +29 -9
README.txt
CHANGED
@@ -46,7 +46,8 @@ Cyclone Slider Pro offers even more features:
|
|
46 |
* Delay. Delay start of slideshow
|
47 |
* Easing. Some cool transition effects.
|
48 |
* Swipe. Swipe gesture support for touch devices.
|
49 |
-
*
|
|
|
50 |
* And two additional templates: Text and Galleria
|
51 |
|
52 |
|
@@ -105,7 +106,7 @@ Most probably its wordpress adding paragpraphs on line breaks next to the slides
|
|
105 |
`remove_filter('the_content', 'wpautop');`
|
106 |
|
107 |
= Where do I add my own templates? =
|
108 |
-
|
109 |
|
110 |
== Screenshots ==
|
111 |
|
@@ -117,6 +118,10 @@ Inside `wp-content` create a folder named "cycloneslider". Add your templates in
|
|
117 |
|
118 |
== Changelog ==
|
119 |
|
|
|
|
|
|
|
|
|
120 |
= 2.12.0 - 2016-07-06 =
|
121 |
* Now uses [Grafika](http://kosinix.github.io/grafika/) for image editing.
|
122 |
* Added link in slide preview image that opens in new tab when clicked.
|
46 |
* Delay. Delay start of slideshow
|
47 |
* Easing. Some cool transition effects.
|
48 |
* Swipe. Swipe gesture support for touch devices.
|
49 |
+
* 6 resize options: Fit, Fill, Crop, Exact, Exact Width, Exact Height
|
50 |
+
* Ability to change the image quality: Low, Medium, High, Very High, Max
|
51 |
* And two additional templates: Text and Galleria
|
52 |
|
53 |
|
106 |
`remove_filter('the_content', 'wpautop');`
|
107 |
|
108 |
= Where do I add my own templates? =
|
109 |
+
See: [http://docs.codefleet.net/cyclone-slider-2/creating-your-own-template/](http://docs.codefleet.net/cyclone-slider-2/creating-your-own-template/)
|
110 |
|
111 |
== Screenshots ==
|
112 |
|
118 |
|
119 |
== Changelog ==
|
120 |
|
121 |
+
= 2.12.1 - 2016-07-09 =
|
122 |
+
* Fix autoloader not finding namespaced classes.
|
123 |
+
* Updated Grafika from source.
|
124 |
+
|
125 |
= 2.12.0 - 2016-07-06 =
|
126 |
* Now uses [Grafika](http://kosinix.github.io/grafika/) for image editing.
|
127 |
* Added link in slide preview image that opens in new tab when clicked.
|
css/admin.css
CHANGED
@@ -690,7 +690,7 @@ label[for="force_resize"]{
|
|
690 |
width: 100%;
|
691 |
height: 100%;
|
692 |
background: #F8F8F8;
|
693 |
-
opacity: 0.
|
694 |
z-index: 99;
|
695 |
}
|
696 |
.cycloneslider-cover p{
|
690 |
width: 100%;
|
691 |
height: 100%;
|
692 |
background: #F8F8F8;
|
693 |
+
opacity: 0.7;
|
694 |
z-index: 99;
|
695 |
}
|
696 |
.cycloneslider-cover p{
|
cyclone-slider.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
Plugin Name: Cyclone Slider 2
|
4 |
Plugin URI: http://www.codefleet.net/cyclone-slider-2/
|
5 |
Description: Create and manage sliders with ease. Built for both casual users and developers.
|
6 |
-
Version: 2.12.
|
7 |
Author: Nico Amarilla
|
8 |
Author URI: http://www.codefleet.net/
|
9 |
License: GPLv3
|
3 |
Plugin Name: Cyclone Slider 2
|
4 |
Plugin URI: http://www.codefleet.net/cyclone-slider-2/
|
5 |
Description: Create and manage sliders with ease. Built for both casual users and developers.
|
6 |
+
Version: 2.12.1
|
7 |
Author: Nico Amarilla
|
8 |
Author URI: http://www.codefleet.net/
|
9 |
License: GPLv3
|
src/CycloneSlider/Data.php
CHANGED
@@ -151,6 +151,7 @@ class CycloneSlider_Data {
|
|
151 |
// Pro options
|
152 |
$settings_to_save['easing'] = '';
|
153 |
$settings_to_save['resize_option'] = 'fit';
|
|
|
154 |
$settings_to_save['allow_wrap'] = 'true';
|
155 |
$settings_to_save['dynamic_height'] = 'off';
|
156 |
$settings_to_save['dynamic_height_speed'] = 250;
|
@@ -743,7 +744,8 @@ class CycloneSlider_Data {
|
|
743 |
'random' => 0,
|
744 |
'resize' => 1,
|
745 |
'width_management' => 'responsive',
|
746 |
-
'resize_option' => '
|
|
|
747 |
'easing' => '',
|
748 |
'allow_wrap' => 'true',
|
749 |
'dynamic_height' => 'off',
|
151 |
// Pro options
|
152 |
$settings_to_save['easing'] = '';
|
153 |
$settings_to_save['resize_option'] = 'fit';
|
154 |
+
$settings_to_save['resize_quality'] = 80;
|
155 |
$settings_to_save['allow_wrap'] = 'true';
|
156 |
$settings_to_save['dynamic_height'] = 'off';
|
157 |
$settings_to_save['dynamic_height_speed'] = 250;
|
744 |
'random' => 0,
|
745 |
'resize' => 1,
|
746 |
'width_management' => 'responsive',
|
747 |
+
'resize_option' => 'fit',
|
748 |
+
'resize_quality' => 80,
|
749 |
'easing' => '',
|
750 |
'allow_wrap' => 'true',
|
751 |
'dynamic_height' => 'off',
|
src/CycloneSlider/Grafika/Gd/DrawingObject/Polygon.php
CHANGED
@@ -17,14 +17,9 @@ class Polygon extends Base implements DrawingObjectInterface
|
|
17 |
if(function_exists('imageantialias')){
|
18 |
imageantialias($image->getCore(), true);
|
19 |
}
|
20 |
-
list($r, $g, $b, $alpha) = $this->getBorderColor()->getRgba();
|
21 |
-
$borderColorResource = imagecolorallocatealpha(
|
22 |
-
$image->getCore(), $r, $g, $b,
|
23 |
-
Editor::gdAlpha($alpha)
|
24 |
-
);
|
25 |
|
26 |
$points = $this->points();
|
27 |
-
$count = count($this->
|
28 |
|
29 |
|
30 |
// Create filled polygon
|
@@ -41,7 +36,12 @@ class Polygon extends Base implements DrawingObjectInterface
|
|
41 |
}
|
42 |
|
43 |
// Create polygon borders. It will be placed on top of the filled polygon (if present)
|
44 |
-
if ( 0 < $this->getBorderSize() ) { // With border > 0
|
|
|
|
|
|
|
|
|
|
|
45 |
imagepolygon($image->getCore(), $points,
|
46 |
$count,
|
47 |
$borderColorResource
|
@@ -52,9 +52,9 @@ class Polygon extends Base implements DrawingObjectInterface
|
|
52 |
|
53 |
protected function points(){
|
54 |
$points = array();
|
55 |
-
foreach($this->
|
56 |
-
$points[] = $
|
57 |
-
$points[] = $
|
58 |
}
|
59 |
if( count($points) < 6 ){
|
60 |
throw new \Exception('Polygon needs at least 3 points.');
|
17 |
if(function_exists('imageantialias')){
|
18 |
imageantialias($image->getCore(), true);
|
19 |
}
|
|
|
|
|
|
|
|
|
|
|
20 |
|
21 |
$points = $this->points();
|
22 |
+
$count = count($this->points);
|
23 |
|
24 |
|
25 |
// Create filled polygon
|
36 |
}
|
37 |
|
38 |
// Create polygon borders. It will be placed on top of the filled polygon (if present)
|
39 |
+
if ( 0 < $this->getBorderSize() and null !== $this->borderColor) { // With border > 0 AND borderColor !== null
|
40 |
+
list($r, $g, $b, $alpha) = $this->getBorderColor()->getRgba();
|
41 |
+
$borderColorResource = imagecolorallocatealpha(
|
42 |
+
$image->getCore(), $r, $g, $b,
|
43 |
+
Editor::gdAlpha($alpha)
|
44 |
+
);
|
45 |
imagepolygon($image->getCore(), $points,
|
46 |
$count,
|
47 |
$borderColorResource
|
52 |
|
53 |
protected function points(){
|
54 |
$points = array();
|
55 |
+
foreach($this->points as $point){
|
56 |
+
$points[] = $point[0];
|
57 |
+
$points[] = $point[1];
|
58 |
}
|
59 |
if( count($points) < 6 ){
|
60 |
throw new \Exception('Polygon needs at least 3 points.');
|
src/CycloneSlider/Grafika/Gd/Editor.php
CHANGED
@@ -21,7 +21,8 @@ use CycloneSlider\Grafika\Color;
|
|
21 |
* GD Editor class. Uses the PHP GD library.
|
22 |
* @package Grafika\Gd
|
23 |
*/
|
24 |
-
final class Editor implements EditorInterface
|
|
|
25 |
|
26 |
/**
|
27 |
* @var Image Holds the image instance.
|
@@ -29,9 +30,10 @@ final class Editor implements EditorInterface {
|
|
29 |
private $image;
|
30 |
|
31 |
/**
|
32 |
-
* Constructor
|
33 |
*/
|
34 |
-
function __construct()
|
|
|
35 |
$this->image = null;
|
36 |
}
|
37 |
|
@@ -40,44 +42,54 @@ final class Editor implements EditorInterface {
|
|
40 |
*
|
41 |
* @return $this
|
42 |
*/
|
43 |
-
public function apply(
|
44 |
-
|
|
|
|
|
45 |
return $this;
|
46 |
}
|
47 |
|
48 |
/**
|
49 |
* Creates a cubic bezier. Cubic bezier has 2 control points.
|
|
|
50 |
* @param array $point1 Array of X and Y value for start point.
|
51 |
* @param array $control1 Array of X and Y value for control point 1.
|
52 |
* @param array $control2 Array of X and Y value for control point 2.
|
53 |
* @param array $point2 Array of X and Y value for end point.
|
54 |
* @param Color|string $color Color of the curve. Accepts hex string or a Color object. Defaults to black.
|
|
|
55 |
* @return Editor
|
56 |
*/
|
57 |
-
public function bezierCubic($point1, $control1, $control2, $point2, $color = '#000000')
|
58 |
-
|
|
|
59 |
$color = new Color($color);
|
60 |
}
|
61 |
$obj = new CubicBezier($point1, $control1, $control2, $point2, $color);
|
|
|
62 |
return $this->draw($obj);
|
63 |
}
|
64 |
|
65 |
/**
|
66 |
* Creates a quadratic bezier. Quadratic bezier has 1 control point.
|
|
|
67 |
* @param array $point1 Array of X and Y value for start point.
|
68 |
* @param array $control Array of X and Y value for control point.
|
69 |
* @param array $point2 Array of X and Y value for end point.
|
70 |
* @param Color|string $color Color of the curve. Accepts hex string or a Color object. Defaults to black.
|
|
|
71 |
* @return Editor
|
72 |
*/
|
73 |
-
public function bezierQuad($point1, $control, $point2, $color = '#000000')
|
74 |
-
|
|
|
75 |
$color = new Color($color);
|
76 |
}
|
77 |
$obj = new QuadraticBezier($point1, $control, $point2, $color);
|
|
|
78 |
return $this->draw($obj);
|
79 |
}
|
80 |
-
|
81 |
/**
|
82 |
* Create a blank image given width and height.
|
83 |
*
|
@@ -86,39 +98,44 @@ final class Editor implements EditorInterface {
|
|
86 |
*
|
87 |
* @return self
|
88 |
*/
|
89 |
-
public function blank(
|
90 |
-
|
|
|
91 |
|
92 |
return $this;
|
93 |
}
|
94 |
|
95 |
/**
|
96 |
* Compare two images and returns a hamming distance. A value of 0 indicates a likely similar picture. A value between 1 and 10 is potentially a variation. A value greater than 10 is likely a different image.
|
|
|
97 |
* @param ImageInterface|string $image1
|
98 |
* @param ImageInterface|string $image2
|
|
|
99 |
* @return int Hamming distance. Note: This breaks the chain if you are doing fluent api calls as it does not return an Editor.
|
100 |
* @throws \Exception
|
101 |
*/
|
102 |
-
public function compare(
|
|
|
103 |
|
104 |
-
if (
|
105 |
-
$image1 = Image::createFromFile(
|
106 |
}
|
107 |
|
108 |
-
if (
|
109 |
-
$image2 = Image::createFromFile(
|
110 |
}
|
111 |
|
112 |
-
$bin1
|
113 |
-
$bin2
|
114 |
-
$str1
|
115 |
-
$str2
|
116 |
$distance = 0;
|
117 |
-
foreach($str1 as $i
|
118 |
-
if($char !== $str2[$i]){
|
119 |
$distance++;
|
120 |
}
|
121 |
}
|
|
|
122 |
return $distance;
|
123 |
|
124 |
}
|
@@ -133,11 +150,12 @@ final class Editor implements EditorInterface {
|
|
133 |
*
|
134 |
* @return self
|
135 |
*/
|
136 |
-
public function crop($cropWidth, $cropHeight, $cropX='center', $cropY='center')
|
|
|
137 |
|
138 |
-
if(is_string($cropX)){
|
139 |
// Compute position from string
|
140 |
-
switch ($cropX){
|
141 |
case 'left':
|
142 |
$x = 0;
|
143 |
break;
|
@@ -148,15 +166,15 @@ final class Editor implements EditorInterface {
|
|
148 |
|
149 |
case 'center':
|
150 |
default:
|
151 |
-
$x = (int)
|
152 |
break;
|
153 |
}
|
154 |
} else {
|
155 |
$x = $cropX;
|
156 |
}
|
157 |
|
158 |
-
if(is_string($cropY)){
|
159 |
-
switch ($cropY){
|
160 |
case 'top':
|
161 |
$y = 0;
|
162 |
break;
|
@@ -167,7 +185,7 @@ final class Editor implements EditorInterface {
|
|
167 |
|
168 |
case 'center':
|
169 |
default:
|
170 |
-
$y = (int)
|
171 |
break;
|
172 |
}
|
173 |
} else {
|
@@ -192,7 +210,7 @@ final class Editor implements EditorInterface {
|
|
192 |
);
|
193 |
|
194 |
// Free memory of old resource
|
195 |
-
imagedestroy(
|
196 |
|
197 |
// Cropped image instance
|
198 |
$this->image = new Image($newImageResource, $this->image->getImageFile(), $cropWidth, $cropHeight, $this->image->getType());
|
@@ -204,18 +222,22 @@ final class Editor implements EditorInterface {
|
|
204 |
* Dither image using Floyd-Steinberg algorithm. Dithering will reduce the color to black and white and add noise.
|
205 |
* @return EditorInterface An instance of image editor.
|
206 |
*/
|
207 |
-
public function dither()
|
|
|
208 |
$e = new Dither();
|
|
|
209 |
return $this->apply($e);
|
210 |
}
|
211 |
-
|
212 |
/**
|
213 |
* @param DrawingObjectInterface $drawingObject
|
214 |
*
|
215 |
* @return $this
|
216 |
*/
|
217 |
-
public function draw(
|
218 |
-
|
|
|
|
|
219 |
return $this;
|
220 |
}
|
221 |
|
@@ -231,17 +253,25 @@ final class Editor implements EditorInterface {
|
|
231 |
*
|
232 |
* @return EditorInterface An instance of image editor.
|
233 |
*/
|
234 |
-
public function ellipse(
|
235 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
236 |
$borderColor = new Color($borderColor);
|
237 |
}
|
238 |
-
if(is_string($fillColor)){
|
239 |
$fillColor = new Color($fillColor);
|
240 |
}
|
241 |
$obj = new Ellipse($width, $height, $pos, $borderSize, $borderColor, $fillColor);
|
|
|
242 |
return $this->draw($obj);
|
243 |
}
|
244 |
-
|
245 |
/**
|
246 |
* Compare if two images are equal. It will compare if the two images are of the same width and height. If the dimensions differ, it will return false. If the dimensions are equal, it will loop through each pixels. If one of the pixel don't match, it will return false. The pixels are compared using their RGB (Red, Green, Blue) values.
|
247 |
*
|
@@ -251,37 +281,39 @@ final class Editor implements EditorInterface {
|
|
251 |
* @return bool True if equals false if not. Note: This breaks the chain if you are doing fluent api calls as it does not return an Editor.
|
252 |
* @throws \Exception
|
253 |
*/
|
254 |
-
public function equal(
|
|
|
255 |
|
256 |
-
if (
|
257 |
-
$image1 = Image::createFromFile(
|
258 |
}
|
259 |
|
260 |
-
if (
|
261 |
-
$image2 = Image::createFromFile(
|
262 |
}
|
263 |
|
264 |
// Check if image dimensions are equal
|
265 |
-
if($image1->getWidth() !== $image2->getWidth() or $image1->getHeight() !== $image2->getHeight()) {
|
|
|
266 |
return false;
|
267 |
|
268 |
} else {
|
269 |
|
270 |
// Loop using image1
|
271 |
-
for (
|
272 |
-
for (
|
273 |
|
274 |
// Get image1 pixel
|
275 |
-
$rgb1 = imagecolorat(
|
276 |
-
$r1
|
277 |
-
$g1
|
278 |
-
$b1
|
279 |
|
280 |
// Get image2 pixel
|
281 |
-
$rgb2 = imagecolorat(
|
282 |
-
$r2
|
283 |
-
$g2
|
284 |
-
$b2
|
285 |
|
286 |
// Compare pixel value
|
287 |
if (
|
@@ -294,20 +326,8 @@ final class Editor implements EditorInterface {
|
|
294 |
}
|
295 |
}
|
296 |
}
|
297 |
-
return true;
|
298 |
-
}
|
299 |
|
300 |
-
|
301 |
-
* Free the current image clearing resources associated with it.
|
302 |
-
*/
|
303 |
-
public function free(){
|
304 |
-
if ( null !== $this->image ) {
|
305 |
-
if( null !== $this->image->getCore() ) {
|
306 |
-
imagedestroy( $this->image->getCore() );
|
307 |
-
}
|
308 |
-
} else {
|
309 |
-
$this->image = null;
|
310 |
-
}
|
311 |
}
|
312 |
|
313 |
/**
|
@@ -319,28 +339,45 @@ final class Editor implements EditorInterface {
|
|
319 |
*
|
320 |
* @return self
|
321 |
*/
|
322 |
-
public function fill(
|
|
|
323 |
|
324 |
$this->_imageCheck();
|
325 |
|
326 |
-
list(
|
327 |
|
328 |
-
$colorResource = imagecolorallocatealpha(
|
329 |
-
$this->gdAlpha(
|
330 |
-
imagefill(
|
331 |
|
332 |
return $this;
|
333 |
}
|
334 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
335 |
/**
|
336 |
* Converts image to grayscale.
|
337 |
*
|
338 |
* @return $this
|
339 |
*/
|
340 |
-
public function grayscale()
|
|
|
341 |
$this->_imageCheck();
|
342 |
|
343 |
-
imagefilter(
|
344 |
|
345 |
return $this;
|
346 |
}
|
@@ -350,7 +387,8 @@ final class Editor implements EditorInterface {
|
|
350 |
*
|
351 |
* @return $this
|
352 |
*/
|
353 |
-
public function greyscale()
|
|
|
354 |
return $this->grayscale();
|
355 |
}
|
356 |
|
@@ -359,22 +397,24 @@ final class Editor implements EditorInterface {
|
|
359 |
*
|
360 |
* @return Image
|
361 |
*/
|
362 |
-
public function getImage()
|
|
|
363 |
return $this->image;
|
364 |
}
|
365 |
|
366 |
/**
|
367 |
-
* Checks the
|
368 |
*
|
369 |
* @return bool True if available false if not.
|
370 |
*/
|
371 |
-
public function isAvailable()
|
372 |
-
|
|
|
373 |
return false;
|
374 |
}
|
375 |
|
376 |
// On some setups GD library does not provide imagerotate()
|
377 |
-
if ( ! function_exists(
|
378 |
|
379 |
return false;
|
380 |
}
|
@@ -389,16 +429,19 @@ final class Editor implements EditorInterface {
|
|
389 |
* @param array $point2 Array containing int X and int Y position of the starting point.
|
390 |
* @param int $thickness Thickness in pixel. Note: This is currently ignored in GD editor and falls back to 1.
|
391 |
* @param Color|string $color Color of the line. Defaults to black.
|
|
|
392 |
* @return Editor
|
393 |
*/
|
394 |
-
public function line(array $point1, array $point2, $thickness = 1, $color = '#000000')
|
395 |
-
|
|
|
396 |
$color = new Color($color);
|
397 |
}
|
398 |
$obj = new Line($point1, $point2, $thickness, $color);
|
|
|
399 |
return $this->draw($obj);
|
400 |
}
|
401 |
-
|
402 |
/**
|
403 |
* Sets the image to the specified opacity level where 1.0 is fully opaque and 0.0 is fully transparent.
|
404 |
* Warning: This function loops thru each pixel manually which can be slow. Use sparingly.
|
@@ -408,7 +451,8 @@ final class Editor implements EditorInterface {
|
|
408 |
* @return self
|
409 |
* @throws \Exception
|
410 |
*/
|
411 |
-
public function opacity(
|
|
|
412 |
|
413 |
$this->_imageCheck();
|
414 |
|
@@ -416,13 +460,13 @@ final class Editor implements EditorInterface {
|
|
416 |
$opacity = ($opacity > 1) ? 1 : $opacity;
|
417 |
$opacity = ($opacity < 0) ? 0 : $opacity;
|
418 |
|
419 |
-
for($y = 0; $y < $this->image->getHeight(); $y++){
|
420 |
-
for($x = 0; $x < $this->image->getWidth(); $x++){
|
421 |
-
$rgb
|
422 |
$alpha = ($rgb >> 24) & 0x7F; // 127 in hex. These are binary operations.
|
423 |
-
$r
|
424 |
-
$g
|
425 |
-
$b
|
426 |
|
427 |
// Reverse alpha values from 127-0 (transparent to opaque) to 0-127 for easy math
|
428 |
// Previously: 0 = opaque, 127 = transparent.
|
@@ -430,8 +474,9 @@ final class Editor implements EditorInterface {
|
|
430 |
$reverse = 127 - $alpha;
|
431 |
$reverse = round($reverse * $opacity);
|
432 |
|
433 |
-
if(
|
434 |
-
imagesetpixel(
|
|
|
435 |
}
|
436 |
}
|
437 |
}
|
@@ -447,13 +492,14 @@ final class Editor implements EditorInterface {
|
|
447 |
* @return Editor
|
448 |
* @throws \Exception
|
449 |
*/
|
450 |
-
public function open(
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
|
|
455 |
} else {
|
456 |
-
throw new \Exception(
|
457 |
}
|
458 |
|
459 |
return $this;
|
@@ -466,7 +512,8 @@ final class Editor implements EditorInterface {
|
|
466 |
*
|
467 |
* @return $this
|
468 |
*/
|
469 |
-
public function openImage(
|
|
|
470 |
$this->image = $image;
|
471 |
|
472 |
return $this;
|
@@ -480,8 +527,9 @@ final class Editor implements EditorInterface {
|
|
480 |
* @return $this
|
481 |
* @throws \Exception
|
482 |
*/
|
483 |
-
public function openFile(
|
484 |
-
|
|
|
485 |
|
486 |
return $this;
|
487 |
}
|
@@ -498,51 +546,50 @@ final class Editor implements EditorInterface {
|
|
498 |
* @return Editor
|
499 |
* @throws \Exception
|
500 |
*/
|
501 |
-
public function overlay(
|
|
|
502 |
|
503 |
$this->_imageCheck();
|
504 |
|
505 |
-
if (
|
506 |
-
$overlay = Image::createFromFile(
|
507 |
}
|
508 |
|
509 |
// Resize overlay
|
510 |
-
if($width and $height){
|
511 |
|
512 |
-
$overlayWidth
|
513 |
$overlayHeight = $overlay->getHeight();
|
514 |
|
515 |
-
if(is_numeric($width)){
|
516 |
-
$overlayWidth = (int)
|
517 |
} else {
|
518 |
-
$percent
|
519 |
-
if(
|
520 |
-
$overlayWidth = intval(
|
521 |
}
|
522 |
}
|
523 |
|
524 |
-
if(is_numeric($height)){
|
525 |
-
$overlayHeight = (int)
|
526 |
} else {
|
527 |
-
$percent
|
528 |
-
if(
|
529 |
-
$overlayHeight = intval(
|
530 |
}
|
531 |
}
|
532 |
|
533 |
$editor = new Editor();
|
534 |
$editor->setImage($overlay);
|
535 |
-
$editor->resizeFit(
|
536 |
$overlay = $editor->getImage();
|
537 |
-
|
538 |
-
//$overlay->setImageResource( $editor->getImage()->getImageResource() );
|
539 |
}
|
540 |
|
541 |
//$x = $y = 0;
|
542 |
|
543 |
-
if (
|
544 |
// Compute position from string
|
545 |
-
switch (
|
546 |
case 'left':
|
547 |
$x = 0;
|
548 |
break;
|
@@ -553,15 +600,15 @@ final class Editor implements EditorInterface {
|
|
553 |
|
554 |
case 'center':
|
555 |
default:
|
556 |
-
$x = (int)
|
557 |
break;
|
558 |
}
|
559 |
} else {
|
560 |
$x = $xPos;
|
561 |
}
|
562 |
|
563 |
-
if (
|
564 |
-
switch (
|
565 |
case 'top':
|
566 |
$y = 0;
|
567 |
break;
|
@@ -572,7 +619,7 @@ final class Editor implements EditorInterface {
|
|
572 |
|
573 |
case 'center':
|
574 |
default:
|
575 |
-
$y = (int)
|
576 |
break;
|
577 |
}
|
578 |
} else {
|
@@ -582,8 +629,8 @@ final class Editor implements EditorInterface {
|
|
582 |
imagecopyresampled(
|
583 |
$this->image->getCore(), // Base image
|
584 |
$overlay->getCore(), // Overlay
|
585 |
-
(int)
|
586 |
-
(int)
|
587 |
0,
|
588 |
0,
|
589 |
$overlay->getWidth(), // Overlay final width
|
@@ -606,35 +653,47 @@ final class Editor implements EditorInterface {
|
|
606 |
*
|
607 |
* @return EditorInterface An instance of image editor.
|
608 |
*/
|
609 |
-
public function polygon($points, $borderSize = 1, $borderColor = '#000000', $fillColor = '#FFFFFF')
|
610 |
-
|
|
|
611 |
$borderColor = new Color($borderColor);
|
612 |
}
|
613 |
-
if(is_string($fillColor)){
|
614 |
$fillColor = new Color($fillColor);
|
615 |
}
|
616 |
$obj = new Polygon($points, $borderSize, $borderColor, $fillColor);
|
|
|
617 |
return $this->draw($obj);
|
618 |
}
|
619 |
|
620 |
/**
|
621 |
* Creates a rectangle.
|
|
|
622 |
* @param int $width Width of rectangle in pixels.
|
623 |
* @param int $height Height in pixels.
|
624 |
* @param array $pos Array of X and Y position. X is the distance in pixels from the left of the canvass to the left of the rectangle. Y is the distance from the top of the canvass to the top of the rectangle. Defaults to array(0,0).
|
625 |
* @param int $borderSize Size of the border in pixels. Defaults to 1 pixel. Set to 0 for no border.
|
626 |
* @param Color|string|null $borderColor Border color. Defaults to black. Set to null for no color.
|
627 |
* @param Color|string|null $fillColor Fill color. Defaults to white. Set to null for no color.
|
|
|
628 |
* @return Editor
|
629 |
*/
|
630 |
-
public function rectangle(
|
631 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
632 |
$borderColor = new Color($borderColor);
|
633 |
}
|
634 |
-
if(is_string($fillColor)){
|
635 |
$fillColor = new Color($fillColor);
|
636 |
}
|
637 |
$obj = new Rectangle($width, $height, $pos, $borderSize, $borderColor, $fillColor);
|
|
|
638 |
return $this->draw($obj);
|
639 |
}
|
640 |
|
@@ -649,31 +708,32 @@ final class Editor implements EditorInterface {
|
|
649 |
* @return Editor
|
650 |
* @throws \Exception
|
651 |
*/
|
652 |
-
public function resize(
|
|
|
653 |
/*
|
654 |
* Resize formula:
|
655 |
* ratio = w / h
|
656 |
* h = w / ratio
|
657 |
* w = h * ratio
|
658 |
*/
|
659 |
-
switch ($mode){
|
660 |
case 'exact':
|
661 |
-
$this->resizeExact(
|
662 |
break;
|
663 |
case 'fill':
|
664 |
$this->resizeFill($newWidth, $newHeight);
|
665 |
break;
|
666 |
case 'exactWidth':
|
667 |
-
$this->resizeExactWidth(
|
668 |
break;
|
669 |
case 'exactHeight':
|
670 |
-
$this->resizeExactHeight(
|
671 |
break;
|
672 |
case 'fit':
|
673 |
$this->resizeFit($newWidth, $newHeight);
|
674 |
break;
|
675 |
default:
|
676 |
-
throw new \Exception(
|
677 |
}
|
678 |
|
679 |
return $this;
|
@@ -687,9 +747,10 @@ final class Editor implements EditorInterface {
|
|
687 |
*
|
688 |
* @return self
|
689 |
*/
|
690 |
-
public function resizeExact(
|
|
|
691 |
|
692 |
-
$this->_resize(
|
693 |
|
694 |
return $this;
|
695 |
}
|
@@ -701,16 +762,17 @@ final class Editor implements EditorInterface {
|
|
701 |
*
|
702 |
* @return self
|
703 |
*/
|
704 |
-
public function resizeExactHeight(
|
|
|
705 |
|
706 |
-
$width
|
707 |
$height = $this->image->getHeight();
|
708 |
-
$ratio
|
709 |
|
710 |
$resizeHeight = $newHeight;
|
711 |
-
$resizeWidth
|
712 |
|
713 |
-
$this->_resize(
|
714 |
|
715 |
return $this;
|
716 |
}
|
@@ -722,16 +784,17 @@ final class Editor implements EditorInterface {
|
|
722 |
*
|
723 |
* @return self
|
724 |
*/
|
725 |
-
public function resizeExactWidth(
|
|
|
726 |
|
727 |
-
$width
|
728 |
$height = $this->image->getHeight();
|
729 |
-
$ratio
|
730 |
|
731 |
-
$resizeWidth
|
732 |
$resizeHeight = round($newWidth / $ratio);
|
733 |
|
734 |
-
$this->_resize(
|
735 |
|
736 |
return $this;
|
737 |
}
|
@@ -744,23 +807,24 @@ final class Editor implements EditorInterface {
|
|
744 |
*
|
745 |
* @return self
|
746 |
*/
|
747 |
-
public function resizeFill(
|
748 |
-
|
|
|
749 |
$height = $this->image->getHeight();
|
750 |
-
$ratio
|
751 |
|
752 |
// Base optimum size on new width
|
753 |
-
$optimumWidth
|
754 |
$optimumHeight = round($newWidth / $ratio);
|
755 |
|
756 |
-
if
|
757 |
// So base optimum size on height instead
|
758 |
-
$optimumWidth
|
759 |
$optimumHeight = $newHeight;
|
760 |
}
|
761 |
|
762 |
-
$this->_resize(
|
763 |
-
$this->crop(
|
764 |
|
765 |
return $this;
|
766 |
}
|
@@ -773,23 +837,24 @@ final class Editor implements EditorInterface {
|
|
773 |
*
|
774 |
* @return self
|
775 |
*/
|
776 |
-
public function resizeFit(
|
|
|
777 |
|
778 |
-
$width
|
779 |
$height = $this->image->getHeight();
|
780 |
-
$ratio
|
781 |
|
782 |
// Try basing it on width first
|
783 |
-
$resizeWidth
|
784 |
$resizeHeight = round($newWidth / $ratio);
|
785 |
|
786 |
-
if
|
787 |
// So base on height instead
|
788 |
$resizeHeight = $newHeight;
|
789 |
-
$resizeWidth
|
790 |
}
|
791 |
|
792 |
-
$this->_resize(
|
793 |
|
794 |
return $this;
|
795 |
}
|
@@ -802,14 +867,16 @@ final class Editor implements EditorInterface {
|
|
802 |
*
|
803 |
* @return EditorInterface An instance of image editor.
|
804 |
*/
|
805 |
-
public function rotate(
|
|
|
806 |
|
807 |
$this->_imageCheck();
|
808 |
|
809 |
-
$color
|
810 |
-
list(
|
811 |
|
812 |
-
imagerotate($this->image->getCore(), $angle,
|
|
|
813 |
|
814 |
return $this;
|
815 |
}
|
@@ -826,44 +893,43 @@ final class Editor implements EditorInterface {
|
|
826 |
* @return Editor
|
827 |
* @throws \Exception
|
828 |
*/
|
829 |
-
public function save(
|
|
|
830 |
|
831 |
$this->_imageCheck();
|
832 |
|
833 |
-
if (
|
834 |
|
835 |
-
$type = $this->_getImageTypeFromFileName(
|
836 |
-
if (
|
837 |
$type = $this->image->getType(); // 0 result, use original image type
|
838 |
}
|
839 |
}
|
840 |
|
841 |
-
$targetDir = dirname(
|
842 |
-
if(
|
843 |
// Create and set default perms to 0755
|
844 |
-
if( !mkdir(
|
845 |
-
throw new \Exception(
|
846 |
}
|
847 |
}
|
848 |
|
849 |
-
switch (
|
850 |
case ImageType::GIF :
|
851 |
-
imagegif(
|
852 |
break;
|
853 |
|
854 |
case ImageType::PNG :
|
855 |
-
|
856 |
-
$
|
857 |
-
$quality = ( $quality < 0 ) ? 0 : $quality;
|
858 |
-
imagepng( $this->image->getCore(), $file, $quality );
|
859 |
break;
|
860 |
|
861 |
default: // Defaults to jpeg
|
862 |
-
$quality = (
|
863 |
-
$quality = (
|
864 |
-
$quality = (
|
865 |
-
imageinterlace(
|
866 |
-
imagejpeg(
|
867 |
}
|
868 |
|
869 |
return $this;
|
@@ -874,7 +940,8 @@ final class Editor implements EditorInterface {
|
|
874 |
*
|
875 |
* @param Image $image
|
876 |
*/
|
877 |
-
public function setImage(
|
|
|
878 |
$this->image = $image;
|
879 |
}
|
880 |
|
@@ -892,21 +959,22 @@ final class Editor implements EditorInterface {
|
|
892 |
* @return EditorInterface
|
893 |
* @throws \Exception
|
894 |
*/
|
895 |
-
public function text(
|
|
|
896 |
|
897 |
$this->_imageCheck();
|
898 |
|
899 |
$y += $size;
|
900 |
|
901 |
-
$color
|
902 |
-
$font
|
903 |
|
904 |
-
list(
|
905 |
|
906 |
$colorResource = imagecolorallocatealpha(
|
907 |
$this->image->getCore(),
|
908 |
$r, $g, $b,
|
909 |
-
$this->gdAlpha(
|
910 |
);
|
911 |
|
912 |
imagettftext(
|
@@ -933,17 +1001,18 @@ final class Editor implements EditorInterface {
|
|
933 |
*
|
934 |
* http://www.hackerfactor.com/blog/index.php?/archives/529-Kind-of-Like-That.html
|
935 |
* @param Image $image
|
|
|
936 |
* @return string
|
937 |
*/
|
938 |
private function _differenceHash($image)
|
939 |
{
|
940 |
|
941 |
-
$width
|
942 |
$height = 8;
|
943 |
|
944 |
$editor = new Editor();
|
945 |
$editor->setImage($image);
|
946 |
-
$editor->resizeExact(
|
947 |
$gd = $editor->getImage()->getCore();
|
948 |
|
949 |
// Build hash
|
@@ -951,17 +1020,17 @@ final class Editor implements EditorInterface {
|
|
951 |
for ($y = 0; $y < $height; $y++) {
|
952 |
// Get the pixel value for the leftmost pixel.
|
953 |
$rgba = imagecolorat($gd, 0, $y);
|
954 |
-
$r
|
955 |
-
$g
|
956 |
-
$b
|
957 |
|
958 |
$left = floor(($r + $g + $b) / 3);
|
959 |
for ($x = 1; $x < $width; $x++) {
|
960 |
// Get the pixel value for each pixel starting from position 1.
|
961 |
-
$rgba
|
962 |
-
$r
|
963 |
-
$g
|
964 |
-
$b
|
965 |
$right = floor(($r + $g + $b) / 3);
|
966 |
// Each hash bit is set based on whether the left pixel is brighter than the right pixel.
|
967 |
if ($left > $right) {
|
@@ -1028,16 +1097,17 @@ final class Editor implements EditorInterface {
|
|
1028 |
*
|
1029 |
* @throws \Exception
|
1030 |
*/
|
1031 |
-
private function _resize(
|
|
|
1032 |
|
1033 |
$this->_imageCheck();
|
1034 |
|
1035 |
// Create blank image
|
1036 |
-
$newImage = Image::createBlank(
|
1037 |
|
1038 |
-
if(
|
1039 |
// Preserve PNG transparency
|
1040 |
-
$newImage->fullAlphaMode(
|
1041 |
}
|
1042 |
|
1043 |
imagecopyresampled(
|
@@ -1054,7 +1124,7 @@ final class Editor implements EditorInterface {
|
|
1054 |
);
|
1055 |
|
1056 |
// Free memory of old resource
|
1057 |
-
imagedestroy(
|
1058 |
|
1059 |
// Resize image instance
|
1060 |
$this->image = new Image(
|
@@ -1074,9 +1144,10 @@ final class Editor implements EditorInterface {
|
|
1074 |
*
|
1075 |
* @return int
|
1076 |
*/
|
1077 |
-
public static function gdAlpha(
|
|
|
1078 |
|
1079 |
-
$scale = round(
|
1080 |
|
1081 |
return $invert = 127 - $scale;
|
1082 |
}
|
@@ -1088,14 +1159,15 @@ final class Editor implements EditorInterface {
|
|
1088 |
*
|
1089 |
* @return ImageType string Type of image.
|
1090 |
*/
|
1091 |
-
private function _getImageTypeFromFileName(
|
1092 |
-
|
|
|
1093 |
|
1094 |
-
if (
|
1095 |
return ImageType::JPEG;
|
1096 |
-
} else if (
|
1097 |
return ImageType::GIF;
|
1098 |
-
} else if (
|
1099 |
return ImageType::PNG;
|
1100 |
} else {
|
1101 |
return ImageType::UNKNOWN;
|
@@ -1107,9 +1179,11 @@ final class Editor implements EditorInterface {
|
|
1107 |
*
|
1108 |
* @throws \Exception
|
1109 |
*/
|
1110 |
-
private function _imageCheck()
|
1111 |
-
|
1112 |
-
|
|
|
1113 |
}
|
1114 |
}
|
|
|
1115 |
}
|
21 |
* GD Editor class. Uses the PHP GD library.
|
22 |
* @package Grafika\Gd
|
23 |
*/
|
24 |
+
final class Editor implements EditorInterface
|
25 |
+
{
|
26 |
|
27 |
/**
|
28 |
* @var Image Holds the image instance.
|
30 |
private $image;
|
31 |
|
32 |
/**
|
33 |
+
* Constructor.
|
34 |
*/
|
35 |
+
function __construct()
|
36 |
+
{
|
37 |
$this->image = null;
|
38 |
}
|
39 |
|
42 |
*
|
43 |
* @return $this
|
44 |
*/
|
45 |
+
public function apply($effect)
|
46 |
+
{
|
47 |
+
$this->image = $effect->apply($this->image);
|
48 |
+
|
49 |
return $this;
|
50 |
}
|
51 |
|
52 |
/**
|
53 |
* Creates a cubic bezier. Cubic bezier has 2 control points.
|
54 |
+
*
|
55 |
* @param array $point1 Array of X and Y value for start point.
|
56 |
* @param array $control1 Array of X and Y value for control point 1.
|
57 |
* @param array $control2 Array of X and Y value for control point 2.
|
58 |
* @param array $point2 Array of X and Y value for end point.
|
59 |
* @param Color|string $color Color of the curve. Accepts hex string or a Color object. Defaults to black.
|
60 |
+
*
|
61 |
* @return Editor
|
62 |
*/
|
63 |
+
public function bezierCubic($point1, $control1, $control2, $point2, $color = '#000000')
|
64 |
+
{
|
65 |
+
if (is_string($color)) {
|
66 |
$color = new Color($color);
|
67 |
}
|
68 |
$obj = new CubicBezier($point1, $control1, $control2, $point2, $color);
|
69 |
+
|
70 |
return $this->draw($obj);
|
71 |
}
|
72 |
|
73 |
/**
|
74 |
* Creates a quadratic bezier. Quadratic bezier has 1 control point.
|
75 |
+
*
|
76 |
* @param array $point1 Array of X and Y value for start point.
|
77 |
* @param array $control Array of X and Y value for control point.
|
78 |
* @param array $point2 Array of X and Y value for end point.
|
79 |
* @param Color|string $color Color of the curve. Accepts hex string or a Color object. Defaults to black.
|
80 |
+
*
|
81 |
* @return Editor
|
82 |
*/
|
83 |
+
public function bezierQuad($point1, $control, $point2, $color = '#000000')
|
84 |
+
{
|
85 |
+
if (is_string($color)) {
|
86 |
$color = new Color($color);
|
87 |
}
|
88 |
$obj = new QuadraticBezier($point1, $control, $point2, $color);
|
89 |
+
|
90 |
return $this->draw($obj);
|
91 |
}
|
92 |
+
|
93 |
/**
|
94 |
* Create a blank image given width and height.
|
95 |
*
|
98 |
*
|
99 |
* @return self
|
100 |
*/
|
101 |
+
public function blank($width, $height)
|
102 |
+
{
|
103 |
+
$this->image = Image::createBlank($width, $height);
|
104 |
|
105 |
return $this;
|
106 |
}
|
107 |
|
108 |
/**
|
109 |
* Compare two images and returns a hamming distance. A value of 0 indicates a likely similar picture. A value between 1 and 10 is potentially a variation. A value greater than 10 is likely a different image.
|
110 |
+
*
|
111 |
* @param ImageInterface|string $image1
|
112 |
* @param ImageInterface|string $image2
|
113 |
+
*
|
114 |
* @return int Hamming distance. Note: This breaks the chain if you are doing fluent api calls as it does not return an Editor.
|
115 |
* @throws \Exception
|
116 |
*/
|
117 |
+
public function compare($image1, $image2)
|
118 |
+
{
|
119 |
|
120 |
+
if (is_string($image1)) { // If string passed, turn it into a Image object
|
121 |
+
$image1 = Image::createFromFile($image1);
|
122 |
}
|
123 |
|
124 |
+
if (is_string($image2)) { // If string passed, turn it into a Image object
|
125 |
+
$image2 = Image::createFromFile($image2);
|
126 |
}
|
127 |
|
128 |
+
$bin1 = $this->_differenceHash($image1);
|
129 |
+
$bin2 = $this->_differenceHash($image2);
|
130 |
+
$str1 = str_split($bin1);
|
131 |
+
$str2 = str_split($bin2);
|
132 |
$distance = 0;
|
133 |
+
foreach ($str1 as $i => $char) {
|
134 |
+
if ($char !== $str2[$i]) {
|
135 |
$distance++;
|
136 |
}
|
137 |
}
|
138 |
+
|
139 |
return $distance;
|
140 |
|
141 |
}
|
150 |
*
|
151 |
* @return self
|
152 |
*/
|
153 |
+
public function crop($cropWidth, $cropHeight, $cropX = 'center', $cropY = 'center')
|
154 |
+
{
|
155 |
|
156 |
+
if (is_string($cropX)) {
|
157 |
// Compute position from string
|
158 |
+
switch ($cropX) {
|
159 |
case 'left':
|
160 |
$x = 0;
|
161 |
break;
|
166 |
|
167 |
case 'center':
|
168 |
default:
|
169 |
+
$x = (int)round(($this->image->getWidth() / 2) - ($cropWidth / 2));
|
170 |
break;
|
171 |
}
|
172 |
} else {
|
173 |
$x = $cropX;
|
174 |
}
|
175 |
|
176 |
+
if (is_string($cropY)) {
|
177 |
+
switch ($cropY) {
|
178 |
case 'top':
|
179 |
$y = 0;
|
180 |
break;
|
185 |
|
186 |
case 'center':
|
187 |
default:
|
188 |
+
$y = (int)round(($this->image->getHeight() / 2) - ($cropHeight / 2));
|
189 |
break;
|
190 |
}
|
191 |
} else {
|
210 |
);
|
211 |
|
212 |
// Free memory of old resource
|
213 |
+
imagedestroy($this->image->getCore());
|
214 |
|
215 |
// Cropped image instance
|
216 |
$this->image = new Image($newImageResource, $this->image->getImageFile(), $cropWidth, $cropHeight, $this->image->getType());
|
222 |
* Dither image using Floyd-Steinberg algorithm. Dithering will reduce the color to black and white and add noise.
|
223 |
* @return EditorInterface An instance of image editor.
|
224 |
*/
|
225 |
+
public function dither()
|
226 |
+
{
|
227 |
$e = new Dither();
|
228 |
+
|
229 |
return $this->apply($e);
|
230 |
}
|
231 |
+
|
232 |
/**
|
233 |
* @param DrawingObjectInterface $drawingObject
|
234 |
*
|
235 |
* @return $this
|
236 |
*/
|
237 |
+
public function draw($drawingObject)
|
238 |
+
{
|
239 |
+
$this->image = $drawingObject->draw($this->image);
|
240 |
+
|
241 |
return $this;
|
242 |
}
|
243 |
|
253 |
*
|
254 |
* @return EditorInterface An instance of image editor.
|
255 |
*/
|
256 |
+
public function ellipse(
|
257 |
+
$width,
|
258 |
+
$height,
|
259 |
+
array $pos,
|
260 |
+
$borderSize = 1,
|
261 |
+
$borderColor = '#000000',
|
262 |
+
$fillColor = '#FFFFFF'
|
263 |
+
) {
|
264 |
+
if (is_string($borderColor)) {
|
265 |
$borderColor = new Color($borderColor);
|
266 |
}
|
267 |
+
if (is_string($fillColor)) {
|
268 |
$fillColor = new Color($fillColor);
|
269 |
}
|
270 |
$obj = new Ellipse($width, $height, $pos, $borderSize, $borderColor, $fillColor);
|
271 |
+
|
272 |
return $this->draw($obj);
|
273 |
}
|
274 |
+
|
275 |
/**
|
276 |
* Compare if two images are equal. It will compare if the two images are of the same width and height. If the dimensions differ, it will return false. If the dimensions are equal, it will loop through each pixels. If one of the pixel don't match, it will return false. The pixels are compared using their RGB (Red, Green, Blue) values.
|
277 |
*
|
281 |
* @return bool True if equals false if not. Note: This breaks the chain if you are doing fluent api calls as it does not return an Editor.
|
282 |
* @throws \Exception
|
283 |
*/
|
284 |
+
public function equal($image1, $image2)
|
285 |
+
{
|
286 |
|
287 |
+
if (is_string($image1)) { // If string passed, turn it into a Image object
|
288 |
+
$image1 = Image::createFromFile($image1);
|
289 |
}
|
290 |
|
291 |
+
if (is_string($image2)) { // If string passed, turn it into a Image object
|
292 |
+
$image2 = Image::createFromFile($image2);
|
293 |
}
|
294 |
|
295 |
// Check if image dimensions are equal
|
296 |
+
if ($image1->getWidth() !== $image2->getWidth() or $image1->getHeight() !== $image2->getHeight()) {
|
297 |
+
|
298 |
return false;
|
299 |
|
300 |
} else {
|
301 |
|
302 |
// Loop using image1
|
303 |
+
for ($y = 0; $y < $image1->getHeight(); $y++) {
|
304 |
+
for ($x = 0; $x < $image1->getWidth(); $x++) {
|
305 |
|
306 |
// Get image1 pixel
|
307 |
+
$rgb1 = imagecolorat($image1->getCore(), $x, $y);
|
308 |
+
$r1 = ($rgb1 >> 16) & 0xFF;
|
309 |
+
$g1 = ($rgb1 >> 8) & 0xFF;
|
310 |
+
$b1 = $rgb1 & 0xFF;
|
311 |
|
312 |
// Get image2 pixel
|
313 |
+
$rgb2 = imagecolorat($image2->getCore(), $x, $y);
|
314 |
+
$r2 = ($rgb2 >> 16) & 0xFF;
|
315 |
+
$g2 = ($rgb2 >> 8) & 0xFF;
|
316 |
+
$b2 = $rgb2 & 0xFF;
|
317 |
|
318 |
// Compare pixel value
|
319 |
if (
|
326 |
}
|
327 |
}
|
328 |
}
|
|
|
|
|
329 |
|
330 |
+
return true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
331 |
}
|
332 |
|
333 |
/**
|
339 |
*
|
340 |
* @return self
|
341 |
*/
|
342 |
+
public function fill($color, $x = 0, $y = 0)
|
343 |
+
{
|
344 |
|
345 |
$this->_imageCheck();
|
346 |
|
347 |
+
list($r, $g, $b, $alpha) = $color->getRgba();
|
348 |
|
349 |
+
$colorResource = imagecolorallocatealpha($this->image->getCore(), $r, $g, $b,
|
350 |
+
$this->gdAlpha($alpha));
|
351 |
+
imagefill($this->image->getCore(), $x, $y, $colorResource);
|
352 |
|
353 |
return $this;
|
354 |
}
|
355 |
|
356 |
+
/**
|
357 |
+
* Free the current image clearing resources associated with it.
|
358 |
+
*/
|
359 |
+
public function free()
|
360 |
+
{
|
361 |
+
if (null !== $this->image) {
|
362 |
+
if (null !== $this->image->getCore()) {
|
363 |
+
imagedestroy($this->image->getCore());
|
364 |
+
}
|
365 |
+
} else {
|
366 |
+
$this->image = null;
|
367 |
+
}
|
368 |
+
}
|
369 |
+
|
370 |
+
|
371 |
/**
|
372 |
* Converts image to grayscale.
|
373 |
*
|
374 |
* @return $this
|
375 |
*/
|
376 |
+
public function grayscale()
|
377 |
+
{
|
378 |
$this->_imageCheck();
|
379 |
|
380 |
+
imagefilter($this->image->getCore(), IMG_FILTER_GRAYSCALE);
|
381 |
|
382 |
return $this;
|
383 |
}
|
387 |
*
|
388 |
* @return $this
|
389 |
*/
|
390 |
+
public function greyscale()
|
391 |
+
{
|
392 |
return $this->grayscale();
|
393 |
}
|
394 |
|
397 |
*
|
398 |
* @return Image
|
399 |
*/
|
400 |
+
public function getImage()
|
401 |
+
{
|
402 |
return $this->image;
|
403 |
}
|
404 |
|
405 |
/**
|
406 |
+
* Checks if the editor is available on the current PHP install.
|
407 |
*
|
408 |
* @return bool True if available false if not.
|
409 |
*/
|
410 |
+
public function isAvailable()
|
411 |
+
{
|
412 |
+
if (false === extension_loaded('gd') || false === function_exists('gd_info')) {
|
413 |
return false;
|
414 |
}
|
415 |
|
416 |
// On some setups GD library does not provide imagerotate()
|
417 |
+
if ( ! function_exists('imagerotate')) {
|
418 |
|
419 |
return false;
|
420 |
}
|
429 |
* @param array $point2 Array containing int X and int Y position of the starting point.
|
430 |
* @param int $thickness Thickness in pixel. Note: This is currently ignored in GD editor and falls back to 1.
|
431 |
* @param Color|string $color Color of the line. Defaults to black.
|
432 |
+
*
|
433 |
* @return Editor
|
434 |
*/
|
435 |
+
public function line(array $point1, array $point2, $thickness = 1, $color = '#000000')
|
436 |
+
{
|
437 |
+
if (is_string($color)) {
|
438 |
$color = new Color($color);
|
439 |
}
|
440 |
$obj = new Line($point1, $point2, $thickness, $color);
|
441 |
+
|
442 |
return $this->draw($obj);
|
443 |
}
|
444 |
+
|
445 |
/**
|
446 |
* Sets the image to the specified opacity level where 1.0 is fully opaque and 0.0 is fully transparent.
|
447 |
* Warning: This function loops thru each pixel manually which can be slow. Use sparingly.
|
451 |
* @return self
|
452 |
* @throws \Exception
|
453 |
*/
|
454 |
+
public function opacity($opacity)
|
455 |
+
{
|
456 |
|
457 |
$this->_imageCheck();
|
458 |
|
460 |
$opacity = ($opacity > 1) ? 1 : $opacity;
|
461 |
$opacity = ($opacity < 0) ? 0 : $opacity;
|
462 |
|
463 |
+
for ($y = 0; $y < $this->image->getHeight(); $y++) {
|
464 |
+
for ($x = 0; $x < $this->image->getWidth(); $x++) {
|
465 |
+
$rgb = imagecolorat($this->image->getCore(), $x, $y);
|
466 |
$alpha = ($rgb >> 24) & 0x7F; // 127 in hex. These are binary operations.
|
467 |
+
$r = ($rgb >> 16) & 0xFF;
|
468 |
+
$g = ($rgb >> 8) & 0xFF;
|
469 |
+
$b = $rgb & 0xFF;
|
470 |
|
471 |
// Reverse alpha values from 127-0 (transparent to opaque) to 0-127 for easy math
|
472 |
// Previously: 0 = opaque, 127 = transparent.
|
474 |
$reverse = 127 - $alpha;
|
475 |
$reverse = round($reverse * $opacity);
|
476 |
|
477 |
+
if ($alpha < 127) { // Process non transparent pixels only
|
478 |
+
imagesetpixel($this->image->getCore(), $x, $y,
|
479 |
+
imagecolorallocatealpha($this->image->getCore(), $r, $g, $b, 127 - $reverse));
|
480 |
}
|
481 |
}
|
482 |
}
|
492 |
* @return Editor
|
493 |
* @throws \Exception
|
494 |
*/
|
495 |
+
public function open($target)
|
496 |
+
{
|
497 |
+
if ($target instanceof ImageInterface) {
|
498 |
+
$this->openImage($target);
|
499 |
+
} else if (is_string($target)) {
|
500 |
+
$this->openFile($target);
|
501 |
} else {
|
502 |
+
throw new \Exception('Could not open image.');
|
503 |
}
|
504 |
|
505 |
return $this;
|
512 |
*
|
513 |
* @return $this
|
514 |
*/
|
515 |
+
public function openImage($image)
|
516 |
+
{
|
517 |
$this->image = $image;
|
518 |
|
519 |
return $this;
|
527 |
* @return $this
|
528 |
* @throws \Exception
|
529 |
*/
|
530 |
+
public function openFile($file)
|
531 |
+
{
|
532 |
+
$this->image = Image::createFromFile($file);
|
533 |
|
534 |
return $this;
|
535 |
}
|
546 |
* @return Editor
|
547 |
* @throws \Exception
|
548 |
*/
|
549 |
+
public function overlay($overlay, $xPos = 'center', $yPos = 'center', $width = null, $height = null)
|
550 |
+
{
|
551 |
|
552 |
$this->_imageCheck();
|
553 |
|
554 |
+
if (is_string($overlay)) { // If string passed, turn it into a Image object
|
555 |
+
$overlay = Image::createFromFile($overlay);
|
556 |
}
|
557 |
|
558 |
// Resize overlay
|
559 |
+
if ($width and $height) {
|
560 |
|
561 |
+
$overlayWidth = $overlay->getWidth();
|
562 |
$overlayHeight = $overlay->getHeight();
|
563 |
|
564 |
+
if (is_numeric($width)) {
|
565 |
+
$overlayWidth = (int)$width;
|
566 |
} else {
|
567 |
+
$percent = strpos($width, '%');
|
568 |
+
if (false !== $percent) {
|
569 |
+
$overlayWidth = intval($width) / 100 * $this->image->getWidth();
|
570 |
}
|
571 |
}
|
572 |
|
573 |
+
if (is_numeric($height)) {
|
574 |
+
$overlayHeight = (int)$height;
|
575 |
} else {
|
576 |
+
$percent = strpos($height, '%');
|
577 |
+
if (false !== $percent) {
|
578 |
+
$overlayHeight = intval($height) / 100 * $this->image->getHeight();
|
579 |
}
|
580 |
}
|
581 |
|
582 |
$editor = new Editor();
|
583 |
$editor->setImage($overlay);
|
584 |
+
$editor->resizeFit($overlayWidth, $overlayHeight);
|
585 |
$overlay = $editor->getImage();
|
|
|
|
|
586 |
}
|
587 |
|
588 |
//$x = $y = 0;
|
589 |
|
590 |
+
if (is_string($xPos)) {
|
591 |
// Compute position from string
|
592 |
+
switch ($xPos) {
|
593 |
case 'left':
|
594 |
$x = 0;
|
595 |
break;
|
600 |
|
601 |
case 'center':
|
602 |
default:
|
603 |
+
$x = (int)round(($this->image->getWidth() / 2) - ($overlay->getWidth() / 2));
|
604 |
break;
|
605 |
}
|
606 |
} else {
|
607 |
$x = $xPos;
|
608 |
}
|
609 |
|
610 |
+
if (is_string($yPos)) {
|
611 |
+
switch ($yPos) {
|
612 |
case 'top':
|
613 |
$y = 0;
|
614 |
break;
|
619 |
|
620 |
case 'center':
|
621 |
default:
|
622 |
+
$y = (int)round(($this->image->getHeight() / 2) - ($overlay->getHeight() / 2));
|
623 |
break;
|
624 |
}
|
625 |
} else {
|
629 |
imagecopyresampled(
|
630 |
$this->image->getCore(), // Base image
|
631 |
$overlay->getCore(), // Overlay
|
632 |
+
(int)$x, // Overlay x position
|
633 |
+
(int)$y, // Overlay y position
|
634 |
0,
|
635 |
0,
|
636 |
$overlay->getWidth(), // Overlay final width
|
653 |
*
|
654 |
* @return EditorInterface An instance of image editor.
|
655 |
*/
|
656 |
+
public function polygon($points, $borderSize = 1, $borderColor = '#000000', $fillColor = '#FFFFFF')
|
657 |
+
{
|
658 |
+
if (is_string($borderColor)) {
|
659 |
$borderColor = new Color($borderColor);
|
660 |
}
|
661 |
+
if (is_string($fillColor)) {
|
662 |
$fillColor = new Color($fillColor);
|
663 |
}
|
664 |
$obj = new Polygon($points, $borderSize, $borderColor, $fillColor);
|
665 |
+
|
666 |
return $this->draw($obj);
|
667 |
}
|
668 |
|
669 |
/**
|
670 |
* Creates a rectangle.
|
671 |
+
*
|
672 |
* @param int $width Width of rectangle in pixels.
|
673 |
* @param int $height Height in pixels.
|
674 |
* @param array $pos Array of X and Y position. X is the distance in pixels from the left of the canvass to the left of the rectangle. Y is the distance from the top of the canvass to the top of the rectangle. Defaults to array(0,0).
|
675 |
* @param int $borderSize Size of the border in pixels. Defaults to 1 pixel. Set to 0 for no border.
|
676 |
* @param Color|string|null $borderColor Border color. Defaults to black. Set to null for no color.
|
677 |
* @param Color|string|null $fillColor Fill color. Defaults to white. Set to null for no color.
|
678 |
+
*
|
679 |
* @return Editor
|
680 |
*/
|
681 |
+
public function rectangle(
|
682 |
+
$width,
|
683 |
+
$height,
|
684 |
+
$pos = array(0, 0),
|
685 |
+
$borderSize = 1,
|
686 |
+
$borderColor = '#000000',
|
687 |
+
$fillColor = '#FFFFFF'
|
688 |
+
) {
|
689 |
+
if (is_string($borderColor)) {
|
690 |
$borderColor = new Color($borderColor);
|
691 |
}
|
692 |
+
if (is_string($fillColor)) {
|
693 |
$fillColor = new Color($fillColor);
|
694 |
}
|
695 |
$obj = new Rectangle($width, $height, $pos, $borderSize, $borderColor, $fillColor);
|
696 |
+
|
697 |
return $this->draw($obj);
|
698 |
}
|
699 |
|
708 |
* @return Editor
|
709 |
* @throws \Exception
|
710 |
*/
|
711 |
+
public function resize($newWidth, $newHeight, $mode = 'fit')
|
712 |
+
{
|
713 |
/*
|
714 |
* Resize formula:
|
715 |
* ratio = w / h
|
716 |
* h = w / ratio
|
717 |
* w = h * ratio
|
718 |
*/
|
719 |
+
switch ($mode) {
|
720 |
case 'exact':
|
721 |
+
$this->resizeExact($newWidth, $newHeight);
|
722 |
break;
|
723 |
case 'fill':
|
724 |
$this->resizeFill($newWidth, $newHeight);
|
725 |
break;
|
726 |
case 'exactWidth':
|
727 |
+
$this->resizeExactWidth($newWidth);
|
728 |
break;
|
729 |
case 'exactHeight':
|
730 |
+
$this->resizeExactHeight($newHeight);
|
731 |
break;
|
732 |
case 'fit':
|
733 |
$this->resizeFit($newWidth, $newHeight);
|
734 |
break;
|
735 |
default:
|
736 |
+
throw new \Exception(sprintf('Invalid resize mode "%s".', $mode));
|
737 |
}
|
738 |
|
739 |
return $this;
|
747 |
*
|
748 |
* @return self
|
749 |
*/
|
750 |
+
public function resizeExact($newWidth, $newHeight)
|
751 |
+
{
|
752 |
|
753 |
+
$this->_resize($newWidth, $newHeight);
|
754 |
|
755 |
return $this;
|
756 |
}
|
762 |
*
|
763 |
* @return self
|
764 |
*/
|
765 |
+
public function resizeExactHeight($newHeight)
|
766 |
+
{
|
767 |
|
768 |
+
$width = $this->image->getWidth();
|
769 |
$height = $this->image->getHeight();
|
770 |
+
$ratio = $width / $height;
|
771 |
|
772 |
$resizeHeight = $newHeight;
|
773 |
+
$resizeWidth = $newHeight * $ratio;
|
774 |
|
775 |
+
$this->_resize($resizeWidth, $resizeHeight);
|
776 |
|
777 |
return $this;
|
778 |
}
|
784 |
*
|
785 |
* @return self
|
786 |
*/
|
787 |
+
public function resizeExactWidth($newWidth)
|
788 |
+
{
|
789 |
|
790 |
+
$width = $this->image->getWidth();
|
791 |
$height = $this->image->getHeight();
|
792 |
+
$ratio = $width / $height;
|
793 |
|
794 |
+
$resizeWidth = $newWidth;
|
795 |
$resizeHeight = round($newWidth / $ratio);
|
796 |
|
797 |
+
$this->_resize($resizeWidth, $resizeHeight);
|
798 |
|
799 |
return $this;
|
800 |
}
|
807 |
*
|
808 |
* @return self
|
809 |
*/
|
810 |
+
public function resizeFill($newWidth, $newHeight)
|
811 |
+
{
|
812 |
+
$width = $this->image->getWidth();
|
813 |
$height = $this->image->getHeight();
|
814 |
+
$ratio = $width / $height;
|
815 |
|
816 |
// Base optimum size on new width
|
817 |
+
$optimumWidth = $newWidth;
|
818 |
$optimumHeight = round($newWidth / $ratio);
|
819 |
|
820 |
+
if (($optimumWidth < $newWidth) or ($optimumHeight < $newHeight)) { // Oops, where trying to fill and there are blank areas
|
821 |
// So base optimum size on height instead
|
822 |
+
$optimumWidth = $newHeight * $ratio;
|
823 |
$optimumHeight = $newHeight;
|
824 |
}
|
825 |
|
826 |
+
$this->_resize($optimumWidth, $optimumHeight);
|
827 |
+
$this->crop($newWidth, $newHeight); // Trim excess parts
|
828 |
|
829 |
return $this;
|
830 |
}
|
837 |
*
|
838 |
* @return self
|
839 |
*/
|
840 |
+
public function resizeFit($newWidth, $newHeight)
|
841 |
+
{
|
842 |
|
843 |
+
$width = $this->image->getWidth();
|
844 |
$height = $this->image->getHeight();
|
845 |
+
$ratio = $width / $height;
|
846 |
|
847 |
// Try basing it on width first
|
848 |
+
$resizeWidth = $newWidth;
|
849 |
$resizeHeight = round($newWidth / $ratio);
|
850 |
|
851 |
+
if (($resizeWidth > $newWidth) or ($resizeHeight > $newHeight)) { // Oops, either with or height does not fit
|
852 |
// So base on height instead
|
853 |
$resizeHeight = $newHeight;
|
854 |
+
$resizeWidth = $newHeight * $ratio;
|
855 |
}
|
856 |
|
857 |
+
$this->_resize($resizeWidth, $resizeHeight);
|
858 |
|
859 |
return $this;
|
860 |
}
|
867 |
*
|
868 |
* @return EditorInterface An instance of image editor.
|
869 |
*/
|
870 |
+
public function rotate($angle, $color = null)
|
871 |
+
{
|
872 |
|
873 |
$this->_imageCheck();
|
874 |
|
875 |
+
$color = ($color !== null) ? $color : new Color('#000000');
|
876 |
+
list($r, $g, $b, $alpha) = $color->getRgba();
|
877 |
|
878 |
+
imagerotate($this->image->getCore(), $angle,
|
879 |
+
imagecolorallocatealpha($this->image->getCore(), $r, $g, $b, $alpha));
|
880 |
|
881 |
return $this;
|
882 |
}
|
893 |
* @return Editor
|
894 |
* @throws \Exception
|
895 |
*/
|
896 |
+
public function save($file, $type = null, $quality = null, $interlace = false, $permission = 0755)
|
897 |
+
{
|
898 |
|
899 |
$this->_imageCheck();
|
900 |
|
901 |
+
if (null === $type) {
|
902 |
|
903 |
+
$type = $this->_getImageTypeFromFileName($file); // Null given, guess type from file extension
|
904 |
+
if (ImageType::UNKNOWN === $type) {
|
905 |
$type = $this->image->getType(); // 0 result, use original image type
|
906 |
}
|
907 |
}
|
908 |
|
909 |
+
$targetDir = dirname($file); // $file's directory
|
910 |
+
if (false === is_dir($targetDir)) { // Check if $file's directory exist
|
911 |
// Create and set default perms to 0755
|
912 |
+
if ( ! mkdir($targetDir, $permission, true)) {
|
913 |
+
throw new \Exception(sprintf('Cannot create %s', $targetDir));
|
914 |
}
|
915 |
}
|
916 |
|
917 |
+
switch (strtoupper($type)) {
|
918 |
case ImageType::GIF :
|
919 |
+
imagegif($this->image->getCore(), $file);
|
920 |
break;
|
921 |
|
922 |
case ImageType::PNG :
|
923 |
+
// PNG is lossless and does not need compression. Although GD allow values 0-9 (0 = no compression), we leave it alone.
|
924 |
+
imagepng($this->image->getCore(), $file);
|
|
|
|
|
925 |
break;
|
926 |
|
927 |
default: // Defaults to jpeg
|
928 |
+
$quality = ($quality === null) ? 75 : $quality; // Default to 75 (GDs default) if null.
|
929 |
+
$quality = ($quality > 100) ? 100 : $quality;
|
930 |
+
$quality = ($quality < 0) ? 0 : $quality;
|
931 |
+
imageinterlace($this->image->getCore(), $interlace);
|
932 |
+
imagejpeg($this->image->getCore(), $file, $quality);
|
933 |
}
|
934 |
|
935 |
return $this;
|
940 |
*
|
941 |
* @param Image $image
|
942 |
*/
|
943 |
+
public function setImage($image)
|
944 |
+
{
|
945 |
$this->image = $image;
|
946 |
}
|
947 |
|
959 |
* @return EditorInterface
|
960 |
* @throws \Exception
|
961 |
*/
|
962 |
+
public function text($text, $size = 12, $x = 0, $y = 0, $color = null, $font = '', $angle = 0)
|
963 |
+
{
|
964 |
|
965 |
$this->_imageCheck();
|
966 |
|
967 |
$y += $size;
|
968 |
|
969 |
+
$color = ($color !== null) ? $color : new Color('#000000');
|
970 |
+
$font = ($font !== '') ? $font : Grafika::fontsDir() . DIRECTORY_SEPARATOR . 'LiberationSans-Regular.ttf';
|
971 |
|
972 |
+
list($r, $g, $b, $alpha) = $color->getRgba();
|
973 |
|
974 |
$colorResource = imagecolorallocatealpha(
|
975 |
$this->image->getCore(),
|
976 |
$r, $g, $b,
|
977 |
+
$this->gdAlpha($alpha)
|
978 |
);
|
979 |
|
980 |
imagettftext(
|
1001 |
*
|
1002 |
* http://www.hackerfactor.com/blog/index.php?/archives/529-Kind-of-Like-That.html
|
1003 |
* @param Image $image
|
1004 |
+
*
|
1005 |
* @return string
|
1006 |
*/
|
1007 |
private function _differenceHash($image)
|
1008 |
{
|
1009 |
|
1010 |
+
$width = 9;
|
1011 |
$height = 8;
|
1012 |
|
1013 |
$editor = new Editor();
|
1014 |
$editor->setImage($image);
|
1015 |
+
$editor->resizeExact($width, $height); // Resize to exactly 9x8
|
1016 |
$gd = $editor->getImage()->getCore();
|
1017 |
|
1018 |
// Build hash
|
1020 |
for ($y = 0; $y < $height; $y++) {
|
1021 |
// Get the pixel value for the leftmost pixel.
|
1022 |
$rgba = imagecolorat($gd, 0, $y);
|
1023 |
+
$r = ($rgba >> 16) & 0xFF;
|
1024 |
+
$g = ($rgba >> 8) & 0xFF;
|
1025 |
+
$b = $rgba & 0xFF;
|
1026 |
|
1027 |
$left = floor(($r + $g + $b) / 3);
|
1028 |
for ($x = 1; $x < $width; $x++) {
|
1029 |
// Get the pixel value for each pixel starting from position 1.
|
1030 |
+
$rgba = imagecolorat($gd, $x, $y);
|
1031 |
+
$r = ($rgba >> 16) & 0xFF;
|
1032 |
+
$g = ($rgba >> 8) & 0xFF;
|
1033 |
+
$b = $rgba & 0xFF;
|
1034 |
$right = floor(($r + $g + $b) / 3);
|
1035 |
// Each hash bit is set based on whether the left pixel is brighter than the right pixel.
|
1036 |
if ($left > $right) {
|
1097 |
*
|
1098 |
* @throws \Exception
|
1099 |
*/
|
1100 |
+
private function _resize($newWidth, $newHeight, $targetX = 0, $targetY = 0, $srcX = 0, $srcY = 0)
|
1101 |
+
{
|
1102 |
|
1103 |
$this->_imageCheck();
|
1104 |
|
1105 |
// Create blank image
|
1106 |
+
$newImage = Image::createBlank($newWidth, $newHeight);
|
1107 |
|
1108 |
+
if (ImageType::PNG === $this->image->getType()) {
|
1109 |
// Preserve PNG transparency
|
1110 |
+
$newImage->fullAlphaMode(true);
|
1111 |
}
|
1112 |
|
1113 |
imagecopyresampled(
|
1124 |
);
|
1125 |
|
1126 |
// Free memory of old resource
|
1127 |
+
imagedestroy($this->image->getCore());
|
1128 |
|
1129 |
// Resize image instance
|
1130 |
$this->image = new Image(
|
1144 |
*
|
1145 |
* @return int
|
1146 |
*/
|
1147 |
+
public static function gdAlpha($alpha)
|
1148 |
+
{
|
1149 |
|
1150 |
+
$scale = round(127 * $alpha);
|
1151 |
|
1152 |
return $invert = 127 - $scale;
|
1153 |
}
|
1159 |
*
|
1160 |
* @return ImageType string Type of image.
|
1161 |
*/
|
1162 |
+
private function _getImageTypeFromFileName($imageFile)
|
1163 |
+
{
|
1164 |
+
$ext = strtolower((string)pathinfo($imageFile, PATHINFO_EXTENSION));
|
1165 |
|
1166 |
+
if ('jpg' == $ext or 'jpeg' == $ext) {
|
1167 |
return ImageType::JPEG;
|
1168 |
+
} else if ('gif' == $ext) {
|
1169 |
return ImageType::GIF;
|
1170 |
+
} else if ('png' == $ext) {
|
1171 |
return ImageType::PNG;
|
1172 |
} else {
|
1173 |
return ImageType::UNKNOWN;
|
1179 |
*
|
1180 |
* @throws \Exception
|
1181 |
*/
|
1182 |
+
private function _imageCheck()
|
1183 |
+
{
|
1184 |
+
if (null === $this->image) {
|
1185 |
+
throw new \Exception('No image to edit.');
|
1186 |
}
|
1187 |
}
|
1188 |
+
|
1189 |
}
|
src/CycloneSlider/Grafika/Imagick/DrawingObject/Polygon.php
CHANGED
@@ -11,18 +11,22 @@ use CycloneSlider\Grafika\DrawingObjectInterface;
|
|
11 |
class Polygon extends Base implements DrawingObjectInterface{
|
12 |
|
13 |
public function draw( $image ) {
|
14 |
-
$
|
15 |
-
|
16 |
-
|
|
|
|
|
|
|
17 |
} else {
|
18 |
-
$
|
19 |
}
|
20 |
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
|
|
26 |
|
27 |
$draw->polygon($this->points());
|
28 |
|
11 |
class Polygon extends Base implements DrawingObjectInterface{
|
12 |
|
13 |
public function draw( $image ) {
|
14 |
+
$draw = new \ImagickDraw();
|
15 |
+
$draw->setStrokeWidth($this->borderSize);
|
16 |
+
|
17 |
+
if(null !== $this->fillColor) {
|
18 |
+
$fillColor = new \ImagickPixel( $this->fillColor->getHexString() );
|
19 |
+
$draw->setFillColor($fillColor);
|
20 |
} else {
|
21 |
+
$draw->setFillOpacity(0);
|
22 |
}
|
23 |
|
24 |
+
if(null !== $this->borderColor) {
|
25 |
+
$borderColor = new \ImagickPixel( $this->borderColor->getHexString() );
|
26 |
+
$draw->setStrokeColor($borderColor);
|
27 |
+
} else {
|
28 |
+
$draw->setStrokeOpacity(0);
|
29 |
+
}
|
30 |
|
31 |
$draw->polygon($this->points());
|
32 |
|
src/CycloneSlider/Grafika/Imagick/DrawingObject/Rectangle.php
CHANGED
@@ -10,14 +10,26 @@ use CycloneSlider\Grafika\DrawingObjectInterface;
|
|
10 |
*/
|
11 |
class Rectangle extends Base implements DrawingObjectInterface{
|
12 |
|
13 |
-
// TODO: check use of stroke property instead of using two rectangles
|
14 |
public function draw( $image ) {
|
15 |
-
$strokeColor = new \ImagickPixel( $this->getBorderColor()->getHexString() );
|
16 |
-
$fillColor = new \ImagickPixel( $this->getFillColor()->getHexString() );
|
17 |
|
18 |
$draw = new \ImagickDraw();
|
19 |
-
$draw->
|
20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
$x1 = $this->pos[0];
|
23 |
$x2 = $x1 + $this->getWidth();
|
@@ -26,14 +38,7 @@ class Rectangle extends Base implements DrawingObjectInterface{
|
|
26 |
|
27 |
$draw->rectangle( $x1, $y1, $x2, $y2 );
|
28 |
|
29 |
-
$borderSize = $this->getBorderSize();
|
30 |
-
$innerRect = new \ImagickDraw();
|
31 |
-
$innerRect->setStrokeOpacity( 0 );
|
32 |
-
$innerRect->setFillColor($fillColor);
|
33 |
-
$innerRect->rectangle( $x1 + $borderSize, $y1 + $borderSize, $x2 - $borderSize, $y2 - $borderSize );
|
34 |
-
|
35 |
$image->getCore()->drawImage($draw);
|
36 |
-
$image->getCore()->drawImage($innerRect);
|
37 |
|
38 |
return $image;
|
39 |
}
|
10 |
*/
|
11 |
class Rectangle extends Base implements DrawingObjectInterface{
|
12 |
|
|
|
13 |
public function draw( $image ) {
|
|
|
|
|
14 |
|
15 |
$draw = new \ImagickDraw();
|
16 |
+
$draw->setStrokeWidth($this->borderSize);
|
17 |
+
|
18 |
+
if(null !== $this->fillColor) {
|
19 |
+
$fillColor = new \ImagickPixel( $this->fillColor->getHexString() );
|
20 |
+
$draw->setFillColor($fillColor);
|
21 |
+
} else {
|
22 |
+
$draw->setFillOpacity(0);
|
23 |
+
}
|
24 |
+
|
25 |
+
if(null !== $this->borderColor) {
|
26 |
+
$borderColor = new \ImagickPixel( $this->borderColor->getHexString() );
|
27 |
+
$draw->setStrokeColor($borderColor);
|
28 |
+
} else {
|
29 |
+
$draw->setStrokeOpacity(0);
|
30 |
+
}
|
31 |
+
|
32 |
+
|
33 |
|
34 |
$x1 = $this->pos[0];
|
35 |
$x2 = $x1 + $this->getWidth();
|
38 |
|
39 |
$draw->rectangle( $x1, $y1, $x2, $y2 );
|
40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
$image->getCore()->drawImage($draw);
|
|
|
42 |
|
43 |
return $image;
|
44 |
}
|
src/CycloneSlider/Grafika/Imagick/Editor.php
CHANGED
@@ -21,17 +21,19 @@ use CycloneSlider\Grafika\Imagick\Effect\Dither;
|
|
21 |
* Imagick Editor class. Uses the PHP Imagick library.
|
22 |
* @package Grafika\Imagick
|
23 |
*/
|
24 |
-
final class Editor implements EditorInterface
|
|
|
25 |
|
26 |
/**
|
27 |
-
* @var Image Holds the image instance
|
28 |
*/
|
29 |
private $image;
|
30 |
|
31 |
/**
|
32 |
* Constructor.
|
33 |
*/
|
34 |
-
function __construct()
|
|
|
35 |
$this->image = null;
|
36 |
}
|
37 |
|
@@ -40,44 +42,54 @@ final class Editor implements EditorInterface {
|
|
40 |
*
|
41 |
* @return $this
|
42 |
*/
|
43 |
-
public function apply(
|
44 |
-
|
|
|
|
|
45 |
return $this;
|
46 |
}
|
47 |
|
48 |
/**
|
49 |
* Creates a cubic bezier. Cubic bezier has 2 control points.
|
|
|
50 |
* @param array $point1 Array of X and Y value for start point.
|
51 |
* @param array $control1 Array of X and Y value for control point 1.
|
52 |
* @param array $control2 Array of X and Y value for control point 2.
|
53 |
* @param array $point2 Array of X and Y value for end point.
|
54 |
* @param Color|string $color Color of the curve. Accepts hex string or a Color object. Defaults to black.
|
|
|
55 |
* @return Editor
|
56 |
*/
|
57 |
-
public function bezierCubic($point1, $control1, $control2, $point2, $color = '#000000')
|
58 |
-
|
|
|
59 |
$color = new Color($color);
|
60 |
}
|
61 |
$obj = new CubicBezier($point1, $control1, $control2, $point2, $color);
|
|
|
62 |
return $this->draw($obj);
|
63 |
}
|
64 |
|
65 |
/**
|
66 |
* Creates a quadratic bezier. Quadratic bezier has 1 control point.
|
|
|
67 |
* @param array $point1 Array of X and Y value for start point.
|
68 |
* @param array $control Array of X and Y value for control point.
|
69 |
* @param array $point2 Array of X and Y value for end point.
|
70 |
* @param Color|string $color Color of the curve. Accepts hex string or a Color object. Defaults to black.
|
|
|
71 |
* @return Editor
|
72 |
*/
|
73 |
-
public function bezierQuad($point1, $control, $point2, $color = '#000000')
|
74 |
-
|
|
|
75 |
$color = new Color($color);
|
76 |
}
|
77 |
$obj = new QuadraticBezier($point1, $control, $point2, $color);
|
|
|
78 |
return $this->draw($obj);
|
79 |
}
|
80 |
-
|
81 |
/**
|
82 |
* Create a blank image given width and height.
|
83 |
*
|
@@ -86,39 +98,44 @@ final class Editor implements EditorInterface {
|
|
86 |
*
|
87 |
* @return self
|
88 |
*/
|
89 |
-
public function blank(
|
90 |
-
|
|
|
91 |
|
92 |
return $this;
|
93 |
}
|
94 |
|
95 |
/**
|
96 |
* Compare two images and returns a hamming distance. A value of 0 indicates a likely similar picture. A value between 1 and 10 is potentially a variation. A value greater than 10 is likely a different image.
|
|
|
97 |
* @param ImageInterface|string $image1
|
98 |
* @param ImageInterface|string $image2
|
|
|
99 |
* @return int Hamming distance. Note: This breaks the chain if you are doing fluent api calls as it does not return an Editor.
|
100 |
* @throws \Exception
|
101 |
*/
|
102 |
-
public function compare(
|
|
|
103 |
|
104 |
-
if (
|
105 |
-
$image1 = Image::createFromFile(
|
106 |
}
|
107 |
|
108 |
-
if (
|
109 |
-
$image2 = Image::createFromFile(
|
110 |
}
|
111 |
|
112 |
-
$bin1
|
113 |
-
$bin2
|
114 |
-
$str1
|
115 |
-
$str2
|
116 |
$distance = 0;
|
117 |
-
foreach($str1 as $i
|
118 |
-
if($char !== $str2[$i]){
|
119 |
$distance++;
|
120 |
}
|
121 |
}
|
|
|
122 |
return $distance;
|
123 |
|
124 |
}
|
@@ -128,16 +145,17 @@ final class Editor implements EditorInterface {
|
|
128 |
*
|
129 |
* @param int $cropWidth Crop width in pixels.
|
130 |
* @param int $cropHeight Crop Height in pixels.
|
131 |
-
* @param int|string $cropX The number of pixels from the left of the image.
|
132 |
-
* @param int|string $cropY The number of pixels from the
|
133 |
*
|
134 |
* @return self
|
135 |
*/
|
136 |
-
public function crop($cropWidth, $cropHeight, $cropX='center', $cropY='center')
|
|
|
137 |
|
138 |
-
if(is_string($cropX)){
|
139 |
// Compute position from string
|
140 |
-
switch ($cropX){
|
141 |
case 'left':
|
142 |
$x = 0;
|
143 |
break;
|
@@ -148,15 +166,15 @@ final class Editor implements EditorInterface {
|
|
148 |
|
149 |
case 'center':
|
150 |
default:
|
151 |
-
$x = (int)
|
152 |
break;
|
153 |
}
|
154 |
} else {
|
155 |
$x = $cropX;
|
156 |
}
|
157 |
|
158 |
-
if(is_string($cropY)){
|
159 |
-
switch ($cropY){
|
160 |
case 'top':
|
161 |
$y = 0;
|
162 |
break;
|
@@ -167,14 +185,14 @@ final class Editor implements EditorInterface {
|
|
167 |
|
168 |
case 'center':
|
169 |
default:
|
170 |
-
$y = (int)
|
171 |
break;
|
172 |
}
|
173 |
} else {
|
174 |
$y = $cropY;
|
175 |
}
|
176 |
|
177 |
-
$this->image->getCore()->cropImage(
|
178 |
|
179 |
return $this;
|
180 |
}
|
@@ -183,18 +201,22 @@ final class Editor implements EditorInterface {
|
|
183 |
* Dither image using Floyd-Steinberg algorithm. Dithering will reduce the color to black and white and add noise.
|
184 |
* @return EditorInterface An instance of image editor.
|
185 |
*/
|
186 |
-
public function dither()
|
|
|
187 |
$e = new Dither();
|
|
|
188 |
return $this->apply($e);
|
189 |
}
|
190 |
-
|
191 |
/**
|
192 |
* @param DrawingObjectInterface $drawingObject
|
193 |
*
|
194 |
* @return $this
|
195 |
*/
|
196 |
-
public function draw(
|
197 |
-
|
|
|
|
|
198 |
return $this;
|
199 |
}
|
200 |
|
@@ -210,17 +232,25 @@ final class Editor implements EditorInterface {
|
|
210 |
*
|
211 |
* @return EditorInterface An instance of image editor.
|
212 |
*/
|
213 |
-
public function ellipse(
|
214 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
215 |
$borderColor = new Color($borderColor);
|
216 |
}
|
217 |
-
if(is_string($fillColor)){
|
218 |
$fillColor = new Color($fillColor);
|
219 |
}
|
220 |
$obj = new Ellipse($width, $height, $pos, $borderSize, $borderColor, $fillColor);
|
|
|
221 |
return $this->draw($obj);
|
222 |
}
|
223 |
-
|
224 |
/**
|
225 |
* Compare if two images are equal. It will compare if the two images are of the same width and height. If the dimensions differ, it will return false. If the dimensions are equal, it will loop through each pixels. If one of the pixel don't match, it will return false. The pixels are compared using their RGB (Red, Green, Blue) values.
|
226 |
*
|
@@ -230,18 +260,19 @@ final class Editor implements EditorInterface {
|
|
230 |
* @return bool True if equals false if not. Note: This breaks the chain if you are doing fluent api calls as it does not return an Editor.
|
231 |
* @throws \Exception
|
232 |
*/
|
233 |
-
public function equal(
|
|
|
234 |
|
235 |
-
if (
|
236 |
-
$image1 = Image::createFromFile(
|
237 |
}
|
238 |
|
239 |
-
if (
|
240 |
-
$image2 = Image::createFromFile(
|
241 |
}
|
242 |
|
243 |
// Check if image dimensions are equal
|
244 |
-
if($image1->getWidth() !== $image2->getWidth() or $image1->getHeight() !== $image2->getHeight()) {
|
245 |
|
246 |
return false;
|
247 |
|
@@ -253,11 +284,12 @@ final class Editor implements EditorInterface {
|
|
253 |
foreach ($pixels as $column => $pixel) { /* Loop through the pixels in the row (columns) */
|
254 |
/**
|
255 |
* Get image1 pixel
|
256 |
-
* @var $pixel \ImagickPixel
|
|
|
257 |
$rgba1 = $pixel->getColor();
|
258 |
|
259 |
// Get image2 pixel
|
260 |
-
$rgba2 = $image2->getCore()->getImagePixelColor(
|
261 |
|
262 |
// Compare pixel value
|
263 |
if (
|
@@ -271,6 +303,7 @@ final class Editor implements EditorInterface {
|
|
271 |
$pixelIterator->syncIterator(); /* Sync the iterator, this is important to do on each iteration */
|
272 |
}
|
273 |
}
|
|
|
274 |
return true;
|
275 |
}
|
276 |
|
@@ -283,12 +316,13 @@ final class Editor implements EditorInterface {
|
|
283 |
*
|
284 |
* @return self
|
285 |
*/
|
286 |
-
public function fill(
|
|
|
287 |
|
288 |
$this->_imageCheck();
|
289 |
|
290 |
$target = $this->image->getCore()->getImagePixelColor($x, $y);
|
291 |
-
$this->image->getCore()->floodfillPaintImage(
|
292 |
|
293 |
return $this;
|
294 |
}
|
@@ -296,9 +330,10 @@ final class Editor implements EditorInterface {
|
|
296 |
/**
|
297 |
* Free the current image clearing resources associated with it.
|
298 |
*/
|
299 |
-
public function free()
|
300 |
-
|
301 |
-
|
|
|
302 |
$this->image->getCore()->clear();
|
303 |
}
|
304 |
} else {
|
@@ -306,13 +341,14 @@ final class Editor implements EditorInterface {
|
|
306 |
}
|
307 |
}
|
308 |
|
|
|
309 |
/**
|
310 |
* Converts image to grayscale.
|
311 |
*
|
312 |
-
* @return
|
313 |
*/
|
314 |
-
public function grayscale()
|
315 |
-
|
316 |
$this->_imageCheck();
|
317 |
|
318 |
$this->image->getCore()->modulateImage(100, 0, 100);
|
@@ -321,34 +357,39 @@ final class Editor implements EditorInterface {
|
|
321 |
}
|
322 |
|
323 |
/**
|
324 |
-
* Alias for grayscale.
|
325 |
*
|
326 |
-
* @return
|
327 |
*/
|
328 |
-
public function greyscale()
|
|
|
329 |
return $this->grayscale();
|
330 |
}
|
331 |
|
332 |
/**
|
|
|
|
|
333 |
* @return Image
|
334 |
*/
|
335 |
-
public function getImage()
|
|
|
336 |
return $this->image;
|
337 |
}
|
338 |
|
339 |
/**
|
340 |
* Checks if the editor is available on the current PHP install.
|
341 |
*
|
342 |
-
* @return bool
|
343 |
*/
|
344 |
-
public function isAvailable()
|
|
|
345 |
// First, test Imagick's extension and classes.
|
346 |
-
if (
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
){
|
352 |
return false;
|
353 |
}
|
354 |
|
@@ -362,16 +403,19 @@ final class Editor implements EditorInterface {
|
|
362 |
* @param array $point2 Array containing int X and int Y position of the starting point.
|
363 |
* @param int $thickness Thickness in pixel. Note: This is currently ignored in GD editor and falls back to 1.
|
364 |
* @param Color|string $color Color of the line. Defaults to black.
|
|
|
365 |
* @return Editor
|
366 |
*/
|
367 |
-
public function line(array $point1, array $point2, $thickness = 1, $color = '#000000')
|
368 |
-
|
|
|
369 |
$color = new Color($color);
|
370 |
}
|
371 |
$obj = new Line($point1, $point2, $thickness, $color);
|
|
|
372 |
return $this->draw($obj);
|
373 |
}
|
374 |
-
|
375 |
/**
|
376 |
* Sets the image to the specified opacity level where 1.0 is fully opaque and 0.0 is fully transparent.
|
377 |
*
|
@@ -380,7 +424,8 @@ final class Editor implements EditorInterface {
|
|
380 |
* @return self
|
381 |
* @throws \Exception
|
382 |
*/
|
383 |
-
public function opacity(
|
|
|
384 |
|
385 |
$this->_imageCheck();
|
386 |
|
@@ -388,7 +433,7 @@ final class Editor implements EditorInterface {
|
|
388 |
$opacity = ($opacity > 1) ? 1 : $opacity;
|
389 |
$opacity = ($opacity < 0) ? 0 : $opacity;
|
390 |
|
391 |
-
$this->image->getCore()->setImageOpacity(
|
392 |
|
393 |
return $this;
|
394 |
}
|
@@ -401,13 +446,14 @@ final class Editor implements EditorInterface {
|
|
401 |
* @return Editor
|
402 |
* @throws \Exception
|
403 |
*/
|
404 |
-
public function open(
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
|
|
409 |
} else {
|
410 |
-
throw new \Exception(
|
411 |
}
|
412 |
|
413 |
return $this;
|
@@ -420,7 +466,8 @@ final class Editor implements EditorInterface {
|
|
420 |
*
|
421 |
* @return $this
|
422 |
*/
|
423 |
-
public function openImage(
|
|
|
424 |
$this->image = $image;
|
425 |
|
426 |
return $this;
|
@@ -434,8 +481,9 @@ final class Editor implements EditorInterface {
|
|
434 |
* @return $this
|
435 |
* @throws \Exception
|
436 |
*/
|
437 |
-
public function openFile(
|
438 |
-
|
|
|
439 |
|
440 |
return $this;
|
441 |
}
|
@@ -452,49 +500,50 @@ final class Editor implements EditorInterface {
|
|
452 |
* @return Editor
|
453 |
* @throws \Exception
|
454 |
*/
|
455 |
-
public function overlay(
|
|
|
456 |
|
457 |
$this->_imageCheck();
|
458 |
|
459 |
-
if (
|
460 |
-
$overlay = Image::createFromFile(
|
461 |
}
|
462 |
|
463 |
// Resize overlay
|
464 |
-
if($width and $height){
|
465 |
|
466 |
-
$overlayWidth
|
467 |
$overlayHeight = $overlay->getHeight();
|
468 |
|
469 |
-
if(is_numeric($width)){
|
470 |
-
$overlayWidth = (int)
|
471 |
} else {
|
472 |
-
$percent
|
473 |
-
if(
|
474 |
-
$overlayWidth = intval(
|
475 |
}
|
476 |
}
|
477 |
|
478 |
-
if(is_numeric($height)){
|
479 |
-
$overlayHeight = (int)
|
480 |
} else {
|
481 |
-
$percent
|
482 |
-
if(
|
483 |
-
$overlayHeight = intval(
|
484 |
}
|
485 |
}
|
486 |
|
487 |
$editor = new Editor();
|
488 |
$editor->setImage($overlay);
|
489 |
-
$editor->resizeFit(
|
490 |
$overlay = $editor->getImage();
|
491 |
}
|
492 |
|
493 |
//$x = $y = 0;
|
494 |
|
495 |
-
if (
|
496 |
// Compute position from string
|
497 |
-
switch (
|
498 |
case 'left':
|
499 |
$x = 0;
|
500 |
break;
|
@@ -505,15 +554,15 @@ final class Editor implements EditorInterface {
|
|
505 |
|
506 |
case 'center':
|
507 |
default:
|
508 |
-
$x = (int)
|
509 |
break;
|
510 |
}
|
511 |
} else {
|
512 |
$x = $xPos;
|
513 |
}
|
514 |
|
515 |
-
if (
|
516 |
-
switch (
|
517 |
case 'top':
|
518 |
$y = 0;
|
519 |
break;
|
@@ -524,7 +573,7 @@ final class Editor implements EditorInterface {
|
|
524 |
|
525 |
case 'center':
|
526 |
default:
|
527 |
-
$y = (int)
|
528 |
break;
|
529 |
}
|
530 |
} else {
|
@@ -548,38 +597,51 @@ final class Editor implements EditorInterface {
|
|
548 |
*
|
549 |
* @return EditorInterface An instance of image editor.
|
550 |
*/
|
551 |
-
public function polygon($points, $borderSize = 1, $borderColor = '#000000', $fillColor = '#FFFFFF')
|
552 |
-
|
|
|
553 |
$borderColor = new Color($borderColor);
|
554 |
}
|
555 |
-
if(is_string($fillColor)){
|
556 |
$fillColor = new Color($fillColor);
|
557 |
}
|
558 |
$obj = new Polygon($points, $borderSize, $borderColor, $fillColor);
|
|
|
559 |
return $this->draw($obj);
|
560 |
}
|
561 |
|
562 |
/**
|
563 |
* Creates a rectangle.
|
|
|
564 |
* @param int $width Width of rectangle in pixels.
|
565 |
* @param int $height Height in pixels.
|
566 |
* @param array $pos Array of X and Y position. X is the distance in pixels from the left of the canvass to the left of the rectangle. Y is the distance from the top of the canvass to the top of the rectangle. Defaults to array(0,0).
|
567 |
* @param int $borderSize Size of the border in pixels. Defaults to 1 pixel. Set to 0 for no border.
|
568 |
* @param Color|string|null $borderColor Border color. Defaults to black. Set to null for no color.
|
569 |
* @param Color|string|null $fillColor Fill color. Defaults to white. Set to null for no color.
|
|
|
570 |
* @return Editor
|
571 |
*/
|
572 |
-
public function rectangle(
|
573 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
574 |
$borderColor = new Color($borderColor);
|
575 |
}
|
576 |
-
if(is_string($fillColor)){
|
577 |
$fillColor = new Color($fillColor);
|
578 |
}
|
579 |
$obj = new Rectangle($width, $height, $pos, $borderSize, $borderColor, $fillColor);
|
|
|
580 |
return $this->draw($obj);
|
581 |
}
|
582 |
|
|
|
583 |
/**
|
584 |
* Wrapper function for the resizeXXX family of functions. Resize image given width, height and mode.
|
585 |
*
|
@@ -587,26 +649,35 @@ final class Editor implements EditorInterface {
|
|
587 |
* @param int $newHeight Height in pixels.
|
588 |
* @param string $mode Resize mode. Possible values: "exact", "exactHeight", "exactWidth", "fill", "fit".
|
589 |
*
|
590 |
-
* @return
|
|
|
591 |
*/
|
592 |
-
public function resize(
|
593 |
-
|
594 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
595 |
case 'exact':
|
596 |
-
$this->resizeExact(
|
597 |
break;
|
598 |
case 'fill':
|
599 |
$this->resizeFill($newWidth, $newHeight);
|
600 |
break;
|
601 |
case 'exactWidth':
|
602 |
-
$this->resizeExactWidth(
|
603 |
break;
|
604 |
case 'exactHeight':
|
605 |
-
$this->resizeExactHeight(
|
606 |
break;
|
607 |
case 'fit':
|
608 |
$this->resizeFit($newWidth, $newHeight);
|
609 |
break;
|
|
|
|
|
610 |
}
|
611 |
|
612 |
return $this;
|
@@ -620,7 +691,8 @@ final class Editor implements EditorInterface {
|
|
620 |
*
|
621 |
* @return self
|
622 |
*/
|
623 |
-
public function resizeExact(
|
|
|
624 |
|
625 |
$this->_resize($newWidth, $newHeight);
|
626 |
|
@@ -634,16 +706,17 @@ final class Editor implements EditorInterface {
|
|
634 |
*
|
635 |
* @return self
|
636 |
*/
|
637 |
-
public function resizeExactHeight(
|
|
|
638 |
|
639 |
-
$width
|
640 |
$height = $this->image->getHeight();
|
641 |
-
$ratio
|
642 |
|
643 |
$resizeHeight = $newHeight;
|
644 |
-
$resizeWidth
|
645 |
|
646 |
-
$this->_resize(
|
647 |
|
648 |
return $this;
|
649 |
}
|
@@ -655,16 +728,17 @@ final class Editor implements EditorInterface {
|
|
655 |
*
|
656 |
* @return self
|
657 |
*/
|
658 |
-
public function resizeExactWidth(
|
|
|
659 |
|
660 |
-
$width
|
661 |
$height = $this->image->getHeight();
|
662 |
-
$ratio
|
663 |
|
664 |
-
$resizeWidth
|
665 |
$resizeHeight = round($newWidth / $ratio);
|
666 |
|
667 |
-
$this->_resize(
|
668 |
|
669 |
return $this;
|
670 |
}
|
@@ -677,23 +751,24 @@ final class Editor implements EditorInterface {
|
|
677 |
*
|
678 |
* @return self
|
679 |
*/
|
680 |
-
public function resizeFill(
|
681 |
-
|
|
|
682 |
$height = $this->image->getHeight();
|
683 |
-
$ratio
|
684 |
|
685 |
// Base optimum size on new width
|
686 |
-
$optimumWidth
|
687 |
$optimumHeight = round($newWidth / $ratio);
|
688 |
|
689 |
-
if
|
690 |
// So base optimum size on height instead
|
691 |
-
$optimumWidth
|
692 |
$optimumHeight = $newHeight;
|
693 |
}
|
694 |
|
695 |
-
$this->_resize(
|
696 |
-
$this->crop(
|
697 |
|
698 |
return $this;
|
699 |
}
|
@@ -706,23 +781,24 @@ final class Editor implements EditorInterface {
|
|
706 |
*
|
707 |
* @return self
|
708 |
*/
|
709 |
-
public function resizeFit(
|
|
|
710 |
|
711 |
-
$width
|
712 |
$height = $this->image->getHeight();
|
713 |
-
$ratio
|
714 |
|
715 |
// Try basing it on width first
|
716 |
-
$resizeWidth
|
717 |
$resizeHeight = round($newWidth / $ratio);
|
718 |
|
719 |
-
if
|
720 |
// So base on height instead
|
721 |
$resizeHeight = $newHeight;
|
722 |
-
$resizeWidth
|
723 |
}
|
724 |
|
725 |
-
$this->_resize(
|
726 |
|
727 |
return $this;
|
728 |
}
|
@@ -735,14 +811,15 @@ final class Editor implements EditorInterface {
|
|
735 |
*
|
736 |
* @return EditorInterface An instance of image editor.
|
737 |
*/
|
738 |
-
public function rotate(
|
|
|
739 |
|
740 |
$this->_imageCheck();
|
741 |
|
742 |
-
$color
|
743 |
-
list(
|
744 |
|
745 |
-
$this->image->getCore()->rotateImage(
|
746 |
|
747 |
return $this;
|
748 |
}
|
@@ -759,56 +836,61 @@ final class Editor implements EditorInterface {
|
|
759 |
* @return Editor
|
760 |
* @throws \Exception
|
761 |
*/
|
762 |
-
public function save(
|
|
|
763 |
|
764 |
$this->_imageCheck();
|
765 |
|
766 |
-
if (
|
767 |
|
768 |
-
$type = $this->_getImageTypeFromFileName(
|
769 |
-
if (
|
770 |
-
$type = $this->image->getType(); //
|
771 |
}
|
772 |
}
|
773 |
|
774 |
-
$targetDir = dirname(
|
775 |
-
if(
|
776 |
-
// Create and set default perms to
|
777 |
-
if( !mkdir(
|
778 |
-
throw new \Exception(
|
779 |
}
|
780 |
}
|
781 |
|
782 |
-
switch (
|
783 |
case ImageType::GIF :
|
784 |
-
$this->image->getCore()->writeImages(
|
785 |
break;
|
786 |
|
787 |
case ImageType::PNG :
|
788 |
-
// PNG is lossless and does not need compression
|
789 |
$this->image->getCore()->setImageFormat($type);
|
790 |
-
$this->image->getCore()->writeImage(
|
791 |
break;
|
792 |
|
793 |
default: // Defaults to jpeg
|
794 |
-
$quality = (
|
795 |
-
$quality = (
|
796 |
-
$quality = (
|
797 |
|
798 |
-
if($interlace){
|
799 |
-
$this->image->getCore()->setImageInterlaceScheme(
|
800 |
}
|
801 |
$this->image->getCore()->setImageFormat($type);
|
802 |
$this->image->getCore()->setImageCompressionQuality($quality);
|
803 |
-
$this->image->getCore()->writeImage(
|
804 |
}
|
|
|
805 |
return $this;
|
806 |
}
|
807 |
|
808 |
/**
|
|
|
|
|
809 |
* @param Image $image
|
810 |
*/
|
811 |
-
public function setImage(
|
|
|
812 |
$this->image = $image;
|
813 |
}
|
814 |
|
@@ -826,24 +908,25 @@ final class Editor implements EditorInterface {
|
|
826 |
* @return EditorInterface
|
827 |
* @throws \Exception
|
828 |
*/
|
829 |
-
public function text(
|
|
|
830 |
|
831 |
$this->_imageCheck();
|
832 |
|
833 |
$y += $size;
|
834 |
|
835 |
-
$color
|
836 |
-
$font
|
837 |
|
838 |
-
list(
|
839 |
|
840 |
// Set up draw properties
|
841 |
$draw = new \ImagickDraw();
|
842 |
// Text color
|
843 |
-
$draw->setFillColor(
|
844 |
// Font properties
|
845 |
-
$draw->setFont(
|
846 |
-
$draw->setFontSize(
|
847 |
|
848 |
// Write text
|
849 |
$this->image->getCore()->annotateImage(
|
@@ -867,29 +950,30 @@ final class Editor implements EditorInterface {
|
|
867 |
*
|
868 |
* http://www.hackerfactor.com/blog/index.php?/archives/529-Kind-of-Like-That.html
|
869 |
* @param Image $image
|
|
|
870 |
* @return string
|
871 |
*/
|
872 |
private function _differenceHash($image)
|
873 |
{
|
874 |
|
875 |
-
$width
|
876 |
$height = 8;
|
877 |
|
878 |
$editor = new Editor();
|
879 |
$editor->setImage($image);
|
880 |
-
$editor->resizeExact(
|
881 |
$imagick = $editor->getImage()->getCore();
|
882 |
|
883 |
// Build hash
|
884 |
$hash = '';
|
885 |
for ($y = 0; $y < $height; $y++) {
|
886 |
// Get the pixel value for the leftmost pixel.
|
887 |
-
$rgba = $imagick->getImagePixelColor(
|
888 |
|
889 |
$left = floor(($rgba['r'] + $rgba['g'] + $rgba['b']) / 3);
|
890 |
for ($x = 1; $x < $width; $x++) {
|
891 |
// Get the pixel value for each pixel starting from position 1.
|
892 |
-
$rgba
|
893 |
$right = floor(($rgba['r'] + $rgba['g'] + $rgba['b']) / 3);
|
894 |
// Each hash bit is set based on whether the left pixel is brighter than the right pixel.
|
895 |
if ($left > $right) {
|
@@ -914,10 +998,11 @@ final class Editor implements EditorInterface {
|
|
914 |
* @return self
|
915 |
* @throws \Exception
|
916 |
*/
|
917 |
-
private function _resize(
|
|
|
918 |
$this->_imageCheck();
|
919 |
|
920 |
-
if (
|
921 |
|
922 |
$imagick = $this->image->getCore()->coalesceImages();
|
923 |
|
@@ -927,12 +1012,14 @@ final class Editor implements EditorInterface {
|
|
927 |
}
|
928 |
|
929 |
// Assign new image with frames
|
930 |
-
$this->image = new Image($imagick->deconstructImages(), $this->image->getImageFile(), $newWidth, $newHeight,
|
|
|
931 |
} else { // Single frame image. Eg. JPEG, PNG
|
932 |
|
933 |
$this->image->getCore()->resizeImage($newWidth, $newHeight, \Imagick::FILTER_LANCZOS, 1, false);
|
934 |
// Assign new image
|
935 |
-
$this->image = new Image($this->image->getCore(), $this->image->getImageFile(), $newWidth, $newHeight,
|
|
|
936 |
}
|
937 |
|
938 |
}
|
@@ -944,18 +1031,16 @@ final class Editor implements EditorInterface {
|
|
944 |
*
|
945 |
* @return ImageType string Type of image.
|
946 |
*/
|
947 |
-
private function _getImageTypeFromFileName(
|
948 |
-
|
|
|
949 |
|
950 |
-
if (
|
951 |
return ImageType::JPEG;
|
952 |
-
|
953 |
-
} else if ( 'gif' == $ext ) {
|
954 |
return ImageType::GIF;
|
955 |
-
|
956 |
-
} else if ( 'png' == $ext ) {
|
957 |
return ImageType::PNG;
|
958 |
-
|
959 |
} else {
|
960 |
return ImageType::UNKNOWN;
|
961 |
}
|
@@ -966,8 +1051,9 @@ final class Editor implements EditorInterface {
|
|
966 |
*
|
967 |
* @throws \Exception
|
968 |
*/
|
969 |
-
private function _imageCheck()
|
970 |
-
|
|
|
971 |
throw new \Exception('No image to edit.');
|
972 |
}
|
973 |
}
|
21 |
* Imagick Editor class. Uses the PHP Imagick library.
|
22 |
* @package Grafika\Imagick
|
23 |
*/
|
24 |
+
final class Editor implements EditorInterface
|
25 |
+
{
|
26 |
|
27 |
/**
|
28 |
+
* @var Image Holds the image instance.
|
29 |
*/
|
30 |
private $image;
|
31 |
|
32 |
/**
|
33 |
* Constructor.
|
34 |
*/
|
35 |
+
function __construct()
|
36 |
+
{
|
37 |
$this->image = null;
|
38 |
}
|
39 |
|
42 |
*
|
43 |
* @return $this
|
44 |
*/
|
45 |
+
public function apply($effect)
|
46 |
+
{
|
47 |
+
$this->image = $effect->apply($this->image);
|
48 |
+
|
49 |
return $this;
|
50 |
}
|
51 |
|
52 |
/**
|
53 |
* Creates a cubic bezier. Cubic bezier has 2 control points.
|
54 |
+
*
|
55 |
* @param array $point1 Array of X and Y value for start point.
|
56 |
* @param array $control1 Array of X and Y value for control point 1.
|
57 |
* @param array $control2 Array of X and Y value for control point 2.
|
58 |
* @param array $point2 Array of X and Y value for end point.
|
59 |
* @param Color|string $color Color of the curve. Accepts hex string or a Color object. Defaults to black.
|
60 |
+
*
|
61 |
* @return Editor
|
62 |
*/
|
63 |
+
public function bezierCubic($point1, $control1, $control2, $point2, $color = '#000000')
|
64 |
+
{
|
65 |
+
if (is_string($color)) {
|
66 |
$color = new Color($color);
|
67 |
}
|
68 |
$obj = new CubicBezier($point1, $control1, $control2, $point2, $color);
|
69 |
+
|
70 |
return $this->draw($obj);
|
71 |
}
|
72 |
|
73 |
/**
|
74 |
* Creates a quadratic bezier. Quadratic bezier has 1 control point.
|
75 |
+
*
|
76 |
* @param array $point1 Array of X and Y value for start point.
|
77 |
* @param array $control Array of X and Y value for control point.
|
78 |
* @param array $point2 Array of X and Y value for end point.
|
79 |
* @param Color|string $color Color of the curve. Accepts hex string or a Color object. Defaults to black.
|
80 |
+
*
|
81 |
* @return Editor
|
82 |
*/
|
83 |
+
public function bezierQuad($point1, $control, $point2, $color = '#000000')
|
84 |
+
{
|
85 |
+
if (is_string($color)) {
|
86 |
$color = new Color($color);
|
87 |
}
|
88 |
$obj = new QuadraticBezier($point1, $control, $point2, $color);
|
89 |
+
|
90 |
return $this->draw($obj);
|
91 |
}
|
92 |
+
|
93 |
/**
|
94 |
* Create a blank image given width and height.
|
95 |
*
|
98 |
*
|
99 |
* @return self
|
100 |
*/
|
101 |
+
public function blank($width, $height)
|
102 |
+
{
|
103 |
+
$this->image = Image::createBlank($width, $height);
|
104 |
|
105 |
return $this;
|
106 |
}
|
107 |
|
108 |
/**
|
109 |
* Compare two images and returns a hamming distance. A value of 0 indicates a likely similar picture. A value between 1 and 10 is potentially a variation. A value greater than 10 is likely a different image.
|
110 |
+
*
|
111 |
* @param ImageInterface|string $image1
|
112 |
* @param ImageInterface|string $image2
|
113 |
+
*
|
114 |
* @return int Hamming distance. Note: This breaks the chain if you are doing fluent api calls as it does not return an Editor.
|
115 |
* @throws \Exception
|
116 |
*/
|
117 |
+
public function compare($image1, $image2)
|
118 |
+
{
|
119 |
|
120 |
+
if (is_string($image1)) { // If string passed, turn it into a Image object
|
121 |
+
$image1 = Image::createFromFile($image1);
|
122 |
}
|
123 |
|
124 |
+
if (is_string($image2)) { // If string passed, turn it into a Image object
|
125 |
+
$image2 = Image::createFromFile($image2);
|
126 |
}
|
127 |
|
128 |
+
$bin1 = $this->_differenceHash($image1);
|
129 |
+
$bin2 = $this->_differenceHash($image2);
|
130 |
+
$str1 = str_split($bin1);
|
131 |
+
$str2 = str_split($bin2);
|
132 |
$distance = 0;
|
133 |
+
foreach ($str1 as $i => $char) {
|
134 |
+
if ($char !== $str2[$i]) {
|
135 |
$distance++;
|
136 |
}
|
137 |
}
|
138 |
+
|
139 |
return $distance;
|
140 |
|
141 |
}
|
145 |
*
|
146 |
* @param int $cropWidth Crop width in pixels.
|
147 |
* @param int $cropHeight Crop Height in pixels.
|
148 |
+
* @param int|string $cropX The number of pixels from the left of the image. This parameter can be a number or any of the words "left", "center", "right".
|
149 |
+
* @param int|string $cropY The number of pixels from the top of the image. This parameter can be a number or any of the words "top", "center", "bottom".
|
150 |
*
|
151 |
* @return self
|
152 |
*/
|
153 |
+
public function crop($cropWidth, $cropHeight, $cropX = 'center', $cropY = 'center')
|
154 |
+
{
|
155 |
|
156 |
+
if (is_string($cropX)) {
|
157 |
// Compute position from string
|
158 |
+
switch ($cropX) {
|
159 |
case 'left':
|
160 |
$x = 0;
|
161 |
break;
|
166 |
|
167 |
case 'center':
|
168 |
default:
|
169 |
+
$x = (int)round(($this->image->getWidth() / 2) - ($cropWidth / 2));
|
170 |
break;
|
171 |
}
|
172 |
} else {
|
173 |
$x = $cropX;
|
174 |
}
|
175 |
|
176 |
+
if (is_string($cropY)) {
|
177 |
+
switch ($cropY) {
|
178 |
case 'top':
|
179 |
$y = 0;
|
180 |
break;
|
185 |
|
186 |
case 'center':
|
187 |
default:
|
188 |
+
$y = (int)round(($this->image->getHeight() / 2) - ($cropHeight / 2));
|
189 |
break;
|
190 |
}
|
191 |
} else {
|
192 |
$y = $cropY;
|
193 |
}
|
194 |
|
195 |
+
$this->image->getCore()->cropImage($cropWidth, $cropHeight, $x, $y);
|
196 |
|
197 |
return $this;
|
198 |
}
|
201 |
* Dither image using Floyd-Steinberg algorithm. Dithering will reduce the color to black and white and add noise.
|
202 |
* @return EditorInterface An instance of image editor.
|
203 |
*/
|
204 |
+
public function dither()
|
205 |
+
{
|
206 |
$e = new Dither();
|
207 |
+
|
208 |
return $this->apply($e);
|
209 |
}
|
210 |
+
|
211 |
/**
|
212 |
* @param DrawingObjectInterface $drawingObject
|
213 |
*
|
214 |
* @return $this
|
215 |
*/
|
216 |
+
public function draw($drawingObject)
|
217 |
+
{
|
218 |
+
$this->image = $drawingObject->draw($this->image);
|
219 |
+
|
220 |
return $this;
|
221 |
}
|
222 |
|
232 |
*
|
233 |
* @return EditorInterface An instance of image editor.
|
234 |
*/
|
235 |
+
public function ellipse(
|
236 |
+
$width,
|
237 |
+
$height,
|
238 |
+
array $pos,
|
239 |
+
$borderSize = 1,
|
240 |
+
$borderColor = '#000000',
|
241 |
+
$fillColor = '#FFFFFF'
|
242 |
+
) {
|
243 |
+
if (is_string($borderColor)) {
|
244 |
$borderColor = new Color($borderColor);
|
245 |
}
|
246 |
+
if (is_string($fillColor)) {
|
247 |
$fillColor = new Color($fillColor);
|
248 |
}
|
249 |
$obj = new Ellipse($width, $height, $pos, $borderSize, $borderColor, $fillColor);
|
250 |
+
|
251 |
return $this->draw($obj);
|
252 |
}
|
253 |
+
|
254 |
/**
|
255 |
* Compare if two images are equal. It will compare if the two images are of the same width and height. If the dimensions differ, it will return false. If the dimensions are equal, it will loop through each pixels. If one of the pixel don't match, it will return false. The pixels are compared using their RGB (Red, Green, Blue) values.
|
256 |
*
|
260 |
* @return bool True if equals false if not. Note: This breaks the chain if you are doing fluent api calls as it does not return an Editor.
|
261 |
* @throws \Exception
|
262 |
*/
|
263 |
+
public function equal($image1, $image2)
|
264 |
+
{
|
265 |
|
266 |
+
if (is_string($image1)) { // If string passed, turn it into a Image object
|
267 |
+
$image1 = Image::createFromFile($image1);
|
268 |
}
|
269 |
|
270 |
+
if (is_string($image2)) { // If string passed, turn it into a Image object
|
271 |
+
$image2 = Image::createFromFile($image2);
|
272 |
}
|
273 |
|
274 |
// Check if image dimensions are equal
|
275 |
+
if ($image1->getWidth() !== $image2->getWidth() or $image1->getHeight() !== $image2->getHeight()) {
|
276 |
|
277 |
return false;
|
278 |
|
284 |
foreach ($pixels as $column => $pixel) { /* Loop through the pixels in the row (columns) */
|
285 |
/**
|
286 |
* Get image1 pixel
|
287 |
+
* @var $pixel \ImagickPixel
|
288 |
+
*/
|
289 |
$rgba1 = $pixel->getColor();
|
290 |
|
291 |
// Get image2 pixel
|
292 |
+
$rgba2 = $image2->getCore()->getImagePixelColor($column, $row)->getColor();
|
293 |
|
294 |
// Compare pixel value
|
295 |
if (
|
303 |
$pixelIterator->syncIterator(); /* Sync the iterator, this is important to do on each iteration */
|
304 |
}
|
305 |
}
|
306 |
+
|
307 |
return true;
|
308 |
}
|
309 |
|
316 |
*
|
317 |
* @return self
|
318 |
*/
|
319 |
+
public function fill($color, $x = 0, $y = 0)
|
320 |
+
{
|
321 |
|
322 |
$this->_imageCheck();
|
323 |
|
324 |
$target = $this->image->getCore()->getImagePixelColor($x, $y);
|
325 |
+
$this->image->getCore()->floodfillPaintImage($color->getHexString(), 1, $target, $x, $y, false);
|
326 |
|
327 |
return $this;
|
328 |
}
|
330 |
/**
|
331 |
* Free the current image clearing resources associated with it.
|
332 |
*/
|
333 |
+
public function free()
|
334 |
+
{
|
335 |
+
if (null !== $this->image) {
|
336 |
+
if (null !== $this->image->getCore()) {
|
337 |
$this->image->getCore()->clear();
|
338 |
}
|
339 |
} else {
|
341 |
}
|
342 |
}
|
343 |
|
344 |
+
|
345 |
/**
|
346 |
* Converts image to grayscale.
|
347 |
*
|
348 |
+
* @return $this
|
349 |
*/
|
350 |
+
public function grayscale()
|
351 |
+
{
|
352 |
$this->_imageCheck();
|
353 |
|
354 |
$this->image->getCore()->modulateImage(100, 0, 100);
|
357 |
}
|
358 |
|
359 |
/**
|
360 |
+
* Alias for grayscale. They are the same.
|
361 |
*
|
362 |
+
* @return $this
|
363 |
*/
|
364 |
+
public function greyscale()
|
365 |
+
{
|
366 |
return $this->grayscale();
|
367 |
}
|
368 |
|
369 |
/**
|
370 |
+
* Get image instance.
|
371 |
+
*
|
372 |
* @return Image
|
373 |
*/
|
374 |
+
public function getImage()
|
375 |
+
{
|
376 |
return $this->image;
|
377 |
}
|
378 |
|
379 |
/**
|
380 |
* Checks if the editor is available on the current PHP install.
|
381 |
*
|
382 |
+
* @return bool True if available false if not.
|
383 |
*/
|
384 |
+
public function isAvailable()
|
385 |
+
{
|
386 |
// First, test Imagick's extension and classes.
|
387 |
+
if (false === extension_loaded('imagick') ||
|
388 |
+
false === class_exists('Imagick') ||
|
389 |
+
false === class_exists('ImagickDraw') ||
|
390 |
+
false === class_exists('ImagickPixel') ||
|
391 |
+
false === class_exists('ImagickPixelIterator')
|
392 |
+
) {
|
393 |
return false;
|
394 |
}
|
395 |
|
403 |
* @param array $point2 Array containing int X and int Y position of the starting point.
|
404 |
* @param int $thickness Thickness in pixel. Note: This is currently ignored in GD editor and falls back to 1.
|
405 |
* @param Color|string $color Color of the line. Defaults to black.
|
406 |
+
*
|
407 |
* @return Editor
|
408 |
*/
|
409 |
+
public function line(array $point1, array $point2, $thickness = 1, $color = '#000000')
|
410 |
+
{
|
411 |
+
if (is_string($color)) {
|
412 |
$color = new Color($color);
|
413 |
}
|
414 |
$obj = new Line($point1, $point2, $thickness, $color);
|
415 |
+
|
416 |
return $this->draw($obj);
|
417 |
}
|
418 |
+
|
419 |
/**
|
420 |
* Sets the image to the specified opacity level where 1.0 is fully opaque and 0.0 is fully transparent.
|
421 |
*
|
424 |
* @return self
|
425 |
* @throws \Exception
|
426 |
*/
|
427 |
+
public function opacity($opacity)
|
428 |
+
{
|
429 |
|
430 |
$this->_imageCheck();
|
431 |
|
433 |
$opacity = ($opacity > 1) ? 1 : $opacity;
|
434 |
$opacity = ($opacity < 0) ? 0 : $opacity;
|
435 |
|
436 |
+
$this->image->getCore()->setImageOpacity($opacity);
|
437 |
|
438 |
return $this;
|
439 |
}
|
446 |
* @return Editor
|
447 |
* @throws \Exception
|
448 |
*/
|
449 |
+
public function open($target)
|
450 |
+
{
|
451 |
+
if ($target instanceof ImageInterface) {
|
452 |
+
$this->openImage($target);
|
453 |
+
} else if (is_string($target)) {
|
454 |
+
$this->openFile($target);
|
455 |
} else {
|
456 |
+
throw new \Exception('Could not open image.');
|
457 |
}
|
458 |
|
459 |
return $this;
|
466 |
*
|
467 |
* @return $this
|
468 |
*/
|
469 |
+
public function openImage($image)
|
470 |
+
{
|
471 |
$this->image = $image;
|
472 |
|
473 |
return $this;
|
481 |
* @return $this
|
482 |
* @throws \Exception
|
483 |
*/
|
484 |
+
public function openFile($file)
|
485 |
+
{
|
486 |
+
$this->image = Image::createFromFile($file);
|
487 |
|
488 |
return $this;
|
489 |
}
|
500 |
* @return Editor
|
501 |
* @throws \Exception
|
502 |
*/
|
503 |
+
public function overlay($overlay, $xPos = 'center', $yPos = 'center', $width = null, $height = null)
|
504 |
+
{
|
505 |
|
506 |
$this->_imageCheck();
|
507 |
|
508 |
+
if (is_string($overlay)) { // If string passed, turn it into a Image object
|
509 |
+
$overlay = Image::createFromFile($overlay);
|
510 |
}
|
511 |
|
512 |
// Resize overlay
|
513 |
+
if ($width and $height) {
|
514 |
|
515 |
+
$overlayWidth = $overlay->getWidth();
|
516 |
$overlayHeight = $overlay->getHeight();
|
517 |
|
518 |
+
if (is_numeric($width)) {
|
519 |
+
$overlayWidth = (int)$width;
|
520 |
} else {
|
521 |
+
$percent = strpos($width, '%');
|
522 |
+
if (false !== $percent) {
|
523 |
+
$overlayWidth = intval($width) / 100 * $this->image->getWidth();
|
524 |
}
|
525 |
}
|
526 |
|
527 |
+
if (is_numeric($height)) {
|
528 |
+
$overlayHeight = (int)$height;
|
529 |
} else {
|
530 |
+
$percent = strpos($height, '%');
|
531 |
+
if (false !== $percent) {
|
532 |
+
$overlayHeight = intval($height) / 100 * $this->image->getHeight();
|
533 |
}
|
534 |
}
|
535 |
|
536 |
$editor = new Editor();
|
537 |
$editor->setImage($overlay);
|
538 |
+
$editor->resizeFit($overlayWidth, $overlayHeight);
|
539 |
$overlay = $editor->getImage();
|
540 |
}
|
541 |
|
542 |
//$x = $y = 0;
|
543 |
|
544 |
+
if (is_string($xPos)) {
|
545 |
// Compute position from string
|
546 |
+
switch ($xPos) {
|
547 |
case 'left':
|
548 |
$x = 0;
|
549 |
break;
|
554 |
|
555 |
case 'center':
|
556 |
default:
|
557 |
+
$x = (int)round(($this->image->getWidth() / 2) - ($overlay->getWidth() / 2));
|
558 |
break;
|
559 |
}
|
560 |
} else {
|
561 |
$x = $xPos;
|
562 |
}
|
563 |
|
564 |
+
if (is_string($yPos)) {
|
565 |
+
switch ($yPos) {
|
566 |
case 'top':
|
567 |
$y = 0;
|
568 |
break;
|
573 |
|
574 |
case 'center':
|
575 |
default:
|
576 |
+
$y = (int)round(($this->image->getHeight() / 2) - ($overlay->getHeight() / 2));
|
577 |
break;
|
578 |
}
|
579 |
} else {
|
597 |
*
|
598 |
* @return EditorInterface An instance of image editor.
|
599 |
*/
|
600 |
+
public function polygon($points, $borderSize = 1, $borderColor = '#000000', $fillColor = '#FFFFFF')
|
601 |
+
{
|
602 |
+
if (is_string($borderColor)) {
|
603 |
$borderColor = new Color($borderColor);
|
604 |
}
|
605 |
+
if (is_string($fillColor)) {
|
606 |
$fillColor = new Color($fillColor);
|
607 |
}
|
608 |
$obj = new Polygon($points, $borderSize, $borderColor, $fillColor);
|
609 |
+
|
610 |
return $this->draw($obj);
|
611 |
}
|
612 |
|
613 |
/**
|
614 |
* Creates a rectangle.
|
615 |
+
*
|
616 |
* @param int $width Width of rectangle in pixels.
|
617 |
* @param int $height Height in pixels.
|
618 |
* @param array $pos Array of X and Y position. X is the distance in pixels from the left of the canvass to the left of the rectangle. Y is the distance from the top of the canvass to the top of the rectangle. Defaults to array(0,0).
|
619 |
* @param int $borderSize Size of the border in pixels. Defaults to 1 pixel. Set to 0 for no border.
|
620 |
* @param Color|string|null $borderColor Border color. Defaults to black. Set to null for no color.
|
621 |
* @param Color|string|null $fillColor Fill color. Defaults to white. Set to null for no color.
|
622 |
+
*
|
623 |
* @return Editor
|
624 |
*/
|
625 |
+
public function rectangle(
|
626 |
+
$width,
|
627 |
+
$height,
|
628 |
+
$pos = array(0, 0),
|
629 |
+
$borderSize = 1,
|
630 |
+
$borderColor = '#000000',
|
631 |
+
$fillColor = '#FFFFFF'
|
632 |
+
) {
|
633 |
+
if (is_string($borderColor)) {
|
634 |
$borderColor = new Color($borderColor);
|
635 |
}
|
636 |
+
if (is_string($fillColor)) {
|
637 |
$fillColor = new Color($fillColor);
|
638 |
}
|
639 |
$obj = new Rectangle($width, $height, $pos, $borderSize, $borderColor, $fillColor);
|
640 |
+
|
641 |
return $this->draw($obj);
|
642 |
}
|
643 |
|
644 |
+
|
645 |
/**
|
646 |
* Wrapper function for the resizeXXX family of functions. Resize image given width, height and mode.
|
647 |
*
|
649 |
* @param int $newHeight Height in pixels.
|
650 |
* @param string $mode Resize mode. Possible values: "exact", "exactHeight", "exactWidth", "fill", "fit".
|
651 |
*
|
652 |
+
* @return Editor
|
653 |
+
* @throws \Exception
|
654 |
*/
|
655 |
+
public function resize($newWidth, $newHeight, $mode = 'fit')
|
656 |
+
{
|
657 |
+
/*
|
658 |
+
* Resize formula:
|
659 |
+
* ratio = w / h
|
660 |
+
* h = w / ratio
|
661 |
+
* w = h * ratio
|
662 |
+
*/
|
663 |
+
switch ($mode) {
|
664 |
case 'exact':
|
665 |
+
$this->resizeExact($newWidth, $newHeight);
|
666 |
break;
|
667 |
case 'fill':
|
668 |
$this->resizeFill($newWidth, $newHeight);
|
669 |
break;
|
670 |
case 'exactWidth':
|
671 |
+
$this->resizeExactWidth($newWidth);
|
672 |
break;
|
673 |
case 'exactHeight':
|
674 |
+
$this->resizeExactHeight($newHeight);
|
675 |
break;
|
676 |
case 'fit':
|
677 |
$this->resizeFit($newWidth, $newHeight);
|
678 |
break;
|
679 |
+
default:
|
680 |
+
throw new \Exception(sprintf('Invalid resize mode "%s".', $mode));
|
681 |
}
|
682 |
|
683 |
return $this;
|
691 |
*
|
692 |
* @return self
|
693 |
*/
|
694 |
+
public function resizeExact($newWidth, $newHeight)
|
695 |
+
{
|
696 |
|
697 |
$this->_resize($newWidth, $newHeight);
|
698 |
|
706 |
*
|
707 |
* @return self
|
708 |
*/
|
709 |
+
public function resizeExactHeight($newHeight)
|
710 |
+
{
|
711 |
|
712 |
+
$width = $this->image->getWidth();
|
713 |
$height = $this->image->getHeight();
|
714 |
+
$ratio = $width / $height;
|
715 |
|
716 |
$resizeHeight = $newHeight;
|
717 |
+
$resizeWidth = $newHeight * $ratio;
|
718 |
|
719 |
+
$this->_resize($resizeWidth, $resizeHeight);
|
720 |
|
721 |
return $this;
|
722 |
}
|
728 |
*
|
729 |
* @return self
|
730 |
*/
|
731 |
+
public function resizeExactWidth($newWidth)
|
732 |
+
{
|
733 |
|
734 |
+
$width = $this->image->getWidth();
|
735 |
$height = $this->image->getHeight();
|
736 |
+
$ratio = $width / $height;
|
737 |
|
738 |
+
$resizeWidth = $newWidth;
|
739 |
$resizeHeight = round($newWidth / $ratio);
|
740 |
|
741 |
+
$this->_resize($resizeWidth, $resizeHeight);
|
742 |
|
743 |
return $this;
|
744 |
}
|
751 |
*
|
752 |
* @return self
|
753 |
*/
|
754 |
+
public function resizeFill($newWidth, $newHeight)
|
755 |
+
{
|
756 |
+
$width = $this->image->getWidth();
|
757 |
$height = $this->image->getHeight();
|
758 |
+
$ratio = $width / $height;
|
759 |
|
760 |
// Base optimum size on new width
|
761 |
+
$optimumWidth = $newWidth;
|
762 |
$optimumHeight = round($newWidth / $ratio);
|
763 |
|
764 |
+
if (($optimumWidth < $newWidth) or ($optimumHeight < $newHeight)) { // Oops, where trying to fill and there are blank areas
|
765 |
// So base optimum size on height instead
|
766 |
+
$optimumWidth = $newHeight * $ratio;
|
767 |
$optimumHeight = $newHeight;
|
768 |
}
|
769 |
|
770 |
+
$this->_resize($optimumWidth, $optimumHeight);
|
771 |
+
$this->crop($newWidth, $newHeight); // Trim excess parts
|
772 |
|
773 |
return $this;
|
774 |
}
|
781 |
*
|
782 |
* @return self
|
783 |
*/
|
784 |
+
public function resizeFit($newWidth, $newHeight)
|
785 |
+
{
|
786 |
|
787 |
+
$width = $this->image->getWidth();
|
788 |
$height = $this->image->getHeight();
|
789 |
+
$ratio = $width / $height;
|
790 |
|
791 |
// Try basing it on width first
|
792 |
+
$resizeWidth = $newWidth;
|
793 |
$resizeHeight = round($newWidth / $ratio);
|
794 |
|
795 |
+
if (($resizeWidth > $newWidth) or ($resizeHeight > $newHeight)) { // Oops, either with or height does not fit
|
796 |
// So base on height instead
|
797 |
$resizeHeight = $newHeight;
|
798 |
+
$resizeWidth = $newHeight * $ratio;
|
799 |
}
|
800 |
|
801 |
+
$this->_resize($resizeWidth, $resizeHeight);
|
802 |
|
803 |
return $this;
|
804 |
}
|
811 |
*
|
812 |
* @return EditorInterface An instance of image editor.
|
813 |
*/
|
814 |
+
public function rotate($angle, $color = null)
|
815 |
+
{
|
816 |
|
817 |
$this->_imageCheck();
|
818 |
|
819 |
+
$color = ($color !== null) ? $color : new Color('#000000');
|
820 |
+
list($r, $g, $b, $alpha) = $color->getRgba();
|
821 |
|
822 |
+
$this->image->getCore()->rotateImage(new \ImagickPixel("rgba($r, $g, $b, $alpha)"), $angle * -1);
|
823 |
|
824 |
return $this;
|
825 |
}
|
836 |
* @return Editor
|
837 |
* @throws \Exception
|
838 |
*/
|
839 |
+
public function save($file, $type = null, $quality = null, $interlace = false, $permission = 0755)
|
840 |
+
{
|
841 |
|
842 |
$this->_imageCheck();
|
843 |
|
844 |
+
if (null === $type) {
|
845 |
|
846 |
+
$type = $this->_getImageTypeFromFileName($file); // Null given, guess type from file extension
|
847 |
+
if (ImageType::UNKNOWN === $type) {
|
848 |
+
$type = $this->image->getType(); // 0 result, use original image type
|
849 |
}
|
850 |
}
|
851 |
|
852 |
+
$targetDir = dirname($file); // $file's directory
|
853 |
+
if (false === is_dir($targetDir)) { // Check if $file's directory exist
|
854 |
+
// Create and set default perms to 0755
|
855 |
+
if ( ! mkdir($targetDir, $permission, true)) {
|
856 |
+
throw new \Exception(sprintf('Cannot create %s', $targetDir));
|
857 |
}
|
858 |
}
|
859 |
|
860 |
+
switch ($type) {
|
861 |
case ImageType::GIF :
|
862 |
+
$this->image->getCore()->writeImages($file, true); // Support animated image. Eg. GIF
|
863 |
break;
|
864 |
|
865 |
case ImageType::PNG :
|
866 |
+
// PNG is lossless and does not need compression. Although GD allow values 0-9 (0 = no compression), we leave it alone.
|
867 |
$this->image->getCore()->setImageFormat($type);
|
868 |
+
$this->image->getCore()->writeImage($file);
|
869 |
break;
|
870 |
|
871 |
default: // Defaults to jpeg
|
872 |
+
$quality = ($quality === null) ? 75 : $quality; // Default to 75 (GDs default) if null.
|
873 |
+
$quality = ($quality > 100) ? 100 : $quality;
|
874 |
+
$quality = ($quality < 0) ? 0 : $quality;
|
875 |
|
876 |
+
if ($interlace) {
|
877 |
+
$this->image->getCore()->setImageInterlaceScheme(\Imagick::INTERLACE_JPEG);
|
878 |
}
|
879 |
$this->image->getCore()->setImageFormat($type);
|
880 |
$this->image->getCore()->setImageCompressionQuality($quality);
|
881 |
+
$this->image->getCore()->writeImage($file); // Single frame image. Eg. JPEG
|
882 |
}
|
883 |
+
|
884 |
return $this;
|
885 |
}
|
886 |
|
887 |
/**
|
888 |
+
* Set image instance.
|
889 |
+
*
|
890 |
* @param Image $image
|
891 |
*/
|
892 |
+
public function setImage($image)
|
893 |
+
{
|
894 |
$this->image = $image;
|
895 |
}
|
896 |
|
908 |
* @return EditorInterface
|
909 |
* @throws \Exception
|
910 |
*/
|
911 |
+
public function text($text, $size = 12, $x = 0, $y = 0, $color = null, $font = '', $angle = 0)
|
912 |
+
{
|
913 |
|
914 |
$this->_imageCheck();
|
915 |
|
916 |
$y += $size;
|
917 |
|
918 |
+
$color = ($color !== null) ? $color : new Color('#000000');
|
919 |
+
$font = ($font !== '') ? $font : Grafika::fontsDir() . DIRECTORY_SEPARATOR . 'LiberationSans-Regular.ttf';
|
920 |
|
921 |
+
list($r, $g, $b, $alpha) = $color->getRgba();
|
922 |
|
923 |
// Set up draw properties
|
924 |
$draw = new \ImagickDraw();
|
925 |
// Text color
|
926 |
+
$draw->setFillColor(new \ImagickPixel("rgba($r, $g, $b, $alpha)"));
|
927 |
// Font properties
|
928 |
+
$draw->setFont($font);
|
929 |
+
$draw->setFontSize($size);
|
930 |
|
931 |
// Write text
|
932 |
$this->image->getCore()->annotateImage(
|
950 |
*
|
951 |
* http://www.hackerfactor.com/blog/index.php?/archives/529-Kind-of-Like-That.html
|
952 |
* @param Image $image
|
953 |
+
*
|
954 |
* @return string
|
955 |
*/
|
956 |
private function _differenceHash($image)
|
957 |
{
|
958 |
|
959 |
+
$width = 9;
|
960 |
$height = 8;
|
961 |
|
962 |
$editor = new Editor();
|
963 |
$editor->setImage($image);
|
964 |
+
$editor->resizeExact($width, $height); // Resize to exactly 9x8
|
965 |
$imagick = $editor->getImage()->getCore();
|
966 |
|
967 |
// Build hash
|
968 |
$hash = '';
|
969 |
for ($y = 0; $y < $height; $y++) {
|
970 |
// Get the pixel value for the leftmost pixel.
|
971 |
+
$rgba = $imagick->getImagePixelColor(0, $y)->getColor();
|
972 |
|
973 |
$left = floor(($rgba['r'] + $rgba['g'] + $rgba['b']) / 3);
|
974 |
for ($x = 1; $x < $width; $x++) {
|
975 |
// Get the pixel value for each pixel starting from position 1.
|
976 |
+
$rgba = $imagick->getImagePixelColor($x, $y)->getColor();
|
977 |
$right = floor(($rgba['r'] + $rgba['g'] + $rgba['b']) / 3);
|
978 |
// Each hash bit is set based on whether the left pixel is brighter than the right pixel.
|
979 |
if ($left > $right) {
|
998 |
* @return self
|
999 |
* @throws \Exception
|
1000 |
*/
|
1001 |
+
private function _resize($newWidth, $newHeight)
|
1002 |
+
{
|
1003 |
$this->_imageCheck();
|
1004 |
|
1005 |
+
if ('GIF' == $this->image->getType()) { // Animated image. Eg. GIF
|
1006 |
|
1007 |
$imagick = $this->image->getCore()->coalesceImages();
|
1008 |
|
1012 |
}
|
1013 |
|
1014 |
// Assign new image with frames
|
1015 |
+
$this->image = new Image($imagick->deconstructImages(), $this->image->getImageFile(), $newWidth, $newHeight,
|
1016 |
+
$this->image->getType());
|
1017 |
} else { // Single frame image. Eg. JPEG, PNG
|
1018 |
|
1019 |
$this->image->getCore()->resizeImage($newWidth, $newHeight, \Imagick::FILTER_LANCZOS, 1, false);
|
1020 |
// Assign new image
|
1021 |
+
$this->image = new Image($this->image->getCore(), $this->image->getImageFile(), $newWidth, $newHeight,
|
1022 |
+
$this->image->getType());
|
1023 |
}
|
1024 |
|
1025 |
}
|
1031 |
*
|
1032 |
* @return ImageType string Type of image.
|
1033 |
*/
|
1034 |
+
private function _getImageTypeFromFileName($imageFile)
|
1035 |
+
{
|
1036 |
+
$ext = strtolower((string)pathinfo($imageFile, PATHINFO_EXTENSION));
|
1037 |
|
1038 |
+
if ('jpg' == $ext or 'jpeg' == $ext) {
|
1039 |
return ImageType::JPEG;
|
1040 |
+
} else if ('gif' == $ext) {
|
|
|
1041 |
return ImageType::GIF;
|
1042 |
+
} else if ('png' == $ext) {
|
|
|
1043 |
return ImageType::PNG;
|
|
|
1044 |
} else {
|
1045 |
return ImageType::UNKNOWN;
|
1046 |
}
|
1051 |
*
|
1052 |
* @throws \Exception
|
1053 |
*/
|
1054 |
+
private function _imageCheck()
|
1055 |
+
{
|
1056 |
+
if (null === $this->image) {
|
1057 |
throw new \Exception('No image to edit.');
|
1058 |
}
|
1059 |
}
|
src/CycloneSlider/ImageResizer.php
CHANGED
@@ -29,8 +29,7 @@ class CycloneSlider_ImageResizer {
|
|
29 |
if(!function_exists('gd_info')){
|
30 |
return false;
|
31 |
}
|
32 |
-
|
33 |
-
$slider_settings['resize_quality'] = 90;
|
34 |
$width = $slider_settings['width'];
|
35 |
$height = $slider_settings['height'];
|
36 |
|
@@ -54,7 +53,7 @@ class CycloneSlider_ImageResizer {
|
|
54 |
|
55 |
// Save image to this file
|
56 |
$image_file_dest = "{$dirname}/{$thumb_name}";
|
57 |
-
|
58 |
// Main slide image
|
59 |
if( isset($slider_settings['resize']) ){
|
60 |
if( 1 == $slider_settings['resize'] ){
|
@@ -63,7 +62,6 @@ class CycloneSlider_ImageResizer {
|
|
63 |
if( ( false === is_file($image_file_dest) ) or ( is_file($image_file_dest) and $slider_settings['force_resize'] ) ){
|
64 |
|
65 |
$this->resize_slide_image( $image_file, $image_file_dest, $width, $height, $slider_settings['resize_option'], $slider_settings['resize_quality'] );
|
66 |
-
|
67 |
}
|
68 |
}
|
69 |
}
|
@@ -86,6 +84,7 @@ class CycloneSlider_ImageResizer {
|
|
86 |
}
|
87 |
}
|
88 |
}
|
|
|
89 |
}
|
90 |
|
91 |
/**
|
29 |
if(!function_exists('gd_info')){
|
30 |
return false;
|
31 |
}
|
32 |
+
|
|
|
33 |
$width = $slider_settings['width'];
|
34 |
$height = $slider_settings['height'];
|
35 |
|
53 |
|
54 |
// Save image to this file
|
55 |
$image_file_dest = "{$dirname}/{$thumb_name}";
|
56 |
+
|
57 |
// Main slide image
|
58 |
if( isset($slider_settings['resize']) ){
|
59 |
if( 1 == $slider_settings['resize'] ){
|
62 |
if( ( false === is_file($image_file_dest) ) or ( is_file($image_file_dest) and $slider_settings['force_resize'] ) ){
|
63 |
|
64 |
$this->resize_slide_image( $image_file, $image_file_dest, $width, $height, $slider_settings['resize_option'], $slider_settings['resize_quality'] );
|
|
|
65 |
}
|
66 |
}
|
67 |
}
|
84 |
}
|
85 |
}
|
86 |
}
|
87 |
+
return true;
|
88 |
}
|
89 |
|
90 |
/**
|
src/autoloader.php
CHANGED
@@ -2,8 +2,11 @@
|
|
2 |
// Autoloader
|
3 |
function cycloneslider_autoloader( $class_name ) {
|
4 |
if ( 0 === strpos( $class_name, 'CycloneSlider' ) ) {
|
5 |
-
|
6 |
-
$
|
|
|
|
|
|
|
7 |
require_once $src . $class;
|
8 |
}
|
9 |
}
|
2 |
// Autoloader
|
3 |
function cycloneslider_autoloader( $class_name ) {
|
4 |
if ( 0 === strpos( $class_name, 'CycloneSlider' ) ) {
|
5 |
+
|
6 |
+
$class_name = str_replace( '\\', '/', $class_name ); // for 5.3 namespaces, replace \ with / to work with linux.
|
7 |
+
$src = dirname( __FILE__ ) . '/';
|
8 |
+
$class = str_replace( '_', '/', $class_name ) . '.php';
|
9 |
+
|
10 |
require_once $src . $class;
|
11 |
}
|
12 |
}
|
views/slider-advanced-settings.php
CHANGED
@@ -49,13 +49,13 @@
|
|
49 |
</span>
|
50 |
<div class="clear"></div>
|
51 |
</div>
|
52 |
-
<div class="cycloneslider-field
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
<span class="note">
|
60 |
<?php if(version_compare(PHP_VERSION, '5.3', '>=')){ ?>
|
61 |
<?php _e('Fit - (Default) Fit images inside the slideshow maintaining aspect ratio.', 'cyclone-slider-2'); ?><br>
|
@@ -64,6 +64,7 @@
|
|
64 |
<?php _e('Exact - Resize images to exact dimensions ignoring aspect ratio.', 'cyclone-slider-2'); ?><br>
|
65 |
<?php _e('Exact Width - Resize to exact width.', 'cyclone-slider-2'); ?><br>
|
66 |
<?php _e('Exact Height - Resize to exact height.', 'cyclone-slider-2'); ?><br>
|
|
|
67 |
<?php } else { ?>
|
68 |
<?php _e('Auto - Cyclone Slider decides the resize option.', 'cyclone-slider-2'); ?><br>
|
69 |
<?php _e('Crop - Resize and remove excess parts.', 'cyclone-slider-2'); ?><br>
|
@@ -72,5 +73,24 @@
|
|
72 |
<?php _e('Portrait - Resize to exact height.', 'cyclone-slider-2'); ?><br>
|
73 |
<?php } ?>
|
74 |
</span>
|
75 |
-
|
76 |
-
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
</span>
|
50 |
<div class="clear"></div>
|
51 |
</div>
|
52 |
+
<div class="cycloneslider-field">
|
53 |
+
<label for="cycloneslider_settings_resize_option"><?php _e('Resize Options:', 'cyclone-slider-2'); ?></label>
|
54 |
+
<select id="cycloneslider_settings_resize_option" name="cycloneslider_settings[resize_option]">
|
55 |
+
<?php foreach( $resize_options as $resize_option=>$resize_name ): ?>
|
56 |
+
<option <?php echo (isset($slider_settings['resize_option']) && $resize_option==$slider_settings['resize_option']) ? 'selected="selected"' : ''; ?> value="<?php echo esc_attr( $resize_option ); ?>"><?php echo esc_attr( $resize_name ); ?></option>
|
57 |
+
<?php endforeach; ?>
|
58 |
+
</select>
|
59 |
<span class="note">
|
60 |
<?php if(version_compare(PHP_VERSION, '5.3', '>=')){ ?>
|
61 |
<?php _e('Fit - (Default) Fit images inside the slideshow maintaining aspect ratio.', 'cyclone-slider-2'); ?><br>
|
64 |
<?php _e('Exact - Resize images to exact dimensions ignoring aspect ratio.', 'cyclone-slider-2'); ?><br>
|
65 |
<?php _e('Exact Width - Resize to exact width.', 'cyclone-slider-2'); ?><br>
|
66 |
<?php _e('Exact Height - Resize to exact height.', 'cyclone-slider-2'); ?><br>
|
67 |
+
<?php _e('Note: Please clear your browser cache if you are not seeing the changes.', 'cyclone-slider-2'); ?><br>
|
68 |
<?php } else { ?>
|
69 |
<?php _e('Auto - Cyclone Slider decides the resize option.', 'cyclone-slider-2'); ?><br>
|
70 |
<?php _e('Crop - Resize and remove excess parts.', 'cyclone-slider-2'); ?><br>
|
73 |
<?php _e('Portrait - Resize to exact height.', 'cyclone-slider-2'); ?><br>
|
74 |
<?php } ?>
|
75 |
</span>
|
76 |
+
<div class="clear"></div>
|
77 |
+
</div>
|
78 |
+
<?php if(version_compare(PHP_VERSION, '5.3', '>=')){ ?>
|
79 |
+
<div class="cycloneslider-field last">
|
80 |
+
<label for="cycloneslider_settings_resize_quality"><?php _e('Image Quality (JPEG):', 'cyclone-slider-2'); ?></label>
|
81 |
+
<select id="cycloneslider_settings_resize_quality" name="cycloneslider_settings[resize_quality]">
|
82 |
+
|
83 |
+
<option <?php selected($slider_settings['resize_quality'], 10); ?> value="10"><?php _e('Low', 'cyclone-slider-2'); ?></option>
|
84 |
+
<option <?php selected($slider_settings['resize_quality'], 30); ?> value="30"><?php _e('Medium', 'cyclone-slider-2'); ?></option>
|
85 |
+
<option <?php selected($slider_settings['resize_quality'], 60); ?> value="60"><?php _e('High', 'cyclone-slider-2'); ?></option>
|
86 |
+
<option <?php selected($slider_settings['resize_quality'], 80); ?> value="80"><?php _e('Very High', 'cyclone-slider-2'); ?></option>
|
87 |
+
<option <?php selected($slider_settings['resize_quality'], 100); ?> value="100"><?php _e('Max', 'cyclone-slider-2'); ?></option>
|
88 |
+
|
89 |
+
</select>
|
90 |
+
<span class="note">
|
91 |
+
<?php _e('The quality of the generated images. Applies to JPEG images only.', 'cyclone-slider-2'); ?><br>
|
92 |
+
<?php _e('Low = low quality but small file size. Max = Best quality but large file size.', 'cyclone-slider-2'); ?><br>
|
93 |
+
</span>
|
94 |
+
<div class="clear"></div>
|
95 |
+
</div>
|
96 |
+
<?php } ?>
|