Changeset 3458273
- Timestamp:
- 02/10/2026 05:08:59 PM (8 days ago)
- Location:
- imsanity
- Files:
-
- 2 added
- 14 edited
- 1 copied
-
tags/2.9.0 (copied) (copied from imsanity/trunk)
-
tags/2.9.0/changelog.txt (modified) (1 diff)
-
tags/2.9.0/class-imsanity-cli.php (modified) (1 diff)
-
tags/2.9.0/imsanity.php (modified) (16 diffs)
-
tags/2.9.0/libs/debug.php (added)
-
tags/2.9.0/libs/utils.php (modified) (24 diffs)
-
tags/2.9.0/media.php (modified) (1 diff)
-
tags/2.9.0/readme.txt (modified) (2 diffs)
-
tags/2.9.0/settings.php (modified) (13 diffs)
-
trunk/changelog.txt (modified) (1 diff)
-
trunk/class-imsanity-cli.php (modified) (1 diff)
-
trunk/imsanity.php (modified) (16 diffs)
-
trunk/libs/debug.php (added)
-
trunk/libs/utils.php (modified) (24 diffs)
-
trunk/media.php (modified) (1 diff)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/settings.php (modified) (13 diffs)
Legend:
- Unmodified
- Added
- Removed
-
imsanity/tags/2.9.0/changelog.txt
r3340527 r3458273 1 = 2.9.0 = 2 *Release Date - February 10, 2026* 3 4 * added: support for resizing AVIF image uploads 5 * added: settings for WebP and AVIF quality 6 * added: support for Modern Image Formats plugin 7 * added: PHP 8.5 compatibility 8 * fixed: quality settings not applied 9 * fixed: PNG alpha detection may throw errors if PHP GD cannot obtain information from a PNG image 10 1 11 = 2.8.7 = 2 12 *Release Date = August 6, 2024* -
imsanity/tags/2.9.0/class-imsanity-cli.php
r2969420 r3458273 76 76 $path = get_attached_file( $id ); 77 77 if ( $path ) { 78 list( $imagew, $imageh ) = getimagesize( $path ); 78 $dimensions = getimagesize( $path ); 79 if ( is_array( $dimensions ) && count( $dimensions ) >= 2 ) { 80 $imagew = $dimensions[0]; 81 $imageh = $dimensions[1]; 82 } 79 83 } 80 84 if ( empty( $imagew ) || empty( $imageh ) ) { -
imsanity/tags/2.9.0/imsanity.php
r3340527 r3458273 15 15 Author: Exactly WWW 16 16 Domain Path: /languages 17 Version: 2. 8.718 Requires at least: 6. 517 Version: 2.9.0 18 Requires at least: 6.6 19 19 Requires PHP: 7.4 20 20 Author URI: https://ewww.io/about/ … … 26 26 } 27 27 28 define( 'IMSANITY_VERSION', '2. 8.7' );28 define( 'IMSANITY_VERSION', '2.9.0' ); 29 29 define( 'IMSANITY_SCHEMA_VERSION', '1.1' ); 30 30 … … 34 34 define( 'IMSANITY_DEFAULT_PNG_TO_JPG', false ); 35 35 define( 'IMSANITY_DEFAULT_QUALITY', 82 ); 36 define( 'IMSANITY_DEFAULT_AVIF_QUALITY', 86 ); 37 define( 'IMSANITY_DEFAULT_WEBP_QUALITY', 86 ); 36 38 37 39 define( 'IMSANITY_SOURCE_POST', 1 ); … … 45 47 */ 46 48 define( 'IMSANITY_PLUGIN_FILE', __FILE__ ); 49 50 /** 51 * The directory path of the main plugin file. 52 * 53 * @var string IMSANITY_PLUGIN_DIR 54 */ 55 define( 'IMSANITY_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); 56 47 57 /** 48 58 * The path of the main plugin file, relative to the plugins/ folder. … … 62 72 * Import supporting libraries. 63 73 */ 74 require_once plugin_dir_path( __FILE__ ) . 'libs/debug.php'; 64 75 require_once plugin_dir_path( __FILE__ ) . 'libs/utils.php'; 65 76 require_once plugin_dir_path( __FILE__ ) . 'settings.php'; … … 68 79 if ( defined( 'WP_CLI' ) && WP_CLI ) { 69 80 require_once plugin_dir_path( __FILE__ ) . 'class-imsanity-cli.php'; 70 }71 72 /**73 * Use the EWWW IO debugging functions (if available).74 *75 * @param string $message A message to send to the debugger.76 */77 function imsanity_debug( $message ) {78 if ( function_exists( 'ewwwio_debug_message' ) ) {79 if ( ! is_string( $message ) ) {80 if ( function_exists( 'print_r' ) ) {81 $message = print_r( $message, true );82 } else {83 $message = 'not a string, print_r disabled';84 }85 }86 ewwwio_debug_message( $message );87 if ( function_exists( 'ewww_image_optimizer_debug_log' ) ) {88 ewww_image_optimizer_debug_log();89 }90 }91 81 } 92 82 … … 175 165 */ 176 166 function imsanity_handle_upload( $params ) { 167 imsanity_debug( __FUNCTION__ ); 168 169 if ( empty( $params['file'] ) || empty( $params['type'] ) ) { 170 imsanity_debug( 'missing file or type parameter, skipping' ); 171 return $params; 172 } 177 173 178 174 // If "noresize" is included in the filename then we will bypass imsanity scaling. 179 175 if ( strpos( $params['file'], 'noresize' ) !== false ) { 176 imsanity_debug( "skipping {$params['file']}" ); 180 177 return $params; 181 178 } 182 179 183 180 if ( apply_filters( 'imsanity_skip_image', false, $params['file'] ) ) { 181 imsanity_debug( "skipping {$params['file']} per filter" ); 184 182 return $params; 185 183 } … … 194 192 } 195 193 196 // Make sure this is a type of image that we want to convert and that it exists.194 // Store the path for reference in case $params is modified. 197 195 $oldpath = $params['file']; 198 196 199 197 // Let folks filter the allowed mime-types for resizing. 198 // Also allows conditional support for WebP and AVIF if the server supports it. 200 199 $allowed_types = apply_filters( 'imsanity_allowed_mimes', array( 'image/png', 'image/gif', 'image/jpeg' ), $oldpath ); 201 200 if ( is_string( $allowed_types ) ) { … … 213 212 in_array( $params['type'], $allowed_types, true ) 214 213 ) { 214 // If the Modern Image Formats plugin is active but fallback mode is disabled, permit conversion to AVIF/WebP during upload by defining IMSANITY_ALLOW_CONVERSION. 215 // Otherwise, no conversion should be allowed at all. The upload handler will still check for conversion and work with it if it happens somehow. 216 if ( ! defined( 'IMSANITY_ALLOW_CONVERSION' ) && function_exists( 'webp_uploads_is_fallback_enabled' ) && ! webp_uploads_is_fallback_enabled() ) { 217 define( 'IMSANITY_ALLOW_CONVERSION', true ); 218 } 215 219 216 220 // figure out where the upload is coming from. … … 226 230 $maxh = (int) $maxh; 227 231 228 list( $oldw, $oldh ) = getimagesize( $oldpath ); 232 $dimensions = getimagesize( $oldpath ); 233 if ( is_array( $dimensions ) && count( $dimensions ) >= 2 ) { 234 $oldw = $dimensions[0]; 235 $oldh = $dimensions[1]; 236 } else { 237 imsanity_debug( "could not get dimensions for $oldpath, skipping" ); 238 return $params; 239 } 229 240 230 241 if ( ( $oldw > $maxw + 1 && $maxw > 0 ) || ( $oldh > $maxh + 1 && $maxh > 0 ) ) { 231 $quality = imsanity_get_option( 'imsanity_quality', IMSANITY_DEFAULT_QUALITY );232 242 233 243 $ftype = imsanity_quick_mimetype( $oldpath ); … … 253 263 $original_preempt = $ewww_preempt_editor; 254 264 $ewww_preempt_editor = true; 255 $resizeresult = imsanity_image_resize( $oldpath, $neww, $newh, apply_filters( 'imsanity_crop_image', false ) , null, null, $quality);265 $resizeresult = imsanity_image_resize( $oldpath, $neww, $newh, apply_filters( 'imsanity_crop_image', false ) ); 256 266 $ewww_preempt_editor = $original_preempt; 257 267 258 268 if ( $resizeresult && ! is_wp_error( $resizeresult ) ) { 259 $newpath = $resizeresult; 260 269 $newpath = $resizeresult; 270 $new_type = $params['type']; 271 272 imsanity_debug( "checking $newpath to see if resize was successful" ); 261 273 if ( is_file( $newpath ) && filesize( $newpath ) < filesize( $oldpath ) ) { 274 imsanity_debug( 'resized image is smaller, replacing original' ); 262 275 // We saved some file space. remove original and replace with resized image. 276 $new_type = imsanity_mimetype( $newpath ); 263 277 unlink( $oldpath ); 264 278 rename( $newpath, $oldpath ); 279 if ( $new_type && $new_type !== $params['type'] ) { 280 imsanity_debug( "mimetype changed from {$params['type']} to $new_type" ); 281 $params['type'] = $new_type; 282 $params['file'] = imsanity_update_extension( $oldpath, $new_type ); 283 if ( $params['file'] !== $oldpath ) { 284 rename( $oldpath, $params['file'] ); 285 } 286 $params['url'] = imsanity_update_extension( $params['url'], $new_type ); 287 imsanity_debug( "renamed file to match new extension: {$params['file']} / {$params['url']}" ); 288 } 265 289 } elseif ( is_file( $newpath ) ) { 290 imsanity_debug( 'resized image is bigger, discarding' ); 266 291 // The resized image is actually bigger in filesize (most likely due to jpg quality). 267 292 // Keep the old one and just get rid of the resized image. … … 269 294 } 270 295 } elseif ( false === $resizeresult ) { 296 imsanity_debug( 'resize returned false, unknown error' ); 271 297 return $params; 272 298 } elseif ( is_wp_error( $resizeresult ) ) { … … 284 310 ) 285 311 ); 312 imsanity_debug( 'resize result is wp_error, should have already output error to log' ); 286 313 } else { 314 imsanity_debug( 'unknown resize result, inconceivable!' ); 287 315 return $params; 288 316 } … … 304 332 */ 305 333 function imsanity_convert_to_jpg( $type, $params ) { 334 imsanity_debug( __FUNCTION__ ); 306 335 307 336 if ( apply_filters( 'imsanity_disable_convert', false, $type, $params ) ) { 337 imsanity_debug( "skipping conversion for {$params['file']}" ); 308 338 return $params; 309 339 } … … 313 343 if ( 'bmp' === $type ) { 314 344 if ( ! function_exists( 'imagecreatefrombmp' ) ) { 345 imsanity_debug( 'imagecreatefrombmp does not exist' ); 315 346 return $params; 316 347 } … … 372 403 // Outputs the actual column information for each attachment. 373 404 add_action( 'manage_media_custom_column', 'imsanity_custom_column', 10, 2 ); 405 // Checks for AVIF support and adds it to the allowed mime types. 406 add_filter( 'imsanity_allowed_mimes', 'imsanity_add_avif_support' ); 374 407 // Checks for WebP support and adds it to the allowed mime types. 375 408 add_filter( 'imsanity_allowed_mimes', 'imsanity_add_webp_support' ); -
imsanity/tags/2.9.0/libs/utils.php
r2969420 r3458273 49 49 } 50 50 return ''; 51 } 52 53 /** 54 * Checks the filename for a protocal wrapper (like s3://). 55 * 56 * @param string $path The path of the file to check. 57 * @return bool True if the file contains :// indicating a stream wrapper. 58 */ 59 function imsanity_file_is_stream_wrapped( $path ) { 60 if ( false !== strpos( $path, '://' ) ) { 61 return true; 62 } 63 return false; 51 64 } 52 65 … … 70 83 case 'pdf': 71 84 return 'application/pdf'; 85 case 'avif': 86 return 'image/avif'; 72 87 case 'webp': 73 88 return 'image/webp'; … … 75 90 return false; 76 91 } 92 } 93 94 /** 95 * Check the mimetype of the given file with magic mime strings/patterns. 96 * 97 * @param string $path The absolute path to the file. 98 * @return bool|string A valid mime-type or false. 99 */ 100 function imsanity_mimetype( $path ) { 101 imsanity_debug( "testing mimetype: $path" ); 102 $type = false; 103 // For S3 images/files, don't attempt to read the file, just use the quick (filename) mime check. 104 if ( imsanity_file_is_stream_wrapped( $path ) ) { 105 return imsanity_quick_mimetype( $path ); 106 } 107 $path = \realpath( $path ); 108 if ( ! is_file( $path ) ) { 109 imsanity_debug( "$path is not a file, or out of bounds" ); 110 return $type; 111 } 112 if ( ! is_readable( $path ) ) { 113 imsanity_debug( "$path is not readable" ); 114 return $type; 115 } 116 $file_handle = fopen( $path, 'rb' ); 117 $file_contents = fread( $file_handle, 4096 ); 118 if ( $file_contents ) { 119 // Read first 12 bytes, which equates to 24 hex characters. 120 $magic = bin2hex( substr( $file_contents, 0, 12 ) ); 121 imsanity_debug( $magic ); 122 if ( 8 === strpos( $magic, '6674797061766966' ) ) { 123 $type = 'image/avif'; 124 imsanity_debug( "imsanity type: $type" ); 125 return $type; 126 } 127 if ( '424d' === substr( $magic, 0, 4 ) ) { 128 $type = 'image/bmp'; 129 imsanity_debug( "imsanity type: $type" ); 130 return $type; 131 } 132 if ( 0 === strpos( $magic, '52494646' ) && 16 === strpos( $magic, '57454250' ) ) { 133 $type = 'image/webp'; 134 imsanity_debug( "imsanity type: $type" ); 135 return $type; 136 } 137 if ( 'ffd8ff' === substr( $magic, 0, 6 ) ) { 138 $type = 'image/jpeg'; 139 imsanity_debug( "imsanity type: $type" ); 140 return $type; 141 } 142 if ( '89504e470d0a1a0a' === substr( $magic, 0, 16 ) ) { 143 $type = 'image/png'; 144 imsanity_debug( "imsanity type: $type" ); 145 return $type; 146 } 147 if ( '474946383761' === substr( $magic, 0, 12 ) || '474946383961' === substr( $magic, 0, 12 ) ) { 148 $type = 'image/gif'; 149 imsanity_debug( "imsanity type: $type" ); 150 return $type; 151 } 152 if ( '25504446' === substr( $magic, 0, 8 ) ) { 153 $type = 'application/pdf'; 154 imsanity_debug( "imsanity type: $type" ); 155 return $type; 156 } 157 if ( preg_match( '/<svg/', $file_contents ) ) { 158 $type = 'image/svg+xml'; 159 imsanity_debug( "imsanity type: $type" ); 160 return $type; 161 } 162 imsanity_debug( "match not found for file: $magic" ); 163 } else { 164 imsanity_debug( 'could not open for reading' ); 165 } 166 return false; 167 } 168 169 /** 170 * Update the file extension based on the new mime type. 171 * 172 * @param string $path The path of the file to update. 173 * @param string $new_mime The new mime type. 174 * @return string The updated path with the new extension. 175 */ 176 function imsanity_update_extension( $path, $new_mime ) { 177 $extension = ''; 178 switch ( $new_mime ) { 179 case 'image/jpeg': 180 $extension = 'jpg'; 181 break; 182 case 'image/png': 183 $extension = 'png'; 184 break; 185 case 'image/gif': 186 $extension = 'gif'; 187 break; 188 case 'image/avif': 189 $extension = 'avif'; 190 break; 191 case 'image/webp': 192 $extension = 'webp'; 193 break; 194 default: 195 return $path; 196 } 197 $pathinfo = pathinfo( $path ); 198 if ( empty( $pathinfo['dirname'] ) || empty( $pathinfo['filename'] ) ) { 199 return $path; 200 } 201 $new_name = trailingslashit( $pathinfo['dirname'] ) . $pathinfo['filename'] . '.' . $extension; 202 return $new_name; 203 } 204 205 /** 206 * Check for AVIF support in the image editor and add to the list of allowed mimes. 207 * 208 * @param array $mimes A list of allowed mime types. 209 * @return array The updated list of mimes after checking AVIF support. 210 */ 211 function imsanity_add_avif_support( $mimes ) { 212 if ( ! in_array( 'image/avif', $mimes, true ) ) { 213 if ( class_exists( 'Imagick' ) ) { 214 $imagick = new Imagick(); 215 $formats = $imagick->queryFormats(); 216 if ( in_array( 'AVIF', $formats, true ) ) { 217 $mimes[] = 'image/avif'; 218 } 219 } 220 } 221 return $mimes; 77 222 } 78 223 … … 120 265 */ 121 266 function imsanity_has_alpha( $filename ) { 267 imsanity_debug( __FUNCTION__ ); 122 268 if ( ! is_file( $filename ) ) { 123 269 return false; … … 131 277 // If we do not have GD and the PNG color type is RGB alpha or Grayscale alpha. 132 278 if ( ! imsanity_gd_support() && ( 4 === $color_type || 6 === $color_type ) ) { 279 imsanity_debug( "color type $color_type indicates alpha channel in $filename" ); 133 280 return true; 134 281 } elseif ( imsanity_gd_support() ) { 135 282 $image = imagecreatefrompng( $filename ); 283 if ( ! $image ) { 284 imsanity_debug( "could not create GD image from $filename" ); 285 return false; 286 } 136 287 if ( imagecolortransparent( $image ) >= 0 ) { 288 imsanity_debug( "$filename has a transparent color" ); 137 289 return true; 138 290 } 139 list( $width, $height ) = getimagesize( $filename ); 291 $image_size = getimagesize( $filename ); 292 if ( empty( $image_size[0] ) || empty( $image_size[1] ) ) { 293 imsanity_debug( "invalid dimensions for $filename" ); 294 return false; 295 } 296 $width = (int) $image_size[0]; 297 $height = (int) $image_size[1]; 140 298 for ( $y = 0; $y < $height; $y++ ) { 141 299 for ( $x = 0; $x < $width; $x++ ) { … … 143 301 $rgb = imagecolorsforindex( $image, $color ); 144 302 if ( $rgb['alpha'] > 0 ) { 303 imsanity_debug( "found alpha in $filename at pixel $x, $y" ); 145 304 return true; 146 305 } … … 175 334 */ 176 335 function imsanity_resize_from_id( $id = 0 ) { 336 imsanity_debug( __FUNCTION__ ); 177 337 178 338 $id = (int) $id; … … 181 341 return; 182 342 } 343 imsanity_debug( "attempting to resize attachment $id" ); 183 344 184 345 $meta = wp_get_attachment_metadata( $id ); … … 196 357 } 197 358 198 // $uploads = wp_upload_dir();199 359 $oldpath = imsanity_attachment_path( $meta, $id, '', false ); 200 360 … … 245 405 $maxw = imsanity_get_option( 'imsanity_max_width', IMSANITY_DEFAULT_MAX_WIDTH ); 246 406 $maxh = imsanity_get_option( 'imsanity_max_height', IMSANITY_DEFAULT_MAX_HEIGHT ); 407 $oldw = false; 408 $oldh = false; 247 409 248 410 // method one - slow but accurate, get file size from file itself. 249 list( $oldw, $oldh ) = getimagesize( $oldpath ); 411 $dimensions = getimagesize( $oldpath ); 412 if ( is_array( $dimensions ) && count( $dimensions ) >= 2 ) { 413 $oldw = $dimensions[0]; 414 $oldh = $dimensions[1]; 415 } 250 416 // method two - get file size from meta, fast but resize will fail if meta is out of sync. 251 417 if ( ! $oldw || ! $oldh ) { … … 255 421 256 422 if ( ( $oldw > $maxw && $maxw > 0 ) || ( $oldh > $maxh && $maxh > 0 ) ) { 257 $quality = imsanity_get_option( 'imsanity_quality', IMSANITY_DEFAULT_QUALITY );258 423 259 424 if ( $maxw > 0 && $maxh > 0 && $oldw >= $maxw && $oldh >= $maxh && ( $oldh > $maxh || $oldw > $maxw ) && apply_filters( 'imsanity_crop_image', false ) ) { … … 269 434 imsanity_debug( "subbing in $source_image for resizing" ); 270 435 } 271 $resizeresult = imsanity_image_resize( $source_image, $neww, $newh, apply_filters( 'imsanity_crop_image', false ), null, null, $quality ); 436 remove_all_filters( 'image_editor_output_format' ); 437 $resizeresult = imsanity_image_resize( $source_image, $neww, $newh, apply_filters( 'imsanity_crop_image', false ) ); 272 438 273 439 if ( $resizeresult && ! is_wp_error( $resizeresult ) ) { 274 440 $newpath = $resizeresult; 275 441 276 if ( $newpath !== $oldpath && is_file( $newpath ) && filesize( $newpath ) < filesize( $oldpath ) ) { 442 $new_type = imsanity_mimetype( $newpath ); 443 if ( $new_type && $new_type !== $ftype ) { 444 // The resized image is a different format, 445 // keep the old one and just get rid of the resized image. 446 imsanity_debug( "mime type changed from $ftype to $new_type, not allowed for existing images" ); 447 if ( is_file( $newpath ) ) { 448 unlink( $newpath ); 449 } 450 $results = array( 451 'success' => false, 452 'id' => $id, 453 /* translators: 1: File-name of the image 2: the error message, translated elsewhere */ 454 'message' => sprintf( esc_html__( 'ERROR: %1$s (%2$s)', 'imsanity' ), $meta['file'], esc_html__( 'File format/mime type was changed', 'imsanity' ) ), 455 ); 456 } elseif ( $newpath !== $oldpath && is_file( $newpath ) && filesize( $newpath ) < filesize( $oldpath ) ) { 277 457 // we saved some file space. remove original and replace with resized image. 458 imsanity_debug( "$newpath is smaller, hurrah!" ); 278 459 unlink( $oldpath ); 279 460 rename( $newpath, $oldpath ); … … 286 467 'success' => true, 287 468 'id' => $id, 288 /* translators: 1: File-name of the image */469 /* translators: 1: File-name of the image 2: the image width in pixels 3: the image height in pixels */ 289 470 'message' => sprintf( esc_html__( 'OK: %1$s resized to %2$s x %3$s', 'imsanity' ), $meta['file'], $neww . 'w', $newh . 'h' ), 290 471 ); … … 292 473 // the resized image is actually bigger in filesize (most likely due to jpg quality). 293 474 // keep the old one and just get rid of the resized image. 475 imsanity_debug( "$newpath is larger than $oldpath, bummer..." ); 294 476 if ( is_file( $newpath ) ) { 295 477 unlink( $newpath ); … … 302 484 ); 303 485 } else { 486 imsanity_debug( "$newpath === $oldpath, strange?" ); 304 487 $results = array( 305 488 'success' => false, … … 310 493 } 311 494 } elseif ( false === $resizeresult ) { 495 imsanity_debug( 'wp_get_image_editor likely missing, no resize result, and no error' ); 312 496 $results = array( 313 497 'success' => false, … … 317 501 ); 318 502 } else { 503 imsanity_debug( 'image editor returned an error: ' . $resizeresult->get_error_message() ); 319 504 $results = array( 320 505 'success' => false, … … 325 510 } 326 511 } else { 512 imsanity_debug( "$oldpath is already small enough: $oldw x $oldh" ); 327 513 $results = array( 328 514 'success' => true, … … 406 592 */ 407 593 function imsanity_remove_original_image( $id, $meta = null ) { 594 imsanity_debug( __FUNCTION__ ); 408 595 $id = (int) $id; 409 596 if ( empty( $id ) ) { … … 420 607 ) { 421 608 $original_image = imsanity_get_original_image_path( $id, '', $meta ); 609 imsanity_debug( "attempting to remove original image at $original_image" ); 422 610 if ( $original_image && is_file( $original_image ) && is_writable( $original_image ) ) { 611 imsanity_debug( 'original is writable, unlinking!' ); 423 612 unlink( $original_image ); 424 613 } 425 614 clearstatcache(); 426 615 if ( empty( $original_image ) || ! is_file( $original_image ) ) { 616 imsanity_debug( 'removal successful, updating meta' ); 427 617 unset( $meta['original_image'] ); 428 618 return $meta; 429 619 } 620 } elseif ( empty( $meta['original_image'] ) ) { 621 imsanity_debug( 'no original_image meta found, nothing to remove' ); 622 } elseif ( ! imsanity_get_option( 'imsanity_delete_originals', false ) ) { 623 imsanity_debug( 'delete_originals option not enabled, not removing' ); 624 } elseif ( ! function_exists( 'wp_get_original_image_path' ) ) { 625 imsanity_debug( 'wp_get_original_image_path function does not exist, cannot remove' ); 430 626 } 431 627 return false; … … 441 637 * @param string $suffix Optional. File suffix. 442 638 * @param string $dest_path Optional. New image file path. 443 * @param int $jpeg_quality Optional, default is 82. Image quality level (1-100).444 639 * @return mixed WP_Error on failure. String with new destination path. 445 640 */ 446 function imsanity_image_resize( $file, $max_w, $max_h, $crop = false, $suffix = null, $dest_path = null, $jpeg_quality = 82 ) { 641 function imsanity_image_resize( $file, $max_w, $max_h, $crop = false, $suffix = null, $dest_path = null ) { 642 imsanity_debug( __FUNCTION__ ); 643 447 644 if ( function_exists( 'wp_get_image_editor' ) ) { 448 imsanity_debug( "resizing $file" ); 645 imsanity_debug( "resizing $file to $max_w x $max_h" ); 646 if ( $crop ) { 647 imsanity_debug( ' cropping enabled' ); 648 } 649 449 650 $editor = wp_get_image_editor( $file ); 450 651 if ( is_wp_error( $editor ) ) { 652 imsanity_debug( 'get editor error: ' . $editor->get_error_message() ); 451 653 return $editor; 452 654 } 453 655 454 $ftype = imsanity_quick_mimetype( $file ); 656 // Default is 82 for JPG, can be anything from 1-100, though the extremes are kind of, well, extreme... 657 $quality = imsanity_jpg_quality(); 658 $ftype = imsanity_quick_mimetype( $file ); 455 659 if ( 'image/webp' === $ftype ) { 456 $ jpeg_quality = (int) round( $jpeg_quality * .91);457 } 458 459 $editor->set_quality( min( 92, $jpeg_quality ) );660 $quality = imsanity_webp_quality(); 661 } elseif ( 'image/avif' === $ftype ) { 662 $quality = imsanity_avif_quality(); 663 } 460 664 461 665 // Return 1 to override auto-rotate. … … 464 668 switch ( $orientation ) { 465 669 case 3: 670 imsanity_debug( 'rotating 180' ); 466 671 $editor->rotate( 180 ); 467 672 break; 468 673 case 6: 674 imsanity_debug( 'rotating -90' ); 469 675 $editor->rotate( -90 ); 470 676 break; 471 677 case 8: 678 imsanity_debug( 'rotating 90' ); 472 679 $editor->rotate( 90 ); 473 680 break; … … 476 683 $resized = $editor->resize( $max_w, $max_h, $crop ); 477 684 if ( is_wp_error( $resized ) ) { 685 imsanity_debug( 'resize error: ' . $resized->get_error_message() ); 478 686 return $resized; 479 687 } … … 485 693 $dest_file = $editor->generate_filename( 'TMP', $dest_path ); 486 694 } 487 488 $saved = $editor->save( $dest_file ); 695 imsanity_debug( "saving resized image to $dest_file with quality $quality" ); 696 697 $editor->set_quality( min( 92, $quality ) ); 698 699 // If Modern Image Formats is active, but fallback option is disabled, IMSANITY_ALLOW_CONVERSION will be set to allow AVIF/WebP conversion. 700 // Otherwise don't allow conversion by any plugin at this stage--MIF will do it later during thumbnail generation. 701 if ( defined( 'IMSANITY_ALLOW_CONVERSION' ) && IMSANITY_ALLOW_CONVERSION ) { 702 imsanity_debug( 'Modern Image Formats detected, but no fallback option, conversion allowed' ); 703 add_filter( 'wp_editor_set_quality', 'imsanity_editor_quality', 11, 2 ); 704 $saved = $editor->save( $dest_file ); 705 remove_filter( 'wp_editor_set_quality', 'imsanity_editor_quality', 11 ); 706 } else { 707 imsanity_debug( "passing mime type $ftype to prevent conversion by Modern Image Formats (or any other plugin)" ); 708 remove_all_filters( 'image_editor_output_format' ); 709 $saved = $editor->save( $dest_file, $ftype ); 710 } 489 711 490 712 if ( is_wp_error( $saved ) ) { 713 imsanity_debug( 'save error: ' . $saved->get_error_message() ); 491 714 return $saved; 492 715 } 493 716 717 if ( ! empty( $saved['path'] ) && $saved['path'] !== $dest_file && is_file( $saved['path'] ) ) { 718 $dest_file = $saved['path']; 719 } 720 imsanity_debug( "resized image saved to $dest_file" ); 494 721 return $dest_file; 495 722 } -
imsanity/tags/2.9.0/media.php
r3340527 r3458273 85 85 } 86 86 87 list( $imagew, $imageh ) = getimagesize( $file_path ); 87 $dimensions = getimagesize( $file_path ); 88 if ( is_array( $dimensions ) && count( $dimensions ) >= 2 ) { 89 $imagew = $dimensions[0]; 90 $imageh = $dimensions[1]; 91 } 92 88 93 if ( empty( $imagew ) || empty( $imageh ) ) { 89 94 $imagew = $meta['width']; -
imsanity/tags/2.9.0/readme.txt
r3340527 r3458273 3 3 Donate link: https://ewww.io/donate/ 4 4 Tags: image, scale, resize, space saver, quality 5 Tested up to: 6. 86 Stable tag: 2. 8.75 Tested up to: 6.9 6 Stable tag: 2.9.0 7 7 License: GPLv3 8 8 … … 107 107 == Changelog == 108 108 109 = 2.9.0 = 110 *Release Date - February 10, 2026* 111 112 * added: support for resizing AVIF image uploads 113 * added: settings for WebP and AVIF quality 114 * added: support for Modern Image Formats plugin 115 * added: PHP 8.5 compatibility 116 * fixed: quality settings not applied 117 * fixed: PNG alpha detection may throw errors if PHP GD cannot obtain information from a PNG image 118 109 119 = 2.8.7 = 110 120 *Release Date = August 6, 2024* -
imsanity/tags/2.9.0/settings.php
r3197618 r3458273 37 37 esc_html__( 'Imsanity', 'imsanity' ), // Menu Title. 38 38 $permissions, // Required permissions. 39 IMSANITY_PLUGIN_FILE_REL,// Slug.39 'imsanity-options', // Slug. 40 40 'imsanity_settings_page' // Function to call. 41 41 ); … … 57 57 esc_html__( 'Imsanity', 'imsanity' ), 58 58 $permissions, 59 IMSANITY_PLUGIN_FILE_REL,59 'imsanity-options', 60 60 'imsanity_network_settings' 61 61 ); 62 62 } 63 } 64 65 /** 66 * Get the settings link, based on whether we are in a multi-site network admin or not. 67 * 68 * @return string The URL for the settings page. 69 */ 70 function imsanity_get_settings_link() { 71 if ( is_multisite() && is_network_admin() ) { 72 return network_admin_url( 'settings.php?page=imsanity-options' ); 73 } 74 return admin_url( 'options-general.php?page=imsanity-options' ); 63 75 } 64 76 … … 74 86 } 75 87 if ( is_multisite() && is_network_admin() ) { 76 $settings_link = '<a href="' . network_admin_url( 'settings.php?page=' . IMSANITY_PLUGIN_FILE_REL) . '">' . esc_html__( 'Settings', 'imsanity' ) . '</a>';88 $settings_link = '<a href="' . imsanity_get_settings_link() . '">' . esc_html__( 'Settings', 'imsanity' ) . '</a>'; 77 89 } else { 78 $settings_link = '<a href="' . admin_url( 'options-general.php?page=' . IMSANITY_PLUGIN_FILE_REL) . '">' . esc_html__( 'Settings', 'imsanity' ) . '</a>';90 $settings_link = '<a href="' . imsanity_get_settings_link() . '">' . esc_html__( 'Settings', 'imsanity' ) . '</a>'; 79 91 } 80 92 array_unshift( $links, $settings_link ); … … 172 184 $data->imsanity_png_to_jpg = IMSANITY_DEFAULT_PNG_TO_JPG; 173 185 $data->imsanity_quality = IMSANITY_DEFAULT_QUALITY; 186 $data->imsanity_avif_quality = IMSANITY_DEFAULT_AVIF_QUALITY; 187 $data->imsanity_webp_quality = IMSANITY_DEFAULT_WEBP_QUALITY; 174 188 $data->imsanity_delete_originals = false; 175 189 return $data; … … 318 332 <tr> 319 333 <th scope="row"> 334 <label for='imsanity_avif_quality'><?php esc_html_e( 'AVIF image quality', 'imsanity' ); ?> 335 </th> 336 <td> 337 <input type='text' id='imsanity_avif_quality' name='imsanity_avif_quality' class='small-text' value='<?php echo (int) $settings->imsanity_avif_quality; ?>' /> 338 <?php esc_html_e( 'Usable values are 1-92.', 'imsanity' ); ?> 339 <p class='description'><?php esc_html_e( 'Only used when resizing images, does not affect thumbnails.', 'imsanity' ); ?></p> 340 </td> 341 </tr> 342 <tr> 343 <th scope="row"> 344 <label for='imsanity_webp_quality'><?php esc_html_e( 'WebP image quality', 'imsanity' ); ?> 345 </th> 346 <td> 347 <input type='text' id='imsanity_webp_quality' name='imsanity_webp_quality' class='small-text' value='<?php echo (int) $settings->imsanity_webp_quality; ?>' /> 348 <?php esc_html_e( 'Usable values are 1-92.', 'imsanity' ); ?> 349 <p class='description'><?php esc_html_e( 'Only used when resizing images, does not affect thumbnails.', 'imsanity' ); ?></p> 350 </td> 351 </tr> 352 <tr> 353 <th scope="row"> 320 354 <label for"imsanity_bmp_to_jpg"><?php esc_html_e( 'Convert BMP to JPG', 'imsanity' ); ?></label> 321 355 </th> 322 356 <td> 323 357 <input type="checkbox" id="imsanity_bmp_to_jpg" name="imsanity_bmp_to_jpg" value="true" <?php checked( $settings->imsanity_bmp_to_jpg ); ?> /> 324 <?php esc_html_e( 'Only applies to new image uploads, existing BMP images cannot be converted or resized.', 'imsanity' ); ?> 358 <?php 359 printf( 360 /* translators: %s: link to install EWWW Image Optimizer plugin */ 361 esc_html__( 'Only applies to new image uploads, existing images may be converted with %s.', 'imsanity' ), 362 '<a href="' . esc_url( admin_url( 'plugin-install.php?s=ewww+image+optimizer&tab=search&type=term' ) ) . '">EWWW Image Optimizer</a>' 363 ); 364 ?> 325 365 </td> 326 366 </tr> … … 349 389 </td> 350 390 </tr> 391 <?php if ( is_file( imsanity_debug_log_path() ) ) : ?> 392 <tr> 393 <th><?php esc_html_e( 'Debug Log', 'imsanity' ); ?></th> 394 <td> 395 <p> 396 <a target='_blank' href='<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?action=imsanity_view_debug_log' ), 'imsanity-options' ) ); ?>'><?php esc_html_e( 'View Log', 'imsanity' ); ?></a> - 397 <a href='<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?action=imsanity_delete_debug_log' ), 'imsanity-options' ) ); ?>'><?php esc_html_e( 'Clear Log', 'imsanity' ); ?></a> 398 </p> 399 </td> 400 </tr> 401 <?php endif; ?> 351 402 </table> 352 403 … … 387 438 $data->imsanity_png_to_jpg = ! empty( $_POST['imsanity_png_to_jpg'] ); 388 439 $data->imsanity_quality = isset( $_POST['imsanity_quality'] ) ? imsanity_jpg_quality( intval( $_POST['imsanity_quality'] ) ) : 82; 440 $data->imsanity_avif_quality = isset( $_POST['imsanity_avif_quality'] ) ? imsanity_avif_quality( intval( $_POST['imsanity_avif_quality'] ) ) : 86; 441 $data->imsanity_webp_quality = isset( $_POST['imsanity_webp_quality'] ) ? imsanity_webp_quality( intval( $_POST['imsanity_webp_quality'] ) ) : 86; 389 442 $data->imsanity_delete_originals = ! empty( $_POST['imsanity_delete_originals'] ); 390 443 391 $ success = $wpdb->update(444 $wpdb->update( 392 445 $wpdb->imsanity_ms, 393 446 array( 'data' => maybe_serialize( $data ) ), … … 501 554 add_option( 'imsanity_png_to_jpg', $settings->imsanity_png_to_jpg, '', false ); 502 555 add_option( 'imsanity_quality', $settings->imsanity_quality, '', false ); 556 add_option( 'imsanity_avif_quality', $settings->imsanity_avif_quality, '', false ); 557 add_option( 'imsanity_webp_quality', $settings->imsanity_webp_quality, '', false ); 503 558 add_option( 'imsanity_delete_originals', $settings->imsanity_delete_originals, '', false ); 504 559 if ( ! get_option( 'imsanity_version' ) ) { … … 528 583 register_setting( 'imsanity-settings-group', 'imsanity_png_to_jpg', 'boolval' ); 529 584 register_setting( 'imsanity-settings-group', 'imsanity_quality', 'imsanity_jpg_quality' ); 585 register_setting( 'imsanity-settings-group', 'imsanity_avif_quality', 'imsanity_avif_quality' ); 586 register_setting( 'imsanity-settings-group', 'imsanity_webp_quality', 'imsanity_webp_quality' ); 530 587 register_setting( 'imsanity-settings-group', 'imsanity_delete_originals', 'boolval' ); 588 } 589 590 /** 591 * Set the quality based on the mime type of the image being resized. 592 * 593 * @param int $quality The quality currently set. 594 * @param string $mime_type The mime type of the image being resized. 595 * @return int The (potentially) adjusted quality level. 596 */ 597 function imsanity_editor_quality( $quality, $mime_type = '' ) { 598 if ( 'image/avif' === $mime_type ) { 599 $new_quality = imsanity_avif_quality(); 600 } elseif ( 'image/webp' === $mime_type ) { 601 $new_quality = imsanity_webp_quality(); 602 } elseif ( 'image/jpeg' === $mime_type ) { 603 $new_quality = imsanity_jpg_quality(); 604 } 605 if ( ! empty( $new_quality ) && $new_quality > 0 && $new_quality <= 92 ) { 606 return $new_quality; 607 } 608 return $quality; 531 609 } 532 610 … … 545 623 } else { 546 624 return IMSANITY_DEFAULT_QUALITY; 625 } 626 } 627 628 /** 629 * Validate and return the AVIF quality setting. 630 * 631 * @param int $quality The AVIF quality currently set. 632 * @return int The (potentially) adjusted quality level. 633 */ 634 function imsanity_avif_quality( $quality = null ) { 635 if ( is_null( $quality ) ) { 636 $quality = get_option( 'imsanity_avif_quality' ); 637 } 638 if ( preg_match( '/^(100|[1-9][0-9]?)$/', $quality ) ) { 639 return (int) $quality; 640 } else { 641 return IMSANITY_DEFAULT_AVIF_QUALITY; 642 } 643 } 644 645 /** 646 * Validate and return the WebP quality setting. 647 * 648 * @param int $quality The WebP quality currently set. 649 * @return int The (potentially) adjusted quality level. 650 */ 651 function imsanity_webp_quality( $quality = null ) { 652 if ( is_null( $quality ) ) { 653 $quality = get_option( 'imsanity_webp_quality' ); 654 } 655 if ( preg_match( '/^(100|[1-9][0-9]?)$/', $quality ) ) { 656 return (int) $quality; 657 } else { 658 return IMSANITY_DEFAULT_WEBP_QUALITY; 547 659 } 548 660 } … … 779 891 780 892 <tr> 781 <th scope="row"><?php esc_html_e( 'Images uploaded elsewhere (Theme headers, backgrounds, logos, etc)', 'imsanity' ); ?></th> 782 <td> 783 <label for="imsanity_max_width_other"><?php esc_html_e( 'Max Width', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_width_other" value="<?php echo (int) get_option( 'imsanity_max_width_other', IMSANITY_DEFAULT_MAX_WIDTH ); ?>" /> 784 <label for="imsanity_max_height_other"><?php esc_html_e( 'Max Height', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_height_other" value="<?php echo (int) get_option( 'imsanity_max_height_other', IMSANITY_DEFAULT_MAX_HEIGHT ); ?>" /> <?php esc_html_e( 'in pixels, enter 0 to disable', 'imsanity' ); ?> 785 </td> 786 </tr> 787 893 <th scope="row"><?php esc_html_e( 'Images uploaded elsewhere (Theme headers, backgrounds, logos, etc)', 'imsanity' ); ?></th> 894 <td> 895 <label for="imsanity_max_width_other"><?php esc_html_e( 'Max Width', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_width_other" value="<?php echo (int) get_option( 'imsanity_max_width_other', IMSANITY_DEFAULT_MAX_WIDTH ); ?>" /> 896 <label for="imsanity_max_height_other"><?php esc_html_e( 'Max Height', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_height_other" value="<?php echo (int) get_option( 'imsanity_max_height_other', IMSANITY_DEFAULT_MAX_HEIGHT ); ?>" /> <?php esc_html_e( 'in pixels, enter 0 to disable', 'imsanity' ); ?> 897 </td> 898 </tr> 788 899 789 900 <tr> … … 800 911 <tr> 801 912 <th scope="row"> 913 <label for='imsanity_avif_quality' ><?php esc_html_e( 'AVIF image quality', 'imsanity' ); ?> 914 </th> 915 <td> 916 <input type='text' id='imsanity_avif_quality' name='imsanity_avif_quality' class='small-text' value='<?php echo (int) imsanity_avif_quality(); ?>' /> 917 <?php esc_html_e( 'Usable values are 1-92.', 'imsanity' ); ?> 918 <p class='description'><?php esc_html_e( 'Only used when resizing images, does not affect thumbnails.', 'imsanity' ); ?></p> 919 </td> 920 </tr> 921 922 <tr> 923 <th scope="row"> 924 <label for='imsanity_webp_quality' ><?php esc_html_e( 'WebP image quality', 'imsanity' ); ?> 925 </th> 926 <td> 927 <input type='text' id='imsanity_webp_quality' name='imsanity_webp_quality' class='small-text' value='<?php echo (int) imsanity_webp_quality(); ?>' /> 928 <?php esc_html_e( 'Usable values are 1-92.', 'imsanity' ); ?> 929 <p class='description'><?php esc_html_e( 'Only used when resizing images, does not affect thumbnails.', 'imsanity' ); ?></p> 930 </td> 931 </tr> 932 933 <tr> 934 <th scope="row"> 802 935 <label for="imsanity_bmp_to_jpg"><?php esc_html_e( 'Convert BMP To JPG', 'imsanity' ); ?></label> 803 936 </th> 804 937 <td> 805 938 <input type="checkbox" id="imsanity_bmp_to_jpg" name="imsanity_bmp_to_jpg" value="true" <?php checked( (bool) get_option( 'imsanity_bmp_to_jpg', IMSANITY_DEFAULT_BMP_TO_JPG ) ); ?> /> 806 <?php esc_html_e( 'Only applies to new image uploads, existing BMP images cannot be converted or resized.', 'imsanity' ); ?> 939 <?php 940 printf( 941 /* translators: %s: link to install EWWW Image Optimizer plugin */ 942 esc_html__( 'Only applies to new image uploads, existing images may be converted with %s.', 'imsanity' ), 943 '<a href="' . esc_url( admin_url( 'plugin-install.php?s=ewww+image+optimizer&tab=search&type=term' ) ) . '">EWWW Image Optimizer</a>' 944 ); 945 ?> 807 946 </td> 808 947 </tr> … … 831 970 </td> 832 971 </tr> 972 <?php if ( is_file( imsanity_debug_log_path() ) ) : ?> 973 <tr> 974 <th><?php esc_html_e( 'Debug Log', 'imsanity' ); ?></th> 975 <td> 976 <p> 977 <a target='_blank' href='<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?action=imsanity_view_debug_log' ), 'imsanity-options' ) ); ?>'><?php esc_html_e( 'View Log', 'imsanity' ); ?></a> - 978 <a href='<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?action=imsanity_delete_debug_log' ), 'imsanity-options' ) ); ?>'><?php esc_html_e( 'Clear Log', 'imsanity' ); ?></a> 979 </p> 980 </td> 981 </tr> 982 <?php endif; ?> 833 983 </table> 834 984 -
imsanity/trunk/changelog.txt
r3340527 r3458273 1 = 2.9.0 = 2 *Release Date - February 10, 2026* 3 4 * added: support for resizing AVIF image uploads 5 * added: settings for WebP and AVIF quality 6 * added: support for Modern Image Formats plugin 7 * added: PHP 8.5 compatibility 8 * fixed: quality settings not applied 9 * fixed: PNG alpha detection may throw errors if PHP GD cannot obtain information from a PNG image 10 1 11 = 2.8.7 = 2 12 *Release Date = August 6, 2024* -
imsanity/trunk/class-imsanity-cli.php
r2969420 r3458273 76 76 $path = get_attached_file( $id ); 77 77 if ( $path ) { 78 list( $imagew, $imageh ) = getimagesize( $path ); 78 $dimensions = getimagesize( $path ); 79 if ( is_array( $dimensions ) && count( $dimensions ) >= 2 ) { 80 $imagew = $dimensions[0]; 81 $imageh = $dimensions[1]; 82 } 79 83 } 80 84 if ( empty( $imagew ) || empty( $imageh ) ) { -
imsanity/trunk/imsanity.php
r3340527 r3458273 15 15 Author: Exactly WWW 16 16 Domain Path: /languages 17 Version: 2. 8.718 Requires at least: 6. 517 Version: 2.9.0 18 Requires at least: 6.6 19 19 Requires PHP: 7.4 20 20 Author URI: https://ewww.io/about/ … … 26 26 } 27 27 28 define( 'IMSANITY_VERSION', '2. 8.7' );28 define( 'IMSANITY_VERSION', '2.9.0' ); 29 29 define( 'IMSANITY_SCHEMA_VERSION', '1.1' ); 30 30 … … 34 34 define( 'IMSANITY_DEFAULT_PNG_TO_JPG', false ); 35 35 define( 'IMSANITY_DEFAULT_QUALITY', 82 ); 36 define( 'IMSANITY_DEFAULT_AVIF_QUALITY', 86 ); 37 define( 'IMSANITY_DEFAULT_WEBP_QUALITY', 86 ); 36 38 37 39 define( 'IMSANITY_SOURCE_POST', 1 ); … … 45 47 */ 46 48 define( 'IMSANITY_PLUGIN_FILE', __FILE__ ); 49 50 /** 51 * The directory path of the main plugin file. 52 * 53 * @var string IMSANITY_PLUGIN_DIR 54 */ 55 define( 'IMSANITY_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); 56 47 57 /** 48 58 * The path of the main plugin file, relative to the plugins/ folder. … … 62 72 * Import supporting libraries. 63 73 */ 74 require_once plugin_dir_path( __FILE__ ) . 'libs/debug.php'; 64 75 require_once plugin_dir_path( __FILE__ ) . 'libs/utils.php'; 65 76 require_once plugin_dir_path( __FILE__ ) . 'settings.php'; … … 68 79 if ( defined( 'WP_CLI' ) && WP_CLI ) { 69 80 require_once plugin_dir_path( __FILE__ ) . 'class-imsanity-cli.php'; 70 }71 72 /**73 * Use the EWWW IO debugging functions (if available).74 *75 * @param string $message A message to send to the debugger.76 */77 function imsanity_debug( $message ) {78 if ( function_exists( 'ewwwio_debug_message' ) ) {79 if ( ! is_string( $message ) ) {80 if ( function_exists( 'print_r' ) ) {81 $message = print_r( $message, true );82 } else {83 $message = 'not a string, print_r disabled';84 }85 }86 ewwwio_debug_message( $message );87 if ( function_exists( 'ewww_image_optimizer_debug_log' ) ) {88 ewww_image_optimizer_debug_log();89 }90 }91 81 } 92 82 … … 175 165 */ 176 166 function imsanity_handle_upload( $params ) { 167 imsanity_debug( __FUNCTION__ ); 168 169 if ( empty( $params['file'] ) || empty( $params['type'] ) ) { 170 imsanity_debug( 'missing file or type parameter, skipping' ); 171 return $params; 172 } 177 173 178 174 // If "noresize" is included in the filename then we will bypass imsanity scaling. 179 175 if ( strpos( $params['file'], 'noresize' ) !== false ) { 176 imsanity_debug( "skipping {$params['file']}" ); 180 177 return $params; 181 178 } 182 179 183 180 if ( apply_filters( 'imsanity_skip_image', false, $params['file'] ) ) { 181 imsanity_debug( "skipping {$params['file']} per filter" ); 184 182 return $params; 185 183 } … … 194 192 } 195 193 196 // Make sure this is a type of image that we want to convert and that it exists.194 // Store the path for reference in case $params is modified. 197 195 $oldpath = $params['file']; 198 196 199 197 // Let folks filter the allowed mime-types for resizing. 198 // Also allows conditional support for WebP and AVIF if the server supports it. 200 199 $allowed_types = apply_filters( 'imsanity_allowed_mimes', array( 'image/png', 'image/gif', 'image/jpeg' ), $oldpath ); 201 200 if ( is_string( $allowed_types ) ) { … … 213 212 in_array( $params['type'], $allowed_types, true ) 214 213 ) { 214 // If the Modern Image Formats plugin is active but fallback mode is disabled, permit conversion to AVIF/WebP during upload by defining IMSANITY_ALLOW_CONVERSION. 215 // Otherwise, no conversion should be allowed at all. The upload handler will still check for conversion and work with it if it happens somehow. 216 if ( ! defined( 'IMSANITY_ALLOW_CONVERSION' ) && function_exists( 'webp_uploads_is_fallback_enabled' ) && ! webp_uploads_is_fallback_enabled() ) { 217 define( 'IMSANITY_ALLOW_CONVERSION', true ); 218 } 215 219 216 220 // figure out where the upload is coming from. … … 226 230 $maxh = (int) $maxh; 227 231 228 list( $oldw, $oldh ) = getimagesize( $oldpath ); 232 $dimensions = getimagesize( $oldpath ); 233 if ( is_array( $dimensions ) && count( $dimensions ) >= 2 ) { 234 $oldw = $dimensions[0]; 235 $oldh = $dimensions[1]; 236 } else { 237 imsanity_debug( "could not get dimensions for $oldpath, skipping" ); 238 return $params; 239 } 229 240 230 241 if ( ( $oldw > $maxw + 1 && $maxw > 0 ) || ( $oldh > $maxh + 1 && $maxh > 0 ) ) { 231 $quality = imsanity_get_option( 'imsanity_quality', IMSANITY_DEFAULT_QUALITY );232 242 233 243 $ftype = imsanity_quick_mimetype( $oldpath ); … … 253 263 $original_preempt = $ewww_preempt_editor; 254 264 $ewww_preempt_editor = true; 255 $resizeresult = imsanity_image_resize( $oldpath, $neww, $newh, apply_filters( 'imsanity_crop_image', false ) , null, null, $quality);265 $resizeresult = imsanity_image_resize( $oldpath, $neww, $newh, apply_filters( 'imsanity_crop_image', false ) ); 256 266 $ewww_preempt_editor = $original_preempt; 257 267 258 268 if ( $resizeresult && ! is_wp_error( $resizeresult ) ) { 259 $newpath = $resizeresult; 260 269 $newpath = $resizeresult; 270 $new_type = $params['type']; 271 272 imsanity_debug( "checking $newpath to see if resize was successful" ); 261 273 if ( is_file( $newpath ) && filesize( $newpath ) < filesize( $oldpath ) ) { 274 imsanity_debug( 'resized image is smaller, replacing original' ); 262 275 // We saved some file space. remove original and replace with resized image. 276 $new_type = imsanity_mimetype( $newpath ); 263 277 unlink( $oldpath ); 264 278 rename( $newpath, $oldpath ); 279 if ( $new_type && $new_type !== $params['type'] ) { 280 imsanity_debug( "mimetype changed from {$params['type']} to $new_type" ); 281 $params['type'] = $new_type; 282 $params['file'] = imsanity_update_extension( $oldpath, $new_type ); 283 if ( $params['file'] !== $oldpath ) { 284 rename( $oldpath, $params['file'] ); 285 } 286 $params['url'] = imsanity_update_extension( $params['url'], $new_type ); 287 imsanity_debug( "renamed file to match new extension: {$params['file']} / {$params['url']}" ); 288 } 265 289 } elseif ( is_file( $newpath ) ) { 290 imsanity_debug( 'resized image is bigger, discarding' ); 266 291 // The resized image is actually bigger in filesize (most likely due to jpg quality). 267 292 // Keep the old one and just get rid of the resized image. … … 269 294 } 270 295 } elseif ( false === $resizeresult ) { 296 imsanity_debug( 'resize returned false, unknown error' ); 271 297 return $params; 272 298 } elseif ( is_wp_error( $resizeresult ) ) { … … 284 310 ) 285 311 ); 312 imsanity_debug( 'resize result is wp_error, should have already output error to log' ); 286 313 } else { 314 imsanity_debug( 'unknown resize result, inconceivable!' ); 287 315 return $params; 288 316 } … … 304 332 */ 305 333 function imsanity_convert_to_jpg( $type, $params ) { 334 imsanity_debug( __FUNCTION__ ); 306 335 307 336 if ( apply_filters( 'imsanity_disable_convert', false, $type, $params ) ) { 337 imsanity_debug( "skipping conversion for {$params['file']}" ); 308 338 return $params; 309 339 } … … 313 343 if ( 'bmp' === $type ) { 314 344 if ( ! function_exists( 'imagecreatefrombmp' ) ) { 345 imsanity_debug( 'imagecreatefrombmp does not exist' ); 315 346 return $params; 316 347 } … … 372 403 // Outputs the actual column information for each attachment. 373 404 add_action( 'manage_media_custom_column', 'imsanity_custom_column', 10, 2 ); 405 // Checks for AVIF support and adds it to the allowed mime types. 406 add_filter( 'imsanity_allowed_mimes', 'imsanity_add_avif_support' ); 374 407 // Checks for WebP support and adds it to the allowed mime types. 375 408 add_filter( 'imsanity_allowed_mimes', 'imsanity_add_webp_support' ); -
imsanity/trunk/libs/utils.php
r2969420 r3458273 49 49 } 50 50 return ''; 51 } 52 53 /** 54 * Checks the filename for a protocal wrapper (like s3://). 55 * 56 * @param string $path The path of the file to check. 57 * @return bool True if the file contains :// indicating a stream wrapper. 58 */ 59 function imsanity_file_is_stream_wrapped( $path ) { 60 if ( false !== strpos( $path, '://' ) ) { 61 return true; 62 } 63 return false; 51 64 } 52 65 … … 70 83 case 'pdf': 71 84 return 'application/pdf'; 85 case 'avif': 86 return 'image/avif'; 72 87 case 'webp': 73 88 return 'image/webp'; … … 75 90 return false; 76 91 } 92 } 93 94 /** 95 * Check the mimetype of the given file with magic mime strings/patterns. 96 * 97 * @param string $path The absolute path to the file. 98 * @return bool|string A valid mime-type or false. 99 */ 100 function imsanity_mimetype( $path ) { 101 imsanity_debug( "testing mimetype: $path" ); 102 $type = false; 103 // For S3 images/files, don't attempt to read the file, just use the quick (filename) mime check. 104 if ( imsanity_file_is_stream_wrapped( $path ) ) { 105 return imsanity_quick_mimetype( $path ); 106 } 107 $path = \realpath( $path ); 108 if ( ! is_file( $path ) ) { 109 imsanity_debug( "$path is not a file, or out of bounds" ); 110 return $type; 111 } 112 if ( ! is_readable( $path ) ) { 113 imsanity_debug( "$path is not readable" ); 114 return $type; 115 } 116 $file_handle = fopen( $path, 'rb' ); 117 $file_contents = fread( $file_handle, 4096 ); 118 if ( $file_contents ) { 119 // Read first 12 bytes, which equates to 24 hex characters. 120 $magic = bin2hex( substr( $file_contents, 0, 12 ) ); 121 imsanity_debug( $magic ); 122 if ( 8 === strpos( $magic, '6674797061766966' ) ) { 123 $type = 'image/avif'; 124 imsanity_debug( "imsanity type: $type" ); 125 return $type; 126 } 127 if ( '424d' === substr( $magic, 0, 4 ) ) { 128 $type = 'image/bmp'; 129 imsanity_debug( "imsanity type: $type" ); 130 return $type; 131 } 132 if ( 0 === strpos( $magic, '52494646' ) && 16 === strpos( $magic, '57454250' ) ) { 133 $type = 'image/webp'; 134 imsanity_debug( "imsanity type: $type" ); 135 return $type; 136 } 137 if ( 'ffd8ff' === substr( $magic, 0, 6 ) ) { 138 $type = 'image/jpeg'; 139 imsanity_debug( "imsanity type: $type" ); 140 return $type; 141 } 142 if ( '89504e470d0a1a0a' === substr( $magic, 0, 16 ) ) { 143 $type = 'image/png'; 144 imsanity_debug( "imsanity type: $type" ); 145 return $type; 146 } 147 if ( '474946383761' === substr( $magic, 0, 12 ) || '474946383961' === substr( $magic, 0, 12 ) ) { 148 $type = 'image/gif'; 149 imsanity_debug( "imsanity type: $type" ); 150 return $type; 151 } 152 if ( '25504446' === substr( $magic, 0, 8 ) ) { 153 $type = 'application/pdf'; 154 imsanity_debug( "imsanity type: $type" ); 155 return $type; 156 } 157 if ( preg_match( '/<svg/', $file_contents ) ) { 158 $type = 'image/svg+xml'; 159 imsanity_debug( "imsanity type: $type" ); 160 return $type; 161 } 162 imsanity_debug( "match not found for file: $magic" ); 163 } else { 164 imsanity_debug( 'could not open for reading' ); 165 } 166 return false; 167 } 168 169 /** 170 * Update the file extension based on the new mime type. 171 * 172 * @param string $path The path of the file to update. 173 * @param string $new_mime The new mime type. 174 * @return string The updated path with the new extension. 175 */ 176 function imsanity_update_extension( $path, $new_mime ) { 177 $extension = ''; 178 switch ( $new_mime ) { 179 case 'image/jpeg': 180 $extension = 'jpg'; 181 break; 182 case 'image/png': 183 $extension = 'png'; 184 break; 185 case 'image/gif': 186 $extension = 'gif'; 187 break; 188 case 'image/avif': 189 $extension = 'avif'; 190 break; 191 case 'image/webp': 192 $extension = 'webp'; 193 break; 194 default: 195 return $path; 196 } 197 $pathinfo = pathinfo( $path ); 198 if ( empty( $pathinfo['dirname'] ) || empty( $pathinfo['filename'] ) ) { 199 return $path; 200 } 201 $new_name = trailingslashit( $pathinfo['dirname'] ) . $pathinfo['filename'] . '.' . $extension; 202 return $new_name; 203 } 204 205 /** 206 * Check for AVIF support in the image editor and add to the list of allowed mimes. 207 * 208 * @param array $mimes A list of allowed mime types. 209 * @return array The updated list of mimes after checking AVIF support. 210 */ 211 function imsanity_add_avif_support( $mimes ) { 212 if ( ! in_array( 'image/avif', $mimes, true ) ) { 213 if ( class_exists( 'Imagick' ) ) { 214 $imagick = new Imagick(); 215 $formats = $imagick->queryFormats(); 216 if ( in_array( 'AVIF', $formats, true ) ) { 217 $mimes[] = 'image/avif'; 218 } 219 } 220 } 221 return $mimes; 77 222 } 78 223 … … 120 265 */ 121 266 function imsanity_has_alpha( $filename ) { 267 imsanity_debug( __FUNCTION__ ); 122 268 if ( ! is_file( $filename ) ) { 123 269 return false; … … 131 277 // If we do not have GD and the PNG color type is RGB alpha or Grayscale alpha. 132 278 if ( ! imsanity_gd_support() && ( 4 === $color_type || 6 === $color_type ) ) { 279 imsanity_debug( "color type $color_type indicates alpha channel in $filename" ); 133 280 return true; 134 281 } elseif ( imsanity_gd_support() ) { 135 282 $image = imagecreatefrompng( $filename ); 283 if ( ! $image ) { 284 imsanity_debug( "could not create GD image from $filename" ); 285 return false; 286 } 136 287 if ( imagecolortransparent( $image ) >= 0 ) { 288 imsanity_debug( "$filename has a transparent color" ); 137 289 return true; 138 290 } 139 list( $width, $height ) = getimagesize( $filename ); 291 $image_size = getimagesize( $filename ); 292 if ( empty( $image_size[0] ) || empty( $image_size[1] ) ) { 293 imsanity_debug( "invalid dimensions for $filename" ); 294 return false; 295 } 296 $width = (int) $image_size[0]; 297 $height = (int) $image_size[1]; 140 298 for ( $y = 0; $y < $height; $y++ ) { 141 299 for ( $x = 0; $x < $width; $x++ ) { … … 143 301 $rgb = imagecolorsforindex( $image, $color ); 144 302 if ( $rgb['alpha'] > 0 ) { 303 imsanity_debug( "found alpha in $filename at pixel $x, $y" ); 145 304 return true; 146 305 } … … 175 334 */ 176 335 function imsanity_resize_from_id( $id = 0 ) { 336 imsanity_debug( __FUNCTION__ ); 177 337 178 338 $id = (int) $id; … … 181 341 return; 182 342 } 343 imsanity_debug( "attempting to resize attachment $id" ); 183 344 184 345 $meta = wp_get_attachment_metadata( $id ); … … 196 357 } 197 358 198 // $uploads = wp_upload_dir();199 359 $oldpath = imsanity_attachment_path( $meta, $id, '', false ); 200 360 … … 245 405 $maxw = imsanity_get_option( 'imsanity_max_width', IMSANITY_DEFAULT_MAX_WIDTH ); 246 406 $maxh = imsanity_get_option( 'imsanity_max_height', IMSANITY_DEFAULT_MAX_HEIGHT ); 407 $oldw = false; 408 $oldh = false; 247 409 248 410 // method one - slow but accurate, get file size from file itself. 249 list( $oldw, $oldh ) = getimagesize( $oldpath ); 411 $dimensions = getimagesize( $oldpath ); 412 if ( is_array( $dimensions ) && count( $dimensions ) >= 2 ) { 413 $oldw = $dimensions[0]; 414 $oldh = $dimensions[1]; 415 } 250 416 // method two - get file size from meta, fast but resize will fail if meta is out of sync. 251 417 if ( ! $oldw || ! $oldh ) { … … 255 421 256 422 if ( ( $oldw > $maxw && $maxw > 0 ) || ( $oldh > $maxh && $maxh > 0 ) ) { 257 $quality = imsanity_get_option( 'imsanity_quality', IMSANITY_DEFAULT_QUALITY );258 423 259 424 if ( $maxw > 0 && $maxh > 0 && $oldw >= $maxw && $oldh >= $maxh && ( $oldh > $maxh || $oldw > $maxw ) && apply_filters( 'imsanity_crop_image', false ) ) { … … 269 434 imsanity_debug( "subbing in $source_image for resizing" ); 270 435 } 271 $resizeresult = imsanity_image_resize( $source_image, $neww, $newh, apply_filters( 'imsanity_crop_image', false ), null, null, $quality ); 436 remove_all_filters( 'image_editor_output_format' ); 437 $resizeresult = imsanity_image_resize( $source_image, $neww, $newh, apply_filters( 'imsanity_crop_image', false ) ); 272 438 273 439 if ( $resizeresult && ! is_wp_error( $resizeresult ) ) { 274 440 $newpath = $resizeresult; 275 441 276 if ( $newpath !== $oldpath && is_file( $newpath ) && filesize( $newpath ) < filesize( $oldpath ) ) { 442 $new_type = imsanity_mimetype( $newpath ); 443 if ( $new_type && $new_type !== $ftype ) { 444 // The resized image is a different format, 445 // keep the old one and just get rid of the resized image. 446 imsanity_debug( "mime type changed from $ftype to $new_type, not allowed for existing images" ); 447 if ( is_file( $newpath ) ) { 448 unlink( $newpath ); 449 } 450 $results = array( 451 'success' => false, 452 'id' => $id, 453 /* translators: 1: File-name of the image 2: the error message, translated elsewhere */ 454 'message' => sprintf( esc_html__( 'ERROR: %1$s (%2$s)', 'imsanity' ), $meta['file'], esc_html__( 'File format/mime type was changed', 'imsanity' ) ), 455 ); 456 } elseif ( $newpath !== $oldpath && is_file( $newpath ) && filesize( $newpath ) < filesize( $oldpath ) ) { 277 457 // we saved some file space. remove original and replace with resized image. 458 imsanity_debug( "$newpath is smaller, hurrah!" ); 278 459 unlink( $oldpath ); 279 460 rename( $newpath, $oldpath ); … … 286 467 'success' => true, 287 468 'id' => $id, 288 /* translators: 1: File-name of the image */469 /* translators: 1: File-name of the image 2: the image width in pixels 3: the image height in pixels */ 289 470 'message' => sprintf( esc_html__( 'OK: %1$s resized to %2$s x %3$s', 'imsanity' ), $meta['file'], $neww . 'w', $newh . 'h' ), 290 471 ); … … 292 473 // the resized image is actually bigger in filesize (most likely due to jpg quality). 293 474 // keep the old one and just get rid of the resized image. 475 imsanity_debug( "$newpath is larger than $oldpath, bummer..." ); 294 476 if ( is_file( $newpath ) ) { 295 477 unlink( $newpath ); … … 302 484 ); 303 485 } else { 486 imsanity_debug( "$newpath === $oldpath, strange?" ); 304 487 $results = array( 305 488 'success' => false, … … 310 493 } 311 494 } elseif ( false === $resizeresult ) { 495 imsanity_debug( 'wp_get_image_editor likely missing, no resize result, and no error' ); 312 496 $results = array( 313 497 'success' => false, … … 317 501 ); 318 502 } else { 503 imsanity_debug( 'image editor returned an error: ' . $resizeresult->get_error_message() ); 319 504 $results = array( 320 505 'success' => false, … … 325 510 } 326 511 } else { 512 imsanity_debug( "$oldpath is already small enough: $oldw x $oldh" ); 327 513 $results = array( 328 514 'success' => true, … … 406 592 */ 407 593 function imsanity_remove_original_image( $id, $meta = null ) { 594 imsanity_debug( __FUNCTION__ ); 408 595 $id = (int) $id; 409 596 if ( empty( $id ) ) { … … 420 607 ) { 421 608 $original_image = imsanity_get_original_image_path( $id, '', $meta ); 609 imsanity_debug( "attempting to remove original image at $original_image" ); 422 610 if ( $original_image && is_file( $original_image ) && is_writable( $original_image ) ) { 611 imsanity_debug( 'original is writable, unlinking!' ); 423 612 unlink( $original_image ); 424 613 } 425 614 clearstatcache(); 426 615 if ( empty( $original_image ) || ! is_file( $original_image ) ) { 616 imsanity_debug( 'removal successful, updating meta' ); 427 617 unset( $meta['original_image'] ); 428 618 return $meta; 429 619 } 620 } elseif ( empty( $meta['original_image'] ) ) { 621 imsanity_debug( 'no original_image meta found, nothing to remove' ); 622 } elseif ( ! imsanity_get_option( 'imsanity_delete_originals', false ) ) { 623 imsanity_debug( 'delete_originals option not enabled, not removing' ); 624 } elseif ( ! function_exists( 'wp_get_original_image_path' ) ) { 625 imsanity_debug( 'wp_get_original_image_path function does not exist, cannot remove' ); 430 626 } 431 627 return false; … … 441 637 * @param string $suffix Optional. File suffix. 442 638 * @param string $dest_path Optional. New image file path. 443 * @param int $jpeg_quality Optional, default is 82. Image quality level (1-100).444 639 * @return mixed WP_Error on failure. String with new destination path. 445 640 */ 446 function imsanity_image_resize( $file, $max_w, $max_h, $crop = false, $suffix = null, $dest_path = null, $jpeg_quality = 82 ) { 641 function imsanity_image_resize( $file, $max_w, $max_h, $crop = false, $suffix = null, $dest_path = null ) { 642 imsanity_debug( __FUNCTION__ ); 643 447 644 if ( function_exists( 'wp_get_image_editor' ) ) { 448 imsanity_debug( "resizing $file" ); 645 imsanity_debug( "resizing $file to $max_w x $max_h" ); 646 if ( $crop ) { 647 imsanity_debug( ' cropping enabled' ); 648 } 649 449 650 $editor = wp_get_image_editor( $file ); 450 651 if ( is_wp_error( $editor ) ) { 652 imsanity_debug( 'get editor error: ' . $editor->get_error_message() ); 451 653 return $editor; 452 654 } 453 655 454 $ftype = imsanity_quick_mimetype( $file ); 656 // Default is 82 for JPG, can be anything from 1-100, though the extremes are kind of, well, extreme... 657 $quality = imsanity_jpg_quality(); 658 $ftype = imsanity_quick_mimetype( $file ); 455 659 if ( 'image/webp' === $ftype ) { 456 $ jpeg_quality = (int) round( $jpeg_quality * .91);457 } 458 459 $editor->set_quality( min( 92, $jpeg_quality ) );660 $quality = imsanity_webp_quality(); 661 } elseif ( 'image/avif' === $ftype ) { 662 $quality = imsanity_avif_quality(); 663 } 460 664 461 665 // Return 1 to override auto-rotate. … … 464 668 switch ( $orientation ) { 465 669 case 3: 670 imsanity_debug( 'rotating 180' ); 466 671 $editor->rotate( 180 ); 467 672 break; 468 673 case 6: 674 imsanity_debug( 'rotating -90' ); 469 675 $editor->rotate( -90 ); 470 676 break; 471 677 case 8: 678 imsanity_debug( 'rotating 90' ); 472 679 $editor->rotate( 90 ); 473 680 break; … … 476 683 $resized = $editor->resize( $max_w, $max_h, $crop ); 477 684 if ( is_wp_error( $resized ) ) { 685 imsanity_debug( 'resize error: ' . $resized->get_error_message() ); 478 686 return $resized; 479 687 } … … 485 693 $dest_file = $editor->generate_filename( 'TMP', $dest_path ); 486 694 } 487 488 $saved = $editor->save( $dest_file ); 695 imsanity_debug( "saving resized image to $dest_file with quality $quality" ); 696 697 $editor->set_quality( min( 92, $quality ) ); 698 699 // If Modern Image Formats is active, but fallback option is disabled, IMSANITY_ALLOW_CONVERSION will be set to allow AVIF/WebP conversion. 700 // Otherwise don't allow conversion by any plugin at this stage--MIF will do it later during thumbnail generation. 701 if ( defined( 'IMSANITY_ALLOW_CONVERSION' ) && IMSANITY_ALLOW_CONVERSION ) { 702 imsanity_debug( 'Modern Image Formats detected, but no fallback option, conversion allowed' ); 703 add_filter( 'wp_editor_set_quality', 'imsanity_editor_quality', 11, 2 ); 704 $saved = $editor->save( $dest_file ); 705 remove_filter( 'wp_editor_set_quality', 'imsanity_editor_quality', 11 ); 706 } else { 707 imsanity_debug( "passing mime type $ftype to prevent conversion by Modern Image Formats (or any other plugin)" ); 708 remove_all_filters( 'image_editor_output_format' ); 709 $saved = $editor->save( $dest_file, $ftype ); 710 } 489 711 490 712 if ( is_wp_error( $saved ) ) { 713 imsanity_debug( 'save error: ' . $saved->get_error_message() ); 491 714 return $saved; 492 715 } 493 716 717 if ( ! empty( $saved['path'] ) && $saved['path'] !== $dest_file && is_file( $saved['path'] ) ) { 718 $dest_file = $saved['path']; 719 } 720 imsanity_debug( "resized image saved to $dest_file" ); 494 721 return $dest_file; 495 722 } -
imsanity/trunk/media.php
r3340527 r3458273 85 85 } 86 86 87 list( $imagew, $imageh ) = getimagesize( $file_path ); 87 $dimensions = getimagesize( $file_path ); 88 if ( is_array( $dimensions ) && count( $dimensions ) >= 2 ) { 89 $imagew = $dimensions[0]; 90 $imageh = $dimensions[1]; 91 } 92 88 93 if ( empty( $imagew ) || empty( $imageh ) ) { 89 94 $imagew = $meta['width']; -
imsanity/trunk/readme.txt
r3340527 r3458273 3 3 Donate link: https://ewww.io/donate/ 4 4 Tags: image, scale, resize, space saver, quality 5 Tested up to: 6. 86 Stable tag: 2. 8.75 Tested up to: 6.9 6 Stable tag: 2.9.0 7 7 License: GPLv3 8 8 … … 107 107 == Changelog == 108 108 109 = 2.9.0 = 110 *Release Date - February 10, 2026* 111 112 * added: support for resizing AVIF image uploads 113 * added: settings for WebP and AVIF quality 114 * added: support for Modern Image Formats plugin 115 * added: PHP 8.5 compatibility 116 * fixed: quality settings not applied 117 * fixed: PNG alpha detection may throw errors if PHP GD cannot obtain information from a PNG image 118 109 119 = 2.8.7 = 110 120 *Release Date = August 6, 2024* -
imsanity/trunk/settings.php
r3197618 r3458273 37 37 esc_html__( 'Imsanity', 'imsanity' ), // Menu Title. 38 38 $permissions, // Required permissions. 39 IMSANITY_PLUGIN_FILE_REL,// Slug.39 'imsanity-options', // Slug. 40 40 'imsanity_settings_page' // Function to call. 41 41 ); … … 57 57 esc_html__( 'Imsanity', 'imsanity' ), 58 58 $permissions, 59 IMSANITY_PLUGIN_FILE_REL,59 'imsanity-options', 60 60 'imsanity_network_settings' 61 61 ); 62 62 } 63 } 64 65 /** 66 * Get the settings link, based on whether we are in a multi-site network admin or not. 67 * 68 * @return string The URL for the settings page. 69 */ 70 function imsanity_get_settings_link() { 71 if ( is_multisite() && is_network_admin() ) { 72 return network_admin_url( 'settings.php?page=imsanity-options' ); 73 } 74 return admin_url( 'options-general.php?page=imsanity-options' ); 63 75 } 64 76 … … 74 86 } 75 87 if ( is_multisite() && is_network_admin() ) { 76 $settings_link = '<a href="' . network_admin_url( 'settings.php?page=' . IMSANITY_PLUGIN_FILE_REL) . '">' . esc_html__( 'Settings', 'imsanity' ) . '</a>';88 $settings_link = '<a href="' . imsanity_get_settings_link() . '">' . esc_html__( 'Settings', 'imsanity' ) . '</a>'; 77 89 } else { 78 $settings_link = '<a href="' . admin_url( 'options-general.php?page=' . IMSANITY_PLUGIN_FILE_REL) . '">' . esc_html__( 'Settings', 'imsanity' ) . '</a>';90 $settings_link = '<a href="' . imsanity_get_settings_link() . '">' . esc_html__( 'Settings', 'imsanity' ) . '</a>'; 79 91 } 80 92 array_unshift( $links, $settings_link ); … … 172 184 $data->imsanity_png_to_jpg = IMSANITY_DEFAULT_PNG_TO_JPG; 173 185 $data->imsanity_quality = IMSANITY_DEFAULT_QUALITY; 186 $data->imsanity_avif_quality = IMSANITY_DEFAULT_AVIF_QUALITY; 187 $data->imsanity_webp_quality = IMSANITY_DEFAULT_WEBP_QUALITY; 174 188 $data->imsanity_delete_originals = false; 175 189 return $data; … … 318 332 <tr> 319 333 <th scope="row"> 334 <label for='imsanity_avif_quality'><?php esc_html_e( 'AVIF image quality', 'imsanity' ); ?> 335 </th> 336 <td> 337 <input type='text' id='imsanity_avif_quality' name='imsanity_avif_quality' class='small-text' value='<?php echo (int) $settings->imsanity_avif_quality; ?>' /> 338 <?php esc_html_e( 'Usable values are 1-92.', 'imsanity' ); ?> 339 <p class='description'><?php esc_html_e( 'Only used when resizing images, does not affect thumbnails.', 'imsanity' ); ?></p> 340 </td> 341 </tr> 342 <tr> 343 <th scope="row"> 344 <label for='imsanity_webp_quality'><?php esc_html_e( 'WebP image quality', 'imsanity' ); ?> 345 </th> 346 <td> 347 <input type='text' id='imsanity_webp_quality' name='imsanity_webp_quality' class='small-text' value='<?php echo (int) $settings->imsanity_webp_quality; ?>' /> 348 <?php esc_html_e( 'Usable values are 1-92.', 'imsanity' ); ?> 349 <p class='description'><?php esc_html_e( 'Only used when resizing images, does not affect thumbnails.', 'imsanity' ); ?></p> 350 </td> 351 </tr> 352 <tr> 353 <th scope="row"> 320 354 <label for"imsanity_bmp_to_jpg"><?php esc_html_e( 'Convert BMP to JPG', 'imsanity' ); ?></label> 321 355 </th> 322 356 <td> 323 357 <input type="checkbox" id="imsanity_bmp_to_jpg" name="imsanity_bmp_to_jpg" value="true" <?php checked( $settings->imsanity_bmp_to_jpg ); ?> /> 324 <?php esc_html_e( 'Only applies to new image uploads, existing BMP images cannot be converted or resized.', 'imsanity' ); ?> 358 <?php 359 printf( 360 /* translators: %s: link to install EWWW Image Optimizer plugin */ 361 esc_html__( 'Only applies to new image uploads, existing images may be converted with %s.', 'imsanity' ), 362 '<a href="' . esc_url( admin_url( 'plugin-install.php?s=ewww+image+optimizer&tab=search&type=term' ) ) . '">EWWW Image Optimizer</a>' 363 ); 364 ?> 325 365 </td> 326 366 </tr> … … 349 389 </td> 350 390 </tr> 391 <?php if ( is_file( imsanity_debug_log_path() ) ) : ?> 392 <tr> 393 <th><?php esc_html_e( 'Debug Log', 'imsanity' ); ?></th> 394 <td> 395 <p> 396 <a target='_blank' href='<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?action=imsanity_view_debug_log' ), 'imsanity-options' ) ); ?>'><?php esc_html_e( 'View Log', 'imsanity' ); ?></a> - 397 <a href='<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?action=imsanity_delete_debug_log' ), 'imsanity-options' ) ); ?>'><?php esc_html_e( 'Clear Log', 'imsanity' ); ?></a> 398 </p> 399 </td> 400 </tr> 401 <?php endif; ?> 351 402 </table> 352 403 … … 387 438 $data->imsanity_png_to_jpg = ! empty( $_POST['imsanity_png_to_jpg'] ); 388 439 $data->imsanity_quality = isset( $_POST['imsanity_quality'] ) ? imsanity_jpg_quality( intval( $_POST['imsanity_quality'] ) ) : 82; 440 $data->imsanity_avif_quality = isset( $_POST['imsanity_avif_quality'] ) ? imsanity_avif_quality( intval( $_POST['imsanity_avif_quality'] ) ) : 86; 441 $data->imsanity_webp_quality = isset( $_POST['imsanity_webp_quality'] ) ? imsanity_webp_quality( intval( $_POST['imsanity_webp_quality'] ) ) : 86; 389 442 $data->imsanity_delete_originals = ! empty( $_POST['imsanity_delete_originals'] ); 390 443 391 $ success = $wpdb->update(444 $wpdb->update( 392 445 $wpdb->imsanity_ms, 393 446 array( 'data' => maybe_serialize( $data ) ), … … 501 554 add_option( 'imsanity_png_to_jpg', $settings->imsanity_png_to_jpg, '', false ); 502 555 add_option( 'imsanity_quality', $settings->imsanity_quality, '', false ); 556 add_option( 'imsanity_avif_quality', $settings->imsanity_avif_quality, '', false ); 557 add_option( 'imsanity_webp_quality', $settings->imsanity_webp_quality, '', false ); 503 558 add_option( 'imsanity_delete_originals', $settings->imsanity_delete_originals, '', false ); 504 559 if ( ! get_option( 'imsanity_version' ) ) { … … 528 583 register_setting( 'imsanity-settings-group', 'imsanity_png_to_jpg', 'boolval' ); 529 584 register_setting( 'imsanity-settings-group', 'imsanity_quality', 'imsanity_jpg_quality' ); 585 register_setting( 'imsanity-settings-group', 'imsanity_avif_quality', 'imsanity_avif_quality' ); 586 register_setting( 'imsanity-settings-group', 'imsanity_webp_quality', 'imsanity_webp_quality' ); 530 587 register_setting( 'imsanity-settings-group', 'imsanity_delete_originals', 'boolval' ); 588 } 589 590 /** 591 * Set the quality based on the mime type of the image being resized. 592 * 593 * @param int $quality The quality currently set. 594 * @param string $mime_type The mime type of the image being resized. 595 * @return int The (potentially) adjusted quality level. 596 */ 597 function imsanity_editor_quality( $quality, $mime_type = '' ) { 598 if ( 'image/avif' === $mime_type ) { 599 $new_quality = imsanity_avif_quality(); 600 } elseif ( 'image/webp' === $mime_type ) { 601 $new_quality = imsanity_webp_quality(); 602 } elseif ( 'image/jpeg' === $mime_type ) { 603 $new_quality = imsanity_jpg_quality(); 604 } 605 if ( ! empty( $new_quality ) && $new_quality > 0 && $new_quality <= 92 ) { 606 return $new_quality; 607 } 608 return $quality; 531 609 } 532 610 … … 545 623 } else { 546 624 return IMSANITY_DEFAULT_QUALITY; 625 } 626 } 627 628 /** 629 * Validate and return the AVIF quality setting. 630 * 631 * @param int $quality The AVIF quality currently set. 632 * @return int The (potentially) adjusted quality level. 633 */ 634 function imsanity_avif_quality( $quality = null ) { 635 if ( is_null( $quality ) ) { 636 $quality = get_option( 'imsanity_avif_quality' ); 637 } 638 if ( preg_match( '/^(100|[1-9][0-9]?)$/', $quality ) ) { 639 return (int) $quality; 640 } else { 641 return IMSANITY_DEFAULT_AVIF_QUALITY; 642 } 643 } 644 645 /** 646 * Validate and return the WebP quality setting. 647 * 648 * @param int $quality The WebP quality currently set. 649 * @return int The (potentially) adjusted quality level. 650 */ 651 function imsanity_webp_quality( $quality = null ) { 652 if ( is_null( $quality ) ) { 653 $quality = get_option( 'imsanity_webp_quality' ); 654 } 655 if ( preg_match( '/^(100|[1-9][0-9]?)$/', $quality ) ) { 656 return (int) $quality; 657 } else { 658 return IMSANITY_DEFAULT_WEBP_QUALITY; 547 659 } 548 660 } … … 779 891 780 892 <tr> 781 <th scope="row"><?php esc_html_e( 'Images uploaded elsewhere (Theme headers, backgrounds, logos, etc)', 'imsanity' ); ?></th> 782 <td> 783 <label for="imsanity_max_width_other"><?php esc_html_e( 'Max Width', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_width_other" value="<?php echo (int) get_option( 'imsanity_max_width_other', IMSANITY_DEFAULT_MAX_WIDTH ); ?>" /> 784 <label for="imsanity_max_height_other"><?php esc_html_e( 'Max Height', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_height_other" value="<?php echo (int) get_option( 'imsanity_max_height_other', IMSANITY_DEFAULT_MAX_HEIGHT ); ?>" /> <?php esc_html_e( 'in pixels, enter 0 to disable', 'imsanity' ); ?> 785 </td> 786 </tr> 787 893 <th scope="row"><?php esc_html_e( 'Images uploaded elsewhere (Theme headers, backgrounds, logos, etc)', 'imsanity' ); ?></th> 894 <td> 895 <label for="imsanity_max_width_other"><?php esc_html_e( 'Max Width', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_width_other" value="<?php echo (int) get_option( 'imsanity_max_width_other', IMSANITY_DEFAULT_MAX_WIDTH ); ?>" /> 896 <label for="imsanity_max_height_other"><?php esc_html_e( 'Max Height', 'imsanity' ); ?></label> <input type="number" step="1" min="0" class="small-text" name="imsanity_max_height_other" value="<?php echo (int) get_option( 'imsanity_max_height_other', IMSANITY_DEFAULT_MAX_HEIGHT ); ?>" /> <?php esc_html_e( 'in pixels, enter 0 to disable', 'imsanity' ); ?> 897 </td> 898 </tr> 788 899 789 900 <tr> … … 800 911 <tr> 801 912 <th scope="row"> 913 <label for='imsanity_avif_quality' ><?php esc_html_e( 'AVIF image quality', 'imsanity' ); ?> 914 </th> 915 <td> 916 <input type='text' id='imsanity_avif_quality' name='imsanity_avif_quality' class='small-text' value='<?php echo (int) imsanity_avif_quality(); ?>' /> 917 <?php esc_html_e( 'Usable values are 1-92.', 'imsanity' ); ?> 918 <p class='description'><?php esc_html_e( 'Only used when resizing images, does not affect thumbnails.', 'imsanity' ); ?></p> 919 </td> 920 </tr> 921 922 <tr> 923 <th scope="row"> 924 <label for='imsanity_webp_quality' ><?php esc_html_e( 'WebP image quality', 'imsanity' ); ?> 925 </th> 926 <td> 927 <input type='text' id='imsanity_webp_quality' name='imsanity_webp_quality' class='small-text' value='<?php echo (int) imsanity_webp_quality(); ?>' /> 928 <?php esc_html_e( 'Usable values are 1-92.', 'imsanity' ); ?> 929 <p class='description'><?php esc_html_e( 'Only used when resizing images, does not affect thumbnails.', 'imsanity' ); ?></p> 930 </td> 931 </tr> 932 933 <tr> 934 <th scope="row"> 802 935 <label for="imsanity_bmp_to_jpg"><?php esc_html_e( 'Convert BMP To JPG', 'imsanity' ); ?></label> 803 936 </th> 804 937 <td> 805 938 <input type="checkbox" id="imsanity_bmp_to_jpg" name="imsanity_bmp_to_jpg" value="true" <?php checked( (bool) get_option( 'imsanity_bmp_to_jpg', IMSANITY_DEFAULT_BMP_TO_JPG ) ); ?> /> 806 <?php esc_html_e( 'Only applies to new image uploads, existing BMP images cannot be converted or resized.', 'imsanity' ); ?> 939 <?php 940 printf( 941 /* translators: %s: link to install EWWW Image Optimizer plugin */ 942 esc_html__( 'Only applies to new image uploads, existing images may be converted with %s.', 'imsanity' ), 943 '<a href="' . esc_url( admin_url( 'plugin-install.php?s=ewww+image+optimizer&tab=search&type=term' ) ) . '">EWWW Image Optimizer</a>' 944 ); 945 ?> 807 946 </td> 808 947 </tr> … … 831 970 </td> 832 971 </tr> 972 <?php if ( is_file( imsanity_debug_log_path() ) ) : ?> 973 <tr> 974 <th><?php esc_html_e( 'Debug Log', 'imsanity' ); ?></th> 975 <td> 976 <p> 977 <a target='_blank' href='<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?action=imsanity_view_debug_log' ), 'imsanity-options' ) ); ?>'><?php esc_html_e( 'View Log', 'imsanity' ); ?></a> - 978 <a href='<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?action=imsanity_delete_debug_log' ), 'imsanity-options' ) ); ?>'><?php esc_html_e( 'Clear Log', 'imsanity' ); ?></a> 979 </p> 980 </td> 981 </tr> 982 <?php endif; ?> 833 983 </table> 834 984
Note: See TracChangeset
for help on using the changeset viewer.