/* * [ExtractColours.java] * * Summary: Extracts unnamed colour numbers from style sheets. * * Copyright: (c) 2009-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.0 2009-04-13 initial release * 1.1 2011-11-09 drop + - and x suffixes. Too hard to maintain. */ package com.mindprod.repair; import com.mindprod.commandline.CommandLine; import com.mindprod.common18.EIO; import com.mindprod.common18.Misc; import com.mindprod.csv.CSVReader; import com.mindprod.csv.CSVWriter; import com.mindprod.filter.AllButSVNDirectoriesFilter; import com.mindprod.filter.ExtensionListFilter; import com.mindprod.htmlmacros.macro.Global; import com.mindprod.htmlmacros.support.ConfigurationForMindprod; import com.mindprod.hunkio.HunkIO; import java.awt.Color; import java.io.BufferedReader; import java.io.EOFException; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import static java.lang.System.*; /** * Extracts unnamed colour numbers from style sheets. *

* Does NOT parse style sheets looking for name comments. * All name-assigning must be done to knowncolours.csv. * Does not bodify style sheets. * * @author Roedy Green, Canadian Mind Products * @version 1.1 2011-11-09 drop + - and x suffixes. Too hard to maintain. * @see AnnotateColours * @since 2009-04-13 */ public class ExtractColours { /** * how close colours have to be to be listed as close. Difference of 4 or less is considered close. */ private static final int CLOSE = 4; private static final int FIRST_COPYRIGHT_YEAR = 2009; /** * undisplayed copyright notice */ @SuppressWarnings( { "UnusedDeclaration" } ) private static final String EMBEDDED_COPYRIGHT = "Copyright: (c) 2009-2017 Roedy Green, Canadian Mind Products, http://mindprod.com"; /** * /** * regex to look for hex colour numbers in a style sheet */ private static final Pattern COLOUR_PATTERN = Pattern.compile( "#\\p{XDigit}{6}" ); /** * track down colours and their descriptions */ private static final TreeMap knownColours = new TreeMap<>(); /** * name of file to read CSV colour/description pairs */ private static File colourDescriptionFile; private static File sourceDir; /** * extract unknown colours from the style sheets on the command line * * @param args command line list of style sheets * * @throws IOException if trouble reading style sheets */ private static void extractUnknownColours( final String[] args ) throws IOException { out.println( "updating: " + colourDescriptionFile ); CommandLine files = new CommandLine( args, new AllButSVNDirectoriesFilter(), new ExtensionListFilter( "css" ) ); for ( File file : files ) { final String contents = HunkIO.readEntireFile( file, HunkIO.UTF8 ); final Matcher m = COLOUR_PATTERN.matcher( contents ); while ( m.find() ) { // chop lead # final String anotherColour = m.group( 0 ).substring( 1 ); if ( !knownColours.containsKey( anotherColour ) ) { err.println( "Warning: unnamed colour: " + anotherColour + " at offset " + m.start( 0 ) + " in " + file.toString() ); knownColours.put( anotherColour, "" ); } } } } /** * find close colours */ private static void findCloseColours() { for ( String okey : knownColours.keySet() ) { final Color oColor = new Color( Integer.parseInt( okey, 16 ) ); final String odesc = knownColours.get( okey ); for ( String ikey : knownColours.keySet() ) { // don't compare with itself, don't compare both outer:inner and inner:outer if ( ikey.compareTo( okey ) <= 0 ) { continue; } final Color iColor = new Color( Integer.parseInt( ikey, 16 ) ); final int dist = Math.abs( oColor.getRed() - iColor.getRed() ) + Math.abs( oColor.getGreen() - iColor.getGreen() ) + Math.abs( oColor.getBlue() - iColor.getBlue() ); final String idesc = knownColours.get( ikey ); // don't report close x11 colours if ( dist <= CLOSE ) { out.println( "close colours: " + okey + " " + ( odesc.length() > 0 ? odesc : "unnamed" ) + " vs " + ikey + " " + ( idesc.length() > 0 ? idesc : "unnamed" ) + " : difference " + dist ); } } } } /** * extract unknown colours from the style sheets on the command line * * @param args command line list of style sheets * * @throws IOException if trouble reading style sheets */ private static void findUnusedColours( final String[] args ) throws IOException { HashSet inuse = new HashSet<>( 1000 ); CommandLine files = new CommandLine( args, new AllButSVNDirectoriesFilter(), new ExtensionListFilter( "css" ) ); for ( File file : files ) { final String contents = HunkIO.readEntireFile( file, HunkIO.UTF8 ); final Matcher m = COLOUR_PATTERN.matcher( contents ); while ( m.find() ) { // chop lead # final String anotherColour = m.group( 0 ).substring( 1 ); inuse.add( anotherColour ); } } for ( String colour : knownColours.keySet() ) { if ( !inuse.contains( colour ) ) { final String odesc = knownColours.get( colour ); err.println( "Colour " + colour + " " + ( odesc.length() > 0 ? odesc : "unnamed" ) + " is not used in" + " any of the style sheets." ); } } } /** * read existing list of known colours * * @throws IOException if trouble reading CSV list of known colours */ private static void readKnownColours() throws IOException { // O P E N final FileReader fr = new FileReader( colourDescriptionFile ); final BufferedReader br = new BufferedReader( fr, 24 * 1024 /* 24K chars (48K bytes), 75% of allocation is optimal */ ); // reader, separatorChar, quoteChar, commentChars, hideComments, trimQuoted, trimUnquoted, // allowMultipleLineFields final CSVReader r = new CSVReader( br, ',', '\"', "#", true, true /* trimQuoted */, true /* trimUnquoted */, false ); final HashMap dupDescDetector = new HashMap<>( 1000 ); try { //noinspection InfiniteLoopStatement while ( true ) { final String colour = r.get(); if ( colour == null ) { // bypass blank line., we have skipped to next line continue; } final String desc = r.get(); if ( desc == null ) { // bypass unnamed colour, we have skipped to next line continue; } // lookup by colour final String prevDesc = knownColours.put( colour, desc ); if ( prevDesc != null ) { err.println( "Error: Duplicate entry for colour number " + colour + " : " + desc + " : " + prevDesc ); } // lookup by desc final String prevColour = dupDescDetector.put( desc, colour ); if ( prevColour != null && desc.length() > 0 ) { err.println( "Warning: Duplicate entry for description " + desc + " : " + colour + " : " + prevColour ); } r.skipToNextLine(); } } catch ( EOFException e ) { r.close(); } } /** * write out our new list of know colours, ready to have descriptions added. Will be sorted in RGB order. * * @throws IOException if trouble exporting data */ private static void writeColours() throws IOException { // O P E N final PrintWriter prw = EIO.getPrintWriter( colourDescriptionFile, 24 * 1024, EIO.UTF8 ); // writer, quoteLevel, separatorChar, quoteChar, commentChar, trim final CSVWriter w = new CSVWriter( prw, -1 /* extra space */, ',', '\"', '#', true ); w.nl( "Canadian Mind Products Stylesheet Colours" ); for ( Map.Entry entry : knownColours.entrySet() ) { // This code does not require an expensive get lookup to find the value. final String colourNumber = entry.getKey(); final String desc = entry.getValue(); w.put( colourNumber ); w.put( desc ); w.nl(); } // end for w.close(); } /** * Extracts lines in files that contain a given string. * * @param args style sheets to scan, e.g. E:\mindprod\mindprod.css */ public static void main( String[] args ) { Global.installConfiguration( new ConfigurationForMindprod() ); // combine dirsWithMacros and dirsWithIncludes into dirsToProcess; sourceDir = new File( Global.configuration.getSourceDirWithSlashes() ); colourDescriptionFile = new File( sourceDir, "repair/knowncolours.csv" ); try { // read existing list of known colours readKnownColours(); // extract unknown colours from the style sheets on the command line extractUnknownColours( args ); // find colours defined in the csv file but not used in style sheets findUnusedColours( args ); // find close colours findCloseColours(); // write out our new list of know colours, ready to have descriptions added. writeColours(); // generate code for inclusion into Palette. out.println( "Done" ); } catch ( Exception e ) { e.printStackTrace( err ); err.println(); } Misc.trackLastThread(); System.exit( 0 ); } // end main }