I have recently been using a jQuery plugin called imgAreaSelect, which allows you to crop images. I wanted to use it with my PHP site so that thumbnails could be cropped and created.

GD Library is a PHP library that allows manipulation of images, in particular it can create new images.  It may need to be installed on some servers, but I found it already installed on my host and on MAMP (my local server). Combining this with imgAreaSelect and we can feed the coordinates that are cropped to create the new thumbnail.  So here’s how

Firstly, attach all the jQuery and plugin scripts in the head tags:

<head>
        <script type="text/javascript" src="js/jquery.min.js">
        </script>
        <script type="text/javascript" src="js/jquery.imgareaselect.js">
        </script>

Now still in the head tags, the plugin needs to be called, here I am pointing it to an image with an id of ‘crop’. I am also selecting the aspect ratio as 1:1 (to keep the thumbnail a square).

<script type='text/javascript'> 
    $(function () {
        $('#crop').imgAreaSelect({ aspectRatio: '1:1', 
onInit: preview, onSelectChange: preview });
    });

The other thing I have done here is called a function named ‘preview’ onInit (on initialisation, when the plugin is first loaded) and onSelectChange (whenever the crop area is changed). This preview function is created below and allows the thumbnail to be previewed live on the same page. It’s not 100% necessary but quite useful:

	function preview(img, selection) {
	    if (!selection.width || !selection.height)
	        return;
 
	    var scaleX = 100 / selection.width;
	    var scaleY = 100 / selection.height;
 
	    $('#preview img').css({
	        width: Math.round(scaleX * ".$width." ),
	        height: Math.round(scaleY * ".$height." ),
	        marginLeft: -Math.round(scaleX * selection.x1),
	        marginTop: -Math.round(scaleY * selection.y1)
	    });

If doing this preview function, you need to give it the width and height of the original image. I have done this by putting each in variables $width and height, using the getImageSize PHP function. This means that you have to echo the JavaScript after declaring the variables.

I have pointed the preview function to a img contained within an element that has the id: ‘preview’. So somewhere on my page I need to insert the following html:

<div id="preview">
<img src="image.jpg" />
<!--This is the same image file as what is being cropped, the javascript
we inserted before will resize it-->
</div>

Now the important part, we need to pass the selection into a form so when it’s submitted we can retrieve the coordinates from the $_POST array. So (continued straight after the code before, still in the head tags), we insert this:

    	$('#x1').val(selection.x1);
    	$('#y1').val(selection.y1);
    	$('#x2').val(selection.x2);
    	$('#y2').val(selection.y2);
    	$('#w').val(selection.width);
    	$('#h').val(selection.height);  
    }
    $(document).ready(function(){
        $('#saveThumb').click(function(){
            var x1 = $('#x1').val();
            var y1 = $('#y1').val();
            var x2 = $('#x2').val();
            var y2 = $('#y2').val();
            var w = $('#w').val();
            var h = $('#h').val();
            if (x1 == "" || y1 == "" || x2 == "" || y2 == "" || w == "" || h == "") {
                alert("You must make a selection first");
                return false;
            }
            else {
                return true;
            }
        });
    });
</script>
</head>

This also includes validation to insure an crop area has been selected.
Now this goes into the body of the page:

<img id='crop' src='image.jpg' />
<p><div id='preview'>
<img src='image.jpg' /></div>
<form name='uploadThumbnail' action='thispage.php' method='post'>
<input type='hidden' name='x1' value='' id='x1' />
<input type='hidden' name='y1' value='' id='y1' />
<input type='hidden' name='w' value='' id='w' />
<input type='hidden' name='h' value='' id='h' />
<input type='hidden' name='extension'  value='jpg' />
<input type='hidden' name='filename'  value='image.jpg' />
<input type='hidden' name='width'  value='$width' />
<input type='hidden' name='height'  value='$height' />
<input type='submit' name='uploadThumbnail' value='Save Thumbnail' id='saveThumb' />";

The image crop page is now complete, we use all these hidden fields to pass the details of the image to the next page, where we will use this data to resize the image correctly.
Here’s how I created the thumbnail using the gd library.

$thumbWidth = 100;
$thumbHeight = 100;
$newFilename = 'newfilename.jpg';
extract($_POST); // Extract the $x1, $y1, $w, $h, $extension, 
//$filename, $width, $height variables
 
//Now lets create the thumbnail
 
    // GD Function List
    $gdExtensions = array (
    'jpg'=>'JPEG',
    'gif'=>'GIF',
    'bmp'=>'WBMP',
    'png'=>'PNG'
    );
 
    $check = false;
 
    $gdExtension = $gdExtensions[$extension];
    $function_to_read = "ImageCreateFrom".$gdExtension;
    $function_to_write = "Image".$gdExtension
 
    // Read the source file
    $source_handle = $function_to_read($filename);
 
    if ($source)
    {
        // Create a blank image
        $destination_handle = ImageCreateTrueColor($thumbWidth, $thumbHeight);
 
        // Put the cropped area onto the blank image
        $check = ImageCopyResampled($destination_handle, $source_handle, 0, 0, $x1, $y1, $thumbWidth, $thumbHeight, $w, $h);
    }
 
    // Save the image
    $function_to_write($destination_handle, $newFilename);
    ImageDestroy($destination_handle);
 
    // Check for any errors
    if ($check)
    {
        echo "Thumbnail created";
    } else
    {
        echo "Thumbnail failed to create";
    }

So that should be thumbnail created, the important part of the PHP is the ImageCopyResampled($destination_handle, $source_handle, 0, 0, $x1, $y1, $thumbWidth, $thumbHeight, $w, $h); function, which writes to the image. The correct way to pass through the data from imgAreaSelect is the way shown here.

Inserting before and swapping rows in mySQL

Posted August 25th, 2009. Filed under PHP

The logic behind inserting a record is to increment every record in front of it (that is, to increment the field that you order the table by), so that a space is given.  Swapping records is a bit more tricky, even though you are simply exchanging data between two rows, at some point both pieces of data will be the same (between updating the first and second record).  So doing this on a primary key field is not an option.  I can also imagine it’s best to avoid changing data whatsoever on the primary key field, as it’s use is for reference and not really for order, problems could also later occur when tables are linked together.

So an extra field called ‘position’ was created, and the rest was done like this:

Inserting:
First we need to know the position of the record we are inserting before. I’ll assume this has been done and the position has been placed in a variable called $position. Then the query to increment each position ahead would go like this:

$query = "UPDATE tablename SET position = CASE 
WHEN position >= $position THEN position+1 
ELSE position END";
$result = mysql_query($query);

Now all the records ahead have increased position by one, all done in one query. I was originally using a loop to go through each record one by one. Using a CASE and WHEN clause is obviously much better. One thing to make sure is that the ELSE clause is put in (or mySQL will update all records).
Now to insert the new record we can use the original $position variable (as this will now be free).

Swapping:
I found this a bit more more difficult than inserting, but managed it okay like this…

Again, I’m assuming the position of the field you wish to swap is in a variable called $position. In case of moving up or moving the record down, I do this through $_GET['action'].

if($_GET['action'] == 'moveup'){
            $operator = '>=';
            $direction = 'ASC';
}elseif($_GET['action'] == 'movedown'){
            $operator = '<=';
            $direction = 'DESC';
}

These variables are created for the next query, the next step is to perform this query to get the two records to switch and put them in an array

$query = "SELECT position FROM tablename 
WHERE position $operator $position 
ORDER BY position $direction 
LIMIT 2";
$result = mysql_query($query);
	$linksToSwictch = array();  // Create the array
	while($row = mysql_fetch_array($result)){
		$linksToSwitch[] = $row[0];
	}

Now we have the array we can use an IF inside a mySQL query to switch the positions…

            if (count($linksToSwitch) == 2) 
// This conditional makes sure there are two links to switch 
// (so trying to move the highest record up or the lowest record down 
// nothing will be executed)
            {
                $newPos = $linksToSwitch[0];
                $oldPos = $linksToSwitch[1];
                $query = "UPDATE tablename 
                SET  `position` = 
                IF( position = $oldPos, $newPos, $oldPos ) 
                WHERE position IN ( $oldPos, $newPos )";
                $result = mysql_query($query);
            }

Having installed galleria on my webpage, I then wanted to align the gallery vertically inside the containing div.

Unfortunatley, there is little CSS support to do this, vertical-align is a property that does not work for images,  and only really works for text appearing next to images or in table-cells.  (Apparently, this property maybe improved for CSS3).

I figured out a way to use Galleria’s onImage : function, which handles anything every time an image is loaded.  So adding the following code will insert a class to any landscape image, and removes it for portrait ones:


if (image.height() < image.width()) {
$('#main_image').addClass('landscape');
} else {
$('#main_image').removeClass('landscape');
}

This can also be extended to be used for other means.  For example, in one gallery I wanted the first image to have some text appearing next to it.  To do this, I created two separate CSS classes to hide and show the text and used this code to flip between them:


if (image.attr('src') == "images/imageWithText.jpg") {
$('#main_image').addClass('showText');
$('#main_image').removeClass('hideText');
} else {
$('#main_image').removeClass('showText');
$('#main_image').addClass('hideText');
}

An example of this in use can be found here.

Using jCarousel with galleria jQuery plugins

Posted August 4th, 2009. Filed under JavaScript

Galleria – a JavaScript image gallery, written in jQuery, creates a gallery (with thumbnails) from a list of images. It’s simple to use, you just attach the script, call it and point it to a <ul> on the page. Like this:

<link href="galleria.css" rel="stylesheet" type="text/css" media="screen"> 
<script type="text/javascript" src="jquery.js"></script> 
<script type="text/javascript" src="jquery.galleria.js"></script> 
<script type="text/javascript"> 
jQuery(function($) { $('ul.gallery').galleria(); }); 
</script>

Combining this with jCarousel, which is another jQuery plugin, and you can scroll through a list of thumbnails at the same time. The two compliment each other nicely.

jCarousel works in a similar way to Galleria. Attach it, call it and point it to a list, so when using with Galleria, point both plugins to the same list.

Combining the two took a bit of tweaking and fiddling, but was overall a simple enough task.

The main problems arose from the css that both plugins require (each plugin comes with a stylesheet included). I used the tango skin that came with jCarousel and copied the contents of the css file to the galleria stylesheet, so I had everything required for the gallery on one. I then stripped down the stylesheet and altered what I needed, step-by-step. Firebug was an invaluable tool in helping me find what styles were actually being used and what weren’t. Once I had got it working okay I inserted the gallery into the website and I was done.

You can see the final result at http://www.mikereedlondon.com/Html/AnIndianWedding.html

Here’s the full code inserted into the <head> tags.

<script type="text/javascript" src="../Assetts/jquery.js"></script>  // Attach the jQuery file - downloadable from the jQuery website
<script type="text/javascript" src="../Assetts/jquery.jcarousel.js"></script>  // Attach the jCarousel file
<script type="text/javascript" src="../Assetts/jquery.galleria.js"></script> // Attach the galleria file
 
// Call the plugins
<script type="text/javascript">
jQuery(document).ready(function() {
    jQuery('ul#gallery').jcarousel({
        // This calls the jCarousel script, points it to ul#gallery and displays and scrolls 8 thumbnails at a time
scroll: 8,
visible: 8
 
    });
});
 
// Now lets call the galleria code
jQuery(function($) { $('ul#gallery').galleria({
			history   : true, // activates the history object for bookmarking, back-button etc.
			clickNext : true, // helper for making the image clickable
			insert    : '#main_image', // the containing selector for our main image
			onImage   : function(image,caption,thumb) { // image effects for the main image are added here
 
				// fade in the image & caption
				if(! ($.browser.mozilla && navigator.appVersion.indexOf("Win")!=-1) ) { // FF/Win fades large images terribly slow
					image.css('display','none').fadeIn(1000);
				}
 
				// fetch the thumbnail container
				var _li = thumb.parents('li');
 
				// fade out inactive thumbnail
				_li.siblings().children('img.selected').fadeTo(500,0.3);
 
				// fade in active thumbnail
				thumb.fadeTo('fast',1).addClass('selected');
			},
			onThumb : function(thumb) { // thumbnail effects goes here
 
				// fetch the thumbnail container
				var _li = thumb.parents('li');
 
				// if thumbnail is active, fade all the way.
				var _fadeTo = _li.is('.active') ? '1' : '0.3';
 
				// fade in the thumbnail when finnished loading
				thumb.css({display:'none',opacity:_fadeTo}).fadeIn(1500);
 
				// hover effects
				thumb.hover(
					function() { thumb.fadeTo('fast',1); },
					function() { _li.not('.active').children('img').fadeTo('fast',0.3); } // don't fade out if the parent is active
				)
			}
		});
	});
 
</script>