Forum Stats

  • 3,827,727 Users
  • 2,260,812 Discussions
  • 7,897,362 Comments

Discussions

general approach to implementing multiple color name dictionaries?

RichF
RichF Member Posts: 214
edited Nov 15, 2010 7:27AM in Java Programming
My [url http://r0k.us/graphics/SIHwheel.html]interactive color wheel applet currently has a single class providing names and hex values for over 1500 colors. I am considering offering multiple of these "color name dictionaries" (CNDs) -- the current set, Munsell colors, Sherwin Williams colors, etc.. Each dictionary element consists of a hex string providing the color value, and a name string. There are at least 3 approaches which might be possible:

1) store each CND in its own plain text file with file names ending in common extension, such as ".cnd". At run time, hunt for .cnd files in current directory and build a GUI selection list dynamically. This would likely be my approach in other languages, and would save space in the jar file. (One byte per character instead of two.) But I do not even know if an applet can read files in its own .jar. If it can, they would be in the current directory, right?

2) store each CND in its own class. Is there a way to just drop classes into a project, and have the java parent automatically recognize what CND classes there are and adjust the GUI to support it/them?

3) store all CNDs in one class, as separate 2-d arrays. It could end up as a huge class (the current class, with just one dictionary, is 78k in size), but might be the simplest to implement.

Which path would you take? Is there a better way that I haven't thought of?
Tagged:

Best Answer

  • Kayaman
    Kayaman Member Posts: 3,844 Silver Trophy
    Answer ✓
    If you're already using getResource() and you don't intend to randomly place your CND files around the filesystem, there's no reason to mix FileInputStreams there.

    Class.getResourceAsStream() is the way to support different kinds of loadings. It even supports having your program as a jar file or an unpacked jar file. You just left the unnecessary catch block there that you need to remove.
«13

Answers

  • Kayaman
    Kayaman Member Posts: 3,844 Silver Trophy
    RichF wrote:
    1) store each CND in its own plain text file with file names ending in common extension, such as ".cnd". At run time, hunt for .cnd files in current directory and build a GUI selection list dynamically. This would likely be my approach in other languages, and would save space in the jar file. (One byte per character instead of two.) But I do not even know if an applet can read files in its own .jar. If it can, they would be in the current directory, right?
    No...they would be in the jar file. You would use getResourceAsStream() to access them.
    2) store each CND in its own class. Is there a way to just drop classes into a project, and have the java parent automatically recognize what CND classes there are and adjust the GUI to support it/them?
    It's possible, but I wouldn't suggest it here, because you're not actually adding functionality but data. The classes are otherwise identical, aren't they?
    3) store all CNDs in one class, as separate 2-d arrays. It could end up as a huge class (the current class, with just one dictionary, is 78k in size), but might be the simplest to implement.
    That would just be storing data in a class. Not exactly a good choice design-wise.
    Which path would you take? Is there a better way that I haven't thought of?
    I'd go with number 1. You can add additional mappers easily by just adding files.
    Kayaman
  • JoachimSauer
    JoachimSauer Member Posts: 4,780
    RichF wrote:
    1) store each CND in its own plain text file with file names ending in common extension, such as ".cnd".
    I'd suggest a .properties file for that.
    This would likely be my approach in other languages, and would save space in the jar file. (One byte per character instead of two.)
    Actually, no it wouldn't. String constants in .class files are stored in UTF-8, not UTF-16! Only at runtime are all characters UTF-16.
    But I do not even know if an applet can read files in its own .jar. If it can, they would be in the current directory, right?
    Yes, an applet may load files from its own .jar using getClass().getResource(). It can't, however, list all entries in a given "directory" in the .jar
    2) store each CND in its own class. Is there a way to just drop classes into a project, and have the java parent automatically recognize what CND classes there are and adjust the GUI to support it/them?
    You could use the ServiceLoader mechanism for this. You'd need a list of those classes in a text file (details in the JavaDoc).
    Which path would you take? Is there a better way that I haven't thought of?
    Personally I'd chose step 1 (or a variation thereof), since I don't see a reason to store that data as executable code. To overcome the "list files" problems, you could either a.) list all entries in a dedicated file or b.) have a predictable naming scheme (e.g. "cnd1.properties", "cnd2.properties", ...) and just try to load as many as possible until you fail to find one.
    JoachimSauer
  • YoungWinston
    YoungWinston Member Posts: 4,310
    edited Nov 11, 2010 7:40AM
    Joachim Sauer wrote:
    RichF wrote:
    1) store each CND in its own plain text file with file names ending in common extension, such as ".cnd".
    I'd suggest a .properties file for that.
    I think I'd probably advise a combo of yours and Kayaman's suggestions: use a properties file and put it in the jar. Makes things ever so much easier for distribution. An alternative, of course, is XML.

    @OP:
    1. If you're worried about size, you could always zip the dictionary file before you store/ship it (text usually compresses anywhere up to 10:1); but I'd definitely leave it until you have a need for it.
    2. I suspect that what would be useful for users of your colours would be to have some wrapper that bangs them all into a HashMap<String, Color>, where the String is the name of the colour; and offer some "fuzzy logic" methods to help people who may not know the exact colour name (eg, "give me all the browns").

    Winston

    PS: If you do think you might need to zip at some point, I'd definitely provide custom load() and unload() (or Stream) methods for your dictionary; even if they just deal with plain text at the moment.

    Edited by: YoungWinston on Nov 11, 2010 1:38 PM
    YoungWinston
  • JoachimSauer
    JoachimSauer Member Posts: 4,780
    YoungWinston wrote:
    Joachim Sauer wrote:
    RichF wrote:
    1) store each CND in its own plain text file with file names ending in common extension, such as ".cnd".
    I'd suggest a .properties file for that.
    I think I'd probably advise a combo of yours and Kayaman's suggestions: use a properties file and put it in the jar.
    That's actually what I tried to advice, but I realize that I didn't make it explicit, that the .properties files could/should be placed in the .jar file.
  • RichF
    RichF Member Posts: 214
    Thanks, everyone. I'll likely go with the .properties files within the .jar.

    One other possibility occurs to me, though. The vast majority of visitors won't bother with any CND except the default one. Could I package the default within the .jar, and then download any others from my server upon request? I'm thinking:

    1) default CND in the .jar and auto-configured for use by app
    2) .properties file within the jar listing other CNDs at the server
    3) visitor selects another dictionary, it is downloaded and configured as the active CND

    Would this be a good idea and relatively easy to implement?
  • Kayaman
    Kayaman Member Posts: 3,844 Silver Trophy
    RichF wrote:
    One other possibility occurs to me, though. The vast majority of visitors won't bother with any CND except the default one. Could I package the default within the .jar, and then download any others from my server upon request? I'm thinking:

    1) default CND in the .jar and auto-configured for use by app
    Better idea, all the CNDs in the .jar and the default one being used by...well, default.
    2) .properties file within the jar listing other CNDs at the server
    Properties file within the jar, listing other CNDs in the Jar.
    3) visitor selects another dictionary, it is downloaded and configured as the active CND
    Visitor selects another dictionary, it's already downloaded with the Jar and just set it as the default.
    Would this be a good idea and relatively easy to implement?
    Yes and yes.
  • RichF
    RichF Member Posts: 214
    Kayaman wrote:
    Would this be a good idea and relatively easy to implement?
    Yes and yes.
    Kayaman, just to be clear -- you are saying having the extra CNDs on the server would be a good idea and easy to implement. But having them already in the .jar, even though most users won't access them, would be a better idea, right?
  • RichF
    RichF Member Posts: 214
    edited Nov 12, 2010 12:12PM
    I'm getting ready to implement. Currently, the single CND is stored as a 2-d array with 1576 entries within a [url http://r0k.us/source/NTC.java]class.
        public static final String names[][] = {
    	{"000000", "Black"},
    	{"000080", "Navy Blue"},
    	{"0000C8", "Dark Blue"},
    	{"0000FF", "Blue"},
            ...
    	{"FFFF99", "Pale Canary"},
    	{"FFFFB4", "Portafino"},
    	{"FFFFF0", "Ivory"},
    	{"FFFFFF", "White"}
        };
    Fortunately, no hex values are repeated, nor will be repeated in other CNDs. To convert this to a properties file, I believe it would look like:
    CND.Name = "Hodge Podge"
    CND.Count = 1567
    000000 = "Black"
    000080 = "Navy Blue"
    0000C8 = "Dark Blue"
    0000FF = "Blue"
    ...
    FFFF99 = "Pale Canary"
    FFFFB4 = "Portafino"
    FFFFF0 = "Ivory"
    FFFFFF = "White"
    Does that look correct? As I understand it, the Properties interface would not read them in any particular order.
    Roedy Green [url http://mindprod.com/jgloss/properties.htmlwrites:}
    Since Properties are Hashtables, they scramble the order of the elements. If you want to preserve order, and don’t need key lookup, you can parse the file yourself with a StreamTokenizer and put it in an array. Do you-all agree this would be the best approach to read them in? Regardless of method, I want them to end back up into a 2-d string array, sorted by hex value. That is the reason for the CND.Count key.

    I guess the other alternative is using the properties interface to read them into a temporary array, and sort it into the final array. I should be able to use propertyNames() to get all the keys, store those in the temporary 1-d array, sort it, then loop getProperty(temp[index]) to fill the final 2-d array. Once the 2-d array is full, I would free the Properties object by setting it to null.

    Hopefully I'm not sounding needy. This stuff is new to me, and I'd like to avoid walking down a blind alley full of gotchas and structural Rube Goldbergs. ;)
  • Kayaman
    Kayaman Member Posts: 3,844 Silver Trophy
    RichF wrote:
    But having them already in the .jar, even though most users won't access them, would be a better idea, right?
    Yes. Getting them separately from a server would be justified if the files were several megabytes in size. But since it's just text and compresses automatically within the jar, there's no reason not to include them all in the same jar even if the user might never switch to another CND.
  • Kayaman
    Kayaman Member Posts: 3,844 Silver Trophy
    >
    Fortunately, no hex values are repeated, nor will be repeated in other CNDs. To convert this to a properties file, I believe it would look like:
    CND.Name = "Hodge Podge"
    CND.Count = 1567
    000000 = "Black"
    000080 = "Navy Blue"
    0000C8 = "Dark Blue"
    0000FF = "Blue"
    ...
    FFFF99 = "Pale Canary"
    FFFFB4 = "Portafino"
    FFFFF0 = "Ivory"
    FFFFFF = "White"
    Does that look correct?
    Looks about right, except you don't need the quotes around your text.
    I guess the other alternative is using the properties interface to read them into a temporary array, and sort it into the final array.
    You don't need a temporary array. You can read all the contents of the properties (it extends Hashtable so there should be some form of getEntries() method to get key/value pairs) in a 2D array and then sort it afterwards.
    I would free the Properties object by setting it to null.
    Setting references to null is rarely needed explicitly. I'd expect the Properties to be a local variable that you create when the user is wanting to change the CND, which will fall out of scope by itself.
    >
    Hopefully I'm not sounding needy. This stuff is new to me, and I'd like to avoid walking down a blind alley full of gotchas and structural Rube Goldbergs. ;)
    No worries.
    Kayaman
This discussion has been closed.