web-dev-qa-db-fra.com

Créez des formats d'image avec différentes qualités lors du téléchargement

J'essaie de trouver une solution dans laquelle les formats d'image générés couvrent à la fois les aspects réactif et haute résolution lors du téléchargement d'un nouvel élément dans WP admin. J'ai mis en place un ensemble de formats qui devraient répondre à ces exigences,

Bureau Retina 2560 x 1600 ('largex2', personnalisé)
Bureau 1280 x 800 (grand)
Tablette rétine 1920 x 1200 ('mediumx2', personnalisé)
960 x 600 comprimés + rétine mobile (moyenne)
Téléphone mobile 480 x 300 (miniature)

Mon problème réside dans la qualité de l'image pour les grandes tailles. L'exportation des images à partir de Photoshop avec un réglage de qualité élevé ou très élevé produira des résultats corrects pour les tailles par défaut, mais qu'en est-il des personnalisées? Ceux que je préférerais exporter à un réglage moyen ou faible afin de conserver une taille de fichier raisonnable.

Ma pensée est la suivante: serait-il possible de prendre une très grande image avec une qualité élevée, de la télécharger, puis de la définir de manière à ce que les plus grandes tailles soient générées avec une qualité bien inférieure?

Toute aide est appréciée! S'il vous plaît, ne me dirigez pas vers des plugins, je veux construire ma propre solution pour cela.

5
Staffan Estberg

1) Une solution de contournement en étendant la classe WP_Image_Editor_Gd

Le problème est de savoir comment accéder aux tailles d’image avant de changer la qualité des images intermédiaires jpeg.

Notez que la fonction image_resize() est obsolète .

Nous pouvons utiliser le filtre jpeg_quality de la méthode publique get_quality de la classe abstraite WP_Image_Editor:

$quality = apply_filters( 'jpeg_quality', $quality, 'image_resize' );

ou le filtre wp_editor_set_quality.

Voici une idée pour définir la qualité de l'image en fonction de la taille de l'image (largeur/hauteur):

/**
 * Set image (jpeg) quality based on the image size (width/height)
 * @see http://wordpress.stackexchange.com/a/165241/26350
 */
add_filter( 'wpse_make_image_arguments', function( $arguments, $filename, $size, $function ) 
{   
    // Only target jpeg cases, i.e. with the quality set in $arguments[2]       
    if( ! isset( $size['height'] ) || ! isset( $size['width'] ) || ! isset( $arguments[2] ) )
        return $arguments;

    // Modify this part to your needs:
    if( $size['height'] <= 150  && $size['width'] <= 150 )
        $arguments[2] = 2; // very low quality for easy testing

    return $arguments;
}, 10, 4 );

où nous avons étendu la classe WP_Image_Editor_Gd:

/**
 * Extend the WP_Image_Editor_Gd to add the custom wpse_make_image_arguments filter.
 * @see http://wordpress.stackexchange.com/a/165241/26350
 */
add_filter( 'wp_image_editors', function( $editors ) 
{
    // Note that the WP_Image_Editor_Gd and WP_Image_Editor_Imagick classes
    // are included within this filter. So let's do the same for our extended class.

    // Our extended class that overrides the WP_Image_Editor_Gd::make_image() method

    if( ! class_exists( 'WPSE_Image_Editor_Gd' ) )
    {   
        class WPSE_Image_Editor_Gd extends WP_Image_Editor_Gd
        {
            protected function make_image( $filename, $function, $arguments ) 
            {
                // Add a custom filter      
                $arguments = apply_filters( 'wpse_make_image_arguments', $arguments, $filename, $this->size, $function );

                // Parent method
                return parent::make_image( $filename, $function, $arguments );
            }
        }
    }

    // Prepend the extended class to the array of image editors:    
    array_unshift( $editors, 'WPSE_Image_Editor_Gd' );

    return $editors;
} );

où nous avons introduit le filtre personnalisé wpse_make_image_arguments.

De cette façon, nous pouvons modifier les paramètres de qualité, avant les fichiers intermédiaires sont sauvegardés.

Voici un exemple:

Example

PS:Je n'ai pas vérifié le cas où la bibliothèque Imagickest utilisée à la place, mais je suppose que nous pourrions faire quelque chose de similaire en étendant la classe WP_Image_Editor_Imagick.

2) Mise à jour - Définir la qualité jpeg par nom de taille d'image

Voici une autre version où nous définissons la qualité jpeg par nom de taille d'image:

/**
 * Extend the WP_Image_Editor_Gd to set quality per image size name.
 * 
 * @see http://wordpress.stackexchange.com/a/165241/26350
 */
add_filter( 'wp_image_editors', function( $editors ) 
{
    // Note that the WP_Image_Editor_Gd and WP_Image_Editor_Imagick classes
    // are included within this filter. So let's do the same for our extended class.

    // Our extended class that overrides the WP_Image_Editor_Gd::_resize() method
    if( ! class_exists( 'WPSE2_Image_Editor_Gd' ) )
    {   
        class WPSE2_Image_Editor_Gd extends WP_Image_Editor_Gd
        {
            protected function _resize( $max_w, $max_h, $crop = false )
            {
                $qualities = apply_filters( 'wpse_jpeg_qualities', [] );
                $default_quality = (int) apply_filters( 'wpse_default_jpeg_quality', 82 );                              
                $sizes = wp_get_additional_image_sizes();
                $this->set_quality( $default_quality );         
                foreach( (array) $qualities as $name => $quality )
                {
                    if( 
                        isset( $sizes[$name] ) 
                        && (int)  $sizes[$name]['width']  === (int)  $max_w
                        && (int)  $sizes[$name]['height'] === (int)  $max_h
                        && (bool) $sizes[$name]['crop']   === (bool) $crop  
                    )   
                        $this->set_quality( $quality );                 
                }

                // Parent method
                return parent::_resize( $max_w, $max_h, $crop );
            }
        }
    }

    // Prepend the extended class to the array of image editors:    
    array_unshift( $editors, 'WPSE2_Image_Editor_Gd' );

    return $editors;
} );

J'ai remarqué que les arguments de recadrage peuvent être 0, faux ou vides, nous faisons donc une conversion de typage pour en être sûr.

Ici, nous avons introduit les nouveaux filtres suivants:

add_filter( 'wpse_jpeg_qualities', function( $qualities )
{ 
    return [ 'hello-image' => 2, 'medium' => 2, 'large' => 2 ];
} );

et

add_filter( 'wpse_default_jpeg_quality', function( $quality )
{ 
    return 82;
} );

j'espère que cela pourra être adapté à vos besoins!

6
birgire

Je peux commenter, je dois poster avec une autre version.

Les problèmes):

Je ne suis pas sûr si la Mise à jour 2) Définir la qualité jpeg par nom de taille d'image dans la réponse acceptée est terminée. wp_get_additional_image_sizes() renvoie le global $_wp_additional_image_sizes et ne contient aucune information sur les tailles par défaut (moyenne, grande ou miniature).

Cela pourrait ne pas fonctionner dans le filtre: 'large' => 2

À partir de https://codex.wordpress.org/Function_Reference/get_intermediate_image_sizes explique avec un code personnalisé la récupération de TOUTES les tailles avec une fonction personnalisée.

Ai-je raison?

Deuxièmement, l’idée de filtrer différentes "tailles" par nom est délicate. _resize( $max_w, $max_h, $crop = false ) comprend et analyse uniquement la largeur, la hauteur et la valeur de rognage correspondantes, et chaque correspondance suppose de correspondre à un nom. Mais dans de nombreux cas, le nom sera "un autre" nom.

Un paramètre d'image "moyen" ayant le même paramètre "shop_product" ne fera que "visiter" cette fonction. Ensuite, nous ne saurons pas s'il s'agit d'une taille "moyenne" ou d'une taille "shop_product" filtrée. Parce que les objectifs ici ne sont qu’un recadrage technique d’une image.

L'idée avec Update 2) est une manipulation plus logique, mais je crains que l'architecture technique ne soit pas là. Pour analyser toutes les tailles d’image enregistrées avant de construire le filtre, il faut plus de développement pour vérifier que l’intention renvoie le programme d’image de qualité correcte sur le thème actuel.

Tous les noms de taille avec des paramètres identiques partagent la même nouvelle qualité car ils partagent la même image sur le serveur.

Donc, si vous vous en tenez toujours à la mise à jour 2) , vous devez appeler une autre fonction pour renseigner la variable $sizes et analyser par var_dump () le $_wp_additional_image_sizes à égalité.

L'approche de 1) Une solution de contournement de ... est plus logique/sémantique. Nous avons résolu ce problème en utilisant la même méthode d'extension, mais en utilisant plutôt un filtre dynamique:

add_filter('wp_image_editors', function($editors){

    if(!class_exists('ENTEX_Image_Editor_Gd')){   
        class ENTEX_Image_Editor_Gd extends WP_Image_Editor_Gd {
            private $wp_quality = null;
            protected function _resize($max_w, $max_h, $crop = false){
                $condition = ($crop ? 'true' : 'false');
                if($this->wp_quality === null) $this->wp_quality = $this->get_quality();
                $quality = apply_filters('wp_editor_set_quality_'. $max_w .'x'. $max_h .'_'. $condition, $this->wp_quality);                              
                $this->set_quality((int) $quality);
                return parent::_resize( $max_w, $max_h, $crop );
            }
        }
    }    
    array_unshift($editors, 'ENTEX_Image_Editor_Gd');
    return $editors;
});

Pour filtrer chaque taille d'image individuelle, nous utilisons ensuite:

add_filter('wp_editor_set_quality_160x160_true', function($quality){
    return 96;
});

Ce qui diffère également de cette version étendue est que nous utilisons/remplit la version add_filter('jpeg_quality' ... comme valeur par défaut.

Voici d'autres exemples de filtres personnalisés:

function high_quality_on_medium_images(){
    $in = 'medium';
    $max_w = get_option($in.'_size_w');
    $max_h = get_option($in.'_size_h');
    $crop = get_option($in.'_crop');
    $condition = ($crop ? 'true' : 'false');
    add_filter('wp_editor_set_quality_'. $max_w .'x'. $max_h .'_'. $condition, 'my_theme_high_quality_images', 10, 1);
}
add_action('after_setup_theme', 'high_quality_on_medium_images', 99);

function my_theme_high_quality_images($quality){
    return (int) 82;
}

attention des développeurs

  • Assurez-vous que des filtres sont appliqués après la configuration des images de thème.
  • Ne pas envelopper dans is_admin() puis appel ajax, frontal, distant
    Les images postées ne mordront pas.

Comme mentionné, la valeur de recadrage peut être 0 ou faux, vous devez convertir (int) ou (bool) en chaîne avec $condition = ($crop ? 'true' : 'false');

Attention aux développeurs de thèmes

La compression par défaut WP est assez progressive. Les valeurs comprises entre 80 et 99 pourraient renvoyer une énorme différence ou aucun résultat visible. Une valeur de compression nulle en tant que 100, renvoie probablement une taille de fichier plus grande sur une "taille plus petite" 800 images , puis la version originale de grande taille 3000 px .

Après de nombreuses années, nous avons trouvé un nombre magique de 96. La taille du fichier diminue, mais vous ne pouvez pas voir la différence entre une compression de valeur 100.

Des images de magasin préparées avec Photoshop de haute qualité, supérieures à 800 pixels, conviennent parfaitement avec Wordpress par défaut 82. Mais les images "grand" envoyées par courrier électronique sur un iPhone nécessitent vraiment une valeur de 96 sur les tailles TOUTES comme les vignettes. Elles deviennent "adoucies" avec les compressions Wordpres.

Vous allez trop faire avec les solutions de cette rubrique si vous ne planifiez pas les scénarios pour votre projet, vos utilisateurs ou votre thème.

Une dernière réflexion

Je suis vraiment déçu par Wordpress que cette question importante soit négligée dans la priorité du développement, car les images sont plus que jamais importantes pour être uniques et efficaces en charge.

Pourquoi ne pas simplement placer un filtre au bon endroit pouvant être utilisé pour une compression individuelle? Ils se donnent la peine de "changer le nom" en wp_editor_set_quality, et add_filter('jpeg_quality' ... est maintenant obsolète. Pourquoi ne pas penser cela complètement et supprimer simplement la méthode if ( ! $this->quality ) seulement cocher une fois comme mentionné par @birgire.

0
Jonas Lundman