Saturday, 22 December 2012

Install pattern files into GIMP 2.8 in OS X

Problem:

How do I install patterns into GIMP 2.8 in OS X?

Solution:

One way to do this is to copy the .pat files directly into the GIMP folder that contains all of the default GIMP pattern files. To find this folder, follow the steps below:

  • open your Applications folder
  • secondary-click GIMP, and select "Show Package Contents" from the context menu
  • navigate to: Contents/Resources/share/gimp/2.0/patterns

Now that you've found the patterns folder, copy all the GIMP-compatible pattern files into this folder. Restart GIMP. You should now be able to see the new patterns in the patterns dialogue/selector of GIMP.

Notes:

Note that the above method will make the patterns you install available for every user of your system. There are other methods available which should only install it to your own user, but they may not be so straightforward for the typical user since they involve creating/opening hidden folders.

If you'd like to find out the alternative locations where GIMP is looking for pattern files, just follow these instructions:

In the main menu, click on (in OS X) GIMP->preferences, (or sometimes in another OS, file->preferences). The preferences dialogue should appear. Then in the left-hand menu of the new dialogue, expand the icon/item labelled 'folders' and look for the item named 'patterns'. Once you click on this, you should be able to find all of the folders GIMP is looking for patterns in, as shown in the following screenshot.

Tuesday, 11 December 2012

Access images in Symfony 2.1 CSS stylesheets with Twig and Assetic

Problem:

How can I access images from my Symfony 2.1 project's CSS stylesheets?

Solution -- intro:

The example in this blog post is only part of the picture and is meant to get the typical project started for the beginner. Please note that it's far from a complete explanation, but hopefully it'll be useful for some out there.

Accessing images in Symfony 2.1 stylesheets can be done by following a few steps. Before we list them out, let's establish some parameters for this blog post's example.

First, for illustration purposes, let's assume that your bundle is named DemoIllustrationBundle, its path is Demo/IllustrationBundle, and that your CSS and image files are located respectively in the following locations in src/Demo/IllustrationBundle/:

  • Resources/public/css
  • Resources/public/images

Let's also assume that our CSS file is named style.css, and that it needs to access the image 'repeat.png' to repeat as the background image.

In style.css, we'll access repeat.png via url('../images/repeat.png'), for example:

background-image: url('../images/repeat.png');

Now that we've established the parameters for this example, we can summarize the steps needed to be taken to properly access images in CSS styles:

  • whitelist the bundle in assetic
  • install web assets
  • use stylesheets tag in twig template with cssrewrite filter
  • compile assets for production (out of the scope of this blog post, but necessary to learn prior to switching to a production environment)

... whitelist bundle in assetic

This step allows you to use the stylesheets tag in your twig templates. You'll need this in order to use the rewrite filter to dynamically update the path of your images in the generated stylesheets of your app.

Open the file app/config.yml, it should have a section that looks like:

assetic:
  ...
  bundles:        []
  ...

Add your bundle to this whitelist. In the case of this blog post's example we'll add DemoIllustrationBundle:

bundles:        ['DemoIllustrationBundle']

Save this file and exit. Note that this assetic whitelist will now apply to all environments.

... install web assets

This step installs the images from your project's Resources/public folder to the web folder.

There are several ways to install assets. We'll be installing assets using the symlink method so we don't have to keep reinstalling them during development. In the command console / terminal, go to your project folder and use the command:

php app/console assets:install web --symlink

You should be able to access the CSS and image files in the web folder now. In the case of this example, they'd be located respectively in:

  • web/bundles/demoillustration/css
  • web/bundles/demoillustration/images

Note how these locations compare to your project's public folder.

... use the stylesheets tag with cssrewrite filter

When including the style.css file in this example, the twig template section should look like the following:

{% stylesheets 'bundles/demoillustration/css/style.css'
   filter="cssrewrite" %}
  <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
{% endstylesheets %}

This should rewrite the '../images/' in the stylesheet to the location of the installed images.

Debugging (incomplete):

There are a few things that can go wrong with the above example. This section will cover two of those bugs with potential approaches to debugging them.

Assetic not configured:

One error can be forgetting to whitelist your bundle. This is indicated by getting an exception such as the following:

An exception has been thrown during the compilation of a template ("You must add DemoIllustrationBundle to the assetic.bundle config to use the {% stylesheets %} tag in DemoIllustrationBundle::base.html.twig.") in "/path/to/Demo/IllustrationBundle/Resources/views/base.html.twig".

Images still aren't showing:

If the above steps were followed but images still aren't showing, there are a few things that should be looked at. We'll use the setup in the example of this blog post to illustrate a few steps that can be looked at when trying to debug this:

  • are there any typos?
  • are images located in the project's "Resources/public/images" folder?
  • does the CSS file look for images in "../images/"?
  • were web assets installed?

Unfortunately, since there is an exhaustive list of things that can potentially go wrong, you'll have to use your ingenuity or Google to search out any other scenarios besides the above ones if they don't seem to apply.

Further reading:

The example in this blog post is only part of the picture and is meant to get the typical project started for the beginner. There's a lot to learn, and several steps left to go in order to make your project suitable for production. The following links are either references that helped in figuring out the above steps in this post, in addition to other resources that may provide more useful information for either clarification or for how to proceed from where this post leaves off.

Thursday, 6 December 2012

Styling links and anchors with CSS by example

Problem:

How do I style anchors and links with CSS? Additionally, how do I override these styles?

Examples:

The examples below in this post will demonstrate how to use the most common pseudo-classes of website links: link, visited, hover, active.

Here's what the pseudo-classes mean:

SelectorInterpretation
:linkall unvisited links
:visitedall visited links
:activethe active link
:hoverthe link selected on mouseover

Link defaults (covers all links in the document):

:link { color:blue; text-decoration:underline; }
:visited { color:green; text-decoration:underline; }
:link:hover { color:blue; text-decoration:none; }
:link:active { color:blue; text-decoration:underline; }

Anchor defaults (covers all links embedded in anchors):

a:link { color:blue; text-decoration:underline; }
a:visited { color:green; text-decoration:underline; }
a:hover { color:blue; text-decoration:none; }
a:active { color:blue; text-decoration:underline; }

Override (covers all links embedded in anchors with the class 'overrideClass'):

a.overrideClass:link { color:red; text-decoration:none; }
a.overrideClass:visited { color:orange; text-decoration:none; }
a.overrideClass:hover { color:red; text-decoration:underline; }
a.overrideClass:active { color:red; text-decoration:underline; }

References:

Friday, 30 November 2012

Check if a javascript variable contains a function

Problem:

How do I check if a value stored in a javascript variable is a function?

Solution:

While there are many ways to do this, the following code should work:

function isFunction(toCheck){
  return toCheck != null 
      && {}.toString.call(toCheck) == '[object Function]';
}

Notes:

Note that the first conditional, toCheck != null, may not be necessary. However, if null or nothing is passed to the function the result could be undefined otherwise (this was encountered, at least, in some older (or buggy?) implementations of javascript but might be a non-issue today -- feel free to test it out).

An alternative (and closely-related) method of checking is to directly call Object.prototype.toString.call() instead of instantiating an anonymous object.

References:

Thursday, 15 November 2012

Workaround for Symfony 2.1 composer.phar update timezone error

Problem:

Every time I run "php composer.phar update", I get an error similar to:

Warning: date_default_timezone_get(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Los_Angeles' for 'PST/-8.0/no DST' instead in /path/to/symfony21/project/vendor/monolog/monolog/src/Monolog/Logger.php line 112

Script Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::clearCache handling the post-update-cmd event terminated with an exception

[RuntimeException] An error occurred when executing the "'cache:clear --no-warmup'" command.

What's worse is that my php.ini file has a timezone already set. For instance, when I run the shell command "php -i | grep date.timezone", a timezone is produced, e.g. "date.timezone => America/Los_Angeles => America/Los_Angeles".

Workaround:

A quick workaround to this issue is to explicitly set a timezone in the app/console script. Open the app/console script in a text editor. In app/console, near the top (for instance, right before set_time_limit(0);), add the following line, replacing the example timezone from below with one of the valid PHP timezones found on the PHP docs page:

date_default_timezone_set('America/Los_Angeles');

When you save your changes to app/console and run "php composer.phar update" once more, it should now work.

Notes/Disclaimer:

This workaround isn't by any means an ideal fix, and it will affect the timezone of all Symfony2 commands run using the app/console script. (A fortunate side-effect, however, would be the workaround of timezone issues in other scripts using app/console.) This workaround may or may not also affect any scripts that try to upgrade app/console. To reverse this change, simply remove the "date_default_timezone_set" line you inserted into app/console. (Or even better, prior to modifying app/console, copy the old app/console script, rename the copy to app/console.old, and replace the script with the copy if you need to revert.) This workaround was tested with Symfony 2.1.3, PHP version 5.3.6 using MAMP 2.0.5 under OS X 10.7. Your mileage may vary with other versions.

Saturday, 10 November 2012

Batch resize images to a fixed width and add watermarks

Problem:

I've got a bunch of images that I want to make a resized version of to post online. Additionally, I want to add a watermark to each of these resized images. I already have ImageMagick installed in my OS X or Linux computer.

Solution:

This is quite a specific problem with a very specific solution. This post assumes that you have read and understood the previous post found here. If not, the solution in this blog post should still be somewhat clear, if not a little fast-paced.

For the sake of this post, let's assume that the source images are a bunch of .JPG images. Additionally, let's assume that we want to resize our images to a width of 320 pixels while maintaining the aspect ratio of the original image. Finally, let's assume that we want to give our images the semi-transparent watermark "grammarofdev.blogspot.com", using the font located at "/Library/Fonts/Arial.ttf". To prevent overriding our original images, we will also create a new sub-folder called 'results'. Below is an example Terminal command of how to do all of this (with line-breaks added for legibility):

$ mkdir ./results
$ mogrify -font /Library/Fonts/Arial.ttf -pointsize 88 -verbose
          -draw "fill rgba(255,255,255,0.5) text 24,75
                 'grammarofdev.blogspot.com'"
          -path ./results -resize 320 -quality 86 -format jpg *.JPG

Phew, what an ugly, long command. What does it all mean?

The "-font /Library/Fonts/Arial.ttf -pointsize 88" selects the Arial TrueType font with a point-size of 88pt. The "-verbose" flag outputs verbose information to the terminal while the conversion is being done. The "-draw "fill rgba(255,255,255,0.5) text 30,80 'grammarofdev.blogspot.com'"" portion tells ImageMagick to render the text "grammarofdev.blogspot.com" with a fill colour of white and an alpha of 0.5, starting at the (x,y) coordinate of (24,75) of the original image.

The "-path ./results" indicates that the resized images should be written to the "results" sub-folder. Note that all files in that sub-folder with the same name will be written over without warning! Additionally, omitting this flag will write over all of your original images!

Next, "-resize 320 -quality 86 -format jpg" indicates that the images should be resized to have a width of 320 pixels, maintaining the original aspect-ratio, and then converted to jpeg with a quality of 86. Finally "*.JPG" indicates that this command should convert all images with the suffix .JPG (case-sensitive).

Note that the text is drawn onto the original image prior to the image being scaled down to the final desired size.

Let's see how well this worked. The following two images will show an image before this command is run, and the resulting image afterwards. Note that the original image dimensions are 3264x2448 pixels, however this image is not included in this post. (A slightly-larger version can be found here!)

Original image (scaled to width 300px):

Watermarked image:

Where can this be useful:

Imagine that you had a hundred images you wanted to automatically watermark and resize, or imagine that you have created a web app that requires re-sizing and watermarking previews of images. Using ImageMagick to perform this task is a quick way to achieve the desired results without needing to program anything complex, or use programs such as Photoshop. This post only touched the surface of what ImageMagick can do. For more details on resizing, or details on drawing on images automatically with ImageMagick, check out the following references.


References:

OS X Terminal says 'you have mail'

Problem:

Whenever I open OS X Terminal, it says "you have mail". Why is this, and how can I get rid of this message?

Explanation:

OS X machines, just like Linux and Unix machines, have the capability to send emails to other machines, as well as receive emails from other machines directly to and from your local machine's user account. Long story short, if you are seeing the "you have mail" message in your Terminal window, your computer's local SMTP server has somehow received an email message to your account. (For far more details, look at the references below, or Google the terms "postfix", "sendmail", and "OS X").

Solution (using Terminal only):

This solution solely uses the Terminal. If you are not comfortable with this, please do not follow the rest of this how-to as you can cause some serious damage to your system if you don't know what you're doing. If you'd still like to poke around your system, try the "partially without Terminal" solution below.

The mail received in your account is saved in the file "/var/mail/$USER", where $USER is the name of your account. For instance, if your account was named "someone", and if your home folder shows up in the OS X filesystem as "/Users/someone", then the mail on your machine has been stored in "/var/mail/someone".

Because this is a regular text file, you can simply open it in a text editor to read the mail stored in this file, or you can view the file's contents directly in the Terminal with the command "more /var/mail/$USER", replacing "$USER" with your username (although typing in the command exactly will also suffice in this case, as Terminal will replace $USER with your username).

To get rid of the "you have mail" message, simply move or delete the email file from /var/mail. For instance, assuming again that your account name is "someone", you can type into the terminal "sudo rm -i /var/mail/someone", then confirm deletion when prompted. This command is permanent and possibly destructive if done wrong, so do not make any typos.

Finally, if you have reason to believe that something unusual is sending out emails from your machine after looking at your email file in /var/mail, you can check out the mail log on your machine with the command "more /var/log/mail.log" to see what email activity has occurred on your machine.

Solution (partially without Terminal):

To view the local mail folder on your OS X system in the Finder, type the following command into the Terminal window:

open /var/mail

Once open in the finder, to view the mail on your local machine, open the text file that matches your user in the "/var/mail" folder. For instance, if your username is "someone" and your home folder is "/Users/someone", then the email file to open is "/var/mail/someone".

With the OS X Finder still open to the "/var/mail" folder, in order to remove the "you have mail" message from the Terminal move the email text file from the "/var/mail" folder, or delete it altogether. For instance, if your user is "someone", you will want to either move or delete the file "/var/mail/someone".

After reading your email, if you suspect that there is unusual email activity happening on your local machine, you can confirm this by looking at the machine's email log with the following Terminal command:

open /var/log/mail.log

References:

Friday, 9 November 2012

Batch convert PNG images to 50% scaled jpg images with mogrify

Problem:

How do I convert a bunch of PNG images to jpeg images at 50% of their original dimensions? I'm on an OS X computer and have already installed ImageMagick.

Solution:

You can use the 'mogrify' command that comes with ImageMagick in the Terminal. Note however, that mogrify has the ability to silently overwrite images, so *be careful*! In the following example a destination folder is created to save images in order to preserve the original images.

$ mkdir ./results
$ mogrify -path ./results -resize 50x50% -quality 80 -format jpg *.PNG

So what did all of that mean?

The first part, "mkdir ./results" created a sub-folder named 'results' to save all of the converted images. You can make a different sub-folder if you already have a folder named 'results' to avoid overwriting contents in that existing sub-folder. Remember to change the folder in the -path portion of the mogrify command, too.

The next part batch converts all of the .PNG images to .jpg images of half the width and height. Note that the extensions are case-sensitive. The "-path ./results" flag indicates that results of the conversion are written to the "./results" folder. All destination images are overwritten if they already exist. The "-resize 50x50%" portion shrinks the final width and height to 50% of the original. The "-quality 80" indicates the compression level of the resulting jpeg images. The "-format jpg" indicates that the final image format should be jpeg. Finally, the "*.PNG" indicates that the input images will be every .PNG image in the current folder.

References:

Wednesday, 7 November 2012

PHP timezone error

Problem:

When trying to make a new DateTime object using PHP, or use any built-in time-related functions, I keep getting the following exception thrown: "DateTime::__construct(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/New_York' for 'EST/-5.0/no DST' instead"

Solution:

This error means that a PHP script should have some method of having its default timezone set besides the unsafe method of using the system's setting (making for more predictable and consistent behaviour of the script).

In the case of PHP, you can either use date_default_timezone_set() somewhere prior to calling any date or time functions. Alternatively, you can edit the /etc/php.ini file to add a valid timezone to the date.timezone parameter (e.g. date.timezone = "America/New_York") so that all scripts will use this timezone unless set otherwise by using date_default_timezone_set().

Reference:

Handle MySQL max_allowed_packet error

Problem:

My web application keeps giving the error "#1153 – Got a packet bigger than ‘max_allowed_packet’ bytes" and fails.

What's happening:

This error occurs when a statement to the MySQL server exceeds a certain size. For instance, if the max_allowed_packet is set to 2M but a statement attempts to INSERT a 5MB BLOB, the query will fail.

Solution:

There are two solutions around this problem, so long as you have sufficient privileges to access the configuration of your MySQL server, and are comfortable with either SSH or editing configuration files. Additionally, you should know how to safely restart your MySQL server.

  1. The first solution is to log into your server via SSH, then connect to your MySQL. Assuming you want the maximum packet size to be 16MB, when logged into MySQL type the following command into the prompt: mysqld --max_allowed_packet=16M
  2. The other solution is to find your MySQL configuration file, usually named my.cnf (though if not, you can easily Google how to find the location of this file on your current OS version). Assuming again that you want a max packet size of 16M, inside this file under the section [mysqld], add or change the following parameter to max_allowed_packet=16M

Once this is completed, you may have to restart your MySQL server to see the change. Note that this is a global change and every script that accesses the database on this server will now, by default, have a maximum allowed packet size to what you set it to.