php imagick round corner box with dropshadow

In this post I will show you how to create a rounded corner box with a drop shadow. First set your background color, foreground color, and the color of the drop shadow.

Once you’ve set up your colors, the script will create two identical imagick objects, one for the background, and one for the foreground. The background is just a base file where you will composite over the drop shadow image and the foreground rounded rectangle.

First the script creates a rounded rectangle within the bounds of the background image with space enough to not cut off the drop shadow. Once this rectangle is drawn on the second “over” image, the script applies a gaussian blur to the image to create the effect of a drop shadow. Once this is done, the script draws another identical rounded rectangle over the drop shadow, only this time with the foreground color rather than the drop shadow color.

After thats all taken care of, the script composites the drop shadow/round rectangle image over the background image that was created first. And, its done. Uncomment the caching code to write the resulting file to disk.

<?
$background = "#FFFFFF";
$foreground = "#EAEAEA";
$shadow = "#666666";
 
//$cachefile = './path/to/your/cachefile.png';
//if (!file_exists($cachefile)) {
 
	try{
 
		$canvas = new Imagick();
		$canvas->newImage(200, 200, $background, "png" );
 
		$box_over = new Imagick();
		$box_over->newImage(200, 200,  $background, "png" );
 
		$draw = new ImagickDraw();
		$draw->setFillColor($shadow);
		$draw->roundRectangle(10, 10, 190, 190, 10, 10);
 
		$box_over->drawImage($draw);
		$box_over->blurImage(8, 5);
 
		$canvas->compositeImage($box_over, imagick::COMPOSITE_OVER, 0, 0);
 
		$draw = new ImagickDraw();
		$draw->setFillColor($foreground);
		$draw->roundRectangle(10, 10, 190, 190, 10, 10);
 
		$box_over->drawImage($draw);
 
		$canvas->compositeImage($box_over, imagick::COMPOSITE_OVER, 0, 0);
 
		$canvas->setImageFormat('jpeg'); 	
 
		//$canvas->writeImage($cachefile);
 
		header( "Content-Type: image/jpg" );
		echo $canvas;
 
		$canvas->clear();
		$canvas->destroy();
 
 
	}catch(Exception $e){
		echo 'Error: ',  $e->getMessage(), "";
	}
 
/*
}else{
 
	$canvas = new imagick($cachefile);
	header("Content-Type: image/png");
	echo $canvas;
 
}
*/
 
?>

NOTE: the cachefile folder must be writable by the server.

php imagick button with round corners and a bezier curve

This post involves a little more complex example of what imagick can do. I am going to show you how to use the draw object to create an button which has rounded corners and a multi-colored curve accent using the “bezier” function of the ImagickDraw object.

First, lets get things set up. We are using four colors for this example. The border color, the accent color, the bezier curve color, and the font color. The bezier curve color in this example is placed over the accent color at 50% alpha to darken it. If you want a specific color, simply change the fill alpha value to 1 and change the bezier color to whatever you want. Note that this example’s image dimensions (as well as the coordinates of the bezier curve) are specific to the text “go” and the font sizes specified. If you want to change the text, you will have to play with these values to make it look right.

Once you’ve set up your colors, the script creates a new imagick object with background color of what you’ve specified in the “accent” color. The script then creates a new ImagickDraw object for the bezier curve. Next is the array of coordinates for the bezier curve to follow. You can have as many points in the curve as you want, but remember that the last point to have in the array will automatically be connected to the first point by the ImagickDraw object. You’ll notice that this script ends it’s curve well outside the x bounds of the image, but the y portion of the coordinate is at 0. This is done so when the draw object connects the first and last points, its at the top of the image and not cutting through the middle of the image making it look wacky.

The rest of the script is fairly straight forward. It continues adding to the draw object by setting the alpha value of the fill color to 1 for the text it’s about to write on the image. Then it draws the bezier curve and the text to the first canvas it set up. It then rounds the edges of the canvas to get the rounded corner effect.

The last step of the script is to create the border, or in this example, a rounded corner fill image that is slightly larger than the canvas the script just created with the text and the bezier curve. Once the corners are rounded on this new canvas, the script composites the first image on top of the second. And its done. The resulting image is outputted to the browser. Uncomment the caching code if you wish to write the resulting image to the server.

<?
 
$border = "#000000";
$accent = "#1365B1";
$bezier = "#000000";
$fontcolor = "#FFFFFF";
$text = "go";
 
$fontfile = "/path/to/your/fontfile.ttf";
 
//$cachefile = './path/to/your/cachefile.png';
//if (!file_exists($cachefile)) {
 
 
	try{
 
		$canvas = new Imagick();
		$canvas->newImage(30, 24, $accent, "png");
 
		$draw = new ImagickDraw();
 
		$draw->setFillColor($bezier);
		$draw->setFillAlpha(.5);
		$draw->bezier(
			array(
				 array("x" => 0, "y" => 0),
				 array("x" => 5, "y" => 8),
				 array("x" => 10, "y" => 11),
				 array("x" => 15, "y" => 15),
				 array("x" => 23, "y" => 18),
				 array("x" => 35, "y" => 30),
				 array("x" => 55, "y" => 0)
			 )
		);
 
		$draw->setFillAlpha(1);
		$canvas->drawImage($draw);
		$draw->setFontSize(16);
		$draw->setFillColor($fontcolor);
		$draw->setFont($fontfile);
		$canvas->annotateImage($draw, 7, 16, 0, $text);
		$canvas->roundCorners(2,2);
 
		$canvas2 = new Imagick();
		$canvas2->newImage( 32, 26, $border, "png" );	
		$canvas2->roundCorners(2,2);
		$canvas2->setImageFormat('png');
 
		$canvas2->compositeImage($canvas,Imagick::COMPOSITE_OVER,1,1);
 
		header( "Content-Type: image/png" );
		echo $canvas2;
 
 
		$canvas->clear();
		$canvas->destroy();
		$canvas2->clear();
		$canvas2->destroy();
 
		//$canvas2->writeImage($cachefile);
 
	}catch(Exception $e){
		echo 'Error: ',  $e->getMessage(), "";
	}
 
/*
}else{
 
	$canvas = new imagick($cachefile);
	header("Content-Type: image/png");
	echo $canvas;
 
}
*/
 
?>

NOTE: the cachefile folder must be writable by the server.

php imagick add round corners to a jpg image

One might think this would be an easy task, and it is, unless you want it to look good. Unfortunately, imagick really only performs well when processing images with an alpha channel. I’ve found that PNG format works best. So, to add rounded corners to a jpg image with php’s imagick object, there are a few steps involved.

First, you have to create an imagick object from the source image. Then, convert it to PNG format before applying the rounded corners. Once in PNG format, the script applies the rounded corners. If you dont care about having the large size of a png file, you can simply output the the browser at this point, but, if you want the smaller file size of a jpg, you must take a few more steps.

After adding the rounded corners to your now PNG file, you must create another imagick image object of the same size as your original image, with your desired background color, of image type jpg. Then, you composite the rounded corner png over the new solid background color image you just created.

Now that you have your rounded corner image over the correct background and in jpg format, you can set the image compression type and quality. Once this is done, you are ready to output the resulting jpg to the browser. There is cache code commented out if you would like to save the resulting jpg to disk.

<?
 
$background = "#FFFFFF";
$imagefile = "/path/to/your/image.jpg";
$cornerradius_x = 50;
$cornerradius_y = 50;
$quality = 70;
 
//$cachefile = '/path/to/your/cachedimage.jpg';
//if (!file_exists($cachefile)) {
 
 
	try{
 
		$canvas = new Imagick($imagefile);
 
		$canvas->setImageFormat('PNG');
		$canvas->roundCorners($cornerradius_x,$cornerradius_y);
 
		$canvas2 = new Imagick();
		$canvas2->newimage($canvas->getImageWidth(),  $canvas->getImageHeight(), $background, 'jpg');
 
		$canvas2->compositeImage($canvas, imagick::COMPOSITE_OVER, 0, 0);
 
		$canvas2->setImageFormat('JPG');
		$canvas2->setImageCompression(Imagick::COMPRESSION_JPEG);
		$canvas2->setImageCompressionQuality($quality); 
 
		//$canvas2->writeImage($cachefile);
 
		header( "Content-Type: image/jpg" );
		echo $canvas2;
 
		$canvas->clear();
		$canvas->destroy();
		$canvas2->clear();
		$canvas2->destroy();	
 
	}catch(Exception $e){
		echo 'Error: ',  $e->getMessage(), "";
	}
 
/*
}else{
 
	$canvas = new imagick($cachefile);
	header("Content-Type: image/png");
	echo $canvas;
 
}
*/
 
?>

NOTE: your “cachefile.jpg” folder must be writable by the server.

php imagick rounded rectangle with border

In this post I will show you how to “draw” a rounded rectangle with a border. This will involve creating a new ImagickDraw object, then applying your draw settings to an Imagick object.

First, set up all your colors, image size, border width, and corner radius. After you have set all the input variables, the script will calculate the dimensions of the rectangle you are going to draw within the size of your image. To do this you must subtract the size of the border from the height and width of your desired image size, otherwise the rectangle will get cut off.

Then the script creates a new Imagick object, and applies your background color. The next step is to create your ImagickDraw object and set your fill color. If you have specified a border width greater than 0, the script will set the stroke color and width. Now the script sets up the rounded rectangle with all the settings you specified in the first step and what the script had calculated for the rectangle’s height and width.

Once the ImagickDraw object is all set up, the script will “draw” it onto the Imagick canvas previously created. And Voila! You have a rounded rectangle with a border. Uncomment the caching code if you want to have the script save the resulting image to disk.

<?
 
$background = "transparent";
$fillcolor = "#C5E3FF";
$bordercolor = "#226FB6";
$borderwidth = 2;
$cornerradius = 10;
 
$height = 300;
$width = 300;
 
//$cachefile = 'path/to/your/cachefile.png';
//if (!file_exists($cachefile)) {
 
	try{
 
		$rectwidth = ($borderwidth>0?($width-($borderwidth+1)):$width-1);
		$rectheight = ($borderwidth>0?($height-($borderwidth+1)):$height-1);
 
		$canvas = new Imagick();
		$canvas->newImage($width, $height, $background, "png" );
 
		$draw = new ImagickDraw();
		$draw->setFillColor($fillcolor);
		if($borderwidth>0){
			$draw->setStrokeColor($bordercolor);
			$draw->setStrokeWidth($borderwidth);
		}
		$draw->roundRectangle($borderwidth, $borderwidth, $rectheight, $rectwidth, $cornerradius, $cornerradius);
 
		$canvas->drawImage($draw);
 
		//$canvas->writeImage($cachefile);
 
		header("Content-Type: image/png");
		echo $canvas;
 
		$canvas->clear();
		$sanvas->destroy();
 
	}catch(Exception $e){
		echo 'Error: ',  $e->getMessage(), "";
	}
 
/*
}else{
 
	$canvas = new imagick($cachefile);
	header("Content-Type: image/png");
	echo $canvas;
 
}
*/
 
?>

NOTE: “$cachefile” path must be writable by the server if you want to save the image to disk.

php imagick simple vertical or horizontal gradient image

In this post I will show you how to create a simple vertical gradient with php’s imagick object.

First, set some variables for the colors you want. In this example we are creating a simple 2 color gradient on a opaque background. Once you have specified which colors you want for the background, the top of the gradient, and the bottom of the gradient, the script will create a new imagick object using the png image type with the background color you have specified.

Next the script creates another imagick object which will be our gradient. On this new blank canvas, the script uses imagick’s “PseudoImage” function which can take a gradient color as it’s background color when creating the image. The first color is the top color of the gradient and the second color is the bottom color of the gradient.

Once this gradient image is created, the script then composites the gradient image on top if the first image you created. I have tried many different constants for imagick’s “compositeImage” function, but the one we will use for this example is “imagick::COMPOSITE_OVER” as we are just combining the two images without any fancyness. You can experiment with other constants such as “imagick::COMPOSITE_SCREEN” or “imagick::COMPOSITE_MULTIPLY” which behave much like photoshop layers. You can find all the available composite constants here.

Once the two images are combined, you can spit out the resulting image to the browser. The image in this example is opaque, but if you were to set the background color to the string “transparent” and one of the two gradient images to “transparent” you would get a png image with a transparent gradient.

If you want a horizontal gradient, simply uncomment one of the two “rotateImage” lines. The first will rotate the image counterclockwise, placing the color specified for the “top” of the gradient to the right, the second will rotate the image clockwise, placing the “top” color to the left side of the image.

If you wanted to create a gradient that was at an arbitrary angle, you would have to first make the image larger than you wanted, change the second parameter of the “rotateImage” function to the angle you want, and then use the “cropImage” function to get the gradient inside the bounds of the rotated rectangle which was just rotated. It might take some trial and error to get your crop bounds right, but that’s the general concept.

<?
 
$background = "#FFFFFF";
$top = "#73AEE5";
$bottom = "#003C74";
 
//$cachefile = 'path/to/your/cachefile.png';
//if (!file_exists($cachefile)) {
 
	try{
 
		$canvas = new Imagick();
		$canvas->newImage(80, 80, $background, "png");
 
		$gradient = new Imagick();
		$gradient->newPseudoImage(80, 80, "gradient:".$top."-".$bottom);
		$canvas->compositeImage( $gradient, imagick::COMPOSITE_OVER, 0, 0 );
 
		//$canvas->rotateImage($background, 90);
		//$canvas->rotateImage($background, -90);
		//$canvas->rotateImage($background, 45);
 
		//$canvas->cropImage(height, width, x, y);
		//$canvas->cropImage(50, 50, 30, 30);
 
		header( "Content-Type: image/png" );
		echo $canvas;
 
		//$canvas->writeImage($cachefile);
 
		$canvas->clear();
		$canvas->destroy();
 
		$gradient->clear();
		$gradient->destroy();
 
	}catch(Exception $e){
		echo 'Error: ',  $e->getMessage(), "";
	}
 
/*
}else{
 
	$canvas = new Imagick($cachefile);
	header("Content-Type: image/png");
	echo $canvas;
 
}
*/
?>

NOTE: I have commented out the code which will cache the image, but you can uncomment it if you want to save CPU cycles =) “$cachefile” path must be writable by the server.

php imagick simple font rendering with automatic image canvas size

I have been working with the image imagick library for PHP (ImageMagick) for some time now. I figure its time to share what I have discovered and figured out. There is very little documentation on this amazing library for PHP, but hopefully my hours of trial and error can help those who are interested in using it. For my first post, I will share a script I wrote which will render a png image for text using a ttf font.

The script uses imagick’s ImagickDraw object to first load the font, set the font size, orientation (GRAVITY_CENTER in this example, but you could set it to GRAVITY_NORTHWEST, or GRAVITY_SOUTHEAST), and fill color. Then the script gets the proper canvas size for the Imagick image object before the image is created, so you don’t need to worry about having to “know” what size the image needs to be. I have found that the metrics ImagickDraw outputs is not always perfect, so I have added a bit of padding to the image size that is calculated.

Next, the script creates a new Imagick image object and sets it’s size to what was calculated in the first step. It then “draws” the font that was set up in the first step. Once this is done, the script sets the image format (“PNG” in this example, but it could be a gif, or jpg if you want). The script finally saves the cache file, then sets the content type header and outputs the image to the browser.

<?php
 
$fontpath = "path/to/your/fontfile.ttf";
if(!file_exists($fontpath)) die("Error!  Font file does not exist at '".$fontpath."'");
 
$cachefile = "path/to/your/cachefile.png";
$text = "ABCD abcd 1234";
$fillcolor = "#999999";
 
 
if (!file_exists($cachefile)) {
 
	try{
 
		$draw = new ImagickDraw();
		$draw->setFont($fontpath);
		$draw->setFontSize(20);
		$draw->setGravity(Imagick::GRAVITY_CENTER);
		$draw->setFillColor($fillcolor);
 
		$canvas = new Imagick();
 
		$metrics = $canvas->queryFontMetrics($draw,$text);
 
		$canvas->newImage($metrics['textWidth'], $metrics['textHeight'], "transparent", "png");
		$canvas->annotateImage($draw,0,0,0,$text);
 
		$canvas->setImageFormat('PNG');
		$canvas->writeImage($cachefile);
 
		header("Content-Type: image/png");
		echo $canvas;
 
		$canvas->clear();
		$canvas->destroy();
 
		$draw->clear();
		$draw->destroy();
 
	}catch(Exception $e){
		echo 'Error: ',  $e->getMessage(), "";
	}
 
} else {
 
	$canvas = new Imagick($cachefile);
	header("Content-Type: image/png");
	echo $canvas;
 
}
 
die();
 
?>

NOTES: Your cache file path must be writable by the server.

OSX Finder New File Contextual Menu Item Using Automator

I have always been annoyed that there is no “New File” contextual menu item in OS X’s Finder. I mean, common Apple, why no new file? Anyway, after looking around I found some packages that don’t work with Snow Leopard. So I decided to see what I could do with Automator. Low and behold, there are many options for writing “services” which appear in a the “Services” sub menu of the contextual menu for a folder. I found this simple shell script which creates an empty text document when saved in Automator as a “Service”. (NOTE: there is a better solution below…)

touch "$@/NewTextFile.txt"

I tried messing around with apple script to get a dialog input from the user for the new file’s extension (UPDATE: figured this out, see below), but got incredibly frustrated trying to turn the input folder into a string that could be run as a shell script with the a fore mentioned script. So I gave up and just made a few of the most common blank files I wanted.

Click Here to download a zip of the Automator Workflow files I created. Hopefully this helps someone who is as frustrated as I am with the lack of a “New File” button or contextual menu in OS X.

Please Note: that you must click on the actual folder (with the icon) to get the “Services” menu to appear in Finder’s contextual menu. The “Services” menu does not show when you click on the “background” of the folder in Finder. Annoying.

A Better Solution

UPDATE: Actually got this working the next day when a co-worker mentioned that the folder string i was looking for was called a POSIX (aka Unix) style folder path string. Anyway, I now have a script which is called from the contextual menu, which prompts you for a filename, then creates it in the folder you have clicked on! Yay!

To create this work flow, you can download the service workflow , then put it in the ~/Library/Services/ folder for your user. Alternatively, you can create your own new “Service” with Automator. Open a new workflow as a “Service”, then search for “applescript” in the actions library. Drag the “Run AppleScript” action into your workflow, select “files and folders” in the “service recieves” drop down, then paste this code into the action:

on run {input}
	display dialog "File Name?" default answer "blank.txt"
	set filename to the text returned of result
	set filepath to POSIX path of input
	do shell script "touch " & quoted form of filepath & filename
	return input
end run

Save the service workflow, and blamo, there it is in your contextual menu when clicking on a folder.

Yet another Prototype Colorpicker

And then there was another…..color….picker…. I have been dissatisfied with all the prototype color pickers out there, so when I found this jQuery colorpicker, I decided to port it to prototype. Yay!

It has lots of options. Examples/Demo available here, download available here. This color picker allows you to not only select your color, but it also enables the following features:

  • specify a preview element
  • specify an input element that’s not the actionable element (ie, you can specify an action element, like a clickable icon, and have the selected color applied to a hidden input)
  • allows for target input element and preview element’s background color to be updated on change of the new color in the picker, or not (only will update on the commit of the color)
  • ability to control hide color picker on commit color, or not
  • ability to customize onShow, onBeforeShow, onChange, onHide, onLoad, and onSubmit functions
  • HSB, RGB, and Hex numbers available
  • Custom Event type on the “show color picker target”, such as onClick or onFocus
  • has an “extra info” button which can allow you to put in a custom color palette, or anything else you might want to put into a color picker. Color palette code can be found at the demo page.
Select Your Color: #  

	var cp = new colorPicker('colorpicker',{
		color:'#008a20',
		previewElement:'colorpicker-preview',
		eventName: 'focus',
		onShow:function(picker){
			new Effect.Appear(picker.cp);
			return false;
		},
		onHide:function(picker){
			new Effect.Fade(picker.cp);
			return false;
		},
		origColor:'#000000',
		livePreview: true,
		hideOnSubmit:false,
		updateOnChange:true,
		flat: false,
		hasExtraInfo:true,
		extraInfo:function(picker){
			var colors = $A([
				  '000000', '993300', '333300', '003300', '003366', '000080', '333399', '333333',
				  '800000', 'FF6600', '808000', '008000', '008080', '0000FF', '666699', '808080',
				  'FF0000', 'FF9900', '99CC00', '339966', '33CCCC', '3366FF', '800080', '969696',
				  'FF00FF', 'FFCC00', 'FFFF00', '00FF00', '00FFFF', '00CCFF', '993366', 'C0C0C0',
				  'FF99CC', 'FFCC99', 'FFFF99', 'CCFFCC', 'CCFFFF', '99CCFF', 'CC99FF', 'FFFFFF'
			]);
 
			var div = Builder.node('DIV').setStyle({padding:'10px 12px'});
			colors.each(function(color){
				var div_inner = Builder.node('DIV').setStyle({backgroundColor:'#'+color,cursor:'pointer',width:'10px',height:'10px','float':'left',border:'2px solid #'+color,margin:'1px'});
				div.insert(div_inner);
				div_inner.observe('click',function(ev){picker.setColor(color);});
				div_inner.observe('mouseover',function(ev){ev.element().setStyle({border:'2px solid #000'});});
				div_inner.observe('mouseout',function(ev){ev.element().setStyle({border:'2px solid #'+color});});		
			});
			picker.extraInfo.update(div);
		}
	});

Textarea auto re-size function….

So I had to create an auto re-size function for textareas. I looked around on the net and found a few things, but nothing really did what i wanted…. so I wrote this quick and dirty function to determine the pixel height a textarea should be based on the number of new lines and length of the content in that textarea. You pass the function the id of the textarea and it returns a number which you should resize the textarea’s pixel height to. The function uses prototype element functions, but these could easily be ported to another framework or replaced with crossbrowser javascript code. I’m just too lazy…..you get the idea =)

 
sizeTextarea = function(textarea){ 
	textarea = $(textarea);
	var hard_lines = 0;
	var soft_lines = 0;
	var lines = 0;
	var str = textarea.value;
	var w = textarea.getWidth();
	var fs = parseInt(textarea.getStyle('font-size').replace('px',''));
	var lh = parseInt(textarea.getStyle('line-height').replace('px',''));
	var tmp_char_cnt = 0;
	var tmp_s = '';
	var sarr = str.split("\n");
	hard_lines = sarr.length;
	if(sarr.length>0){
		for(i=0;i<sarr.length;i++) {
			tmp_s = sarr[i].split('');
			tmp_char_cnt = (tmp_s.length*6)/w;
			if(tmp_char_cnt > 1){
				soft_lines += tmp_char_cnt;
			}
		}
	}
 
	lines = hard_lines+soft_lines+1;
	return (lines*lh); 
}

You may need to change this line:

tmp_char_cnt = (tmp_s.length*6)/w;

as I found the number 6 just seemed to work for me with the font size in my textarea…..good luck! I hope someone finds this useful….

String Functions for Javascript – trim, to camel case, to dashed, and to underscore

So I was messing with a little template builder, and decided to try and dynamically read and write CSS to elements on a page. This brought up the difference between JavaScript having camel case representations of the dashed css properties. Soooooo, I had to write little string functions to convert camel case to dashed strings and visa versa. Heres what I came up with:

Trim String

1
2
3
String.prototype.trim = function(){
	return this.replace(/^\s+|\s+$/g, "");
};

To Camel Case

1
2
3
String.prototype.toCamel = function(){
	return this.replace(/(\-[a-z])/g, function($1){return $1.toUpperCase().replace('-','');});
};

To Dashed from Camel Case

1
2
3
String.prototype.toDash = function(){
	return this.replace(/([A-Z])/g, function($1){return "-"+$1.toLowerCase();});
};

To Underscore from Camel Case

1
2
3
String.prototype.toUnderscore = function(){
	return this.replace(/([A-Z])/g, function($1){return "_"+$1.toLowerCase();});
};

Enjoy!