Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 61
0.00% covered (danger)
0.00%
0 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
Image_CDN_Image
0.00% covered (danger)
0.00%
0 / 61
0.00% covered (danger)
0.00%
0 / 13
342
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 resize
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 get_size
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 reset_to_original
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 get_filename
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_raw_filename
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 get_width
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_height
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_mime_type
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 is_resized
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_resized_filename
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
 image_resize_dimensions
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
6
 set_width_height
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
1<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2/**
3 * The Image Class.
4 *
5 * @package automattic/jetpack-image-cdn
6 */
7
8namespace Automattic\Jetpack\Image_CDN;
9
10use WP_Error;
11
12/**
13 * Represents a resizable image, exposing properties necessary for properly generating srcset.
14 */
15class Image_CDN_Image {
16
17    /**
18     * Attachment's Filename.
19     *
20     * @var string
21     */
22    public $filename;
23
24    /**
25     * Attachment's mime-type, WP_Error on failure when recalculating the dimensions.
26     *
27     * @var string|WP_Error
28     */
29    private $mime_type;
30
31    /**
32     * Image original width.
33     *
34     * @var int
35     */
36    private $original_width;
37
38    /**
39     * Image original height.
40     *
41     * @var int
42     */
43    private $original_height;
44
45    /**
46     * Current attachment's width.
47     *
48     * @var int
49     */
50    private $width;
51
52    /**
53     * Current attachment's height.
54     *
55     * @var int
56     */
57    private $height;
58
59    /**
60     * Whether the attachment has been resized yet, or not.
61     *
62     * @var bool
63     */
64    private $is_resized = false;
65
66    /**
67     * Constructs the image object.
68     *
69     * The $data array should provide at least
70     *  file   : string Image file path
71     *  width  : int    Image width
72     *  height : int    Image height
73     *
74     * @param array           $data                Array of attachment metadata, typically value of _wp_attachment_metadata postmeta.
75     * @param string|WP_Error $mime_type Typically value returned from get_post_mime_type function.
76     */
77    public function __construct( $data, $mime_type ) {
78        $this->filename        = $data['file'];
79        $this->original_width  = $data['width'];
80        $this->original_height = $data['height'];
81        $this->width           = $this->original_width;
82        $this->height          = $this->original_height;
83        $this->mime_type       = $mime_type;
84    }
85
86    /**
87     * Resizes the image to given size.
88     *
89     * @param array $size_data Array of width, height, and crop properties of a size.
90     *
91     * @return bool|WP_Error True if resize was successful, WP_Error on failure.
92     */
93    public function resize( $size_data ) {
94
95        $dimensions = $this->image_resize_dimensions( $size_data['width'], $size_data['height'], $size_data['crop'] );
96
97        if ( true === is_wp_error( $dimensions ) ) {
98            return $dimensions; // Returns WP_Error.
99        }
100
101        if ( true === is_wp_error( $this->mime_type ) ) {
102            return $this->mime_type; // Returns WP_Error.
103        }
104
105        $this->set_width_height( $dimensions );
106
107        $this->is_resized = true;
108
109        return true;
110    }
111
112    /**
113     * Generates size data for usage in $metadata['sizes'];.
114     *
115     * @param array $size_data Array of width, height, and crop properties of a size.
116     *
117     * @return array|WP_Error An array containing file, width, height, and mime-type keys and it's values. WP_Error on failure.
118     */
119    public function get_size( $size_data ) {
120
121        $is_resized = $this->resize( $size_data );
122
123        if ( true === is_wp_error( $is_resized ) ) {
124            return $is_resized;
125        }
126
127        return array(
128            'file'      => $this->get_filename(),
129            'width'     => $this->get_width(),
130            'height'    => $this->get_height(),
131            'mime-type' => $this->get_mime_type(),
132        );
133    }
134
135    /**
136     * Resets the image to it's original dimensions.
137     *
138     * @return bool True on successful reset to original dimensions.
139     */
140    public function reset_to_original() {
141        $this->width      = $this->original_width;
142        $this->height     = $this->original_height;
143        $this->is_resized = false;
144
145        return true;
146    }
147
148    /**
149     * Return the basename filename. If the image has been resized, including
150     * the resizing params for Jetpack CDN.
151     *
152     * @return string Basename of the filename.
153     */
154    public function get_filename() {
155        return wp_basename( $this->get_raw_filename() );
156    }
157
158    /**
159     * Return the absolute filename. If the image has been resized, including
160     * the resizing params for Jetpack CDN.
161     *
162     * @return string Filename.
163     */
164    public function get_raw_filename() {
165        return $this->is_resized() ? $this->get_resized_filename() : $this->filename;
166    }
167
168    /**
169     * Returns current image width. Either original, or after resize.
170     *
171     * @return int
172     */
173    public function get_width() {
174        return (int) $this->width;
175    }
176
177    /**
178     * Returns current image height. Either original, or after resize.
179     *
180     * @return int
181     */
182    public function get_height() {
183        return (int) $this->height;
184    }
185
186    /**
187     * Returns image mime type.
188     *
189     * @return string|WP_Error Image's mime type or WP_Error if it was not determined.
190     */
191    public function get_mime_type() {
192        return $this->mime_type;
193    }
194
195    /**
196     * Checks the resize status of the image.
197     *
198     * @return bool If the image has been resized.
199     */
200    public function is_resized() {
201        return ( true === $this->is_resized );
202    }
203
204    /**
205     * Get filename with proper args for the Photon service.
206     *
207     * @return string Filename with query args for Photon service
208     */
209    protected function get_resized_filename() {
210        $query_args = array(
211            'resize' => implode(
212                ',',
213                array(
214                    $this->get_width(),
215                    $this->get_height(),
216                )
217            ),
218        );
219
220        return add_query_arg( $query_args, $this->filename );
221    }
222
223    /**
224     * Get resize dimensions used for the Jetpack CDN service.
225     *
226     * Converts the list of values returned from `image_resize_dimensions()` to
227     * associative array for the sake of more readable code no relying on index
228     * nor `list`.
229     *
230     * @param int        $max_width  Maximum width.
231     * @param int        $max_height Maximum height.
232     * @param bool|array $crop       Cropping parameters.
233     *
234     * @return array|WP_Error Array of dimensions matching the parameters to imagecopyresampled. WP_Error on failure.
235     */
236    protected function image_resize_dimensions( $max_width, $max_height, $crop ) {
237        $dimensions = image_resize_dimensions( $this->original_width, $this->original_height, $max_width, $max_height, $crop );
238        if ( ! $dimensions ) {
239            return new WP_Error( 'error_getting_dimensions', __( 'Could not calculate resized image dimensions', 'jetpack-image-cdn' ), $this->filename );
240        }
241
242        return array_combine(
243            array(
244                'dst_x',
245                'dst_y',
246                'src_x',
247                'src_y',
248                'dst_w',
249                'dst_h',
250                'src_w',
251                'src_h',
252            ),
253            $dimensions
254        );
255    }
256
257    /**
258     * Sets proper width and height from dimensions.
259     *
260     * @param array $dimensions an array of image dimensions.
261     * @return void
262     */
263    protected function set_width_height( $dimensions ) {
264        $this->width  = (int) $dimensions['dst_w'];
265        $this->height = (int) $dimensions['dst_h'];
266    }
267}