PDF In-Depth

Image Mapping in PDF - Create a JavaScript Color Picker

August 05, 2001

Advertisement
Advertisement
 

Among the many feats of "HTML emulation" of which PDF is capable, one of the less-appreciated (but more remarkable) such feats is image-mapping. This is the familiar web-page trick where you click on a given spot in an image, and the X-Y coordinate info from your click is used to determine what pops up next on your browser's screen.

For example, if you're looking at information about a company's products and you want to be contacted by a sales rep, there may be a web page where you can click on a map of your state or province, thereby triggering a web page that shows the name or phone number for the sales rep in your area. This kind of trick is surprisingly easy to pull off in PDF. As with HTML, the hard part of image mapping is getting the back-end magic to happen on the server. If your hosting service will let you write CGI scripts (in Perl, say), you're 90% of the way there.

In this article, I'll show you how to set up an image map in a PDF file and couple it to a Perl script running on a server. The actual example used in this exercise is a color-picker swatch. The idea is that when the user clicks on a given spot in the swatch, the mouse coordinates (which get sent to our server script) can be used to derive red, green, and blue values that correspond to the RGB color the user clicked on. We can then serve those red, green, and blue values back to the user in the form of FDF data. The FDF data will populate textfield values in a form of our choice. In this simple example, we just populate the color-channel fields in the input form. A simple JavaScript routine then converts those values to an RGB color; and we use that RGN color as the background color in an otherwise-empty "mini-swatch" textfield, which gives visual feedback as to the color the user has chosen.

Color Picker

Notice that the cursor is over an orange area of the picker swatch. The mouse has been clicked at this position, causing the mini-swatch in the lower left portion of the screen to be filled with the selected color, but only after a round trip to the server. A script on the server uses the mouse-hit info to generate the color in the mini-swatch.

To see how it all works, let's talk, first, about how image-mapping can be set up in PDF.

Image Maps in PDF

There is no interface to image mapping in Acrobat, unfortunately. That's the Bad News. The Good News is that you can set this feature up quite painlessly by following a few steps. The first thing to remember is that image maps are associated with links, not with form fields. And in order for this to work, your link has to be to an URL on the World Wide Web. So do this:

  1. First, drag out a link bounding box using Acrobat's Link Tool.

  2. When the link is sized the way you want it, use the Action Type popup menu in the Create Link dialog box to choose World Wide Web Link. This will cause the button at the bottom of the dialog to change to "Edit URL..."

  3. Click the "Edit URL..." button. Enter the URL address where you expect to place your server script (the script that will deal with the incoming mouse-hit info). But don't dismiss the dialog just yet!

  4. After you've typed your URL, add the following string to the URL: -/IsMap true. That should be 12 characters, beginning with a hypen and ending with the lowercase word "true." Dismiss all dialogs and Save the PDF file.

  5. Open your PDF file in a text editor. Search for the string "-/IsMap true)" and replace it with ") /IsMap true". When you are done there should be no parenthesis after "true." There should, however, be a closed-paren after the web URL of your link, and the original hyphen should be a space. What we are doing here is adding a new dictionary entry, /IsMap true, to your link's action. If you carry this out exactly as described, you will not change the file length of your PDF file and there should be no internal restructuring of the file (that is, the 'xref' table offset will be undisturbed). Save the file.
  6. Reopen the PDF file in Acrobat or Reader. Check to see that when you leave the mouse over a "hot" part of the link bounding box, the URL name shows up in the yellow hint-box, followed by a question mark and the mouse X-Y coordinates. The coordinates will change as you move the mouse. (Pretty amazing, isn't it?)

If you saw the X-Y coordinates of the mouse in step six, it means everything went okay and you now have a "map" under the link area. Any click on this link whne the file is being viewed in a browser should cause the browser to emit a GET operation to the URL in the link, with mouse-coordinates appended following a question mark. This is what you want.

The Picker

Our example file uses a link over the top of a color-swatch. The color-picker swatch is a 300-by-100-pixel bitmap created in Photoshop using Jim Bumgardner's excellent freeware plug-in, Expression 3.0b. The way Expression works is that it allows you to enter C-like expressions (containing arithmetic operations) for the various color channels, using certain predefined variables such as 'x' for the x-coordinate of the current pixel and 'w' for the overall width of the bitmap (in pixels). Thus, if you were to enter an expression of 'x/w' for, say, the red channel of an RGB image, you would fill the red channel with a color ramp, with values ranging from zero at the lefthand edge of the bitmap to 1.0 at the right edge. In Photoshop, pixel values between zero and 1.0 will simply result in black, since Photoshop expects color values to be in the range 0..255. Hence, a better way to get a "red ramp" in Photoshop would be to use '255*x/w' (255 times 'x', divided by the image width) in the Red channel of Expression (and zero in the other channels). Expression also allows the use of trigonometric functions, so you can vary colors sinusoidally across a given swatch.

Our 300x100 color-picker image was created with the following formulas in Expression:

RED   = 255-(y/h)*255*(1+sin(6.3*x/w))/2

GREEN = 255-(y/h)*255*(1+cos(6.3*x/w))/2

BLUE  = 255-(y/h)*255*(1-sin(6.3*x/w))/2

Acrobat uses a normalized representation of RGB space, in which channel values go from 0..1, so to get Acrobat color-channel values from the above expressions, just substitute 1.0 for 255.

In making the PDF file containing the color map, I applied the color map as a button icon, stretched to 522 by 176, but found that the resulting PDF file was over 100 Kbytes in size. To get the filesize back down, I saved a Postscript version of the file and Distilled it with JPEG compression set to Maximum quality, which brought the file to less than 10K. (In a color map of this sort, the smooth, gradual color changes in the map cause JPEG to be very efficient, giving excellent compression even with quality set to Maximum.) I then added some text fields, which brought the total file size to just over 14,000 bytes.

To make the swatch a true image map, I added a link, following the six steps outlined above.

Technically, the file ends up being a PDF form since there are textfields in it. But it's a form with no Submit button! Notice that what activates the form is a mouse hit in the color-swatch area (the image map). This triggers a GET operation back to the server.

At the Server

A simple Perl script (10 expressions long) at the web URL specified in our link does all the "hard work" (if it can be called that) of processing the image hit. Since the script is triggered by a GET operation, we can retrieve the mouse coords in the QUERY_STRING environmental variable. Our job is to use the X and Y coordinates to derive red, green, and blue color-channel values using the above-mentioned formulas. The Perl code for doing this is very straightforward. (The entire script is reproduced below.)

#!/usr/bin/perl
use CGI qw/:standard/;

$query = $ENV{'QUERY_STRING'};
print header('application/fdf');
print GenerateFDF($query);

# -------------------------------------------
sub GenerateFDF {
   
my ($x,$y) = split /,/,$_[0];
   
my $red = 1.0-($y/176)*(1+sin(6.3*$x/522))/2;
my $green = 1.0-($y/176)*(1+cos(6.3*$x/522))/2;
my $blue = 1.0-($y/176)*(1-sin(6.3*$x/522))/2;
     
$fdfString =<> << /V
($green)/T (g)>> << /V ($red)/T (r)>> << /V
(ColorPicker)/T (title)>> 
] 
/F (http://www.acroforms.com/archive/picker.pdf)>> 
>> 
endobj
trailer
<<
/Root 1 0 R 
>>
%%EOF
END_FDF

return $fdfString;
}

As you can see, the main routine is only three lines long. All the work is done in the subroutine, GenerateFDF(). The first line of that subroutine just splits the incoming mouse coords at the comma and puts the raw numbers into Perl variables, $x and $y. The next three lines derive the color-channel values ($red, $green, and $blue) using the appropriate math. Finally, we stuff a Perl variable ($fdfString) with raw FDF containing our red, green, and blue values, using Perl's handy "HERE statement" construct. The returned string contains the entire FDF output, which gets written out to the HTTP connection back to the browser (after first writing the appropriate MIME-typed header info).

Bottom line: We send back a dynamically generated FDF response containing RGB info for the hit. Note that the /F entry in the FDF data specifies the URL of the PDF file we want our data to be merged into. In this case, we're simply merging the data into the same PDF form that originated the GET, but in theory we could send FDF to any PDF form of our choosing. That means, for example, that Form A could (based on a user button-hit) cause the color-picker form to be called up; and a hit in the color-picker form could cause control to return to Form A.

In Conclusion

In this short but fairly sophisticated example we've seen how to set up a link to be an "image map" in PDF; how to process the mouse-hit data at the server; how to serve dynamic FDF back to the client; and how to use the returned data to do something useful back at the client's machine (i.e., display a mini-swatch showing the selected color to the user). It's significant to note that neither the PDF form nor the server script need be long or complex. In this example, the PDF form was barely 14K in size and the Perl script was only ten expressions long. And since FDF was used for the transmission of data back to the client, we avoided having to re-serve large amounts of HTML or other data; in fact, our FDF stream was only 200 bytes long. With these sorts of filesizes, lightning-fast response times are possible, even on slow networks.

Another win-win situation for PDF.

PDF In-Depth Free Product Trials Ubiquitous PDF

Debenu Quick PDF Library

Get products to market faster with this amazing PDF developer SDK. Over 900 functions and an equally...

Download free demo

PDF Master Series III: Eugene Y. Xiong talks with Planet PDF

Planet PDF talks with another Master of the PDF Universe, Eugene Y. Xiong, Founder and Chairman of the Board at Foxit Software Inc. in Fremont California. Xiong is a quiet yet astounding achiever, you (usually) won't find him talking at conferences, exhibits, or publishings, but what you will find is the result of his leadership in places you would never expect.

September 14, 2016
Platinum Sponsor



Search Planet PDF
more searching options...
Planet PDF Newsletter
Most Popular Articles
Featured Product

Debenu PDF Aerialist 12

The ultimate plug-in for Adobe Acrobat. Advanced splitting, merging, stamping, bookmarking, and link control. Take Acrobat to the next level.

Features

Adding a PDF Stamp Comment

OK, so you want to stamp your document. Maybe you need to give reviewers some advice about the document's status or sensitivity. This tip from author Ted Padova demonstrates how to add stamps with the Stamp Tool along with related comments.