";
}
add_action('post-flash-upload-ui', 'scissors_post_upload_ui');
add_action('post-html-upload-ui', 'scissors_post_upload_ui');
// Manual cropping and resizing functionality ---------------------------------
function scissors_admin_head()
{
if(strstr($_SERVER['REQUEST_URI'], 'media'))
{
global $scissors_dirname;
wp_enqueue_script('scissors_crop', '/' . PLUGINDIR . '/'.$scissors_dirname.'/js/jquery.Jcrop.js', array('jquery') );
wp_enqueue_script('scissors_js', '/' . PLUGINDIR . '/'.$scissors_dirname.'/js/scissors.js' );
$thisUrl = admin_url('admin-ajax.php');
echo "\n";
echo "\n";
echo "\n";
}
}
function scissors_styles()
{
global $scissors_dirname;
wp_register_style('jcrop_style', '/' .PLUGINDIR . "/$scissors_dirname/css/jquery.Jcrop.css");
wp_register_style('scissors_style', '/' .PLUGINDIR . "/$scissors_dirname/css/scissors.css");
wp_enqueue_style('jcrop_style');
wp_enqueue_style('scissors_style');
wp_enqueue_style('thickbox');
}
function gcd($a, $b)
{
if ($a == 0 || $b == 0)
return 0;
else if ($a == $b)
return $a;
else
{
do
{
$r = $a % $b;
$a = $b; $b = $r;
} while($r != 0);
return $a;
}
}
function scissors_media_meta($string, $post)
{
$errstr = "";
if(!scissors_supports_imagetype($post->post_mime_type))
$errstr = sprintf(__('Failed to load image. Image type %s not supported.', 'scissors'), $post->post_mime_type);
{
$postId = $post->ID;
$filename = get_attached_file($postId);
if(!$filename || !file_exists($filename))
$errstr = __('Failed to load image. File not found.', 'scissors');
else
{
list($width, $height) = getimagesize($filename);
if($width <= 0 || $height <= 0)
$errstr = __('Failed to load image. Invalid image dimensions.', 'scissors');
}
}
if($errstr != "")
{
$string .= "\n\t\t
";
$string .= " | ";
$string .= "";
$cropTargets = "";
$aspectMode = get_option('scissors_crop_defaultaspect');
$aspectChecked = ($aspectMode != 2) ? "checked='checked'" : "";
if($aspectMode == 1)
{
$aspectX = intval(get_option('scissors_crop_useraspectx'));
$aspectY = intval(get_option('scissors_crop_useraspecty'));
}
if($aspectMode != 1 || $aspectX <= 0 || $aspectY <= 0)
{
$aspectX = $width; $aspectY = $height;
while(($g = gcd($aspectX, $aspectY)) > 1)
{
$aspectX = intval($aspectX / $g);
$aspectY = intval($aspectY / $g);
}
}
$cropAspect = ":";
$cropAspect .= "";
$reirChecked = get_option('scissors_crop_defaultreir') ? "checked='checked'" : "";
$string .= "";
$string .= sprintf($text_crop2, $cropTargets);
$string .= " ";
$string .= " ";
$string .= " ";
$string .= " ";
$string .= " ";
$string .= "";
$string .= " ";
$string .= sprintf($text_crop3, $cropAspect);
$string .= " ";
$string .= " ";
$string .= " ";
$fields = " × ";
$fields .= "";
$string .= "";
$string .= sprintf(__('Resize to %s pixels.', 'scissors'), $fields);
$string .= " ";
$string .= " ";
$string .= "";
$string .= "";
$string .= "";
$string .= "";
$string .= "";
$string .= " ";
$text_rotate2 = __('Rotate by', 'scissors');
$text_left90 = __('90 degrees left', 'scissors');
$text_right90 = __('90 degrees right', 'scissors');
$text_180 = __('180 degrees', 'scissors');
if(function_exists('imagerotate'))
{
$string .= "";
$string .= "$text_rotate2 .";
$string .= " ";
$string .= " ";
$string .= " ";
}
$string .= "";
$wstate = scissors_get_watermarking_state($postId);
$string .= "";
$sizes = (is_array($metadata) && isset($metadata['sizes']) && count($metadata['sizes']) > 0) ? array_keys($metadata['sizes']) : array();
$sizes[] = 'full'; $sizes[] = 'custom';
foreach($sizes as $size)
{
$checked = scissors_is_watermarking_enabled($size, $postId, TRUE) ? "checked" : "";
$string .= " ";
}
$string .= " ";
$string .= " ";
$string .= " ";
$string .= "";
}
return $string;
}
function scissors_image_make_intermediate_size($file, $width, $height, $crop=false, $adaptive=false)
{
if($adaptive == '1')
{
$fullsize = getimagesize($file);
$width = ($fullsize[0] >= $fullsize[1]) ? $width : 0;
$height = ($fullsize[1] >= $fullsize[0]) ? $height : 0;
}
$intermediate_result = image_make_intermediate_size($file, $width, $height, $crop);
if(!$intermediate_result)
{
// simply use the specified file as the new intermediate albeit with smaller dimensions
$suffix = "{$width}x{$height}";
$info = pathinfo($file);
$dir = $info['dirname'];
$ext = $info['extension'];
$name = basename($file, ".{$ext}");
$destfilename = "{$dir}/{$name}-{$suffix}.{$ext}";
copy($file, $destfilename);
list($realW, $realH) = getimagesize($file);
$intermediate_result = array('file' => basename($destfilename), 'width' => $realW, 'height' => $realH);
}
return $intermediate_result;
}
function scissors_has_thumbnail($metadata)
{
return is_array($metadata) && isset($metadata['sizes']) && count($metadata['sizes']) > 0 &&
isset($metadata['sizes']['thumbnail']) && isset($metadata['sizes']['thumbnail']);
}
function scissors_crop($post, $srcfile, $src)
{
$x = intval($_POST['x']); $y = intval($_POST['y']);
$w = intval($_POST['w']); $h = intval($_POST['h']);
if($x >= 0 && $y >= 0 && $w > 0 && $h > 0)
{
$fullfile = get_attached_file($post->ID);
if($_POST['target'] == 'chain' || $_POST['target'] == 'full')
$dstfile = $fullfile;
else if($intermediate = image_get_intermediate_size($post->ID, $_POST['target']))
$dstfile = tempnam(dirname($fullfile), 'scissors');
else
return __('Invalid target.', 'scissors');
// TODO: respect auto-size settings for full-sized image? cropping is no problem, but rotation ...
$dst = scissors_create_image($w, $h);
if(is_resource($dst))
{
if(imagecopy($dst, $src, 0, 0, $x, $y, $w, $h))
{
if(scissors_save_image($dst, $dstfile, $post->post_mime_type))
{
if($dstfile == $fullfile)
scissors_rebuild_watermark_meta($dst, $post->post_mime_type, $post->ID);
$metadata = wp_get_attachment_metadata($post->ID);
if($_POST['target'] == 'chain' || $_POST['target'] == 'full')
{
// update meta data for the full-size image
$metadata['width'] = $w; $metadata['height'] = $h;
list($uwidth, $uheight) = wp_shrink_dimensions($metadata['width'], $metadata['height']);
$metadata['hwstring_small'] = "height='$uheight' width='$uwidth'";
$msg = "done;full,{$w},{$h}"; // signal change of the full-size image
if(!scissors_has_thumbnail($metadata)) $msg .= "+thumbnail,{$w},{$h}"; // full size image is used as thumbnail, force GUI updated
// update existing intermediate images if requested
if($_POST['target'] == 'chain' && is_array($metadata) && isset($metadata['sizes']) && count($metadata['sizes']) > 0)
{
foreach($metadata['sizes'] as $size => $data)
{
$srcfile = $fullfile;
$w2 = get_option("{$size}_size_w");
$h2 = get_option("{$size}_size_h");
if($_POST['reir'] == '1')
{
$fx = $w2 / $w; $fy = $h2 / $h;
$factor = sqrt($fx > $fy ? $fx : $fy);
$cw = ceil($w * $factor); $ch = ceil($h * $factor);
if($cw != $w || $ch != $h)
{
$cx = floor(($w - $cw) / 2); $cy = floor(($h - $ch) / 2);
$interfile = tempnam(dirname($fullfile), 'scissors');
// crop $fullfile to ($cx,$cy) [$cw,$ch] and store to $interfile
$tmp = scissors_create_image($cw, $ch);
if(is_resource($tmp))
{
if(imagecopy($tmp, $dst, 0, 0, $cx, $cy, $cw, $ch))
{
if(scissors_save_image($tmp, $interfile, $post->post_mime_type))
$srcfile = $interfile;
}
imagedestroy($tmp);
}
if($srcfile != $interfile)
unlink($interfile);
}
}
$resized = scissors_image_make_intermediate_size($srcfile, $w2, $h2, get_option("{$size}_crop"), get_option("{$size}_adaptive"));
if($resized)
{
$oldfile = path_join(dirname($fullfile), $data['file']);
if($resized['file'] != $data['file'])
{
// overwrite the old file with the newly created image
$resizedfile = path_join(dirname($srcfile), $resized['file']);
copy($resizedfile, $oldfile);
unlink($resizedfile);
$resized['file'] = $data['file'];
}
$metadata['sizes'][$size] = $resized;
$msg .= "+$size," . $resized['width'] . ',' . $resized['height']; // signal change
if(scissors_is_watermarking_enabled($size, $post->ID, TRUE))
scissors_watermark_file($oldfile);
}
if($srcfile != $fullfile)
unlink($srcfile); // clean up reir temporary
}
}
wp_update_attachment_metadata($post->ID, $metadata);
if(scissors_is_watermarking_enabled('full', $post->ID, TRUE))
scissors_watermark_file($dstfile);
}
else
{
$size = $_POST['target'];
$resized = scissors_image_make_intermediate_size($dstfile, get_option("{$size}_size_w"), get_option("{$size}_size_h"), get_option("{$size}_crop"), get_option("{$size}_adaptive"));
if($resized)
{
// overwrite the specified destination
$resizedfile = path_join(dirname($dstfile), $resized['file']);
$oldfile = path_join(dirname($fullfile), $intermediate['file']);
if(copy($resizedfile, $oldfile))
{
$resized['file'] = $intermediate['file'];
$metadata['sizes'][$size] = $resized;
$msg = "done;$size," . $resized['width'] . ',' . $resized['height']; // signal change
if(scissors_is_watermarking_enabled($size, $post->ID, TRUE))
scissors_watermark_file($oldfile);
}
else
$msg = __('Failed to save new image.', 'scissors');
unlink($resizedfile);
}
else
$msg = __('Failed to save new image.', 'scissors');
wp_update_attachment_metadata($post->ID, $metadata);
}
}
else
$msg = __('Failed to save new image.', 'scissors');
}
else
$msg = __('Failed to crop image.', 'scissors');
imagedestroy($dst);
}
else
$msg = __('Failed to allocate memory.', 'scissors');
// cleanup temporary file
if($intermediate)
unlink($dstfile);
return $msg;
}
else
return __('Invalid selection.', 'scissors');
}
function scissors_resize($post, $filename, $src)
{
$w = intval($_POST['width']); $h = intval($_POST['height']);
if($w > 0 && $h > 0)
{
$srcW = imagesx($src); $srcH = imagesy($src);
if($w != $srcW || $h != $srcH)
{
$dst = scissors_create_image($w, $h);
if(is_resource($dst))
{
if(imagecopyresampled($dst, $src, 0, 0, 0, 0, $w, $h, $srcW, $srcH))
{
scissors_rebuild_watermark_meta($dst, $post->post_mime_type, $post->ID);
if(scissors_is_watermarking_enabled('full', $post->ID, TRUE))
scissors_watermark_image($dst);
if(scissors_save_image($dst, $filename, $post->post_mime_type))
{
// update meta data, no need to rebuild intermediate images because the aspect ratio always stays the same
$metadata = wp_get_attachment_metadata($post->ID);
$metadata['width'] = $w; $metadata['height'] = $h;
list($uwidth, $uheight) = wp_shrink_dimensions($metadata['width'], $metadata['height']);
$metadata['hwstring_small'] = "height='$uheight' width='$uwidth'";
wp_update_attachment_metadata($post->ID, $metadata);
$msg = "done;full,{$w},{$h}"; // signal change of the full-size image
if(!scissors_has_thumbnail($metadata)) $msg .= "+thumbnail,{$w},{$h}"; // full size image is used as thumbnail, force GUI updated
}
else
$msg = __('Failed to save new image.', 'scissors');
}
else
$msg = __('Failed to resize image.', 'scissors');
imagedestroy($dst);
return $msg;
}
else
return __('Failed to allocate memory.', 'scissors');
}
else
return 'done;*'; // signal no change
}
else
return __('Invalid destination dimensions.', 'scissors');
}
function scissors_per_image_watermarks($post, $srcfile, $src)
{
scissors_set_watermarking_state($post->ID, $_POST['state']);
// reuse the cropping functionality to rebuild the image chain with/without watermarking
// TODO: this does a lot more work than what is necessary ... OPTIMIZE ME!
$_POST['x'] = 0; $_POST['y'] = 0;
$_POST['w'] = imagesx($src); $_POST['h'] = imagesy($src);
$_POST['target'] = 'chain'; $_POST['reir'] = 0;
return scissors_crop($post, $srcfile, $src);
}
function scissors_rotate($post, $srcfile, $src)
{
$angle = intval($_POST['angle']);
switch($angle)
{
case -90: case 90: case 180: $rotated = imagerotate($src, $angle, 0); break;
default: return __('Invalid query.', 'scissors');
}
// reuse the cropping functionality to rebuild the image chain after rotation
$_POST['x'] = 0; $_POST['y'] = 0;
$_POST['w'] = imagesx($rotated); $_POST['h'] = imagesy($rotated);
$_POST['target'] = 'chain'; $_POST['reir'] = 0;
return scissors_crop($post, $srcfile, $rotated);
}
function scissors_action()
{
$postId = intval($_POST['post_id']); // perform security checks
if (wp_verify_nonce($_POST['_wpnonce'], "scissors-$postId") && current_user_can('upload_files'))
{
// retrieve post data and load the full-size image
$post = get_post($postId);
$filename = get_attached_file($postId);
if($post && $filename && file_exists($filename))
{
scissors_set_memory_limit();
$src = scissors_load_image($filename, $post->post_mime_type); // load the source image
if(is_resource($src))
{
// if the full image contains a watermark we have to remove it first ...
scissors_remove_watermark($src, $postId);
if($_POST['action'] == 'scissorsCrop')
$msg = scissors_crop($post, $filename, $src);
else if($_POST['action'] == 'scissorsResize')
$msg = scissors_resize($post, $filename, $src);
else if($_POST['action'] == 'scissorsRotate')
$msg = scissors_rotate($post, $filename, $src);
else if($_POST['action'] == 'scissorsWatermark')
$msg = scissors_per_image_watermarks($post, $filename, $src);
else
$msg = __('Invalid query.', 'scissors');
imagedestroy($src);
}
else
$msg = __('Failed to load image.', 'scissors');
}
else
$msg = __('Invalid post-id.', 'scissors');
}
else
$msg = __('Unauthorized query.', 'scissors');
die($msg);
}
add_filter('media_meta', 'scissors_media_meta', 99, 2);
add_action('admin_print_scripts', 'scissors_admin_head');
add_action('admin_print_styles', 'scissors_styles');
add_action('wp_ajax_scissorsCrop', 'scissors_action');
add_action('wp_ajax_scissorsResize', 'scissors_action');
add_action('wp_ajax_scissorsRotate', 'scissors_action');
add_action('wp_ajax_scissorsWatermark', 'scissors_action');
// On-the-fly image resampling functionality ----------------------------------
class Scissors
{
function Scissors()
{
add_filter('mce_external_plugins', array(&$this, 'mce_external_plugins'));
add_filter('content_save_pre', array(&$this, 'content_save_pre'));
add_action('save_post', array(&$this, 'save_post'));
add_action('delete_post', array(&$this, 'delete_post'));
global $wp_version;
if(version_compare($wp_version, '2.8', '>='))
add_action('delete_attachment', array(&$this, 'delete_attachment'));
else
{
// NOTE: We cannot use the delete_attachment-action because at the time it is invoked the metadata
// associated with the attachment is already gone.
add_filter('wp_delete_file', array(&$this, 'wp_delete_file'));
}
}
function mce_external_plugins($plugins)
{
$plugins['scissors'] = plugins_url('/scissors/mce/editor_plugin.js');
return $plugins;
}
function _getImagePostIdFromUrl($url)
{
$wud = wp_upload_dir(); // remove the base url
$url = str_replace($wud['baseurl'] . '/', '', $url);
// remove -(width)x(height) and -custom
if(preg_match('!(-[0-9]+x[0-9]+(-custom)?)([^/\\\]+)$!', $url, $match) == 1)
$url = str_replace($match[1], '', $url);
global $wpdb;
$post = $wpdb->get_row($wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_value = %s LIMIT 1", $url));
return ($post != null) ? $post->post_id : FALSE;
}
function _createResampledImage($imgurl, $destWidth, $destHeight)
{
$retval = FALSE;
$postId = $this->_getImagePostIdFromUrl($imgurl);
if($postId != FALSE)
{
// retrieve post data and load the full-size image
$post = get_post($postId);
$filename = get_attached_file($postId);
if($post && $filename && file_exists($filename))
{
$url = wp_get_attachment_url($postId);
list($fullWidth, $fullHeight) = getimagesize($filename);
if($destWidth < $fullWidth || $destHeight < $fullHeight)
{
$path_parts = pathinfo($filename);
$sansext = substr($path_parts['basename'], 0, -(strlen($path_parts['extension']) + 1)); // +1 for the dot
$path_parts['basename'] = "{$sansext}-{$destWidth}x{$destHeight}-custom." . $path_parts['extension'];
$url = str_replace(basename($url), $path_parts['basename'], $url);
$destfilename = $path_parts["dirname"] . '/' . $path_parts['basename'];
if(!file_exists($destfilename))
{
scissors_set_memory_limit();
$src = scissors_load_image($filename, $post->post_mime_type); // load the source image
if(is_resource($src))
{
$dst = scissors_create_image($destWidth, $destHeight);
if(is_resource($dst))
{
// if the full image contains a watermark we have to remove it first ...
scissors_remove_watermark($src, $postId);
if(imagecopyresampled($dst, $src, 0, 0, 0, 0, $destWidth, $destHeight, imagesx($src), imagesy($src)))
{
// add the watermark to the resampled image
if(scissors_is_watermarking_enabled('custom', $postId, TRUE))
scissors_watermark_image($dst);
if(scissors_save_image($dst, $destfilename, $post->post_mime_type))
{
$key = basename($url);
add_post_meta($postId, "_scissors_custom_images", array(), true); // initialize if non-existant
$meta = get_post_meta($postId, '_scissors_custom_images', true);
$meta[$key] = array('ref' => '');
update_post_meta($postId, "_scissors_custom_images", $meta);
$retval = $url;
}
}
imagedestroy($dst);
}
imagedestroy($src);
}
}
else
$retval = $url;
}
else
$retval = $url;
}
}
return $retval;
}
function content_save_pre($content)
{
// find images with class 'scissors-resample' and resample the image to the specified size
$pattern = '!(<)img[^>]+class=\\\"[^">]*scissors-resample[^">]*\\\"[^>]*(>)!is';
$count = preg_match_all($pattern, $content, $matches, PREG_OFFSET_CAPTURE | PREG_PATTERN_ORDER);
if($count > 0)
{
$newcontent = ''; $last = 0;
for($i = 0; $i < $count; $i++)
{
$tagStart = $matches[1][$i][1]; $tagEnd = $matches[2][$i][1];
$newcontent .= substr($content, $last, $tagStart - $last); // append the content up to the tag
$last = $tagEnd + 1; // skip over the tag itself
$tag = substr($content, $tagStart, $tagEnd - $tagStart + 1);
$tag = str_replace('scissors-resample', '', str_replace(' scissors-resample', '', $tag)); // remove the class
$width = -1; $height = -1; $url = '';
if(preg_match('!width=\\\"([0-9]+)\\\"!is', $tag, $widthmatch) == 1)
$width = ($widthmatch[1]);
if(preg_match('!height=\\\"([0-9]+)\\\"!is', $tag, $heightmatch) == 1)
$height = ($heightmatch[1]);
if(preg_match('!src=\\\"([^">]*)\\\"!is', $tag, $urlmatch, PREG_OFFSET_CAPTURE) == 1)
$url = $urlmatch[1][0];
if($width > 0 && $height > 0 && $url != '')
{
$newurl = $this->_createResampledImage($url, $width, $height);
if($newurl != FALSE)
$tag = str_replace($url, $newurl, $tag);
}
$newcontent .= $tag; // append the modified tag
}
$newcontent .= substr($content, $last);
return $newcontent;
}
else
return $content;
}
function _deleteReferenceToCustomImage($imgPostId, $key, $postId)
{
$meta = get_post_meta($imgPostId, '_scissors_custom_images', true);
if($meta != FALSE)
{
if(strstr($meta[$key]['ref'], "[$postId]") != FALSE)
{
$meta[$key]['ref'] = str_replace("[$postId]", '', $meta[$key]['ref']);
if($meta[$key]['ref'] == '')
{
$filename = get_attached_file($imgPostId);
$filename = str_replace(basename($filename), $key, $filename);
@unlink($filename);
unset($meta[$key]);
}
if(count($meta) > 0)
update_post_meta($imgPostId, "_scissors_custom_images", $meta);
else
delete_post_meta($imgPostId, "_scissors_custom_images");
}
}
}
function save_post($postId)
{
$post = get_post($postId);
$newimglist = array();
// find references to custom images
$pattern = '! ]+src="([^">]+-[0-9]+x[0-9]+-custom[^">/\\\]+)"[^>]*>!is';
$count = preg_match_all($pattern, $post->post_content, $matches, PREG_PATTERN_ORDER);
foreach($matches[1] as $url)
{
$imgPostId = $this->_getImagePostIdFromUrl($url);
if($imgPostId != FALSE)
{
$meta = get_post_meta($imgPostId, '_scissors_custom_images', true);
if($meta != FALSE)
{
$key = basename($url);
$newimglist[] = "$imgPostId:$key";
if(strstr($meta[$key]['ref'], "[$postId]") == FALSE)
{
$meta[$key]['ref'] .= "[$postId]";
update_post_meta($imgPostId, "_scissors_custom_images", $meta);
}
}
}
}
$newimglist = array_unique($newimglist);
// if this post gets edited, make sure to remove references to images
// that are no longer present in the new version
$oldimglist = get_post_meta($postId, '_scissors_custom_images', true);
if(is_array($oldimglist))
{
$oldimglist = array_diff($oldimglist, $newimglist);
foreach($oldimglist as $elem)
{
list($imgPostId, $key) = explode(':', $elem);
$this->_deleteReferenceToCustomImage($imgPostId, $key, $postId);
}
}
if(count($newimglist) > 0)
{
add_post_meta($postId, "_scissors_custom_images", $newimglist, true) or
update_post_meta($postId, "_scissors_custom_images", $newimglist);
}
else
delete_post_meta($postId, "_scissors_custom_images");
}
function delete_post($postId)
{
$post = get_post($postId);
// find references to custom images
$pattern = '! ]+src="([^">]+-[0-9]+x[0-9]+-custom[^">/\\\]+)"[^>]*>!is';
$count = preg_match_all($pattern, $post->post_content, $matches, PREG_PATTERN_ORDER);
foreach($matches[1] as $url)
{
$imgPostId = $this->_getImagePostIdFromUrl($url);
if($imgPostId != FALSE)
{
$key = basename($url);
$this->_deleteReferenceToCustomImage($imgPostId, $key, $postId);
}
}
}
function delete_attachment($postId) // proper semantics in WP >= 2.8
{
$meta = get_post_meta($postId, '_scissors_custom_images', true);
if($meta != FALSE)
{
$filename = get_attached_file($postId);
$path_parts = pathinfo($filename);
foreach($meta as $key => $value)
@unlink($path_parts["dirname"] . '/' . $key);
}
}
function wp_delete_file($filename)
{
if(file_exists($filename))
{
$path_parts = pathinfo($filename);
$sansext = substr($path_parts['basename'], 0, -(strlen($path_parts['extension']) + 1)); // +1 for the dot
$pattern = '!' . preg_quote($sansext) . '-[0-9]+x[0-9]+-custom' . preg_quote('.' . $path_parts['extension']) . '$!';
$dir = opendir($path_parts['dirname']);
while($file = readdir($dir))
{
if(preg_match($pattern, $file) == 1)
@unlink($path_parts['dirname'] . '/' . $file);
}
closedir($dir);
}
return $filename;
}
}
$ScissorsInstance = new Scissors();
} // integration check end
?>
|