AlkantarClanX12
Current Path : /home/thanudqk/thepball.com/wp-content/plugins/wp-smushit/core/modules/ |
Current File : /home/thanudqk/thepball.com/wp-content/plugins/wp-smushit/core/modules/class-png2jpg.php |
<?php /** * PNG to JPG conversion: Png2jpg class * * @package Smush\Core\Modules * * @version 2.4 * * @author Umesh Kumar <umesh@incsub.com> * * @copyright (c) 2016, Incsub (http://incsub.com) */ namespace Smush\Core\Modules; use Exception; use Imagick; use ImagickPixel; use Smush\Core\Helper; use WP_Smush; if ( ! defined( 'WPINC' ) ) { die; } /** * Class Png2jpg */ class Png2jpg extends Abstract_Module { /** * Does PNG contain transparency. * * @var bool */ private $is_transparent = false; /** * Init method. * * @since 3.0 */ public function init() {} /** * Check if Imagick is available or not * * @return bool True/False Whether Imagick is available or not */ private function supports_imagick() { if ( ! class_exists( '\Imagick' ) ) { return false; } return true; } /** * Check if GD is loaded * * @return bool True/False Whether GD is available or not */ private function supports_gd() { if ( ! function_exists( 'gd_info' ) ) { return false; } return true; } /** * Checks if the Given PNG file is transparent or not * * @param string $id Attachment ID. * @param string $file File path for the attachment. * * @return bool|int */ private function is_transparent( $id = '', $file = '' ) { // No attachment id/ file path, return. if ( empty( $id ) && empty( $file ) ) { return false; } if ( empty( $file ) ) { $file = Helper::get_attached_file( $id ); } // Check if File exists. if ( empty( $file ) || ! file_exists( $file ) ) { return false; } $transparent = ''; // Try to get transparency using Imagick. if ( $this->supports_imagick() ) { try { $im = new Imagick( $file ); return $im->getImageAlphaChannel(); } catch ( Exception $e ) { error_log( 'Imagick: Error in checking PNG transparency ' . $e->getMessage() ); } } else { // Simple check. // Src: http://camendesign.com/code/uth1_is-png-32bit. if ( ord( file_get_contents( $file, false, null, 25, 1 ) ) & 4 ) { return true; } // Src: http://www.jonefox.com/blog/2011/04/15/how-to-detect-transparency-in-png-images/. $contents = file_get_contents( $file ); if ( stripos( $contents, 'PLTE' ) !== false && stripos( $contents, 'tRNS' ) !== false ) { return true; } // If both the conditions failed, that means not transparent. return false; } // If Imagick is installed, and the code exited due to some error. // Src: StackOverflow. if ( empty( $transparent ) && $this->supports_gd() ) { // Check for transparency using GD. $i = imagecreatefrompng( $file ); $palette = ( imagecolortransparent( $i ) < 0 ); if ( $palette ) { return true; } } return false; } /** * Check whether to convert the PNG to JPG or not * * @param string $id Attachment ID. * @param string $file File path for the attachment. * * @return bool Whether to convert the PNG or not */ private function should_convert( $id, $file ) { // Get the Transparency conversion settings. $convert_png = $this->settings->get( 'png_to_jpg' ); if ( ! $convert_png ) { return false; } // Whether to convert transparent images or not. $transparent_settings = $this->settings->get_setting( WP_SMUSH_PREFIX . 'transparent_png', false ); $convert_transparent = $transparent_settings['convert']; // Transparency Check. $this->is_transparent = $this->is_transparent( $id, $file ); // If we are suppose to convert transparent images, skip is transparent check. if ( $convert_transparent || ! $this->is_transparent ) { return true; } return false; } /** * Check if given attachment id can be converted to JPEG or not * * @param string $id Atachment ID. * @param string $size Image size. * @param string $mime Mime type. * @param string $file File. * * @return bool True/False Can be converted or not */ public function can_be_converted( $id = '', $size = 'full', $mime = '', $file = '' ) { if ( empty( $id ) ) { return false; } // False if not a PNG. $mime = empty( $mime ) ? get_post_mime_type( $id ) : $mime; if ( 'image/png' !== $mime && 'image/x-png' !== $mime ) { return false; } // Return if Imagick and GD is not available. if ( ! $this->supports_imagick() && ! $this->supports_gd() ) { return false; } // If already tried the conversion. if ( get_post_meta( $id, WP_SMUSH_PREFIX . 'pngjpg_savings', true ) ) { return false; } // Check if registered size is supposed to be converted or not. if ( 'full' !== $size && WP_Smush::get_instance()->core()->mod->smush->skip_image_size( $size ) ) { return false; } if ( empty( $file ) ) { $file = Helper::get_attached_file( $id ); } /** Whether to convert to jpg or not */ $should_convert = $this->should_convert( $id, $file ); /** * Filter whether to convert the PNG to JPG or not * * @since 2.4 * * @param bool $should_convert Current choice for image conversion * * @param int $id Attachment id * * @param string $file File path for the image * * @param string $size Image size being converted */ $should_convert = apply_filters( 'wp_smush_convert_to_jpg', $should_convert, $id, $file, $size ); return $should_convert; } /** * Update the image URL, MIME Type, Attached File, file path in Meta, URL in post content * * @param string $id Attachment ID. * @param string $o_file Original File Path that has to be replaced. * @param string $n_file New File Path which replaces the old file. * @param string $meta Attachment Meta. * @param string $size_k Image Size. * @param string $o_type Operation Type "conversion", "restore". * * @return mixed Attachment Meta with updated file path. */ public function update_image_path( $id, $o_file, $n_file, $meta, $size_k, $o_type = 'conversion' ) { // Upload Directory. $upload_dir = wp_upload_dir(); // Upload Path. $upload_path = trailingslashit( $upload_dir['basedir'] ); $dir_name = pathinfo( $o_file, PATHINFO_DIRNAME ); // Full Path to new file. $n_file_path = path_join( $dir_name, $n_file ); // Current URL for image. $o_url = wp_get_attachment_url( $id ); // Update URL for image size. if ( 'full' !== $size_k ) { $base_url = dirname( $o_url ); $o_url = $base_url . '/' . basename( $o_file ); } // Update File path, Attached File, GUID. $meta = empty( $meta ) ? wp_get_attachment_metadata( $id ) : $meta; $mime = Helper::get_mime_type( $n_file_path ); // Update File Path, Attached file, Mime Type for Image. if ( 'full' === $size_k ) { if ( ! empty( $meta ) ) { $new_file = str_replace( $upload_path, '', $n_file_path ); $meta['file'] = $new_file; } // Update Attached File. update_attached_file( $id, $meta['file'] ); // Update Mime type. wp_update_post( array( 'ID' => $id, 'post_mime_type' => $mime, ) ); } else { $meta['sizes'][ $size_k ]['file'] = basename( $n_file ); $meta['sizes'][ $size_k ]['mime-type'] = $mime; } // To be called after the attached file key is updated for the image. $this->update_image_url( $id, $size_k, $n_file, $o_url ); // Delete the Original files if backup not enabled. if ( 'conversion' === $o_type && ! $this->settings->get( 'backup' ) ) { @unlink( $o_file ); } return $meta; } /** * Replace the file if there are savings, and return savings * * @param string $file Original File Path. * @param array $result Array structure. * @param string $n_file Updated File path. * * @return array */ private function replace_file( $file = '', $result = array(), $n_file = '' ) { if ( empty( $file ) || empty( $n_file ) ) { return $result; } // Get the file size of original image. $o_file_size = filesize( $file ); $n_file = path_join( dirname( $file ), $n_file ); $n_file_size = filesize( $n_file ); // If there aren't any savings return. if ( $n_file_size >= $o_file_size ) { // Delete the JPG image and return. @unlink( $n_file ); return $result; } // Get the savings. $savings = $o_file_size - $n_file_size; // Store Stats. $savings = array( 'bytes' => $savings, 'size_before' => $o_file_size, 'size_after' => $n_file_size, ); $result['savings'] = $savings; return $result; } /** * Perform the conversion process, using WordPress Image Editor API * * @param string $id Attachment ID. * @param string $file Attachment File path. * @param string $meta Attachment meta. * @param string $size Image size, default empty for full image. * * @return array $result array( * 'meta' => array Update Attachment metadata * 'savings' => Reduction of Image size in bytes * ) */ private function convert_to_jpg( $id = '', $file = '', $meta = '', $size = 'full' ) { $result = array( 'meta' => $meta, 'savings' => '', ); // Flag: Whether the image was converted or not. if ( 'full' === $size ) { $result['converted'] = false; } // If any of the values is not set. if ( empty( $id ) || empty( $file ) || empty( $meta ) ) { return $result; } $editor = wp_get_image_editor( $file ); if ( is_wp_error( $editor ) ) { // Use custom method maybe. return $result; } $n_file = pathinfo( $file ); if ( ! empty( $n_file['filename'] ) && $n_file['dirname'] ) { // Get a unique File name. $n_file['filename'] = wp_unique_filename( $n_file['dirname'], $n_file['filename'] . '.jpg' ); $n_file = path_join( $n_file['dirname'], $n_file['filename'] ); } else { return $result; } // Save PNG as JPG. $new_image_info = $editor->save( $n_file, 'image/jpeg' ); // If image editor was unable to save the image, return. if ( is_wp_error( $new_image_info ) ) { return $result; } $n_file = ! empty( $new_image_info ) ? $new_image_info['file'] : ''; // Replace file, and get savings. $result = $this->replace_file( $file, $result, $n_file ); if ( ! empty( $result['savings'] ) ) { if ( 'full' === $size ) { $result['converted'] = true; } // Update the File Details. and get updated meta. $result['meta'] = $this->update_image_path( $id, $file, $n_file, $meta, $size ); /** * Perform a action after the image URL is updated in post content */ do_action( 'wp_smush_image_url_changed', $id, $file, $n_file, $size ); } return $result; } /** * Convert a PNG to JPG, Lossless Conversion, if we have any savings * * @param string $id Image ID. * @param string|array $meta Image meta. * * @uses Backup::add_to_image_backup_sizes() * * @return mixed|string * * TODO: Save cumulative savings */ public function png_to_jpg( $id = '', $meta = '' ) { // If we don't have meta or ID, or if not a premium user. if ( empty( $id ) || empty( $meta ) || ! WP_Smush::is_pro() ) { return $meta; } $file = Helper::get_attached_file( $id ); // Whether to convert to jpg or not. $should_convert = $this->can_be_converted( $id ); if ( ! $should_convert ) { return $meta; } $result['meta'] = $meta; if ( ! $this->is_transparent ) { // Perform the conversion, and update path. $result = $this->convert_to_jpg( $id, $file, $result['meta'] ); } else { $result = $this->convert_tpng_to_jpg( $id, $file, $result['meta'] ); } $savings['full'] = ! empty( $result['savings'] ) ? $result['savings'] : ''; // If original image was converted and other sizes are there for the image, Convert all other image sizes. if ( $result['converted'] ) { if ( ! empty( $meta['sizes'] ) ) { foreach ( $meta['sizes'] as $size_k => $data ) { $s_file = path_join( dirname( $file ), $data['file'] ); // Whether to convert to jpg or not. $should_convert = $this->can_be_converted( $id, $size_k, 'image/png', $s_file ); // Perform the conversion. if ( ! $should_convert ) { continue; } // Perform the conversion, and update path. if ( ! $this->is_transparent ) { // Perform the conversion, and update path. $result = $this->convert_to_jpg( $id, $s_file, $result['meta'], $size_k ); } else { $result = $this->convert_tpng_to_jpg( $id, $s_file, $result['meta'], $size_k ); } if ( ! empty( $result['savings'] ) ) { $savings[ $size_k ] = $result['savings']; } } } // Save the original File URL. $o_file = ! empty( $file ) ? $file : get_post_meta( $id, '_wp_attached_file', true ); WP_Smush::get_instance()->core()->mod->backup->add_to_image_backup_sizes( $id, $o_file, 'smush_png_path' ); // Remove webp images created from the png version, if any. WP_Smush::get_instance()->core()->mod->webp->delete_images( $id, true, $o_file ); /** * Do action, if the PNG to JPG conversion was successful */ do_action( 'wp_smush_png_jpg_converted', $id, $meta, $savings ); } // Update the Final Stats. update_post_meta( $id, WP_SMUSH_PREFIX . 'pngjpg_savings', $savings ); return $result['meta']; } /** * Convert a transparent PNG to JPG, with specified background color * * @param string $id Attachment ID. * @param string $file File Path Original Image. * @param string $meta Attachment Meta. * @param string $size Image size. set to 'full' by default. * * @return array Savings and Updated Meta */ private function convert_tpng_to_jpg( $id = '', $file = '', $meta = '', $size = 'full' ) { $result = array( 'meta' => $meta, 'savings' => '', ); // Flag: Whether the image was converted or not. if ( 'full' === $size ) { $result['converted'] = false; } // If any of the values is not set. if ( empty( $id ) || empty( $file ) || empty( $meta ) ) { return $result; } // Get the File name without ext. $n_file = pathinfo( $file ); if ( empty( $n_file['dirname'] ) || empty( $n_file['filename'] ) ) { return $result; } $n_file['filename'] = wp_unique_filename( $n_file['dirname'], $n_file['filename'] . '.jpg' ); // Updated File name. $n_file = path_join( $n_file['dirname'], $n_file['filename'] ); $transparent_png = $this->settings->get_setting( WP_SMUSH_PREFIX . 'transparent_png' ); /** * Filter Background Color for Transparent PNGs */ $bg = apply_filters( 'wp_smush_bg', $transparent_png['background'], $id, $size ); $quality = $this->get_quality( $file ); if ( $this->supports_imagick() ) { try { $imagick = new Imagick( $file ); $imagick->setImageBackgroundColor( new ImagickPixel( '#' . $bg ) ); $imagick->setImageAlphaChannel( 11 ); $imagick->setImageFormat( 'JPG' ); $imagick->setCompressionQuality( $quality ); $imagick->writeImage( $n_file ); } catch ( Exception $e ) { error_log( 'WP Smush PNG to JPG Conversion error in ' . __FILE__ . ' at ' . __LINE__ . ' ' . $e->getMessage() ); return $result; } } else { // Use GD for conversion. // Get data from PNG. $input = imagecreatefrompng( $file ); // Width and Height of image. list( $width, $height ) = getimagesize( $file ); // Create New image. $output = imagecreatetruecolor( $width, $height ); // set background color for GD. $r = hexdec( '0x' . strtoupper( substr( $bg, 0, 2 ) ) ); $g = hexdec( '0x' . strtoupper( substr( $bg, 2, 2 ) ) ); $b = hexdec( '0x' . strtoupper( substr( $bg, 4, 2 ) ) ); // Set the Background color. $rgb = imagecolorallocate( $output, $r, $g, $b ); // Fill Background. imagefilledrectangle( $output, 0, 0, $width, $height, $rgb ); // Create New image. imagecopy( $output, $input, 0, 0, 0, 0, $width, $height ); // Create JPG. imagejpeg( $output, $n_file, $quality ); } // Replace file, and get savings. $result = $this->replace_file( $file, $result, $n_file ); if ( ! empty( $result['savings'] ) ) { if ( 'full' === $size ) { $result['converted'] = true; } // Update the File Details. and get updated meta. $result['meta'] = $this->update_image_path( $id, $file, $n_file, $meta, $size ); /** * Perform a action after the image URL is updated in post content */ do_action( 'wp_smush_image_url_changed', $id, $file, $n_file, $size ); } return $result; } /** * Get JPG quality from WordPress Image Editor * * @param string $file File. * * @return int Quality for JPEG images */ private function get_quality( $file ) { if ( empty( $file ) ) { return 82; } $editor = wp_get_image_editor( $file ); if ( ! is_wp_error( $editor ) ) { $quality = $editor->get_quality(); } // Choose the default quality if we didn't get it. if ( ! isset( $quality ) || $quality < 1 || $quality > 100 ) { // The default quality. $quality = 82; } return $quality; } /** * Check whether the given attachment was converted from PNG to JPG * * @param string $id Attachment ID. * * @return bool True/False Whether the image was converted from PNG or not */ public function is_converted( $id = '' ) { if ( empty( $id ) ) { return false; } // Get the original file path and check if it exists. $original_file = get_post_meta( $id, WP_SMUSH_PREFIX . 'original_file', true ); // If original file path is not stored, then it wasn't converted or was restored to original. if ( empty( $original_file ) ) { return false; } // Upload Directory. $upload_dir = wp_upload_dir(); // Upload Path. $upload_path = trailingslashit( $upload_dir['basedir'] ); // If file exists return true. if ( file_exists( path_join( $upload_path, $original_file ) ) ) { return true; } return false; } /** * Update Image URL in post content * * @param string $id Attachment ID. * @param string $size_k Image Size. * @param string $n_file New File Path which replaces the old file. * @param string $o_url URL to search for. */ private function update_image_url( $id, $size_k, $n_file, $o_url ) { if ( 'full' === $size_k ) { // Get the updated image URL. $n_url = wp_get_attachment_url( $id ); } else { $n_url = trailingslashit( dirname( $o_url ) ) . basename( $n_file ); } // Update In Post Content, Loop Over a set of posts to avoid the query failure for large sites. global $wpdb; // Get existing Images with current URL. $query = $wpdb->prepare( "SELECT ID, post_content FROM $wpdb->posts WHERE post_content LIKE '%%%s%%'", $o_url ); $rows = $wpdb->get_results( $query, ARRAY_A ); if ( empty( $rows ) || ! is_array( $rows ) ) { return; } // Iterate over rows to update post content. foreach ( $rows as $row ) { // replace old URLs with new URLs. $post_content = $row['post_content']; $post_content = str_replace( $o_url, $n_url, $post_content ); // Update Post content. $wpdb->update( $wpdb->posts, array( 'post_content' => $post_content, ), array( 'ID' => $row['ID'], ) ); clean_post_cache( $row['ID'] ); } } }