PluginProbe ʕ •ᴥ•ʔ
TinyPNG – JPEG, PNG & WebP image compression / trunk
TinyPNG – JPEG, PNG & WebP image compression vtrunk
3.7.0 3.6.14 trunk 1.0.0 1.1.0 1.2.0 1.2.1 1.3.0 1.3.1 1.3.2 1.4.0 1.5.0 1.6.0 1.7.0 1.7.1 1.7.2 2.0.0 2.0.1 2.0.2 2.1.0 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 3.0.0 3.0.1 3.1.0 3.2.0 3.2.1 3.3 3.4 3.4.1 3.4.2 3.4.4 3.4.5 3.4.6 3.5.0 3.5.1 3.5.2 3.6.0 3.6.1 3.6.10 3.6.11 3.6.12 3.6.13 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.6.9
tiny-compress-images / src / class-tiny-image.php
tiny-compress-images / src Last commit date
compatibility 1 day ago config 1 day ago css 5 months ago data 3 years ago images 3 years ago js 1 day ago vendor 4 months ago views 1 day ago class-tiny-apache-rewrite.php 1 day ago class-tiny-bulk-optimization.php 1 day ago class-tiny-cli.php 1 day ago class-tiny-compress-client.php 1 day ago class-tiny-compress-fopen.php 1 day ago class-tiny-compress.php 1 day ago class-tiny-conversion.php 2 months ago class-tiny-diagnostics.php 5 months ago class-tiny-exception.php 5 months ago class-tiny-helpers.php 1 day ago class-tiny-image-size.php 1 day ago class-tiny-image.php 1 day ago class-tiny-logger.php 1 day ago class-tiny-migrate.php 1 day ago class-tiny-notices.php 1 day ago class-tiny-php.php 1 day ago class-tiny-picture.php 1 day ago class-tiny-plugin.php 1 day ago class-tiny-settings.php 1 day ago class-tiny-source-base.php 2 months ago class-tiny-source-image.php 5 months ago class-tiny-source-picture.php 5 months ago class-tiny-wp-base.php 1 day ago
class-tiny-image.php
665 lines
1 <?php
2 /*
3 * Tiny Compress Images - WordPress plugin.
4 * Copyright (C) 2015-2018 Tinify B.V.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc., 51
18 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 class Tiny_Image {
22 const ORIGINAL = 0;
23 const ORIGINAL_UNSCALED = 'original_unscaled';
24
25 /** @var Tiny_Settings */
26 private $settings;
27 private $id;
28 private $name;
29 private $wp_metadata;
30 private $sizes = array();
31 private $statistics = array();
32
33 public function __construct(
34 $settings,
35 $id,
36 $wp_metadata = null,
37 $tiny_metadata = null,
38 $active_sizes = null,
39 $active_tinify_sizes = null
40 ) {
41 $this->settings = $settings;
42 $this->id = $id;
43 $this->wp_metadata = $wp_metadata;
44 $this->parse_wp_metadata();
45 $this->parse_tiny_metadata( $tiny_metadata );
46 $this->detect_duplicates( $active_sizes, $active_tinify_sizes );
47 }
48
49 private function parse_wp_metadata() {
50 if ( ! is_array( $this->wp_metadata ) ) {
51 $this->wp_metadata = wp_get_attachment_metadata( $this->id );
52 }
53
54 if ( ! is_array( $this->wp_metadata ) || ! isset( $this->wp_metadata['file'] ) ) {
55 /*
56 No file metadata found, this might be another plugin messing with
57 metadata. Simply ignore this! */
58 return;
59 }
60
61 $upload_dir = wp_upload_dir();
62 $path_prefix = $upload_dir['basedir'] . '/';
63 $path_info = pathinfo( $this->wp_metadata['file'] );
64 if ( isset( $path_info['dirname'] ) ) {
65 $path_prefix .= $path_info['dirname'] . '/';
66 }
67
68 /*
69 Do not use pathinfo for getting the filename.
70 It doesn't work when the filename starts with a special character. */
71 $path_parts = explode( '/', $this->wp_metadata['file'] );
72 $this->name = end( $path_parts );
73 $filename = $path_prefix . $this->name;
74 $this->sizes[ self::ORIGINAL ] = new Tiny_Image_Size( $filename );
75
76 if ( isset( $this->wp_metadata['original_image'] ) ) {
77 $this->sizes[ self::ORIGINAL_UNSCALED ] = new Tiny_Image_Size(
78 $path_prefix . wp_basename( $this->wp_metadata['original_image'] )
79 );
80 }
81
82 // Ensure 'sizes' exists and is an array to prevent PHP Warnings
83 $sizes = isset( $this->wp_metadata['sizes'] ) && is_array( $this->wp_metadata['sizes'] )
84 ? $this->wp_metadata['sizes']
85 : array();
86
87 $sanitized_sizes = array();
88 foreach ( $sizes as $size_name => $size_info ) {
89 // size is valid when its an array and has a file
90 if ( is_array( $size_info ) && isset( $size_info['file'] ) ) {
91 // Add to sanitized metadata
92 $sanitized_sizes[ $size_name ] = $size_info;
93 $this->sizes[ $size_name ] = new Tiny_Image_Size(
94 $path_prefix . wp_basename( $size_info['file'] )
95 );
96 }
97 }
98
99 // Update the metadata with only the valid sizes found
100 $this->wp_metadata['sizes'] = $sanitized_sizes;
101 }
102
103 private function detect_duplicates( $active_sizes, $active_tinify_sizes ) {
104 $filenames = array();
105
106 if ( is_array( $this->wp_metadata )
107 && isset( $this->wp_metadata['file'] )
108 && isset( $this->wp_metadata['sizes'] )
109 && is_array( $this->wp_metadata['sizes'] ) ) {
110
111 if ( null == $active_sizes ) {
112 $active_sizes = $this->settings->get_sizes();
113 }
114 if ( null == $active_tinify_sizes ) {
115 $active_tinify_sizes = $this->settings->get_active_tinify_sizes();
116 }
117
118 foreach ( $this->wp_metadata['sizes'] as $size_name => $size ) {
119 if ( $this->sizes[ $size_name ]->has_been_compressed()
120 && array_key_exists( $size_name, $active_sizes ) ) {
121 $filenames = $this->duplicate_check( $filenames, $size['file'], $size_name );
122 }
123 }
124 foreach ( $this->wp_metadata['sizes'] as $size_name => $size ) {
125 if ( in_array( $size_name, $active_tinify_sizes, true ) ) {
126 $filenames = $this->duplicate_check( $filenames, $size['file'], $size_name );
127 }
128 }
129 foreach ( $this->wp_metadata['sizes'] as $size_name => $size ) {
130 if ( array_key_exists( $size_name, $active_sizes ) ) {
131 $filenames = $this->duplicate_check( $filenames, $size['file'], $size_name );
132 }
133 }
134 foreach ( $this->wp_metadata['sizes'] as $size_name => $size ) {
135 $filenames = $this->duplicate_check( $filenames, $size['file'], $size_name );
136 }
137 }
138 }
139
140 private function duplicate_check( $filenames, $file, $size_name ) {
141 if ( isset( $filenames[ $file ] ) ) {
142 if ( $filenames[ $file ] != $size_name ) {
143 $this->sizes[ $size_name ]->mark_duplicate( $filenames[ $file ] );
144 }
145 } else {
146 $filenames[ $file ] = $size_name;
147 }
148 return $filenames;
149 }
150
151 /**
152 * Will retrieve compression meta data for the given post_id.
153 *
154 * As migrations on large libraries can take longer, we will fall back on
155 * the legacy key on migrating. We can remove the LEGACY_META_KEY on 3.8.0.
156 *
157 * @since 3.7.0
158 *
159 * @param int $post_id Attachment ID.
160 * @return mixed The stored tiny metadata, or '' when none exists.
161 */
162 public static function get_tiny_metadata( $post_id ) {
163 $tiny_metadata = get_post_meta( $post_id, Tiny_Config::META_KEY, true );
164
165 if ( empty( $tiny_metadata ) ) {
166 $tiny_metadata = get_post_meta( $post_id, Tiny_Config::LEGACY_META_KEY, true );
167 }
168
169 return $tiny_metadata;
170 }
171
172 private function parse_tiny_metadata( $tiny_metadata = null ) {
173 if ( is_null( $tiny_metadata ) ) {
174 $tiny_metadata = self::get_tiny_metadata( $this->id );
175 }
176 if ( $tiny_metadata ) {
177 foreach ( $tiny_metadata as $size => $meta ) {
178 if ( ! isset( $this->sizes[ $size ] ) ) {
179 if ( self::is_retina( $size ) && Tiny_Settings::wr2x_active() ) {
180 $size_name = rtrim( $size, '_wr2x' );
181 if ( 'original' === $size_name ) {
182 $size_name = '0';
183 }
184 $retina_path = wr2x_get_retina(
185 $this->sizes[ $size_name ]->filename
186 );
187 $this->sizes[ $size ] = new Tiny_Image_Size( $retina_path );
188 } else {
189 $this->sizes[ $size ] = new Tiny_Image_Size();
190 }
191 }
192 $this->sizes[ $size ]->meta = $meta;
193 }
194 }
195 }
196
197 public function get_id() {
198 return $this->id;
199 }
200
201 public function get_name() {
202 return $this->name;
203 }
204
205 public function get_wp_metadata() {
206 return $this->wp_metadata;
207 }
208
209 public function file_type_allowed() {
210 return in_array(
211 $this->get_mime_type(),
212 array( 'image/jpeg', 'image/png', 'image/webp' ),
213 true
214 );
215 }
216
217 public function get_mime_type() {
218 return get_post_mime_type( $this->id );
219 }
220
221 public function compress() {
222 Tiny_Logger::debug(
223 'compress',
224 array(
225 'image_id' => $this->id,
226 'name' => $this->name,
227 )
228 );
229 if ( $this->settings->get_compressor() === null || ! $this->file_type_allowed() ) {
230 return;
231 }
232
233 $success = 0;
234 $failed = 0;
235
236 $active_tinify_sizes = $this->settings->get_active_tinify_sizes();
237
238 if ( $this->settings->get_conversion_enabled() ) {
239 $uncompressed_sizes = $this->filter_image_sizes( 'uncompressed', $active_tinify_sizes );
240 $unconverted_sizes = $this->filter_image_sizes( 'unconverted', $active_tinify_sizes );
241
242 $unprocessed_sizes = $uncompressed_sizes + $unconverted_sizes;
243 } else {
244 $unprocessed_sizes = $this->filter_image_sizes( 'uncompressed', $active_tinify_sizes );
245 }
246
247 $compressor = $this->settings->get_compressor();
248 $convert_to = $this->convert_to();
249
250 foreach ( $unprocessed_sizes as $size_name => $size ) {
251 if ( ! $size->is_duplicate() ) {
252 $size->add_tiny_meta_start();
253 $this->update_tiny_post_meta();
254 $resize = $this->settings->get_resize_options( $size_name );
255 $preserve = $this->settings->get_preserve_options( $size_name );
256 Tiny_Logger::debug(
257 'compress size',
258 array(
259 'image_id' => $this->id,
260 'size' => $size_name,
261 'resize' => $resize,
262 'preserve' => $preserve,
263 'convert' => $convert_to,
264 'modified' => $size->modified(),
265 'filename' => $size->filename,
266 'is_duplicate' => $size->is_duplicate(),
267 'exists' => $size->exists(),
268 'has_been_compressed' => $size->has_been_compressed(),
269 'filesize' => $size->filesize(),
270 'mimetype' => $size->mimetype(),
271 )
272 );
273 try {
274 $response = $compressor->compress_file(
275 $size->filename,
276 $resize,
277 $preserve,
278 $convert_to
279 );
280
281 // ensure that all conversion are in the same format as the first one
282 $convert_to = isset( $response['convert'] ) ?
283 array( $response['convert']['type'] ) :
284 $convert_to;
285
286 $size->add_tiny_meta( $response );
287 ++$success;
288 Tiny_Logger::debug(
289 'compress success',
290 array(
291 'size' => $size_name,
292 'image_id' => $this->id,
293 )
294 );
295 } catch ( Tiny_Exception $e ) {
296 $size->add_tiny_meta_error( $e );
297 ++$failed;
298 Tiny_Logger::error(
299 'compress failed',
300 array(
301 'error' => $e->get_message(),
302 'size' => $size_name,
303 'image_id' => $this->id,
304 )
305 );
306 }
307 $this->add_wp_metadata( $size_name, $size );
308 $this->update_tiny_post_meta();
309 }// End if().
310 }// End foreach().
311
312 /*
313 Other plugins can hook into this action to execute custom logic
314 after the image sizes have been compressed, ie. cache flushing.
315 */
316 do_action( 'tiny_image_after_compression', $this->id, $success );
317
318 return array(
319 'success' => $success,
320 'failed' => $failed,
321 );
322 }
323
324 public function delete_converted_image() {
325 $sizes = $this->get_image_sizes();
326 foreach ( $sizes as $size ) {
327 $size->delete_converted_image_size();
328 }
329 }
330
331 public function compress_retina( $size_name, $path ) {
332 if ( $this->settings->get_compressor() === null || ! $this->file_type_allowed() ) {
333 return;
334 }
335
336 if ( ! isset( $this->sizes[ $size_name ] ) ) {
337 $this->sizes[ $size_name ] = new Tiny_Image_Size( $path );
338 }
339
340 $size = $this->sizes[ $size_name ];
341
342 $compressor = $this->settings->get_compressor();
343 $convert_to = $this->convert_to();
344
345 if ( ! $size->has_been_compressed() ) {
346 $size->add_tiny_meta_start();
347 $this->update_tiny_post_meta();
348 $preserve = $this->settings->get_preserve_options( $size_name );
349
350 try {
351 $response = $compressor->compress_file( $path, false, $preserve, $convert_to );
352 $size->add_tiny_meta( $response );
353 } catch ( Tiny_Exception $e ) {
354 $size->add_tiny_meta_error( $e );
355 }
356 $this->update_tiny_post_meta();
357 }
358 }
359
360 public function remove_retina_metadata() {
361 // Remove metadata from all sizes, as this callback only fires when all
362 // retina sizes are deleted.
363 foreach ( $this->sizes as $size_name => $size ) {
364 if ( self::is_retina( $size_name ) ) {
365 unset( $this->sizes[ $size_name ] );
366 }
367 }
368 $this->update_tiny_post_meta();
369 }
370
371 public function add_wp_metadata( $size_name, $size ) {
372 if ( self::is_original( $size_name ) ) {
373 if ( isset( $size->meta['output'] ) ) {
374 $output = $size->meta['output'];
375 if ( isset( $output['width'] ) && isset( $output['height'] ) ) {
376 $this->wp_metadata['width'] = $output['width'];
377 $this->wp_metadata['height'] = $output['height'];
378 $this->wp_metadata['filesize'] = $output['size'];
379 }
380 }
381 }
382 }
383
384 public function update_tiny_post_meta() {
385 $tiny_metadata = array();
386 foreach ( $this->sizes as $size_name => $size ) {
387 $tiny_metadata[ $size_name ] = $size->meta;
388 }
389 update_post_meta( $this->id, Tiny_Config::META_KEY, $tiny_metadata );
390 /*
391 This action is being used by WPML:
392 https://gist.github.com/srdjan-jcc/5c47685cda4da471dff5757ba3ce5ab1
393 */
394 do_action( 'updated_tiny_postmeta', $this->id, Tiny_Config::META_KEY, $tiny_metadata );
395 }
396
397 public function get_image_sizes() {
398 $original = isset( $this->sizes[ self::ORIGINAL ] )
399 ? array(
400 self::ORIGINAL => $this->sizes[ self::ORIGINAL ],
401 )
402 : array();
403 $compressed = array();
404 $uncompressed = array();
405 foreach ( $this->sizes as $size_name => $size ) {
406 if ( self::is_original( $size_name ) ) {
407 continue;
408 }
409
410 if ( $size->has_been_compressed() ) {
411 $compressed[ $size_name ] = $size;
412 } else {
413 $uncompressed[ $size_name ] = $size;
414 }
415 }
416 ksort( $compressed );
417 ksort( $uncompressed );
418 return $original + $compressed + $uncompressed;
419 }
420
421 public function get_image_size( $size = self::ORIGINAL, $create = false ) {
422 if ( isset( $this->sizes[ $size ] ) ) {
423 return $this->sizes[ $size ];
424 } elseif ( $create ) {
425 return new Tiny_Image_Size();
426 } else {
427 return null;
428 }
429 }
430
431 public function filter_image_sizes( $method, $filter_sizes = null ) {
432 $selection = array();
433 if ( is_null( $filter_sizes ) ) {
434 $filter_sizes = array_keys( $this->sizes );
435 }
436 foreach ( $filter_sizes as $size_name ) {
437 if ( ! isset( $this->sizes[ $size_name ] ) ) {
438 continue;
439 }
440
441 $tiny_image_size = $this->sizes[ $size_name ];
442 if ( $tiny_image_size->$method() ) {
443 $selection[ $size_name ] = $tiny_image_size;
444 }
445 }
446 return $selection;
447 }
448
449 public function get_count( $methods, $count_sizes = null ) {
450 $stats = array_fill_keys( $methods, 0 );
451 if ( is_null( $count_sizes ) ) {
452 $count_sizes = array_keys( $this->sizes );
453 }
454 foreach ( $count_sizes as $size ) {
455 if ( ! isset( $this->sizes[ $size ] ) ) {
456 continue;
457 }
458
459 foreach ( $methods as $method ) {
460 if ( $this->sizes[ $size ]->$method() ) {
461 ++$stats[ $method ];
462 }
463 }
464 }
465 return $stats;
466 }
467
468 public function get_latest_error() {
469 $active_tinify_sizes = $this->settings->get_active_tinify_sizes();
470 $error_message = null;
471 $last_timestamp = null;
472 foreach ( $this->sizes as $size_name => $size ) {
473 if ( in_array( $size_name, $active_tinify_sizes, true ) ) {
474 if ( isset( $size->meta['error'] ) && isset( $size->meta['message'] ) ) {
475 if (
476 null === $last_timestamp ||
477 $last_timestamp < $size->meta['timestamp']
478 ) {
479 $last_timestamp = $size->meta['timestamp'];
480 $error_message = Tiny_Helpers::truncate_text(
481 $size->meta['message'],
482 140
483 );
484 }
485 }
486 }
487 }
488 return $error_message;
489 }
490
491 public function get_savings( $stats ) {
492 $before = $stats['initial_total_size'];
493 $after = $stats['compressed_total_size'];
494 if ( 0 === $before ) {
495 $savings = 0;
496 } else {
497 $savings = ( $before - $after ) / $before * 100;
498 }
499 return '' . number_format( $savings, 1 );
500 }
501
502 public function get_statistics( $active_sizes, $active_tinify_sizes ) {
503 if ( $this->statistics ) {
504 Tiny_Logger::error( 'Strangely the image statistics are asked for again.' );
505 return $this->statistics;
506 }
507
508 $this->statistics['initial_total_size'] = 0;
509 $this->statistics['compressed_total_size'] = 0;
510 $this->statistics['image_sizes_compressed'] = 0;
511 $this->statistics['available_uncompressed_sizes'] = 0;
512 $this->statistics['image_sizes_converted'] = 0;
513 $this->statistics['available_unconverted_sizes'] = 0;
514 $this->statistics['image_sizes_optimized'] = 0;
515 $this->statistics['available_unoptimized_sizes'] = 0;
516
517 $conversion_enabled = $this->settings->get_conversion_enabled();
518
519 foreach ( $this->sizes as $size_name => $size ) {
520 // skip duplicates or inactive sizes
521 if ( $size->is_duplicate() || ! isset( $active_sizes[ $size_name ] ) ) {
522 continue;
523 }
524
525 $file_size = $size->filesize();
526 $is_active_size = in_array( $size_name, $active_tinify_sizes, true );
527
528 if ( isset( $size->meta['input'] ) ) {
529 $input_size = (int) $size->meta['input']['size'];
530 $this->statistics['initial_total_size'] += $input_size;
531
532 if ( isset( $size->meta['output'] ) ) {
533 $output_size = (int) $size->meta['output']['size'];
534
535 if ( $size->modified() ) {
536 $this->statistics['compressed_total_size'] += $file_size;
537 if ( $is_active_size ) {
538 ++$this->statistics['available_uncompressed_sizes'];
539 }
540 } else {
541 $this->statistics['compressed_total_size'] += $output_size;
542 ++$this->statistics['image_sizes_compressed'];
543 }
544 } else {
545 $this->statistics['compressed_total_size'] += $input_size;
546 }
547 } elseif ( $size->exists() ) {
548 $this->statistics['initial_total_size'] += $file_size;
549 $this->statistics['compressed_total_size'] += $file_size;
550 if ( $is_active_size ) {
551 ++$this->statistics['available_uncompressed_sizes'];
552 }
553 }
554
555 if ( $is_active_size ) {
556 if ( $size->has_been_converted() ) {
557 ++$this->statistics['image_sizes_converted'];
558 } else {
559 ++$this->statistics['available_unconverted_sizes'];
560 }
561
562 $needs_compression = $size->uncompressed();
563 $needs_conversion = $conversion_enabled && $size->unconverted();
564 if ( $needs_compression || $needs_conversion ) {
565 ++$this->statistics['available_unoptimized_sizes'];
566 } elseif ( $size->compressed() && ( ! $conversion_enabled
567 || $size->has_been_converted() ) ) {
568 ++$this->statistics['image_sizes_optimized'];
569 }
570 }
571 }// End foreach().
572
573 return $this->statistics;
574 }
575
576
577 public static function is_original( $size ) {
578 return self::ORIGINAL === $size;
579 }
580
581
582 /**
583 * Check wether given $size is the original_unscaled image size.
584 *
585 * @since 3.6.14
586 *
587 * @param string $size the size descriptor
588 * @return bool true if size is the original unscaled image
589 */
590 public static function is_original_unscaled( $size ) {
591 return self::ORIGINAL_UNSCALED === $size;
592 }
593
594 public static function is_retina( $size ) {
595 return strrpos( $size, 'wr2x' ) === strlen( $size ) - strlen( 'wr2x' );
596 }
597
598 public function can_be_converted() {
599 return $this->settings->get_conversion_enabled() && $this->file_type_allowed();
600 }
601
602 /**
603 * Get the targeted conversion.
604 * If original is already converted, then we use the originals' mimetype.
605 * If nothing is converted yet, we use the settings conversion settings.
606 *
607 * @since 3.6.4
608 *
609 * @return array{string} mimetypes to which the image should be converted to
610 */
611 private function convert_to() {
612 $convert_settings = $this->settings->get_conversion_options();
613 if ( ! $convert_settings['convert'] ) {
614 // conversion is off so return no mimetypes to convert to
615 return array();
616 }
617
618 if ( isset( $this->sizes[ self::ORIGINAL ] ) ) {
619 // original is not in sizes so mimetypes are open
620 return $convert_settings['convert_to'];
621 }
622
623 $original_img_size = $this->sizes[ self::ORIGINAL ];
624 if ( $original_img_size->converted() ) {
625 // original has been convert so use that mimetype to convert to
626 return array( $original_img_size->meta['convert']['type'] );
627 }
628
629 return $convert_settings['convert_to'];
630 }
631
632 /**
633 * Marks the image as compressed without actually compressing it.
634 *
635 * This method parses existing metadata and delegates to each image size to mark
636 * itself as compressed. It considers conversion settings when marking the sizes.
637 * This is useful for images that are already optimized or when you want to skip
638 * compression while still marking them as processed in the system.
639 *
640 * @since 3.0.0
641 */
642 public function mark_as_compressed() {
643 $this->parse_tiny_metadata();
644
645 $conversion_enabled = $this->settings->get_conversion_enabled();
646
647 $active_tinify_sizes = $this->settings->get_active_tinify_sizes();
648
649 if ( $this->settings->get_conversion_enabled() ) {
650 $uncompressed_sizes = $this->filter_image_sizes( 'uncompressed', $active_tinify_sizes );
651 $unconverted_sizes = $this->filter_image_sizes( 'unconverted', $active_tinify_sizes );
652
653 $unprocessed_sizes = $uncompressed_sizes + $unconverted_sizes;
654 } else {
655 $unprocessed_sizes = $this->filter_image_sizes( 'uncompressed', $active_tinify_sizes );
656 }
657
658 foreach ( $unprocessed_sizes as $size ) {
659 $size->mark_as_compressed( $conversion_enabled );
660 }
661
662 $this->update_tiny_post_meta();
663 }
664 }
665