PR 15743: Add support for custom palettes: Submitted by Brian Sanders

git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@352978 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Avik Sengupta 2003-01-02 11:17:57 +00:00
parent e4e984b482
commit 04571a0a59
5 changed files with 236 additions and 9 deletions

View File

@ -27,6 +27,7 @@
<li><link href="#FrillsAndFills">Fills and color</link></li> <li><link href="#FrillsAndFills">Fills and color</link></li>
<li><link href="#MergedCells">Merging cells</link></li> <li><link href="#MergedCells">Merging cells</link></li>
<li><link href="#WorkingWithFonts">Working with fonts</link></li> <li><link href="#WorkingWithFonts">Working with fonts</link></li>
<li><link href="#CustomColors">Custom colors</link></li>
<li><link href="#ReadWriteWorkbook">Reading and writing</link></li> <li><link href="#ReadWriteWorkbook">Reading and writing</link></li>
<li><link href="#NewLinesInCells">Use newlines in cells.</link></li> <li><link href="#NewLinesInCells">Use newlines in cells.</link></li>
<li><link href="#DataFormats">Create user defined data formats.</link></li> <li><link href="#DataFormats">Create user defined data formats.</link></li>
@ -280,6 +281,60 @@
fileOut.close(); fileOut.close();
</source> </source>
</section> </section>
<anchor id="CustomColors"/>
<section title="Custom colors">
<source>
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
HSSFRow row = sheet.createRow((short) 0);
HSSFCell cell = row.createCell((short) 0);
cell.setCellValue("Default Palette");
//apply some colors from the standard palette,
// as in the previous examples.
//we'll use red text on a lime background
HSSFCellStyle style = wb.createCellStyle();
style.setFillForegroundColor(HSSFColor.LIME.index);
style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
HSSFFont font = wb.createFont();
font.setColor(HSSFColor.RED.index);
style.setFont(font);
cell.setCellStyle(style);
//save with the default palette
FileOutputStream out = new FileOutputStream("default_palette.xls");
wb.write(out);
out.close();
//now, let's replace RED and LIME in the palette
// with a more attractive combination
// (lovingly borrowed from freebsd.org)
cell.setCellValue("Modified Palette");
//creating a custom palette for the workbook
HSSFPalette palette = wb.getCustomPalette();
//replacing the standard red with freebsd.org red
palette.setColorAtIndex(HSSFColor.RED.index,
(byte) 153, //RGB red (0-255)
(byte) 0, //RGB green
(byte) 0 //RGB blue
);
//replacing lime with freebsd.org gold
palette.setColorAtIndex(HSSFColor.LIME.index, (byte) 255, (byte) 204, (byte) 102);
//save with the modified palette
// note that wherever we have previously used RED or LIME, the
// new colors magically appear
out = new FileOutputStream("modified_palette.xls");
wb.write(out);
out.close();
</source>
</section>
<anchor id="ReadWriteWorkbook"/> <anchor id="ReadWriteWorkbook"/>
<section title="Reading and Rewriting Workbooks"> <section title="Reading and Rewriting Workbooks">
<source> <source>

View File

@ -89,6 +89,7 @@ import java.util.Locale;
* @author Sergei Kozello (sergeikozello at mail.ru) * @author Sergei Kozello (sergeikozello at mail.ru)
* @author Luc Girardin (luc dot girardin at macrofocus dot com) * @author Luc Girardin (luc dot girardin at macrofocus dot com)
* @author Dan Sherman (dsherman at isisph.com) * @author Dan Sherman (dsherman at isisph.com)
* @author Brian Sanders (bsanders at risklabs dot com) - custom palette
* @see org.apache.poi.hssf.usermodel.HSSFWorkbook * @see org.apache.poi.hssf.usermodel.HSSFWorkbook
* @version 1.0-pre * @version 1.0-pre
*/ */
@ -146,6 +147,7 @@ public class Workbook implements Model {
private int backuppos = 0; // holds the position of the backup record. private int backuppos = 0; // holds the position of the backup record.
private int namepos = 0; // holds the position of last name record private int namepos = 0; // holds the position of last name record
private int supbookpos = 0; // holds the position of sup book private int supbookpos = 0; // holds the position of sup book
private int palettepos = 0; // hold the position of the palette, if applicable
private short maxformatid = -1; // holds the max format id private short maxformatid = -1; // holds the max format id
private boolean uses1904datewindowing = false; // whether 1904 date windowing is being used private boolean uses1904datewindowing = false; // whether 1904 date windowing is being used
@ -249,7 +251,9 @@ public class Workbook implements Model {
log.log(DEBUG, "found datewindow1904 record at " + k); log.log(DEBUG, "found datewindow1904 record at " + k);
retval.uses1904datewindowing = ((DateWindow1904Record)rec).getWindowing() == 1; retval.uses1904datewindowing = ((DateWindow1904Record)rec).getWindowing() == 1;
break; break;
case PaletteRecord.sid:
log.log(DEBUG, "found palette record at " + k);
retval.palettepos = k;
default : default :
} }
records.add(rec); records.add(rec);
@ -328,6 +332,7 @@ public class Workbook implements Model {
{ {
records.add( retval.createStyle( k ) ); records.add( retval.createStyle( k ) );
} }
retval.palettepos = records.size();
records.add( retval.createUseSelFS() ); records.add( retval.createUseSelFS() );
for ( int k = 0; k < 1; k++ ) for ( int k = 0; k < 1; k++ )
{ // now just do 1 { // now just do 1
@ -578,6 +583,7 @@ public class Workbook implements Model {
ExtendedFormatRecord xf = createExtendedFormat(); ExtendedFormatRecord xf = createExtendedFormat();
++xfpos; ++xfpos;
++palettepos;
++bspos; ++bspos;
records.add(xfpos, xf); records.add(xfpos, xf);
numxfs++; numxfs++;
@ -1566,6 +1572,16 @@ public class Workbook implements Model {
return retval; return retval;
} }
/**
* Creates a palette record initialized to the default palette
* @return a PaletteRecord instance populated with the default colors
* @see org.apache.poi.hssf.record.PaletteRecord
*/
protected PaletteRecord createPalette()
{
return new PaletteRecord(PaletteRecord.sid);
}
/** /**
* Creates the UseSelFS object with the use natural language flag set to 0 (false) * Creates the UseSelFS object with the use natural language flag set to 0 (false)
* @return record containing a UseSelFSRecord * @return record containing a UseSelFSRecord
@ -1864,6 +1880,7 @@ public class Workbook implements Model {
public short createFormat( String format ) public short createFormat( String format )
{ {
++xfpos; //These are to ensure that positions are updated properly ++xfpos; //These are to ensure that positions are updated properly
++palettepos;
++bspos; ++bspos;
FormatRecord rec = new FormatRecord(); FormatRecord rec = new FormatRecord();
maxformatid = maxformatid >= (short) 0xa4 ? (short) ( maxformatid + 1 ) : (short) 0xa4; //Starting value from M$ empiracle study. maxformatid = maxformatid >= (short) 0xa4 ? (short) ( maxformatid + 1 ) : (short) 0xa4; //Starting value from M$ empiracle study.
@ -1941,6 +1958,7 @@ public class Workbook implements Model {
// { // {
// backuppos += chartRecords.size(); // backuppos += chartRecords.size();
// fontpos += chartRecords.size(); // fontpos += chartRecords.size();
// palettepos += chartRecords.size();
// bspos += chartRecords.size(); // bspos += chartRecords.size();
// xfpos += chartRecords.size(); // xfpos += chartRecords.size();
// //
@ -1956,4 +1974,25 @@ public class Workbook implements Model {
public boolean isUsing1904DateWindowing() { public boolean isUsing1904DateWindowing() {
return uses1904datewindowing; return uses1904datewindowing;
} }
/**
* Returns the custom palette in use for this workbook; if a custom palette record
* does not exist, then it is created.
*/
public PaletteRecord getCustomPalette()
{
PaletteRecord palette;
Record rec = (Record) records.get(palettepos);
if (rec instanceof PaletteRecord)
{
palette = (PaletteRecord) rec;
}
else
{
palette = createPalette();
records.add(palettepos, palette);
++bspos;
}
return palette;
}
} }

View File

@ -63,6 +63,7 @@ import org.apache.poi.util.LittleEndian;
/** /**
* PaletteRecord - Supports custom palettes. * PaletteRecord - Supports custom palettes.
* @author Andrew C. Oliver (acoliver at apache dot org) * @author Andrew C. Oliver (acoliver at apache dot org)
* @author Brian Sanders (bsanders at risklabs dot com) - custom palette editing
* @version 2.0-pre * @version 2.0-pre
*/ */
@ -70,6 +71,10 @@ public class PaletteRecord
extends Record extends Record
{ {
public final static short sid = 0x92; public final static short sid = 0x92;
/** The standard size of an XLS palette */
public final static byte STANDARD_PALETTE_SIZE = (byte) 56;
/** The byte index of the first color */
public final static short FIRST_COLOR_INDEX = (short) 0x8;
private short field_1_numcolors; private short field_1_numcolors;
private List field_2_colors; private List field_2_colors;
@ -78,6 +83,14 @@ public class PaletteRecord
{ {
} }
/**
* Constructs a custom palette with the default set of colors
*/
public PaletteRecord(short id)
{
super(id, STANDARD_PALETTE_SIZE, getDefaultData());
}
/** /**
* Constructs a PaletteRecord record and sets its fields appropriately. * Constructs a PaletteRecord record and sets its fields appropriately.
* *
@ -131,7 +144,7 @@ public class PaletteRecord
{ {
StringBuffer buffer = new StringBuffer(); StringBuffer buffer = new StringBuffer();
buffer.append("[Palette]\n"); buffer.append("[PALETTE]\n");
buffer.append(" numcolors = ").append(field_1_numcolors) buffer.append(" numcolors = ").append(field_1_numcolors)
.append('\n'); .append('\n');
for (int k = 0; k < field_1_numcolors; k++) { for (int k = 0; k < field_1_numcolors; k++) {
@ -142,16 +155,18 @@ public class PaletteRecord
buffer.append("/*colornum = ").append(k) buffer.append("/*colornum = ").append(k)
.append('\n'); .append('\n');
} }
buffer.append("[/Palette]\n"); buffer.append("[/PALETTE]\n");
return buffer.toString(); return buffer.toString();
} }
public int serialize(int offset, byte [] data) public int serialize(int offset, byte [] data)
{ {
LittleEndian.putShort(data, 0 + offset, sid); LittleEndian.putShort(data, 0 + offset, sid);
LittleEndian.putShort(data, 2 + offset, (short) (getRecordSize() - 4));
LittleEndian.putShort(data, 4 + offset, field_1_numcolors);
for (int k = 0; k < field_1_numcolors; k++) { for (int k = 0; k < field_1_numcolors; k++) {
PColor c = (PColor)field_2_colors.get(k); PColor c = (PColor)field_2_colors.get(k);
c.serialize(data, (2+offset+(k*4))); c.serialize(data, (6+offset+(k*4)));
} }
return getRecordSize(); return getRecordSize();
@ -159,7 +174,7 @@ public class PaletteRecord
public int getRecordSize() public int getRecordSize()
{ {
return 2 + (field_1_numcolors * 4); return 4 + 2 + (field_1_numcolors * 4);
} }
public short getSid() public short getSid()
@ -167,6 +182,115 @@ public class PaletteRecord
return this.sid; return this.sid;
} }
/**
* Returns the color value at a given index
*
* @return the RGB triplet for the color, or null if the specified index
* does not exist
*/
public byte[] getColor(short byteIndex)
{
int i = byteIndex - FIRST_COLOR_INDEX;
if (i < 0 || i >= field_2_colors.size())
{
return null;
}
PColor color = (PColor) field_2_colors.get(i);
return new byte[] { color.red, color.green, color.blue };
}
/**
* Sets the color value at a given index
*
* If the given index is greater than the current last color index,
* then black is inserted at every index required to make the palette continuous.
*
* @param i the index to set; if this index is less than 0x8 or greater than
* 0x40, then no modification is made
*/
public void setColor(short byteIndex, byte red, byte green, byte blue)
{
int i = byteIndex - FIRST_COLOR_INDEX;
if (i < 0 || i >= STANDARD_PALETTE_SIZE)
{
return;
}
while (field_2_colors.size() <= i)
{
field_2_colors.add(new PColor((byte) 0, (byte) 0, (byte) 0));
}
PColor custColor = new PColor(red, green, blue);
field_2_colors.set(i, custColor);
}
/**
* Returns the default palette as PaletteRecord binary data
*
* @see org.apache.poi.hssf.model.Workbook#createPalette
*/
public static byte[] getDefaultData()
{
return new byte[]
{
STANDARD_PALETTE_SIZE, (byte) 0,
(byte) 0, (byte) 0, (byte) 0, (byte) 0, //color 0...
(byte) 255, (byte) 255, (byte) 255, (byte) 0,
(byte) 255, (byte) 0, (byte) 0, (byte) 0,
(byte) 0, (byte) 255, (byte) 0, (byte) 0,
(byte) 0, (byte) 0, (byte) 255, (byte) 0,
(byte) 255, (byte) 255, (byte) 0, (byte) 0,
(byte) 255, (byte) 0, (byte) 255, (byte) 0,
(byte) 0, (byte) 255, (byte) 255, (byte) 0,
(byte) 128, (byte) 0, (byte) 0, (byte) 0,
(byte) 0, (byte) 128, (byte) 0, (byte) 0,
(byte) 0, (byte) 0, (byte) 128, (byte) 0,
(byte) 128, (byte) 128, (byte) 0, (byte) 0,
(byte) 128, (byte) 0, (byte) 128, (byte) 0,
(byte) 0, (byte) 128, (byte) 128, (byte) 0,
(byte) 192, (byte) 192, (byte) 192, (byte) 0,
(byte) 128, (byte) 128, (byte) 128, (byte) 0,
(byte) 153, (byte) 153, (byte) 255, (byte) 0,
(byte) 153, (byte) 51, (byte) 102, (byte) 0,
(byte) 255, (byte) 255, (byte) 204, (byte) 0,
(byte) 204, (byte) 255, (byte) 255, (byte) 0,
(byte) 102, (byte) 0, (byte) 102, (byte) 0,
(byte) 255, (byte) 128, (byte) 128, (byte) 0,
(byte) 0, (byte) 102, (byte) 204, (byte) 0,
(byte) 204, (byte) 204, (byte) 255, (byte) 0,
(byte) 0, (byte) 0, (byte) 128, (byte) 0,
(byte) 255, (byte) 0, (byte) 255, (byte) 0,
(byte) 255, (byte) 255, (byte) 0, (byte) 0,
(byte) 0, (byte) 255, (byte) 255, (byte) 0,
(byte) 128, (byte) 0, (byte) 128, (byte) 0,
(byte) 128, (byte) 0, (byte) 0, (byte) 0,
(byte) 0, (byte) 128, (byte) 128, (byte) 0,
(byte) 0, (byte) 0, (byte) 255, (byte) 0,
(byte) 0, (byte) 204, (byte) 255, (byte) 0,
(byte) 204, (byte) 255, (byte) 255, (byte) 0,
(byte) 204, (byte) 255, (byte) 204, (byte) 0,
(byte) 255, (byte) 255, (byte) 153, (byte) 0,
(byte) 153, (byte) 204, (byte) 255, (byte) 0,
(byte) 255, (byte) 153, (byte) 204, (byte) 0,
(byte) 204, (byte) 153, (byte) 255, (byte) 0,
(byte) 255, (byte) 204, (byte) 153, (byte) 0,
(byte) 51, (byte) 102, (byte) 255, (byte) 0,
(byte) 51, (byte) 204, (byte) 204, (byte) 0,
(byte) 153, (byte) 204, (byte) 0, (byte) 0,
(byte) 255, (byte) 204, (byte) 0, (byte) 0,
(byte) 255, (byte) 153, (byte) 0, (byte) 0,
(byte) 255, (byte) 102, (byte) 0, (byte) 0,
(byte) 102, (byte) 102, (byte) 153, (byte) 0,
(byte) 150, (byte) 150, (byte) 150, (byte) 0,
(byte) 0, (byte) 51, (byte) 102, (byte) 0,
(byte) 51, (byte) 153, (byte) 102, (byte) 0,
(byte) 0, (byte) 51, (byte) 0, (byte) 0,
(byte) 51, (byte) 51, (byte) 0, (byte) 0,
(byte) 153, (byte) 51, (byte) 0, (byte) 0,
(byte) 153, (byte) 51, (byte) 102, (byte) 0,
(byte) 51, (byte) 51, (byte) 153, (byte) 0,
(byte) 51, (byte) 51, (byte) 51, (byte) 0
};
}
} }
/** /**
@ -191,9 +315,9 @@ class PColor {
public String toString() { public String toString() {
StringBuffer buffer = new StringBuffer(); StringBuffer buffer = new StringBuffer();
buffer.append(" red = ").append(red).append('\n'); buffer.append(" red = ").append(red & 0xff).append('\n');
buffer.append(" green = ").append(green).append('\n'); buffer.append(" green = ").append(green & 0xff).append('\n');
buffer.append(" blue = ").append(blue).append('\n'); buffer.append(" blue = ").append(blue & 0xff).append('\n');
return buffer.toString(); return buffer.toString();
} }
} }

View File

@ -728,6 +728,11 @@ public class HSSFWorkbook
} }
public HSSFPalette getCustomPalette()
{
return new HSSFPalette(workbook.getCustomPalette());
}
/** /**
* Copies nodes from one POIFS to the other minus the excepts * Copies nodes from one POIFS to the other minus the excepts
* @param source is the source POIFS to copy from * @param source is the source POIFS to copy from

View File

@ -27,6 +27,7 @@ import org.apache.poi.hssf.record.TestLineFormatRecord;
import org.apache.poi.hssf.record.TestLinkedDataRecord; import org.apache.poi.hssf.record.TestLinkedDataRecord;
import org.apache.poi.hssf.record.TestNumberFormatIndexRecord; import org.apache.poi.hssf.record.TestNumberFormatIndexRecord;
import org.apache.poi.hssf.record.TestObjectLinkRecord; import org.apache.poi.hssf.record.TestObjectLinkRecord;
import org.apache.poi.hssf.record.TestPaletteRecord;
import org.apache.poi.hssf.record.TestPlotAreaRecord; import org.apache.poi.hssf.record.TestPlotAreaRecord;
import org.apache.poi.hssf.record.TestPlotGrowthRecord; import org.apache.poi.hssf.record.TestPlotGrowthRecord;
import org.apache.poi.hssf.record.TestRecordFactory; import org.apache.poi.hssf.record.TestRecordFactory;
@ -53,6 +54,7 @@ import org.apache.poi.hssf.usermodel.TestCellStyle;
import org.apache.poi.hssf.usermodel.TestFormulas; import org.apache.poi.hssf.usermodel.TestFormulas;
import org.apache.poi.hssf.usermodel.TestHSSFCell; import org.apache.poi.hssf.usermodel.TestHSSFCell;
import org.apache.poi.hssf.usermodel.TestHSSFDateUtil; import org.apache.poi.hssf.usermodel.TestHSSFDateUtil;
import org.apache.poi.hssf.usermodel.TestHSSFPalette;
import org.apache.poi.hssf.usermodel.TestHSSFRow; import org.apache.poi.hssf.usermodel.TestHSSFRow;
import org.apache.poi.hssf.usermodel.TestHSSFSheet; import org.apache.poi.hssf.usermodel.TestHSSFSheet;
import org.apache.poi.hssf.usermodel.TestNamedRange; import org.apache.poi.hssf.usermodel.TestNamedRange;
@ -86,6 +88,7 @@ public class HSSFTests
suite.addTest(new TestSuite(TestFormulas.class)); suite.addTest(new TestSuite(TestFormulas.class));
suite.addTest(new TestSuite(TestHSSFCell.class)); suite.addTest(new TestSuite(TestHSSFCell.class));
suite.addTest(new TestSuite(TestHSSFDateUtil.class)); suite.addTest(new TestSuite(TestHSSFDateUtil.class));
suite.addTest(new TestSuite(TestHSSFPalette.class));
suite.addTest(new TestSuite(TestHSSFRow.class)); suite.addTest(new TestSuite(TestHSSFRow.class));
suite.addTest(new TestSuite(TestHSSFSheet.class)); suite.addTest(new TestSuite(TestHSSFSheet.class));
suite.addTest(new TestSuite(TestNamedRange.class)); suite.addTest(new TestSuite(TestNamedRange.class));
@ -116,6 +119,7 @@ public class HSSFTests
suite.addTest(new TestSuite(TestLinkedDataRecord.class)); suite.addTest(new TestSuite(TestLinkedDataRecord.class));
suite.addTest(new TestSuite(TestNumberFormatIndexRecord.class)); suite.addTest(new TestSuite(TestNumberFormatIndexRecord.class));
suite.addTest(new TestSuite(TestObjectLinkRecord.class)); suite.addTest(new TestSuite(TestObjectLinkRecord.class));
suite.addTest(new TestSuite(TestPaletteRecord.class));
suite.addTest(new TestSuite(TestPlotAreaRecord.class)); suite.addTest(new TestSuite(TestPlotAreaRecord.class));
suite.addTest(new TestSuite(TestPlotGrowthRecord.class)); suite.addTest(new TestSuite(TestPlotGrowthRecord.class));
suite.addTest(new TestSuite(TestRecordFactory.class)); suite.addTest(new TestSuite(TestRecordFactory.class));