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'); }