Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/class-tiny-compress-client.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ protected function validate() {
}
}

protected function compress( $input, $resize_opts, $preserve_opts, $convert_opts ) {
protected function compress( $input, $resize_opts, $preserve_opts, $convert_to ) {
try {
$this->last_error_code = 0;
$this->set_request_options( \Tinify\Tinify::getClient() );
Expand Down Expand Up @@ -121,8 +121,7 @@ protected function compress( $input, $resize_opts, $preserve_opts, $convert_opts
$buffer = $compress_result->toBuffer();
$result = array( $buffer, $meta, null );

if ( isset( $convert_opts['convert'] ) && true == $convert_opts['convert'] ) {
$convert_to = $convert_opts['convert_to'];
if ( count( $convert_to ) > 0 ) {
$convert_source = $source->convert( array(
'type' => $convert_to,
) );
Expand Down
5 changes: 2 additions & 3 deletions src/class-tiny-compress-fopen.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ protected function validate() {
}
}

protected function compress( $input, $resize_opts, $preserve_opts, $convert_opts ) {
protected function compress( $input, $resize_opts, $preserve_opts, $convert_to ) {
$params = $this->request_options( 'POST', $input );
list($details, $headers, $status_code) = $this->request( $params );

Expand Down Expand Up @@ -146,8 +146,7 @@ protected function compress( $input, $resize_opts, $preserve_opts, $convert_opts

$convert = null;

if ( isset( $convert_opts['convert'] ) && true === $convert_opts['convert'] ) {
$convert_to = $convert_opts['convert_to'];
if ( count( $convert_to ) > 0 ) {
$convert_params = $this->request_options(
'POST',
array(
Expand Down
8 changes: 4 additions & 4 deletions src/class-tiny-compress.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,14 @@ public function get_status() {
* @param [type] $file
* @param array $resize_opts
* @param array $preserve_opts
* @param array{ convert: bool, convert_to: string } conversion options
* @param array{ string } conversion options
* @return void
*/
public function compress_file(
$file,
$resize_opts = array(),
$preserve_opts = array(),
$convert_opts = array()
$convert_to = array()
) {
if ( $this->get_key() == null ) {
throw new Tiny_Exception( self::KEY_MISSING, 'KeyError' );
Expand All @@ -131,7 +131,7 @@ public function compress_file(
$file_data,
$resize_opts,
$preserve_opts,
$convert_opts
$convert_to
);
} catch ( Tiny_Exception $err ) {
$this->call_after_compress_callback();
Expand Down Expand Up @@ -172,7 +172,7 @@ protected abstract function compress(
$input,
$resize_options,
$preserve_options,
$convert_opts
$convert_to
);

protected static function identifier() {
Expand Down
53 changes: 47 additions & 6 deletions src/class-tiny-image.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
class Tiny_Image {
const ORIGINAL = 0;

/** @var Tiny_Settings */
private $settings;
private $id;
private $name;
Expand Down Expand Up @@ -179,7 +180,6 @@ public function compress() {
$success = 0;
$failed = 0;

$compressor = $this->settings->get_compressor();
$active_tinify_sizes = $this->settings->get_active_tinify_sizes();

if ( $this->settings->get_conversion_enabled() ) {
Expand All @@ -191,20 +191,28 @@ public function compress() {
$unprocessed_sizes = $this->filter_image_sizes( 'uncompressed', $active_tinify_sizes );
}

$compressor = $this->settings->get_compressor();
$convert_to = $this->convert_to();

foreach ( $unprocessed_sizes as $size_name => $size ) {
if ( ! $size->is_duplicate() ) {
$size->add_tiny_meta_start();
$this->update_tiny_post_meta();
$resize = $this->settings->get_resize_options( $size_name );
$preserve = $this->settings->get_preserve_options( $size_name );
$convert_opts = $this->settings->get_conversion_options();
try {
$response = $compressor->compress_file(
$size->filename,
$resize,
$preserve,
$convert_opts
$convert_to
);

// ensure that all conversion are in the same format as the first one
$convert_to = isset( $response['convert'] ) ?
array( $response['convert']['type'] ) :
$convert_to;

$size->add_tiny_meta( $response );
$success++;
} catch ( Tiny_Exception $e ) {
Expand Down Expand Up @@ -243,17 +251,19 @@ public function compress_retina( $size_name, $path ) {
if ( ! isset( $this->sizes[ $size_name ] ) ) {
$this->sizes[ $size_name ] = new Tiny_Image_Size( $path );
}

$size = $this->sizes[ $size_name ];

$compressor = $this->settings->get_compressor();
$convert_to = $this->convert_to();

if ( ! $size->has_been_compressed() ) {
$size->add_tiny_meta_start();
$this->update_tiny_post_meta();
$compressor = $this->settings->get_compressor();
$preserve = $this->settings->get_preserve_options( $size_name );
$conversion = $this->settings->get_conversion_options();

try {
$response = $compressor->compress_file( $path, false, $preserve, $conversion );
$response = $compressor->compress_file( $path, false, $preserve, $convert_to );
$size->add_tiny_meta( $response );
} catch ( Tiny_Exception $e ) {
$size->add_tiny_meta_error( $e );
Expand Down Expand Up @@ -472,6 +482,37 @@ public function can_be_converted() {
return $this->settings->get_conversion_enabled() && $this->file_type_allowed();
}

/**
* Get the targeted conversion.
* If original is already converted, then we use the originals' mimetype.
* If nothing is converted yet, we use the settings conversion settings.
*
* @since 3.6.4
*
* @return array{string} mimetypes to which the image should be converted to
*/
private function convert_to() {
$convert_settings = $this->settings->get_conversion_options();
if ( ! $convert_settings['convert'] ) {
// conversion is off so return no mimetypes to convert to
return array();
}

if ( isset( $this->sizes[ self::ORIGINAL ] ) ) {
// original is not in sizes so mimetypes are open
return $convert_settings['convert_to'];
}

$original_img_size = $this->sizes[ self::ORIGINAL ];
if ( $original_img_size->converted() ) {
// original has been convert so use that mimetype to convert to
return array( $original_img_size->meta['convert']['type'] );
}

return $convert_settings['convert_to'];

}

/**
* Marks the image as compressed without actually compressing it.
*
Expand Down
120 changes: 98 additions & 22 deletions src/class-tiny-picture.php
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ protected function get_image_srcsets( $html ) {
// Trim whitespace
$entry = trim( $entry );

// Split by whitespace to separate path and size descriptor
// Split by whitespace to separate path and size/density descriptor
$parts = preg_split( '/\s+/', $entry, 2 );

if ( count( $parts ) === 2 ) {
Expand All @@ -316,24 +316,33 @@ protected function get_image_srcsets( $html ) {
'size' => $parts[1],
);
} elseif ( count( $parts ) === 1 ) {
// We only have a path (unusual in srcset)
// We only have a path, will be interpreted as pixel
// density 1x (unusual in srcset)
$result[] = array(
'path' => $parts[0],
'size' => '',
);
}
}
}
return $result;
}

/**
* Retrieves the sources from the <img> or <source> element
*
* @return array{path: string, size: string}[] The image sources
*/
private function get_image_src( $html ) {
$source = $this::get_attribute_value( $html, 'src' );
if ( ! empty( $source ) ) {
// No srcset, but we have a src attribute
$result[] = array(
return array(
'path' => $source,
'size' => '',
);
}
return $result;
return array();
}


Expand All @@ -346,15 +355,22 @@ protected function get_image_srcsets( $html ) {
*/
protected function create_alternative_sources( $original_source_html ) {
$srcsets = $this->get_image_srcsets( $original_source_html );
if ( empty( $srcsets ) ) {
// no srcset, try src attribute
$srcsets[] = $this->get_image_src( $original_source_html );
}

if ( empty( $srcsets ) ) {
return array();
}

$is_source_tag = (bool) preg_match( '#<source\b#i', $original_source_html );

$sources = array();
$width_descriptor = $this->get_largest_width_descriptor( $srcsets );

foreach ( $this->valid_mimetypes as $mimetype ) {
$srcset_parts = [];
$srcset_parts = array();

foreach ( $srcsets as $srcset ) {
$alt_source = $this->get_formatted_source( $srcset, $mimetype );
Expand All @@ -363,32 +379,92 @@ protected function create_alternative_sources( $original_source_html ) {
}
}

if ( ! empty( $srcset_parts ) ) {
$source_attr_parts = array();
if ( $width_descriptor &&
! self::srcset_contains_width_descriptor(
$srcset_parts,
$width_descriptor
) ) {
continue;
}

$srcset_attr = implode( ', ', $srcset_parts );
$source_attr_parts['srcset'] = $srcset_attr;
if ( empty( $srcset_parts ) ) {
continue;
}

if ( $is_source_tag ) {
foreach ( array( 'sizes', 'media', 'width', 'height' ) as $attr ) {
$attr_value = $this->get_attribute_value( $original_source_html, $attr );
if ( $attr_value ) {
$source_attr_parts[ $attr ] = $attr_value;
}
$source_attr_parts = array();

$srcset_attr = implode( ', ', $srcset_parts );
$source_attr_parts['srcset'] = $srcset_attr;

if ( $is_source_tag ) {
foreach ( array( 'sizes', 'media', 'width', 'height' ) as $attr ) {
$attr_value = $this->get_attribute_value( $original_source_html, $attr );
if ( $attr_value ) {
$source_attr_parts[ $attr ] = $attr_value;
}
}
}

$source_attr_parts['type'] = $mimetype;
$source_parts = array( '<source' );
foreach ( $source_attr_parts as $source_attr_name => $source_attr_val ) {
$source_parts[] = $source_attr_name . '="' . $source_attr_val . '"';
}
$source_parts[] = '/>';
$sources[] = implode( ' ', $source_parts );
}// End foreach().

$source_attr_parts['type'] = $mimetype;
$source_parts = array( '<source' );
foreach ( $source_attr_parts as $source_attr_name => $source_attr_val ) {
$source_parts[] = $source_attr_name . '="' . $source_attr_val . '"';
return $sources;
}

/**
* Returns the largest numeric width descriptor
* (e.g. 2000 from "2000w") found in the srcset data.
*
* @param array<array{path: string, size: string}> $srcsets
* @return int
*/
public static function get_largest_width_descriptor( $srcsets ) {
$largest = 0;

foreach ( $srcsets as $srcset ) {
if ( empty( $srcset['size'] ) ) {
continue;
}

if ( preg_match( '/(\d+)w/', $srcset['size'], $matches ) ) {
$width = (int) $matches[1];
if ( $width > $largest ) {
$largest = $width;
}
$source_parts[] = '/>';
$sources[] = implode( ' ', $source_parts );
}
}

return $sources;
return $largest;
}

/**
* Determines whether a srcset list contains the provided width descriptor.
*
* @param string[] $srcset_parts
* @param int $width_descriptor
* @return bool true if width is in srcset
*/
public static function srcset_contains_width_descriptor( $srcset_parts, $width_descriptor ) {
if ( empty( $srcset_parts ) || $width_descriptor <= 0 ) {
return false;
}

$suffix = ' ' . $width_descriptor . 'w';
$suffix_length = strlen( $suffix );

foreach ( $srcset_parts as $srcset_part ) {
if ( substr( $srcset_part, -$suffix_length ) === $suffix ) {
return true;
}
}

return false;
}
}

Expand Down
8 changes: 7 additions & 1 deletion src/class-tiny-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,12 @@ protected static function get_intermediate_size( $size ) {
return array( null, null );
}

/**
* Retrieves image sizes as a map of size and width, height and tinify meta data
* The first entry will always be '0', aka the original uploaded image.
*
* @return array{string: array{width: int|null, height: int|null, tinify: array{}}} $sizes
*/
public function get_sizes() {
if ( is_array( $this->sizes ) ) {
return $this->sizes;
Expand Down Expand Up @@ -374,7 +380,7 @@ public function get_resize_options( $size_name ) {
/**
* Retrieves the configured settings for conversion.
*
* @return array{ convert: bool, convert_to: string } The conversion options.
* @return array{ convert: bool, convert_to: array{string} } The conversion options.
*/
public function get_conversion_options() {
return array(
Expand Down
Loading