Simple photo tagging with PHP and jQuery

Written by pelister. Posted in PHP

To call it as “photo tagging” is outright wrong, to be precise it should be called as image annotation or even sticky notes, which is the process of super-imposing a piece of information or data( called as tags) to a specific part of an image without changing the underlying image. You can have one or more tags for a single image. Most of us are already familiar with tags marked over group photos on social media sites, but this type of tagging information onto an image serves wider purpose. Annotation or Image tagging ( to sound familiar ) can be used in the following scenarios.

  • To highlight errors or provide some corrections, write comments or suggestions on any kind of design.
  • Can be helpful as a presentational markup.
  • Annotation on plans and designs will be helpful in remembering the concept and idea and discussing it further.
  • Markup on graphs and scientific images.
  • Name of people or person on photos. ( I bet you already know this he..he.. )

image-taggingAll right, my intent was to write a piece of software code with PHP and jQuery to annotate images, store them in database and retrieve them when a particular image is loaded. Then I came across various photo tagging scripts and plugins, some are too complex, some are simple but doesn’t have the expected feature. Here is what I came up with, a simple code without any plugin or complexity. But before getting into the code I would like to present a basic workflow on how image annotation works.

annotation-workflow

Now lets take a look into the code.  Here is the break-up of what is to be done.

  1. Present an image( it can be one within a gallery, or an image embedded in an article ).
  2. When the image has been loaded, we send an ajax request to retrieve the annotations for the particular image and load them if available.
  3. Setup interactivity for all the annotations with jQuery. So that each annotation appears only when mouse pointer moves over annotated or tagged area.
  4. Setup event handlers to create and remove annotations.

The PHP that presents the image to the user.

  <div id="container">
  <div id="imgtag"> 
    <?php 
    $sql = "SELECT * FROM picture WHERE id=1";
    $qry = mysql_query( $sql );
    $rs = mysql_fetch_array( $qry );
    ?>
    <img id="<?php echo $rs['id']; ?>" src="<?php echo $rs['name']; ?>" /> 
    <div id="tagbox">
    </div>
  </div> 
  <div id="taglist"> 
    <ol> 
    </ol> 
  </div> 
  </div>

Every image we insert into gallery or article will be given unique id, which will be used to retrieve the image. So you can see in the above code we construct a query with id=1, which is image id. You can make this dynamic by replacing the number with a variable or value from query string. We have also placed the image within a div name imgtag, along with 2 more div elements which will be used to place the annotation data. Now after presenting the image, the rest is taken care by jQuery.

jQuery Code for capturing the Click event on the image.

    $("#imgtag img").click(function(e) { // make sure the image is clicked
      var imgtag = $(this).parent(); // get the div to append the tagging list
      mouseX = ( e.pageX - $(imgtag).offset().left ) - 50; // x and y axis
      mouseY = ( e.pageY - $(imgtag).offset().top ) - 50;
      $( '#tagit' ).remove( ); // remove any tagit div first
      //insert an input box with save and cancel operations.
      $( imgtag ).append( '<div id="tagit"><div class="box"></div><div class="name"><div class="text">Type any name or tag</div><input type="text" name="txtname" id="tagname" /><input type="button" name="btnsave" value="Save" id="btnsave" /><input type="button" name="btncancel" value="Cancel" id="btncancel" /></div></div>' );
      $( '#tagit' ).css({ top:mouseY, left:mouseX });
      
      $('#tagname').focus();
    });

Now when the user clicks on the image, the above code will place an input box with save and cancel buttons, so user can enter the required tag or info to be saved. Clicking save after entering the tag will send an ajax request to save the tag. The following jQuery code will send the x and y position and the tag to the server.

    $( document ).on( 'click',  '#tagit #btnsave', function(){
        name = $('#tagname').val();
	var img = $('#imgtag').find( 'img' );
	var id = $( img ).attr( 'id' );
      $.ajax({
        type: "POST", 
        url: "savetag.php", 
        data: "pic_id=" + id + "&name=" + name + "&pic_x=" + mouseX + "&pic_y=" + mouseY + "&type=insert",
        cache: true, 
        success: function(data){
          viewtag( id );
          $('#tagit').fadeOut();
        }
      });
      
    });

The following PHP code will store the annotated area, that is x and y position and the user entered tag into database.

if( !empty( $_POST['type'] ) && $_POST['type'] == "insert" )
{
  $id = $_POST['pic_id'];  
  $name = $_POST['name'];
  $pic_x = $_POST['pic_x'];
  $pic_y = $_POST['pic_y'];
  $sql = "INSERT INTO image_tag (pic_id,name,pic_x,pic_y) VALUES ( $id, '$name', $pic_x, $pic_y )";
  $qry = mysql_query($sql);
}

Now we have successfully stored the tag in to the database. All we have to do is retrieve the X and Y position of the annotated area and the tags  associated with the image. You may have multiple annotations per image( e.g  a group photo or a natural scenery ), we must load them all. We will load two kinds of data here.

  1. Tag boxes with data to be placed over the image.
  2. The list of tags with an option to remove the tag.

jQuery code to retrieve the tags.

$.post( "taglist.php" ,  "pic_id=" + pic_id, function( data ) {
  	$('#taglist ol').html(data.lists);
	$('#tagbox').html(data.boxes);
}, "json");

You can see in the above code snippet, we are expecting a json object which contains two different data

  • boxes – those are the tag boxes to be place on the image.
  • lists – those are list with optional tag removing feature.

Now you take a look into the PHP code that sends json object.

$sql = "SELECT * FROM image_tag WHERE pic_id=" . $_POST[ 'pic_id' ] ;
$qry = mysql_query($sql);
$rs = mysql_fetch_array($qry);

$data['boxes'] = '';
$data['lists'] = '';

if ($rs){
  do{
	
    $data['boxes'] .= '<div class="tagview" style="left:' . $rs['pic_x'] . 'px;top:' . $rs['pic_y'] . 'px;" id="view_'.$rs['id'].'">';
	$data['boxes'] .= '<div class="square"></div>';
	$data['boxes'] .= '<div class="person" style="left:' . $rs['pic_x'] . 'px;top:' . $rs['pic_y']  . 'px;">' . $rs[ 'name' ] . '</div>';
	$data['boxes'] .= '</div>';
	
	$data['lists'] .= '<li id="'.$rs['id'].'"><a>' . $rs['name'] . '</a> (<a class="remove">Remove</a>)</li>';
	
  }while($rs = mysql_fetch_array($qry));
}

echo json_encode( $data );

In the above code we place the div in $data[‘boxes’] and lists in $data[‘lists’] and send it as a json object, we did this way so that we can eliminate two separate ajax requests for tag boxes and lists.

Now we have placed the tag boxes over the image, but it should not appear unless the user hovers the mouse over the image. the trick lies in the CSS code, we just set the opacity of the div to 0(zero), so that the div disappears completely. So when the user hover the mouse over the annotated/tagged area we set the opacity of the div to 1, so it appears. Here is the jQuery code that does the trick.

	// mouseover the tagboxes that is already there but opacity is 0.
	$( '#tagbox' ).on( 'mouseover', '.tagview', function( ) {
		var pos = $( this ).position();
		$(this).css({ opacity: 1.0 }); // div appears when opacity is set to 1.
	}).on( 'mouseout', '.tagview', function( ) {
		$(this).css({ opacity: 0.0 }); // hide the div by setting opacity to 0.
	});


So we have chained the mouseover and mouseout events which sets the opacity to 1 and 0 respectively for the tag boxes which has the class name “tagview“. we have done the same to capture the mouse hover on the lists, and display the tags accordingly. We also have implemented remove tag feature which basically sends an ajax request and removes the tag. You can download the full working code here. Hope you like it.

Demo 

Download

1 Star2 Stars3 Stars4 Stars5 Stars (24 votes, average: 4.25 out of 5)
Loading...
pelister
3D modeler and Web designer. Founder of Techlister. Love to build sites using WordPress and Joomla. Interested in Astronomy, project member of SETI (Search for Extra Terrestrial Intelligence).

Tags: , ,

Comments (11)

  • astro

    |

    is this possible to join with an autocomplete jquery? so when user click on image then the text box show another source, like facebook image tagging..

    Reply

      • astro

        |

        thanks for reply sir..

        I’ve tried to join autocomplete with your simple photo tagging.. but the text box not match autocomplete result.. with using id of input from textfield, for this case i’m using “#tagname” I call it with jquery. but there are no result match.

        I give you, my simple code, I add this on index.php file:

        $(document).ready(function(){
        $(“#tagname”).autocomplete(“autocomplete.php”, {selectFirst: true});

        and my autocomplete.php code like :

        $sql = “SELECT * FROM country ORDER BY slno DESC”;
        $result = mysql_query($sql) or die(mysql_error());
        if($result)
        {
        while($row=mysql_fetch_array($result))
        {
        echo $row[‘country’].”\n”;
        }
        }
        });

        can you give me advice about that? thank’s so much before sir

        Reply

        • pelister

          |

          Hi astro, you need to send an ajax request to invoke the autocomplete.php

          You have written –
          $(“#tagname”).autocomplete(
          jquery does not have .autocomplete(), you need to write

          $.post( “autocomplete.php”, { data }, callback function() { process all output here } )

          Reply

          • astro

            |

            sorry sir.. I’m confused how to implement as your advice, I’m new using ajax..

            I follow usage of jquery autocomplete, this is my code:
            1. I include jquery autocomplete on specific folder.

            2. I write my script, with call specific input id.(#tagdiv)

            $(document).ready(function(){
            $(“#tagname”).autocomplete(“autocomplete.php”, {selectFirst: true});
            });

            3. on my autocomplete.php, i write, this code
            $g=$_GET[‘q’];
            $my_data=mysql_real_escape_string($g);

            $sql = “SELECT * FROM country WHERE country LIKE ‘%$my_data%’ ORDER BY slno DESC”;
            $result = mysql_query($sql) or die(mysql_error());
            if($result)
            {
            while($row=mysql_fetch_array($result))
            {
            echo $row[‘country’].”\n”;
            }
            }

            on default textfield, at php file which i’ve made, this way was worked, but not for this tagging. Can u help me please,..?

            Reply

          • pelister

            |

            Pls provide details on what you are trying to do, if possible any page where I can see your code implemented and working and the feature you look for.

            Reply

          • astro

            |

            Thanks a lot sir for your time…

            I give you the code, i only add an autocomplete on your photo tagging.
            you can download it on http://www.filedropper.com/tag

            maybe you can see it,..

            Reply

          • astro

            |

            It has resolved sir.. I join it with uiautocoplete.. and work .. thanks for your help 🙂

            Reply

          • pelister

            |

            You have done it Astro. Happy its working for you. If possible post me the link so that I can see how it works.

            Reply

  • David

    |

    Hello!

    Fantastic, you would not believe how long have I been searching for something like this. I bought some crap off codecanyon, that never worked well, and this is awesome.

    Although, I have the same issue as the previous guy, i have a perfectly working autocomplete search, which i just wanted to redirect onto your #tagname , but nothing comes up anywhere, and console says uncaught render to autocomplete UI. Which is insane, since redirecting that to the normal input field below, works.

    Here is the link: https://dl.dropboxusercontent.com/u/78706473/annotation.zip
    the table is in it as well that I use as a sample database to test it.

    Could you take a look at it why doesn’t it work properly? 🙂 Thanks!

    Reply

  • David

    |

    I wish it would be fancybox ready 🙂 In the last hour or so (since the autocomplete still doesn’t work)I tried to handle the part as just showing the boxes on hover and the tags, but no removal, and no interaction. Imagining as a normal non admin user. It’d be nice to have the boxes and tags appear over a fancybox or any lightbox alternative, which should be completely doable. No interaction needed, only pulling the ajax request on the pic_id that is stored per image over html, when opening via fancybox.

    Once again, wonderful plugin, with a little work, you could codecanyon it for gazillions of credits 🙂

    Reply

Leave a comment

Techlister© - 2012