Calidad de imagen basada en el tamaño de la imagen.

15

¿Es posible establecer la calidad de la imagen en función del tamaño de la imagen? Me gustaría tener una mejor calidad de imagen para imágenes más grandes (80), y peor para miniaturas pequeñas (30).

Esperaba un parámetro en add_size para controlar eso, pero no hay ninguno.

Si es importante: estoy usando ImageMagick.

Nils Riedemann
fuente

Respuestas:

15

El único momento en que la calidad realmente importa es justo antes de que la imagen se guarde o se transmita (para el editor). Ambos tienen el filtro "image_editor_save_pre" allí, pasando la instancia del editor de imágenes. Por lo tanto, puede usar eso para modificar la imagen de la manera que desee, incluida la configuración de la calidad.

Entonces, algo como esto debería hacer el trabajo simple y fácilmente:

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;
}
Otón
fuente
La razón por la que no usé algo tan directo como este (+1) es que recuerdo vagamente que al editar alguna imagen (rotar, recortar, etc.), cada acción se llamaba dos veces, reduciendo la calidad dos veces. Aún así, la parte "es una instancia de WP_Image_Editor" es una solución mucho más de lo que escribí.
Kaiser
1
La calidad es un valor exacto, no un porcentaje. Puede configurarlo y restablecerlo todo lo que quiera, hasta que se guarde. Establecerlo en 10 cientos de veces lo deja en 10.
Otto
Asumí que ahorraría en el medio. Gracias por el aviso.
Kaiser
Me parece que image_editor_save_preno me llaman. Cuando trato de generar cosas usando error_log(que definitivamente funciona) no obtengo ningún resultado. : /
Nils Riedemann
1
La regeneración también podría funcionar si vuelve a guardar la imagen. Ningún código va a cambiar los archivos existentes en el sistema sin que usted tome la acción de volver a cargarlos y volverlos a guardar.
Otto
5

Nota por adelantado: la respuesta a continuación no está terminada y no se ha probado, pero no me queda tiempo suficiente, así que lo dejaré aquí como borrador. Lo que probablemente necesite un segundo par de ojos es el método de calidad y la interpretación deversion_compare() .

Primero necesitamos un punto de entrada. Después de leer la publicación de nuevo, pensé que lo mejor sería saltar antes de que el Editor de imágenes guarde la imagen recién creada. Entonces, aquí hay un microcontrolador que intercepta durante una devolución de llamada conectada image_editor_save_prey carga una clase que luego recorre la configuración definida dentro de una devolución de llamada wpse_jpeg_quality. Simplemente devuelve diferentes relaciones de compresión para el jpeg_qualityfiltro que se ejecuta dentro del Editor de imágenes.

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

El trabajador real es la JPEGQualityWorkerclase. Reside en el mismo directorio que el archivo de complemento principal anterior y se nombra worker.php(o cambia el controlador anterior).

Recupera la imagen y su configuración y luego agrega devoluciones de llamada al jpeg_qualityfiltro. Lo que hace es

  • recuperar su referencia de imagen (ancho o alto)
  • cuestionando su punto de interrupción que decide dónde cambiar entre relación calidad / compresión baja y alta
  • recuperar el tamaño de la imagen original
  • decidir qué calidad devolver

El punto de ruptura y el límite es lo que decide entre alto y bajo y, como se mencionó anteriormente, esto podría necesitar un poco más de 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;
    }
}
emperador
fuente
¿Sigo trabajando en eso? En lo que a mí respecta, me encantaría ver eso como un complemento.
Nils Riedemann
Lo siento, pero no, no lo estoy. Me gustaría ver eso también como complemento, pero como actualmente no lo necesito y no tengo el tiempo, no va a suceder hasta ahora. Tal vez intente, vea hasta dónde llega y presente una edición o una respuesta por separado. :)
kaiser
Kaiser: Creo que lo complicaste demasiado. La imagen $ enviada a image_editor_save_pre es una instancia de la clase WP_Image_Editor. Tiene funciones para obtener el tamaño y establecer la calidad y todo lo demás que ya está en él. Todo lo que tienes que hacer es llamarlos.
Otto