/[drupal]/contributions/modules/drawing/modules/drawing_gd/drawing_gd.module
ViewVC logotype

Diff of /contributions/modules/drawing/modules/drawing_gd/drawing_gd.module

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

revision 1.1, Sat May 9 05:56:28 2009 UTC revision 1.1.2.1, Sat May 9 05:56:28 2009 UTC
# Line 0  Line 1 
1    <?php
2    // $Id$
3    
4    /**
5     * @file
6     * The GD toolkit module.
7     */
8    
9    /**
10     * Implementation of hook_drawing_method().
11     */
12    function drawing_gd_drawing_method() {
13      return array('drawing_gd' => t('GD toolkit'));
14    }
15    
16    /**
17     * A list of GD element types the drawing module should theme.
18     */
19    function drawing_gd_element_list() {
20      return array(
21        'canvas',
22        'group',
23        'file',
24        'ellipse',
25        'circle',
26        'rectangle',
27        'line',
28        'polyline',
29        'polygon',
30        'path',
31        'text',
32      );
33    }
34    
35    /**
36     * Implementation of hook_drawing_theme_alter().
37     */
38    function drawing_gd_drawing_theme_alter(&$themes) {
39      $drawing_themes = drawing_gd_element_list();
40      foreach ($drawing_themes as $theme_name) {
41        $themes[] = 'drawing_'. $theme_name;
42      }
43    }
44    
45    /**
46     * Implementation of hook_theme().
47     */
48    function drawing_gd_theme() {
49      $drawing_gd_themes = array();
50      $themes = drawing_gd_element_list();
51      foreach ($themes as $theme_name) {
52        $drawing_gd_themes['drawing_gd_drawing_'. $theme_name] = array(
53          'arguments' => array(
54            'element' => NULL,
55          ),
56        );
57      }
58      return $drawing_gd_themes;
59    }
60    
61    /**
62     * Set and get the image using static caching.
63     */
64    function drawing_gd_image($gd_id, $image = NULL) {
65      static $images;
66      if (!is_null($image)) {
67        $images[$gd_id] = $image;
68      }
69      elseif ($image === FALSE) {
70        imagedestroy($images[$gd_id]);
71      }
72      return $images[$gd_id];
73    }
74    
75    /**
76     * Recursively pre render the canvas elements.
77     *
78     * @param $canvas
79     *   The canvas to process
80     * @return
81     *   The updated canvas.
82     */
83    function drawing_gd_pre_render_canvas($canvas) {
84      foreach (element_children($canvas) as $child) {
85        // pass down #gd_id to all the child elements.
86        $canvas[$child]['#gd_id'] = $canvas['#gd_id'];
87        $canvas[$child] = drawing_gd_pre_render_canvas($canvas[$child]);
88      }
89      return $canvas;
90    }
91    
92    /**
93     * Recursively transform the canvas elements.
94     *
95     * @param $elements
96     *   The elements to process
97     * @return
98     *   The updated elements.
99     */
100    function drawing_gd_transform($elements) {
101      foreach (element_children($elements) as $child) {
102        // transform it here
103        $elements[$child] = drawing_gd_transform($elements[$child]);
104      }
105      return $elements;
106    }
107    
108    /**
109     * Root canvas drawing function.
110     */
111    function drawing_gd_drawing_canvas($element) {
112      // Include Drupal's GD functions for this request
113      include_once './includes/image.gd.inc';
114      // Include the color functions.
115      module_load_include('inc', 'drawing_gd', 'drawing_gd_color');
116      // Check for an existing image for this $canvas
117      $element['#rendered'] = db_fetch_array(db_query("SELECT gd_id, file FROM {drawing_gd_image} WHERE data = '%s'", serialize($element)));
118      // If there is no existing image, create one.
119      if (!$element['#rendered']) {
120        unset($element['#rendered']);
121        // Create an $image array for insertion into the database
122        $image['data'] = $element;
123        // If there is no #format set, default it to 'png'.
124        if (!$element['#format']) {
125          $element['#format'] = 'png';
126        }
127        // If there is no #directory and no #file, set the #directory because we will need it.
128        if (!$element['#directory'] && !$element['#file']) {
129          $element['#directory'] = file_directory_path() .'/drawing_gd';
130          // confirm the existence of directory
131          file_check_directory($element['#directory'], FILE_CREATE_DIRECTORY);
132        }
133        // If we can calculate the file already, do it, and add it to the $image
134        if ($element['#file'] || $element['#filename']) {
135          $element['#file'] = $element['#file'] ? $element['#file'] : $element['#directory'] .'/'. $element['#filename'];
136          $image['file'] = $element['#file'];
137        }
138        // Write an entry into the table, to get a 'gd_id'.
139        drupal_write_record('drawing_gd_image', $image);
140        $element['#gd_id'] = $image['gd_id'];
141        // Remove the $image['data'] to avoid writing it back to the database again.
142        unset($image['data']);
143        // Create gd image
144        $img = imagecreatetruecolor($element['#width'], $element['#height']);
145        // Fill gd image with blank image
146        imagealphablending($img, FALSE);
147        imagesavealpha($img, TRUE);
148    
149        $blank = imagecreatefromstring(base64_decode(drawing_gd_blank()));
150        imagecopyresized($img, $blank, 0, 0, 0, 0, $element['#width'], $element['#height'], imagesx($blank), imagesy($blank));
151        /*
152        $new_image = ImageCreateTruecolor($element['#width'], $element['#height']);
153        // Set a White & Transparent Background Color
154        $bg = ImageColorAllocateAlpha($new_image, 255, 255, 255, 127); // (PHP 4 >= 4.3.2, PHP 5)
155        ImageFill($new_image, 0, 0 , $bg);
156        // Copy and merge
157        ImageCopyMerge($img, $new_image, 0, 0, 0, 0, $element['#width'], $element['#height'], 100);
158        */
159    
160        // Store gd image in a static cache
161        drawing_gd_image($element['#gd_id'], $img);
162        // Compose the file path if not done so already, and update the database with it.
163        if (!$element['#file']) {
164          $element['#filename'] = $element['#filename'] ? $element['#filename'] : $element['#gd_id'] .'.'. $element['#format'];
165          $element['#file'] = $element['#file'] ? $element['#file'] : $element['#directory'] .'/'. $element['#filename'];
166          $image['file'] = $element['#file'];
167          drupal_write_record('drawing_gd_image', $image, 'gd_id');
168        }
169        // Recursively pre_render the elements
170        $element = drawing_gd_pre_render_canvas($element);
171    
172      }
173      else {
174        $element['#file'] = $element['#rendered']['file'];
175        unset($element['#pre_render']);
176        $element['#defaults_loaded'] = TRUE;
177        $element['#sorted'] = TRUE;
178        $element['#children'] = TRUE;
179      }
180      return $element;
181    }
182    
183    /**
184     * Root canvas drawing theme function.
185     */
186    function theme_drawing_gd_drawing_canvas($element) {
187      drupal_set_message("Warning: The Drawing GD toolkit is in development.", 'warning');
188      // if this element is already rendered, avoid creating a duplicate
189      if (!$element['#rendered']) {
190        // Read the GD resource from the static cache
191        $img = drawing_gd_image($element['#gd_id']);
192        // Use Drupal's GD toolkit functions to write it to file
193        image_gd_close($img, $element['#file'], $element['#format']);
194        // Destroy the GD resource from the static cache
195        drawing_gd_image($element['#gd_id'], FALSE);
196      }
197      // Output the file path of the saved file
198      return $element['#file'];
199    }
200    
201    /**
202     * Group canvas drawing function.
203     */
204    function drawing_gd_drawing_group($element) {
205      return drawing_gd_transform($element);
206    }
207    
208    /**
209     * Standalone image embedding.
210    
211    function theme_drawing_gd_drawing_file($element) {
212      $dimensions = (isset($element['#height']) && ($element['#width'])) ?
213        ' width="'. $element['#width'] .'" height="'. $element['#height'] .'"' : '';
214      return '<object data="'. $element['#location'] .'" type="image/gd+xml" '. $dimensions .' >
215        <embed src="'. $element['#location'] .'" type="image/gd+xml" '. $dimensions .' /></object>';
216    } */
217    
218    /**
219     * Return an ellipse.
220     */
221    function theme_drawing_gd_drawing_ellipse($shape) {
222      $img = drawing_gd_image($shape['#gd_id']);
223      $cx1 = $shape['#cx1'] ? $shape['#cx1'] : $shape['#cx'];
224      $cy1 = $shape['#cy1'] ? $shape['#cy1'] : $shape['#cy'];
225      $width = $shape['#width'] ? $shape['#width'] : 2 * $shape['#rx'];
226      $height = $shape['#height'] ? $shape['#height'] : 2 * $shape['#ry'];
227      if ($shape['#stroke-width'] > 1) {
228        $shape['#stroke_func'] = $shape['#stroke_func'] ? $shape['#stroke_func'] : 'drawing_gd_stroked_ellipse';
229        $shape['#stroke_args'] = $shape['#stroke_args'] ? $shape['#stroke_args'] : array($shape['#stroke-width'] ? $shape['#stroke-width'] : 1);
230      }
231      $img = drawing_gd_shape($img, $shape, 'ellipse', array($cx1, $cy1, $width, $height));
232      drawing_gd_image($shape['#gd_id'], $img);
233    }
234    
235    /**
236     * Return a circle.
237     */
238    function theme_drawing_gd_drawing_circle($shape) {
239      $shape['#rx'] = $shape['#rx'] ? $shape['#rx'] : $shape['#r'];
240      $shape['#ry'] = $shape['#ry'] ? $shape['#ry'] : $shape['#r'];
241      return theme('drawing_gd_drawing_ellipse', $shape);
242    }
243    
244    /**
245     * Return a rectangle
246     */
247    function theme_drawing_gd_drawing_rectangle($shape) {
248      $img = drawing_gd_image($shape['#gd_id']);
249      $cx1 = $shape['#cx1'] ? $shape['#cx1'] : $shape['#cx'];
250      $cy1 = $shape['#cy1'] ? $shape['#cy1'] : $shape['#cy'];
251      $cx2 = $shape['#cx2'] ? $shape['#cx2'] : $cx1 + $shape['#width'];
252      $cy2 = $shape['#cy2'] ? $shape['#cy2'] : $cx2 + $shape['#height'];
253      $img = drawing_gd_shape($img, $shape, 'rectangle', array($cx1, $cy1, $cx2, $cy2));
254      drawing_gd_image($shape['#gd_id'], $img);
255    }
256    
257    /**
258     * Return a line
259     * obligatory elements: #cx1, #cy1, #cx2, #cy2.
260     */
261    function theme_drawing_gd_drawing_line($shape) {
262      $img = drawing_gd_image($shape['#gd_id']);
263      $opacity = drawing_gd_opacity($shape['#opacity']);
264      $fill = drawing_gd_color($shape['#fill']);
265      $color = imagecolorallocatealpha($img, $fill['r'], $fill['g'], $fill['b'], $opacity);
266      imageline($img, $shape['#points']['#cx1'], $shape['#points']['#cy1'], $shape['#points']['#cx2'], $shape['#points']['#cy2'], $color);
267      drawing_gd_image($shape['#gd_id'], $img);
268    }
269    
270    /**
271     * Return a polyline
272     * Shape has a special element: $shape['#points'] = array(),
273     * this contains the coordinate pairs for each point.
274    
275    function theme_drawing_gd_drawing_polyline($shape) {
276      $points = '';
277      $polyline['id'] = drawing_gd_get_value('#id', 'id', $shape);
278      $polyline['class'] = drawing_gd_get_value('#class', 'class', $shape);
279      $attributes = implode($polyline, ' ');
280      foreach ($shape['#points'] as $point => $crds) {
281        // output form: cx1,cy1 cx2,cy2 cx3,cx3 ...
282        $points .= $crds['#cx'] .','. $crds['#cy'] .' '; // the number of the point is $point
283      }
284      $output = '<gd:polyline points="'. $points .'" '. $attributes . drawing_gd_style($shape) .'/>';
285      $output = drawing_gd_anchor($shape, $output);
286      return $output;
287    } */
288    
289    /**
290     * Return a polygon
291     * $shape['#points'] = array( int N => array( '#cx' => 'int', '#cy' => 'int')); where N
292     * is the number of the given point.
293    
294    function theme_drawing_gd_drawing_polygon($shape) {
295      $polygon['id']  = drawing_gd_get_value('#id', 'id', $shape);
296      $polygon['class']  = drawing_gd_get_value('#class', 'class', $shape);
297      $attributes = implode($polygon, ' ');
298    
299      $points = '';
300      foreach ($shape['#points'] as $point => $crds) {
301        // output form: cx1,cy1 cx2,cy2 cx3,cx3 ...
302        $points .= $crds['#cx'] .','. $crds['#cy'] .' '; // the number of the point is $point
303      }
304      $output = '<gd:polygon points="'. $points .'" '. $attributes . drawing_gd_style($shape) .'/>';
305      $output = drawing_gd_anchor($shape, $output);
306      return $output;
307    } */
308    
309    /**
310     * Return a path
311     * point definition can be explicit or implicit.
312    
313    function theme_drawing_gd_drawing_path($shape) {
314      $points = '';
315      $output = '';
316      $id = drawing_gd_get_value('#id', 'id', $shape);
317      $class = drawing_gd_get_value('#class', 'class', $shape);
318      if (!isset($shape['#explicit']) || $shape['#explicit'] == FALSE) {
319        // not having '#explicit' set means we define the points via the API
320        foreach ($shape['#points'] as $point => $attributes) { // $points = int N
321          $modifier = $attributes['#modifier'];
322          $points .= ((isset($modifier) && $modifier != 'z') ? $modifier : '' ) .
323            $attributes['#cx'] .','. $attributes['#cy'] .
324            (($modifier == 'z') ? $modifier : '') .' ';
325        }
326      }
327      else { // meaning we have explicit point declaration, e.g from a drawing program
328        // Warning, no validation checking here!
329        $points = $shape['#points'];
330      }
331      $output = drawing_gd_anchor($shape, $output);
332      $output = '<gd:path '. $id .' d="'. $points .'" '. drawing_gd_style($shape) .'/>';
333      return $output;
334    } */
335    
336    /**
337     * Return text.
338    
339    function theme_drawing_gd_drawing_text($shape) {
340      $text = array();
341      $text['id'] = drawing_gd_get_value('#id', 'id', $shape);
342      $text['class'] = drawing_gd_get_value('#class', 'class', $shape);
343      $text['position'] = drawing_gd_get_position($shape);
344      $text['rotation'] = drawing_gd_get_value('#rotate', 'rotate', $shape);
345      $text['textlength'] = drawing_gd_get_value('#width', 'textLength', $shape);
346      $attributes = implode($text, ' ');
347      $attributes = $attributes . drawing_gd_get_transformation($shape);
348      $output = '<gd:text '. $attributes . drawing_gd_style($shape) .'>'. $shape['#value'] .'</gd:text>';
349      $output = drawing_gd_anchor($shape, $output);
350      return $output;
351    } */
352    
353    
354    /**
355     *  Get a string reprenstation of a blank PNG image.
356     *
357     *  @return
358     *    String representing a blank image in PNG format.
359     */
360    function drawing_gd_blank() {
361      return "iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29m"
362            ."dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAADqSURBVHjaYvz//z/DYAYAAcTEMMgBQAANegcCBNCg"
363            ."dyBAAA16BwIE0KB3IEAADXoHAgTQoHcgQAANegcCBNCgdyBAAA16BwIE0KB3IEAADXoHAgTQoHcgQAAN"
364            ."egcCBNCgdyBAAA16BwIE0KB3IEAADXoHAgTQoHcgQAANegcCBNCgdyBAAA16BwIE0KB3IEAADXoHAgTQ"
365            ."oHcgQAANegcCBNCgdyBAAA16BwIE0KB3IEAADXoHAgTQoHcgQAANegcCBNCgdyBAAA16BwIE0KB3IEAA"
366            ."DXoHAgTQoHcgQAANegcCBNCgdyBAgAEAMpcDTTQWJVEAAAAASUVORK5CYII=";
367    }
368    
369    /**
370     *  Create and write an animated gif to the file system based on source gifs.
371     *
372     *  @param $file
373     *    Output path.
374     *  @param $sources
375     *     Array of filenames or binary data for gif frames.
376     *  @param $delays
377     *     Array of integers indicating delay times for each
378     *     Leave blank to default each frame to 5 miliseconds.
379     *  @param $loops
380     *     Number of times to loop the animation (integer).
381     *  @param $disposal
382     *     Method of frame removal.
383     *  @param $transparent
384     *    A color to use for transparency when composing animation.
385     *    Can be english html/x11 color, hex color, or rgb(r, g, b) string.
386     *  @param $mode
387     *    'url' if supplying filenames in $sources, 'bin' if supplying binary data.
388     *  @return
389     *    TRUE or FALSE whether the file was created successfully.
390     */
391    function drawing_gd_animated_gif($file, $sources, $delays = NULL, $loops = NULL, $disposal = NULL, $transparent = NULL, $mode = NULL) {
392      module_load_include('inc', 'drawing_gd', 'drawing_gd_gif89a');
393      if (is_null($delays)) {
394        for ($i = 0; $i <= count($sources); $i++) {
395          $delays[] = 5;
396        }
397      }
398      $loops = is_null($loops) ? 0 : $loops;
399      $disposal = is_null($disposal) ? 2 : $disposal;
400      if (is_null($transparent)) {
401        // ???
402      }
403      $mode = is_null($mode) ? 'url' : $mode;
404      $trans = drawing_gd_color($transparent);
405      $gif89a = new drawing_gd_gif98a(
406        $sources,
407        $delays,
408        $loops,
409        $disposal,
410        $trans['r'],
411        $trans['g'],
412        $trans['b'],
413        $mode
414      );
415      if (!$gif89a->error) {
416        if (fwrite(fopen($file, "wb"), $gif89a->get_animation())) {
417          return TRUE;
418        }
419      }
420      return FALSE;
421    }
422    
423    /**
424     *  Convert opacity in the range 0-1 to opacity in the range 127-0.
425     *
426     */
427    function drawing_gd_opacity($opacity) {
428      return !is_null($opacity) ? (1 - $opacity) * 127 : 0;
429    }
430    
431    /**
432     * Helps draw shapes.
433     */
434    function drawing_gd_shape($img, $shape, $shape_type, $args) {
435      $opacity = drawing_gd_opacity($shape['#opacity']);
436      $fill_func = $shape['#fill_func'] ? $shape['#fill_func'] : 'imagefilled'. $shape_type;
437      if ($shape['#fill'] && function_exists($fill_func)) {
438        $fill_opacity = $shape['#fill-opacity'] ? drawing_gd_opacity($shape['#fill-opacity']) : $opacity;
439        $fill = drawing_gd_color($shape['#fill']);
440        $fill_color = imagecolorallocatealpha($img, $fill['r'], $fill['g'], $fill['b'], $fill_opacity);
441        $fill_args = array_merge(array($img), $args, array($fill_color));
442        if ($shape['#fill_args']) {
443          $fill_args = array_merge($fill_args, $shape['#fill_args']);
444        }
445        call_user_func_array($fill_func, $fill_args);
446      }
447      $stroke_func = $shape['#stroke_func'] ? $shape['#stroke_func'] : 'image'. $shape_type;
448      if ($shape['#stroke'] && function_exists($stroke_func)) {
449        $stroke_opacity = $shape['#stroke-opacity'] ? drawing_gd_opacity($shape['#stroke-opacity']) : $opacity;
450        $stroke = drawing_gd_color($shape['#stroke']);
451        $stroke_color = imagecolorallocatealpha($img, $stroke['r'], $stroke['g'], $stroke['b'], $stroke_opacity);
452        $stroke_width = $shape['#stroke-width'] ? $shape['#stroke-width'] : 1;
453        imagesetthickness($img, $stroke_width);
454        $stroke_args = array_merge(array($img), $args, array($stroke_color));
455        if ($shape['#stroke_args']) {
456          $stroke_args = array_merge($stroke_args, $shape['#stroke_args']);
457        }
458        call_user_func_array($stroke_func, $stroke_args);
459      }
460      return $img;
461    }
462    
463    /**
464     * Helps draw stroked ellipses.
465     */
466    function drawing_gd_stroked_ellipse($img, $cx, $cy, $width, $height, $color, $stroke_width) {
467      $line = 0;
468      while ($line < $stroke_width) {
469        imageellipse($img, $cx, $cy, $width, $height, $color);
470        $line++;
471        $width--;
472        $height--;
473      }
474    }

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.1.2.1

  ViewVC Help
Powered by ViewVC 1.1.2