0

Can I create a white PNG rectangle in ImageMagick which has a pixel ruler along each edge? E.g. every 50 pixels is a line and the text? Or at least a line.

Kind of like:

enter image description here

But so that I can create of arbitrary sizes.

theonlygusti
  • 11,032
  • 11
  • 64
  • 119
  • I find that xmgrace (https://en.wikipedia.org/wiki/Grace_%28plotting_tool%29) is good for such things. I'd use xmgrace to create a starting image with the tick-marks and import that image into ImageMagick. – Glenn Randers-Pehrson May 20 '17 at 22:41

2 Answers2

3

You could do something like this. It is only half the actual code it appears to be because I have spread it out logically and commented it into blocks to make it easy to follow:

#!/bin/bash
WIDTH=480        # Canvas width
HEIGHT=120       # Canvas height
TL=10            # Tick length

# Draw ticks using a loop across width of ruler
for ((i=0;i<$WIDTH;i+=10)); do

   # Decide tick length, doubling length if multiple of 100
   r=$TL
   [[ $((i%100)) -eq 0 ]] && ((r=2*r))

   # Draw ticks along top edge of ruler
   echo line $i,0 $i,$r

   # Draw ticks along bottom edge of ruler
   echo line $i,$HEIGHT $i,$((HEIGHT-r))

done | convert -size ${WIDTH}x${HEIGHT} xc:yellow -draw @- result.png

enter image description here

The for loop in the script is generating drawing commands like the following and passing them into the single convert command at the end which reads them from its standard input because of the -draw @-

line 0,0 0,20
line 0,120 0,100
line 10,0 10,10
line 10,120 10,110
line 20,0 20,10
line 20,120 20,110
line 30,0 30,10
line 30,120 30,110

I don't have all day to experiment with positioning of numbering labels but if you add the following couple of lines in just before the done at the bottom of the file, you will get labels:

# Add numbering labels
if [ $((i%100)) -eq 0 ]; then
   echo text $i,$((HEIGHT/2)) \"$i\"
fi

enter image description here


As regards the ticks down the vertical sides, there are a couple of ways to do it that rely increasingly on bash features - such as compound statements and the like. To keep it simple, I would probably take the image from the original part above and reload it to draw the vertical lines on and then re-save. It would look like this:

#!/bin/bash
WIDTH=480        # Canvas width
HEIGHT=120       # Canvas height
TL=10            # Tick length

# Draw ticks using a loop across width of ruler
for ((i=0;i<$WIDTH;i+=10)); do

   # Decide tick length, doubling length if multiple of 100
   r=$TL
   [[ $((i%100)) -eq 0 ]] && ((r=2*r))

   # Draw ticks along top edge of ruler
   echo line $i,0 $i,$r

   # Draw ticks along bottom edge of ruler
   echo line $i,$HEIGHT $i,$((HEIGHT-r))

   # Add numbering labels
   if [ $((i%100)) -eq 0 ]; then
      echo text $i,$((HEIGHT/2)) \"$i\"
   fi

done | convert -size ${WIDTH}x${HEIGHT} xc:yellow -draw @- result.png

### NEW PART FOR VERTICAL EDGES FOLLOWS 

# Draw ticks down sides of ruler
for ((i=10;i<$((HEIGHT-10));i+=10)); do

   # Decide tick length, doubling length if multiple of 100
   r=$TL
   [[ $((i%100)) -eq 0 ]] && ((r=2*r))

   # Draw ticks along left edge of ruler
   echo line 0,$i $r,$i

   # Draw ticks along right edge of ruler
   echo line $((WIDTH-r)),$i $WIDTH,$i

done | convert result.png -draw @- result.png

enter image description here


A few more refinements in this version:

#!/bin/bash
WIDTH=730        # Canvas width
HEIGHT=310       # Canvas height
TL=10            # Tick length

# Draw ticks using a loop across width of ruler
for ((i=0;i<$WIDTH;i+=10)); do

   # Decide tick length, doubling length if multiple of 100
   r=$TL
   [[ $((i%50)) -eq 0 ]] && ((r=3*TL/2))
   [[ $((i%100)) -eq 0 ]] && ((r=2*TL))

   # Draw ticks along top edge of ruler
   echo line $i,0 $i,$r

   # Draw ticks along bottom edge of ruler
   echo line $i,$HEIGHT $i,$((HEIGHT-r))

   # Add numbering labels
   if [ $((i%100)) -eq 0 ]; then
      echo text $i,$((HEIGHT/8)) \"$i\"
      echo text $i,$((7*HEIGHT/8)) \"$i\"
   fi

done | convert -size ${WIDTH}x${HEIGHT} xc:yellow -draw @- result.png

# Draw ticks down sides of ruler
for ((i=10;i<$((HEIGHT-10));i+=10)); do

   # Decide tick length, doubling length if multiple of 100
   r=$TL
   [[ $((i%50)) -eq 0 ]] && ((r=3*TL/2))
   [[ $((i%100)) -eq 0 ]] && ((r=2*TL))

   # Draw ticks along left edge of ruler
   echo line 0,$i $r,$i

   # Draw ticks along right edge of ruler
   echo line $((WIDTH-r)),$i $WIDTH,$i

   # Add numbering labels
   if [ $((i%100)) -eq 0 ]; then
      echo text 40,$i \"$i\"
      echo text $((WIDTH-80)),$i \"$i\"
   fi

done | convert result.png -draw @- result.png

enter image description here

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • This looks perfect! How do I extend it to include vertical measurements as well? – theonlygusti May 21 '17 at 09:45
  • 1
    Very nice Mark. To get the left and right sides, you could also just rotate the image and use your same code for the top and bottom. Then rotate back. The labels on the sides would be rotated also. I don't know if that is an issue or not. – fmw42 May 21 '17 at 19:24
2

Something quick and dirty can be done with ImageMagick using my script, grid, if you are running a Unix-like OS: Linux/Mac OSX/Windows 10 unix/Windows w/Cygwin). This will create a grid with spacing 10.

convert -size 499x149 xc:white miff:- | grid -s 10 -d 9 - grid.png 

enter image description here

convert grid.png \( -size 481x131 xc:white \) -gravity center -compose over -composite ruler.png

enter image description here

fmw42
  • 46,825
  • 10
  • 62
  • 80