Have you ever pulled a handful of hair from your head? If you’ve ever tried to create an HTML Image Map with the GIMP, then I’m sure your sitting in clumps of it. No More! With gen_imgmap.py
, you can auto-generate your image maps from a simple PNG image file and a CSV text file!
Here’s how it works:
Create an image that has a unique color for each area you would like to make clickable. Like this:
Now, all you need is a CSV file that maps the color values in your image to the href, name, title, and any other attributes that you would like on your area tags. The first line of the CSV contains labels for the following rows. The first label has to be “color”, it can be either a hexadecimal color code or an integer color code. The remaining columns can be whichever attributes you would like to give to your area tags. Like This (I’m using integer color codes here):
color, id, title, href
46621634, AKZ208, Lower Kobuk and Noatak Valleys, http://pafg.arh.noaa.gov/zonefcst.php?zone=AKZ208
47610067, AKZ217, Upper Kobuk and Noatak Valleys, http://pafg.arh.noaa.gov/zonefcst.php?zone=AKZ217
47549398, AKZ205, Northwestern Brooks Range, http://pafg.arh.noaa.gov/zonefcst.php?zone=AKZ205
49656045, AKZ206, Northeastern Brooks Range, http://pafg.arh.noaa.gov/zonefcst.php?zone=AKZ206
49847290, AKZ218, Southeastern Brooks Range, http://pafg.arh.noaa.gov/zonefcst.php?zone=AKZ218
45763761, AKZ210, Northern and Interior Seward Peninsula, http://pafg.arh.noaa.gov/zonefcst.php?zone=AKZ210
46099384, AKZ216, Lower Koyukuk and Middle Yukon Valleys, http://pafg.arh.noaa.gov/zonefcst.php?zone=AKZ216
46608056, AKZ219, Upper Koyukuk Valley, http://pafg.arh.noaa.gov/zonefcst.php?zone=AKZ219
45777072, AKZ220, Yukon Flats and Surrounding Uplands, http://pafg.arh.noaa.gov/zonefcst.php?zone=AKZ220
45322154, AKZ221, Central Interior, http://pafg.arh.noaa.gov/zonefcst.php?zone=AKZ221
47940043, AKZ222, Middle Tanana Valley, http://pafg.arh.noaa.gov/zonefcst.php?zone=AKZ222
47594677, AKZ224, Upper Tanana Valley and the Fortymile Country, http://pafg.arh.noaa.gov/zonefcst.php?zone=AKZ224
49981415, AKZ215, Lower Yukon Valley, http://pafg.arh.noaa.gov/zonefcst.php?zone=AKZ215
45428630, AKZ151, Kuskokwim Valley, http://pafg.arh.noaa.gov/zonefcst.php?zone=AKZ151
48126408, AKZ225, Denali, http://pafg.arh.noaa.gov/zonefcst.php?zone=AKZ225
49956578, AKZ223, Deltana and Tanana Flats, http://pafg.arh.noaa.gov/zonefcst.php?zone=AKZ223
47673817, AKZ226, Eastern Alaska Range, http://pafg.arh.noaa.gov/zonefcst.php?zone=AKZ226
If for some reason you need to use comma’s inside one of your attribute strings, you’ll have to double quote all of them.
Now, all that must be done is the running of the program (-i
tells gen_imgmap.py
to use integer color codes):
./gen_imgmap.py -i alaska.png attributes.csv map.html
This will take a couple of minutes. For simpler color maps, obviously the program will run far more quickly. When it’s finished, you’ll be left with something like this:
You may also notice that a folder called “masks” is created, and that this folder contains a bunch of PNG image masks with column two of the CSV file as their image name. gen_imgmap.py
uses these files to figure out where to place the bounding polygons for your area tags. You may also use them to create overlays for each region of your image. Check out this page to see how I have applied this method to a production web page.
To use gen_imgmap.py
you’ll need the following software:
- ImageMagick ≥ 6.3.0
- Python ≥ 2.4
- numpy ≥ 1.0
- PIL ≥ 1.1.6
You can get it here: gen_imgmap.py
.
Update:
micheal fixed a couple of problems with the script with a patch below in the comments. I have updated the link to reflect his patch.
14 comments:
Hey AJ, this is pretty cool! I remember you telling me about working on something like this for the weather service, but I didn't know you generalized it all nice like that. Maybe I can take advantage for my website at some point... I've wanted to include some location information so people can look up say recycling and see the recycling centers in their area since the conception of the site. Anyways, I look forward to seeing more tricks you come up with.
Thanks for the great tool Alex. I have the tool running my my "mask" png files are all black. I was wondering if you could highlight the steps you use when generating the color values. For example, will a true-color PNG file work? If I reduce the colors down then the colors dither... so reducing the colors doesn't appear to be an option in my case. For the true-color PNG I am using hex color values in the form: c41f54 as displayed in GIMP. Is this the format of the color that I should be using? What tool will give you the integer color values that you refer to? Thanks for your help with this.
Roland
Roland,
Yes. A true color PNG should work. In your CSV file, you can specify the colors in hex. Note that dithering will prevent the algorithm from working, as it depends on regions being the same integer color. There shouldn't be any aliasing between regions either, that also will confuse the algorithm.
If you link an image you are having trouble with, I'll be glad to look into why it might not be working.
The integer color values are generated by the ArcMap GIS software... I haven't run into any other systems that use them.
Alex
Hi Alex,
I too have access to ArcMap. However, I don't see how you may be getting the integer values with out-of-the-box ArcMap. I notice that when I run the Python Script that the following hex values get converted to the list of RGB values below. However, these RGB values are different from other converters.
color
C41F54
ED7740
color
rgb(7, 12, 8)
rgb(12, 1, 5)
I believe I have eliminated any dithering in the image.
Thanks,
Roland
Hi Alex,
To help reduce the variables with this question, I have downloaded the file alaska.png from this page. I performed a identify -verbose in imagemagick to determine the list of colors in the file. This is a snippet of the listing:
5473: (184,107,191) #B86BBF rgb(184,107,191)
4230: (176,128,186) #B080BA rgb(176,128,186)
...
Next, using the imagemagick results I changed your integer values to these HEX values in your example .csv file above. This allowed me to run the tool using hex values instead of the integer values. These are the first two rows of the results. All masks returned as black:
convert alaska.png -transparent "rgb(9, 2, 11)" -fx "a" +matte -negate masks/AKZ
215.png
convert alaska.png -transparent "rgb(12, 5, 13)" -fx "a" +matte -negate masks/AK
Z219.png
These results are similar to my previous results, where the rgb values seem low.
Thanks Again,
Roland
the algorithm that converts hex to int values has a bug, should be color[i:i+2], that's why the low values. Also the html it generates is invalid - here's a diff for the fixes i made minor fixes
I also added a check for PIL version because this a nasty problem to figure out - the script dies and doesn't give any hint why that is ;)
Very cool software, thanks a lot for sharing it.
micheal,
thanks for catching these bugs. i've updated the post with a patched version of the file and a credit to you in the file comments.
roland,
does it work with these changes?
Hi Michael,
Thanks for your changes. They fixed it.
Alex,
Still curious how you are getting your integer values out of ArcMap.
Thanks Again For Sharing,
Roland
Hey Roland.
I wrote a VBA script for ArcMap to generate a CSV text file in the required format for the python script. I don't have this VBA script on hand... I no longer work for the company that I was working for and this file is probably lost.
I notice your production version does not have unique colors for each area -- is that because you produce the same size image with a different theme, so the original image map still works? --tim
Tim,
That's exactly why. The color-themed image's only purpose is to generate the HTML image map. Once the image map has been generated you can use any image that you like. In fact, the image on the production page is being regenerated at 15 minute intervals so that the weather hazards are always up to date.
–Alex
Even cooler to me is the fact that you can update them every 15 minutes (and you're not even there anymore, right?) I'd love to be able to update maps every week with new values -- I don't have a map server though, just ArcView 9.2 ... mind if I ask you how managed it?
thanks again,
--tim
Hey Tim,
I wrote a python script that searches through the forecast directories and builds a list of zones that need highlighting. I have a “mask” image for each zone that I generated from the same multicolored PNG that I used to generate the HTML. These masks are used to create colored overlays for the zones that need them. The overlays are layered on top of the basemap. It's only a few commands for each overlay with imagemagick. I put this script on a cron job, and it's been running every fifteen minutes for over at least a year and a half now.
–Alex
I found another tricky issue with this script. At first it was working, but when I manually created a PNG of a few polygons to imagemap, it would run for a really long time (72 minutes for 4 polygons) and in the end it would just output boxes the size of the whole image for polygons. I determined that the problem was the PNG had transparency around the group of polygons. Maybe the color where it was transparent somehow was matching every other color or something. When I put a solid white background behind the polygons, it worked fine. Just a heads up for everyone.
Also might want to add sys.stdout.flush() after some of those print statements so it can show the output while it's running instead of at the end. And I see weird characters in there too at the end of the lines.
Post a Comment