1    /* ====================================================================
2     * The Apache Software License, Version 1.1
3     *
4     * Copyright (c) 2002 The Apache Software Foundation.  All rights
5     * reserved.
6     *
7     * Redistribution and use in source and binary forms, with or without
8     * modification, are permitted provided that the following conditions
9     * are met:
10    *
11    * 1. Redistributions of source code must retain the above copyright
12    *    notice, this list of conditions and the following disclaimer.
13    *
14    * 2. Redistributions in binary form must reproduce the above copyright
15    *    notice, this list of conditions and the following disclaimer in
16    *    the documentation and/or other materials provided with the
17    *    distribution.
18    *
19    * 3. The end-user documentation included with the redistribution,
20    *    if any, must include the following acknowledgment:
21    *       "This product includes software developed by the
22    *        Apache Software Foundation (http://www.apache.org/)."
23    *    Alternately, this acknowledgment may appear in the software itself,
24    *    if and wherever such third-party acknowledgments normally appear.
25    *
26    * 4. The names "Apache" and "Apache Software Foundation" and
27    *    "Apache POI" must not be used to endorse or promote products
28    *    derived from this software without prior written permission. For
29    *    written permission, please contact apache@apache.org.
30    *
31    * 5. Products derived from this software may not be called "Apache",
32    *    "Apache POI", nor may "Apache" appear in their name, without
33    *    prior written permission of the Apache Software Foundation.
34    *
35    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38    * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46    * SUCH DAMAGE.
47    * ====================================================================
48    *
49    * This software consists of voluntary contributions made by many
50    * individuals on behalf of the Apache Software Foundation.  For more
51    * information on the Apache Software Foundation, please see
52    * <http://www.apache.org/>.
53    */
54   package org.apache.poi.hssf.usermodel;
55   
56   import org.apache.poi.hssf.record.PaletteRecord;
57   import org.apache.poi.hssf.util.HSSFColor;
58   
59   /**
60    * Represents a workbook color palette.
61    * Internally, the XLS format refers to colors using an offset into the palette
62    * record.  Thus, the first color in the palette has the index 0x8, the second
63    * has the index 0x9, etc. through 0x40
64    *
65    * @author Brian Sanders (bsanders at risklabs dot com)
66    */
67   public class HSSFPalette
68   {
69       private PaletteRecord palette;
70       
71       protected HSSFPalette(PaletteRecord palette)
72       {
73           this.palette = palette;
74       }
75       
76       /**
77        * Retrieves the color at a given index
78        *
79        * @param index the palette index, between 0x8 to 0x40 inclusive
80        * @return the color, or null if the index is not populated
81        */
82       public HSSFColor getColor(short index)
83       {
84           byte[] b = palette.getColor(index);
85           if (b != null)
86           {
87               return new CustomColor(index, b);
88           }
89           return null;
90       }
91       
92       /**
93        * Finds the first occurance of a given color
94        *
95        * @param red the RGB red component, between 0 and 255 inclusive
96        * @param green the RGB green component, between 0 and 255 inclusive
97        * @param blue the RGB blue component, between 0 and 255 inclusive
98        * @return the color, or null if the color does not exist in this palette
99        */
100      public HSSFColor findColor(byte red, byte green, byte blue)
101      {
102          byte[] b = palette.getColor(PaletteRecord.FIRST_COLOR_INDEX);
103          for (short i = (short) PaletteRecord.FIRST_COLOR_INDEX; b != null;
104              b = palette.getColor(++i))
105          {
106              if (b[0] == red && b[1] == blue && b[2] == green)
107              {
108                  return new CustomColor(i, b);
109              }
110          }
111          return null;
112      }
113      
114      /**
115       * Sets the color at the given offset
116       *
117       * @param index the palette index, between 0x8 to 0x40 inclusive
118       * @param red the RGB red component, between 0 and 255 inclusive
119       * @param green the RGB green component, between 0 and 255 inclusive
120       * @param blue the RGB blue component, between 0 and 255 inclusive
121       */
122      public void setColorAtIndex(short index, byte red, byte green, byte blue)
123      {
124          palette.setColor(index, red, green, blue);
125      }
126      
127      private static class CustomColor extends HSSFColor
128      {
129          private short byteOffset;
130          private byte red;
131          private byte green;
132          private byte blue;
133          
134          private CustomColor(short byteOffset, byte[] colors)
135          {
136              this(byteOffset, colors[0], colors[1], colors[2]);
137          }
138          
139          private CustomColor(short byteOffset, byte red, byte green, byte blue)
140          {
141              this.byteOffset = byteOffset;
142              this.red = red;
143              this.green = green;
144              this.blue = blue;
145          }
146          
147          public short getIndex()
148          {
149              return byteOffset;
150          }
151          
152          public short[] getTriplet()
153          {
154              return new short[]
155              {
156                  (short) (red   & 0xff),
157                  (short) (green & 0xff),
158                  (short) (blue  & 0xff)
159              };
160          }
161          
162          public String getHexString()
163          {
164              StringBuffer sb = new StringBuffer();
165              sb.append(getGnumericPart(red));
166              sb.append(':');
167              sb.append(getGnumericPart(green));
168              sb.append(':');
169              sb.append(getGnumericPart(blue));
170              return sb.toString();
171          }
172          
173          private String getGnumericPart(byte color)
174          {
175              String s;
176              if (color == 0)
177              {
178                  s = "0";
179              }
180              else
181              {
182                  int c = color & 0xff; //as unsigned
183                  c = (c << 8) | c; //pad to 16-bit
184                  s = Integer.toHexString(c).toUpperCase();
185                  while (s.length() < 4)
186                  {
187                      s = "0" + s;
188                  }
189              }
190              return s;
191          }
192      }
193  }
194