File: /home/yoyo0427/www/www.yn-artspace.com/wp-content/plugins/imagemagick-engine/imagemagick-engine.php
<?php
/*
Plugin Name: ImageMagick Engine
Plugin URI: https://wordpress.org/plugins/imagemagick-engine/
Description: Improve the quality of re-sized images by replacing standard GD library with ImageMagick
Author: Orangelab
Author URI: https://orangelab.com/
Version: 1.7.13
Text Domain: imagemagick-engine
License: GPLv2 or later
Copyright @ 2024 Orangelab AB
Licenced under the GNU GPL:
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Must not be called directly' );
}
/*
* Constants
*/
define( 'IME_OPTION_VERSION', 1 );
define( 'IME_VERSION', '1.7.13' );
/*
* Global variables
*/
// Plugin options default values -- change on plugin admin page
global $ime_options_default;
$ime_options_default = [
'enabled' => false,
'mode' => null,
'cli_path' => null,
'handle_sizes' => [
'thumbnail' => 'size',
'medium' => 'quality',
'medium_large' => 'quality',
'large' => 'quality',
],
'quality' => [
'quality' => -1,
'size' => 70,
],
'interlace' => false,
'quality' => '',
'version' => constant( 'IME_OPTION_VERSION' ),
];
// Available modes
$ime_available_modes = [
'php' => __( 'Imagick PHP module', 'imagemagick-engine' ),
'cli' => __( 'ImageMagick command-line', 'imagemagick-engine' ),
];
// Available quality modes
$ime_available_quality_modes = [ 'quality', 'size', 'skip' ];
// Current options
$ime_options = null;
// Keep track of attachment file & sizes between different filters
$ime_image_sizes = null;
$ime_image_file = null;
/*
* Functions
*/
add_action( 'plugins_loaded', 'ime_init_early' );
add_action( 'init', 'ime_init' );
/* Plugin setup (early) */
function ime_init_early() {
if ( ime_active() ) {
add_filter( 'intermediate_image_sizes_advanced', 'ime_filter_image_sizes', 99, 1 );
add_filter( 'wp_read_image_metadata', 'ime_filter_read_image_metadata', 10, 3 );
add_filter( 'wp_generate_attachment_metadata', 'ime_filter_attachment_metadata', 10, 2 );
}
}
/* Plugin setup */
function ime_init() {
load_plugin_textdomain( 'imagemagick-engine', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
if ( is_admin() ) {
add_action( 'admin_menu', 'ime_admin_menu' );
add_filter( 'plugin_action_links', 'ime_filter_plugin_actions', 10, 2 );
add_filter( 'media_meta', 'ime_filter_media_meta', 10, 2 );
add_action( 'wp_ajax_ime_test_im_path', 'ime_ajax_test_im_path' );
add_action( 'wp_ajax_ime_process_image', 'ime_ajax_process_image' );
add_action( 'wp_ajax_ime_regeneration_get_images', 'ime_ajax_regeneration_get_images' );
wp_register_script( 'alpinejs', 'https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js', [], constant('IME_VERSION'), ['strategy' => 'defer'] );
wp_register_script( 'ime-admin', plugins_url( '/js/ime-admin.js', __FILE__ ), [ 'jquery', 'jquery-ui-progressbar', 'alpinejs' ], constant('IME_VERSION') );
}
}
/* Are we enabled with valid mode? */
function ime_active() {
return ime_get_option( 'enabled' ) && ime_mode_valid();
}
/* Check if mode is valid */
function ime_mode_valid( $mode = null ) {
if ( empty( $mode ) ) {
$mode = ime_get_option( 'mode' );
}
$fn = 'ime_im_' . $mode . '_valid';
return ( ! empty( $mode ) && function_exists( $fn ) && call_user_func( $fn ) );
}
// Check version of a registered WordPress script
function ime_script_version_compare( $handle, $version, $compare = '>=' ) {
global $wp_scripts;
if ( ! is_a( $wp_scripts, 'WP_Scripts' ) ) {
$wp_scripts = new WP_Scripts();
}
$query = $wp_scripts->query( $handle, 'registered' );
if ( ! $query ) {
return false;
}
return version_compare( $query->ver, $version, $compare );
}
// Get array of available image sizes
function ime_available_image_sizes() {
global $_wp_additional_image_sizes;
$sizes = [
'thumbnail' => __( 'Thumbnail', 'imagemagick-engine' ),
'medium' => __( 'Medium', 'imagemagick-engine' ),
'medium_large' => __( 'Medium Large', 'imagemagick-engine' ),
'large' => __( 'Large', 'imagemagick-engine' ),
]; // Standard sizes
if ( isset( $_wp_additional_image_sizes ) && count( $_wp_additional_image_sizes ) ) {
foreach ( $_wp_additional_image_sizes as $name => $spec ) {
$sizes[ $name ] = $name;
}
}
return $sizes;
}
/*
* Plugin option handling
*/
// Setup plugin options
function ime_setup_options() {
global $ime_options;
// Already setup?
if ( is_array( $ime_options ) ) {
return;
}
$ime_options = get_option( 'ime_options' );
// No stored options yet?
if ( ! is_array( $ime_options ) ) {
global $ime_options_default;
$ime_options = $ime_options_default ?? array();
}
// Do we need to upgrade options?
if ( ! array_key_exists( 'version', $ime_options )
|| $ime_options['version'] < constant( 'IME_OPTION_VERSION' ) ) {
/*
* Future compatability code goes here!
*/
$ime_options['version'] = constant( 'IME_OPTION_VERSION' );
ime_store_options();
}
}
// Store plugin options
function ime_store_options() {
global $ime_options;
ime_setup_options();
$stored_options = get_option( 'ime_options' );
if ( $stored_options === false ) {
add_option( 'ime_options', $ime_options, null, false );
} else {
update_option( 'ime_options', $ime_options );
}
}
// Get plugin option
function ime_get_option( $option_name, $default = null ) {
ime_setup_options();
global $ime_options, $ime_options_default;
if ( is_array( $ime_options ) && array_key_exists( $option_name, $ime_options ) ) {
return $ime_options[ $option_name ];
}
if ( ! is_null( $default ) ) {
return $default;
}
if ( is_array( $ime_options_default ) && array_key_exists( $option_name, $ime_options_default ) ) {
return $ime_options_default[ $option_name ];
}
return null;
}
// Set plugin option
function ime_set_option( $option_name, $option_value, $store = false ) {
ime_setup_options();
global $ime_options;
$ime_options[ $option_name ] = $option_value;
if ( $store ) {
ime_store_options();
}
}
// Should images be converted with interlace or not
function ime_interlace() {
return ime_get_option( 'interlace' );
}
// Get image quality setting for type
function ime_get_quality( $resize_mode = 'quality' ) {
$quality = ime_get_option( 'quality', '-1' );
if ( ! $quality ) {
return -1;
}
if ( ! is_array( $quality ) ) {
return $quality;
}
if ( isset( $quality[ $resize_mode ] ) ) {
return $quality[ $resize_mode ];
}
return -1;
}
// Get resize mode for size
function ime_get_resize_mode( $size ) {
$handle_sizes = ime_get_option( 'handle_sizes' );
if ( isset( $handle_sizes[ $size ] ) && is_string( $handle_sizes[ $size ] ) ) {
return $handle_sizes[ $size ];
} else {
return 'quality'; // default to quality
}
}
/*
* WP integration & image handling functions
*/
/*
* Filter image sizes (in wp_generate_attachment_metadata()).
*
* We store the sizes we are interested in, and remove those sizes from the
* list so that WP doesn't handle them -- we will take care of them later.
*
* The reason we do things this way is so we do not resize image twize (once
* by WordPress using GD, and then again by us).
*/
function ime_filter_image_sizes( $sizes ) {
global $ime_image_sizes;
$handle_sizes = ime_get_option( 'handle_sizes' );
foreach ( $handle_sizes as $s => $handle ) {
if ( ! $handle || $handle == 'skip' || ! array_key_exists( $s, $sizes ) ) {
continue;
}
$ime_image_sizes[ $s ] = $sizes[ $s ];
unset( $sizes[ $s ] );
}
return $sizes;
}
/*
* Filter to get target file name.
*
* Function wp_generate_attachment_metadata calls wp_read_image_metadata which
* gives us a hook to get the target filename.
*/
function ime_filter_read_image_metadata( $metadata, $file, $ignore ) {
global $ime_image_file;
$ime_image_file = $file;
return $metadata;
}
/*
* Filter new attachment metadata
*
* Resize image for the sizes we are interested in.
*
* Parts of function copied from wp-includes/media.php:image_resize()
*/
function ime_filter_attachment_metadata( $metadata, $attachment_id ) {
global $ime_image_sizes, $ime_image_file;
// Any sizes we are interested in?
if ( empty( $ime_image_sizes ) ) {
return $metadata;
}
$attachment = get_post( $attachment_id );
// We can only process attachments.
if ( 'attachment' !== get_post_type( $attachment ) ) {
return $metadata;
}
// Make sure file exists on server
if ( ! $ime_image_file || ! file_exists( $ime_image_file ) ) {
return $metadata;
}
$editor = wp_get_image_editor( $ime_image_file );
if ( is_wp_error( $editor ) ) {
// Display a more helpful error message.
if ( 'image_no_editor' === $editor->get_error_code() ) {
$editor = new WP_Error( 'image_no_editor', __( 'The current image editor cannot process this file type.', 'regenerate-thumbnails' ) );
}
$editor->add_data( array(
'attachment' => $attachment,
'status' => 415,
) );
return $editor;
}
// Get size & image type of original image
$old_stats = wp_getimagesize( $ime_image_file );
if ( ! $old_stats || is_wp_error( $old_stats ) ) {
return $metadata;
}
list($orig_w, $orig_h, $orig_type) = $old_stats;
/*
* Sort out the filename, extension (and image type) of resized images
*/
$info = pathinfo( $ime_image_file );
$dir = $info['dirname'];
$ext = $info['extension'];
/*
* Do the actual resize
*/
foreach ( $ime_image_sizes as $size => $size_data ) {
$width = $size_data['width'];
$height = $size_data['height'];
// ignore sizes equal to or larger than original size
if ( $orig_w <= $width && $orig_h <= $height ) {
continue;
}
$crop = $size_data['crop'];
$dims = image_resize_dimensions( $orig_w, $orig_h, $width, $height, $crop );
if ( ! $dims ) {
continue;
}
list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = $dims;
$suffix = "{$dst_w}x{$dst_h}";
$new_filename = $editor->generate_filename( $suffix, null, $ext );
$resized = ime_im_resize( $ime_image_file, $new_filename, $dst_w, $dst_h, $crop, ime_get_resize_mode( $size ) );
if ( ! $resized ) {
continue;
}
$metadata['sizes'][ $size ] = [
'file' => wp_basename( $new_filename ),
'width' => $dst_w,
'height' => $dst_h,
];
if ( ! isset( $metadata['image-converter'] ) || ! is_array( $metadata['image-converter'] ) ) {
$metadata['image-converter'] = [];
}
$metadata['image-converter'][ $size ] = 'IME';
// Set correct file permissions
$stat = stat( dirname( $new_filename ) );
$perms = $stat['mode'] & 0000666; //same permissions as parent folder, strip off the executable bits
@ chmod( $new_filename, $perms );
}
$ime_image_sizes = null;
return $metadata;
}
// Resize file by calling mode specific resize function
function ime_im_resize( $old_file, $new_file, $width, $height, $crop, $resize_mode = 'quality' ) {
$mode = ime_get_option( 'mode' );
$fn = 'ime_im_' . $mode . '_valid';
if ( empty( $mode ) || ! function_exists( $fn ) || ! call_user_func( $fn ) ) {
return false;
}
$fn = 'ime_im_' . $mode . '_resize';
$success = ( function_exists( $fn ) && call_user_func( $fn, $old_file, $new_file, $width, $height, $crop, $resize_mode ) );
do_action( 'ime_after_resize', $success, $old_file, $new_file, $width, $height, $crop, $resize_mode );
return $success;
}
// Is this the filename of a jpeg?
function ime_im_filename_is_jpg( $filename ) {
$info = pathinfo( $filename );
$ext = $info['extension'];
return ( strcasecmp( $ext, 'jpg' ) == 0 ) || ( strcasecmp( $ext, 'jpeg' ) == 0 );
}
// Get file extenstion
function ime_im_get_filetype( $filename ) {
$info = pathinfo( $filename );
return strtolower( $info['extension'] );
}
/*
* PHP ImageMagick ("Imagick") class handling
*/
// Does class exist?
function ime_im_php_valid() {
return class_exists( 'Imagick' );
}
// Resize file using PHP Imagick class
function ime_im_php_resize( $old_file, $new_file, $width, $height, $crop, $resize_mode = 'quality' ) {
$im = new Imagick( $old_file );
if ( ! $im->valid() ) {
return false;
}
try {
$im->setImageFormat( ime_im_get_filetype( $old_file ) );
$quality = ime_get_quality( $resize_mode );
if ( is_numeric( $quality ) && $quality >= 0 && $quality <= 100 && ime_im_filename_is_jpg( $new_file ) ) {
$im->setImageCompression( Imagick::COMPRESSION_JPEG );
$im->setImageCompressionQuality( $quality );
}
if ( ime_interlace() ) {
$im->setInterlaceScheme( Imagick::INTERLACE_PLANE );
}
if ( $resize_mode == 'size' ) {
$im->stripImage();
}
if ( $crop ) {
/*
* Unfortunately we cannot use the PHP module
* cropThumbnailImage() function as it strips profile data.
*
* Crop an area proportional to target $width and $height and
* fall through to scaleImage() below.
*/
$geo = $im->getImageGeometry();
$orig_width = $geo['width'];
$orig_height = $geo['height'];
if ( ( $orig_width / $width ) < ( $orig_height / $height ) ) {
$crop_width = $orig_width;
$crop_height = ceil( ( $height * $orig_width ) / $width );
$off_x = 0;
$off_y = ceil( ( $orig_height - $crop_height ) / 2 );
} else {
$crop_width = ceil( ( $width * $orig_height ) / $height );
$crop_height = $orig_height;
$off_x = ceil( ( $orig_width - $crop_width ) / 2 );
$off_y = 0;
}
$im->cropImage( $crop_width, $crop_height, $off_x, $off_y );
}
$im->scaleImage( $width, $height, true );
$im->setImagePage( $width, $height, 0, 0 ); // to make sure canvas is correct
$im->writeImage( $new_file );
return file_exists( $new_file );
} catch ( ImagickException $ie ) {
return false;
}
}
/*
* ImageMagick executable handling
*/
// Check if path is executable depending on OS
function ime_is_executable($fullpath) {
$whereIsCommand = (PHP_OS == 'WINNT') ? 'where' : 'which';
return function_exists('shell_exec') ? `$whereIsCommand $fullpath` : @is_executable($fullpath);
}
// Do we have a valid ImageMagick executable set?
function ime_im_cli_valid() {
$cmd = ime_im_cli_command();
return !empty($cmd) && ime_is_executable($cmd);
}
// Test if we are allowed to exec executable!
function ime_im_cli_check_executable($fullpath) {
if ( ! ime_is_executable($fullpath) || ! function_exists('exec') ) {
return false;
}
@exec( '"' . $fullpath . '" --version', $output );
if ( is_array($output) && (count( $output ) > 0) ) {
preg_match('/ImageMagick ([0-9]+\.[0-9]+\.[0-9]+)/', $output[0], $im_version);
ime_set_option( 'imagemagick_version', $im_version[1], true );
return true;
}
return false;
}
/*
* Try to get realpath of path
*
* This won't work if there is open_basename restrictions.
*/
function ime_try_realpath( $path ) {
$realpath = @realpath( $path );
if ( $realpath ) {
return escapeshellcmd( $realpath );
} else {
return str_replace([';', ' ', '=', '`'], '', escapeshellcmd( $path ));
}
}
// Check if path leads to ImageMagick executable
function ime_im_cli_check_command( $path ) {
$path = ime_try_realpath( $path );
$executables = [ 'magick', 'convert' ];
foreach ( $executables as $executable ) {
$cmd = $path . '/' . $executable;
if ( ime_im_cli_check_executable( $cmd ) ) {
return $cmd;
}
$cmd = $cmd . '.exe';
if ( ime_im_cli_check_executable( $cmd ) ) {
return $cmd;
}
}
return null;
}
// Try to find a valid ImageMagick executable
function ime_im_cli_find_command() {
$possible_paths = [ '/usr/bin', '/usr/local/bin' ];
foreach ( $possible_paths as $path ) {
if ( ime_im_cli_check_command( $path ) ) {
return $path;
}
}
return null;
}
// Get ImageMagick executable
function ime_im_cli_command() {
$path = ime_get_option( 'cli_path' );
if ( ! empty( $path ) ) {
return ime_im_cli_check_command( $path );
}
$path = ime_im_cli_find_command();
if ( empty( $path ) ) {
return null;
}
ime_set_option( 'cli_path', $path, true );
return ime_im_cli_check_command( $path );
}
// Check if we are running under Windows (which differs for character escape)
function ime_is_windows() {
return ( constant( 'PHP_SHLIB_SUFFIX' ) == 'dll' );
}
// Resize using ImageMagick executable
function ime_im_cli_resize( $old_file, $new_file, $width, $height, $crop, $resize_mode = 'quality' ) {
$cmd = ime_im_cli_command();
if ( empty( $cmd ) ) {
return false;
}
$old_file = addslashes( $old_file );
$new_file = addslashes( $new_file );
$geometry = $width . 'x' . $height;
// limits are 150mb and 128mb
$cmd = "\"$cmd\" \"$old_file\" -limit memory 157286400 -limit map 134217728 -resize $geometry";
if ( $crop ) {
// '^' is an escape character on Windows
$cmd .= ( ime_is_windows() ? '^^' : '^' ) . " -gravity center -extent $geometry";
} else {
$cmd .= '!'; // force these dimensions
}
$quality = ime_get_quality( $resize_mode );
if ( is_numeric( $quality ) && $quality >= 0 && $quality <= 100 && ime_im_filename_is_jpg( $new_file ) ) {
$cmd .= ' -quality ' . intval( $quality );
}
if ( ime_interlace() ) {
$cmd .= ' -interlace Plane';
}
if ( $resize_mode == 'size' ) {
$cmd .= ' -strip';
}
$cmd .= ' "' . $new_file . '"';
exec( $cmd );
return file_exists( $new_file );
}
/*
* AJAX functions
*/
// Test if a path is correct for IM binary
function ime_ajax_test_im_path() {
if ( ! current_user_can( 'install_plugins' ) || ! wp_verify_nonce( $_REQUEST['ime_nonce'], 'ime-admin-nonce') ) {
wp_die( 'Sorry, but you do not have permissions to perform this action.' );
}
$r = ime_im_cli_check_command( @realpath( $_REQUEST['cli_path'] ) );
echo empty( $r ) ? '0' : '1';
wp_die();
}
// Get list of attachments to regenerate
function ime_ajax_regeneration_get_images() {
global $wpdb;
if ( ! current_user_can( 'manage_options' ) || ! wp_verify_nonce( $_REQUEST['ime_nonce'], 'ime-admin-nonce') ) {
wp_die( 'Sorry, but you do not have permissions to perform this action.' );
}
// Query for the IDs only to reduce memory usage
$images = $wpdb->get_results( "SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' AND post_mime_type LIKE 'image/%' AND post_mime_type != 'image/svg+xml'" );
// Generate the list of IDs
$ids = [];
foreach ( $images as $image ) {
$ids[] = $image->ID;
}
$ids = implode( ',', $ids );
wp_die( $ids );
}
// Process single attachment ID
function ime_ajax_process_image() {
global $ime_image_sizes, $ime_image_file, $_wp_additional_image_sizes;
error_reporting( E_ERROR | E_WARNING );
if ( ! current_user_can( 'manage_options' ) || ! ime_mode_valid() || ! wp_verify_nonce( $_REQUEST['ime_nonce'], 'ime-admin-nonce') ) {
wp_die( '-1' );
}
if ( ! isset( $_REQUEST['id'] ) ) {
wp_die( '-1' );
}
$id = intval( $_REQUEST['id'] );
if ( $id <= 0 ) {
wp_die( '-1' );
}
$temp_sizes = $_REQUEST['sizes'];
if ( empty( $temp_sizes ) ) {
wp_die( '-1' );
}
$temp_sizes = explode( '|', $temp_sizes );
if ( count( $temp_sizes ) < 1 ) {
wp_die( '-1' );
}
$temp_sizes = apply_filters( 'intermediate_image_sizes', $temp_sizes );
foreach ( $temp_sizes as $s ) {
$sizes[ $s ] = [
'width' => '',
'height' => '',
'crop' => false,
];
if ( isset( $_wp_additional_image_sizes[ $s ]['width'] ) ) {
$sizes[ $s ]['width'] = intval( $_wp_additional_image_sizes[ $s ]['width'] ); // For theme-added sizes
} else {
$sizes[ $s ]['width'] = get_option( "{$s}_size_w" ); // For default sizes set in options
}
if ( isset( $_wp_additional_image_sizes[ $s ]['height'] ) ) {
$sizes[ $s ]['height'] = intval( $_wp_additional_image_sizes[ $s ]['height'] ); // For theme-added sizes
} else {
$sizes[ $s ]['height'] = get_option( "{$s}_size_h" ); // For default sizes set in options
}
if ( isset( $_wp_additional_image_sizes[ $s ]['crop'] ) ) {
$sizes[ $s ]['crop'] = intval( $_wp_additional_image_sizes[ $s ]['crop'] ); // For theme-added sizes
} else {
$sizes[ $s ]['crop'] = get_option( "{$s}_crop" ); // For default sizes set in options
}
}
remove_filter( 'intermediate_image_sizes_advanced', 'ime_filter_image_sizes', 99, 1 );
$sizes = apply_filters( 'intermediate_image_sizes_advanced', $sizes );
$force = isset( $_REQUEST['force'] ) && ! ! $_REQUEST['force'];
$ime_image_file = function_exists('wp_get_original_image_path') ? wp_get_original_image_path( $id ) : get_attached_file( $id );
if ( false === $ime_image_file || ! file_exists( $ime_image_file ) ) {
wp_die( '-1' );
}
$metadata = wp_get_attachment_metadata( $id );
// Do not re-encode IME images unless forced
if ( ! $force && isset( $metadata['image-converter'] ) && is_array( $metadata['image-converter'] ) ) {
$converter = $metadata['image-converter'];
foreach ( $sizes as $s => $ignore ) {
if ( isset( $converter[ $s ] ) && $converter[ $s ] == 'IME' ) {
unset( $sizes[ $s ] );
}
}
if ( count( $sizes ) < 1 ) {
wp_die( 1 );
}
}
$ime_image_sizes = $sizes;
set_time_limit( 60 );
$new_meta = ime_filter_attachment_metadata( $metadata, $id );
if ( is_wp_error( $new_meta ) ) {
wp_die( '-1' );
}
wp_update_attachment_metadata( $id, $new_meta );
/*
* Normally the old file gets overwritten by the new one when
* regenerating resized images.
*
* However, if the specifications of image sizes were changed this
* will result in different resized file names.
*
* Make sure they get deleted.
*/
// No old sizes, nothing to check
if ( ! isset( $metadata['sizes'] ) || empty( $metadata['sizes'] ) ) {
wp_die( '1' );
}
$dir = trailingslashit( dirname( $ime_image_file ) );
foreach ( $metadata['sizes'] as $size => $sizeinfo ) {
$old_file = $sizeinfo['file'];
// Does file exist in new meta?
$exists = false;
foreach ( $new_meta['sizes'] as $ignore => $new_sizeinfo ) {
if ( $old_file != $new_sizeinfo['file'] ) {
continue;
}
$exists = true;
break;
}
if ( $exists ) {
continue;
}
// Old file did not exist in new meta. Delete it!
@ unlink( $dir . $old_file );
}
wp_die( '1' );
}
/*
* Admin page functions
*/
/* Add admin page */
function ime_admin_menu() {
$ime_page = add_options_page( 'ImageMagick Engine', 'ImageMagick Engine', 'manage_options', 'imagemagick-engine', 'ime_option_page' );
$script_pages = [ $ime_page, 'media.php', 'media-new.php', 'media-upload.php', 'media-upload-popup', 'post.php', 'upload.php' ];
foreach ( $script_pages as $page ) {
add_action( 'admin_print_scripts-' . $page, 'ime_admin_print_scripts' );
add_action( 'admin_print_styles-' . $page, 'ime_admin_print_styles' );
}
}
/* Enqueue admin page scripts */
function ime_admin_print_scripts() {
wp_enqueue_script( 'ime-admin' );
$data = [
'noimg' => __( 'You dont have any images to regenerate', 'imagemagick-engine' ),
'done' => __( 'All done!', 'imagemagick-engine' ),
'processed_fmt' => __( 'Processed %d images', 'imagemagick-engine' ),
'failed' => '<strong>' . __( 'Failed to resize image!', 'imagemagick-engine' ) . '</strong>',
'resized' => __( 'Resized using ImageMagick Engine', 'imagemagick-engine' ),
'ime_nonce' => wp_create_nonce('ime-admin-nonce'),
];
wp_localize_script( 'ime-admin', 'ime_admin', $data );
}
/* Enqueue admin page style */
function ime_admin_print_styles() {
wp_enqueue_style( 'ime-admin-style', plugins_url( '/css/ime-admin.css', __FILE__ ), [] );
}
/* Add settings to plugin action links */
function ime_filter_plugin_actions( $links, $file ) {
if ( $file == plugin_basename( __FILE__ ) ) {
$settings_link = '<a href="options-general.php?page=imagemagick-engine">'
. __( 'Settings', 'imagemagick-engine' ) . '</a>';
array_unshift( $links, $settings_link ); // before other links
}
return $links;
}
/*
* Add admin information if attachment is converted using plugin
*/
function ime_filter_media_meta( $content, $post ) {
global $wp_version;
if ( ! ime_mode_valid() ) {
return $content;
}
if ( version_compare( $wp_version, '3.5.0', '>=' ) ) {
// WordPress 3.5 and newer
if ( ! wp_image_editor_supports( [ 'mime_type' => $post->post_mime_type ] ) ) {
return $content;
}
} else {
// WordPress older than 3.5
if ( ! gd_edit_image_support( $post->post_mime_type ) ) {
return $content;
}
}
$metadata = wp_get_attachment_metadata( $post->ID );
$ime = false;
if ( is_array( $metadata ) && array_key_exists( 'image-converter', $metadata ) ) {
foreach ( $metadata['image-converter'] as $size => $converter ) {
if ( $converter != 'IME' ) {
continue;
}
$ime = true;
break;
}
}
$content .= '</p><p>';
if ( $ime ) {
$message = ' <div class="ime-media-message" id="ime-message-' . $post->ID . '">' . __( 'Resized using ImageMagick Engine', 'imagemagick-engine' ) . '</div>';
$resize = __( 'Resize image', 'imagemagick-engine' );
$force = '1';
} else {
$message = '<div class="ime-media-message" id="ime-message-' . $post->ID . '" style="display: none;"></div>';
$resize = __( 'Resize using ImageMagick Engine', 'imagemagick-engine' );
$force = '0';
}
$handle_sizes = ime_get_option( 'handle_sizes' );
$sizes = [];
foreach ( $handle_sizes as $s => $h ) {
if ( ! $h ) {
continue;
}
$sizes[] = $s;
}
$sizes = implode( '|', $sizes );
$resize_call = 'imeRegenMediaImage(' . $post->ID . ', \'' . $sizes . '\', ' . $force . '); return false;';
$content .= '<a href="#" id="ime-regen-link-' . $post->ID . '" class="button ime-regen-button" onclick="' . $resize_call . '">' . $resize . '</a> ' . $message . ' <div id="ime-spinner-' . $post->ID . '" class="ime-spinner"><img src="' . admin_url( 'images/wpspin_light.gif' ) . '" /></div>';
return $content;
}
// Url to admin images
function ime_option_admin_images_url() {
return get_bloginfo( 'wpurl' ) . '/wp-admin/images/';
}
// Url to status icon
function ime_option_status_icon( $yes = true ) {
return ime_option_admin_images_url() . ( $yes ? 'yes' : 'no' ) . '.png';
}
// Display, or not
function ime_option_display( $display = true, $echo = true ) {
if ( $display ) {
return '';
}
$s = ' style="display: none" ';
if ( $echo ) {
echo $s;
}
return $s;
}
/* Plugin admin / status page */
function ime_option_page() {
global $ime_available_modes, $ime_available_quality_modes;
if ( ! current_user_can( 'install_plugins' ) ) {
wp_die( 'Sorry, but you do not have permissions to change settings.' );
}
/* Make sure post was from this page */
if ( count( $_POST ) > 0 ) {
check_admin_referer( 'ime-options' );
}
$sizes = ime_available_image_sizes();
if ( isset( $_POST['regenerate-images'] ) ) {
ime_show_regenerate_images( array_keys( $sizes ) );
return;
}
/* Should we update settings? */
if ( isset( $_POST['update_settings'] ) ) {
$new_enabled = isset( $_POST['enabled'] ) && ! ! $_POST['enabled'];
ime_set_option( 'enabled', $new_enabled );
if ( isset( $_POST['mode'] ) && array_key_exists( $_POST['mode'], $ime_available_modes ) ) {
ime_set_option( 'mode', $_POST['mode'] );
}
if ( isset( $_POST['cli_path'] ) ) {
ime_set_option( 'cli_path', ime_try_realpath( trim( $_POST['cli_path'] ) ) );
}
$new_quality = [
'quality' => -1,
'size' => 70,
];
if ( isset( $_POST['quality-quality'] ) ) {
if ( is_numeric( $_POST['quality-quality'] ) ) {
$new_quality['quality'] = min( 100, max( 0, intval( $_POST['quality-quality'] ) ) );
} elseif ( empty( $_POST['quality-quality'] ) ) {
$new_quality['quality'] = -1;
}
}
if ( isset( $_POST['quality-size'] ) ) {
if ( is_numeric( $_POST['quality-size'] ) ) {
$new_quality['size'] = min( 100, max( 0, intval( $_POST['quality-size'] ) ) );
} elseif ( empty( $_POST['quality-size'] ) ) {
$new_quality['size'] = -1;
}
}
ime_set_option( 'quality', $new_quality );
$new_interlace = isset( $_POST['interlace'] ) && ! ! $_POST['interlace'];
ime_set_option( 'interlace', $new_interlace );
$new_handle_sizes = [];
foreach ( $sizes as $s => $name ) {
$new_mode = isset( $_POST[ 'handle-mode-' . $s ] ) ? $_POST[ 'handle-mode-' . $s ] : 'skip';
if ( in_array( $new_mode, $ime_available_quality_modes ) ) {
$mode = $new_mode;
} else {
$mode = 'quality';
}
$new_handle_sizes[ $s ] = $mode;
}
ime_set_option( 'handle_sizes', $new_handle_sizes );
ime_store_options();
echo '<div id="message" class="updated fade"><p>'
. __( 'Settings updated', 'imagemagick-engine' )
. '</p></div>';
}
$modes_valid = $ime_available_modes;
$any_valid = false;
foreach ( $modes_valid as $m => $ignore ) {
$modes_valid[ $m ] = ime_mode_valid( $m );
if ( $modes_valid[ $m ] ) {
$any_valid = true;
}
}
$current_mode = ime_get_option( 'mode' );
if ( ! isset( $modes_valid[ $current_mode ] ) || ! $modes_valid[ $current_mode ] ) {
$current_mode = null;
}
if ( is_null( $current_mode ) && $any_valid ) {
foreach ( $modes_valid as $m => $valid ) {
if ( $valid ) {
$current_mode = $m;
break;
}
}
}
$enabled = ime_get_option( 'enabled' ) && $current_mode;
$cli_path = ime_get_option( 'cli_path' );
if ( is_null( $cli_path ) ) {
$cli_path = ime_im_cli_command();
}
$cli_path_ok = ime_im_cli_check_command( $cli_path );
$quality = ime_get_option( 'quality' );
if ( ! is_array( $quality ) ) {
$n = [
'quality' => -1,
'size' => 70,
];
if ( is_numeric( $quality ) && $quality > 0 ) {
$n['quality'] = $quality;
}
$quality = $n;
}
$interlace = ime_get_option( 'interlace' );
$handle_sizes = ime_get_option( 'handle_sizes' );
if ( ! $any_valid ) {
echo '<div id="warning" class="error"><p>'
. __( 'No valid ImageMagick mode found!', 'imagemagick-engine' )
. '</p></div>';
} elseif ( ! $enabled ) {
echo '<div id="warning" class="error"><p>'
. __( 'ImageMagick Engine is not enabled.', 'imagemagick-engine' )
. '</p></div>';
}
?>
<div class="wrap">
<div id="regen-message" class="hidden updated fade"></div>
<h2><?php _e( 'ImageMagick Engine Settings', 'imagemagick-engine' ); ?></h2>
<div id="ime-regeneration" title="<?php _e( 'Regenerating images', 'imagemagick-engine' ); ?>...">
<noscript><p><em><?php _e( 'You must enable Javascript in order to proceed!', 'imagemagick-engine' ); ?></em></p></noscript>
<p><strong><?php _e( 'Regenerating images', 'imagemagick-engine' ); ?>...</strong></p>
<div id="ime-regenbar">
<div id="ime-regenbar-percent"></div>
</div>
</div>
<form action="options-general.php?page=imagemagick-engine" method="post" name="update_options">
<?php wp_nonce_field( 'ime-options' ); ?>
<div id="poststuff" class="metabox-holder has-right-sidebar">
<div class="inner-sidebar">
<div class="meta-box-sortables ui-sortable">
<div id="regenerate-images-metabox" class="postbox">
<h3 class="hndle"><span><?php _e( 'Regenerate Images', 'imagemagick-engine' ); ?></span></h3>
<div class="inside">
<div class="submitbox">
<table border=0>
<tr>
<td scope="row" valign="top" style="padding-right: 20px;"><?php _e( 'Sizes', 'imagemagick-engine' ); ?>:</td>
<td>
<?php
foreach ( $sizes as $s => $name ) {
echo '<input type="checkbox" name="regen-size-' . $s . '" value="1" ' . ( ( isset( $handle_sizes[ $s ] ) && $handle_sizes[ $s ] != 'skip' && $handle_sizes[ $s ] != false ) ? ' checked="checked" ' : '' ) . ' /> ' . $name . '<br />';
}
?>
</td>
</tr>
</table>
<p><?php _e( 'ImageMagick images too', 'imagemagick-engine' ); ?>:
<input type="checkbox" name="force" id="force" value="1" /></p>
<?php
if ( ! ime_active() ) {
echo '<p class="howto">' . __( 'Resize will use standard WordPress functions.', 'imagemagick-engine' ) . '</p>';
}
?>
<p><input class="button-primary" type="button" id="regenerate-images" value="<?php _e( 'Regenerate', 'imagemagick-engine' ); ?>" /></p>
<p class="description"><?php _e( '(this can take a long time)', 'imagemagick-engine' ); ?></p>
</div>
</div>
</div>
</div>
</div>
<div id="post-body">
<div id="post-body-content">
<div id="ime-settings" class="postbox">
<h3 class="hndle"><span><?php _e( 'Settings', 'imagemagick-engine' ); ?></span></h3>
<div class="inside">
<table class="form-table">
<tr>
<th scope="row" valign="top"><?php _e( 'Enable enhanced image engine', 'imagemagick-engine' ); ?>:</th>
<td>
<input type="checkbox" id="enabled" name="enabled" value="1"
<?php
echo $enabled ? ' CHECKED ' : '';
echo $any_valid ? '' : ' disabled=disabled ';
?>
/>
</td>
</tr>
<tr>
<th scope="row" valign="top"><?php _e( 'Image engine', 'imagemagick-engine' ); ?>:</th>
<td>
<select id="ime-select-mode" name="mode">
<?php
foreach ( $modes_valid as $m => $valid ) {
echo '<option value="' . $m . '"';
if ( $m == $current_mode ) {
echo ' selected=selected ';
}
echo '>' . $ime_available_modes[ $m ] . '</option>';
}
?>
</select>
</td>
</tr>
<tr id="ime-row-php">
<th scope="row" valign="top"><?php _e( 'Imagick PHP module', 'imagemagick-engine' ); ?>:</th>
<td>
<img src="<?php echo ime_option_status_icon( $modes_valid['php'] ); ?>" />
<?php echo $modes_valid['php'] ? __( 'Imagick PHP module found', 'imagemagick-engine' ) : __( 'Imagick PHP module not found', 'imagemagick-engine' ); ?>
</td>
</tr>
<tr id="ime-row-cli">
<th scope="row" valign="top"><?php _e( 'ImageMagick path', 'imagemagick-engine' ); ?>:</th>
<td>
<img id="cli_path_yes" class="cli_path_icon" src="<?php echo ime_option_status_icon( true ); ?>" alt="" <?php ime_option_display( $cli_path_ok ); ?> />
<img id="cli_path_no" class="cli_path_icon" src="<?php echo ime_option_status_icon( false ); ?>" alt="<?php _e( 'Command not found', 'qp-qie' ); ?>" <?php ime_option_display( ! $cli_path_ok ); ?> />
<img id="cli_path_progress" src="<?php echo ime_option_admin_images_url(); ?>wpspin_light.gif" alt="<?php _e( 'Testing command...', 'qp-qie' ); ?>" <?php ime_option_display( false ); ?> />
<input id="cli_path" type="text" name="cli_path" size="<?php echo max( 30, strlen( $cli_path ) + 5 ); ?>" value="<?php echo $cli_path; ?>" />
<input type="button" name="ime_cli_path_test" id="ime_cli_path_test" value="<?php _e( 'Test path', 'imagemagick-engine' ); ?>" class="button-secondary" />
<span <?php ime_option_display( $cli_path_ok ); ?>><br><br><?php if (ime_get_option( 'imagemagick_version' )) { echo 'ImageMagick version ' . ime_get_option( 'imagemagick_version' ); } ?></span>
</td>
</tr>
<tr>
<th scope="row" valign="top"><?php _e( 'ImageMagick quality', 'imagemagick-engine' ); ?>:</th>
<td>
<p><input id="quality-quality" type="text" name="quality-quality" size="3" value="<?php echo ( ( isset( $quality['quality'] ) && $quality['quality'] > 0 ) ? $quality['quality'] : '' ); ?>" /> <?php _e( 'Optimize for quality', 'imagemagick-engine' ); ?></p>
<p><input id="quality-size" type="text" name="quality-size" size="3" value="<?php echo ( ( isset( $quality['size'] ) && $quality['size'] > 0 ) ? $quality['size'] : '' ); ?>" /> <?php _e( 'Optimize for size', 'imagemagick-engine' ); ?></p>
<p class="ime-description"><?php _e( 'Set to 0-100. Higher value gives better image quality but larger file size. Leave empty for default value, computed dynamically.', 'imagemagick-engine' ); ?></p>
</td>
</tr>
<tr>
<th scope="row" valign="top"><?php _e( 'Image interlace?', 'imagemagick-engine' ); ?>:</th>
<td>
<input type="checkbox" id="interlace" name="interlace" value="1"
<?php
echo $interlace ? ' CHECKED ' : '';
?>
/>
<p class="ime-description"><?php _e( 'Adds interlace option to ImageMagick when images are processed.', 'imagemagick-engine' ); ?></p>
</td>
</tr>
<tr>
<td colspan="2" class="ime-handle-table-wrapper">
<table border='0' class="ime-handle-table" id="ime-handle-table">
<tr>
<th scope="row" class="ime-headline" valign="top"><?php _e( 'Optimize for', 'imagemagick-engine' ); ?></th>
<td class="ime-headline ime-fixed-width"><?php _e( 'Quality', 'imagemagick-engine' ); ?></td>
<td class="ime-headline ime-fixed-width"><?php _e( 'Size', 'imagemagick-engine' ); ?></td>
<td class="ime-headline"><?php _e( 'None (use WP instead)', 'imagemagick-engine' ); ?></td>
</tr>
<?php
foreach ( $sizes as $s => $name ) {
// fixup for old (pre 1.5.0) options
if ( ! isset( $handle_sizes[ $s ] ) || ! $handle_sizes[ $s ] ) {
$handle_sizes[ $s ] = 'skip';
} elseif ( $handle_sizes[ $s ] === true ) {
$handle_sizes[ $s ] = 'quality';
}
?>
<tr>
<th scope="row" valign="top"><?php echo $name; ?></th>
<td class="ime-fixed-width">
<input type="radio" name="handle-mode-<?php echo $s; ?>" value="quality" <?php checked( 'quality', $handle_sizes[ $s ] ); ?> />
</td>
<td class="ime-fixed-width">
<input type="radio" name="handle-mode-<?php echo $s; ?>" value="size" <?php checked( 'size', $handle_sizes[ $s ] ); ?> />
</td>
<td>
<input type="radio" name="handle-mode-<?php echo $s; ?>" value="skip" <?php checked( 'skip', $handle_sizes[ $s ] ); ?> />
</td>
</tr>
<?php
}
?>
</table>
</td>
</tr>
<tr>
<td>
<input class="button-primary" type="submit" name="update_settings" value="<?php _e( 'Save Changes', 'imagemagick-engine' ); ?>" />
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</form>
</div>
<?php
}
?>