added a smaller version fo the available-tags icon for the photo details
[phpfspot.git] / phpfspot.class.php
1 <?php
2
3 require_once "phpfspot_cfg.php";
4 require_once "phpfspot_db.php";
5 require_once "phpfspot_tmpl.php";
6
7 class PHPFSPOT {
8
9    var $cfg;
10    var $db;
11    var $cfg_db;
12    var $tmpl;
13    var $tags;
14    var $avail_tags;
15    var $current_tags;
16
17    public function __construct()
18    {
19       /* Check necessary requirements */
20       if(!$this->checkRequirements()) {
21          exit(1);
22       }
23
24       $this->cfg = new PHPFSPOT_CFG;
25
26       $this->db  = new PHPFSPOT_DB(&$this, $this->cfg->fspot_db);
27       $this->cfg_db = new PHPFSPOT_DB(&$this, $this->cfg->phpfspot_db);
28       $this->check_config_table();
29
30       $this->tmpl = new PHPFSPOT_TMPL($this);
31
32       $this->get_tags();
33
34       session_start();
35
36       if(!isset($_SESSION['tag_condition']))
37          $_SESSION['tag_condition'] = 'or';
38
39       if(!isset($_SESSION['searchfor']))
40          $_SESSION['searchfor'] = '';
41
42    } // __construct()
43
44    public function __destruct()
45    {
46
47    } // __destruct()
48
49    public function show()
50    {
51       $this->tmpl->assign('searchfor', $_SESSION['searchfor']);
52       $this->tmpl->assign('page_title', $this->cfg->page_title);
53       $this->tmpl->assign('current_condition', $_SESSION['tag_condition']);
54
55       switch($_GET['mode']) {
56          case 'showpi':
57             if(isset($_GET['tags'])) {
58                $_SESSION['selected_tags'] = split(',', $_GET['tags']);
59             }
60             break;
61       }
62
63       $this->tmpl->assign('content_page', 'welcome.tpl');
64       $this->tmpl->show("index.tpl");
65
66
67    } // show()
68
69    private function get_tags()
70    {
71    
72       $this->avail_tags = Array();
73       $count = 0;
74    
75       $result = $this->db->db_query("
76          SELECT id,name
77          FROM tags
78          ORDER BY sort_priority ASC
79       ");
80       
81       while($row = $this->db->db_fetch_object($result)) {
82
83          $tag_id = $row['id'];
84          $tag_name = $row['name'];
85
86          /* check if config requests to ignore this tag */
87          if(in_array($row['name'], $this->cfg->hide_tags))
88             continue;
89
90          $this->tags[$tag_id] = $tag_name; 
91          $this->avail_tags[$count] = $tag_id;
92
93          $count++;
94
95       }
96
97    } // get_tags()
98
99    public function get_photo_details($idx)
100    {
101       $result = $this->db->db_query("
102          SELECT *
103          FROM photos
104          WHERE id='". $idx ."'
105       ");
106       
107       return $this->db->db_fetch_object($result);
108
109    } // get_photo_details
110
111    public function translate_path($path, $width = 0)
112    {  
113       return str_replace($this->cfg->path_replace_from, $this->cfg->path_replace_to, $path);
114
115    } // translate_path
116
117    public function showPhoto($photo)
118    {
119       $all_photos = $this->getPhotoSelection();
120
121       foreach($all_photos as $all_photo) {
122          
123          if($get_next) {
124             $next_img = $all_photo;
125             break;
126          }
127
128          if($all_photo == $photo) {
129             $get_next = 1;
130          }
131          else {
132             $previous_img = $all_photo;
133          }
134       }
135
136       $details = $this->get_photo_details($photo);
137       $orig_path = $this->translate_path($details['directory_path']) ."/". $details['name'];
138       $thumb_path = $this->cfg->base_path ."/thumbs/". $this->cfg->photo_width ."_". $this->getMD5($photo);
139
140       if(!file_exists($orig_path)) {
141          print "Photo ". $orig_path ." does not exist!<br />\n";
142       }
143
144       if(!is_readable($orig_path)) {
145          print "Photo ". $orig_path ." is not readable for user ". get_current_user() ."<br />\n";
146       }
147
148       /* If the thumbnail doesn't exist yet, try to create it */
149       if(!file_exists($thumb_path)) {
150          $this->gen_thumb($photo, true);
151       }
152
153       $meta = $this->get_meta_informations($orig_path);
154
155       if(file_exists($thumb_path)) {
156
157          $info = getimagesize($thumb_path);
158
159          $this->tmpl->assign('description', $details['description']);
160          $this->tmpl->assign('image_name', $details['name']);
161
162          $this->tmpl->assign('width', $info[0]);
163          $this->tmpl->assign('height', $info[1]);
164          $this->tmpl->assign('ExifMadeOn', strftime("%a %x %X", $meta['FileDateTime']));
165          $this->tmpl->assign('ExifMadeWith', $meta['Make'] ." ". $meta['Model']);
166          $this->tmpl->assign('ExifOrigResolution', $meta['ExifImageWidth'] ."x". $meta['ExifImageLength']);
167          $this->tmpl->assign('ExifFileSize', round($meta['FileSize']/1024, 1));
168     
169          $this->tmpl->assign('image_url', 'phpfspot_img.php?idx='. $photo ."&amp;width=". $this->cfg->photo_width);
170          $this->tmpl->assign('image_url_full', 'phpfspot_img.php?idx='. $photo);
171
172          $this->tmpl->assign('tags', $this->get_photo_tags($photo));
173       }
174       else {
175          print "Can't open file ". $thumb_path ."\n";
176       }
177
178       if($previous_img) {
179          $this->tmpl->assign('previous_url', "javascript:showImage(". $previous_img .");");
180       }
181
182       if($next_img) {
183          $this->tmpl->assign('next_url', "javascript:showImage(". $next_img .");");
184       }
185
186       $this->tmpl->show("single_photo.tpl");
187
188    } // showPhoto()
189
190    public function getAvailableTags()
191    {
192       $result = $this->db->db_query("
193          SELECT tag_id as id, count(tag_id) as quantity
194          FROM photo_tags
195          INNER JOIN tags t
196             ON t.id = tag_id
197          GROUP BY tag_id
198          ORDER BY t.name ASC
199       ");
200
201       $tags = Array();
202
203       while($row = $this->db->db_fetch_object($result)) {
204          $tags[$row['id']] = $row['quantity'];
205       }
206
207       // change these font sizes if you will
208       $max_size = 125; // max font size in %
209       $min_size = 75; // min font size in %
210
211       // get the largest and smallest array values
212       $max_qty = max(array_values($tags));
213       $min_qty = min(array_values($tags));
214
215       // find the range of values
216       $spread = $max_qty - $min_qty;
217       if (0 == $spread) { // we don't want to divide by zero
218          $spread = 1;
219       }
220
221       // determine the font-size increment
222       // this is the increase per tag quantity (times used)
223       $step = ($max_size - $min_size)/($spread);
224
225       // loop through our tag array
226       foreach ($tags as $key => $value) {
227
228          if(isset($_SESSION['selected_tags']) && in_array($key, $_SESSION['selected_tags']))
229             continue;
230
231           // calculate CSS font-size
232           // find the $value in excess of $min_qty
233           // multiply by the font-size increment ($size)
234           // and add the $min_size set above
235          $size = $min_size + (($value - $min_qty) * $step);
236           // uncomment if you want sizes in whole %:
237          $size = ceil($size);
238
239          print "<a href=\"javascript:Tags('add', ". $key .");\" class=\"tag\" style=\"font-size: ". $size ."%;\">". $this->tags[$key] ."</a>, ";
240
241       }
242
243    } // getAvailableTags()
244
245    public function getSelectedTags()
246    {
247       foreach($this->avail_tags as $tag)
248       {
249          // return all selected tags
250          if(isset($_SESSION['selected_tags']) && in_array($tag, $_SESSION['selected_tags'])) {
251             print "<a href=\"javascript:Tags('del', ". $tag .");\" class=\"tag\">". $this->tags[$tag] ."</a>&nbsp;";
252          }
253
254       }
255
256    } // getSelectedTags()
257
258    public function addTag($tag)
259    {
260       if(!isset($_SESSION['selected_tags']))
261          $_SESSION['selected_tags'] = Array();
262
263       if(!in_array($tag, $_SESSION['selected_tags']))
264          array_push($_SESSION['selected_tags'], $tag);
265    
266    } // addTag()
267
268    public function delTag($tag)
269    {
270       if(isset($_SESSION['selected_tags'])) {
271          $key = array_search($tag, $_SESSION['selected_tags']);
272          unset($_SESSION['selected_tags'][$key]);
273          sort($_SESSION['selected_tags']);
274       }
275
276    } // delTag()
277
278    public function resetTags()
279    {
280       unset($_SESSION['selected_tags']);
281
282    } // resetTags()
283
284    public function resetTagSearch()
285    {
286       unset($_SESSION['searchfor']);
287
288    } // resetTagSearch()
289
290    public function getPhotoSelection()
291    {  
292       $tagged_photos = Array();
293
294       /* return a search result */
295       if(isset($_SESSION['searchfor']) && $_SESSION['searchfor'] != '') {
296          $result = $this->db->db_query("
297             SELECT DISTINCT photo_id
298                FROM photo_tags pt
299             INNER JOIN photos p
300                ON p.id=pt.photo_id
301             INNER JOIN tags t
302                ON pt.tag_id=t.id
303             WHERE t.name LIKE '%". $_SESSION['searchfor'] ."%'
304                ORDER BY p.time ASC
305          ");
306          while($row = $this->db->db_fetch_object($result)) {
307             array_push($tagged_photos, $row['photo_id']);
308          }
309          return $tagged_photos;
310       }
311
312       /* return according the selected tags */
313       if(isset($_SESSION['selected_tags']) && !empty($_SESSION['selected_tags'])) {
314          $selected = "";
315          foreach($_SESSION['selected_tags'] as $tag)
316             $selected.= $tag .",";
317          $selected = substr($selected, 0, strlen($selected)-1);
318
319          if($_SESSION['tag_condition'] == 'or') {
320             $result = $this->db->db_query("
321                SELECT DISTINCT photo_id
322                   FROM photo_tags pt
323                INNER JOIN photos p
324                   ON p.id=pt.photo_id
325                WHERE pt.tag_id IN (". $selected .")
326                ORDER BY p.time ASC
327             ");
328          }
329          elseif($_SESSION['tag_condition'] == 'and') {
330
331             /* Join together a table looking like
332
333                pt1.photo_id pt1.tag_id pt2.photo_id pt2.tag_id ...
334
335                so the query can quickly return all images matching the
336                selected tags in an AND condition
337
338             */
339
340             $query_str = "
341                SELECT DISTINCT pt1.photo_id
342                   FROM photo_tags pt1
343             ";
344
345             for($i = 0; $i < count($_SESSION['selected_tags']); $i++) {
346                $query_str.= "
347                   INNER JOIN photo_tags pt". ($i+2) ."
348                      ON pt1.photo_id=pt". ($i+2) .".photo_id
349                ";
350             }
351             $query_str.= "WHERE pt1.tag_id=". $_SESSION['selected_tags'][0];
352             for($i = 1; $i < count($_SESSION['selected_tags']); $i++) {
353                $query_str.= "
354                   AND pt". ($i+1) .".tag_id=". $_SESSION['selected_tags'][$i] ."
355                "; 
356             }
357             $result = $this->db->db_query($query_str);
358          }
359
360          while($row = $this->db->db_fetch_object($result)) {
361             array_push($tagged_photos, $row['photo_id']);
362          }
363          return $tagged_photos;
364       }
365
366       /* return all available photos */
367       $result = $this->db->db_query("
368          SELECT DISTINCT photo_id
369             FROM photo_tags pt
370          INNER JOIN photos p
371             ON p.id=pt.photo_id
372          ORDER BY p.time ASC
373       ");
374       while($row = $this->db->db_fetch_object($result)) {
375          array_push($tagged_photos, $row['photo_id']);
376       }
377       return $tagged_photos;
378
379    } // getPhotoSelection()
380
381    public function showPhotoIndex()
382    {
383       $photos = $this->getPhotoSelection();
384
385       $count = count($photos);
386
387       if(!$_SESSION['begin_with'] || $_SESSION['begin_with'] == 0)
388          $begin_with = 0;
389       else
390          $begin_with = $_SESSION['begin_with'];
391
392       if($this->cfg->rows_per_page == 0)
393          $end_with = $count;
394       else
395          $end_with = $begin_with + ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
396
397    
398       $rows = 0;
399       $cols = 0;
400       $images[$rows] = Array();
401       $img_height[$rows] = Array();
402       $img_width[$rows] = Array();
403
404       for($i = $begin_with; $i < $end_with; $i++) {
405
406          $images[$rows][$cols] = $photos[$i];
407
408          $thumb_path = $this->cfg->base_path ."/thumbs/". $this->cfg->thumb_width ."_". $this->getMD5($photos[$i]);
409
410          if(file_exists($thumb_path)) {
411             $info = getimagesize($thumb_path); 
412             $img_width[$rows][$cols] = $info[0];
413             $img_height[$rows][$cols] = $info[1];
414          }
415
416          if($cols == $this->cfg->thumbs_per_row-1) {
417             $cols = 0;
418             $rows++;
419             $images[$rows] = Array();
420             $img_width[$rows] = Array();
421             $img_height[$rows] = Array();
422          }
423          else {
424             $cols++;
425          }
426       } 
427
428       // +1 for for smarty's selection iteration
429       $rows++;
430
431       if(isset($_SESSION['searchfor']) && $_SESSION['searchfor'] != '')
432          $this->tmpl->assign('searchfor', $_SESSION['searchfor']);
433
434       if($this->cfg->rows_per_page != 0) {
435          $previous_start = $begin_with - ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
436          $next_start = $begin_with + ($this->cfg->rows_per_page * $this->cfg->thumbs_per_row);
437
438          if($begin_with != 0) 
439             $this->tmpl->assign("previous_url", "javascript:showPhotoIndex(". $previous_start .");"); 
440          if($end_with < $count)
441             $this->tmpl->assign("next_url", "javascript:showPhotoIndex(". $next_start .");"); 
442       }
443
444       $current_tags = "";
445       if($_SESSION['selected_tags'] != "") {
446          foreach($_SESSION['selected_tags'] as $tag)
447             $current_tags.= $tag .",";
448          $current_tags = substr($current_tags, 0, strlen($current_tags)-1);
449       }
450
451       $extern_link = "http://". $_SERVER['SERVER_NAME'] ."/index.php?mode=showpi&tags=". $current_tags;
452
453       $this->tmpl->assign('extern_link', $extern_link);
454       $this->tmpl->assign('count', $count);
455       $this->tmpl->assign('width', $this->cfg->thumb_width);
456       $this->tmpl->assign('images', $images);
457       $this->tmpl->assign('img_width', $img_width);
458       $this->tmpl->assign('img_height', $img_height);
459       $this->tmpl->assign('rows', $rows);
460       $this->tmpl->assign('columns', $this->cfg->thumbs_per_row);
461       $this->tmpl->show("photo_index.tpl");
462
463
464    } // showPhotoIndex()
465
466    public function showBubbleDetails($photo, $direction)
467    {
468       if($direction == "up")
469          $direction = "bubbleimg_up";
470       else
471          $direction = "bubbleimg_down";
472
473       $details = $this->get_photo_details($photo);
474       $orig_path = $this->translate_path($details['directory_path'])  ."/". $details['name'];
475
476       $image_url = "phpfspot_img.php?idx=". $photo ."&amp;width=". $this->cfg->bubble_width;
477
478       $filesize = filesize($orig_path);
479       $filesize = rand($filesize/1024, 2);
480
481       if(!file_exists($orig_path)) {
482          print "Photo ". $orig_path ." does not exist!<br />\n";
483          return;
484       }
485       
486       if(!is_readable($orig_path)) {
487          print "Photo ". $orig_path ." is not readable for user ". get_current_user() ."<br />\n";
488          return;
489       }
490
491       $img = getimagesize($orig_path);
492
493       $this->tmpl->assign('file_size', $filesize);
494       $this->tmpl->assign('width', $img[0]);
495       $this->tmpl->assign('height', $img[1]);
496       $this->tmpl->assign('file_name', $details['name']);
497       $this->tmpl->assign('image_id', $direction);
498       $this->tmpl->assign('image_url', $image_url);
499       $this->tmpl->show("bubble_details.tpl");
500
501    } // showBubbleDetails()
502
503    public function showCredits()
504    {
505       $this->tmpl->assign('version', $this->cfg->version);
506       $this->tmpl->assign('product', $this->cfg->product);
507       $this->tmpl->show("credits.tpl");
508
509    } // showCredits()
510
511    public function create_thumbnail($orig_image, $thumb_image, $width)
512    {  
513       if(!file_exists($orig_image))
514          return false;
515
516       $details = getimagesize($orig_image);
517       
518       /* check if original photo is a support image type */
519       if(!$this->parent->checkifImageSupported($details['mime']))
520          return false;
521
522       $meta = $this->get_meta_informations($orig_image);
523
524       $rotate = 0;
525       $flip = false;
526
527       switch($meta['Orientation']) {
528
529          case 1:
530             $rotate = 0; $flip = false; break;
531          case 2:
532             $rotate = 0; $flip = true; break;
533          case 3:
534             $rotate = 180; $flip = false; break;
535          case 4:
536             $rotate = 180; $flip = true; break;
537          case 5:
538             $rotate = 90; $flip = true; break;
539          case 6:
540             $rotate = 90; $flip = false; break;
541          case 7:
542             $rotate = 270; $flip = true; break;
543          case 8:
544             $rotate = 270; $flip = false; break;
545       }
546
547       $src_img = @imagecreatefromjpeg($orig_image);
548
549       if(!$src_img) {
550          print "Can't load image from ". $orig_image ."\n";
551          return false;
552       }
553
554       /* grabs the height and width */
555       $new_w = imagesx($src_img);
556       $new_h = imagesy($src_img);
557
558       // If requested width is more then the actual image width,
559       // do not generate a thumbnail
560
561       if($width >= $new_w) {
562          imagedestroy($src_img);
563          return true;
564       }
565
566       /* calculates aspect ratio */
567       $aspect_ratio = $new_h / $new_w;
568
569       /* sets new size */
570       $new_w = $width;
571       $new_h = abs($new_w * $aspect_ratio);
572
573       /* creates new image of that size */
574       $dst_img = imagecreatetruecolor($new_w, $new_h);
575
576       imagefill($dst_img, 0, 0, ImageColorAllocate($dst_img, 255, 255, 255));
577
578       /* copies resized portion of original image into new image */
579       imagecopyresampled($dst_img,$src_img,0,0,0,0,$new_w,$new_h,imagesx($src_img),imagesy($src_img));
580
581       /* needs the image to be flipped horizontal? */
582       if($flip) {
583          print "(FLIP)";
584          $image = $dst_img;
585          for($x = 0; $x < $new_w; $x++) {
586             imagecopy($dst_img, $image, $x, 0, $w - $x - 1, 0, 1, $h);
587          }
588       }
589
590       if($rotate) {
591          print "(ROTATE)";
592          $dst_img = $this->rotateImage($dst_img, $rotate);
593       }
594
595       /* write down new generated file */
596       $result = imagejpeg($dst_img, $thumb_image, 75);
597
598       /* free your mind */
599       imagedestroy($dst_img);
600       imagedestroy($src_img);
601
602       if($result === false) {
603          print "Can't write thumbnail ". $thumb_image ."\n";
604          return false;
605       }
606
607       return true;
608
609    } // create_thumbnail()
610
611    public function get_meta_informations($file)
612    {
613       return exif_read_data($file);
614
615    } // get_meta_informations()
616
617    public function check_config_table()
618    {
619       // if the config table doesn't exist yet, create it
620       if(!$this->cfg_db->db_check_table_exists("images")) {
621          $this->cfg_db->db_exec("
622             CREATE TABLE images (
623                img_idx int primary key,
624                img_md5 varchar(32)
625             )
626             ");
627       }
628
629    } // check_config_table
630
631    /**
632     * Generates a thumbnail from photo idx
633     *
634     * This function will generate JPEG thumbnails from provided F-Spot photo
635     * indizes.
636     *
637     * 1. Check if all thumbnail generations (width) are already in place and
638     *    readable
639     * 2. Check if the md5sum of the original file has changed
640     * 3. Generate the thumbnails if needed
641     */
642    public function gen_thumb($idx = 0, $force = 0)
643    {
644       $error = 0;
645
646       $resolutions = Array(
647          $this->cfg->thumb_width,
648          $this->cfg->bubble_width,
649          $this->cfg->photo_width,
650       );
651
652       /* get details from F-Spot's database */
653       $details = $this->get_photo_details($idx);
654
655       /* calculate file MD5 sum */
656       $full_path = $this->translate_path($details['directory_path'])  ."/". $details['name'];
657       $file_md5 = md5_file($full_path);
658
659       $this->_debug("Image [". $idx ."] ". $details['name'] ." Thumbnails:");
660
661       foreach($resolutions as $resolution) {
662
663          $thumb_path = $this->cfg->base_path ."/thumbs/". $resolution ."_". $file_md5;
664
665          /* if the thumbnail file doesn't exist, create it */
666          if(!file_exists($thumb_path)) {
667
668             $this->_debug(" ". $resolution ."px");
669             if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
670                $error = 1;
671          }
672
673          /* if the file hasn't changed there is no need to regen the thumb */
674          elseif($file_md5 != $this->getMD5($idx) || $force) {
675
676             $this->_debug(" ". $resolution ."px");
677             if(!$this->create_thumbnail($full_path, $thumb_path, $resolution))
678                $error = 1;
679
680          }
681       }
682
683       /* set the new/changed MD5 sum for the current photo */
684       if(!$error) {
685          $this->setMD5($idx, $file_md5);
686       }
687
688       $this->_debug("\n");
689
690    } // gen_thumb()
691
692    public function getMD5($idx)
693    {
694       $result = $this->cfg_db->db_query("
695          SELECT img_md5 
696          FROM images
697          WHERE img_idx='". $idx ."'
698       ");
699
700       if(!$result)
701          return 0;
702
703       $img = $this->cfg_db->db_fetch_object($result);
704       return $img['img_md5'];
705       
706    } // getMD5()
707
708    private function setMD5($idx, $md5)
709    {
710       $result = $this->cfg_db->db_exec("
711          REPLACE INTO images (img_idx, img_md5)
712          VALUES ('". $idx ."', '". $md5 ."')
713       ");
714
715    } // setMD5()
716
717    public function setTagCondition($mode)
718    {
719       $_SESSION['tag_condition'] = $mode;
720
721    } // setTagCondition()
722
723    public function startTagSearch($searchfor)
724    {
725       $_SESSION['searchfor'] = $searchfor;
726       $_SESSION['selected_tags'] = Array();
727
728       foreach($this->avail_tags as $tag) {
729          if(preg_match('/'. $searchfor .'/i', $this->tags[$tag]))
730             array_push($_SESSION['selected_tags'], $tag);
731       }
732
733    } // startTagSearch()
734
735    private function rotateImage($img, $degrees)
736    {
737       if(function_exists("imagerotate"))
738          $img = imagerotate($img, $degrees, 0);
739       else
740       {
741          function imagerotate($src_img, $angle)
742          {
743             $src_x = imagesx($src_img);
744             $src_y = imagesy($src_img);
745             if ($angle == 180) {
746                $dest_x = $src_x;
747                $dest_y = $src_y;
748             }
749             elseif ($src_x <= $src_y) {
750                $dest_x = $src_y;
751                $dest_y = $src_x;
752             }
753             elseif ($src_x >= $src_y) {
754                $dest_x = $src_y;
755                $dest_y = $src_x;
756             }
757                
758             $rotate=imagecreatetruecolor($dest_x,$dest_y);
759             imagealphablending($rotate, false);
760                
761             switch ($angle) {
762             
763                case 90:
764                   for ($y = 0; $y < ($src_y); $y++) {
765                      for ($x = 0; $x < ($src_x); $x++) {
766                         $color = imagecolorat($src_img, $x, $y);
767                         imagesetpixel($rotate, $dest_x - $y - 1, $x, $color);
768                      }
769                   }
770                   break;
771
772                case 270:
773                   for ($y = 0; $y < ($src_y); $y++) {
774                      for ($x = 0; $x < ($src_x); $x++) {
775                         $color = imagecolorat($src_img, $x, $y);
776                         imagesetpixel($rotate, $y, $dest_y - $x - 1, $color);
777                      }
778                   }
779                   break;
780
781                case 180:
782                   for ($y = 0; $y < ($src_y); $y++) {
783                      for ($x = 0; $x < ($src_x); $x++) {
784                         $color = imagecolorat($src_img, $x, $y);
785                         imagesetpixel($rotate, $dest_x - $x - 1, $dest_y - $y - 1, $color);
786                      }
787                   }
788                   break;
789
790                default: $rotate = $src_img;
791             };
792
793             return $rotate;
794
795          }
796
797          $img = imagerotate($img, $degrees);
798
799       }
800
801       return $img;
802
803    } // rotateImage()
804
805    private function get_photo_tags($idx)
806    {
807       $result = $this->db->db_query("
808          SELECT t.id, t.name
809          FROM tags t
810          INNER JOIN photo_tags pt
811             ON t.id=pt.tag_id
812          WHERE pt.photo_id='". $idx ."'
813       ");
814
815       $tags = Array();
816
817       while($row = $this->db->db_fetch_object($result))
818          $tags[$row['id']] = $row['name'];
819
820       return $tags;
821
822    } // get_photo_tags()
823
824    public function showTextImage($txt, $color=000000, $space=4, $font=4, $w=300)
825    {
826       if (strlen($color) != 6) 
827          $color = 000000;
828
829       $int = hexdec($color);
830       $h = imagefontheight($font);
831       $fw = imagefontwidth($font);
832       $txt = explode("\n", wordwrap($txt, ($w / $fw), "\n"));
833       $lines = count($txt);
834       $im = imagecreate($w, (($h * $lines) + ($lines * $space)));
835       $bg = imagecolorallocate($im, 255, 255, 255);
836       $color = imagecolorallocate($im, 0xFF & ($int >> 0x10), 0xFF & ($int >> 0x8), 0xFF & $int);
837       $y = 0;
838
839       foreach ($txt as $text) {
840          $x = (($w - ($fw * strlen($text))) / 2);
841          imagestring($im, $font, $x, $y, $text, $color);
842          $y += ($h + $space);
843       }
844
845       Header("Content-type: image/png");
846       ImagePng($im);
847
848    } // showTextImage()
849
850    private function checkRequirements()
851    {
852       if(!function_exists("imagecreatefromjpeg")) {
853          print "PHP GD library extension is missing<br />\n";
854          $missing = true;
855       }
856
857       if(!function_exists("sqlite3_open")) {
858          print "PHP SQLite3 library extension is missing<br />\n";
859          $missing = true;
860       }
861
862       /* Check for HTML_AJAX PEAR package, lent from Horde project */
863       ini_set('track_errors', 1);
864       @include_once 'HTML/AJAX/Server.php';
865       if(isset($php_errormsg)) {
866          print "PEAR HTML_AJAX package is missing<br />\n";
867          $missing = true;
868       }
869       ini_restore('track_errors');
870
871       if(isset($missing))
872          return false;
873
874       return true;
875
876    } // checkRequirements()
877
878    private function _debug($text)
879    {
880       if($this->fromcmd) {
881          print $text;
882       }
883
884    } // _debug()
885
886    public function checkifImageSupported($mime)
887    {
888       if(in_array($mime, Array("image/jpeg")))
889          return true;
890
891       return false;
892
893    } // checkifImageSupported()
894
895 }
896
897 ?>