1 //@(#) Xpm.java 1.9@(#)
2 //Copyright (c) 2001, Phil Brown, phil@bolthole.com
3 //licensed under GNU LGPL version 2
5 /* A library class to convert Xpm data into an image.
6 * It also has nice little utilities like converting
7 * color NAMES to rgb values (based on X11 rgb.txt)
9 * Note1: There might be a slight conflict of copyright,
10 * If the rgb.txt data from the X11 distribution has nasty copyright
11 * stuff attached to it. If so... my apologies to the X11 folk.
13 * This is an improved version, that is not hardcoded so much for
14 * "crossfire". It should hopefully handle all xpm types.
15 * If it doesnt, please send me email, with a sample xpm image
16 * that it fails under, and I'll try to fix it.
18 package org.biojava.dasobert.das;
21 import java.awt.Image;
22 import java.util.Hashtable;
23 import java.awt.Toolkit;
24 import java.awt.image.*;
26 //rgb data originally from
27 //! $XConsortium: rgb.txt,v 10.41 94/02/20 18:39:36 rws Exp $
31 //Note: This class is huge, and has icky large static initializers.
32 //They are also ARRAY-based, which means poor lookup speed.
33 //While that is kinda annoying, it shouldn't be TOO bad.
34 //And it should greatly improve STARTUP time, which I consider
35 //at this point to be more important
39 static String VersionString="Phil@bolthole.com Xpm v1.1";
40 static final int rgbents[][] = {
795 static String rgbnames[] = {
930 "medium spring green",
947 "light goldenrod yellow",
948 "LightGoldenrodYellow",
1000 "medium violet red",
1549 // rgbents, rgbnames
1550 public static boolean debugflag=false;
1552 static void debug(String msg)
1555 System.out.println(msg);
1558 // look up string name of color. return int[3] of rgb, or
1559 // null if color not found
1560 public static int[] NameToRGB3(String str)
1562 int rsize=rgbnames.length;
1564 for(int count=0;count<rsize; count++)
1566 if(str.equalsIgnoreCase(rgbnames[count]))
1568 return rgbents[count];
1575 // This returns an int. If the int were represented as
1576 // 0xffffffff, then the format would match data as
1578 //BUT.. returns 0xffffffff if color not found
1579 public static int NameToRGB(String str)
1581 int rsize=rgbnames.length;
1583 if(str.charAt(0)=='#'){
1584 // Have to deal with rrggbb, OR rrrrggggbbbb
1585 // Erm.. except this only deals with
1586 // #rrggbb, it looks like... ?!!
1587 String Substr=str.substring(1,7);
1588 int rgb=Integer.parseInt(Substr,16);
1593 for(int count=0;count<rsize; count++)
1595 if(str.equalsIgnoreCase(rgbnames[count]))
1599 (rgbents[count][0]<<16) |
1600 (rgbents[count][1]<<8) |
1606 if(!str.equalsIgnoreCase("None"))
1607 debug("NameToRGB: Could not find match for color "+str);
1611 public static String RGB3ToName(int val[])
1616 int rsize=rgbnames.length;
1617 for(int count=0; count<rsize; count++)
1619 if(val[0] ==rgbents[count][0])
1620 if(val[1] ==rgbents[count][1])
1621 if(val[2] ==rgbents[count][2])
1622 return rgbnames[count];
1629 /************************************************************
1630 * This part implements reading in xpm data, and doing something
1631 * USEFUL with it. This is the only public routine that people
1632 * will probably care about.
1633 * xpm is possibly copyright/trademarked by Arnaud LE HORS,
1634 * BULL Research, France. lehors@sophia.inria.fr
1635 ************************************************************/
1637 // we dont care/try to deal with mono conversion
1638 public static Image XpmToImage(String xpm) {
1640 /* general rules I'm going to follow:
1642 * skip all (* xxxx*) but possibly insist on initial
1644 * skip static char .....
1645 * read "<width> <height> <colors> <charsperpixel>" <hotx,hoty>?
1646 * Then in main reading;
1647 * take c FIRST. fall back to s. fall back to g. fall back to g4.
1654 debug("XpmToImage : Provided xpm is null!");
1658 int parse, parseend;
1659 int width, height,colcount,charsperpixel;
1660 Hashtable colorlookup = new Hashtable();
1661 // add default val for "transparent"
1662 // the initial 0xff should mean it should not show up
1665 if(! xpm.startsWith("/* XPM */"))
1667 debug("xpm data doesn't start with XPM magic. exit");
1668 debug(xpm.substring(0,10));
1672 /*********************************************
1673 * Do initial width/size,etc parsing
1674 **********************************************/
1675 parse = xpm.indexOf('"', 9);
1678 parseend=xpm.indexOf(' ', parse);
1679 width=Integer.parseInt(xpm.substring(parse,parseend));
1682 parseend=xpm.indexOf(' ', parse);
1683 height=Integer.parseInt(xpm.substring(parse,parseend));
1686 parseend=xpm.indexOf(' ', parse);
1687 colcount=Integer.parseInt(xpm.substring(parse,parseend));
1690 parseend=xpm.indexOf('"',parse);
1694 charsperpixel=Integer.parseInt(xpm.substring(parse,parseend));
1696 debug("width="+width+",height="+height+
1697 ",colcount="+colcount+",cpp="+charsperpixel);
1701 if(charsperpixel==1){
1702 colorlookup.put(new Integer(' '),
1703 new Integer(0x00000000));
1705 int tmpchar=(' ' &0xff) <<8;
1706 tmpchar |= (' '&0xff);
1707 colorlookup.put(new Integer((tmpchar&0xffff)),
1708 new Integer(0x00000000));
1712 /**************************************************
1713 * Now do parsing of color naming/indexing
1714 **************************************************/
1718 imageb = new int[width * height];
1719 int bytecount=0; // counting bytes into image array
1721 parse=xpm.indexOf('"', parseend+1)+1;
1726 debug("ERROR: expecting color def");
1732 parseend=xpm.indexOf('"', parse+1);
1735 getColorName(xpm.substring(parse, parseend));
1738 debug("colorname on line is "+colorname);
1739 debug("now parsing "+
1740 xpm.substring(parse,parse+charsperpixel));
1744 if(charsperpixel==1){
1745 colref=new Integer(xpm.charAt(parse++));
1747 int tmpchar=xpm.charAt(parse++);
1748 tmpchar = (tmpchar&0xff)<<8;
1749 tmpchar |= xpm.charAt(parse++) & 0xff;
1752 debug("two charsperpixel: substre==" +
1753 xpm.substring(parse-2,parse)+
1754 " which generates char "+
1758 colref=new Integer(tmpchar&0xffff);
1763 rgb = new Integer(NameToRGB(colorname));
1766 debug("Color num parsed for \"" +colorname+"\"("+
1767 Integer.toHexString(colref.intValue())+
1769 Integer.toHexString(rgb.intValue()) );
1773 colorlookup.put(colref, rgb);
1774 parse=xpm.indexOf('"', parseend+1)+1;
1779 debug("Done with color defs");
1781 /****************************************************
1782 * Finally, now that we have all the data,
1783 * fully interpret the actual image
1784 ***************************************************/
1786 parse = xpm.indexOf("\n\"", parseend+1);
1789 debug("ERROR; incomplete Xpm data");
1794 debug("Xpm starting image parse");
1795 while(xpm.charAt(parse) =='"')
1798 parseend = xpm.indexOf('"', parse);
1800 debug("Xpm; parsing \""+xpm.substring(parse, parseend)+"\"");
1802 for(int pix=parse; pix<parseend;pix++)
1808 if(charsperpixel==1){
1809 tmpchar=xpm.charAt(pix);
1811 tmpchar=xpm.charAt(pix++);
1812 tmpchar = (tmpchar&0xff)<<8;
1813 tmpchar |= xpm.charAt(pix) & 0xff;
1816 pixchar=new Integer(tmpchar&0xffff);
1819 pixval = (Integer)colorlookup.get(pixchar);
1822 debug("HEY MORON: no value stored "+
1824 Integer.toHexString(tmpchar)+
1825 ", char substring "+
1826 xpm.substring(pix-charsperpixel,
1831 imageb[bytecount++]=pixval.intValue();
1834 parse=xpm.indexOf('"', parseend+1);
1839 if(bytecount<(width * height -1))
1841 debug("Warning.. pixmap truncated!");
1844 //printbytes(imageb);
1845 image=BytesToImage(imageb, width, height);
1852 static Image BytesToImage(int bytes[], int width, int height)
1855 Toolkit tk = Toolkit.getDefaultToolkit();
1856 myimage=tk.createImage(new MemoryImageSource(width, height, bytes, 0, width));
1863 static void printbytes(int b[])
1866 for(index=0; index<b.length; index++)
1868 System.out.print(" "+Integer.toHexString(b[index]));
1870 System.out.println(" ");
1873 // This just parses out the string that defines the colorname
1874 // we do NOT interpret. we just split it out from the rest of
1875 // the line. Call NameToRGB() on the result.
1876 // We make the assumption that our string does NOT
1877 // have a trailing '"'
1878 static String getColorName(String xpmline)
1880 //debug("getColorName passed: "+xpmline);
1882 int parsemid, parsemidend;
1883 parsemid = xpmline.indexOf("\tc");
1885 parsemid = xpmline.indexOf(" c");
1888 debug("Xpm: oops. no c found, in: "+xpmline);
1892 parsemidend=xpmline.indexOf('\t',parsemid);
1894 parsemidend=xpmline.length();
1896 return xpmline.substring(parsemid, parsemidend);