| @@ -1,6 +1,9 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | |
| 3 | +use Optimole\Sdk\Resource\ImageProperty\ResizeTypeProperty; | |
| 4 | +use Optimole\Sdk\ValueObject\Position; | |
| 5 | + | |
| 3 | 6 | /** |
| 4 | 7 | * Normalization traits. |
| 5 | 8 | * |
| 6 | 9 | * @package \Optml\Inc\Traits |
| @@ -8,8 +11,15 @@ | ||
| 8 | 11 | */ |
| 9 | 12 | trait Optml_Normalizer { |
| 10 | 13 | |
| 11 | 14 | /** |
| 15 | + * Static cache for dimension calculations | |
| 16 | + * | |
| 17 | + * @var array | |
| 18 | + */ | |
| 19 | + private static $dimension_cache = []; | |
| 20 | + | |
| 21 | + /** | |
| 12 | 22 | * Normalize value to boolean. |
| 13 | 23 | * |
| 14 | 24 | * @param mixed $value Value to process. |
| 15 | 25 | * |
| @@ -27,8 +37,37 @@ | ||
| 27 | 37 | return boolval( $value ); |
| 28 | 38 | } |
| 29 | 39 | |
| 30 | 40 | /** |
| 41 | + * Get the unoptimized url from an Optimole url. | |
| 42 | + * Works only on non-offloaded images. | |
| 43 | + * | |
| 44 | + * @param string $url The url to get the unoptimized url for. | |
| 45 | + * | |
| 46 | + * @return string The unoptimized url. | |
| 47 | + */ | |
| 48 | + public function get_unoptimized_url( $url ) { | |
| 49 | + | |
| 50 | + // If the url is not an optimole url, return the url | |
| 51 | + if ( strpos( $url, Optml_Config::$service_url ) === false ) { | |
| 52 | + return $url; | |
| 53 | + } | |
| 54 | + // If the url is an uploaded image, return the url | |
| 55 | + if ( Optml_Media_Offload::is_uploaded_image( $url ) ) { | |
| 56 | + $pattern = '#/id:([^/]+)/((?:https?://|http://|directUpload/)\S+)#'; | |
| 57 | + if ( preg_match( $pattern, $url, $matches ) ) { | |
| 58 | + $url = $matches[0]; | |
| 59 | + } | |
| 60 | + return $url; | |
| 61 | + } | |
| 62 | + | |
| 63 | + $url_parts = explode( 'http', $url ); | |
| 64 | + if ( ! isset( $url_parts[2] ) ) { | |
| 65 | + return $url; | |
| 66 | + } | |
| 67 | + return 'http' . $url_parts[2]; | |
| 68 | + } | |
| 69 | + /** | |
| 31 | 70 | * Return domain hash. |
| 32 | 71 | * |
| 33 | 72 | * @param string $domain Full url. |
| 34 | 73 | * |
| @@ -46,14 +85,14 @@ | ||
| 46 | 85 | } |
| 47 | 86 | /** |
| 48 | 87 | * Strip slashes on unicode encoded strings. |
| 49 | 88 | * |
| 50 | - * @param string $string Input string. | |
| 89 | + * @param string $content Input string. | |
| 51 | 90 | * |
| 52 | 91 | * @return string Decoded string. |
| 53 | 92 | */ |
| 54 | - public function strip_slashes( $string ) { | |
| 55 | - return html_entity_decode( stripslashes( preg_replace( '/\\\u([\da-fA-F]{4})/', '&#x\1;', $string ) ) ); | |
| 93 | + public function strip_slashes( $content ) { | |
| 94 | + return html_entity_decode( stripslashes( preg_replace( '/\\\u([\da-fA-F]{4})/', '&#x\1;', $content ) ) ); | |
| 56 | 95 | } |
| 57 | 96 | |
| 58 | 97 | /** |
| 59 | 98 | * Normalize value to positive integer. |
| @@ -72,18 +111,18 @@ | ||
| 72 | 111 | * Normalize value to map. |
| 73 | 112 | * |
| 74 | 113 | * @param mixed $value Value to process. |
| 75 | 114 | * @param array $map Associative list from witch to return. |
| 76 | - * @param mixed $default Default. | |
| 115 | + * @param mixed $initial Default. | |
| 77 | 116 | * |
| 78 | 117 | * @return mixed |
| 79 | 118 | */ |
| 80 | - public function to_map_values( $value, $map, $default ) { | |
| 119 | + public function to_map_values( $value, $map, $initial ) { | |
| 81 | 120 | if ( in_array( $value, $map, true ) ) { |
| 82 | 121 | return $value; |
| 83 | 122 | } |
| 84 | 123 | |
| 85 | - return $default; | |
| 124 | + return $initial; | |
| 86 | 125 | } |
| 87 | 126 | |
| 88 | 127 | /** |
| 89 | 128 | * Normalize value to an accepted quality. |
| @@ -151,8 +190,79 @@ | ||
| 151 | 190 | return $integer; |
| 152 | 191 | } |
| 153 | 192 | |
| 154 | 193 | /** |
| 194 | + * Convert image size to dimensions. | |
| 195 | + * | |
| 196 | + * This function takes an image size and its metadata, and returns the dimensions | |
| 197 | + * of the image based on the specified size. It handles different cases such as | |
| 198 | + * custom sizes, predefined sizes, and full size. | |
| 199 | + * | |
| 200 | + * @param mixed $size The size of the image. Can be an array of width and height, a predefined size, or 'full'. | |
| 201 | + * @param array $image_meta Metadata of the image, including width and height. | |
| 202 | + * @param int $attachment_id The ID of the attachment. | |
| 203 | + * | |
| 204 | + * @return array The dimensions of the image, including width, height, and optional resize parameters. | |
| 205 | + */ | |
| 206 | + public function size_to_dimension( $size, $image_meta, $attachment_id = null ) { | |
| 207 | + // default size | |
| 208 | + $sizes = [ | |
| 209 | + 'width' => isset( $image_meta['width'] ) ? intval( $image_meta['width'] ) : false, | |
| 210 | + 'height' => isset( $image_meta['height'] ) ? intval( $image_meta['height'] ) : false, | |
| 211 | + ]; | |
| 212 | + $image_args = Optml_App_Replacer::image_sizes(); | |
| 213 | + $sizes2crop = Optml_App_Replacer::size_to_crop(); | |
| 214 | + switch ( $size ) { | |
| 215 | + case is_array( $size ): | |
| 216 | + $width = isset( $size[0] ) ? (int) $size[0] : false; | |
| 217 | + $height = isset( $size[1] ) ? (int) $size[1] : false; | |
| 218 | + if ( ! $width || ! $height ) { | |
| 219 | + break; | |
| 220 | + } | |
| 221 | + $cache_key = 'a' . $width . '_' . $height . '_' . $sizes['width'] . '_' . $sizes['height']; | |
| 222 | + if ( isset( self::$dimension_cache[ $cache_key ] ) ) { | |
| 223 | + return self::$dimension_cache[ $cache_key ]; | |
| 224 | + } | |
| 225 | + if ( $attachment_id ) { | |
| 226 | + $intermediate = image_get_intermediate_size( $attachment_id, $size ); | |
| 227 | + if ( $intermediate ) { | |
| 228 | + $sizes['width'] = $intermediate['width']; | |
| 229 | + $sizes['height'] = $intermediate['height']; | |
| 230 | + } | |
| 231 | + } | |
| 232 | + | |
| 233 | + list( $sizes['width'], $sizes['height'] ) = image_constrain_size_for_editor( $sizes['width'], $sizes['height'], $size ); | |
| 234 | + $resize = apply_filters( 'optml_default_crop', [] ); | |
| 235 | + if ( isset( $sizes2crop[ $sizes['width'] . $sizes['height'] ] ) ) { | |
| 236 | + $resize = $this->to_optml_crop( $sizes2crop[ $sizes['width'] . $sizes['height'] ] ); | |
| 237 | + } | |
| 238 | + $sizes['resize'] = $resize; | |
| 239 | + self::$dimension_cache[ $cache_key ] = $sizes; | |
| 240 | + break; | |
| 241 | + case 'full' !== $size && isset( $image_args[ $size ] ): | |
| 242 | + $cache_key = 'b' . $size . '_' . $sizes['width'] . '_' . $sizes['height']; | |
| 243 | + if ( isset( self::$dimension_cache[ $cache_key ] ) ) { | |
| 244 | + return self::$dimension_cache[ $cache_key ]; | |
| 245 | + } | |
| 246 | + $image_resized = image_resize_dimensions( $sizes['width'], $sizes['height'], $image_args[ $size ]['width'], $image_args[ $size ]['height'], $image_args[ $size ]['crop'] ); | |
| 247 | + | |
| 248 | + if ( $image_resized ) { // This could be false when the requested image size is larger than the full-size image. | |
| 249 | + $sizes['width'] = $image_resized[6]; | |
| 250 | + $sizes['height'] = $image_resized[7]; | |
| 251 | + } | |
| 252 | + // There are cases when the image meta is missing and image size is non existent, see SVG image handling. | |
| 253 | + if ( ! $sizes['width'] || ! $sizes['height'] ) { | |
| 254 | + break; | |
| 255 | + } | |
| 256 | + list( $sizes['width'], $sizes['height'] ) = image_constrain_size_for_editor( $sizes['width'], $sizes['height'], $size, 'display' ); | |
| 257 | + | |
| 258 | + $sizes['resize'] = $this->to_optml_crop( $image_args[ $size ]['crop'] ); | |
| 259 | + self::$dimension_cache[ $cache_key ] = $sizes; | |
| 260 | + break; | |
| 261 | + } | |
| 262 | + return $sizes; | |
| 263 | + } | |
| 264 | + /** | |
| 155 | 265 | * Normalize arguments for crop. |
| 156 | 266 | * |
| 157 | 267 | * @param array|bool $crop_args Crop arguments. |
| 158 | 268 | * |
| @@ -166,11 +276,11 @@ | ||
| 166 | 276 | $crop_args = $crop_args['crop']; |
| 167 | 277 | } |
| 168 | 278 | if ( $crop_args === true ) { |
| 169 | 279 | return [ |
| 170 | - 'type' => Optml_Resize::RESIZE_FILL, | |
| 280 | + 'type' => ResizeTypeProperty::FILL, | |
| 171 | 281 | 'enlarge' => $enlarge, |
| 172 | - 'gravity' => Optml_Resize::GRAVITY_CENTER, | |
| 282 | + 'gravity' => Position::CENTER, | |
| 173 | 283 | ]; |
| 174 | 284 | } |
| 175 | 285 | if ( $crop_args === false || ! is_array( $crop_args ) || count( $crop_args ) !== 2 ) { |
| 176 | 286 | return []; |
| @@ -186,16 +296,16 @@ | ||
| 186 | 296 | 'center' => true, |
| 187 | 297 | 'bottom' => true, |
| 188 | 298 | ]; |
| 189 | 299 | $allowed_gravities = [ |
| 190 | - 'left' => Optml_Resize::GRAVITY_WEST, | |
| 191 | - 'right' => Optml_Resize::GRAVITY_EAST, | |
| 192 | - 'top' => Optml_Resize::GRAVITY_NORTH, | |
| 193 | - 'bottom' => Optml_Resize::GRAVITY_SOUTH, | |
| 194 | - 'lefttop' => Optml_Resize::GRAVITY_NORTH_WEST, | |
| 195 | - 'leftbottom' => Optml_Resize::GRAVITY_SOUTH_WEST, | |
| 196 | - 'righttop' => Optml_Resize::GRAVITY_NORTH_EAST, | |
| 197 | - 'rightbottom' => Optml_Resize::GRAVITY_SOUTH_EAST, | |
| 300 | + 'left' => Position::WEST, | |
| 301 | + 'right' => Position::EAST, | |
| 302 | + 'top' => Position::NORTH, | |
| 303 | + 'bottom' => Position::SOUTH, | |
| 304 | + 'lefttop' => Position::NORTH_WEST, | |
| 305 | + 'leftbottom' => Position::SOUTH_WEST, | |
| 306 | + 'righttop' => Position::NORTH_EAST, | |
| 307 | + 'rightbottom' => Position::SOUTH_EAST, | |
| 198 | 308 | 'centertop' => [ 0.5, 0 ], |
| 199 | 309 | 'centerbottom' => [ 0.5, 1 ], |
| 200 | 310 | 'leftcenter' => [ 0, 0.5 ], |
| 201 | 311 | 'rightcenter' => [ 1, 0.5 ], |
| @@ -200,13 +310,13 @@ | ||
| 200 | 310 | 'leftcenter' => [ 0, 0.5 ], |
| 201 | 311 | 'rightcenter' => [ 1, 0.5 ], |
| 202 | 312 | ]; |
| 203 | 313 | |
| 204 | - $gravity = Optml_Resize::GRAVITY_CENTER; | |
| 314 | + $gravity = Position::CENTER; | |
| 205 | 315 | $key_search = ( $crop_args[0] === true ? '' : |
| 206 | 316 | ( isset( $allowed_x[ $crop_args[0] ] ) ? $crop_args[0] : '' ) ) . |
| 207 | - ( $crop_args[1] === true ? '' : | |
| 208 | - ( isset( $allowed_y[ $crop_args[1] ] ) ? $crop_args[1] : '' ) ); | |
| 317 | + ( $crop_args[1] === true ? '' : | |
| 318 | + ( isset( $allowed_y[ $crop_args[1] ] ) ? $crop_args[1] : '' ) ); | |
| 209 | 319 | |
| 210 | 320 | if ( array_key_exists( $key_search, $allowed_gravities ) ) { |
| 211 | 321 | $gravity = $allowed_gravities[ $key_search ]; |
| 212 | 322 | } |
| @@ -211,9 +321,9 @@ | ||
| 211 | 321 | $gravity = $allowed_gravities[ $key_search ]; |
| 212 | 322 | } |
| 213 | 323 | |
| 214 | 324 | return [ |
| 215 | - 'type' => Optml_Resize::RESIZE_FILL, | |
| 325 | + 'type' => ResizeTypeProperty::FILL, | |
| 216 | 326 | 'enlarge' => $enlarge, |
| 217 | 327 | 'gravity' => $gravity, |
| 218 | 328 | ]; |
| 219 | 329 | } |
| @@ -226,18 +336,18 @@ | ||
| 226 | 336 | * @return array |
| 227 | 337 | */ |
| 228 | 338 | public function to_optml_watermark( $watermark_args = [] ) { |
| 229 | 339 | $allowed_gravities = [ |
| 230 | - 'left' => Optml_Resize::GRAVITY_WEST, | |
| 231 | - 'right' => Optml_Resize::GRAVITY_EAST, | |
| 232 | - 'top' => Optml_Resize::GRAVITY_NORTH, | |
| 233 | - 'bottom' => Optml_Resize::GRAVITY_SOUTH, | |
| 234 | - 'left_top' => Optml_Resize::GRAVITY_NORTH_WEST, | |
| 235 | - 'left_bottom' => Optml_Resize::GRAVITY_SOUTH_WEST, | |
| 236 | - 'right_top' => Optml_Resize::GRAVITY_NORTH_EAST, | |
| 237 | - 'right_bottom' => Optml_Resize::GRAVITY_SOUTH_EAST, | |
| 340 | + 'left' => Position::WEST, | |
| 341 | + 'right' => Position::EAST, | |
| 342 | + 'top' => Position::NORTH, | |
| 343 | + 'bottom' => Position::SOUTH, | |
| 344 | + 'left_top' => Position::NORTH_WEST, | |
| 345 | + 'left_bottom' => Position::SOUTH_WEST, | |
| 346 | + 'right_top' => Position::NORTH_EAST, | |
| 347 | + 'right_bottom' => Position::SOUTH_EAST, | |
| 238 | 348 | ]; |
| 239 | - $gravity = Optml_Resize::GRAVITY_CENTER; | |
| 349 | + $gravity = Position::CENTER; | |
| 240 | 350 | if ( isset( $watermark_args['position'] ) && array_key_exists( $watermark_args['position'], $allowed_gravities ) ) { |
| 241 | 351 | $gravity = $allowed_gravities[ $watermark_args['position'] ]; |
| 242 | 352 | } |
| 243 | 353 | |
| @@ -261,9 +371,9 @@ | ||
| 261 | 371 | } else { |
| 262 | 372 | $should_add_schema = substr( $schema_url, 0, strlen( '//' ) ) === '//'; |
| 263 | 373 | } |
| 264 | 374 | if ( $should_add_schema ) { |
| 265 | - $schema_url = is_ssl() ? 'https:' : 'http:' . $schema_url; | |
| 375 | + $schema_url = ( is_ssl() ? 'https:' : 'http:' ) . $schema_url; | |
| 266 | 376 | } |
| 267 | 377 | return $schema_url; |
| 268 | 378 | } |
| 269 | 379 | } |