Bildqualität basierend auf der Bildgröße

15

Ist es möglich, die Bildqualität basierend auf der Bildgröße einzustellen? Ich hätte gerne eine bessere Bildqualität für größere Bilder (80) - und eine schlechtere für kleine Thumbnails (30).

Ich hatte erwartet, dass ein Parameter dies add_sizesteuert - aber es gibt keinen.

Wenn es darauf ankommt: Ich benutze ImageMagick.

Nils Riedemann
quelle

Antworten:

15

Die einzige Zeit, bei der es auf die Qualität ankommt, ist, bevor das Bild gespeichert oder gestreamt wird (für den Editor). Beide haben dort den Filter "image_editor_save_pre" und übergeben ihm die Instanz des Bildeditors. Auf diese Weise können Sie das Bild nach Belieben ändern, einschließlich der Einstellung der Qualität.

So etwas sollte also einfach und problemlos funktionieren:

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
quelle
Der Grund, warum ich etwas so Gerades wie dieses (+1) nicht verwendet habe, ist, dass ich mich vage daran erinnere, dass beim Bearbeiten eines Bildes (Drehen, Beschneiden usw.) jede Aktion zweimal aufgerufen wurde, wodurch die Qualität zweimal verringert wurde. Trotzdem ist der WP_Image_EditorTeil "ist eine Instanz von " viel mehr eine Lösung als das, was ich geschrieben habe.
Kaiser
1
Die Qualität ist ein exakter Wert, kein Prozentsatz. Sie können es nach Belieben einstellen und zurücksetzen, bis es gespeichert wird. Wenn es hundertmal auf 10 gesetzt wird, wird es um 10 Uhr verlassen.
Otto
Ich nahm an, dass es dazwischen sparen würde. Danke für die Warnung.
Kaiser
Es scheint mir, dass image_editor_save_prenicht angerufen wird. Wenn ich versuche, etwas mit auszugeben error_log(was definitiv funktioniert), erhalte ich keine Ausgabe. : /
Nils Riedemann
1
Die Neuerstellung funktioniert möglicherweise auch, wenn das Bild erneut gespeichert wird. Es wird kein Code vorhandene Dateien auf dem System ändern, ohne dass Sie tatsächlich die Aktion zum erneuten Laden und Speichern dieser Dateien ausführen.
Otto
5

Vorherige Anmerkung: Die unten stehende Antwort ist noch nicht fertig und wurde noch nicht getestet, aber ich habe nicht mehr genug Zeit, also lasse ich dies hier als Entwurf. Was wahrscheinlich ein zweites Paar Augen braucht, ist die Qualitätsmethode und die Interpretation von version_compare().

Zuerst brauchen wir einen Einstiegspunkt. Nachdem ich den Make-Post noch einmal durchgelesen hatte, dachte ich, es wäre am besten, zu springen, bevor der Bildeditor das neu erstellte Bild speichert. Hier ist also ein Mikrocontroller, der während eines Rückrufs abfängt image_editor_save_preund eine Klasse lädt, die dann Ihre in einem Rückruf definierten Einstellungen durchläuft wpse_jpeg_quality. Es werden einfach verschiedene Komprimierungsverhältnisse für den jpeg_qualityFilter zurückgegeben, der im Bildeditor ausgeführt wird.

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

Der eigentliche Arbeiter ist die JPEGQualityWorkerKlasse. Es befindet sich im selben Verzeichnis wie die Haupt-Plugin-Datei und trägt den Namen worker.php(oder Sie ändern den Controller oben).

Es ruft das Bild und Ihre Einstellungen ab und fügt dem jpeg_qualityFilter Rückrufe hinzu . Was ist, ist

  • Abrufen Ihrer Bildreferenz (Breite oder Höhe)
  • Hinterfragen des Haltepunkts, der entscheidet, wo zwischen geringem und hohem Qualitäts- / Komprimierungsverhältnis umgeschaltet werden soll
  • Abrufen der ursprünglichen Bildgröße
  • Entscheiden, welche Qualität zurückgegeben werden soll

Der Haltepunkt und die Grenze entscheiden zwischen hoch und niedrig, und wie oben erwähnt, könnte dies etwas mehr Liebe erfordern.

<?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
quelle
Arbeiten Sie noch daran? Was mich betrifft, würde ich das gerne als Plugin sehen.
Nils Riedemann
Entschuldigung, aber nein, bin ich nicht. Ich würde das gerne auch als Plugin sehen, aber da ich es momentan nicht brauche und keine Zeit habe, wird es bisher nicht passieren. Vielleicht probieren Sie es aus, sehen Sie, wie weit Sie kommen, und reichen Sie eine Bearbeitung oder eine separate Antwort ein? :)
Kaiser
kaiser: Du hast es überkompliziert, denke ich. Das an image_editor_save_pre gesendete $ image ist eine Instanz der WP_Image_Editor-Klasse. Es hat Funktionen zum Abrufen der Größe und Einstellen der Qualität und alles andere, was bereits enthalten ist. Sie müssen sie nur noch anrufen.
Otto