t('Imagecrop'),
'path' => 'admin/settings/imagecrop',
'callback' => 'drupal_get_form',
'callback arguments' => 'imagecrop_settings',
'access' => $access_settings,
);
$items[] = array(
'path' => 'imagecrop/window',
'callback' => 'imagecrop_window',
'type' => MENU_CALLBACK,
'access' => $access_crop,
);
$items[] = array(
'path' => 'imagecrop/result',
'callback' => 'imagecrop_result',
'type' => MENU_CALLBACK,
'access' => $access_crop,
);
}
return $items;
}
/**
* Imagecrop settings page
*/
function imagecrop_settings() {
// hook into image module
if (module_exists('image')) {
$options_modules['image'] = t('Hook into image module');
}
// hook into imagefield module
if (module_exists('imagefield')) {
$res = db_query("SELECT field_name,label FROM {node_field_instance} WHERE widget_type = 'image'");
while ($row = db_fetch_object($res)){
$options_fields[$row->field_name] = t('Hook into imagefield %s',array('%s' => $row->label));
}
}
// show checkboxes if options are not empty
if (!empty($options_modules) || !empty($options_fields)) {
if (!empty($options_modules)) {
$form['imagecrop_modules'] = array(
'#type' => 'checkboxes',
'#title' => t('Hook into modules'),
'#default_value' => variable_get('imagecrop_modules',array()),
'#options' => $options_modules,
);
}
if (!empty($options_fields)) {
$form['imagecrop_fields'] = array(
'#type' => 'checkboxes',
'#title' => t('Hook into cck fields'),
'#default_value' => variable_get('imagecrop_fields',array()),
'#options' => $options_fields,
);
}
$form['array_filter'] = array('#type' => 'hidden');
} else {
$form['no_modules_fields'] = array(
'#type' => 'item',
'#value' => t('No modules or fields are found to hook into'),
);
}
// drupal message if no action is found with javascript_crop
if (imagecrop_action_exists() == false) {
drupal_set_message(t('No preset is found with the javascript_crop action so far. If you want to take advantage of this module, you will need to create at least one preset with that action.'));
}
return system_settings_form($form);
}
/**
* Implementation of hook_cron().
* Delete all references in imagecrop table when
* a) file doesn't exist anymore.
* b) when preset has been deleted.
* c) when javascrip_crop action is removed from a preset.
*/
function imagecrop_cron() {
// get all files which do not exist anymore.
$result = db_query("select fid,presetid from {imagecrop} ic where not exists (select fid from {files} f where ic.fid = f.fid)");
while ($row = db_fetch_object($result)) {
$records[] = array('fid' => $row->fid, 'presetid' => $row->presetid);
}
// get all records from presets which do not exist anymore.
// @todo look for presets which have lost the javascript_crop action
// I'll have to lookup some to see if I can find this in one query or do another one
$result = db_query("select ic.fid,ic.presetid from {imagecrop} ic where not exists (select presetid from {imagecache_action} ia where ic.presetid = ia.presetid)");
while ($row = db_fetch_object($result)) {
$records[] = array('fid' => $row->fid, 'presetid' => $row->presetid);
}
if (!empty($records)) {
while (list($key,$val) = each($records)) {
db_query("DELETE FROM {imagecrop} WHERE fid=%d AND presetid=%d",$val['fid'],$val['presetid']);
}
}
}
/**
* Implementation of hook_imagecache_actions().
*/
function imagecrop_imagecache_actions() {
$actions = array(
'imagecrop_javascript' => array(
'name' => 'Javascript crop',
'description' => 'Create a crop with a javascript toolbox.',
'file' => 'imagecrop_actions.inc',
),
);
return $actions;
}
/**
* Helper function to check if a preset exists with the imagecrop_javascript action.
* Needed to determine if we have to display our javascript crop link.
*
* @return true or false
*/
function imagecrop_action_exists() {
$result = db_result(db_query("SELECT actionid FROM {imagecache_action} WHERE action = 'imagecrop_javascript'"));
return $result;
}
/**
* Implementation of hook_form_alter().
*
* Hook into several existing image upload modules
* @todo what todo with temporary uploads (ie in imagefield)
*/
function imagecrop_form_alter($form_id,&$form) {
// do we have presets with javascript_crop ?
$exists = imagecrop_action_exists();
// user access
$access = user_access('crop images with toolbox');
// build array with available modules/fields
$modules = variable_get('imagecrop_modules',array());
$fields = variable_get('imagecrop_fields',array());
$hooks = array_merge($modules,$fields);
// hook into imagefield module
// @todo handle multiple values per field
if (module_exists('imagefield') && $exists != false && $access) {
$formfield = imagecrop_find_imagefields($form,$fields);
if ($formfield != false) {
$count = count($formfield);
for($i=0;$i<$count;$i++) {
imagecrop_formitem($form,$form[$formfield[$i]][0]['fid']['#value'],'field_image');
}
}
}
// hook into image module
if (module_exists('image') && $exists != false && $access && in_array('image',$hooks) && isset($form['images']['thumbnail'])) {
// it's anonying we have to make a database call to get the right fid.
$fid = db_result(db_query("SELECT fid FROM {files} WHERE nid=%d AND filename = '_original' AND filepath='%s'",$form['nid']['#value'],$form['images']['_original']['#default_value']));
imagecrop_formitem($form,$fid,'images');
}
}
/**
* Helper function to add form item
*
* @return $form form markup
*/
function imagecrop_formitem(&$form,$fid,$fieldname) {
$form[$fieldname]['crop_tab'] = array(
'#type' => 'item',
'#value' => 'Javascript crop',
);
return $form;
}
/**
* Helper function to search for a cck field image
*
* @param $form complete form object
* @param $fields all available fields from settings
* @return ckk imagefields array or false
*/
function imagecrop_find_imagefields($form,$fields) {
$count = count($fields);
$return = false;
for($i=0;$i<$count;$i++){
if (isset($form[$fields[$i]])) {
$return[] = $fields[$i];
}
}
return $return;
}
/**
* Popup window with picture.
*
* @param $fid id of file
* @param $presetid id of preset
*/
function imagecrop_window($fid,$presetid = 0) {
if (imagecrop_action_exists() == true) {
$presets = return_presets($presetid);
$presetid = $presets['presetid'];
$file = return_object($fid,$presetid);
if($file != false) {
// get size of temporary image
$size = getimagesize($file->dst);
$width = $size[0];
$height = $size[1];
// return warning message if crop toolbox is too big and not resizable.
if (($width < $file->crop_width || $height < $file->crop_height) && $file->resizable == 0) {
return t('The crop toolbox is too big for this image.');
}
// add javascript and css
jquery_interface_add();
imagecrop_markup(true,true);
// output
$url = url($file->dst);
$output = theme('presettabs',$presets,$fid,$presetid);
$output .= theme('imagecrop',$url,$width,$height,$file->resizable);
$output .= drupal_get_form('imageoffsets',$file->xoffset,$file->yoffset,$file->crop_width,$file->crop_height,$presetid,$fid);
return $output;
} else {
return '
'.t('Image to crop was not found.').'
';
}
} else {
return ''.t('No preset is found with the javascript_crop action so far. If you want to take advantage of this module, you will need to create at least one preset with that action.').'
';
}
}
/**
* Callback to return offsets, height & width
*
* @param $xoffset x value of javascript box
* @param $yoffset y value of javascript box
* @param $crop_width width of javascript box
* @param $crop_height height of javascript box
* @param $presetid id of preset
* @param $fid id of file
* @return array $form
*/
function imageoffsets($xoffset,$yoffset,$crop_width,$crop_height,$presetid,$fid) {
$form['image-crop-x'] = array('#type' => 'hidden','#default_value' => $xoffset,'#attributes' => array('class' => 'edit-image-crop-x'));
$form['image-crop-y'] = array('#type' => 'hidden','#default_value' => $yoffset,'#attributes' => array('class' => 'edit-image-crop-y'));
$form['image-crop-width'] = array('#type' => 'hidden','#default_value' => $crop_width,'#attributes' => array('class' => 'edit-image-crop-width'));
$form['image-crop-height'] = array('#type' => 'hidden','#default_value' => $crop_height,'#attributes' => array('class' => 'edit-image-crop-height'));
$form['submit'] = array('#type' => 'submit', '#value' => t('Create crop'));
$form['fid'] = array('#type' => 'hidden','#value' => $fid);
$form['presetid'] = array('#type' => 'hidden','#value' => $presetid);
return $form;
}
/**
* Save the offset & size values
*
* @param $form_id id of the form
* @param $form_values submitted values of the imageoffsets form
*/
function imageoffsets_submit($form_id,$form_values) {
db_query("DELETE FROM {imagecrop} WHERE fid=%d AND presetid=%d",$form_values['fid'],$form_values['presetid']);
db_query("INSERT INTO {imagecrop} VALUES (%d,%d,%d,%d,%d,%d)",$form_values['fid'],$form_values['presetid'],$form_values['image-crop-x'],$form_values['image-crop-y'],$form_values['image-crop-width'],$form_values['image-crop-height']);
drupal_goto('imagecrop/result/'.$form_values['fid'].'/'.$form_values['presetid']);
}
/**
* Show the crop result
*
* @param $fid file id
* @param $presetid id of preset
* @return cropped result of chosen image
*/
function imagecrop_result($fid,$presetid) {
if (imagecrop_action_exists() == true) {
$file = return_object($fid,$presetid,TRUE);
$presets = return_presets($presetid);
imagecrop_markup(false,true);
$output = theme('presettabs',$presets,$fid,$presetid);
$output .= theme('imagecache', $file->presetname, $file->filepath);
$output .= 'Imagecache Theme function: '.htmlentities("theme('imagecache', '$file->presetname', '$file->filepath'');").'
';
$output .= ''.l(t('Return to crop'),'imagecrop/window/'.$fid.'/'.$presetid).'
';
return $output;
} else {
return ''.t('No preset is found with the javascript_crop action so far. If you want to take advantage of this module, you will need to create at least one preset with that action.').'
';
}
}
/**
* Helper function to determine which preset exists and which to load
*
* @param $presetid id of preset
* @return $presets array with presetid to load and list of all other possible presets
*/
function return_presets($presetid){
$result = db_query("SELECT ip.presetid, ip.presetname FROM {imagecache_preset} ip INNER JOIN {imagecache_action} ia on ia.presetid = ip.presetid WHERE action = 'imagecrop_javascript' ORDER by ip.presetname ASC");
while($row = db_fetch_object($result)) {
$presets['tabs'][] = array('id' => $row->presetid, 'name' => $row->presetname);
}
if (!empty($presetid)) $presets['presetid'] = $presetid;
else $presets['presetid'] = $presets['tabs'][0]['id'];
return $presets;
}
/**
* Helper function to create temporary image and return file object
*
* @param $fid file id in files table
* @param $presetid id of the preset
* @param $cutoff delete the javascript crop action when user wants to define the offsets
* @return $file with file, javascript crop and preset properties
*/
function return_object($fid,$presetid,$cutoff = false) {
$file = _imagecrop_file_load($fid);
if ($file != false) {
$preset = imagecache_preset($presetid);
imagecache_image_flush($file->filename);
if ($cutoff == false) {
// get the actions from the preset and and throw out the javascript_crop action
// and every other action which comes after it.
$actions_count = count($preset['actions']);
while(list($key,$val) = each($preset['actions'])){
if ($val['action'] == 'imagecrop_javascript') {
$crop_width = $preset['actions'][$key]['data']['width'];
$crop_height = $preset['actions'][$key]['data']['height'];
$resizable = $preset['actions'][$key]['data']['resizable'];
unset($preset['actions'][$key]);
// stop the loop, we don't need anything after this
break;
}
}
// see if we have stored values allready for this file
$file->xoffset = 0;
$file->yoffset = 0;
$file->crop_width = $crop_width;
$file->crop_height = $crop_height;
$row = db_fetch_object(db_query("SELECT xoffset,yoffset,width,height FROM {imagecrop} ic where ic.fid = %d AND ic.presetid = %d",$fid,$presetid));
if (!empty($row)) {
$file->xoffset = $row->xoffset;
$file->yoffset = $row->yoffset;
$file->crop_width = $row->width;
$file->crop_height = $row->height;
}
// resizable or not
$file->resizable = $resizable;
}
$src = $file->filepath;
$file->presetname = $preset['presetname'];
$dst = imagecache_create_path($preset['presetname'], $file->filepath);
$file->dst = $dst;
// create the file to either display for the crop or the result
imagecache_build_derivative($preset, $src, $dst);
return $file;
} else return false;
}
/**
* Helper function to load a file into an object
*
* @param $fid file id
* @return $file with properties of the file or false
*/
function _imagecrop_file_load($fid) {
$result = db_query('SELECT * FROM {files} WHERE fid = %d', $fid);
$file = db_fetch_object($result);
if ($file) {
// make sure it's an image. Any other mime extensions possible?
// return false if it's not the right mime type
$filemime = array('image/jpeg','image/gif','image/png');
if (!in_array($file->filemime,$filemime)) return false;
// access denied if current user hasn't enough permissions
// @todo test this!
$node = node_load($file->nid);
if (!user_access('administer nodes') && !user_access('edit '.$node->type) && !user_access('edit own '.$node->type)) {
drupal_access_denied();
exit();
}
// all seems ok, return file
return $file;
}
// return false if no file was found.
return false;
}
/**
* Theme image crop.
*
* @param $url url of image
* @param $width width of image
* @param $height height of image
* @param $resize wether the cropping box is resizeble or not
* @return $output html of the javascript crop area
*/
function theme_imagecrop($url,$width,$height,$resize = 0) {
$output = '
';
if ($resize == 1) {
$output .= '
';
}
$output .= '
';
$output .= 'Use the selector to choose your crop area.
';
return $output;
}
/**
* Theme preset tabs
*
* @param $tabs array of available presets
* @param fid file id
* @param $presetid preset to highlight
* @return $output html of the tabs
*/
function theme_presettabs($presets,$fid,$presetid) {
$tab_output = '';
foreach($presets['tabs'] as $key => $value) {
$class = ($value['id'] == $presetid) ? 'imagecrop_tab imagecrop_highlight' : 'imagecrop_tab ';
$tab_output .= ''.l($value['name'],'imagecrop/window/'.$fid.'/'.$value['id']).'';
}
$output = ''.$tab_output.'
';
return $output;
}
/**
* Add imagecrop css & javascript
*/
function imagecrop_markup($js,$css) {
$path = drupal_get_path('module', 'imagecrop');
if ($js == true) drupal_add_js($path.'/imagecrop.js');
if ($css == true) drupal_add_css($path.'/imagecrop.css');
}