<?xml version="1.0" encoding="UTF-8"?>
<essay xml:lang="en" version="5.0" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:gal="http://norman.walsh.name/rdf/gallery#" xmlns:foaf="http://xmlns.com/foaf/0.1/">
<info>
    
    
    
    
    
    
<title>Image callouts</title><biblioid class="uri">http://norman.walsh.name/2006/06/10/imageobjectco</biblioid>
<volumenum>9</volumenum>
<issuenum>58</issuenum>
<pubdate>2006-06-10T16:55:51-04:00</pubdate>
<date>$Date: 2006-06-10 18:03:46 -0400 (Sat, 10 Jun 2006) $</date>
<author>
      <personname>
<firstname>Norman</firstname>
	<surname>Walsh</surname>
</personname>
    </author>
<copyright>
      <year>2006</year>
      <holder>Norman Walsh</holder>
    </copyright>
<abstract>
<para>A couple of simple tools designed to
make the DocBook <tag>imageobjectco</tag> tag more usable.</para>
</abstract>
<dc:subject rdf:resource="http://norman.walsh.name/knows/taxonomy#DocBook"/>
</info>

<para xml:id="p1">In designing DocBook markup, we've always tried to
stay within the capabilities of common, or at least known, processors.
No matter how sophisticated and semantically rich a markup design
is, if there aren't any tools that can actually process it in a
meaningful way, it's not very practical.</para>

<para xml:id="p2">Arguably, we were persuaded (back in mid-nineties) to introduce
graphic callouts before their time. (Or maybe one of the important
users at the time had a processor that could use them, I
don't actually recall.) It's always bothered me that they were so
hard to use.</para>

<para xml:id="p3">For those of you not familiar with this particular corner of
DocBook, graphic callout markup looks like this:</para>

<programlisting>&lt;mediaobject&gt;
  &lt;imageobjectco&gt;
    &lt;areaspec&gt;
      &lt;area xml:id="p1" coords="240,9049 497,8786"   linkends="c1"/&gt;
      &lt;area xml:id="p2" coords="2905,1360 3162,1098" linkends="c2"/&gt;
      &lt;area xml:id="p3" coords="8796,1491 9052,1229" linkends="c3"/&gt;
    &lt;/areaspec&gt;
    &lt;imageobject&gt;
      &lt;imagedata fileref="duckl-co.png"/&gt;
    &lt;/imageobject&gt;
  &lt;/imageobjectco&gt;
&lt;/mediaobject&gt;</programlisting>

<para xml:id="p4">(There's a corresponding element for callouts in a program listing
or other verbatim text, but it's well supported and fairly easy to
understand.)</para>

<para xml:id="p5">The idea is that those coordinates, expressed in somewhat
idiosyncratic units borrowed from
<link xlink:href="http://en.wikipedia.org/wiki/CALS">CALS</link>,
identify a region of the graphic where a “callout” occurs, that is,
a link to some description or other content related to that region of the
graphic. Here's a silly example:</para>

<sidebar>
<mediaobject>
  <imageobjectco>
    <areaspec>
      <area xml:id="pt1" coords="240,9049 497,8786" linkends="c1"/>
      <area xml:id="pt2" coords="2905,1360 3162,1098" linkends="c2"/>
      <area xml:id="pt3" coords="8796,1491 9052,1229" linkends="c3"/>
    </areaspec>
    <imageobject>
      <imagedata fileref="images/duckl-co.png"/>
    </imageobject>
  </imageobjectco>
</mediaobject>

<calloutlist>
  <callout arearefs="pt1" xml:id="c1">
	<para xml:id="p6">The bill.</para>
      </callout>
  <callout arearefs="pt2" xml:id="c2">
	<para xml:id="p7">The feet.</para>
      </callout>
  <callout arearefs="pt3" xml:id="c3">
	<para xml:id="p8">The tail.</para>
      </callout>
</calloutlist>
</sidebar>

<para xml:id="p9">In a browser context, the client side image map needed to make
the links active is generated automatically. So once you have the
graphic and the markup, it works reasonably well.</para>

<para xml:id="p10">There are two big problems: first, you have to generate CALS
coordinates that exactly correspond to the marks in the graphic.
Second, you have to actually add the callout marks to the graphic. As
far as I can tell, there's no way (in CSS, for example) to persuade
the renderer to add the marks as overlays<footnote>
      <para xml:id="p11">This would
require support for relative positioning on top of a relatively
positioned graphic. If it's possible, I'd love to be proved
wrong.</para>
    </footnote>.</para>

<para xml:id="p12">The CALS coordinates express the region using percentages of the
graphic size with an origin in the <emphasis>lower</emphasis> left
corner. You only have to work your way from pixels to CALS units with
a calculator once to convince yourself that you never want to do it
again.</para>

<para xml:id="p13">So I wrote a tool to do that part. Presented with a graphic
consisting only of rectangles on a plain background, it will find the
rectangles and calculate the CALS coordinates.</para>

<para xml:id="p14">Using layers in an editor like the
<link xlink:href="http://en.wikipedia.org/wiki/GIMP">GIMP</link>
makes it pretty easy to generate that graphic.</para>

<procedure>
<step>
      <para xml:id="p15">Open the original graphic.</para>
<mediaobject>
  <imageobject>
    <imagedata fileref="images/duck1.png"/>
  </imageobject>
</mediaobject>
</step>
<step>
      <para xml:id="p16">Add a new layer with a white background. Set the opacity to
about 40%.</para>
<mediaobject>
  <imageobject>
    <imagedata fileref="images/duck2.png"/>
  </imageobject>
</mediaobject>
</step>
<step>
      <para xml:id="p17">Select the pencil tool. Set the foreground color to black.
Choose an appropriate square brush. Add rectangles where you'd like
the callouts to appear.</para>
<mediaobject>
  <imageobject>
    <imagedata fileref="images/duck3.png"/>
  </imageobject>
</mediaobject>
</step>
<step>
      <para xml:id="p18">Raise the opacity of the layer to 100% and save the image
as a PNG (using a different name, of course, and exporting it so that
only the visible layer is in the saved image).
</para>
<mediaobject>
  <imageobject>
    <imagedata fileref="images/duck4.png"/>
  </imageobject>
</mediaobject>
</step>
</procedure>

<para xml:id="p19">Now run
<command xlink:href="examples/areasearch">areasearch</command>
on that graphic. This will print the relevant <tag>area</tag>s:</para>

<screen>$ areasearch images/duckr-callouts.png 
Loading images/duckr-callouts.png...
Searching for background color...
Searching for rectangles...
New rectangle at 276, 16 (10 x 10)
New rectangle at 156, 153 (10 x 10)
New rectangle at 18, 186 (10 x 10)
New rectangle at 164, 247 (10 x 10)
New rectangle at 179, 264 (10 x 10)
&lt;area xml:id="" linkends="" units="calspair" coords="9200,9455 9500,9149"/&gt;
&lt;area xml:id="" linkends="" units="calspair" coords="5200,4795 5500,4489"/&gt;
&lt;area xml:id="" linkends="" units="calspair" coords="600,3673 900,3367"/&gt;
&lt;area xml:id="" linkends="" units="calspair" coords="5466,1598 5766,1292"/&gt;
&lt;area xml:id="" linkends="" units="calspair" coords="5966,1020 6266,714"/&gt;</screen>

<para xml:id="p20">The areas are displayed in top-to-bottom, left-to-right order.
I actually want the last two areas to get the same number, so I edited the
results a little bit when building my <tag>imageobjectco</tag>:</para>

<programlisting>&lt;mediaobject&gt;
  &lt;imageobjectco&gt;
    &lt;areaspec&gt;
      &lt;area xml:id="p4" linkends="c4" coords="9200,9455 9500,9149"/&gt;
      &lt;area xml:id="p5" linkends="c5" coords="5200,4795 5500,4489"/&gt;
      &lt;area xml:id="p6" linkends="c6" coords="600,3673 900,3367"/&gt;
      &lt;areaset xml:id="p7" linkends="c7"&gt;
	&lt;area coords="5466,1598 5766,1292"/&gt;
	&lt;area coords="5966,1020 6266,714"/&gt;
      &lt;/areaset&gt;
    &lt;/areaspec&gt;
    &lt;imageobject&gt;
      &lt;imagedata fileref="images/duckr-co.png"/&gt;
    &lt;/imageobject&gt;
  &lt;/imageobjectco&gt;
&lt;/mediaobject&gt;</programlisting>

<para xml:id="p21">Now I can go back and add the actual callout numbers to the
graphic and I'll be ready to go.</para>

<para xml:id="p22">But wait. I already know where I want the callouts to go, why
am I doing this by hand? The <tag>area</tag>s in the DocBook document
identify the numbers and their locations, all I need is a tool to
combine them.</para>

<para xml:id="p23">In the DocBook document, the graphic identified in the 
<tag class="attribute">fileref</tag> attribute is the image that will
be displayed. If we want a tool to do the work, we need to tell that
tool how to find the original, pristine image. I could have done this
with a naming convention or by relative location, but I decided to use
a processing instruction. Adding
<tag class="xmlpi">base-image figures/duckr.png</tag> to the
<tag>imageobject</tag> gives
<command xlink:href="examples/areaoverlay">areaoverlay</command>
enough information to do the work.</para>

<para xml:id="p24">The result is just what you'd expect.</para>

<sidebar>
<mediaobject>
  <imageobjectco>
    <areaspec>
      <area xml:id="pt4" linkends="c4" coords="9200,9455 9500,9149"/>
      <area xml:id="pt5" linkends="c5" coords="5200,4795 5500,4489"/>
      <area xml:id="pt6" linkends="c6" coords="600,3673 900,3367"/>
      <areaset xml:id="pt7" linkends="c7">
	<area coords="5466,1598 5766,1292"/>
	<area coords="5966,1020 6266,714"/>
      </areaset>
    </areaspec>
    <imageobject>
      <?base-image images/duckr.png?>
      <imagedata fileref="images/duckr-co.png"/>
    </imageobject>
  </imageobjectco>
</mediaobject>

<calloutlist>
  <callout arearefs="pt4" xml:id="c4">
	<para xml:id="p25">The bill.</para>
      </callout>
  <callout arearefs="pt5" xml:id="c5">
	<para xml:id="p26">The body.</para>
      </callout>
  <callout arearefs="pt6" xml:id="c6">
	<para xml:id="p27">The tail.</para>
      </callout>
  <callout arearefs="pt7" xml:id="c7">
	<para xml:id="p28">The feet.</para>
      </callout>
</calloutlist>
</sidebar>

<para xml:id="p29">One interesting feature of the CALS units is that, because they're
percentages, the same callout markup can be used to put callouts on both
a low resolution image for screen presentation and a high resolution image
for print presentation.</para>

<para xml:id="p30">These tools make <tag>imageobjectco</tag> much easier to use, maybe
even practical. At last.</para>

</essay>

