Skip to main content

Linux tip: Creating a pixel ruler from the command line

How to draw lines and text on images with Bash scripting, shell arithmetic, and ImageMagick

Ian Shields, Senior Programmer, IBM
Ian Shields
Ian Shields works on a multitude of Linux projects for the developerWorks Linux zone. He is a Senior Programmer at IBM at the Research Triangle Park, NC. He joined IBM in Canberra, Australia, as a Systems Engineer in 1973, and has since worked on communications systems and pervasive computing in Montreal, Canada, and RTP, NC. He has several patents. His undergraduate degree is in pure mathematics and philosophy from the Australian National University. He has an M.S. and Ph.D. in computer science from North Carolina State University.

Summary:  Learn how to use the Linux® command line and some basic Bash scripting techniques to draw lines and text on images using ImageMagick. And create a pixel ruler along the way.

View more content in this series

Date:  23 Jul 2009
Level:  Intermediate PDF:  A4 and Letter (64KB | 11 pages)Get Adobe® Reader®
Activity:  10923 views
Comments:  

Sometimes I need to draw a few lines or some text on an image or a blank canvas. Just recently I needed to include a simple image of a pixel ruler in a developerWorks article. I wanted the image to be 572 pixels wide, to match the current recommended maximum for developerWorks article images as described in "Illustrating your article or tutorial for developerWorks." Lots of on-screen pixel rulers are available for Linux and for Windows (see Resources), but I just wanted a simple GIF, JPEG or PNG image. This tip shows you how to use Bash scripting, shell arithmetic, and ImageMagick to create a pixel ruler.

Make a canvas

The first thing any artist needs is a canvas, so let's create one using the XC pseudo image type in ImageMagick. We also need a color, either one of the many named colors in ImageMagick, or a custom color. (See Resources for a link to the ImageMagick documentation, where you can find a full list of pseudo image types as well as color names.) Listing 1 shows how to make a light blue 572x100 canvas using the convert command. (The convert command is customarily used to convert to a different image format or otherwise alter an image.)


Listing 1. Creating a canvas
convert -size 572x100 xc:lightblue ruler1.gif
            

Figure 1 shows our new canvas.


Figure 1. A light blue 572x100 pixel canvas for our ruler
A light blue 572x100 pixel                     canvas for our ruler

Add a few lines

Now that we have a canvas, let's draw marks to show the various points along the ruler. 72 ppi (pixels per inch) is standard for Web-based graphics, so let's put our first mark at 72 pixels and make it extend 30 pixels from the bottom of the image. Let's also make the fill color for the line black and specify the two end points of the line.


Listing 2. Adding a line to the canvas
convert  -fill black -draw "line 72,70 72,100" ruler1.gif ruler2.gif 
            

Figure 2 shows our new image with a single line drawn on it.


Figure 2. The canvas with a single vertical line 72 pixels from the left
The canvas with a single                     vertical line 72 pixels from the left

Doing this individually for each line we want on the ruler isn't too appealing. So let's use the seq command to generate a list of horizontal offsets 72 pixels apart and a for loop to draw our main lines on the ruler as shown in Listing 3.


Listing 3. Adding lines to the canvas every 72 pixels
convert  -fill black -draw "$(for n in $(seq 0 72 572) ;\
 do echo line $n,70 $n,100 ; done)" ruler1.gif ruler3.gif 
            

Notice that we use two command substitutions to generate the individual line specifications for the draw operation. We also put a mark at 0, the left edge. Figure 3 is now starting to look more like a ruler.


Figure 3. The canvas with vertical lines every 72 pixels from the left
The canvas with vertical                     lines every 72 pixels from the left

Scripting more lines

At this point, our command line is getting a little complex, and we still have only the major marks on our ruler. Time to start scripting. In Listing 4, we use shell arithmetic and for loops to place a 20-pixel mark half way between the marks we already have, and to place 10-pixel marks every 6 pixels between the longer marks. We'll call the script buildruler.sh and put it in our working directory for the purposes of this article.


Listing 4. Adding a full set of marks to the ruler
#!/bin/bash
# Take user parameters or set defaults
rulername="$1"
rulerlength="$2"
rulername="${rulername:=ruler.gif}"
rulerlength="${rulerlength:=572}"
drawstring=""
#Build the line definitions for the ruler marks
for x1 in `seq 0 72 $rulerlength`; do
  drawstring="$drawstring line $x1,70 $x1,100"
  for x2 in 0 36; do
    (( offset = $x1 + $x2 ))
    drawstring="$drawstring line $offset,80 $offset,100"
    for x3 in `seq 6 6 30`; do
      (( offset2 = $offset + $x3 ))
      drawstring="$drawstring line $offset2,90 $offset2,100"
    done
  done
done
#Create the ruler
convert -size "${rulerlength}x100" xc:lightblue -fill black \
 -draw "$drawstring" "$rulername"
            

Notice that we added a couple of parameters to allow a user to change the name of the ruler and to specify the length. Our ruler now looks like Figure 4. We used the command ./buildruler.sh ruler4.gif to generate this ruler.


Figure 4. Our ruler with a full set of marks 6 pixels apart
Our ruler with a full set                     of marks 6 pixels apart

Adding text

Quoting

One of the tricky things with scripting is knowing when quotes are needed and when they are not, and how to pass quoted strings as parameters. Pay particular attention to the quoting used in these scripts.

Now let's label the larger marks on our ruler with the numbers 0, 72, 144, and so on. We need to tell ImageMagick what font to use and what size and color it should be. Obviously, the 0 should be at the left edge of the ruler, but if we place the two- and three-digit numbers at the 72-pixel points, they will appear unbalanced. To correct this, we'll shift them slightly to the left, to make them appear more centered over the mark. Our enlarged script is shown in Listing 5.


Listing 5. Adding labels to the ruler
#!/bin/bash
# Take user parameters or set defaults
rulername="$1"
rulerlength="$2"
rulername="${rulername:=ruler.gif}"
rulerlength="${rulerlength:=572}"
drawstring=""
#Build the line definitions for the ruler marks
for x1 in `seq 0 72 $rulerlength`; do
  drawstring="$drawstring line $x1,70 $x1,100"
  for x2 in 0 36; do
    (( offset = $x1 + $x2 ))
    drawstring="$drawstring line $offset,80 $offset,100"
    for x3 in `seq 6 6 30`; do
      (( offset2 = $offset + $x3 ))
      drawstring="$drawstring line $offset2,90 $offset2,100"
    done
  done
done
#Add the labels
labelfont="-fill black -font helvetica -pointsize 24  -draw"
labelstring="text 0,60 \"0\" "
for x1 in 72; do
  (( offset = $x1 - 12 ))
  labelstring="$labelstring text $offset,60 \"$x1\" "
done
for x1 in `seq 144 72 $rulerlength`; do
  (( offset = $x1 - 18 ))
  labelstring="$labelstring text $offset,60 \"$x1\" "
done

#Create the ruler
convert -size "${rulerlength}x100" xc:lightblue -fill black \
 -draw "$drawstring" $labelfont "$labelstring" "$rulername"

Now our ruler looks like Figure 5.


Figure 5. Our ruler with labels a full set of marks
Our ruler with labels a                     full set of marks

Positioning text

So how did we know how much to offset the text or how far down from the top to place it? The short answer is that I experimented and guessed! Not an ideal solution.

To do a better job on placing text, we need to know how big the rectangle containing the text will be. But that depends on the font and whether the font is proportional and other things that aren't so easy to calculate. Fortunately, in the same way that we can create a canvas with ImageMagick, we can also create a label. We'll create a title of Pixel Ruler and make it a 36-point font. The label is created as an image, and we can use the identify command to determine its size, as shown in Listing 6.


Listing 6. Creating a title and measuring its size
$ convert -fill NavyBlue -background Lavender -font helvetica -pointsize 36 \
 label:"Pixel Ruler" label.gif
$ identify "label.gif"
label.gif GIF 175x36 175x36+0+0 8-bit PseudoClass 256c 1.98kb 

We've made the text navy blue and added a lavender background color to help the image stand out from this page background, but you get the same size image with or without the background color. The resulting label image is shown in Figure 6.


Figure 6. The label as an image
The label as an                     image

Even better than writing a file, we can use the ImageMagick INFO class to determine even more information about the text, including where the baseline is. We'll write the text onto a large enough canvas and then trim the canvas to the edge of the text as shown in Listing 7.


Listing 7. Using the INFO image class to determine font information
$ convert -size 572x100 xc:lightblue -font helvetica -pointsize 36 \
  -fill black -undercolor lavender  -annotate +40+50 'Pixel Ruler' -trim info:
xc:lightblue XC 174x36 572x100+40+23 16-bit DirectClass

Annotated text starts at a point whose y coordinate represents the baseline of the text. The above output shows that the text fits in a box that is 174x36 pixels in size. The 1-pixel discrepancy between this and our earlier result is not significant. The top of the box is positioned 23 pixels below the top of our original canvas. Since the baseline was 50 pixels below the top of the original canvas, this means the baseline is actually 27 pixels (50 minus 23) below the top of the text, leaving 9 pixels for descenders. Figure 7 illustrates the relationship using an image placed on the untrimmed canvas.


Figure 7. The label metrics
The label                     metrics

So now that we have the label dimensions, let's place the baseline 40 pixels from the top of the image and center it horizontally. Our final script is shown in Listing 8 and is also available for download.


Listing 8. Our final script
#!/bin/bash
# Take user parameters or set defaults
rulername="$1"
rulerlength="$2"
rulername="${rulername:=ruler.gif}"
rulerlength="${rulerlength:=572}"
drawstring=""
#Build the line definitions for the ruler marks
for x1 in `seq 0 72 $rulerlength`; do
  drawstring="$drawstring line $x1,70 $x1,100"
  for x2 in 0 36; do
    (( offset = $x1 + $x2 ))
    drawstring="$drawstring line $offset,80 $offset,100"
    for x3 in `seq 6 6 30`; do
      (( offset2 = $offset + $x3 ))
      drawstring="$drawstring line $offset2,90 $offset2,100"
    done
  done
done
#Add the labels
labelfont="-fill black -font helvetica -pointsize 24  -draw"
labelstring="text 0,60 '0' "
for x3 in 72; do
  offset3=$(($x3 - 12 ))
  labelstring="$labelstring text $offset3,60 '$x3' "
done
for x4 in `seq 144 72 $rulerlength`; do
  offset4=$(( $x4 - 18 ))
  labelstring="$labelstring text $offset4,60 '$x4' "
done
#Add a title
titledimension=$(convert -size 572x100 xc:lightblue -font helvetica \
  -pointsize 36  -fill black -undercolor lavender\
  -annotate +40+50 'Pixel Ruler' -trim info: | awk ' {print $3 } ')
titlewidth=${titledimension%x*}
titlefont="-fill NavyBlue -font helvetica -pointsize 36"  
titlepos=$(( (($rulerlength - $titlewidth)) / 2 ))
titletext="text $titlepos,30 'Pixel Ruler' "
#Create the ruler
convert -size "${rulerlength}x100" xc:lightblue \
 -fill black  -draw "$drawstring" $labelfont "$labelstring" \
 $titlefont -draw "$titletext" "$rulername"

The final ruler is shown in Figure 8.


Figure 8. The final ruler, complete with title
The final ruler, complete                     with title

Not too bad for someone with no artistic skills!


A semi-practical example

When images are indented—as in lists, for example—the maximum width allowed on developerWorks is reduced accordingly. So you can use these handy rulers as a check for any images you submit with an article.

  • This is a short ruler in an unordered list that was created with the command ./buildruler.sh ruler9.gif 400.

    Figure 9. A 400-pixel ruler
    A 400-pixel                             ruler

    • And this is an even shorter ruler that is further indented. It was created with the command ./buildruler.sh ruler10.gif 300.

      Figure 10. A 300-pixel ruler
      A 300-pixel ruler


Conclusion

In this short exercise, you've seen some basic techniques for scripting images containing lines and text using ImageMagick. You'll find more techniques in our articles "Graphics from the command line" and "More graphics from the command line." You'll also find a host of other examples at the ImageMagick home page. See Resources for links.

The scripts here are not bullet-proof. For example, we do not validate that length is a positive number big enough for a meaningful ruler or that the file specified is a valid image file type for ImageMagick. You will find other issues as well. For example, the ruler labels may be truncated as in Figure 10 above, a possibility our script did not consider.

You can also parameterize as many aspects as you wish. Try adding color or ruler height as parameters, for example.

While this tip has focused on using ImageMagick with Linux, ImageMagick is available for other platforms including Windows. Try using these techniques with your favorite scripting tools on your favorite platform.



Download

DescriptionNameSizeDownload method
Script to build your own pixel rulerbuildruler.zip1KB HTTP

Information about download methods


Resources

Learn

Get products and technologies

Discuss

  • Get involved in the My developerWorks community; with your personal profile and custom home page, you can tailor developerWorks to your interests and interact with other developerWorks users.

About the author

Ian Shields

Ian Shields works on a multitude of Linux projects for the developerWorks Linux zone. He is a Senior Programmer at IBM at the Research Triangle Park, NC. He joined IBM in Canberra, Australia, as a Systems Engineer in 1973, and has since worked on communications systems and pervasive computing in Montreal, Canada, and RTP, NC. He has several patents. His undergraduate degree is in pure mathematics and philosophy from the Australian National University. He has an M.S. and Ph.D. in computer science from North Carolina State University.

Comments



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Linux
ArticleID=416343
ArticleTitle=Linux tip: Creating a pixel ruler from the command line
publish-date=07232009
author1-email=ishields@us.ibm.com
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers