wake-up-neo.com

Ändern der JPEG-Komprimierung abhängig von der Bildgröße

Kurz. Ich möchte, dass "große" Bilder um 90% und "mittlere" um 60% komprimiert werden. Wie Sie wissen, leiden viele größere Bilder unter einer hohen Komprimierung, andere kleine Bilder dagegen nicht.

Mit dieser Funktion können alle JPG-Bilder neu abgetastet werden

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

Wie filtere ich nach Bildgröße?

8
DarkGhostHunter

Ein sehr spezieller Filter

Der jpeg_quality-Filter ist ein wirklich spezieller: Er wird in drei verschiedenen Fällen verwendet und Sie müssen das zweite Argument verwenden, um zu bestimmen, ob Sie den Filter verwenden möchten oder nicht.

Lass es nicht alles machen

Das Hauptproblem eines solchen special -Filters besteht darin, dass es möglicherweise für spätere Aktionen ausgelöst wird, wenn Sie es nicht entfernen - lassen Sie es nach der ersten Überprüfung ausführen. Wir müssen also einen weiteren Filter in wp_save_image_file() einbauen, um zu prüfen, ob wir die Komprimierung ändern wollen oder nicht. Um es für einen anderen Speichervorgang zu deaktivieren, entfernen wir es direkt vor dem Ändern der Komprimierung.

Das coole Kind

Das wirklich Seltsame ist, dass WP eine Standardkomprimierung von 90% (was 10% reduzierter Qualität entspricht) für jeden Speichervorgang verwendet. Dies bedeutet, dass jedes Mal, wenn Sie ein Bild hochladen, zuschneiden oder bearbeiten, die Qualität reduziert wird. Dies ist ein Schmerz für Bilder, die beim Hochladen nicht die besten sind (testen Sie es mit einem Bild, das viel Rot enthält mit kontrastreichem Hintergrund). Aber ... Das wirklich nette ist, dass Sie dieses Verhalten ändern können. Sie möchten also die Komprimierung ändern, aber gleichzeitig eine höhere Qualität erzielen - viel besser als der Kern zulässt.

/**
 * 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: Nach einer kurzen Diskussion mit @toscho wies er darauf hin, dass der gesamte Rückruf auf das Folgende reduziert werden könnte:

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;
}

Da ich den Code aus einem Plugin gezogen habe, an dem ich gerade arbeite, brauchte ich die switch, um Einstellungen hinzuzufügen. Außerdem muss ich beachten, dass ich die global nicht in meinem Plugin verwende, da es ein OOP Ansatz. Der Code, den Sie oben lesen können ↑, ist hauptsächlich reduzierter und geänderter Code aus dem Plugin, der einige kleinere Reste hat und für spätere Leser erklärend sein soll und immer noch funktioniert. Wenn Sie es als Plugin verwenden möchten, können Sie je nach Ihrem persönlichen Anwendungsfall einige Optimierungen vornehmen.


Anmerkungen:

Bei einigen Untersuchungen zu den verschiedenen Aufgaben ist mir aufgefallen, dass bei den folgenden Schritten mehrere $cases ausgelöst werden:

  • Drehen: edit-image "image-resize (das spätere 1 × für jede beliebige Größe, die Sie auswählen - Miniaturansicht usw.)
  • Spiegeln: edit-image "image-resize (-" -)

Dies bedeutet, dass der Filter-Rückruf für jpeq_quality 2 × zum Drehen/Spiegeln eines Bildes und + 1 × für jede weitere hinzugefügte Größe auslöst. Wenn Sie also weniger als 100% erhalten, wird die Qualität zweimal reduziert. Ich habe viel zu diesem Thema recherchiert, bin mir aber immer noch nicht sicher, welche genauen Funktionen dieses Verhalten verursachen.

11
kaiser