Qualidade de imagem com base no tamanho da imagem


15

É possível definir a qualidade da imagem com base no tamanho da imagem? Eu gostaria de ter uma melhor qualidade de imagem para imagens maiores (80) - e pior para miniaturas pequenas (30).

Eu estava esperando um parâmetro add_sizepara controlar isso - mas não há nenhum.

Se isso importa: estou usando o ImageMagick.

Respostas:


15

O único momento em que a qualidade é realmente importante é justamente antes da imagem ser salva ou transmitida (para o editor). Ambos têm o filtro "image_editor_save_pre", passando a instância do editor de imagens. Assim, você pode usá-lo para modificar a imagem da maneira que desejar, incluindo a definição da qualidade.

Portanto, algo assim deve fazer o trabalho de maneira simples e fácil:

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 pelo qual não usei algo tão reto como este (+1), lembro vagamente que, ao editar alguma imagem (girar, recortar etc.), cada ação era chamada duas vezes, reduzindo a qualidade duas vezes. Ainda assim, a parte "is a instance of WP_Image_Editor" é uma solução muito mais do que eu escrevi.
Kaiser #

1
A qualidade é um valor exato, não uma porcentagem. Você pode definir e redefinir tudo o que quiser, até salvar. Defini-lo para 10 cem vezes deixa-lo em 10.
Otto

Eu assumi que isso salvaria no meio. Obrigado pela atenção.
Kaiser #

Parece-me que image_editor_save_prenão é chamado. Quando tento produzir coisas usando error_log(o que definitivamente funciona), não recebo nenhuma saída. : /
Nils Riedemann 27/03

1
A regeneração também pode funcionar se salvar a imagem novamente. Nenhum código alterará os arquivos existentes no sistema sem que você efetue a ação para recarregá-los e salvá-los novamente.
Otto

5

Observação antecipada: a resposta abaixo não está concluída e não foi testada, mas como ainda não tenho tempo, deixarei isso aqui como rascunho. O que provavelmente precisa de um segundo par de olhos é o método de qualidade e a interpretação de version_compare().

Primeiro, precisamos de um ponto de entrada. Depois de ler novamente o make post , pensei que seria melhor pular antes que o Image Editor salve a imagem recém-criada. Então, aqui está um microcontrolador que intercepta durante um retorno de chamada conectado image_editor_save_pree carrega uma classe que percorre suas configurações definidas dentro de um retorno de chamada para wpse_jpeg_quality. Ele simplesmente retorna taxas de compactação diferentes para o jpeg_qualityfiltro que é executado dentro do Image Editor.

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

O trabalhador real é a JPEGQualityWorkerclasse. Ele reside no mesmo diretório que o arquivo principal do plugin acima e é nomeado worker.php(ou você altera o controlador acima).

Ele recupera a imagem e suas configurações e adiciona retornos de chamada ao jpeg_qualityfiltro. O que é que é

  • recuperando sua referência de imagem (largura ou altura)
  • questionando seu ponto de interrupção que decide onde alternar entre baixa e alta relação qualidade / compressão
  • recuperando o tamanho da imagem original
  • decidir qual qualidade retornar

O ponto de interrupção e o limite é o que decide entre alto e baixo e, como mencionado acima, isso pode precisar de mais amor.

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

Ainda está trabalhando nisso? Para mim, eu adoraria ver isso como um plugin.
Nils Riedemann

Desculpe, mas não, não estou. Eu gostaria de ver isso também como plugin, mas como atualmente não preciso dele e não tenho tempo, isso não acontecerá até agora. Talvez tente, veja até onde você chega e arquive uma edição ou uma resposta separada? :)
kaiser

Kaiser: Você complicou demais, eu acho. A imagem $ enviada para image_editor_save_pre é uma instância da classe WP_Image_Editor. Possui funções para obter o tamanho e definir a qualidade e tudo o mais. Tudo o que você precisa fazer é ligar para eles.
Otto
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.