// "JavaPlaid.java" version 0.9 // // Copyright 1997 Thomas Insel // // You may redistribute this file provided it is unchanged and you // include the entirety of this notice and disclaimer. You may // distribute a compiled version of this file provided you reproduce // the entirety of this notice and disclaimer in the documentation // and/or other materials provided with the distribution. // // Please contact the author if you wish to distribute this file under // different conditions or have changes to the file. // // You may obtain the current version of this file from // http://jaka.ece.uiuc.edu/~tinsel/Java/Tartan/src/JavaPlaid.java // // DISCLAIMER // // This software is provided "as is" and any express or implied // warranties, including, but not limited to the implied warranties of // merchantability and fitness for a particular purpose are // disclaimed. // // In no event shall Thomas Insel be liable for any direct, indirect, // special, exemplary, or consequential damages (including, but not // limited to, procurement of substitute goods or services; loss of // use, data, or profits; or business interruption) however caused an // on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out // of the use of this software, even if advised of the possibility of // such damage. // TODO -- preprocess string to deal with no spaces. // -- put utility functions in their own classes. import java.applet.Applet; import java.awt.*; import java.awt.image.*; import java.util.StringTokenizer; import java.net.*; /** * A tartan patterned component. * @version 1.0, 1 June 1997 * @author Thomas Insel */ public class Plaid extends Canvas { private Image tartan; private int threadCount=0; private String sett; private int symmetry; private boolean darkened; /** * NOSYMM -- the threads are used as given in the sett. */ public static final int NOSYMM = 0; /** * SINGLEPIVOT -- the middle bands are reflected around the rightmost band. For * example, "R 1 O 1 Y 1 G 1" becomes "R 1 O 1 Y 1 G 1 Y 1 O 1". */ public static final int SINGLEPIVOT = 1; /** * DOUBLEPIVOT -- the first TWO bands are not repeated. For example, * "R 1 O 1 Y 1 G 1" becomes "R 1 O 1 Y 1 G 1 Y 1". I'm not positive this is * the proper meaning of double pivot. */ public static final int DOUBLEPIVOT = 2; /** * Creates the component with the given sett, symmetry, and darkened values. * For example, * Plaid("R 16 W 16 B 16", SINGLEPIVOT, true) * @param sett an alternating list of color abbreviations and thread counts * @param symmetry one of: NOSYMM, SINGLEPIVOT, or DOUBLEPIVOT * @param darkened do we darken the colors? */ public Plaid(String sett, int symmetry, boolean darkened) { sett = spaceify(sett); StringTokenizer st = new StringTokenizer(sett); int bandColors[] = new int[st.countTokens()]; int bandThreads[] = new int[st.countTokens()]; // we leave room for symmetry int bandCount=0; // Store these for future reference. this.sett = sett; this.symmetry = symmetry; this.darkened = darkened; // Convert string to bands (a list of colors and color counts). while (st.countTokens() > 1) { int color = string2RGB(st.nextToken()); int count = java.lang.Integer.valueOf(st.nextToken()).intValue(); if (count > 0) { bandColors[bandCount] = color; bandThreads[bandCount] = count; threadCount += bandThreads[bandCount++]; } } // Adjust the bands for symmetry. if (symmetry != NOSYMM) for (int i = bandCount - ((symmetry==DOUBLEPIVOT) ? 3 : 2); i > ((symmetry==DOUBLEPIVOT) ? 0 : 1); i--) { bandColors[bandCount] = bandColors[i]; bandThreads[bandCount++] = bandThreads[i]; threadCount += bandThreads[i]; } // Expand bands to threads. int threadColors[] = new int[threadCount]; int index = 0; for (int i=0; i HHVV // VHHV int pix[] = new int[threadCount * threadCount]; index = 0; for (int y = 0; y < threadCount; y++) for (int x = 0; x < threadCount; x++) pix[index++] = threadColors[ (((x%4) - (y%4) + 4) %4 > 1) ? x : y ]; // Finally, make an image from the weaving. tartan = createImage(new MemoryImageSource(threadCount, threadCount, pix, 0, threadCount)); } // ----- Color Functions ----- // Since we work with integers, we do these functions on our own instead of using Color.*. private int rgb(int r, int g, int b) { if (darkened) { // this algorithm is from XTartan. if ((r==b && b==g) || (r==g && b==0) ||(b==0 && g==0)) { // gray, yellow, red r = (r*2)/3; g = (g*2)/3; b = (b*2)/3; } else { // other colors r /= 2; b = (b*2)/5; g /= 2; } } return (255<<24) + (r<<16) + (g<<8) + b; } private int string2RGB(String s) { // I have copied these color abbreviations from XTartan, and the RGB values // from /usr/X11/lib/X11/rgb.txt. I think that they're too bright as is, but // look pretty good when darkened. if (s.equalsIgnoreCase("r")) return rgb(255,0,0); // Red else if (s.equalsIgnoreCase("cr")) return rgb(178,34,34); // Crimson (Firebrick) else if (s.equalsIgnoreCase("mn")) return rgb(176,48,96); // Maroon else if (s.equalsIgnoreCase("or")) return rgb(255,165,0); // Orange else if (s.equalsIgnoreCase("y")) return rgb(255,255,0); // Yellow else if (s.equalsIgnoreCase("g")) return rgb(34,139,34); // Green (Forest Green) else if (s.equalsIgnoreCase("lg")) return rgb(152,251,152);// Light Green (Pale Green) else if (s.equalsIgnoreCase("db")) return rgb(0,0,128); // Dark Blue (Navy) else if (s.equalsIgnoreCase("b")) return rgb(0,0,205); // Medium Blue else if (s.equalsIgnoreCase("az")) return rgb(135,206,235);// Azure (Sky Blue) else if (s.equalsIgnoreCase("pu")) return rgb(221,160,221);// Purple (Plum) else if (s.equalsIgnoreCase("lil"))return rgb(218,112,214);// Lilac (Orchid) else if (s.equalsIgnoreCase("lv")) return rgb(230,230,250);// Lavendar else if (s.equalsIgnoreCase("ma")) return rgb(255,0,255); // Magenta else if (s.equalsIgnoreCase("br")) return rgb(165,42,42); // Brown else if (s.equalsIgnoreCase("w")) return rgb(255,255,255);// White else if (s.equalsIgnoreCase("gy")) return rgb(190,190,190);// Gray else return rgb(0,0,0); // K, BK for black // Cy: Cyan Cor: Coral ForGr: ForestGreen SlB: Slate Blue // Glr: Goldenrod Mar: Maroon Trq: Turquoise Wh: Wheat } // ----- String Utilities ----- /** * Gets rid of garbage and extra white space, and spaces the letter and number sections. * @param s the string * @returns the cleaned-up string */ private String spaceify(String s) { int LETTER = 1; int NUMBER = 2; int OTHER = 3; int kind, lastKind=OTHER; StringBuffer t = new StringBuffer(2 * s.length()); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".indexOf(c) != -1) kind = LETTER; else if ("0123456789".indexOf(c) != -1) kind = NUMBER; else kind = OTHER; if ( kind != OTHER && (kind == lastKind || lastKind == OTHER)) t.append(c); else if (kind == OTHER) { if (lastKind != OTHER) t.append(' '); } else t.append(' ').append(c); lastKind = kind; } return t.toString(); } // ----- Necessary but Boring ----- /** * Paints the tartan. * @param g the specified Graphics window */ public void paint(Graphics g) { g.drawImage(tartan, 0, 0, null); } /** * Returns the size of the rendered tartan. */ public Dimension preferredSize() { return new Dimension(threadCount, threadCount); } /** * Returns the String representation of the tartan. */ public String toString() { return getClass().getName() + "[sett=" + sett + ",symmetry=" + symmetry + (darkened ? ",darkened" : "") + "]"; } } /** * This applet is a wrapper for the Plaid class. * @version 1.0, 1 June 1997 * @author Thomas Insel * @see Tartan */ public class Tartan extends Applet { private Plaid myPlaid; /** * Initialize the applet. */ public void init() { String sett = getParameter("sett"); if (sett == null) sett = "r 16 w 16 g 16 w 16 b 16"; String symmString = getParameter("symm"); int symm = ( symmString == null ? Plaid.SINGLEPIVOT : java.lang.Integer.valueOf(symmString).intValue()); myPlaid = new Plaid(sett, symm, getParameter("darkened") != null); add(myPlaid); } /** * Go to the about page when clicked. * @param evt the event * @param x the x-coordinate * @param y the y-coordinate * @returns true since we always handle the click * @throws MalformedURLException but this should never really happen */ public boolean mouseDown(Event evt, int x, int y) { try { URL u = new URL("http://jaka.ece.uiuc.edu/~tinsel/Java/Tartan/about.html"); getAppletContext().showDocument(u); } catch(MalformedURLException e) { System.out.println("Error " + e); System.out.println(getAppletInfo()); } return true; } /** * Returns info on this applet. */ public String getAppletInfo() { return "Tartan 1.0. Copyright 1997 by Thomas Insel (tinsel@jaka.ece.uiuc.edu)"; } /** * Returns parameter information */ public String[][] getParameterInfo() { String[][] info = { {"sett", "string", "alternating list of colors and counts"}, {"symm", "0,1,or 2", "symmetry"}, {"darkened", "anything", "darkens colors"} }; return info; } }