<?php
/* wppa-photo-files.php
*
* Functions used to create/manipulate photofiles
* Version 8.0.08.001
*
*/

if ( ! defined( 'ABSPATH' ) ) die( "Can't load this file directly" );

// Unfortunately there is no php function to rotate or resize an image file while the exif data is preserved.
// The origianal sourcefile is normally saved, to be available for download or hires uses e.g. in lightbox.
// The orientation of photos made by mobile devices is often non-standard ( 1 ), so we need a higres file,
// rotated and/or mirrored to the correct position.
// When the sourefile name is e.g.: .../wp-content/uploads/wppa-source/album-1/MyImage.jpg,
// We create the correct oriented file: .../wp-content/uploads/wppa-source/album-1/MyImage-o1.jpg. ( o1 stands for orientation=1 ).
// Note: wppa_get_source_path() should return the un-oriented file always, while wppa_get_hires_url() must return the -o1 file, if available.
function wppa_make_o1_source( $id ) {

	// Init
	$src_path = wppa_get_source_path( $id );

	// Source available?
	if ( ! is_file( $src_path ) ) return false;

	// Only needed for non-standard orientations
	$orient = wppa_get_exif_orientation( $src_path );
	if ( ! in_array( $orient, array( '2', '3', '4', '5', '6', '7', '8' ) ) ) return false;

	// Only on jpg file type
	$ext = wppa_get_ext( $src_path );
	if ( ! in_array( $ext, array( 'jpg', 'JPG', 'jpeg', 'JPEG' ) ) ) return false;

	// Make destination path
	$dst_path = wppa_get_o1_source_path( $id );

	// ImageMagick
	if ( wppa_can_magick() ) {
		wppa_image_magick( 'convert ' . $src_path . ' -auto-orient ' . $dst_path );
	}

	// Classic
	else {

		// Copy source to destination
		wppa_copy( $src_path, $dst_path );

		// Correct orientation
		if ( ! wppa_orientate_image_file( $dst_path, $orient ) ) {
			wppa_unlink( $dst_path );
			return false;
		}
	}

	// Done
	return true;
}

// Convert source file path to proper oriented source file path
function wppa_get_o1_source_path( $id ) {

	$src_path = wppa_get_source_path( $id );
	if ( $src_path ) {
		$src_path = wppa_strip_ext( $src_path ) . '-o1.' . wppa_get_ext( $src_path );
	}

	return $src_path;
}

// Rotate/mirror a photo display image by id
function wppa_orientate_image( $id, $ori ) {

	// If orientation right, do nothing
	if ( ! $ori || $ori == '1' ) {
		return;
	}

	wppa_orientate_image_file( wppa_get_photo_path( $id ), $ori );
	wppa_bump_photo_rev();
}

// Rotate/mirror an image file by pathname
function wppa_orientate_image_file( $file, $ori ) {

	// Validate args
	if ( ! is_file( $file ) ) {
		wppa_log( 'Err', 'File not found (wppa_orientate_image_file())' );
		return false;
	}
	if ( ! wppa_is_int( $ori ) || $ori < '2' || $ori > '8' ) {
		wppa_log( 'Err', 'Bad arg $ori:'.$ori.' (wppa_orientate_image_file())' );
		return false;
	}

	// Load image
	$source = wppa_imagecreatefromjpeg( $file );
	if ( ! $source ) {
		return false;
	}

	// Perform operation
	switch ( $ori ) {
		case '2':
			$orientate = $source;
			imageflip( $orientate, IMG_FLIP_HORIZONTAL );
			break;
		case '3':
			$orientate = imagerotate( $source, 180, 0 );
			break;
		case '4':
			$orientate = $source;
			imageflip( $orientate, IMG_FLIP_VERTICAL );
			break;
		case '5':
			$orientate = imagerotate( $source, 270, 0 );
			imageflip( $orientate, IMG_FLIP_HORIZONTAL );
			break;
		case '6':
			$orientate = imagerotate( $source, 270, 0 );
			break;
		case '7':
			$orientate = imagerotate( $source, 90, 0 );
			imageflip( $orientate, IMG_FLIP_HORIZONTAL );
			break;
		case '8':
			$orientate = imagerotate( $source, 90, 0 );
			break;
		default:
			break;
	}

	// Output
	wppa_imagejpeg( $orientate, $file, wppa_opt( 'jpeg_quality' ) );

	// Free the memory
	imagedestroy( $source );
	@ imagedestroy( $orientate );

	// Done
	return true;
}

// Make the display and thumbnails from a given pathname or upload temp image file.
// The id and extension must be supplied.
function wppa_make_the_photo_files( $file, $id, $ext, $do_thumb = true ) {
global $wpdb;
wppa_log('dbg', 'make called with'.$file.' '.$id.' '.$ext.' '.$do_thumb. ' exists=' . is_file($file), true);
	$thumb = wppa_cache_thumb( $id );

	$documentstub = WPPA_UPLOAD_PATH . '/documentstub.png';

	// If it is a pdf, check if the .jpg source exists, and change $file to the source .jpg
	if ( wppa_is_pdf( $id ) ) {

		$pdf = wppa_strip_ext( wppa_get_source_path( $id ) ) . '.pdf';
		$jpg = wppa_strip_ext( wppa_get_source_path( $id ) ) . '.jpg';
		$png = wppa_strip_ext( wppa_get_source_path( $id ) ) . '.png';

		if ( wppa_can_magick() ) {

			// Try making the jpg from the pdf
			wppa_image_magick( 'convert -density 150 ' . $pdf . '[0] -quality 90 -background white -alpha remove ' . $jpg );
			$err = ! wppa_is_file( $jpg );
			if ( ! $err ) {
				switch ( wppa_opt( 'newphoto_name_method' ) ) {
					case 'filename':
						$name = wppa_strip_ext( $thumb['filename'] ) . '.pdf';
						break;
					case 'noext':
						$name = wppa_strip_ext( $thumb['filename'] );
						break;
					case 'noextspace':
						$name = str_replace( '-', ' ', wppa_strip_ext( $thumb['filename'] ) );
						break;
					case 'Photo w#id':
						$name = 'Photo w#id';
						break;
					default:
						$name = '';
						break;
				}
// wppa_log('obs','method = '.wppa_opt( 'newphoto_name_method' ).', filename = '.$thumb['filename'].', name = '.$name);
				wppa_update_photo( array( 'id' => $id,
										  'ext' => 'jpg',
										  'name' => $name
										) );

				// Remove possible old stubfile
				if ( wppa_is_file( $png ) ) {
					wppa_unlink( $png );
				}

				// Remove possible old displayfile
				$disp = wppa_strip_ext( wppa_get_photo_path( $id ) ) . '.png';
				if ( wppa_is_file( $disp ) ) {
					wppa_unlink( $disp );
				}

				// Remove possible old thumbnailfile
				$disp = wppa_strip_ext( wppa_get_thumb_path( $id ) ) . '.png';
				if ( wppa_is_file( $disp ) ) {
					wppa_unlink( $disp );
				}
			}
		}

		// Find what we have to create display and thumbfiles
		// First look for jpg
		if ( wppa_is_file( $jpg ) ) {
			wppa_update_photo( array( 'id' => $id, 'ext' => 'jpg' ) );
			$file = $jpg;
			$ext = 'jpg';
		}
		// Then look for png
		elseif( wppa_is_file( $png ) ) {
			wppa_update_photo( array( 'id' => $id, 'ext' => 'png' ) );
			$file = $png;
			$ext = 'png';
		}
		// Last resort: use document stub
		else {
			wppa_copy( $documentstub, $png );
			wppa_update_photo( array( 'id' => $id, 'ext' => 'png' ) );
			$file = $png;
			$ext = 'png';
		}

		// Hoesekeeping
		clearstatcache();
		wppa_cache_thumb( 'invalidate', $id );
		$thumb = wppa_cache_thumb( $id );
	}

	$src_size = @getimagesize( $file, $info );

	// If the given file is not an image file, log error and exit
	if ( ! $src_size ) {
		if ( is_admin() ) wppa_error_message( sprintf( __( 'ERROR: File %s is not a valid picture file.' , 'wp-photo-album-plus'), htmlspecialchars( $file  ) ) );
		else wppa_alert( __( 'ERROR: File is not a valid picture file.', 'wp-photo-album-plus') );
		return false;
	}

	// Find output path photo file
	$newimage = wppa_get_photo_path( $id, false );
	if ( $ext ) {
		$newimage = wppa_strip_ext( $newimage ) . '.' . strtolower( $ext );
	}

	// Max sizes
	if ( wppa_opt( 'resize_to' ) == '0' ) {	// from fullsize
		$max_width 	= wppa_opt( 'fullsize' );
		$max_height = wppa_opt( 'maxheight' );
		$do_resize = true;
	}
	elseif ( wppa_opt( 'resize_to' ) == '-1' ) { // no resize
		$do_resize = false;
	}
	else {										// from selection
		$screen = explode( 'x', wppa_opt( 'resize_to' ) );
		$max_width 	= $screen[0];
		$max_height = $screen[1];
		$do_resize = true;
	}

	// If Resize on upload is checked
	if ( $do_resize && wppa_can_resize( $file, max( $max_width, $max_height ) ) ) {

		// ImageMagick
		if ( wppa_can_magick() ) {

			// If jpg, apply jpeg quality
			$q = wppa_opt( 'jpeg_quality' );
			$quality = '';
			if ( wppa_get_ext( $file ) == 'jpg' ) {
				$quality = '-quality ' . $q;
			}

			$iret = wppa_image_magick( 'convert ' . $file . ' ' . $quality . ' -resize ' . ( $thumb['stereo'] ? 2 * $max_width : $max_width ) . 'x' . $max_height . ' ' . $newimage );
			if ( $iret ) {
				wppa_log( 'fso', 'Magick could not create ' . $newimage );
			}
		}

		// Classic GD
		if ( ! wppa_can_magick() || ! is_file( $newimage ) ) {

			// Picture sizes
			$src_width 	= $src_size[0];

			// Temp convert to logical width if stereo
			if ( $thumb['stereo'] ) {
				$src_width /= 2;
			}
			$src_height = $src_size[1];

			// If orientation needs +/- 90 deg rotation, swap max x and max y
			$ori = wppa_get_exif_orientation( $file );
			if ( $ori >= 5 && $ori <= 8 ) {
				$t = $max_width;
				$max_width = $max_height;
				$max_height = $t;
			}

			// Is source more landscape or more portrait than max window
			if ( $src_width/$src_height > $max_width/$max_height ) {	// focus on width
				$focus = 'W';
				$need_downsize = ( $src_width > $max_width );
			}
			else {														// focus on height
				$focus = 'H';
				$need_downsize = ( $src_height > $max_height );
			}

			// Convert back to physical size
			if ( $thumb['stereo'] ) {
				$src_width *= 2;
			}

			// Downsize required ?
			if ( $need_downsize ) {

				// Find mime type
				$mime = $src_size[2];

				// Create the source image
				switch ( $mime ) {	// mime type
					case 1: // gif
						$temp = @ wppa_imagecreatefromgif( $file );
						if ( $temp ) {
							$src = imagecreatetruecolor( $src_width, $src_height );
							imagecopy( $src, $temp, 0, 0, 0, 0, $src_width, $src_height );
							imagedestroy( $temp );
						}
						else $src = false;
						break;
					case 2:	// jpeg
						if ( ! function_exists( 'imagecreatefromjpeg' ) ) {
							wppa_log( 'Error', 'Function imagecreatefromjpeg does not exist.' );
						}
						$src = @ wppa_imagecreatefromjpeg( $file );
						break;
					case 3:	// png
						$src = @ wppa_imagecreatefrompng( $file );
						break;
					default:
						wppa_log( 'err', 'Unimplemented mime type: ' . $mime . ' in wppa_make_the_photo_files()' );
						break;
				}

				if ( ! $src ) {
					return false;
				}

				// Create the ( empty ) destination image
				if ( $focus == 'W') {
					if ( $thumb['stereo'] ) $max_width *= 2;
					$dst_width 	= $max_width;
					$dst_height = round( $max_width * $src_height / $src_width );
				}
				else {
					$dst_height = $max_height;
					$dst_width = round( $max_height * $src_width / $src_height );
				}
				$dst = imagecreatetruecolor( $dst_width, $dst_height );

				// If Png, save transparancy
				if ( $mime == 3 ) {
					imagealphablending( $dst, false );
					imagesavealpha( $dst, true );
				}

				// Do the copy
				imagecopyresampled( $dst, $src, 0, 0, 0, 0, $dst_width, $dst_height, $src_width, $src_height );

				// Remove source image
				imagedestroy( $src );

				// Save the photo
				switch ( $mime ) {	// mime type
					case 1:
						wppa_imagegif( $dst, $newimage );
						break;
					case 2:
						wppa_imagejpeg( $dst, $newimage, wppa_opt( 'jpeg_quality' ) );
						break;
					case 3:
						wppa_imagepng( $dst, $newimage, 6 );
						break;
					default:
						wppa_log( 'err', sprintf( 'Unimplemented mime type %s encountered in wppa_create_thumbnail()', $mime ) );
				}

				// Remove destination image
				imagedestroy( $dst );

			}
			else {	// No downsize needed, picture is small enough
				wppa_copy( $file, $newimage );
			}
		}
//		wppa_log('dbg', 'Max memory used: ' . sprintf( '%6.2f MB', memory_get_peak_usage( true ) / ( 1024 * 1024 ) ) );
	}

	// No resize on upload checked or too big
	else {
		wppa_copy( $file, $newimage );
	}

	// These things do not exist in pdfs
	if ( ! wppa_is_pdf( $id ) ) {

		// Process the iptc data
		wppa_import_iptc( $id, $info );

		// Process the exif data
		wppa_import_exif( $id, $file );

		// GPS
		wppa_get_coordinates( $file, $id );

		// Set ( update ) exif date-time if available
		$exdt = wppa_get_exif_datetime( $file );
		if ( $exdt ) {
			wppa_update_photo( array( 'id' => $id, 'exifdtm' => $exdt ) );
		}

		// Check orientation
		wppa_orientate_image( $id, wppa_get_exif_orientation( $file ) );
	}

	// Compute and save sizes
	wppa_get_photox( $id, 'force' );

	// Show progression
	if ( is_admin() && ! wppa( 'ajax' ) ) echo( '.' );

	// Update CDN
	$cdn = wppa_cdn( 'admin' );
	if ( $cdn ) {
		switch ( $cdn ) {
			case 'cloudinary':
				wppa_upload_to_cloudinary( $id );
				break;
			case 'local':
				wppa_cdn_delete( $id ); // Remove existing local cdn files. They will be re-created automatically
				break;
			default:
				wppa_dbg_msg( 'Missing upload instructions for '.$cdn, 'red', 'force' );
		}
	}

	// Create stereo images
	wppa_create_stereo_images( $id );

	// Create thumbnail...
	if ( $do_thumb ) {
		wppa_create_thumbnail( $id );
	}

	// Reset sizes
	wppa_get_photox( $id, true );
	wppa_get_photoy( $id, true );
	wppa_get_thumbx( $id, true );
	wppa_get_thumby( $id, true );

	// Clear magickstack
	wppa_update_photo( array( 'id' => $id, 'magickstack' => '' ) );

	// Clear (super)cache
	wppa_clear_cache( array( 'photos' => true ) );
	return true;

}

// Create thubnail
function wppa_create_thumbnail( $id, $use_source = true ) {

	$locked = wppa_get_photo_item( $id, 'thumblock' );
	if ( $locked ) {
		return false;
	}

	$documentstub = WPPA_UPLOAD_PATH . '/documentstub.png';

	if ( $use_source && ! wppa_switch( 'watermark_thumbs' ) ) {

		// Try o1 source
		$file = wppa_get_o1_source_path( $id );

		// Try source path
		if ( ! wppa_is_file( $file ) || wppa_get_photo_item( $id, 'panorama' ) == '1' ) {
			$file = wppa_get_source_path( $id );
		}

		// Use photo path
		if ( ! wppa_is_file( $file ) ) {
			$file = wppa_get_photo_path( $id, false );
		}
	}

	// Not source requested
	else {
		$file = wppa_fix_poster_ext( wppa_get_photo_path( $id, false ), $id );
	}

	// If pdf, find image file
	if ( wppa_get_ext( $file ) == 'pdf' ) {
		$file = wppa_strip_ext( $file ) . '.' . wppa_get_photo_item( $id, 'ext' );

		// If no (poster) file exists, take the document-stub file
		if ( ! is_file( $file ) ) {
			$file = $documentstub;
			if ( is_file( $file ) ) {
				wppa_update_photo( array( 'id' => $id, 'ext' => 'png' ) );
			}
		}
	}

	// Max side
	$max_side = wppa_get_minisize();

	// Check file
	if ( ! wppa_is_file( $file ) ) return false;		// No file, fail
	$img_attr = getimagesize( $file );
	if ( ! $img_attr ) return false;				// Not an image, fail

	// Retrieve aspect
	$asp_attr = explode( ':', wppa_opt( 'thumb_aspect' ) );

	// Get output path
	$thumbpath = wppa_get_thumb_path( $id );

	// If already existing, save the filetime
	if ( wppa_is_file( $thumbpath ) ) {
		$thumbtime = wppa_filetime( $thumbpath );
	}
	else {
		$thumbtime = 0;
	}

	// Source size
	$src_size_w = $img_attr[0];
	$src_size_h = $img_attr[1];

	// Temp convert width if stereo
	if ( wppa_get_photo_item( $id, 'stereo' ) ) {
		$src_size_w /= 2;
	}

	// Mime type and thumb type
	$mime = $img_attr[2];
	$type = $asp_attr[2];

	// Source native aspect
	$src_asp = $src_size_h / $src_size_w;

	// Required aspect
	if ( $type == 'none' || ! $asp_attr[0] || ! $asp_attr[1] ) {
		$dst_asp = $src_asp;
	}
	else {
		$dst_asp = $asp_attr[0] / $asp_attr[1];
	}

	// Convert back width if stereo
	if ( wppa_get_photo_item( $id, 'stereo' ) ) {
		$src_size_w *= 2;
	}

	$done = false;

	// Enough memory?
	if ( wppa_can_resize( $file, $max_side ) ) {

		$frac = $max_side / max( $img_attr[0],$img_attr[1] );
		$perc = 100 * $frac;

		// Image Magick class?
		if ( false && class_exists( 'Imagick' ) && wppa_can_magick() && $type == 'none' ) {

			try {
				$im = new Imagick( $file );
				$im->thumbnailImage( $frac * $img_attr[0], $frac * $img_attr[1] );
				$iret = $im->writeImage( $thumbpath );
				$im->destroy();
			}
			catch (Exception $e) {
				wppa_log( 'err', 'Remake thumbnail raised exception: ',  $e->getMessage());
			}
			if ( $iret ) {
				wppa_log( 'fso', 'Magick class created ' . $thumbpath );
				$done = true;
			}
			else {
				wppa_log( 'fso', 'Magick class could not create ' . $thumbpath );
			}
		}

		// External Magick command?
		if ( ! $done && wppa_can_magick() && $type == 'none' ) {

			$cmd = 'convert ' . $file . ' -thumbnail ' . $perc . '% ' . $thumbpath;
			$iret = wppa_image_magick( $cmd );
			if ( $iret ) {
				wppa_log( 'fso', 'Magick command could not create ' . $thumbpath );
			}
			else {
				wppa_log( 'fso', 'Magick command created ' . $thumbpath );
				$done = true;
			}
		}

		// Classic GD
		if ( ! $done ) {

			// Create the source image
			switch ( $mime ) {	// mime type
				case 1: // gif
					$temp = @ wppa_imagecreatefromgif( $file );
					if ( $temp ) {
						$src = imagecreatetruecolor( $src_size_w, $src_size_h );
						imagecopy( $src, $temp, 0, 0, 0, 0, $src_size_w, $src_size_h );
						imagedestroy( $temp );
					}
					else $src = false;
					break;
				case 2:	// jpeg
					if ( ! function_exists( 'imagecreatefromjpeg' ) ) wppa_log( 'Error', 'Function imagecreatefromjpeg does not exist.' );
					$src = @ wppa_imagecreatefromjpeg( $file );
					break;
				case 3:	// png
					$src = @ wppa_imagecreatefrompng( $file );
					break;
				default:
					$src = null;
					break;
			}
			if ( ! $src ) {
				wppa_log( 'Error', 'Image file ' . $file . ' is corrupt while creating thmbnail' );
				return true;
			}

			// Compute the destination image size
			if ( $dst_asp < 1.0 ) {	// Landscape
				$dst_size_w = $max_side;
				$dst_size_h = round( $max_side * $dst_asp );
			}
			else {					// Portrait
				$dst_size_w = round( $max_side / $dst_asp );
				$dst_size_h = $max_side;
			}

			// Create the ( empty ) destination image
			$dst = imagecreatetruecolor( $dst_size_w, $dst_size_h );
			if ( $mime == 3 ) {	// Png, save transparancy
				imagealphablending( $dst, false );
				imagesavealpha( $dst, true );
			}

			// Fill with the required color
			$c = trim( strtolower( wppa_opt( 'bgcolor_thumbnail' ) ) );
			if ( $c != '#000000' ) {
				$r = hexdec( substr( $c, 1, 2 ) );
				$g = hexdec( substr( $c, 3, 2 ) );
				$b = hexdec( substr( $c, 5, 2 ) );
				$color = imagecolorallocate( $dst, $r, $g, $b );
				if ( $color === false ) {
					wppa_log( 'Err', 'Unable to set background color to: '.$r.', '.$g.', '.$b.' in wppa_create_thumbnail' );
				}
				else {
					imagefilledrectangle( $dst, 0, 0, $dst_size_w, $dst_size_h, $color );
				}
			}

			// Switch on what we have to do
			switch ( $type ) {
				case 'none':	// Use aspect from fullsize image
					$src_x = 0;
					$src_y = 0;
					$src_w = $src_size_w;
					$src_h = $src_size_h;
					$dst_x = 0;
					$dst_y = 0;
					$dst_w = $dst_size_w;
					$dst_h = $dst_size_h;
					break;
				case 'clip':	// Clip image to given aspect ratio
					if ( $src_asp < $dst_asp ) {	// Source image more landscape than destination
						$dst_x = 0;
						$dst_y = 0;
						$dst_w = $dst_size_w;
						$dst_h = $dst_size_h;
						$src_x = round( ( $src_size_w - $src_size_h / $dst_asp ) / 2 );
						$src_y = 0;
						$src_w = round( $src_size_h / $dst_asp );
						$src_h = $src_size_h;
					}
					else {
						$dst_x = 0;
						$dst_y = 0;
						$dst_w = $dst_size_w;
						$dst_h = $dst_size_h;
						$src_x = 0;
						$src_y = round( ( $src_size_h - $src_size_w * $dst_asp ) / 2 );
						$src_w = $src_size_w;
						$src_h = round( $src_size_w * $dst_asp );
					}
					break;
				case 'padd':	// Padd image to given aspect ratio
					if ( $src_asp < $dst_asp ) {	// Source image more landscape than destination
						$dst_x = 0;
						$dst_y = round( ( $dst_size_h - $dst_size_w * $src_asp ) / 2 );
						$dst_w = $dst_size_w;
						$dst_h = round( $dst_size_w * $src_asp );
						$src_x = 0;
						$src_y = 0;
						$src_w = $src_size_w;
						$src_h = $src_size_h;
					}
					else {
						$dst_x = round( ( $dst_size_w - $dst_size_h / $src_asp ) / 2 );
						$dst_y = 0;
						$dst_w = round( $dst_size_h / $src_asp );
						$dst_h = $dst_size_h;
						$src_x = 0;
						$src_y = 0;
						$src_w = $src_size_w;
						$src_h = $src_size_h;
					}
					break;
				default:		// Not implemented
					return false;
			}

			// Copy left half if stereo
			if ( wppa_get_photo_item( $id, 'stereo' ) ) {
				$src_w /= 2;
			}

			// Do the copy
			imagecopyresampled( $dst, $src, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h );

			// Save the thumb
			$thumbpath = wppa_strip_ext( $thumbpath );
			switch ( $mime ) {	// mime type
				case 1:
					$full_thumbpath = $thumbpath . '.gif';
					wppa_imagegif( $dst, $full_thumbpath );
					break;
				case 2:
					$full_thumbpath = $thumbpath . '.jpg';
					wppa_imagejpeg( $dst, $full_thumbpath, wppa_opt( 'jpeg_quality' ) );
					break;
				case 3:
					$full_thumbpath = $thumbpath . '.png';
					wppa_imagepng( $dst, $full_thumbpath, 6 );
					break;
				default:
					wppa_log( 'err', sprintf( 'Unimplemented mime type %s encountered in wppa_create_thumbnail()', $mime ) );
			}
			$thumbpath = $full_thumbpath;

			wppa_log( 'fso', 'GD created ' . $thumbpath );
			$done = true;

			// Cleanup
			imagedestroy( $src );
			imagedestroy( $dst );
		}
	}

	// Too litlle memory
	if ( ! $done ) {
		wppa_copy( $file, $thumbpath );
	}

	// Compute and save sizes
	wppa_get_thumbx( $id, 'force' );	// forces recalc x and y

	// Invalidate cache
	wppa_cache_thumb( 'invalidate', $id );

	// If existing file not updated, return false
	if ( wppa_is_file( $thumbpath ) ) {
		$newtime = wppa_filetime( $thumbpath );
	}
	if ( $newtime == $thumbtime ) {
		return false;
	}
	return true;
}

// See if ImageMagick command exists
function wppa_is_magick( $command ) {
	if ( ! $command ) {
		return false;
	}
	if ( ! wppa_can_magick() ) {
		return false;
	}
	return is_file( rtrim( wppa_opt( 'image_magick' ), '/' ) . '/' . $command );
}

// Process ImageMagick command
function wppa_image_magick( $command ) {

	// Image magic enabled?
	if ( ! wppa_can_magick() ) {
		return '-9';
	}

	// Image Magick root dir
	$path = rtrim( wppa_opt( 'image_magick' ), '/' ) . '/';

	// Try to prepend 'magick' to the command if its not already there.
	// This is for forward compatibility, e.g. when 'magick' exists but 'convert' not.
	if ( wppa_is_magick( 'magick' ) && substr( $command, 0, 6 ) != 'magick' ) {
		$command = 'magick ' . $command;
	}
	$out  = array();
	$err  = 0;

	try {
		$run  = exec( escapeshellcmd( $path . $command ), $out, $err );
	}
	catch (Exception $e) {
		wppa_log( 'err', 'Exec imagick cmd raised exception: ',  $e->getMessage());
	}

	$logcom = $command;
	$logcom = str_replace( ABSPATH, '...', $logcom );
	$logcom = str_replace( wppa_opt( 'image_magick' ), '...', $logcom );

	wppa_log( 'Fso', 'Exec ' . $logcom . ' return status: ' . $err . ', last output line: ' . $run );
	foreach( $out as $line ) {
//		wppa_log( 'OBS', $line );
	}

	if ( $err == '46' ) $err = '0';
	return $err;
}

// Convert .png's to .jpg's
//
// @1: photo id (integer) or pathname (string)
function wppa_convert_png_to_jpg( $arg ) {
global $wpdb;

	// Photo id given
	if ( is_numeric( $arg ) ) {

		// Does photo exist?
		$photo = wppa_cache_photo( $arg );
		if ( ! $photo ) {
			wppa_log( 'Err', 'Non existent photo: ' . $arg . ' in wppa_convert_png_to_jpg()' );
			return false;
		}
		$id 	= $photo['id'];
		$ext 	= wppa_get_photo_item( $id, 'ext' );
		$alb 	= wppa_get_photo_item( $id, 'album' );

		// Is it a photo with extension .png, or a multimedia or pdf with possible png posterfile?
		if ( strtolower( $ext ) == 'png' || wppa_is_multi( $id ) || wppa_is_pdf( $id ) ) {

			// Convert files
			wppa_convert_png_to_jpg( wppa_get_source_path( $id ) );
			wppa_convert_png_to_jpg( wppa_get_o1_source_path( $id ) );
			wppa_convert_png_to_jpg( wppa_get_photo_path( $id ) );
			wppa_convert_png_to_jpg( wppa_get_thumb_path( $id ) );

			// Fix local CDN files
			$cdn_files = wppa_cdn_files( $id );
			foreach( $cdn_files as $file ) {
				wppa_convert_png_to_jpg( $file );
			}

			// Make new filename
			if ( strpos( $photo['filename'], '.' ) ) {

				// Do not change filename for PDF, VIDEO and AUDIO
				if ( wppa_is_pdf( $id ) || wppa_is_multi( $id ) ) {
					$new_filename = $photo['filename'];
				}
				else {
					$new_filename = wppa_strip_ext( $photo['filename'] ) . '.jpg';
				}
			}
			else {
				$new_filename = $photo['filename'] . '.jpg';
			}

			// Make new ext, do not chnage for VIDEO and AUDIO
			if ( $ext == 'xxx' ) {
				$new_ext = $ext;
			}
			else {
				$new_ext = 'jpg';
			}

			// Update DB
			$wpdb->query( "UPDATE $wpdb->wppa_photos SET ext = '$new_ext', filename = '$new_filename' WHERE id = $id" );

			// Done!
			wppa_log( 'obs', 'Converted possible .png files from item ' . $id . ' to .jpg' );
		}

		// Nothing to convert
		else {
			return false;
		}
	}

	// Is it a filepath with .png extension?
	elseif ( strtolower( wppa_get_ext( $arg ) ) == 'png' ) {
		$file 	= $arg;
		if ( ! wppa_is_file( $file ) ) {
			return false;
		}

		// Process the file
		$img = wppa_imagecreatefrompng( $file );
		if ( $img ) {
			$newfile = wppa_strip_ext( $file ) . '.jpg';
			if ( wppa_imagejpeg( $img, $newfile, wppa_opt( 'jpeg_quality' ) ) ) {
				wppa_unlink( $file );
				wppa_log( 'Fso', "Converted $file to $newfile" );
				return true;
			}
		}
		else {
			wppa_log( 'Err', 'Invalid .png file found in wppa_convert_png_to_jpg(): ' . $file );
			return false;
		}
	}

	// No, its not a .png file
	else {
		return false;
	}
}