Qualità dell'immagine basata sulla dimensione dell'immagine


15

È possibile impostare la qualità dell'immagine in base alla dimensione dell'immagine? Mi piacerebbe avere una migliore qualità dell'immagine per immagini più grandi (80) - e peggio per le miniature piccole (30).

Mi aspettavo un parametro add_sizeper controllarlo, ma non ce n'è.

Se è importante: sto usando ImageMagick.

Risposte:


15

L'unica volta che l'impostazione della qualità conta davvero è prima che l'immagine venga salvata o trasmessa in streaming (per l'editor). Entrambi hanno il filtro "image_editor_save_pre" lì, passandogli l'istanza dell'editor di immagini. Quindi puoi usarlo per modificare l'immagine nel modo che preferisci, inclusa l'impostazione della qualità.

Quindi, qualcosa del genere dovrebbe fare il lavoro in modo semplice e facile:

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

Motivo per cui non ho usato qualcosa di dritto come questo (+1), che ricordo vagamente che durante la modifica di un'immagine (rotazione, ritaglio, ecc.), Ogni azione veniva chiamata due volte, riducendo la qualità due volte. Tuttavia la parte "è un'istanza di WP_Image_Editor" è una soluzione molto più di quella che ho scritto.
Kaiser

1
La qualità è un valore esatto, non una percentuale. È possibile impostare e ripristinare tutto ciò che vuoi, fino a quando non salva. Impostandolo su 10 cento volte lo lascia a 10.
Otto

Ho pensato che avrebbe risparmiato nel mezzo. Grazie per il testa a testa.
Kaiser

Mi sembra che image_editor_save_prenon venga chiamato. Quando provo a produrre roba usando error_log(che sicuramente funziona) non ottengo alcun output. : /
Nils Riedemann il

1
Anche la rigenerazione potrebbe funzionare se ripristina l'immagine. Nessun codice cambierà i file esistenti sul sistema senza che tu effettivamente esegua l'azione per ricaricarli e salvarli di nuovo.
Otto

5

Nota in anticipo: la risposta di seguito non è terminata e non è stata testata, ma non mi rimane abbastanza tempo, quindi lascerò questo qui come bozza. Ciò che probabilmente ha bisogno di un secondo paio di occhi è il metodo di qualità e l'interpretazione di version_compare().

Per prima cosa abbiamo bisogno di un punto di accesso. Dopo aver letto di nuovo il post di make , ho pensato che sarebbe stato meglio saltare prima che Image Editor salvasse l'immagine appena creata. Quindi ecco un microcontrollore che intercetta durante un callback collegato image_editor_save_pree carica una classe che quindi passa attraverso le impostazioni definite all'interno di un callback a wpse_jpeg_quality. Restituisce semplicemente diversi rapporti di compressione per il jpeg_qualityfiltro che viene eseguito all'interno dell'editor di immagini.

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

Il vero lavoratore è la JPEGQualityWorkerclasse. Risiede nella stessa directory del file del plug-in principale sopra ed è chiamato worker.php(o si cambia il controller sopra).

Recupera l'immagine e le impostazioni e quindi aggiunge le richiamate al jpeg_qualityfiltro. Quello che fa è

  • recupero del riferimento dell'immagine (larghezza o altezza)
  • mettere in discussione il tuo punto di interruzione che decide dove passare tra il rapporto qualità / compressione basso e alto
  • recupero della dimensione originale dell'immagine
  • decidere quale qualità restituire

Il punto di interruzione e il limite è ciò che decide tra alto e basso e, come detto sopra, potrebbe essere necessario un po 'più di amore.

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

Ci sto ancora lavorando? Per quanto mi riguarda, mi piacerebbe vederlo come un plugin.
Nils Riedemann,

Scusa, ma no, non lo sono. Mi piacerebbe vederlo anche come plugin, ma poiché al momento non ne ho bisogno e non ho tempo, non succederà finora. Forse provaci, vedi quanto lontano arrivi e invia una modifica o una risposta separata? :)
Kaiser

Kaiser: L'hai complicato troppo, penso. $ Image inviata a image_editor_save_pre è un'istanza della classe WP_Image_Editor. Ha funzioni per ottenere le dimensioni e impostare la qualità e tutto il resto già presente. Tutto quello che devi fare è chiamarli.
Otto
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.