pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / contrib / highlighter / src / java / org / apache / lucene / search / highlight / GradientFormatter.java
1 package org.apache.lucene.search.highlight;
2 /**
3  * Licensed to the Apache Software Foundation (ASF) under one or more
4  * contributor license agreements.  See the NOTICE file distributed with
5  * this work for additional information regarding copyright ownership.
6  * The ASF licenses this file to You under the Apache License, Version 2.0
7  * (the "License"); you may not use this file except in compliance with
8  * the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 /**
20  * Formats text with different color intensity depending on the score of the
21  * term.
22  *
23  */
24 public class GradientFormatter implements Formatter
25 {
26     private float maxScore;
27
28     int fgRMin, fgGMin, fgBMin;
29
30     int fgRMax, fgGMax, fgBMax;
31
32     protected boolean highlightForeground;
33
34     int bgRMin, bgGMin, bgBMin;
35
36     int bgRMax, bgGMax, bgBMax;
37
38     protected boolean highlightBackground;
39
40     /**
41      * Sets the color range for the IDF scores
42      * 
43      * @param maxScore
44      *            The score (and above) displayed as maxColor (See QueryScorer.getMaxWeight 
45      *                    which can be used to calibrate scoring scale)
46      * @param minForegroundColor
47      *            The hex color used for representing IDF scores of zero eg
48      *            #FFFFFF (white) or null if no foreground color required
49      * @param maxForegroundColor
50      *            The largest hex color used for representing IDF scores eg
51      *            #000000 (black) or null if no foreground color required
52      * @param minBackgroundColor
53      *            The hex color used for representing IDF scores of zero eg
54      *            #FFFFFF (white) or null if no background color required
55      * @param maxBackgroundColor
56      *            The largest hex color used for representing IDF scores eg
57      *            #000000 (black) or null if no background color required
58      */
59     public GradientFormatter(float maxScore, String minForegroundColor,
60             String maxForegroundColor, String minBackgroundColor,
61             String maxBackgroundColor)
62     {
63         highlightForeground = (minForegroundColor != null)
64                 && (maxForegroundColor != null);
65         if (highlightForeground)
66         {
67             if (minForegroundColor.length() != 7)
68             {
69                 throw new IllegalArgumentException(
70                         "minForegroundColor is not 7 bytes long eg a hex "
71                                 + "RGB value such as #FFFFFF");
72             }
73             if (maxForegroundColor.length() != 7)
74             {
75                 throw new IllegalArgumentException(
76                         "minForegroundColor is not 7 bytes long eg a hex "
77                                 + "RGB value such as #FFFFFF");
78             }
79             fgRMin = hexToInt(minForegroundColor.substring(1, 3));
80             fgGMin = hexToInt(minForegroundColor.substring(3, 5));
81             fgBMin = hexToInt(minForegroundColor.substring(5, 7));
82
83             fgRMax = hexToInt(maxForegroundColor.substring(1, 3));
84             fgGMax = hexToInt(maxForegroundColor.substring(3, 5));
85             fgBMax = hexToInt(maxForegroundColor.substring(5, 7));
86         }
87
88         highlightBackground = (minBackgroundColor != null)
89                 && (maxBackgroundColor != null);
90         if (highlightBackground)
91         {
92             if (minBackgroundColor.length() != 7)
93             {
94                 throw new IllegalArgumentException(
95                         "minBackgroundColor is not 7 bytes long eg a hex "
96                                 + "RGB value such as #FFFFFF");
97             }
98             if (maxBackgroundColor.length() != 7)
99             {
100                 throw new IllegalArgumentException(
101                         "minBackgroundColor is not 7 bytes long eg a hex "
102                                 + "RGB value such as #FFFFFF");
103             }
104             bgRMin = hexToInt(minBackgroundColor.substring(1, 3));
105             bgGMin = hexToInt(minBackgroundColor.substring(3, 5));
106             bgBMin = hexToInt(minBackgroundColor.substring(5, 7));
107
108             bgRMax = hexToInt(maxBackgroundColor.substring(1, 3));
109             bgGMax = hexToInt(maxBackgroundColor.substring(3, 5));
110             bgBMax = hexToInt(maxBackgroundColor.substring(5, 7));
111         }
112         //        this.corpusReader = corpusReader;
113         this.maxScore = maxScore;
114         //        totalNumDocs = corpusReader.numDocs();
115     }
116
117     public String highlightTerm(String originalText, TokenGroup tokenGroup)
118     {
119         if (tokenGroup.getTotalScore() == 0)
120             return originalText;
121         float score = tokenGroup.getTotalScore();
122         if (score == 0)
123         {
124             return originalText;
125         }
126         StringBuilder sb = new StringBuilder();
127         sb.append("<font ");
128         if (highlightForeground)
129         {
130             sb.append("color=\"");
131             sb.append(getForegroundColorString(score));
132             sb.append("\" ");
133         }
134         if (highlightBackground)
135         {
136             sb.append("bgcolor=\"");
137             sb.append(getBackgroundColorString(score));
138             sb.append("\" ");
139         }
140         sb.append(">");
141         sb.append(originalText);
142         sb.append("</font>");
143         return sb.toString();
144     }
145
146     protected String getForegroundColorString(float score)
147     {
148         int rVal = getColorVal(fgRMin, fgRMax, score);
149         int gVal = getColorVal(fgGMin, fgGMax, score);
150         int bVal = getColorVal(fgBMin, fgBMax, score);
151         StringBuilder sb = new StringBuilder();
152         sb.append("#");
153         sb.append(intToHex(rVal));
154         sb.append(intToHex(gVal));
155         sb.append(intToHex(bVal));
156         return sb.toString();
157     }
158
159     protected String getBackgroundColorString(float score)
160     {
161         int rVal = getColorVal(bgRMin, bgRMax, score);
162         int gVal = getColorVal(bgGMin, bgGMax, score);
163         int bVal = getColorVal(bgBMin, bgBMax, score);
164         StringBuilder sb = new StringBuilder();
165         sb.append("#");
166         sb.append(intToHex(rVal));
167         sb.append(intToHex(gVal));
168         sb.append(intToHex(bVal));
169         return sb.toString();
170     }
171
172     private int getColorVal(int colorMin, int colorMax, float score)
173     {
174         if (colorMin == colorMax)
175         {
176             return colorMin;
177         }
178         float scale = Math.abs(colorMin - colorMax);
179         float relScorePercent = Math.min(maxScore, score) / maxScore;
180         float colScore = scale * relScorePercent;
181         return Math.min(colorMin, colorMax) + (int) colScore;
182     }
183
184     private static char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7',
185             '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
186
187     private static String intToHex(int i)
188     {
189         return "" + hexDigits[(i & 0xF0) >> 4] + hexDigits[i & 0x0F];
190     }
191
192     /**
193      * Converts a hex string into an int. Integer.parseInt(hex, 16) assumes the
194      * input is nonnegative unless there is a preceding minus sign. This method
195      * reads the input as twos complement instead, so if the input is 8 bytes
196      * long, it will correctly restore a negative int produced by
197      * Integer.toHexString() but not necessarily one produced by
198      * Integer.toString(x,16) since that method will produce a string like '-FF'
199      * for negative integer values.
200      * 
201      * @param hex
202      *            A string in capital or lower case hex, of no more then 16
203      *            characters.
204      * @throws NumberFormatException
205      *             if the string is more than 16 characters long, or if any
206      *             character is not in the set [0-9a-fA-f]
207      */
208     public static final int hexToInt(String hex)
209     {
210         int len = hex.length();
211         if (len > 16)
212             throw new NumberFormatException();
213
214         int l = 0;
215         for (int i = 0; i < len; i++)
216         {
217             l <<= 4;
218             int c = Character.digit(hex.charAt(i), 16);
219             if (c < 0)
220                 throw new NumberFormatException();
221             l |= c;
222         }
223         return l;
224     }
225
226 }
227