mambax7/extgallery

View on GitHub
assets/js/ml-slider/inc/metaslider.imagehelper.class.php

Summary

Maintainability
D
2 days
Test Coverage
<?php

/**
 * Helper class for resizing images, returning the correct URL to the image etc
 */
class MetaSliderImageHelper
{
    private $smart_crop = 'false';
    private $container_width; // slideshow width
    private $container_height; // slideshow height
    private $id; // slide/attachment ID
    private $url;
    private $path; // path to attachment on server
    private $use_image_editor;

    /**
     * Constructor
     *
     * @param int    $slide_id
     * @param int    $width  - required width of image
     * @param int    $height - required height of image
     * @param string $smart_crop
     * @param bool   $use_image_editor
     */
    public function __construct($slide_id, $width, $height, $smart_crop, $use_image_editor = true)
    {
        $upload_dir = wp_upload_dir();

        $this->id               = $slide_id;
        $this->url              = $upload_dir['baseurl'] . '/' . get_post_meta($slide_id, '_wp_attached_file', true);
        $this->path             = get_attached_file($slide_id);
        $this->container_width  = $width;
        $this->container_height = $height;
        $this->smart_crop       = $smart_crop;
        $this->use_image_editor = $use_image_editor;
    }

    /**
     * Return the crop dimensions.
     *
     * Smart Crop: If the image is smaller than the container width or height, then return
     * dimensions that respect the container size ratio. This ensures image displays in a
     * sane manner in responsive sliders
     *
     * @param  int $image_width
     * @param  int $image_height
     * @return array   image dimensions
     */
    private function get_crop_dimensions($image_width, $image_height)
    {
        if ('false' === $this->smart_crop) {
            return ['width' => $this->container_width, 'height' => $this->container_height];
        }

        $container_width  = $this->container_width;
        $container_height = $this->container_height;

        /**
         * Slideshow Width == Slide Width
         */
        if ($image_width == $container_width && $image_height == $container_height) {
            $new_slide_width  = $container_width;
            $new_slide_height = $container_height;
        }

        if ($image_width == $container_width && $image_height < $container_height) {
            $new_slide_height = $image_height;
            $new_slide_width  = $container_width / ($container_height / $image_height);
        }

        if ($image_width == $container_width && $image_height > $container_height) {
            $new_slide_width  = $container_width;
            $new_slide_height = $container_height;
        }

        /**
         * Slideshow Width < Slide Width
         */
        if ($image_width < $container_width && $image_height == $container_height) {
            $new_slide_width  = $image_width;
            $new_slide_height = $image_height / ($container_width / $image_width);
        }

        /**
         * Slide is smaller than slidehow - both width and height
         */
        if ($image_width < $container_width && $image_height < $container_height) {
            if ($container_width > $container_height) {
                // wide

                if ($image_width > $image_height) {
                    // wide
                    $new_slide_height = $image_height;
                    $new_slide_width  = $container_width / ($container_height / $image_height);

                    if ($new_slide_width > $image_width) {
                        $new_slide_width  = $image_width;
                        $new_slide_height = $container_height / ($container_width / $image_width);
                    }
                } else {
                    // tall
                    $new_slide_width  = $image_width;
                    $new_slide_height = $container_height / ($container_width / $image_width);

                    if ($new_slide_height > $image_height) {
                        $new_slide_height = $image_height;
                        $new_slide_width  = $container_width / ($container_height / $image_height);
                    }
                }
            } else {
                // tall
                if ($image_width > $image_height) {
                    // wide
                    $new_slide_height = $image_height;
                    $new_slide_width  = $container_width / ($container_height / $image_height);

                    if ($new_slide_width > $image_width) {
                        $new_slide_width  = $image_width;
                        $new_slide_height = $container_height / ($container_width / $image_width);
                    }
                } else {
                    // tall
                    $new_slide_width  = $image_width;
                    $new_slide_height = $container_height / ($container_width / $image_width);

                    if ($new_slide_height > $image_height) {
                        $new_slide_height = $image_height;
                        $new_slide_width  = $container_width / ($container_height / $image_height);
                    }
                }
            }
        }

        if ($image_width < $container_width && $image_height > $container_height) {
            $new_slide_width  = $image_width;
            $new_slide_height = $container_height / ($container_width / $image_width);
        }

        /**
         * Slideshow Width > Slide Width
         */
        if ($image_width > $container_width && $image_height == $container_height) {
            $new_slide_width  = $container_width;
            $new_slide_height = $container_height;
        }

        if ($image_width > $container_width && $image_height < $container_height) {
            $new_slide_height = $image_height;
            $new_slide_width  = $container_width / ($container_height / $image_height);
        }

        if ($image_width > $container_width && $image_height > $container_height) {
            $new_slide_width  = $container_width;
            $new_slide_height = $container_height;
        }

        return ['width' => floor($new_slide_width), 'height' => floor($new_slide_height)];
    }

    /**
     * Return the image URL, crop the image to the correct dimensions if required
     *
     * @return string resized image URL
     */
    public function get_image_url()
    {
        // Get the image file path
        if (!mb_strlen($this->path)) {
            return $this->url;
        }

        // if the file exists, just return it without going any further
        $dest_file_name = $this->get_destination_file_name([
                                                               'width'  => $this->container_width,
                                                               'height' => $this->container_height,
                                                           ]);

        if (file_exists($dest_file_name)) {
            return str_replace(basename($this->url), basename($dest_file_name), $this->url);
        }

        // file doesn't exist, detect required size
        $orig_size = $this->get_original_image_dimensions();

        // bail out if we can't find the image dimensions
        if (false === $orig_size) {
            return $this->url;
        }

        // required size
        $dest_size = $this->get_crop_dimensions($orig_size['width'], $orig_size['height']);

        // check if a resize is needed
        if ($orig_size['width'] == $dest_size['width'] && $orig_size['height'] == $dest_size['height']) {
            return $this->url;
        }

        $dest_file_name = $this->get_destination_file_name($dest_size);

        if (file_exists($dest_file_name)) {
            // good. no need for resize, just return the URL
            $dest_url = str_replace(basename($this->url), basename($dest_file_name), $this->url);
        } elseif ($this->use_image_editor) {
            // resize, assuming we're allowed to use the image editor
            $dest_url = $this->resize_image($orig_size, $dest_size, $dest_file_name);
        } else {
            // fall back to the full URL
            $dest_url = $this->url;
        }

        $dest_url = apply_filters('metaslider_resized_image_url', $dest_url, $this->url);

        return $dest_url;
    }

    /**
     * Get the image dimensions for the original image.
     *
     * Fall back to using the WP_Image_Editor if the size is not stored in metadata
     *
     * @return array
     */
    private function get_original_image_dimensions()
    {
        $size = [];

        // try and get the image size from metadata
        $meta = wp_get_attachment_metadata($this->id);

        if (isset($meta['width'], $meta['height'])) {
            return $meta;
        }

        if ($this->use_image_editor) {
            // get the size from the image itself
            $image = wp_get_image_editor($this->path);

            if (!is_wp_error($image)) {
                $size = $image->get_size();

                return $size;
            }
        }

        return false;
    }

    /**
     * Return the file name for the required image size
     *
     * @param  array $dest_size image dimensions (width/height) in pixels
     * @return string
     */
    private function get_destination_file_name($dest_size)
    {
        $info           = pathinfo($this->path);
        $dir            = $info['dirname'];
        $ext            = $info['extension'];
        $name           = wp_basename($this->path, ".$ext");
        $dest_file_name = "{$dir}/{$name}-{$dest_size['width']}x{$dest_size['height']}.{$ext}";

        return $dest_file_name;
    }

    /**
     * Use WP_Image_Editor to create a resized image and return the URL for that image
     *
     * @param  array $orig_size
     * @param  array $dest_size
     * @param        $dest_file_name
     * @return string
     */
    private function resize_image($orig_size, $dest_size, $dest_file_name)
    {
        // load image
        $image = wp_get_image_editor($this->path);

        // editor will return an error if the path is invalid
        if (is_wp_error($image)) {
            if (is_admin()) {
                echo '<div id="message" class="error">';
                echo '<p><strong>ERROR</strong> ' . $image->get_error_message() . " Check <a href='http://codex.wordpress.org/Changing_File_Permissions' target='_blank'>file permissions</a></p>";
                echo "<button class='toggle'>Show Details</button>";
                echo "<div class='message' style='display: none;'><br >Slide ID: {$this->id}<pre>";
                var_dump($image);
                echo '</pre></div>';
                echo '</div>';
            }

            return $this->url;
        }

        $dims = image_resize_dimensions($orig_size['width'], $orig_size['height'], $dest_size['width'], $dest_size['height'], true);

        if ($dims) {
            list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = $dims;
            $image->crop($src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h);
        }

        $saved = $image->save($dest_file_name);

        if (is_wp_error($saved)) {
            return $this->url;
        }

        // Record the new size so that the file is correctly removed when the media file is deleted.
        $backup_sizes = get_post_meta($this->id, '_wp_attachment_backup_sizes', true);

        if (!is_array($backup_sizes)) {
            $backup_sizes = [];
        }

        $backup_sizes["resized-{$dest_size['width']}x{$dest_size['height']}"] = $saved;
        update_post_meta($this->id, '_wp_attachment_backup_sizes', $backup_sizes);

        $url = str_replace(basename($this->url), basename($saved['path']), $this->url);

        return $url;
    }
}