web-dev-qa-db-fra.com

La définition de la compression JPEG pour les tailles d'image personnalisées ne fonctionne pas dans les cas spécifiques.

J'ai une taille d'image personnaliséehello-image:

add_image_size( 'hello-image', 700, 300, true );

Chaque fois qu'une image est téléchargée, je compresse l'image recadrée de taille hello-image en 40% compression JPEG. Cela fonctionne très bien dans tous les cas sauf ...

Le problème

Si le width de l'image d'origine est plus grand que 700px, cela fonctionne très bien. Mais si sa largeur est moins que 700px, la compression passe à environ 0%.

Comment le tester

Téléchargez les deux images suivantes:

BIG: 784px × 441px

PETIT: 670px × 377px

Ensuite, j'ai créé un plugin qui a tout le code approprié:

<?php
/*
Plugin Name: WPSE: custom image size and JPEG compression
Description: custom image size and JPEG compression
Author: WPSE
Version: 1.0
*/

// Set JPEG compression quality
add_filter('jpeg_quality', create_function('$quality', 'return 100;'));

add_action('added_post_meta', 'ad_update_jpeg_quality', 10, 4);

function ad_update_jpeg_quality($meta_id, $attach_id, $meta_key, $attach_meta) {

    if ($meta_key == '_wp_attachment_metadata') {

        $post = get_post($attach_id);

        if ($post->post_mime_type == 'image/jpeg' && is_array($attach_meta['sizes'])) {

            $pathinfo = pathinfo($attach_meta['file']);
            $uploads = wp_upload_dir();
            $dir = $uploads['basedir'] . '/' . $pathinfo['dirname'];

            foreach ($attach_meta['sizes'] as $size => $value) {

                $image = $dir . '/' . $value['file'];
                $resource = imagecreatefromjpeg($image);

                if ($size == 'large') {

                    // set the jpeg quality for 'large' size
                    imagejpeg($resource, $image, 35);

                } elseif ($size == 'medium') {

                    // set the jpeg quality for the 'medium' size
                    imagejpeg($resource, $image, 35);

                } elseif ($size == 'hello-image') {

                    // set the jpeg quality for the 'hello-image' size
                    imagejpeg($resource, $image, 40);

                } else {

                    // set the jpeg quality for the rest of sizes
                    imagejpeg($resource, $image, 35); // 38
                }

                imagedestroy($resource);
            }
        }
    }
}


// add custom image sizes to media uploader
function my_insert_custom_image_sizes( $sizes ) {
    // get the custom image sizes
    global $_wp_additional_image_sizes;
    // if there are none, just return the built-in sizes
    if ( empty( $_wp_additional_image_sizes ) )
        return $sizes;

    // add all the custom sizes to the built-in sizes
    foreach ( $_wp_additional_image_sizes as $id => $data ) {
        // take the size ID (e.g., 'my-name'), replace hyphens with spaces,
        // and capitalise the first letter of each Word
        if ( !isset($sizes[$id]) )
            $sizes[$id] = ucfirst( str_replace( '-', ' ', $id ) );
    }

    return $sizes;
}

// Which custom image size selected by default
function my_set_default_image_size () {
    return 'hello-image';
}

function custom_image_setup () {
    // custom image sizes
    add_image_size( 'medium', 300, 9999 ); //  medium
    add_image_size( 'hello-image', 700, 300, true ); // custom
    add_image_size( 'large', 700, 3000 ); //  large

    add_filter( 'image_size_names_choose', 'my_insert_custom_image_sizes' );
    add_filter( 'pre_option_image_default_size', 'my_set_default_image_size' );
}

add_action( 'after_setup_theme', 'custom_image_setup' );

Maintenant, téléchargez l’image grande _ et voyez comment l’image hello-image est correctement compressée. Ensuite, chargez l'image petite et voyez comment la même taille d'image est compressée terriblement. Donc, pour clarifier, voici les résultats:

700x300 = 40% compression
670x300 = 0% compression

Les deux sont générés via la même taille d'image personnalisée. Quelle est la cause de ceci et comment peut-on le réparer?

Je tiens à souligner que mon collègue a posté une question ici demandant comment éviter de créer cette taille d'image si la largeur est inférieure à 700px... mais je suis un connaisseur de WordPress qui préférerait résoudre la cause du problème que d'ajouter un correctif hacky à cela.

Enfin, j'ai commencé à voir ce problème dans une récente mise à jour de WordPress. Il peut donc s'agir d'un bogue dans le noyau, par opposition à un problème dans mon code.

Edit : Lire le update .

6
Christine Cooper

Quelques suggestions:

Si vous voulez essayer le API de l'éditeur d'image, vous pouvez essayer de le remplacer.

imagejpeg( $resource, $image, 35 );

avec:

$editor = wp_get_image_editor( $image );  
if ( ! is_wp_error( $editor ) )
{
    $editor->set_quality( 35 );
    $editor->save( $image  );
}
unset( $editor );

Essayez également de tester par exemple ces parties:

$resource = imagecreatefromjpeg( $image );
if( false !== $resource )
{
    imagejpeg( $resource, $image, 35 );
    imagedestroy( $resource );
}

dans un script autonome PHP, pour vous assurer qu'il ne s'agit pas d'un problème lié à PHP ou à Gd.

PS: Voici une approche différente où nous essayons de modifier la qualité de l’image avant la taille de l’image est générée.

Test du plugin

Vérifions le plugin de la question principale.

Test d'installation

  • WordPress version 4.9-alpha-40917
  • PHP 7.0.19

 Gd  imagick 

Voici la taille générée hello-image (670x300), de l'image SMALL (670 × 377), à partir de la question, où nous avons défini la qualité sur 40:

imagejpeg( $resource, $image, 40 );

 q=40 

Voici la même chose mais avec la qualité définie sur 0:

imagejpeg( $resource, $image, 0 );

 q=0 

Il semble donc que nous ne obtenons pas le même comportement que celui décrit dans la question: lorsque la qualité est définie sur 40, elle devient 0 pour la taille hello-image de l'image d'origine 670x377.

6
birgire

Intéressant, je l'ai essayé et la petite image s'affiche en 670x300 et la grande image 700x300. Il me semble que son logiciel fait exactement ce qu'il doit faire. Il recadre l'image si la hauteur ou la largeur sont au-dessus du type d'image (ou les deux).

Je comprends que vous souhaitiez recadrer l’image uniquement si la hauteur est plus élevée? Ensuite, utiliser ceci fonctionnerait:

  add_image_size( 'hello-world', 700, 0, true );

Je ré-télécharge les images après cela et les petites images sont affichées 670 sur 377 et la grande image 700 sur 394. J'ai téléchargé une autre version plus petite (516x290) et elle n'est pas recadrée.

Bien que, lorsque vous téléchargez une image telle que 690x4000, elle n’obtient pas non plus de recadrage.

0
berend