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

Contents of /contributions/modules/imagefield_crop/imagefield_crop.module

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


Revision 1.1 - (show annotations) (download) (as text)
Sun Jan 13 20:54:34 2008 UTC (22 months, 1 week ago) by yhager
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-5
File MIME type: text/x-php
Initial revision of the imagefield_crop widget
1 <?php
2 // $Id$
3
4 /**
5 * imagefield crop widget
6 * Author: Yuval Hager <yuval@avramzon.net>, 2008
7 * Description: see README.txt
8 */
9
10 /**
11 * TODO:
12 *
13 * o) On editing an existing image, set the default crop values to include the whole image [DONE]
14 * o) Need to scale the image to match available width/height [DONE]
15 * o) Add a definition of final resolution [DONE]
16 * o) Add a definition of crop area resolution [DONE]
17 * o) Upgrade to latest imagefield [WORKS WITH 1.2-rc1]
18 * o) On edit node, after preview shows an empty grey box [DONE]
19 * o) Test without 'always show cropping area' [OK]
20 * o) Enforce final size of the image according to widget resolution and cropped box [DONE]
21 * o) After changing crop see the old cropped image on preview [Same with imagefield]
22 * o) What about the delete checkbox? [DONE]
23 * o) Make the resizing box a little faster (ease on JS code) [NOT NOW]
24 * o) Edit existing node, cannot upload new image [DONE]
25 * o) Experiencing some segmentation faults (WSOD) [Probably xdebug related]
26 * o) Not using GD, but imagemagick [TEST]
27 * o) when creating a new node, upload one file, then another, can't crop [DONE]
28 * o) Test with imagefield-2.0 [edit existing node loses the image]
29 * o) NEW NODE: Uploading a file with existing filename shows the cropped image [??]
30 * o) Editing an existing image and cropping again loses the image [DONE]
31 * o) Sometimes we see old file (upload file with exising filename into crop box of
32 * existing node. Probably a problem with 'file_create_path' [??]
33 * o) How to scale without distroting the image? [Force ratio]
34 * o) Do we scale up? [YES]
35 * o) Do we want to use $_SESSION['imagefield'] and save some code? [YES]
36 * o) REFACTOR the code that is duplicated for 'always show cropping area' [DONE]
37 * o) After submitting a cropped image with existing name, the old image is shown [Need to click 'refresh']
38 */
39
40 function imagefield_crop_menu($may_cache) {
41 // REFACTOR: Maybe this is not needed, if we can use the original imagefield_menu
42 if (!$may_cache && $_SESSION['imagefield']) {
43 foreach ($_SESSION['imagefield'] as $fieldname => $files) {
44 if (is_array($files)) {
45 foreach ($files as $delta => $file) {
46 if ($file['crop']['preview']) {
47 $items[] = array(
48 'path' => $file['crop']['preview'],
49 'callback' => '_imagefield_crop_cropped_preview',
50 'access' => TRUE,
51 'type' => MENU_CALLBACK,
52 );
53 }
54 }
55 }
56 }
57 }
58 return $items;
59 }
60
61 function _imagefield_crop_cropped_preview() {
62 foreach ($_SESSION['imagefield'] as $fieldname => $files) {
63 foreach ($files as $delta => $file) {
64 if ($file['crop']['preview'] == $_GET['q']) {
65 file_transfer($file['crop']['filepath'],
66 array('Content-Type: '. mime_header_encode($file['filemime']),
67 'Content-Length: '. $file['filesize']));
68 exit();
69 }
70 }
71 }
72 }
73
74 /**
75 * Implementation of hook_widget_info()
76 */
77 function imagefield_crop_widget_info() {
78 return array(
79 'image crop' => array(
80 'label' => 'Image with cropping',
81 'field types' => array('image'),
82 ),
83 );
84 }
85
86 /**
87 * Implementation of hook_widget_settings().
88 */
89 function imagefield_crop_widget_settings($op, $widget) {
90 switch ($op) {
91 case 'callbacks':
92 return array('default value' => CONTENT_CALLBACK_CUSTOM);
93
94 case 'form':
95 $form = array();
96 $form['resolution'] = array (
97 '#type' => 'textfield',
98 '#title' => t('The resolution to crop the image onto'),
99 '#default_value' => isset($widget['resolution']) ? $widget['resolution'] : '200x150',
100 '#size' => 15,
101 '#maxlength' => 10,
102 '#description' =>
103 t('The output resolution of the cropped image, expressed as WIDTHxHEIGHT (e.g. 640x480). Set to 0 not to rescale after cropping.')
104 );
105 $form['enforce_ratio'] = array(
106 '#type' => 'checkbox',
107 '#title' => t('Enforce box crop box ratio'),
108 '#default_value' => isset($widget['enforce_ratio']) ? $widget['enforce_ratio'] : 1,
109 '#description' => t('Check this to force the ratio of the output on the crop box. NOTE: If you leave this unchecked, final images may be distorted'),
110 );
111 $form['croparea'] = array(
112 '#type' => 'textfield',
113 '#title' => t('The resolution of the cropping area'),
114 '#default_value' => isset($widget['croparea']) ? $widget['croparea'] : '500x500',
115 '#size' => 15,
116 '#maxlength' => 10,
117 '#description' => t('The resolution of the area used for the cropping of the image. Image will be scaled down to this size before cropping. Use WIDTHxHEIGHT format'),
118 );
119 $form['always_show'] = array( // REFACTOR: give a better name
120 '#type' => 'checkbox',
121 '#title' => t('Always show the cropping area'),
122 '#default_value' => isset($widget['always_show']) ? $widget['always_show'] : 0,
123 '#description' => t('Check this to show the cropping area even before the image is uploaded'),
124 );
125 $form['use_unscaled'] = array(
126 '#type' => 'checkbox',
127 '#title' => t('Use original (unscaled) image for cropping'),
128 '#default_value' => isset($widget['use_unscaled']) ? $widget['use_unscaled'] : 1,
129 '#description' => t('For better quality, use the original image for cropping, and not the one scaled for viewing'),
130 );
131 $form['image_path'] = array(
132 '#type' => 'textfield',
133 '#title' => t('Image path'),
134 '#default_value' => $widget['image_path'] ? $widget['image_path'] : '',
135 '#description' => t('Optional subdirectory within the "%dir" directory where images will be stored. Do not include trailing slash.', array('%dir' => variable_get('file_directory_path', 'files'))),
136 '#after_build' => array('imagefield_form_check_directory'),
137 );
138 $form['custom_alt'] = array(
139 '#type' => 'checkbox',
140 '#title' => t('Enable custom alternate text'),
141 '#default_value' => $widget['custom_alt'] ? $widget['custom_alt'] : 0,
142 '#description' => t('Enable custom alternate text for images. Filename will be used if not checked.'),
143 );
144 $form['custom_title'] = array(
145 '#type' => 'checkbox',
146 '#title' => t('Enable custom title text'),
147 '#default_value' => $widget['custom_title'] ? $widget['custom_title'] : 0,
148 '#description' => t('Enable custom title text for images. Filename will be used if not checked.'),
149 );
150 return $form;
151
152 case 'validate':
153 list($rw, $rh) = explode('x', $widget['resolution']);
154 if ($widget['enforce_ratio'] &&
155 (!is_numeric($rw) || intval($rw) != $rw || $rw <= 0 ||
156 !is_numeric($rh) || intval($rh) != $rh || $rh <= 0)) {
157 form_set_error('resolution', t('Target resolution must be defined as WIDTHxHEIGHT if resolution is to be enforced'));
158 }
159 list($cw, $ch) = explode('x', $widget['croparea']);
160 if (!is_numeric($cw) || intval($cw) != $cw || $cw <= 0 ||
161 !is_numeric($ch) || intval($ch) != $ch || $ch <= 0) {
162 form_set_error('croparea', t('Crop area resolution must be defined as WIDTHxHEIGHT'));
163 }
164 _imagefield_crop_verify_gd();
165 break;
166
167 case 'save':
168 return array('resolution', 'enforce_ratio', 'croparea', 'always_show', 'use_unscaled', 'image_path', 'custom_alt', 'custom_title');
169 }
170 }
171
172
173 /**
174 * Implementation of hook_widget().
175 */
176 function imagefield_crop_widget($op, &$node, $field, &$node_field) {
177 switch ($op) {
178 case 'default value':
179 return array();
180
181 case 'prepare form values':
182 _imagefield_crop_widget_prepare_form_values($node, $field, $node_field);
183 break;
184
185 case 'form':
186 return _imagefield_crop_widget_form($node, $field, $node_field);
187 break;
188
189 case 'validate':
190 if ($field['required']) {
191 if (!count($node_field)) {
192 form_set_error($field['field_name'], $field['widget']['label'] .' is required.');
193 }
194 }
195 break;;
196
197 case 'submit':
198 /*
199 ** move cropped file into the file's place
200 */
201 foreach ($node_field as $delta => $file) {
202 $cropped = $file['crop']['filepath'];
203 if (is_file($cropped)) {
204 if (!file_copy($cropped, $file['filepath'], FILE_EXISTS_REPLACE)) {
205 form_set_error(NULL, 'Could not copy cropped file');
206 }
207 file_delete($file['crop']['filepath']);
208 }
209 file_delete($file['filepath'] .'.unscaled');
210 }
211 break;
212 }
213 }
214
215 function _imagefield_crop_widget_prepare_form_values(&$node, $field, &$node_field) {
216 $fieldname = $field['field_name'];
217
218 // clean up the session if we weren't posted.
219 if (!count($_POST)) {
220 imagefield_crop_clear_session();
221 }
222
223 // Attach new files
224 $new_file_uploaded = FALSE;
225 if ($file = file_check_upload($fieldname .'_upload')) {
226 $file = (array)$file;
227 if (strpos($file['filemime'],'image') !== FALSE) {
228 if ($field['widget']['use_unscaled']) {
229 file_copy($unscaled = $file['filepath'], $file['filepath'] .'.unscaled', FILE_EXISTS_REPLACE);
230 }
231 $file = _imagefield_scale_image($file, $field['widget']['croparea']);
232
233 // Create the filepath for the image preview
234 $filepath = file_create_filename($file['filename'], file_create_path($field['widget']['image_path']));
235 if (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PRIVATE) {
236 if (strpos($filepath, file_directory_path()) !== FALSE) {
237 $filepath = trim(substr($filepath, strlen(file_directory_path())), '\\/');
238 }
239 $filepath = 'system/files/' . $filepath;
240 }
241
242 $file['fid'] = 'upload';
243 $file['preview'] = $filepath;
244
245 // If a single field, mark any other images for deletion and delete files in session
246 if (!$field['multiple']) {
247 if (is_array($node_field)) {
248 foreach ($node_field as $delta => $session_file) {
249 $node_field[$delta]['flags']['delete'] = TRUE;
250 }
251 }
252 imagefield_crop_clear_field_session($fieldname);
253 }
254 // Add the file to the session
255 $file_id = count($node_field) + count($_SESSION['imagefield'][$fieldname]);
256 $_SESSION['imagefield'][$fieldname][$file_id] = $file;
257 unset($_SESSION['imagefield'][$fieldname][$file_id]['crop']); /* REFACTOR: does this indeed clear crop values upon upload ? */
258 $new_file_uploaded = TRUE;
259 }
260 }
261
262 // Load files from preview state. before committing actions.
263 if (is_array($_SESSION['imagefield'][$fieldname]) && count($_SESSION['imagefield'][$fieldname])) {
264 foreach($_SESSION['imagefield'][$fieldname] as $delta => $file) {
265 if (isset($_POST[$fieldname][$delta]['crop'])) {
266 // we have a file in the session, but crop attributes on $_POST. Combine them
267 foreach(array('x','y','width','height') as $att) {
268 $file['crop'][$att] = $_POST[$fieldname][$delta]['crop'][$att];
269 //$file['crop'] = $_POST[$fieldname][$delta]['crop'];
270 }
271 }
272 $node_field[] = $file;
273 }
274 } else if (is_array($_POST[$fieldname])) {
275 // We were posted, but nothing in the session, so act on existing image
276 foreach ($_POST[$fieldname] as $delta => $file) {
277 $node_field[$delta]['crop'] = $file['crop'];
278 }
279 }
280
281 /*
282 ** Here we should crop the image, if crop values are given
283 */
284 foreach ($node_field as $delta => $file) {
285 if ($file['crop']['x'] != '') {
286 /* crop is requested */
287
288 /* REFACTOR: wild try - this might actually work */
289 if ($delta) {
290 $node_field[$delta-1]['flags']['delete'] = TRUE;
291 }
292
293 /* REFACTOR: make code readable !! */
294 if (!isset($file['crop']['filepath'])) {
295 $node_field[$delta]['crop']['filepath'] = tempnam(file_directory_temp(), 'tmpcp_');
296 }
297 _imagefield_crop_resize($node_field[$delta]['filepath'],
298 $file['crop'],
299 $field['widget']['resolution'],
300 $node_field[$delta]['crop']['filepath']);
301
302 /* @@@REFACTOR: is this line required ? */
303 $node_field[$delta]['crop']['preview'] = ($node_field[$delta]['fid'] == 'upload' ? $node_field[$delta]['preview'] : $node_field[$delta]['filepath']) .'-crop';
304
305 // save crop path and preview path in the session
306 $_SESSION['imagefield'][$fieldname][$delta]['crop'] = $node_field[$delta]['crop'];
307 }
308 }
309 }
310
311 function imagefield_crop_clear_session() {
312 if (is_array($_SESSION['imagefield']) && count($_SESSION['imagefield'])) {
313 foreach (array_keys($_SESSION['imagefield']) as $fieldname) {
314 imagefield_crop_clear_field_session($fieldname);
315 }
316 unset($_SESSION['imagefield']);
317 }
318 }
319
320 function imagefield_crop_clear_field_session($fieldname) {
321 if (is_array($_SESSION['imagefield'][$fieldname]) && count($_SESSION['imagefield'][$fieldname])) {
322 foreach ($_SESSION['imagefield'][$fieldname] as $files) {
323 file_delete($file['filepath']);
324 file_delete($file['crop']['filepath']);
325 file_delete($file['filepath'] .'.unscaled');
326 }
327 unset($_SESSION['imagefield'][$fieldname]);
328 }
329 }
330
331
332
333 function _imagefield_crop_widget_form($node, $field, &$node_field) {
334 $fieldname = $field['field_name'];
335
336 // REFACTOR: Do we need CSS file from imagefield.module?
337 drupal_add_css(drupal_get_path('module', 'imagefield') .'/imagefield.css');
338
339 $module_path = drupal_get_path('module', 'imagefield_crop');
340 drupal_add_css($module_path .'/imagefield_crop.css'); // REFACTOR: rename to imagefield_crop.css
341
342 jquery_interface_add();
343 if ($field['widget']['enforce_ratio']) {
344 list($w,$h) = explode('x', $field['widget']['resolution']);
345 drupal_add_js('Drupal.imagefield_crop = { ratio:'. $h/$w .'}', 'inline');
346 }
347 drupal_add_js($module_path .'/imagefield_crop.js'); // REFACTOR: rename to imagefield_crop.js
348
349 $form = array();
350 $form[$fieldname] = array(
351 '#type' => 'fieldset',
352 '#title' => t($field['widget']['label']),
353 '#weight' => $field['widget']['weight'],
354 '#collapsible' => TRUE,
355 '#collapsed' => FALSE,
356 '#tree' => TRUE,
357 );
358
359 // Seperate from tree becase of that silly things won't be
360 // displayed if they are a child of '#type' = form issue
361 $form[$fieldname][$fieldname .'_upload'] = array(
362 '#type' => 'file',
363 '#description' => $field['widget']['description'],
364 '#tree' => FALSE,
365 '#weight' => 9,
366 );
367
368 $form[$fieldname]['upload'] = array(
369 '#type' => 'button',
370 '#value' => t('Upload'),
371 '#name' => 'cck_imagefield_'.$fieldname.'_op', // REFACTOR: cck_imagefield_crop_ ??
372 '#attributes' => array('id' => $fieldname.'-attach-button'),
373 '#tree' => FALSE,
374 '#weight' => 10,
375 );
376
377 // Store the file data object to be carried on.
378 list($w, $h) = explode('x', $field['widget']['resolution']);
379 if (is_array($node_field) && count($node_field)) {
380 $crop_attrs = array(
381 // REFACTOR: Are weights necessary here?
382 'x' => array('weight' => 5, 'default' => 0),
383 'y' => array('weight' => 6, 'default' => 0),
384 'width' => array('weight' => 7, 'default' => $w ? $w : 50),
385 'height' => array('weight' => 8, 'default' => $h ? $h : 50),
386 );
387
388 // drupal_set_message('node_field is <pre>'. print_r($node_field, TRUE) .'</pre>');
389 foreach ($node_field as $delta => $file) {
390 if ($file['filepath'] && !$file['flags']['delete']) {
391 $form[$fieldname][$delta] = array(
392 '#theme' => 'imagefield_crop_edit_crop_image_row',
393 '#croparea' => $field['widget']['croparea'],
394 );
395
396 $form[$fieldname][$delta]['flags']['delete'] = array(
397 '#type' => 'checkbox',
398 '#title' => t('Delete'),
399 '#default_value' => 0,
400 );
401
402 $filename = $file['fid'] == 'upload' ? file_create_filename($file['filename'], file_create_path($field['widget']['image_path'])) : $file['filepath'];
403
404 if (is_file($file['filepath']) && (list($width, $height, $type, $image_attributes) = @getimagesize($file['filepath']))) {
405 if ($field['widget']['enforce_ratio']) {
406 list($fw,$fh) = explode('x', $field['widget']['resolution']);
407 $ratio = $fw/$fh;
408 $image_ratio = $width/$height;
409 if ($ratio > $image_ratio) {
410 $height = $width/$ratio;
411 } else {
412 $width = $height*$ratio;
413 }
414 }
415 $crop_attrs['width']['default'] = $width;
416 $crop_attrs['height']['default'] = $height;
417
418 }
419
420 $form[$fieldname][$delta]['preview'] = array(
421 '#type' => 'markup',
422 '#value' => theme('imagefield_crop_crop_image', $file, $file['alt'], $file['title'], NULL, /*@@ FALSE @@*/ TRUE),
423 );
424
425 $form[$fieldname][$delta]['crop'] = array();
426
427 foreach ($crop_attrs as $attr => $value) {
428 $form[$fieldname][$delta]['crop'][$attr] = array(
429 '#type' => 'hidden',
430 '#title' => $attr,
431 '#size' => 4,
432 '#maxlength' => 25,
433 '#weight' => $value['weight'],
434 '#attributes' => array('class' => 'edit-image-crop-'. $attr),
435 '#value' => $file['crop'][$attr] ? $file['crop'][$attr] : $value['default'],
436 );
437 }
438 /*
439 ** Show crop preview
440 */
441 $cropped = $file['crop'];
442 $cropped['fid'] = 'upload'; /* fool the theme function */
443 $form[$fieldname][$delta]['crop']['preview'] = array(
444 '#type' => 'markup',
445 '#value' => theme('imagefield_image', $cropped, '', '', array('class' => 'imagefield-crop-image-preview')),
446 );
447
448
449 // drupal_set_message('imagefield['. $fieldname .'] '. $op .' node field: <pre>'. print_r($node_field, true) .'</pre>');
450
451 $form[$fieldname][$delta]['description'] = array(
452 '#type' => 'markup',
453 '#value' => '<strong>' . t('Filename: ') . '</strong>' . $file['filename'],
454 );
455
456 $form[$fieldname][$delta]['alt'] = array(
457 '#type' => 'hidden',
458 '#value' => $file['filename'],
459 );
460 // overwrite with an input field if custom_alt is flagged;
461 if ($field['widget']['custom_alt']) {
462 $form[$fieldname][$delta]['alt'] = array(
463 '#type' => 'textfield',
464 '#title' => t('Alternate text'),
465 '#default_value' => $file['alt'],
466 '#description' => t('Alternate text to be displayed if the image cannot be displayed.'),
467 '#maxlength' => 255,
468 '#size' => 10,
469 );
470 }
471
472 $form[$fieldname][$delta]['title'] = array(
473 '#type' => 'hidden',
474 '#value' => $file['filename'],
475 );
476 // overwrite with an input field if custom_title is flagged;
477 if ($field['widget']['custom_title']) {
478 $form[$fieldname][$delta]['title'] = array(
479 '#type' => 'textfield',
480 '#title' => t('Title'),
481 '#default_value' => $file['title'],
482 '#description' => t('Text to be displayed on mouse overs.'),
483 '#maxlength' => 255,
484 '#size' => 10,
485 );
486 }
487 // Special handling for single value fields
488 if (!$field['multiple']) {
489 $form[$fieldname][$delta]['replace'] = array(
490 '#type' => 'markup',
491 '#value' => t('If a new image is chosen, the current image will be replaced upon submitting the form.'),
492 );
493 }
494 }
495 /* applied patch from http://drupal.org/node/130296 */
496 elseif ($file['filepath'] && $file['flags']['delete']) {
497 // Hide all the form values if this item is marked for deletion
498 $form[$fieldname][$delta]['flags']['delete'] = array('#type' => 'value', '#value' => $file['flags']['delete']);
499 $form[$fieldname][$delta]['title'] = array('#type' => 'value', '#value' => $file['title']);
500 $form[$fieldname][$delta]['alt'] = array('#type' => 'value', '#value' => $file['alt']);
501 }
502 $form[$fieldname][$delta]['filename'] = array('#type' => 'value', '#value' => $file['filename']);
503 $form[$fieldname][$delta]['filepath'] = array('#type' => 'value', '#value' => $file['filepath']);
504 $form[$fieldname][$delta]['filemime'] = array('#type' => 'value', '#value' => $file['filemime']);
505 $form[$fieldname][$delta]['filesize'] = array('#type' => 'value', '#value' => $file['filesize']);
506 $form[$fieldname][$delta]['fid'] = array('#type' => 'value', '#value' => $file['fid']);
507 //$form[$fieldname][$delta]['preview-path'] = array('#type' => 'value', '#value' => $filename);
508
509 $form[$fieldname][$delta]['crop']['filepath'] = array('#type' => 'value', '#value' => $file['crop']['filepath']);
510 //$form[$fieldname][$delta]['crop']['preview-path'] = array('#type' => 'value', '#value' => $file['crop']['preview']);
511 }
512 } else {
513 if ($field['widget']['always_show']) {
514 // just show croppable area, without any image
515 $form[$fieldname][0] = array(
516 '#theme' => 'imagefield_crop_edit_crop_image_row',
517 '#croparea' => $field['widget']['croparea'],
518 );
519 $form[$fieldname][0]['preview'] = array(
520 '#type' => 'markup',
521 /* REFACTOR: use different theme based on croppable widget settings */
522 '#value' => theme('imagefield_crop_crop_image', NULL, '', '', NULL, FALSE),
523 );
524 }
525 }
526 return $form;
527 }
528
529 function _imagefield_crop_verify_gd() {
530 if (image_get_toolkit() != 'gd') {
531 $toolkits = image_get_available_toolkits();
532 drupal_set_message(t('Image cropping only works with %toolkit. Please select it at !url, or ask your system administrator to do so', array('%toolkit' => $toolkits['gd'], '!url' => l('Image Toolkit selection page', 'admin/settings/image-toolkit'))), 'error');
533 return FALSE;
534 }
535 return TRUE;
536 }
537
538 function _imagefield_crop_resize($src, $crop = NULL, $resize = 0, $dst = NULL) {
539
540 if (!is_file($src)) {
541 return FALSE;
542 }
543
544 /*
545 ** The drupal image API is not good enough:
546 ** 1. It enforces file saving between operations
547 ** 2. In case of lossy compression (jpeg) quality is reduced on every action (http://drupal.org/node/128963)
548 **
549 ** ==> This should be better with Drupal 6, so take note to fix this for the Drupal 6 version of this module
550 */
551 if (!_imagefield_crop_verify_gd()) {
552 return FALSE;
553 }
554
555 $info = image_get_info($src);
556
557 if (!$info) {
558 return FALSE;
559 }
560
561 // if an unscaled version of the image exists, we should use it for cropping
562 $unscaled = $src .'.unscaled';
563 if (is_file($unscaled)) {
564 $unscaled_info = image_get_info($unscaled);
565 $scale=array();
566 $scale['width'] = $unscaled_info['width']/$info['width'];
567 $scale['height'] = $unscaled_info['height']/$info['height'];
568 if (!empty($crop)) {
569 $crop['x'] *= $scale['width'];
570 $crop['y'] *= $scale['height'];
571 $crop['width'] *= $scale['width'];
572 $crop['height'] *= $scale['height'];
573 }
574 $src = $unscaled;
575 $info = $unscaled_info;
576 }
577
578
579 // find the final image dimensions
580 list($width, $height) = array($info['width'], $info['height']);
581 if ($resize) {
582 list($width, $height) = explode('x', $resize);
583 }
584 elseif (!empty($crop)) {
585 list($width, $height) = array($crop['width'], $crop['height']);
586 }
587
588 /* REFACTOR: Don't scale up */
589
590 $im = image_gd_open($src, $info['extension']);
591 $res = imageCreateTrueColor($width, $height);
592 $background = imageColorAllocate($res, 255, 255, 255);
593
594 imageCopyResampled($res, $im,
595 0, 0,
596 $src_x = $crop['x'] ? $crop['x'] : 0, $src_y = $crop['y'] ? $crop['y'] : 0,
597 $width, $height,
598 $src_w = $crop['width'] ? $crop['width'] : $info['width'],
599 $src_h = $crop['height'] ? $crop['height'] : $info['height']);
600 $ratio_w = $width/$src_w;
601 $ratio_h = $height/$src_h;
602
603 /**
604 * Fill background around the image if required.
605 * Note that if it is not required, the rectangles are outside of the
606 * image boundaries anyway.
607 * REFACTOR: verify which is better in performance - with conditionals or w/o
608 */
609 /* bottom */
610 imageFilledRectangle($res, 0, $ratio_h*($info['height']-$src_y),
611 $width, $height, $background);
612 /* right */
613 imageFilledRectangle($res, $ratio_w*($info['width']-$src_x), 0,
614 $width, $height, $background);
615 /* top */
616 if ($src_y<0) {
617 imageFilledRectangle($res, 0, 0,
618 $width, $ratio_h*(-1)*$src_y, $background);
619 }
620 /* left */
621 if ($src_x<0) {
622 imageFilledRectangle($res, 0, 0,
623 $ratio_w*(-1)*$src_x, $height, $background);
624 }
625
626 $result = image_gd_close($res, empty($dst) ? $src : $dst, $info['extension']);
627 imageDestroy($im);
628 imageDestroy($res);
629 return $result;
630 }
631
632 function theme_imagefield_crop_edit_crop_image_row($element) {
633
634 list($cropw, $croph) = explode('x', $element['#croparea']);
635
636 $output .= '<div class="imagefield-crop-preview" style="width:'. $cropw .'px; height:'. $croph .'px">';
637 $output .= drupal_render($element['preview']) .'</div>';
638 if ($element['crop']) {
639 $output .= '<div class="imagefield-edit-image-detail">';
640
641 // REFACTOR: Don't 'flags' only if multiple is unsupported
642 $output .= '<div class="imagefield-edit-image-flags">'. drupal_render($element['flags']) .'</div>';
643
644 $output .= '<div class="imagefield-edit-image-description">'. drupal_render($element['description']);
645 $output .= '</div>';
646 $output .= drupal_render($element['crop']);
647 $output .= drupal_render($element['alt']);
648 $output .= drupal_render($element['title']);
649 $output .= '</div>';
650 }
651 $output = '<div class="imagefield-edit-image-row clear-block">'. $output .'</div>';
652 if (isset($element['replace'])) {
653 $output .= '<div class="imagefield-edit-image-replace">'. drupal_render($element['replace']) .'</div>';
654 }
655 return $output;
656 }
657
658 function theme_imagefield_crop_crop_image($file = NULL, $alt = '', $title = '', $attributes = NULL, $getsize = TRUE) {
659 $output = '<div class="imagefield-crop-wrapper">';
660
661 if (!empty($file)) {
662 $file = (array)$file;
663 if (!$getsize || (is_file($file['filepath']) && (list($width, $height, $type, $image_attributes) = @getimagesize($file['filepath'])))) {
664 //$attributes = drupal_attributes($attributes);
665
666 $path = $file['fid'] == 'upload' ? $file['preview'] : $file['filepath'];
667 $alt = empty($alt) ? $file['alt'] : $alt;
668 $title = empty($title) ? $file['title'] : $title;
669
670 $url = file_create_url($path);
671
672 $output .= '
673 <div id="image-crop-container"
674 style="background-image: url(\''. $url .'\'); width:'. $width .'px; height:'. $height .'px; margin-left:-'. $width/2 .'px; margin-top:-'. $height/2 .'px;">
675 </div>
676
677 <div id="resizeMe"
678 style="background-image: url(\''. $url .'\')">
679 <div id="resizeSE"></div>
680 <div id="resizeE"></div>
681 <div id="resizeNE"></div>
682 <div id="resizeN"></div>
683 <div id="resizeNW"></div>
684 <div id="resizeW"></div>
685 <div id="resizeSW"></div>
686 <div id="resizeS"></div>
687
688 </div>';
689 }
690 }
691 $output .= '</div>';
692
693 return $output;
694 }

  ViewVC Help
Powered by ViewVC 1.1.2