/home/arranoyd/magicraft/wp-content/plugins/wp-smushit/lib/class-wp-smush-png_jpg.php
<?php
/**
* @package WP Smush
*
* @version 2.4
*
* @author Umesh Kumar <umesh@incsub.com>
*
* @copyright (c) 2016, Incsub (http://incsub.com)
*/
if ( ! class_exists( 'WpSmushPngtoJpg' ) ) {
class WpSmushPngtoJpg {
var $is_transparent = false;
/**
* Check if Imagick is available or not
*
* @return bool True/False Whether Imagick is available or not
*
*/
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
*
*/
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
*
* @return bool|int
*/
function is_transparent( $id = '', $file = '' ) {
global $wpsmush_helper;
//No attachment id/ file path, return
if ( empty( $id ) && empty( $file ) ) {
return false;
}
if ( empty( $file ) ) {
$file = $wpsmush_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 $id Attachment ID
* @param $file File path for the attachment
*
* @return bool Whether to convert the PNG or not
*
*/
function should_convert( $id, $file ) {
global $wpsmush_settings;
$should_convert = false;
//Get the Transparency conversion settings
$convert_png = $wpsmush_settings->get_setting( WP_SMUSH_PREFIX . 'png_to_jpg', false );
if ( ! $convert_png ) {
return $should_convert;
}
//Whether to convert transparent images or not
$transparent_settings = $wpsmush_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 transaprent images, skip is transparent check
if ( $convert_transparent || !$this->is_transparent ) {
$should_convert = true;
}
return $should_convert;
}
/**
* Check if given attachment id can be converted to JPEG or not
*
* @param string $id Atachment id
*
* @param string $id
* @param string $size
* @param string $mime
* @param string $file
*
* @return bool True/False Can be converted or not
*/
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 ) {
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
global $wpsmushit_admin, $wpsmush_helper;
if ( 'full' != $size && $wpsmushit_admin->skip_image_size( $size ) ) {
return false;
}
if ( empty( $file ) ) {
$file = $wpsmush_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 $id Attachment ID
* @param $o_file Original File Path that has to be replaced
* @param $n_file New File Path which replaces the old file
* @param $meta Attachment Meta
* @param $size_k Image Size
* @param $o_type Operation Type "conversion", "restore"
*
* @return mixed Attachment Meta with updated file path
*
*/
function update_image_path( $id, $o_file, $n_file, $meta, $size_k, $o_type = 'conversion' ) {
global $wpsmush_settings;
//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;
//Get the File mime
if ( class_exists( 'finfo' ) ) {
$finfo = new finfo( FILEINFO_MIME_TYPE );
} else {
$finfo = false;
}
if ( $finfo ) {
$mime = file_exists( $n_file_path ) ? $finfo->file( $n_file_path ) : '';
} elseif ( function_exists( 'mime_content_type' ) ) {
$mime = mime_content_type( $n_file_path );
} else {
$mime = false;
}
//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;
}
if ( 'full' == $size_k ) {
//Get the updated image URL
$n_url = wp_get_attachment_url( $id );
} else {
$n_url = dirname( $o_url ) . '/' . basename( $n_file );
}
//Update In Post Content
global $wpdb;
$query = $wpdb->prepare( "UPDATE $wpdb->posts SET post_content = REPLACE(post_content, '%s', '%s');", $o_url, $n_url );
$wpdb->query( $query );
//Delete the Original files if backup not enabled
if ( 'conversion' == $o_type && ! $wpsmush_settings->get_setting( WP_SMUSH_PREFIX . 'backup' ) ) {
@unlink( $o_file );
}
return $meta;
}
function update_stats( $id = '', $savings = '' ) {
if ( empty( $id ) || empty( $savings ) ) {
return false;
}
}
/**
* 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
*/
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 $id Attachment Id
* @param $file Attachment File path
* @param $meta Attachment meta
* @param $size Image size, default empty for full image
*
* @return array $result array(
* 'meta' => array Update Attachment metadata
* 'savings' => Reduction of Image size in bytes
* )
*
*/
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
* @param string $meta
*
* @uses WpSmushBackup::add_to_image_backup_sizes()
*
* @return mixed|string
*/
function png_to_jpg( $id = '', $meta = '' ) {
global $wpsmush_backup;
//If we don't have meta or ID
if ( empty( $id ) || empty( $meta ) ) {
return $meta;
}
global $wpsmush_helper;
$file = $wpsmush_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 );
$wpsmush_backup->add_to_image_backup_sizes( $id, $o_file, 'smush_png_path' );
/**
* 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
*/
function convert_tpng_to_jpg( $id = '', $file = '', $meta = '', $size = 'full' ) {
global $wpsmush_settings;
$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 = $wpsmush_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 $file
*
* @return int Quality for JPEG images
*
*/
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 quaity if we didn't get it
if ( ! $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
*
* @return bool True/False Whether the image was converted from PNG or not
*
*/
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;
}
}
global $wpsmush_pngjpg;
$wpsmush_pngjpg = new WpSmushPngtoJpg();
}