Qualité d'image basée sur la taille de l'image

15

Est-il possible de définir la qualité d'image en fonction de la taille de l'image? J'aimerais avoir une meilleure qualité d'image pour les images plus grandes (80) - et pire pour les petites vignettes (30).

Je m'attendais à un paramètre à add_size pour contrôler cela - mais il n'y en a pas.

Si cela importe: j'utilise ImageMagick.

Nils Riedemann
la source

Réponses:

15

Le seul moment où la qualité est vraiment importante est juste avant que l'image ne soit enregistrée ou diffusée (pour l'éditeur). Les deux ont le filtre "image_editor_save_pre", en lui passant l'instance de l'éditeur d'image. Vous pouvez donc l'utiliser pour modifier l'image comme vous le souhaitez, y compris pour définir la qualité.

Donc, quelque chose comme ça devrait faire le travail simplement et facilement:

add_filter('image_editor_save_pre','example_adjust_quality');
function example_adjust_quality($image) {
    $size = $image->get_size();
    // Values are $size['width'] and $size['height']. Based on those, do what you like. Example:
    if ( $size['width'] <= 100 ) {
        $image->set_quality(30);
    }
    if ( $size['width'] > 100 && $size['width'] <= 300 ) {
        $image->set_quality(70);
    }
    if ( $size['width'] > 300 ) {
        $image->set_quality(80);
    }
    return $image;
}
Otto
la source
La raison pour laquelle je n'ai pas utilisé quelque chose d'aussi droit que celui-ci (+1), c'est que je me souviens vaguement que lors de l'édition d'une image (rotation, recadrage, etc.), chaque action a été appelée deux fois, réduisant la qualité deux fois. Pourtant, la partie "est une instance de WP_Image_Editor" est bien plus une solution que ce que j'ai écrit.
kaiser
1
La qualité est une valeur exacte, pas un pourcentage. Vous pouvez définir et réinitialiser tout ce que vous voulez, jusqu'à ce qu'il soit enregistré. Le régler à 10 cent fois le laisse à 10.
Otto
J'ai supposé que cela permettrait d'économiser entre les deux. Merci pour l'information.
kaiser
Il me semble que image_editor_save_precela ne se fait pas appeler. Lorsque j'essaie de produire des trucs en utilisant error_log(ce qui fonctionne vraiment), je n'obtiens aucune sortie. : /
Nils Riedemann
1
La régénération peut également fonctionner si elle réenregistre l'image. Aucun code ne modifiera les fichiers existants sur le système sans que vous ayez réellement pris les mesures nécessaires pour les recharger et les réenregistrer.
Otto
5

Remarque initiale: la réponse ci-dessous n'est pas terminée et n'est pas testée, mais je n'ai pas assez de temps, je vais donc laisser cela ici comme brouillon. Ce qui nécessite probablement une deuxième paire d'yeux, c'est la méthode de qualité et l'interprétation de version_compare().

Nous avons d'abord besoin d'un point d'entrée. Après avoir relu le post de création, j'ai pensé que le mieux serait de sauter avant que l'éditeur d'images enregistre l'image nouvellement créée. Voici donc un microcontrôleur qui intercepte lors d'un rappel accroché à image_editor_save_preet charge une classe qui parcourt ensuite vos paramètres définis dans un rappel vers wpse_jpeg_quality. Il renvoie simplement différents taux de compression pour le jpeg_qualityfiltre qui s'exécute dans l'éditeur d'image.

<?php

namespace WPSE;

/**
 * Plugin Name: (#138751) JPEG Quality Router
 * Author:      Franz Josef Kaiser
 * Author URI:  http://unserkaiser.com
 * License:     CC-BY-SA 2.5
 */

add_filter( 'image_editor_save_pre', 'WPSE\JPEGQualityController', 20, 2 );
/**
 * @param string $image
 * @param int $post_id
 * @return string
 */
function JPEGQualityController( $image, $post_id )
{
    $config = apply_filters( 'wpse_jpeg_quality', array(
        # Valid: <, lt, <=, le, >, gt, >=, ge, ==, =, eq
        'limit'      => 'gt',
        # Valid: h, w
        'reference'  => 'w',
        'breakpoint' => 50,

        'low'        => 80,
        'high'       => 100,
    ) );
    include_once plugin_dir_path( __FILE__ ).'worker.php';
    new \WPSE\JPEGQualityWorker( $image, $config );

    return $image;
}

Le travailleur réel est la JPEGQualityWorkerclasse. Il réside dans le même répertoire que le fichier de plugin principal ci-dessus et est nomméworker.php (ou vous changez le contrôleur ci-dessus).

Il récupère l'image et vos paramètres, puis ajoute des rappels au jpeg_qualityfiltre. Qu'est-ce que c'est

  • récupérer votre référence d'image (largeur ou hauteur)
  • interroger votre point d'arrêt qui décide où basculer entre un rapport qualité / compression faible et élevé
  • récupération de la taille d'image d'origine
  • décider quelle qualité retourner

Le point d'arrêt et la limite sont ce qui décide entre le haut et le bas et comme mentionné ci-dessus, cela pourrait nécessiter plus d'amour.

<?php

namespace WPSE;

/**
 * Class JPEGQualityWorker
 * @package WPSE
 */
class JPEGQualityWorker
{
    protected $config, $image;
    /**
     * @param string $image
     * @param array $config
     */
    public function __construct( Array $config, $image )
    {
        $this->config = $config;
        $this->image  = $image;

        add_filter( 'jpeg_quality', array( $this, 'setQuality' ), 20, 2 );
    }

    /**
     * Return the JPEG compression ratio.
     *
     * Avoids running in multiple context, as WP runs the function multiple
     * times per resize/upload/edit task, which leads to over compressed images.
     *
     * @param int $compression
     * @param string $context Context: edit_image/image_resize/wp_crop_image
     * @return int
     */
    public function setQuality( $compression, $context )
    {
        if ( in_array( $context, array(
            'edit_image',
            'wp_crop_image',
        ) ) )
            return 100;

        $c = $this->getCompression( $this->config, $this->image );

        return ! is_wp_error( $c )
            ? $c
            : 100;
    }

    /**
     * @param array $config
     * @param string $image
     * @return int|string|\WP_Error
     */
    public function getCompression( Array $config, $image )
    {
        $reference = $this->getReference( $config );
        if ( is_wp_error( $reference ) )
            return $reference;
        $size = $this->getOriginalSize( $image, $reference );
        if ( is_wp_error( $size ) )
            return $size;

        return $this->getQuality( $config, $size );
    }

    /**
     * Returns the quality set for the current image size.
     * If
     * @param array $config
     * @param int $size
     */
    protected function getQuality( Array $config, $size )
    {
        $result = version_compare( $config['breakpoint'], $size );
        return (
            0 === $result
            AND in_array( $config['limit'], array( '>', 'gt', '>=', 'ge', '==', '=', 'eq' ) )
            ||
            1 === $result
            AND in_array( $config['limit'], array( '<', 'lt', '<=', 'le', ) )
        )
            ? $config['high']
            : $config['low'];
    }

    /**
     * Returns the reference size (width or height).
     *
     * @param array $config
     * @return string|\WP_Error
     */
    protected function getReference( Array $config )
    {
        $r = $config['reference'];
        return ! in_array( $r, array( 'w', 'h', ) )
            ? new \WP_Error(
                'wrong-arg',
                sprintf( 'Wrong argument for "reference" in %s', __METHOD__ )
            )
            : $r;
    }

    /**
     * Returns the size of the original image (width or height)
     * depending on the reference.
     *
     * @param string $image
     * @param string $reference
     * @return int|\WP_Error
     */
    protected function getOriginalSize( $image, $reference )
    {
        $size = 'h' === $reference
            ? imagesy( $image )
            : imagesx( $image );

        # @TODO Maybe check is_resource() to see if we got an image
        # @TODO Maybe check get_resource_type() for a valid image
        # @link http://www.php.net/manual/en/resource.php

        return ! $size
            ? new \WP_Error(
                'image-failure',
                sprintf( 'Resource failed in %s', get_class( $this ) )
            )
            : $size;
    }
}
kaiser
la source
Travaille toujours dessus? En ce qui me concerne, j'aimerais voir cela comme un plugin.
Nils Riedemann
Désolé, mais non. J'aimerais voir cela comme un plugin aussi, mais comme je n'en ai pas besoin actuellement et que je n'ai pas le temps, cela n'arrivera pas jusqu'à présent. Peut-être lui donner un coup de feu, voir jusqu'où vous obtenez et déposer une modification ou une réponse distincte? :)
kaiser
kaiser: Vous l'avez trop compliqué, je pense. L'image $ envoyée à image_editor_save_pre est une instance de la classe WP_Image_Editor. Il a des fonctions pour obtenir la taille et définir la qualité et tout le reste déjà dedans. Il vous suffit de les appeler.
Otto