WordPress Plugin Development, Part 1

WordPress is an extremely powerful content management system, and while we are drupal heads over here at SOTC, WordPress is still to be loved and respected. It offers not only users, but also developers an easy to use system that allows easy content construction and management. Today, using WordPress 3.0.1, we are going to make a very simple WordPress plugin that will introduce you to the basics of developing in the WordPress system.

The Rick Rolling craze has come and gone. It was fun while it lasted, but no one really seems to want to pull a good Rick Roll these days….that is until our WordPress plugin comes to life. That’s right, I am going to take you through the creation of a Rick Roll WordPress plugin.

Before we start diving into things too deep, lets start with a “shell”. This is how our plugin will start:

<?php
/*
Plugin Name: Rick Roller
Plugin URI: http://www.switchonthecode.com/
Description: Rick Roll Shortcode
Version: 1.0
Author: The Hairiest
*/

class RickRoll
{
  private $vidURL = "http://www.youtube.com/watch?v=4R-7ZO4I1pI";
       
  function RickRoll()
  {    
  }
}

$rickRoll  = new RickRoll();
?>

As you can see, we have something very basic to start with. The important thing to note at this point is the comment at the top, which supplies WordPress with information on the plugin, so it is important to always remember to put that comment in. Other than that, we have pretty much a standard PHP class. Just don’t forget to initiate a new RickRoll object the bottom of the file.

So lets imagine that you want to insert a tricky RickRoll link into your post. All you want to do is use a tag, say [RickRoll], to insert a link to a video on YouTube. This is all too simple. All we have to do is add a function to our class to register a new shortcode event with wordpress. First we have our shortcode function, and remember we are adding this to our RickRoll class:

function RR_Shortcode($atts)
{
  $rickRoll  = "<a href=\"". $this->vidURL . "\">" . $atts[‘title’] . "</a>";
  return $rickRoll;
}

As you can see, this seems almost too simple. However, we must also remember that all we are doing is replacing some text, so nothing complicated is needed. Basically what we are doing with this function is returning what the tag will be replaced with. In the case of the tag attributes we can set, those are passed into the function by WordPress itself. Now all we have to do is tell WordPress that we have a new “shortcode” for it to filter. We do this by adding a simple line to our class constructor:

function RickRoll()
{      
  add_shortcode(‘rickroll’, array(&$this, ‘RR_Shortcode’));
}

That’s it. You may, however, want to take notice at the array we are passing as the second argument. With a small function and one line in our constructor we have created our WordPress shortcode filter. With this plugin we can now write:

[rickroll title="Not a Rick Roll"]

And it turns into:

<a href="http://www.youtube.com/watch?v=4R-7ZO4I1pI">Not a Rick Roll</a>

Pretty tricky, no? But you know, I am not really satisfied with having to input all my Rick Rolls. What if I just wanted to take every link in my post and turn it into a rick roll? Well, thankfully for mischievous people everywhere, we can easily accomplish this with filters. Again, we have to start with a function addition to our RickRoll class:

function Replace_RR_Content($content)
{
  $anchors = array();
  preg_match_all(‘/<a.*?>.*?<\/a>/x’, $content,
    $oldAnchors, PREG_PATTERN_ORDER);
               
  foreach($oldAnchors as $anchor)
  {
    $newAnchor = preg_replace(‘/href=.*?/’,
      "href=\"". $this->vidURL . "\"", anchor[0]);
    $content = str_replace($anchor, $newAnchor, $content);
  }
       
  return $content;
}

You probably can already tell that this is another super simple function, and you would be right. First WordPress passes the function the post content, then we find all the anchor tags inside this content. Then we replace the href‘s of all the anchor tags, finally returning the content back to WordPress for display.

However, just like before, WordPress needs to know that we want this function to filter our post content. This requires another addition to our class constructor:

function RickRoll()
{      
  add_shortcode(‘rickroll’, array(&$this, ‘RR_Shortcode’));
  add_filter(‘the_content’, array(&$this, ‘Replace_RR_Content’));
}

With this addition our rick rolling filter is complete. Now all of the anchor tags in a post will be replaced. For example:

[rickroll title="Not a Rick Roll"]

<a title="Some Link Again" href="http://codex.wordpress.org/Function_Reference/add_filter" target="_blank">Link 1</a>
<a class="wp-caption-dd" title="Another Link!" href="http://www.spaweditor.com/scripts/regex/index.php" target="_blank">Link 2</a>
<a class="alignright" title="Some Link" href="http://www.php.net/manual/en/function.preg-replace.php" target="_blank">Link 3</a>

Becomes:

<a href="http://www.youtube.com/watch?v=4R-7ZO4I1pI">Not a Rick Roll</a>

<a title="Some Link Again" href="http://www.youtube.com/watch?v=4R-7ZO4I1pI" target="_blank">Link 1</a>
<a class="wp-caption-dd" title="Another Link!" href="http://www.youtube.com/watch?v=4R-7ZO4I1pI" target="_blank">Link 2</a>
<a class="alignright" title="Some Link" href="http://www.youtube.com/watch?v=4R-7ZO4I1pI" target="_blank">Link 3</a>

Quite a devious plugin indeed. Yet somehow I feel we need more Rick Astley on our blog. I think it is about time we pull out all the stops and put a rick roll video directly in every post, embed Rick Astley into the top of everything. And once again, this is all too easy. Here is the function to add this time around:

function Add_RR($content)
{
  $rrVid = <<<rrvid
    <object width="640" height="385">
      <param name="movie"
       value="http://www.youtube.com/v/4R-7ZO4I1pI?fs=1&amp;hl=en_US"></param>
      <param name="allowFullScreen" value="true"></param>
      <param name="allowscriptaccess" value="always"></param>
      <embed src="http://www.youtube.com/v/4R-7ZO4I1pI?fs=1&amp;hl=en_US"
        type="application/x-shockwave-flash"
        allowscriptaccess="always" allowfullscreen="true" width="640"
        height="385"></embed>
    </object>
rrvid
;
   
    $content = $rrVid . $content;
   
    return $content;
  }

This is the same basic concept as the other function, except, we are going to add this as an action rather than a filter. This could be accomplished as a filter, but actions are extremely important to WordPress, so we might as well go over how to add an action as well. Here is what our final constructor will look like:

function RickRoll()
{      
  add_shortcode(‘rickroll’, array(&$this, ‘RR_Shortcode’));
  add_filter(‘the_content’, array(&$this, ‘Replace_RR_Content’));
  add_action(‘the_content’, array(&$this, ‘Add_RR’));
}

As you can tell, adding an action is exactly like adding a filter. The main difference is really how you implement them. Filters are meant to….well, filter the data, while actions extend normal WordPress processes. In this case our filter and action are about the same functionally, but our action is actually called before the the_content() function is called in WordPress. With our filter, we are merely passed the post content to modify. It seems similar, but when you start building more complex plugins, the difference becomes more apparent.

With this final addition, we add a rick roll in every post. So a post like so:

[rickroll title="Not a Rick Roll"]

<a title="Some Link Again" href="http://codex.wordpress.org/Function_Reference/add_filter" target="_blank">Link 1</a>
<a class="wp-caption-dd" title="Another Link!" href="http://www.spaweditor.com/scripts/regex/index.php" target="_blank">Link 2</a>
<a class="alignright" title="Some Link" href="http://www.php.net/manual/en/function.preg-replace.php" target="_blank">Link 3</a>

Transforms into:

<object width="640" height="385">
 <param name="movie"
  value="http://www.youtube.com/v/4R-7ZO4I1pI?fs=1&amp;hl=en_US"></param>
 <param name="allowFullScreen" value="true"></param>
 <param name="allowscriptaccess" value="always"></param>
 <embed src="http://www.youtube.com/v/4R-7ZO4I1pI?fs=1&amp;hl=en_US"
  type="application/x-shockwave-flash"
  allowscriptaccess="always" allowfullscreen="true" width="640"
  height="385"></embed>
</object>

<a href="http://www.youtube.com/watch?v=4R-7ZO4I1pI">Not a Rick Roll</a>

<a title="Some Link Again" href="http://www.youtube.com/watch?v=4R-7ZO4I1pI" target="_blank">Link 1</a>
<a class="wp-caption-dd" title="Another Link!" href="http://www.youtube.com/watch?v=4R-7ZO4I1pI" target="_blank">Link 2</a>
<a class="alignright" title="Some Link" href="http://www.youtube.com/watch?v=4R-7ZO4I1pI" target="_blank">Link 3</a>

At this point we are done with our Rick Roll plugin and if all is right, you should have just one php file. Now, in order to use the plugin we have to put it in the WordPress plugin folder. Makes sense, huh? You will find it at your-wordpress-blog/wp-content/plugins. Once you have it in the right place all you have to do is activate it and start using it. Remember, we have a tag [rickroll title="some title"], all links in your content will be replaced with Rick Rolls, and finally our plugin will at a Rick Roll video to all our posts/pages. All you have to do now is make a post.

So this is our rick rolling plugin, in all its silly glory. It wasn’t that difficult, but we did a whole lot with our code, all thanks to the powerful WordPress plugin API. This concludes this tutorial, but just remember, when you need coding help all you have to do is Switch On The Code.

Silverlight Tutorial – Using Yahoo Pipes to Access Cross-Domain JSON

If you’ve ever sat down to create a web application in Flash or Silverlight you might have run into cross-domain access restrictions. For security reasons, client side technologies won’t let you access data on a different domain if the remote server doesn’t explicitly allow it. Many APIs grant cross-domain access, however there are times there is no way to access the service directly. That’s where this tutorial comes in. Back in 2007 Yahoo! released Pipes, which allows developers to combine and filter web-based information which is then re-hosted by Yahoo. The great thing about this is that Pipes allows cross domain access.

The app we’re going to create today is a simple Silverlight app that displays the most recent 25 “Hot” Reddit posts. You can play with the app below. We’ve dealt with Silverlight and cross-domain issues before. The previous tutorial used Pipes to access Twitter’s XML. This tutorial, on the other hand, will being using Pipes to access Reddit’s JSON API.

?

Create The Pipe

The first thing we’re going to have to do is create a pipe. You’ll have to have a Yahoo account to do this, and everything is free. Once you’re logged in, you’ll see a large “Create Pipe” button at the top of the main Pipes site.

Create Pipe

After you create the pipe, you’ll see a blank canvas.

Blank Pipe

Every pipe starts with a data source. For this pipe, drag a “Fetch Data” module onto the canvas. For the URL, enter the address of the desired JSON data. In our case, we’ll be using reddit.com/.json. Reddit’s API is pretty simple -basically you stick “.json” at the end of any regular page to receive a JSON feed of the same data.

Fetch Data Module

When you connect this module to the Pipe Output module, you should be able to see it in the Debugger window.

Pipe Output

There are tons of other things we can do with this data, but for the purposes of this tutorial, our Pipe is done. All we needed was for Yahoo to give us cross-domain access to this data. We can now save our Pipe.

Save Pipe

I named this pipe “Reddit”.

Pipe Name

Run The Pipe

The last thing we need to do is run the pipe.

Run Pipe

After you click the “Run Pipe…” link, you’ll be taken to the pipe’s page where you can do basic administrative stuff. The thing we want to do is get a link to the JSON output for this pipe. To do this, all we need to do is click the “Get as JSON” link.

Get as JSON

The link initially provided by Yahoo doesn’t support cross-domain calls. Thanks to a post by Jonas Follesø I found out all that’s needed is a simple change to the URL. So take the link that Yahoo provides:

http://pipes.yahoo.com/pipes/pipe.run?_id=…&_render=json

and change it to:

http://pipes.yahooapis.com/pipes/pipe.run?_id=…&_render=json

Create the Silverlight Project

Now that we have the data, it’s time to start building our application. The first thing we need to do is create a new Silverlight 4 application.

New Silverlight Project

When it asks whether or not to create a website for the application, simply use the defaults.

New Silverlight Website

Now we need a class to hold the information obtained from Reddit’s API. Let’s call the class, “RedditEntry”.

namespace RedditViewer
{
  public class RedditEntry
  {
    /// <summary>
    /// Gets or sets the title of the reddit post.
    /// </summary>
    public string Title { get; set; }

    /// <summary>
    /// Gets or sets the thumbnail image.
    /// </summary>
    public string Thumbnail { get; set; }

    /// <summary>
    /// Gets or sets the url to the Reddit comments page.
    /// </summary>
    public string Permalink { get; set; }

    /// <summary>
    /// Gets or sets the url to actual contents.
    /// </summary>
    public string Link { get; set; }

    /// <summary>
    /// Gets or sets the number of comments.
    /// </summary>
    public int NumComments { get; set; }
  }
}

Because we’re going to be using the DataContractJsonSerializer class to deserialize our JSON data, we need to add some markup to this class so .NET knows how to parse the incoming data. The first thing we need to do is add a reference to System.Runtime.Serialization.

Add Reference System.Runtime.Serialization

Now we need to add attributes to support the DataContractJsonSerializer.

using System.Runtime.Serialization;

namespace RedditViewer
{
  [DataContract]
  public class RedditEntry
  {
    /// <summary>
    /// Gets or sets the title of the reddit post.
    /// </summary>
    [DataMember(Name="title")]
    public string Title { get; set; }

    /// <summary>
    /// Gets or sets the thumbnail image.
    /// </summary>
    [DataMember(Name="thumbnail")]
    public string Thumbnail { get; set; }

    /// <summary>
    /// Gets or sets the url to the Reddit comments page.
    /// </summary>
    [DataMember(Name="permalink")]
    public string Permalink { get; set; }

    /// <summary>
    /// Gets or sets the url to actual contents.
    /// </summary>
    [DataMember(Name="url")]
    public string Link { get; set; }

    /// <summary>
    /// Gets or sets the number of comments.
    /// </summary>
    [DataMember(Name="num_comments")]
    public int NumComments { get; set; }
  }
}

I got the names of the fields by looking at the JSON output in the pipe editor.

Highlighted Pipe Output

Request and Parse the JSON Data

Now that we’ve got an object to hold our data, we can go ahead and create a function to request and parse the output.

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;

namespace RedditViewer
{
  public partial class MainPage : UserControl
  {
    public MainPage()
    {
      InitializeComponent();

      RequestRedditEntries();
    }

    private void RequestRedditEntries()
    {
      // Create a Uri with the address to the Yahoo Pipe.
      Uri pipeUri = new Uri(
        @"http://pipes.yahooapis.com/pipes/pipe.run?_id=…&_render=json");

      // Create a WebClient to request the information.
      WebClient webClient = new WebClient();
      webClient.DownloadStringCompleted += webClient_DownloadStringCompleted;
      webClient.DownloadStringAsync(pipeUri);
    }

    void webClient_DownloadStringCompleted(object sender,
      DownloadStringCompletedEventArgs e)
    {
      // Show the results in a MessageBox.
      // TODO: parse results.
      MessageBox.Show(e.Result);
    }
  }
}

I created a function, RequestRedditEntries, that is initially called when the page loads. This function creates a WebClient that will go out and download the JSON from the Yahoo Pipe. When the request is complete it will call the event handler webClient_DownloadStringCompleted. At the moment, this handler simply displays the results in a MessageBox. If everything went well, you should see a huge alert filled with JSON data. If something went wrong, the properties inside DownloadStringCompletedEventArgs can tell you what happened.

Let’s now parse the output.

void webClient_DownloadStringCompleted(object sender,
  DownloadStringCompletedEventArgs e)
{
  List<RedditEntry> entries = new List<RedditEntry>();

  // Initialize the deserializer.
  DataContractJsonSerializer jsonSerializer =
    new DataContractJsonSerializer(typeof(RedditEntry));

  try
  {
    // Dig through the JSON and find the array of results.
    // The tree is: response -> value -> items -> [0] -> data -> children[]
    JsonObject jsonResponse = (JsonObject)JsonObject.Load(new StringReader(e.Result));
    JsonObject jsonValue = (JsonObject)jsonResponse["value"];
    JsonObject jsonItems = (JsonObject)((JsonArray)jsonValue["items"])[0];
    JsonObject jsonData = (JsonObject)jsonItems["data"];
    JsonArray jsonChildren = (JsonArray)jsonData["children"];

    // Iterate through every child.
    foreach (JsonObject child in jsonChildren)
    {
      // Get the data for the reddit post.
      JsonObject data = (JsonObject)child["data"];

      // Create a memory stream of the JSON text
      // to be passed to the deserializer.
      using (MemoryStream memStream =
        new MemoryStream(UTF8Encoding.UTF8.GetBytes(data.ToString())))
      {
        // Add the entry to the collection.
        entries.Add((RedditEntry)jsonSerializer.ReadObject(memStream));
      }
    }
  }
  catch (Exception ex)
  {
    MessageBox.Show("Failed to parse JSON: " + ex.ToString());
  }
}

There’s a lot going on here, so let’s break it down. First, you’ll have to add a reference to System.Json and System.ServiceModel.Web. The top of this function is simply there to dig through the JSON output and find the array of Reddit entries. I downloaded a tool called JSON Viewer to help see the structure of the JSON.

JSON Viewer

If you want to make this a little cleaner, Yahoo Pipes has lots of ways to massage the data to make it a little more straight forward to parse. Once we get down to the actual array of Reddit entries, I begin invoking the DataContractJsonSerializer. This object can only work on streams so I need to wrap the JSON for a single entry in a MemoryStream. I surrounded the entire thing in a try-catch since there’s about a million things that can go wrong when requesting data from a web service.

We now have a collection of Reddit entries and are ready to move on to the user interface.

Build the User Interface

The user interface is not the primary part of this tutorial, so I’m going to just stick all of the XAML right here. I’ll explain it briefly afterwards.

<UserControl x:Class="RedditViewer.MainPage"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:my="clr-namespace:RedditViewer"
            mc:Ignorable="d"
            Width="400"
            Height="600">
  <UserControl.Resources>
    <my:CommentLinkConverter x:Key="commentLinkConverter" />
  </UserControl.Resources>
  <Grid x:Name="LayoutRoot"
       Background="White">
    <ListBox Name="_redditEntries"
            ScrollViewer.HorizontalScrollBarVisibility="Hidden">
      <ListBox.ItemTemplate>
        <DataTemplate>
          <Border BorderThickness="0,0,0,1"
                 BorderBrush="LightGray"
                 Padding="5">
            <Grid>
              <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
              </Grid.ColumnDefinitions>

              <!– Thumbnail Image –>
              <Border BorderThickness="1"
                     BorderBrush="LightGray"
                     Width="70"
                     Height="70">
                <Image Width="70"
                      Height="70"
                      Stretch="Uniform">
                  <Image.Source>
                    <BitmapImage UriSource="{Binding Thumbnail}" />
                  </Image.Source>
                </Image>
              </Border>

              <Grid Margin="10,0,0,0"
                   Grid.Column="1">
                <Grid.RowDefinitions>
                  <RowDefinition Height="Auto" />
                  <RowDefinition Height="*" />
                </Grid.RowDefinitions>

                <!– Title –>
                <HyperlinkButton VerticalAlignment="Top"
                                NavigateUri="{Binding Link}"
                                TargetName="_blank"
                                ToolTipService.ToolTip="{Binding Link}"
                                Foreground="Blue">
                  <TextBlock Text="{Binding Title}"
                            Width="285"
                            TextWrapping="Wrap" />
                </HyperlinkButton>

                <!– Comments –>
                <HyperlinkButton NavigateUri="{Binding Permalink, Converter={StaticResource commentLinkConverter}}"
                                VerticalAlignment="Bottom"
                                ToolTipService.ToolTip="{Binding Permalink, Converter={StaticResource commentLinkConverter}}"
                                Margin="0,10,0,0"
                                TargetName="_blank"
                                Grid.Row="1">
                  <StackPanel Orientation="Horizontal">
                    <Image Source="comments.png" />
                    <TextBlock Text="{Binding NumComments}"
                              Margin="5,0,0,0" />
                    <TextBlock Text=" Comments" />
                  </StackPanel>
                </HyperlinkButton>
              </Grid>
            </Grid>
          </Border>
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>
  </Grid>
</UserControl>

The entire UI is basically created as an ItemTemplate within a ListBox. I created an Image to hold the thumbnail and a couple of HyperlinkButtons to allow the user to click through to the content. I had to create a binding converter to convert the comments link since Reddit returns the link as a relative URL.

public class CommentLinkConverter : IValueConverter
{
  public object Convert(object value, Type targetType,
    object parameter, System.Globalization.CultureInfo culture)
  {
    string commentLink = value as string;
    if (commentLink != null)
    {
      commentLink = @"http://www.reddit.com" + commentLink;
    }

    return commentLink;
  }

  public object ConvertBack(object value, Type targetType,
    object parameter, System.Globalization.CultureInfo culture)
  {
    throw new NotImplementedException();
  }
}

Other than the binding converter, everything else is a pretty straight forward user interface. The last thing to remember is to set the ItemsSource of the ListBox to the collection of RedditEntries we parsed earlier.

_redditEntries.ItemsSource = entries;

And there you have it. We’ve created a fully functional Silverlight app for viewing the main page of Reddit. Since Reddit doesn’t support cross-domain access we used Yahoo Pipes to provide it for us. The entire source of this application can be downloaded below. If you have any questions, feel free to leave them or head on over to our forums.

Apple Profiling Tools – Shark is Out, Instruments is In

As we sat down today to do some performance profiling in Shark, we came to a sudden realization – it doesn’t work anymore with iOS4. After some quick Google searching I came across a thread in Apple’s developer forum (registration required) that indicated there were no plans to bring iOS4 support to Shark. What we have now is Instruments.

Instruments Icon

I’ll say it right off the bat – Instruments is better than Shark. It’s easier to use and easier to interpret the results. Shark always had a “dated” feel to it – probably because it’s a fairly old application now. Instruments has a much more cohesive user interface, allowing for simple switching between profiling a device, a simulator, or a desktop application.

Unlike Shark, getting Instruments to profile a device is a piece of cake. Once you launch it, you’ll be presented with a screen where you can choose the most typical profiling options.

Profiling Templates

Since we were interested in why a certain part of our application was taking so long, I chose “Time Profiler”, which will tell you where the CPU is spending most of its time.

The next thing you’ll have to do it select the application to target. You’ll want to go ahead and launch the application now. Since we’re working on Drop & Lock, I selected that.

Target Selection

All that’s left to do now is hit the big record button at the top to start and stop the profiler. When you’re done the results will be displayed much like any other profiler (including Shark).

Output

As you can see, most of our processing time is spent rendering the scene and might be a good place to start optimizing. An option that I found very helpful was “Show Obj-C Only”. This will remove items from the output that aren’t written in Objective-C. Since most of our app is written in Objective-C, this helps us find places in our code that can be improved. The option is located to the left of the results beneath the Call Tree options.

I haven’t had much time to see how powerful Instruments truly is, but at first glance, it looks to have a lot of capability. So if you app is running a bit slow, or using a bit too much memory, Instruments is a great tool for discovering why.

WPF 4 Lowers Default BitmapScalingMode Quality

If you’ve recently upgraded a .NET 3.5 WPF application to .NET 4.0, you may have noticed that some of your images look like crap. This is because Microsoft has changed how WPF rescales images. Instead of the original high quality, it has been lowered to low quality. This was done, they say, to improve performance.

Here’s some images that demonstrate what’s going on. I created an application and did nothing except change the target version of the .NET framework. .NET 3.5 is on the left and .NET 4.0 is on the right.

The clock image is courtesy of Paul R. Hayes.

There’s no way to change the default scaling mode in WPF, however you can put a style in your App.xaml or some other high-level place and have it apply to all of your images.

<Window.Resources>
    <Style TargetType="{x:Type Image}">
        <Setter Property="RenderOptions.BitmapScalingMode"
               Value="HighQuality" />
    </Style>
</Window.Resources>

I have mixed feelings on the change. The downside is that some apps will look quite a bit different when switching to .NET 4.0. The upsides is, however, that the low quality scaling mode is entirely done in the GPU, which means the performance will be way better than the CPU-only high quality scaling.

Creating a Javascript Bookmarklet

For nearly all problems there are probably a hundred different solutions. Recently one solution I have chosen for a few problems has been a Javascript bookmarklet. A bookmarklet is a regular bookmark that runs a bit of Javascript code instead of just going to a link. They are really useful for doing a small task on a website or webpage that you don’t have direct access to the backend or source of. So, today I am going to show you how to make a simple bookmarklet.

The bookmarklet today is going to grab a super high-res photo of Amazon Products. Ok, let me explain a little bit more. So, a designer co-worker uses super high-res product images for design mockups. Well, he typically would go scouring the internet for these images. However, he noticed that on Amazon product pages you can look at really large images of products using their Zoom viewer, but you could right-click and download the image from there. So I created a simple bookmarklet to grab the product id from the page url and then open up a link to the large image.

Okay, back to work. So a typical link which can be turned into a book looks like:

SOTC Tutorials

And the code looks like.

<a href="/tutorials">SOTC Tutorials</a>

So if we were going to do something javascript we could do something like:

And the code would be:

<a href="javascript:location.href=’http://switchonthecode.com/tutorials’">SOTC Tutorials</a>

Now, that just covers the basics of the syntax we are going to use for this. You can see above that to tell the browser to run our href as Javascript we need to start with javascript:. Ok so let’s jump to something a bit more complicated. The next piece of Javascript is going create an alert with the current time – I know we all love alerts.

<a href="javascript:(function(){ct=new Date();t=ct.getHours()+’:’+ct.getMinutes();alert(t);})();">Current Time</a>

Looking at the code we start by creating anonymous function and inside the function we create a new Date object, then use it to create a string of hours and minutes, and then show this (current time) in an alert.

So, now if you want to make this a Bookmarklet simply do one of two things.

  1. Drag the link to your bookmark toolbar.
  2. Create a bookmark. Copy the location of the link above and change location of the new bookmark you just created.

The final piece of code we are going to look a is the actual bookmarklet Javascript for the Amazon Image grabber.

regexp=new RegExp(‘/dp/[^/]+(?=/)’);
prod=location.href.match(regexp);
imgloc=‘http://ec2.images-amazon.com/images/P/’+prod[0].substring(4)+‘.01._SCRM_.jpg’;
location.href=imgloc;

The code starts with creating a regular expression that pulls the product id from a url. Next we run the expression on the current page url – it won’t work on this page – using the match to run the expression. Then the url for the large image is created. The last thing is to change the url of the page to go to the large image. Really, that is about it. For a link we wrap it with the aforementioned function and the javascript: starting. In link format this looks like:

<a href="javascript:(function(){regexp=new RegExp(‘/dp/[^/]+(?=/)’);prod=location.href.match(regexp);imgloc=’http://ec2.images-amazon.com/images/P/’+prod[0].substring(4)+’.01._SCRM_.jpg’;location.href=imgloc;})();">Amazon XL Image</a>

And the link:

Well, I hope you learned something today about Javascript links and Bookmarklets. If you have any questions or comments feel free to leave a comment below or head on over to the forums.

How to Build a Simple Twitter Client using Python

Building a Twitter client is nothing new to Switch On The Code. We’ve done it in WCF and Silverlight. To be honest though, using the Twitter API is a great way to exercise two very useful parts of a language and framework – making web requests and parsing XML. That’s what we’re going to do today. We’re going to build a very simple command line twitter client (read-only) using Python.

Today’s app will be very simple. It will request Switch On The Code’s Twitter feed and display them with their dates. Here’s what the first five tweets in the output will look like:

Date: Thu Jul 22 19:46:19 +0000 2010
Tweet: VS 2010 Productivity Power Tools Update (with some cool new features) http://sotc.me/46680 via @scottgu #vs2010 #programming

Date: Thu Jul 22 17:34:45 +0000 2010
Tweet: SQLite 3.7.0 released http://sotc.me/92864 #sqlite

Date: Wed Jul 21 19:08:01 +0000 2010
Tweet: 20+ Required #Windows Apps: Web DesignerGÇÖs Choice http://sotc.me/28662 via @nettuts – I personally love Notepad++ myself!

Date: Mon Jul 19 20:20:23 +0000 2010
Tweet: Windows Phone 7 in-depth preview http://sotc.me/58189 via @engadget #wp7 #microsoft

Date: Mon Jul 19 17:13:38 +0000 2010
Tweet: Would love to get a hold of Windows Phone 7 device to build a couple applications for it, anyone know how to go about that? #windowsphone7

Python has a very large and powerful framework behind it, do doing simple things like making web requests and parsing XML are fairly straight forward and don’t require a lot of code. Let’s start by requesting the XML from Twitter’s API.

import httplib

# Open a connection to twitter.com.
twitterConn = httplib.HTTPConnection("www.twitter.com")

# Requestion Switch On The Code’s tweets.
twitterConn.request("GET", "/statuses/user_timeline.xml?screen_name=SwitchOnTheCode")
twitterResponse = twitterConn.getresponse()

# Check that everything went ok.
if twitterResponse.status != 200:
  print("Failed to request tweets.")
 
# Read the response.
tweets = twitterResponse.read()

# Close the connection.
twitterConn.close()

The first thing we do is create an HTTPConnection object for twitter.com. We then tell it to request the timeline for the user SwitchOnTheCode. Next, we get the response as an HTTPResponse object. I do a quick check to make sure the request went ok, since we all know how often Twitter goes down. All that’s left to do is simply read the contents of the response, which will be our XML.

Now we need to parse the XML. There are a couple of available options, but I chose the DOM approach as I think it makes more logical sense.

import httplib
from xml.dom.minidom import parseString

# Open a connection to twitter.com.
twitterConn = httplib.HTTPConnection("www.twitter.com")

# Requestion Switch On The Code’s tweets.
twitterConn.request("GET", "/statuses/user_timeline.xml?screen_name=SwitchOnTheCode")
twitterResponse = twitterConn.getresponse()

# Check that everything went ok.
if twitterResponse.status != 200:
  print("Failed to request tweets.")
 
# Read the response.
tweets = twitterResponse.read()

# Close the connection.
twitterConn.close()

#Parse the XML.
twitterDom = parseString(tweets)

# Find all the status tweets.
for tweet in twitterDom.getElementsByTagName("status"):
  for tweetParts in tweet.childNodes:
    # Find the date tag.
    if tweetParts.nodeName == "created_at":
      for textNode in tweetParts.childNodes:
        # Find the contents of the date tag.
        if textNode.nodeType == textNode.TEXT_NODE:
          print("Date: " + textNode.nodeValue)
    # Find the tweet tag.
    elif tweetParts.nodeName == "text":
      for textNode in tweetParts.childNodes:
      # Find the contents of the tweet tag.
        if textNode.nodeType == textNode.TEXT_NODE:
          print("Tweet: " + textNode.nodeValue.encode(‘utf-8’) + "\n")

Using Python’s minidom, we first parse the XML returned from Twitter using parseString (don’t forget to import parseString at the top of the file). Now things get a litte tricky. We need to rip through the DOM looking for the items we want to display. First off, every tweet is stored beneath a “status” tag, so we need to loop through every one of those. Underneath each status tag there’s the date (created_at) and the actual tweet (text), so we need to loop through every child of the status tag looking for those. Once we find one, we then need to find the text contained within it. Text is contained in TEXT_NODE type nodes, so we need to search through the children of our created_at and text tags looking for that specific type. Once we find it, we then print the nodeValue and we’re done.

Since tweets are Unicode, I needed to encode the text as utf-8 before printing it to the console.

And that’s it. With just a few lines of code, and some pretty complicated DOM traversing, we’ve got a very basic Twitter reader built in Python. If you’ve got any questions or comments, feel free to leave them below or head on over to our forums.

How to Build a Simple Twitter Client using Python

Building a Twitter client is nothing new to Switch On The Code. We’ve done it in WCF and Silverlight. To be honest though, using the Twitter API is a great way to exercise two very useful parts of a language and framework – making web requests and parsing XML. That’s what we’re going to do today. We’re going to build a very simple command line twitter client (read-only) using Python.

Today’s app will be very simple. It will request Switch On The Code’s Twitter feed and display them with their dates. Here’s what the first five tweets in the output will look like:

Date: Thu Jul 22 19:46:19 +0000 2010
Tweet: VS 2010 Productivity Power Tools Update (with some cool new features) http://sotc.me/46680 via @scottgu #vs2010 #programming

Date: Thu Jul 22 17:34:45 +0000 2010
Tweet: SQLite 3.7.0 released http://sotc.me/92864 #sqlite

Date: Wed Jul 21 19:08:01 +0000 2010
Tweet: 20+ Required #Windows Apps: Web DesignerGÇÖs Choice http://sotc.me/28662 via @nettuts – I personally love Notepad++ myself!

Date: Mon Jul 19 20:20:23 +0000 2010
Tweet: Windows Phone 7 in-depth preview http://sotc.me/58189 via @engadget #wp7 #microsoft

Date: Mon Jul 19 17:13:38 +0000 2010
Tweet: Would love to get a hold of Windows Phone 7 device to build a couple applications for it, anyone know how to go about that? #windowsphone7

Python has a very large and powerful framework behind it, do doing simple things like making web requests and parsing XML are fairly straight forward and don’t require a lot of code. Let’s start by requesting the XML from Twitter’s API.

import httplib

# Open a connection to twitter.com.
twitterConn = httplib.HTTPConnection("www.twitter.com")

# Requestion Switch On The Code’s tweets.
twitterConn.request("GET", "/statuses/user_timeline.xml?screen_name=SwitchOnTheCode")
twitterResponse = twitterConn.getresponse()

# Check that everything went ok.
if twitterResponse.status != 200:
  print("Failed to request tweets.")
 
# Read the response.
tweets = twitterResponse.read()

# Close the connection.
twitterConn.close()

The first thing we do is create an HTTPConnection object for twitter.com. We then tell it to request the timeline for the user SwitchOnTheCode. Next, we get the response as an HTTPResponse object. I do a quick check to make sure the request went ok, since we all know how often Twitter goes down. All that’s left to do is simply read the contents of the response, which will be our XML.

Now we need to parse the XML. There are a couple of available options, but I chose the DOM approach as I think it makes more logical sense.

import httplib
from xml.dom.minidom import parseString

# Open a connection to twitter.com.
twitterConn = httplib.HTTPConnection("www.twitter.com")

# Requestion Switch On The Code’s tweets.
twitterConn.request("GET", "/statuses/user_timeline.xml?screen_name=SwitchOnTheCode")
twitterResponse = twitterConn.getresponse()

# Check that everything went ok.
if twitterResponse.status != 200:
  print("Failed to request tweets.")
 
# Read the response.
tweets = twitterResponse.read()

# Close the connection.
twitterConn.close()

#Parse the XML.
twitterDom = parseString(tweets)

# Find all the status tweets.
for tweet in twitterDom.getElementsByTagName("status"):
  for tweetParts in tweet.childNodes:
    # Find the date tag.
    if tweetParts.nodeName == "created_at":
      for textNode in tweetParts.childNodes:
        # Find the contents of the date tag.
        if textNode.nodeType == textNode.TEXT_NODE:
          print("Date: " + textNode.nodeValue)
    # Find the tweet tag.
    elif tweetParts.nodeName == "text":
      for textNode in tweetParts.childNodes:
      # Find the contents of the tweet tag.
        if textNode.nodeType == textNode.TEXT_NODE:
          print("Tweet: " + textNode.nodeValue.encode(‘utf-8’) + "\n")

Using Python’s minidom, we first parse the XML returned from Twitter using parseString (don’t forget to import parseString at the top of the file). Now things get a litte tricky. We need to rip through the DOM looking for the items we want to display. First off, every tweet is stored beneath a “status” tag, so we need to loop through every one of those. Underneath each status tag there’s the date (created_at) and the actual tweet (text), so we need to loop through every child of the status tag looking for those. Once we find one, we then need to find the text contained within it. Text is contained in TEXT_NODE type nodes, so we need to search through the children of our created_at and text tags looking for that specific type. Once we find it, we then print the nodeValue and we’re done.

Since tweets are Unicode, I needed to encode the text as utf-8 before printing it to the console.

And that’s it. With just a few lines of code, and some pretty complicated DOM traversing, we’ve got a very basic Twitter reader built in Python. If you’ve got any questions or comments, feel free to leave them below or head on over to our forums.

Creating a Javascript Bookmarklet

For nearly all problems there are probably a hundred different solutions. Recently one solution I have chosen for a few problems has been a Javascript bookmarklet. A bookmarklet is a regular bookmark that runs a bit of Javascript code instead of just going to a link. They are really useful for doing a small task on a website or webpage that you don’t have direct access to the backend or source of. So, today I am going to show you how to make a simple bookmarklet.

The bookmarklet today is going to grab a super high-res photo of Amazon Products. Ok, let me explain a little bit more. So, a designer co-worker uses super high-res product images for design mockups. Well, he typically would go scouring the internet for these images. However, he noticed that on Amazon product pages you can look at really large images of products using their Zoom viewer, but you could right-click and download the image from there. So I created a simple bookmarklet to grab the product id from the page url and then open up a link to the large image.

Okay, back to work. So a typical link which can be turned into a book looks like:

SOTC Tutorials

And the code looks like.

<a href="/tutorials">SOTC Tutorials</a>

So if we were going to do something javascript we could do something like:

And the code would be:

<a href="javascript:location.href=’http://switchonthecode.com/tutorials’">SOTC Tutorials</a>

Now, that just covers the basics of the syntax we are going to use for this. You can see above that to tell the browser to run our href as Javascript we need to start with javascript:. Ok so let’s jump to something a bit more complicated. The next piece of Javascript is going create an alert with the current time – I know we all love alerts.

<a href="javascript:(function(){ct=new Date();t=ct.getHours()+’:’+ct.getMinutes();alert(t);})();">Current Time</a>

Looking at the code we start by creating anonymous function and inside the function we create a new Date object, then use it to create a string of hours and minutes, and then show this (current time) in an alert.

So, now if you want to make this a Bookmarklet simply do one of two things.

  1. Drag the link to your bookmark toolbar.
  2. Create a bookmark. Copy the location of the link above and change location of the new bookmark you just created.

The final piece of code we are going to look a is the actual bookmarklet Javascript for the Amazon Image grabber.

regexp=new RegExp(‘/dp/[^/]+(?=/)’);
prod=location.href.match(regexp);
imgloc=‘http://ec2.images-amazon.com/images/P/’+prod[0].substring(4)+‘.01._SCRM_.jpg’;
location.href=imgloc;

The code starts with creating a regular expression that pulls the product id from a url. Next we run the expression on the current page url – it won’t work on this page – using the match to run the expression. Then the url for the large image is created. The last thing is to change the url of the page to go to the large image. Really, that is about it. For a link we wrap it with the aforementioned function and the javascript: starting. In link format this looks like:

<a href="javascript:(function(){regexp=new RegExp(‘/dp/[^/]+(?=/)’);prod=location.href.match(regexp);imgloc=’http://ec2.images-amazon.com/images/P/’+prod[0].substring(4)+’.01._SCRM_.jpg’;location.href=imgloc;})();">Amazon XL Image</a>

And the link:

Well, I hope you learned something today about Javascript links and Bookmarklets. If you have any questions or comments feel free to leave a comment below or head on over to the forums.

Flex & Actionscript Singleton Model Class

In many of the projects and applications I build with Flex I use a singleton for the Model – we’ve talked about Singletons in the past here. Whether this is the preferred method of handling a model is a matter of opinion so I won’t be discussing it. However, I do want to share the model class that I typically use. Actionscript lacks a real static constructor, used for creating a single instance of a class, which means creating a nice singleton takes a bit more work.

To create the singleton I take advantage of using a local class definition inside of my model Actionscript file. From my understanding the local class, it is only visible and valid inside of the file. Also I owe props to some blog for pointing this trick out but I can’t remember the blog – sorry. This means we can ensure that the only instance of the model is created inside of the class. Let’s take a look of the entire code below and we can make a little more sense of it.

package
{
  [Bindable]
  public class MainModel
  {
    private static var _instance:MainModel = new MainModel(ModelEnforcer);
   
    public static function getInstance():MainModel
    {
      return _instance;
    }
   
    public function MainModel(enforcer:Class)
    {
      if(enforcer != ModelEnforcer) {
        throw new Error("Use MainModel.getInstance to access model");
      }
    }
 
  }
}

class ModelEnforcer {}

Ok so above we have the ever so popular GetInstance method which is what all external files will use to get an instance of the model. This will check if the local static variable for the single instance is populated and if not calls the constructor which takes the aforementioned local class. Inside the constructor you can initialize whatever you need to and basically everything else in the class is going to a public variable or a convenience method.

To summarize, we have a local class that makes sure that the only instance is created inside the MainModel class. And, of course, use GetInstance to grab the instance. That is pretty much it. If you have any questions or want to simply comment on using this method feel free to leave a comment.

Flex & Actionscript Singleton Model Class

In many of the projects and applications I build with Flex I use a singleton for the Model – we’ve talked about Singletons in the past here. Whether this is the preferred method of handling a model is a matter of opinion so I won’t be discussing it. However, I do want to share the model class that I typically use. Actionscript lacks a real static constructor, used for creating a single instance of a class, which means creating a nice singleton takes a bit more work.

To create the singleton I take advantage of using a local class definition inside of my model Actionscript file. From my understanding the local class, it is only visible and valid inside of the file. Also I owe props to some blog for pointing this trick out but I can’t remember the blog – sorry. This means we can ensure that the only instance of the model is created inside of the class. Let’s take a look of the entire code below and we can make a little more sense of it.

package
{
  [Bindable]
  public class MainModel
  {
    private static var _instance:MainModel = new MainModel(ModelEnforcer);
   
    public static function getInstance():MainModel
    {
      return _instance;
    }
   
    public function MainModel(enforcer:Class)
    {
      if(enforcer != ModelEnforcer) {
        throw new Error("Use MainModel.getInstance to access model");
      }
    }
 
  }
}

class ModelEnforcer {}

Ok so above we have the ever so popular GetInstance method which is what all external files will use to get an instance of the model. This will check if the local static variable for the single instance is populated and if not calls the constructor which takes the aforementioned local class. Inside the constructor you can initialize whatever you need to and basically everything else in the class is going to a public variable or a convenience method.

To summarize, we have a local class that makes sure that the only instance is created inside the MainModel class. And, of course, use GetInstance to grab the instance. That is pretty much it. If you have any questions or want to simply comment on using this method feel free to leave a comment.

Running a Method After A Delay on iPhone or Mac

In nearly every programming language there is a way to delay a method call. Objective-C is no different. They have built in a few simple methods to achieve this. We are going take a look at one of these methods today, all which reside in NSObject. This means any class you create will have the ability to call these methods. The method we are going to take a gander at is - (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay, got the love the Objective-C method names.

This method is pretty self explanatory thanks to the super long name. Basically, we are going to run a method and pass in the object as the parameter for the method after a certain amount of time (in seconds). Okay, imagine we have built an application which has a label that we want to change the text of after 5 seconds, why? I don’t know, if the label keeps the same text for more than 5 seconds it will self destruct, anyway I digress. So, we create a method to change the text to something like the following:

(void)changeText:(NSString *)text
{
  myLabel.text = text;
}

The new method is about as simple as it gets, it changes the label’s text to the passed in value. Now, in order to call this on a delay we need to use our aforementioned method, - (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay. In order to call our change text method with this it would look something like below.

[self performSelector:@selector(changeText:) withObject:@"Hello" afterDelay:5];

This pretty much covers it. One note is that say you have a method that doesn’t take a parameter like the one below.

(void)changeText
{
  myLabel.text = @"Hello";
}

Then if you want to call the method you pass in nil for the withObject argument, like the following:

[self performSelector:@selector(changeText) withObject:nil afterDelay:5];

Well that pretty much sums it up. You should now be able to call code after a delay. If you have any questions feel free to leave a comment or head on over to the forums.

Running a Method After A Delay on iPhone or Mac

In nearly every programming language there is a way to delay a method call. Objective-C is no different. They have built in a few simple methods to achieve this. We are going take a look at one of these methods today, all which reside in NSObject. This means any class you create will have the ability to call these methods. The method we are going to take a gander at is - (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay, got the love the Objective-C method names.

This method is pretty self explanatory thanks to the super long name. Basically, we are going to run a method and pass in the object as the parameter for the method after a certain amount of time (in seconds). Okay, imagine we have built an application which has a label that we want to change the text of after 5 seconds, why? I don’t know, if the label keeps the same text for more than 5 seconds it will self destruct, anyway I digress. So, we create a method to change the text to something like the following:

(void)changeText:(NSString *)text
{
  myLabel.text = text;
}

The new method is about as simple as it gets, it changes the label’s text to the passed in value. Now, in order to call this on a delay we need to use our aforementioned method, - (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay. In order to call our change text method with this it would look something like below.

[self performSelector:@selector(changeText:) withObject:@"Hello" afterDelay:5];

This pretty much covers it. One note is that say you have a method that doesn’t take a parameter like the one below.

(void)changeText
{
  myLabel.text = @"Hello";
}

Then if you want to call the method you pass in nil for the withObject argument, like the following:

[self performSelector:@selector(changeText) withObject:nil afterDelay:5];

Well that pretty much sums it up. You should now be able to call code after a delay. If you have any questions feel free to leave a comment or head on over to the forums.

Python Tutorial – Batch Image Resizing

Every once and a while I come across a simple task that deserves a script. Instead of using a language I know, this is often a great opportunity to pick up a new language or get a refresher on one I haven’t used in a long time. In this case, I needed to resize an entire directory of images. There are tons of free tools out there to do this, but where’s the fun in that? Also, I could have whipped this tool up very quickly in a language I know, like C#, however I haven’t used Python in several years and I decided it was time for a refresher.

For this tutorial, I’m using Python 2.6.5 and the Python Image Library (PIL). If you’re reading this tutorial, I’m sure you’ve got the first one installed and ready to go. The second one, PIL, is a free download.

I decided to create a simple command line application for this task. It will take three arguments: -d, -w, and -h. -d is the directory where your images are located. -w is the output image’s desired width. -h is the output image’s desired height. It will be used like this:

> python BatchImageResize.py -d "C:\MyImages" -w 1024 -h 768

The first thing we’re going to have to do is parse the command line arguments. Fortunately Python comes with a function, getopt, that makes this very simple.

import getopt, sys

# Parse the command line arguments
opts, args = getopt.getopt(sys.argv[1:], "d:w:h:")

getopt requires two parameters. The first is the list of arguments passed into the script. We’re skipping the first argument because that’s just the name of the script being executed. The second is the shorthand notation for each command line option. Since each option requires extra information, like a directory path, we need to stick a colon after each one. If the option were just a flag, with no extra info, the colon would be omitted. This returns two things. The first is a collection of tuples containing the argument and the extra information. The second contains all the other arguments that didn’t match what we were looking for. getopt has an optional third parameter that lets you specify a long name for each argument, but it’s not necessary for this tutorial.

Now that we’ve got the command line arguments parsed, we need to read the values into some variables. And while we’re at it, we might as well stick in a little bit of validation.

import getopt, sys

# Parse the command line arguments
opts, args = getopt.getopt(sys.argv[1:], "d:w:h:")

directory = ""
width = –1
height = –1

# Read the command line arguments
for opt, arg in opts:
  if opt == ‘-d’:
    directory = arg
  elif opt == ‘-w’:
    width = int(arg)
  elif opt == ‘-h’:
    height = int(arg)

# Check that the options were all set
if directory == "" or width == –1 or height == –1:
  print "Invalid command line arguments.\
  -d [directory] -w [width] -h [height] required"

  exit())

All we’re doing here is iterating through every specified option and saving the value to some variables. The width and height will need to be converted to integers for later use.

We’re now ready to actually convert all the images.

import os, getopt, sys, Image

# Parse the command line arguments
opts, args = getopt.getopt(sys.argv[1:], "d:w:h:")

directory = ""
width = –1
height = –1

# Read the command line arguments
for opt, arg in opts:
  if opt == ‘-d’:
    directory = arg
  elif opt == ‘-w’:
    width = int(arg)
  elif opt == ‘-h’:
    height = int(arg)

# Check that the options were all set
if directory == "" or width == –1 or height == –1:
  print "Invalid command line arguments.\
  -d [directory] -w [width] -h [height] required"

  exit()
 
# Iterate through every image in the directory and resize them
for file in os.listdir(directory):
  print "Resizing image " + file
  # Open the image
  img = Image.open(directory + "\\" + file)
  # Resize it
  img = img.resize((width, height), Image.BILINEAR)
  # Save it back to disk
  img.save(directory + "\\resized" + file)

This is actually the entire contents of the script. We first iterate through every file in the specified directory. We then open, resize, and save the image using PIL. There are several resizing techniques available, however I chose Bilinear because it yields perfectly satisfactory results. Every file will be saved to the same location it came from except with “resized” appended on the beginning.

And that’s it. Python has some great support for easily and quickly creating powerful command line applications. Thanks to the active community of developers there are libraries, like PIL, that will do pretty much anything you’ll need.

Python Tutorial – Batch Image Resizing

Every once and a while I come across a simple task that deserves a script. Instead of using a language I know, this is often a great opportunity to pick up a new language or get a refresher on one I haven’t used in a long time. In this case, I needed to resize an entire directory of images. There are tons of free tools out there to do this, but where’s the fun in that? Also, I could have whipped this tool up very quickly in a language I know, like C#, however I haven’t used Python in several years and I decided it was time for a refresher.

For this tutorial, I’m using Python 2.6.5 and the Python Image Library (PIL). If you’re reading this tutorial, I’m sure you’ve got the first one installed and ready to go. The second one, PIL, is a free download.

I decided to create a simple command line application for this task. It will take three arguments: -d, -w, and -h. -d is the directory where your images are located. -w is the output image’s desired width. -h is the output image’s desired height. It will be used like this:

> python BatchImageResize.py -d "C:\MyImages" -w 1024 -h 768

The first thing we’re going to have to do is parse the command line arguments. Fortunately Python comes with a function, getopt, that makes this very simple.

import getopt, sys

# Parse the command line arguments
opts, args = getopt.getopt(sys.argv[1:], "d:w:h:")

getopt requires two parameters. The first is the list of arguments passed into the script. We’re skipping the first argument because that’s just the name of the script being executed. The second is the shorthand notation for each command line option. Since each option requires extra information, like a directory path, we need to stick a colon after each one. If the option were just a flag, with no extra info, the colon would be omitted. This returns two things. The first is a collection of tuples containing the argument and the extra information. The second contains all the other arguments that didn’t match what we were looking for. getopt has an optional third parameter that lets you specify a long name for each argument, but it’s not necessary for this tutorial.

Now that we’ve got the command line arguments parsed, we need to read the values into some variables. And while we’re at it, we might as well stick in a little bit of validation.

import getopt, sys

# Parse the command line arguments
opts, args = getopt.getopt(sys.argv[1:], "d:w:h:")

directory = ""
width = –1
height = –1

# Read the command line arguments
for opt, arg in opts:
  if opt == ‘-d’:
    directory = arg
  elif opt == ‘-w’:
    width = int(arg)
  elif opt == ‘-h’:
    height = int(arg)

# Check that the options were all set
if directory == "" or width == –1 or height == –1:
  print "Invalid command line arguments.\
  -d [directory] -w [width] -h [height] required"

  exit())

All we’re doing here is iterating through every specified option and saving the value to some variables. The width and height will need to be converted to integers for later use.

We’re now ready to actually convert all the images.

import os, getopt, sys, Image

# Parse the command line arguments
opts, args = getopt.getopt(sys.argv[1:], "d:w:h:")

directory = ""
width = –1
height = –1

# Read the command line arguments
for opt, arg in opts:
  if opt == ‘-d’:
    directory = arg
  elif opt == ‘-w’:
    width = int(arg)
  elif opt == ‘-h’:
    height = int(arg)

# Check that the options were all set
if directory == "" or width == –1 or height == –1:
  print "Invalid command line arguments.\
  -d [directory] -w [width] -h [height] required"

  exit()
 
# Iterate through every image in the directory and resize them
for file in os.listdir(directory):
  print "Resizing image " + file
  # Open the image
  img = Image.open(directory + "\\" + file)
  # Resize it
  img = img.resize((width, height), Image.BILINEAR)
  # Save it back to disk
  img.save(directory + "\\resized" + file)

This is actually the entire contents of the script. We first iterate through every file in the specified directory. We then open, resize, and save the image using PIL. There are several resizing techniques available, however I chose Bilinear because it yields perfectly satisfactory results. Every file will be saved to the same location it came from except with “resized” appended on the beginning.

And that’s it. Python has some great support for easily and quickly creating powerful command line applications. Thanks to the active community of developers there are libraries, like PIL, that will do pretty much anything you’ll need.

Loading XML Through XNA Content Pipeline

XNA is quite possibly one of the most robust game programming frameworks out there. You can do nearly anything with it, and one of the reasons it is so flexible is its “Content Pipeline”. But sometimes it can be a bit tricky to use this feature, requiring us to do bit more work. But in the end, it helps to use the Content Pipeline. Luckily today we are going over how to use it to load in some XML.

A quick google search will reveal that loading in XML with C# and XNA can be a bit more complicated that it seems. There are several ways to accomplish XML integration, all dependent on your needs. Today we are going to go over the simplest way to load XML in XNA using the fancy Content Pipeline.

For the best viewing, use full screen mode.

<!–

Get Adobe Flash player

<!–