Jakość obrazu na podstawie rozmiaru obrazu

15

Czy można ustawić jakość obrazu na podstawie rozmiaru obrazu? Chciałbym mieć lepszą jakość obrazu dla większych obrazów (80) - a gorszą dla małych miniatur (30).

Spodziewałem się parametru, add_sizektóry to kontroluje - ale nie ma żadnego.

Jeśli to ważne: używam ImageMagick.

Nils Riedemann
źródło

Odpowiedzi:

15

Jedyne ustawienie czasu, które naprawdę ma znaczenie, to tuż przed zapisaniem lub przesłaniem obrazu (dla edytora). Oba mają tam filtr „image_editor_save_pre”, przekazując mu instancję edytora obrazów. Dzięki temu możesz modyfikować obraz w dowolny sposób, w tym ustawić jakość.

Coś takiego powinno więc wykonać zadanie w prosty i łatwy sposób:

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
źródło
Powodem, dla którego nie użyłem czegoś tak prostego jak ten (+1) jest to, że niejasno pamiętam, że podczas edycji jakiegoś obrazu (obracanie, przycinanie itp.) Każda akcja była wywoływana dwukrotnie, co dwukrotnie obniżało jakość. Mimo to część „jest przykładem WP_Image_Editor” jest rozwiązaniem o wiele bardziej niż to, co napisałem.
kaiser
1
Jakość to dokładna wartość, a nie procent. Możesz ustawić i zresetować wszystko, co chcesz, dopóki nie zostanie zapisane. Ustawienie go na 10 stokroć pozostawia ją na 10.
Otto
Zakładałem, że zaoszczędzę pomiędzy. Dzięki za heads-upy.
kaiser
Wydaje mi się, że image_editor_save_prenie można się nazywać. Kiedy próbuję wyprowadzać dane za pomocą error_log(co zdecydowanie działa), nie otrzymuję żadnych danych wyjściowych. : /
Nils Riedemann
1
Regeneracja może również działać, jeśli ponownie zapisuje obraz. Żaden kod nie zmieni istniejących plików w systemie bez podjęcia działań w celu ich ponownego załadowania i ponownego zapisania.
Otto
5

Uwaga z góry: Poniższa odpowiedź nie jest ukończona i nie została przetestowana, ale nie mam wystarczająco dużo czasu, więc zostawię ją tutaj jako wersję roboczą. Druga para oczu prawdopodobnie potrzebuje metody jakości i interpretacji version_compare().

Najpierw potrzebujemy punktu wejścia. Po ponownym przeczytaniu „ make post” pomyślałem, że najlepiej będzie wskoczyć, zanim Edytor obrazów zapisze nowo utworzony obraz. Oto mikrokontroler, który przechwytuje przechwycone połączenie zwrotne image_editor_save_prei ładuje klasę, która następnie przechodzi przez ustawienia zdefiniowane w wywołaniu zwrotnym wpse_jpeg_quality. Zwraca po prostu różne współczynniki kompresji dla jpeg_qualityfiltra działającego w edytorze obrazów.

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

Rzeczywistym pracownikiem jest JPEGQualityWorkerklasa. Znajduje się w tym samym katalogu, co powyższy główny plik wtyczki i ma nazwę worker.php(lub zmienisz kontroler powyżej).

Pobiera obraz i twoje ustawienia, a następnie dodaje wywołania zwrotne do jpeg_qualityfiltra. To, co robi, jest

  • pobieranie odniesienia do obrazu (szerokość lub wysokość)
  • kwestionowanie punktu przerwania, który decyduje, gdzie przełączyć między niskim i wysokim współczynnikiem jakości / kompresji
  • pobieranie oryginalnego rozmiaru obrazu
  • decydowanie, jaką jakość zwrócić

Punktem granicznym i limitem jest to, co decyduje między wysokim a niskim, i jak wspomniano powyżej, może to wymagać trochę więcej miłości.

<?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;
    }
}
kajzer
źródło
Nadal nad tym pracuję? Jeśli o mnie chodzi, chciałbym zobaczyć to jako wtyczkę.
Nils Riedemann
Przepraszam, ale nie, nie jestem. Chciałbym również zobaczyć to jako wtyczkę, ale ponieważ obecnie nie potrzebuję jej i nie mam czasu, do tej pory tak się nie stało. Może spróbujesz, zobaczysz, jak daleko się posuniesz i prześlesz edycję lub osobną odpowiedź? :)
kaiser
kaiser: Myślę, że nadmiernie to skomplikowałeś. Obraz $ wysłany do image_editor_save_pre jest instancją klasy WP_Image_Editor. Ma funkcje pozwalające uzyskać rozmiar i ustawić jakość oraz wszystko, co już w nim jest. Wszystko, co musisz zrobić, to zadzwonić do nich.
Otto