Skip to content

Commit f66ec7f

Browse files
committed
Merge pull request #111 from ResponsiveImagesCG/dev
Merging v2.3
2 parents b2e6e07 + aa517f7 commit f66ec7f

8 files changed

+757
-157
lines changed

.editorconfig

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# This file is for unifying the coding style for different editors and IDEs
2+
# editorconfig.org
3+
4+
# WordPress Coding Standards
5+
# https://make.wordpress.org/core/handbook/coding-standards/
6+
7+
root = true
8+
9+
[*]
10+
charset = utf-8
11+
end_of_line = lf
12+
insert_final_newline = true
13+
trim_trailing_whitespace = true
14+
indent_style = tab
15+
16+
[{.jshintrc,*.json,*.yml}]
17+
indent_style = space
18+
indent_size = 2
19+
20+
[{*.txt,wp-config-sample.php}]
21+
end_of_line = crlf

class-respimg.php

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
<?php
2+
3+
/**
4+
* hacked up version of php-respimg <https://github.com/nwtn/php-respimg>
5+
*
6+
* @package wp-respimg
7+
* @version 0.0.1
8+
*/
9+
10+
if (class_exists('Imagick')) {
11+
class RespimgImagick extends Imagick { }
12+
} else {
13+
class RespimgImagick { }
14+
}
15+
16+
17+
/**
18+
* An Imagick extension to provide better (higher quality, lower file size) image resizes.
19+
*
20+
* This class extends Imagick (<http://php.net/manual/en/book.imagick.php>) based on
21+
* research into optimal image resizing techniques (<https://github.com/nwtn/image-resize-tests>).
22+
*
23+
* Using these methods with their default settings should provide image resizing that is
24+
* visually indistinguishable from Photoshop’s “Save for Web…”, but at lower file sizes.
25+
*
26+
* @author David Newton <david@davidnewton.ca>
27+
* @copyright 2015 David Newton
28+
* @license https://raw.githubusercontent.com/nwtn/php-respimg/master/LICENSE MIT
29+
* @version 1.0.0
30+
*/
31+
32+
class Respimg extends RespimgImagick {
33+
34+
/**
35+
* Resizes the image using smart defaults for high quality and low file size.
36+
*
37+
* This function is basically equivalent to:
38+
*
39+
* $optim == true: `mogrify -path OUTPUT_PATH -filter Triangle -define filter:support=2.0 -thumbnail OUTPUT_WIDTH -unsharp 0.25x0.08+8.3+0.045 -dither None -posterize 136 -quality 82 -define jpeg:fancy-upsampling=off -define png:compression-filter=5 -define png:compression-level=9 -define png:compression-strategy=1 -define png:exclude-chunk=all -interlace none -colorspace sRGB INPUT_PATH`
40+
*
41+
* $optim == false: `mogrify -path OUTPUT_PATH -filter Triangle -define filter:support=2.0 -thumbnail OUTPUT_WIDTH -unsharp 0.25x0.25+8+0.065 -dither None -posterize 136 -quality 82 -define jpeg:fancy-upsampling=off -define png:compression-filter=5 -define png:compression-level=9 -define png:compression-strategy=1 -define png:exclude-chunk=all -interlace none -colorspace sRGB -strip INPUT_PATH`
42+
*
43+
* @access public
44+
*
45+
* @param integer $columns The number of columns in the output image. 0 = maintain aspect ratio based on $rows.
46+
* @param integer $rows The number of rows in the output image. 0 = maintain aspect ratio based on $columns.
47+
* @param bool $optim Whether you intend to perform optimization on the resulting image. Note that setting this to `true` doesn’t actually perform any optimization.
48+
*/
49+
50+
public function smartResize($columns, $rows, $optim = false) {
51+
52+
$this->setOption('filter:support', '2.0');
53+
$this->thumbnailImage($columns, $rows, false, false, Imagick::FILTER_TRIANGLE);
54+
if ($optim) {
55+
$this->unsharpMaskImage(0.25, 0.08, 8.3, 0.045);
56+
} else {
57+
$this->unsharpMaskImage(0.25, 0.25, 8, 0.065);
58+
}
59+
$this->posterizeImage(136, false);
60+
$this->setImageCompressionQuality(82);
61+
$this->setOption('jpeg:fancy-upsampling', 'off');
62+
$this->setOption('png:compression-filter', '5');
63+
$this->setOption('png:compression-level', '9');
64+
$this->setOption('png:compression-strategy', '1');
65+
$this->setOption('png:exclude-chunk', 'all');
66+
$this->setInterlaceScheme(Imagick::INTERLACE_NO);
67+
$this->setColorspace(Imagick::COLORSPACE_SRGB);
68+
if (!$optim) {
69+
$this->stripImage();
70+
}
71+
72+
}
73+
74+
75+
/**
76+
* Changes the size of an image to the given dimensions and removes any associated profiles.
77+
*
78+
* `thumbnailImage` changes the size of an image to the given dimensions and
79+
* removes any associated profiles. The goal is to produce small low cost
80+
* thumbnail images suited for display on the Web.
81+
*
82+
* With the original Imagick thumbnailImage implementation, there is no way to choose a
83+
* resampling filter. This class recreates Imagick’s C implementation and adds this
84+
* additional feature.
85+
*
86+
* Note: <https://github.com/mkoppanen/imagick/issues/90> has been filed for this issue.
87+
*
88+
* @access public
89+
*
90+
* @param integer $columns The number of columns in the output image. 0 = maintain aspect ratio based on $rows.
91+
* @param integer $rows The number of rows in the output image. 0 = maintain aspect ratio based on $columns.
92+
* @param bool $bestfit Treat $columns and $rows as a bounding box in which to fit the image.
93+
* @param bool $fill Fill in the bounding box with the background colour.
94+
* @param integer $filter The resampling filter to use. Refer to the list of filter constants at <http://php.net/manual/en/imagick.constants.php>.
95+
*
96+
* @return bool Indicates whether the operation was performed successfully.
97+
*/
98+
99+
public function thumbnailImage($columns, $rows, $bestfit = false, $fill = false, $filter = Imagick::FILTER_TRIANGLE) {
100+
101+
// sample factor; defined in original ImageMagick thumbnailImage function
102+
// the scale to which the image should be resized using the `sample` function
103+
$SampleFactor = 5;
104+
105+
// filter whitelist
106+
$filters = array(
107+
Imagick::FILTER_POINT,
108+
Imagick::FILTER_BOX,
109+
Imagick::FILTER_TRIANGLE,
110+
Imagick::FILTER_HERMITE,
111+
Imagick::FILTER_HANNING,
112+
Imagick::FILTER_HAMMING,
113+
Imagick::FILTER_BLACKMAN,
114+
Imagick::FILTER_GAUSSIAN,
115+
Imagick::FILTER_QUADRATIC,
116+
Imagick::FILTER_CUBIC,
117+
Imagick::FILTER_CATROM,
118+
Imagick::FILTER_MITCHELL,
119+
Imagick::FILTER_LANCZOS,
120+
Imagick::FILTER_BESSEL,
121+
Imagick::FILTER_SINC
122+
);
123+
124+
// Parse parameters given to function
125+
$columns = (double) ($columns);
126+
$rows = (double) ($rows);
127+
$bestfit = (bool) $bestfit;
128+
$fill = (bool) $fill;
129+
130+
// We can’t resize to (0,0)
131+
if ($rows < 1 && $columns < 1) {
132+
return false;
133+
}
134+
135+
// Set a default filter if an acceptable one wasn’t passed
136+
if (!in_array($filter, $filters)) {
137+
$filter = Imagick::FILTER_TRIANGLE;
138+
}
139+
140+
// figure out the output width and height
141+
$width = (double) $this->getImageWidth();
142+
$height = (double) $this->getImageHeight();
143+
$new_width = $columns;
144+
$new_height = $rows;
145+
146+
$x_factor = $columns / $width;
147+
$y_factor = $rows / $height;
148+
if ($rows < 1) {
149+
$new_height = round($x_factor * $height);
150+
} elseif ($columns < 1) {
151+
$new_width = round($y_factor * $width);
152+
}
153+
154+
// if bestfit is true, the new_width/new_height of the image will be different than
155+
// the columns/rows parameters; those will define a bounding box in which the image will be fit
156+
if ($bestfit && $x_factor > $y_factor) {
157+
$x_factor = $y_factor;
158+
$new_width = round($y_factor * $width);
159+
} elseif ($bestfit && $y_factor > $x_factor) {
160+
$y_factor = $x_factor;
161+
$new_height = round($x_factor * $height);
162+
}
163+
if ($new_width < 1) {
164+
$new_width = 1;
165+
}
166+
if ($new_height < 1) {
167+
$new_height = 1;
168+
}
169+
170+
// if we’re resizing the image to more than about 1/3 it’s original size
171+
// then just use the resize function
172+
if (($x_factor * $y_factor) > 0.1) {
173+
$this->resizeImage($new_width, $new_height, $filter, 1);
174+
175+
// if we’d be using sample to scale to smaller than 128x128, just use resize
176+
} elseif ((($SampleFactor * $new_width) < 128) || (($SampleFactor * $new_height) < 128)) {
177+
$this->resizeImage($new_width, $new_height, $filter, 1);
178+
179+
// otherwise, use sample first, then resize
180+
} else {
181+
$this->sampleImage($SampleFactor * $new_width, $SampleFactor * $new_height);
182+
$this->resizeImage($new_width, $new_height, $filter, 1);
183+
}
184+
185+
// if the alpha channel is not defined, make it opaque
186+
if ($this->getImageAlphaChannel() == Imagick::ALPHACHANNEL_UNDEFINED) {
187+
$this->setImageAlphaChannel(Imagick::ALPHACHANNEL_OPAQUE);
188+
}
189+
190+
// set the image’s bit depth to 8 bits
191+
$this->setImageDepth(8);
192+
193+
// turn off interlacing
194+
$this->setInterlaceScheme(Imagick::INTERLACE_NO);
195+
196+
// Strip all profiles except color profiles.
197+
foreach ($this->getImageProfiles('*', true) as $key => $value) {
198+
if ($key != 'icc' && $key != 'icm') {
199+
$this->removeImageProfile($key);
200+
}
201+
}
202+
203+
if (method_exists($this, 'deleteImageProperty')) {
204+
$this->deleteImageProperty('comment');
205+
$this->deleteImageProperty('Thumb::URI');
206+
$this->deleteImageProperty('Thumb::MTime');
207+
$this->deleteImageProperty('Thumb::Size');
208+
$this->deleteImageProperty('Thumb::Mimetype');
209+
$this->deleteImageProperty('software');
210+
$this->deleteImageProperty('Thumb::Image::Width');
211+
$this->deleteImageProperty('Thumb::Image::Height');
212+
$this->deleteImageProperty('Thumb::Document::Pages');
213+
} else {
214+
$this->setImageProperty('comment', '');
215+
$this->setImageProperty('Thumb::URI', '');
216+
$this->setImageProperty('Thumb::MTime', '');
217+
$this->setImageProperty('Thumb::Size', '');
218+
$this->setImageProperty('Thumb::Mimetype', '');
219+
$this->setImageProperty('software', '');
220+
$this->setImageProperty('Thumb::Image::Width', '');
221+
$this->setImageProperty('Thumb::Image::Height', '');
222+
$this->setImageProperty('Thumb::Document::Pages', '');
223+
}
224+
225+
// In case user wants to fill use extent for it rather than creating a new canvas
226+
// …fill out the bounding box
227+
if ($bestfit && $fill && ($new_width != $columns || $new_height != $rows)) {
228+
$extent_x = 0;
229+
$extent_y = 0;
230+
231+
if ($columns > $new_width) {
232+
$extent_x = ($columns - $new_width) / 2;
233+
}
234+
if ($rows > $new_height) {
235+
$extent_y = ($rows - $new_height) / 2;
236+
}
237+
238+
$this->extentImage($columns, $rows, 0 - $extent_x, $extent_y);
239+
}
240+
241+
return true;
242+
243+
}
244+
245+
}

0 commit comments

Comments
 (0)