Modification de la compression JPEG en fonction de la taille de l'image

8

Court. Je veux que les images «grandes» soient compressées à 90% et «moyennes» à 60%. Comme vous le savez, de grandes images souffrent parfois d'une compression élevée, mais pas d'autres petites images.

Cette fonction permet de rééchantillonner toutes les images jpg

function custom_jpg_compression($args) {
    return 90;
}
add_filter('jpeg_quality', 'custom_jpg_compression');

Comment filtrer par taille d'image?

DarkGhostHunter
la source

Réponses:

11

Un filtre très spécial

Le jpeg_qualityfiltre est vraiment spécial: il est utilisé dans trois cas différents et vous devez utiliser le deuxième argument pour déterminer si vous souhaitez utiliser le filtre ou non.

Ne le laisse pas tout faire

Le principal problème d'un tel filtre spécial est qu'il peut se déclencher pour des actions ultérieures, si vous ne le supprimez pas - laissez-le s'exécuter après la première vérification. Nous devons donc obtenir un autre filtre à l'intérieur wp_save_image_file()pour vérifier si nous voulons modifier la compression ou non. Pour le désactiver pour un autre processus de sauvegarde, nous le supprimons juste avant de modifier la compression.

L'enfant kool

La chose vraiment étrange est que WP utilise une compression par défaut de 90% (ce qui représente une qualité réduite de 10%) pour chaque processus de sauvegarde. Cela signifie que chaque fois que vous téléchargez / recadrez / éditez une image, vous réduisez sa qualité ... ce qui est pénible pour les images qui ne sont pas les meilleures, lorsque vous les téléchargez (testez-la avec une image contenant beaucoup de rouge) avec un fond à contraste élevé). Mais ... La chose vraiment intéressante est que vous pouvez changer ce comportement. Vous voulez donc changer la compression, mais obtenir en même temps une qualité accrue - bien meilleure que le noyau le permet.

/**
 * Alter the image compression, depending on case
 * 
 * @param  int $compression
 * @param  string $case
 * @return int $compression
 */
function wpse58600_custom_jpg_compression_cb( $compression, $case )
{
    global $size_switch;

    // Should only fire once - don't leave it in for later cases
    remove_filter( current_filter(), __FUNCTION__ );

    // Alter the compression, depending on the case
    switch ( $case )
    {
        case( 'edit_image' ) :
            // We only add the compression, if the switch triggered,
            // which means, that the size is smaller, than set in the main function.
            // 60 is the percentage value, that gets added as compression to the smaller images.
            $compression = $size_switch ? 60 : 100;
            break;

        case( 'image_resize' ) :
            // Better leave it on 100% for resize
            $compression = 100;
            break;

        case( 'wp_crop_image' ) :
            // Better leave it on 100% for crop
            // We already compressed it on the camera, the desktop/handheld device 
            // and the server previously. That's enough so far.
            $compression = 100;
            break;
    }

    return $compression;
}

/**
 * Alter the compression for JPEG mime type images
 * Checks for a specific min size of the image, before altering it
 * 
 * @param  string $image
 * @param  int $post_id 
 * @return string $image
 */
function wpse58600_custom_jpg_compression( $image, $post_id )
{
    global $size_switch;
    $size_switch = false;

    // Define the size, that stops adding a compression
    $trigger_size = 641;

    // Get the sizes
    $size_x = imagesx( $image );
    $size_y = imagesy( $image );

    // Add the filter only in case
    if ( $trigger_size < $size_x )
    {
        $size_switch = true;
    }
    add_filter( 'jpeg_quality', 'wpse58600_custom_jpg_compression_cb', 20, 2 );

    return $image;
}
add_filter( 'image_save_pre', 'wpse58600_custom_jpg_compression', 20, 2 );

EDIT: Après une brève discussion avec @toscho, il a souligné que l'ensemble du rappel pourrait être réduit comme suit:

function wpse58600_custom_jpg_compression_cb( $compression, $case )
{
    // Should only fire once - don't leave it in for later cases
    remove_filter( current_filter(), __FUNCTION__ );

    return ( $GLOBALS['size_switch'] && 'edit_image' === $case ) ? 60 : 100;
}

Comme j'ai extrait le code d'un plugin sur switchlequel je travaille actuellement, j'avais besoin d'ajouter des paramètres. Je dois également noter que je n'utilise pas le globaldans mon plugin, car c'est une approche OOP. Le code que vous pouvez lire ↑ ci-dessus, est principalement du code réduit et modifié du plugin, qui a quelques restes mineurs et est destiné à être explicatif pour les lecteurs ultérieurs et fonctionne toujours. Si vous souhaitez l'utiliser comme plugin, vous pouvez faire une optimisation en fonction de votre cas d'utilisation personnel.


Remarques:

À partir d'une enquête sur les différentes tâches, il y a, j'ai remarqué, que plusieurs $cases sont déclenchés aux étapes suivantes:

  • Rotation: edit-image» image-resize(le dernier 1 × pour n'importe quelle taille que vous choisissez - Vignette, etc.)
  • Miroir: edit-image» image-resize(-" -)

Cela signifie que le rappel du filtre jpeq_qualitydéclenchera 2 × pour la rotation / la mise en miroir d'une image et + 1 × pour toute taille supplémentaire que vous ajoutez. Donc, si vous avez moins de 100%, cela réduira la qualité deux fois. J'ai fait beaucoup de recherches sur ce sujet, mais je ne sais toujours pas exactement quelles fonctions exactes provoquent ce comportement.

kaiser
la source
Ups tu m'as eu, print_r / var_dump ne fonctionne pas. Comment puis-je produire cela?
DarkGhostHunter
Utilisez echo '<pre>'.var_export( $image, true ).'</pre>';. Mettez un exit;après, pour qu'il ne soit pas ignoré lors du rechargement de la page, etc.
kaiser
putain, perdu dans les bois - je ne vois pas où il imprime. J'ai ce code avant le retour de l'image $;
DarkGhostHunter
Ajoutez-le juste au début de la wpse58600_custom_jpg_compression()fonction.
kaiser