/[drupal]/contributions/modules/imagecrop/imagecrop.module
ViewVC logotype

Contents of /contributions/modules/imagecrop/imagecrop.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (show annotations) (download) (as text)
Mon Mar 24 16:29:28 2008 UTC (20 months ago) by swentel
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-5, DRUPAL-6--1
File MIME type: text/x-php
Initial import of imagecrop. This module provides an extra imagecache action called javascript_crop and hooks into modules or fields to manipulate images with a javascript toolbox
1 <?php
2
3 /**
4 * @file imagecrop
5 * Provides a javascript toolbox through an imagecache action.
6 *
7 * @todo hook into more modules (gallery, img_filter, attachments, assets, ulink)
8 * @todo onclose window handler to warn user or another way to clean up temporary imagecache actions
9 *
10 * @todo Cool feature: add complete files directory browser with filter - with extra permission
11 * Load it via other file.
12 *
13 * @author Kristof De Jaeger - http://drupal.org/user/107403 - http://realize.be
14 * @version this is the drupal 5.x version
15 */
16
17 /**
18 * Implementation of hook_perm().
19 */
20 function imagecrop_perm(){
21 return array('crop images with toolbox','crop images in filebrowser','administer imagecrop');
22 }
23
24 /**
25 * Implementation of hook_menu().
26 */
27 function imagecrop_menu($may_cache){
28 $items = array();
29 $access_crop = user_access('crop images with toolbox');
30 $access_settings = user_access('administer imagecrop');
31 if ($may_cache) {
32 $items[] = array(
33 'title' => t('Imagecrop'),
34 'path' => 'admin/settings/imagecrop',
35 'callback' => 'drupal_get_form',
36 'callback arguments' => 'imagecrop_settings',
37 'access' => $access_settings,
38 );
39 $items[] = array(
40 'path' => 'imagecrop/window',
41 'callback' => 'imagecrop_window',
42 'type' => MENU_CALLBACK,
43 'access' => $access_crop,
44 );
45 $items[] = array(
46 'path' => 'imagecrop/result',
47 'callback' => 'imagecrop_result',
48 'type' => MENU_CALLBACK,
49 'access' => $access_crop,
50 );
51 }
52 return $items;
53 }
54
55 /**
56 * Imagecrop settings page
57 */
58 function imagecrop_settings() {
59 // hook into image module
60 if (module_exists('image')) {
61 $options_modules['image'] = t('Hook into image module');
62 }
63 // hook into imagefield module
64 if (module_exists('imagefield')) {
65 $res = db_query("SELECT field_name,label FROM {node_field_instance} WHERE widget_type = 'image'");
66 while ($row = db_fetch_object($res)){
67 $options_fields[$row->field_name] = t('Hook into imagefield %s',array('%s' => $row->label));
68 }
69 }
70 // show checkboxes if options are not empty
71 if (!empty($options_modules) || !empty($options_fields)) {
72 if (!empty($options_modules)) {
73 $form['imagecrop_modules'] = array(
74 '#type' => 'checkboxes',
75 '#title' => t('Hook into modules'),
76 '#default_value' => variable_get('imagecrop_modules',array()),
77 '#options' => $options_modules,
78 );
79 }
80 if (!empty($options_fields)) {
81 $form['imagecrop_fields'] = array(
82 '#type' => 'checkboxes',
83 '#title' => t('Hook into cck fields'),
84 '#default_value' => variable_get('imagecrop_fields',array()),
85 '#options' => $options_fields,
86 );
87 }
88 $form['array_filter'] = array('#type' => 'hidden');
89 } else {
90 $form['no_modules_fields'] = array(
91 '#type' => 'item',
92 '#value' => t('No modules or fields are found to hook into'),
93 );
94 }
95 // drupal message if no action is found with javascript_crop
96 if (imagecrop_action_exists() == false) {
97 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.'));
98 }
99 return system_settings_form($form);
100 }
101
102 /**
103 * Implementation of hook_cron().
104 * Delete all references in imagecrop table when
105 * a) file doesn't exist anymore.
106 * b) when preset has been deleted.
107 * c) when javascrip_crop action is removed from a preset.
108 */
109 function imagecrop_cron() {
110 // get all files which do not exist anymore.
111 $result = db_query("select fid,presetid from {imagecrop} ic where not exists (select fid from {files} f where ic.fid = f.fid)");
112 while ($row = db_fetch_object($result)) {
113 $records[] = array('fid' => $row->fid, 'presetid' => $row->presetid);
114 }
115 // get all records from presets which do not exist anymore.
116 // @todo look for presets which have lost the javascript_crop action
117 // I'll have to lookup some to see if I can find this in one query or do another one
118 $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)");
119 while ($row = db_fetch_object($result)) {
120 $records[] = array('fid' => $row->fid, 'presetid' => $row->presetid);
121 }
122 if (!empty($records)) {
123 while (list($key,$val) = each($records)) {
124 db_query("DELETE FROM {imagecrop} WHERE fid=%d AND presetid=%d",$val['fid'],$val['presetid']);
125 }
126 }
127 }
128
129 /**
130 * Implementation of hook_imagecache_actions().
131 */
132 function imagecrop_imagecache_actions() {
133 $actions = array(
134 'imagecrop_javascript' => array(
135 'name' => 'Javascript crop',
136 'description' => 'Create a crop with a javascript toolbox.',
137 'file' => 'imagecrop_actions.inc',
138 ),
139 );
140 return $actions;
141 }
142
143 /**
144 * Helper function to check if a preset exists with the imagecrop_javascript action.
145 * Needed to determine if we have to display our javascript crop link.
146 *
147 * @return true or false
148 */
149 function imagecrop_action_exists() {
150 $result = db_result(db_query("SELECT actionid FROM {imagecache_action} WHERE action = 'imagecrop_javascript'"));
151 return $result;
152 }
153
154 /**
155 * Implementation of hook_form_alter().
156 *
157 * Hook into several existing image upload modules
158 * @todo what todo with temporary uploads (ie in imagefield)
159 */
160 function imagecrop_form_alter($form_id,&$form) {
161 // do we have presets with javascript_crop ?
162 $exists = imagecrop_action_exists();
163 // user access
164 $access = user_access('crop images with toolbox');
165 // build array with available modules/fields
166 $modules = variable_get('imagecrop_modules',array());
167 $fields = variable_get('imagecrop_fields',array());
168 $hooks = array_merge($modules,$fields);
169
170 // hook into imagefield module
171 // @todo handle multiple values per field
172 if (module_exists('imagefield') && $exists != false && $access) {
173 $formfield = imagecrop_find_imagefields($form,$fields);
174 if ($formfield != false) {
175 $count = count($formfield);
176 for($i=0;$i<$count;$i++) {
177 imagecrop_formitem($form,$form[$formfield[$i]][0]['fid']['#value'],'field_image');
178 }
179 }
180 }
181
182 // hook into image module
183 if (module_exists('image') && $exists != false && $access && in_array('image',$hooks) && isset($form['images']['thumbnail'])) {
184 // it's anonying we have to make a database call to get the right fid.
185 $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']));
186 imagecrop_formitem($form,$fid,'images');
187 }
188 }
189
190 /**
191 * Helper function to add form item
192 *
193 * @return $form form markup
194 */
195 function imagecrop_formitem(&$form,$fid,$fieldname) {
196 $form[$fieldname]['crop_tab'] = array(
197 '#type' => 'item',
198 '#value' => '<a href="javascript:;" onclick="window.open(\''.$GLOBALS['base_url'].url('imagecrop/window/'.$fid).'\',\'imagecrop\',\'menubar=0,resizable=1,width=700,height=650\');">Javascript crop</a>',
199 );
200 return $form;
201 }
202
203 /**
204 * Helper function to search for a cck field image
205 *
206 * @param $form complete form object
207 * @param $fields all available fields from settings
208 * @return ckk imagefields array or false
209 */
210 function imagecrop_find_imagefields($form,$fields) {
211 $count = count($fields);
212 $return = false;
213 for($i=0;$i<$count;$i++){
214 if (isset($form[$fields[$i]])) {
215 $return[] = $fields[$i];
216 }
217 }
218 return $return;
219 }
220
221 /**
222 * Popup window with picture.
223 *
224 * @param $fid id of file
225 * @param $presetid id of preset
226 */
227 function imagecrop_window($fid,$presetid = 0) {
228 if (imagecrop_action_exists() == true) {
229 $presets = return_presets($presetid);
230 $presetid = $presets['presetid'];
231 $file = return_object($fid,$presetid);
232 if($file != false) {
233
234 // get size of temporary image
235 $size = getimagesize($file->dst);
236 $width = $size[0];
237 $height = $size[1];
238 // return warning message if crop toolbox is too big and not resizable.
239 if (($width < $file->crop_width || $height < $file->crop_height) && $file->resizable == 0) {
240 return t('The crop toolbox is too big for this image.');
241 }
242
243 // add javascript and css
244 jquery_interface_add();
245 imagecrop_markup(true,true);
246
247 // output
248 $url = url($file->dst);
249 $output = theme('presettabs',$presets,$fid,$presetid);
250 $output .= theme('imagecrop',$url,$width,$height,$file->resizable);
251 $output .= drupal_get_form('imageoffsets',$file->xoffset,$file->yoffset,$file->crop_width,$file->crop_height,$presetid,$fid);
252 return $output;
253
254 } else {
255 return '<div>'.t('Image to crop was not found.').'</div>';
256 }
257 } else {
258 return '<div>'.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.').'</div>';
259 }
260 }
261
262 /**
263 * Callback to return offsets, height & width
264 *
265 * @param $xoffset x value of javascript box
266 * @param $yoffset y value of javascript box
267 * @param $crop_width width of javascript box
268 * @param $crop_height height of javascript box
269 * @param $presetid id of preset
270 * @param $fid id of file
271 * @return array $form
272 */
273 function imageoffsets($xoffset,$yoffset,$crop_width,$crop_height,$presetid,$fid) {
274 $form['image-crop-x'] = array('#type' => 'hidden','#default_value' => $xoffset,'#attributes' => array('class' => 'edit-image-crop-x'));
275 $form['image-crop-y'] = array('#type' => 'hidden','#default_value' => $yoffset,'#attributes' => array('class' => 'edit-image-crop-y'));
276 $form['image-crop-width'] = array('#type' => 'hidden','#default_value' => $crop_width,'#attributes' => array('class' => 'edit-image-crop-width'));
277 $form['image-crop-height'] = array('#type' => 'hidden','#default_value' => $crop_height,'#attributes' => array('class' => 'edit-image-crop-height'));
278 $form['submit'] = array('#type' => 'submit', '#value' => t('Create crop'));
279 $form['fid'] = array('#type' => 'hidden','#value' => $fid);
280 $form['presetid'] = array('#type' => 'hidden','#value' => $presetid);
281 return $form;
282 }
283
284 /**
285 * Save the offset & size values
286 *
287 * @param $form_id id of the form
288 * @param $form_values submitted values of the imageoffsets form
289 */
290 function imageoffsets_submit($form_id,$form_values) {
291 db_query("DELETE FROM {imagecrop} WHERE fid=%d AND presetid=%d",$form_values['fid'],$form_values['presetid']);
292 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']);
293 drupal_goto('imagecrop/result/'.$form_values['fid'].'/'.$form_values['presetid']);
294 }
295
296
297 /**
298 * Show the crop result
299 *
300 * @param $fid file id
301 * @param $presetid id of preset
302 * @return cropped result of chosen image
303 */
304 function imagecrop_result($fid,$presetid) {
305 if (imagecrop_action_exists() == true) {
306 $file = return_object($fid,$presetid,TRUE);
307 $presets = return_presets($presetid);
308 imagecrop_markup(false,true);
309 $output = theme('presettabs',$presets,$fid,$presetid);
310 $output .= theme('imagecache', $file->presetname, $file->filepath);
311 $output .= '<div>Imagecache Theme function: '.htmlentities("theme('imagecache', '$file->presetname', '$file->filepath'');").'</div>';
312 $output .= '<div>'.l(t('Return to crop'),'imagecrop/window/'.$fid.'/'.$presetid).'</div>';
313 return $output;
314 } else {
315 return '<div>'.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.').'</div>';
316 }
317 }
318
319 /**
320 * Helper function to determine which preset exists and which to load
321 *
322 * @param $presetid id of preset
323 * @return $presets array with presetid to load and list of all other possible presets
324 */
325 function return_presets($presetid){
326 $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");
327 while($row = db_fetch_object($result)) {
328 $presets['tabs'][] = array('id' => $row->presetid, 'name' => $row->presetname);
329 }
330 if (!empty($presetid)) $presets['presetid'] = $presetid;
331 else $presets['presetid'] = $presets['tabs'][0]['id'];
332 return $presets;
333 }
334
335 /**
336 * Helper function to create temporary image and return file object
337 *
338 * @param $fid file id in files table
339 * @param $presetid id of the preset
340 * @param $cutoff delete the javascript crop action when user wants to define the offsets
341 * @return $file with file, javascript crop and preset properties
342 */
343 function return_object($fid,$presetid,$cutoff = false) {
344 $file = _imagecrop_file_load($fid);
345 if ($file != false) {
346 $preset = imagecache_preset($presetid);
347 imagecache_image_flush($file->filename);
348 if ($cutoff == false) {
349 // get the actions from the preset and and throw out the javascript_crop action
350 // and every other action which comes after it.
351 $actions_count = count($preset['actions']);
352 while(list($key,$val) = each($preset['actions'])){
353 if ($val['action'] == 'imagecrop_javascript') {
354 $crop_width = $preset['actions'][$key]['data']['width'];
355 $crop_height = $preset['actions'][$key]['data']['height'];
356 $resizable = $preset['actions'][$key]['data']['resizable'];
357 unset($preset['actions'][$key]);
358 // stop the loop, we don't need anything after this
359 break;
360 }
361 }
362 // see if we have stored values allready for this file
363 $file->xoffset = 0;
364 $file->yoffset = 0;
365 $file->crop_width = $crop_width;
366 $file->crop_height = $crop_height;
367 $row = db_fetch_object(db_query("SELECT xoffset,yoffset,width,height FROM {imagecrop} ic where ic.fid = %d AND ic.presetid = %d",$fid,$presetid));
368 if (!empty($row)) {
369 $file->xoffset = $row->xoffset;
370 $file->yoffset = $row->yoffset;
371 $file->crop_width = $row->width;
372 $file->crop_height = $row->height;
373 }
374 // resizable or not
375 $file->resizable = $resizable;
376 }
377 $src = $file->filepath;
378 $file->presetname = $preset['presetname'];
379 $dst = imagecache_create_path($preset['presetname'], $file->filepath);
380 $file->dst = $dst;
381
382 // create the file to either display for the crop or the result
383 imagecache_build_derivative($preset, $src, $dst);
384 return $file;
385 } else return false;
386 }
387
388 /**
389 * Helper function to load a file into an object
390 *
391 * @param $fid file id
392 * @return $file with properties of the file or false
393 */
394 function _imagecrop_file_load($fid) {
395 $result = db_query('SELECT * FROM {files} WHERE fid = %d', $fid);
396 $file = db_fetch_object($result);
397 if ($file) {
398 // make sure it's an image. Any other mime extensions possible?
399 // return false if it's not the right mime type
400 $filemime = array('image/jpeg','image/gif','image/png');
401 if (!in_array($file->filemime,$filemime)) return false;
402 // access denied if current user hasn't enough permissions
403 // @todo test this!
404 $node = node_load($file->nid);
405 if (!user_access('administer nodes') && !user_access('edit '.$node->type) && !user_access('edit own '.$node->type)) {
406 drupal_access_denied();
407 exit();
408 }
409 // all seems ok, return file
410 return $file;
411 }
412 // return false if no file was found.
413 return false;
414 }
415
416 /**
417 * Theme image crop.
418 *
419 * @param $url url of image
420 * @param $width width of image
421 * @param $height height of image
422 * @param $resize wether the cropping box is resizeble or not
423 * @return $output html of the javascript crop area
424 */
425 function theme_imagecrop($url,$width,$height,$resize = 0) {
426 $output = '
427 <div class="imagefield-crop-wrapper" style="width: '.$width.'px; height: '.$height.'px;">
428 <div id="image-crop-container" style="background-image: url(\''. $url .'\'); width:'. $width .'px; height:'. $height .'px;"></div>
429 <div id="resizeMe" style="background-image: url(\''. $url .'\'); width:'. $width .'px; height:'. $height .'px; top: 20px;">';
430 if ($resize == 1) {
431 $output .= '
432 <div id="resizeSE"></div>
433 <div id="resizeE"></div>
434 <div id="resizeNE"></div>
435 <div id="resizeN"></div>
436 <div id="resizeNW"></div>
437 <div id="resizeW"></div>
438 <div id="resizeSW"></div>
439 <div id="resizeS"></div>
440 ';
441 }
442 $output .= '</div></div><div class="clear:both;"></div>';
443 $output .= '<div id="imagecrophelp">Use the selector to choose your crop area.</div>';
444
445 return $output;
446 }
447
448 /**
449 * Theme preset tabs
450 *
451 * @param $tabs array of available presets
452 * @param fid file id
453 * @param $presetid preset to highlight
454 * @return $output html of the tabs
455 */
456 function theme_presettabs($presets,$fid,$presetid) {
457 $tab_output = '';
458 foreach($presets['tabs'] as $key => $value) {
459 $class = ($value['id'] == $presetid) ? 'imagecrop_tab imagecrop_highlight' : 'imagecrop_tab ';
460 $tab_output .= '<span class="'.$class.'">'.l($value['name'],'imagecrop/window/'.$fid.'/'.$value['id']).'</span>';
461 }
462 $output = '<div id="presettabs">'.$tab_output.'</div>';
463 return $output;
464 }
465
466 /**
467 * Add imagecrop css & javascript
468 */
469 function imagecrop_markup($js,$css) {
470 $path = drupal_get_path('module', 'imagecrop');
471 if ($js == true) drupal_add_js($path.'/imagecrop.js');
472 if ($css == true) drupal_add_css($path.'/imagecrop.css');
473 }

  ViewVC Help
Powered by ViewVC 1.1.2