* Excel can get cranky if you give it files containing too
* many (especially duplicate) objects, and this class can
* help to avoid those.
- * In general, it's much better to make sure you don't
+ * In general, it's much better to make sure you don't
* duplicate the objects in your code, as this is likely
* to be much faster than creating lots and lots of
* excel objects+records, only to optimise them down to
public static void optimiseFonts(HSSFWorkbook workbook) {
// Where each font has ended up, and if we need to
// delete the record for it. Start off with no change
- short[] newPos =
+ short[] newPos =
new short[workbook.getWorkbook().getNumberOfFontRecords()+1];
boolean[] zapRecords = new boolean[newPos.length];
for(int i=0; i<newPos.length; i++) {
newPos[i] = (short)i;
zapRecords[i] = false;
}
-
+
// Get each font record, so we can do deletes
// without getting confused
- FontRecord[] frecs = new FontRecord[newPos.length];
+ FontRecord[] frecs = new FontRecord[newPos.length];
for(int i=0; i<newPos.length; i++) {
// There is no 4!
if(i == 4) continue;
-
+
frecs[i] = workbook.getWorkbook().getFontRecordAt(i);
}
-
+
// Loop over each font, seeing if it is the same
// as an earlier one. If it is, point users of the
- // later duplicate copy to the earlier one, and
+ // later duplicate copy to the earlier one, and
// mark the later one as needing deleting
// Note - don't change built in fonts (those before 5)
for(int i=5; i<newPos.length; i++) {
int earlierDuplicate = -1;
for(int j=0; j<i && earlierDuplicate == -1; j++) {
if(j == 4) continue;
-
+
FontRecord frCheck = workbook.getWorkbook().getFontRecordAt(j);
if(frCheck.sameProperties(frecs[i])) {
earlierDuplicate = j;
}
}
-
+
// If we got a duplicate, mark it as such
if(earlierDuplicate != -1) {
newPos[i] = (short)earlierDuplicate;
zapRecords[i] = true;
}
}
-
+
// Update the new positions based on
// deletes that have occurred between
// the start and them
for(int j=0; j<preDeletePos; j++) {
if(zapRecords[j]) newPosition--;
}
-
+
// Update the new position
newPos[i] = newPosition;
}
-
+
// Zap the un-needed user font records
for(int i=5; i<newPos.length; i++) {
if(zapRecords[i]) {
);
}
}
-
+
// Tell HSSFWorkbook that it needs to
// re-start its HSSFFontCache
workbook.resetFontCache();
-
- // Update the cell styles to point at the
+
+ // Update the cell styles to point at the
// new locations of the fonts
for(int i=0; i<workbook.getWorkbook().getNumExFormats(); i++) {
ExtendedFormatRecord xfr = workbook.getWorkbook().getExFormatAt(i);
newPos[ xfr.getFontIndex() ]
);
}
-
+
// Update the rich text strings to point at
// the new locations of the fonts
// Remember that one underlying unicode string
if(cell.getCellType() == CellType.STRING) {
HSSFRichTextString rtr = (HSSFRichTextString)cell.getRichStringCellValue();
UnicodeString u = rtr.getRawUnicodeString();
-
+
// Have we done this string already?
if(! doneUnicodeStrings.contains(u)) {
// Update for each new position
u.swapFontUse(i, newPos[i]);
}
}
-
+
// Mark as done
doneUnicodeStrings.add(u);
}
}
}
}
-
+
/**
* Goes through the Wokrbook, optimising the cell styles
* by removing duplicate ones, and ones that aren't used.
short[] newPos = new short[workbook.getWorkbook().getNumExFormats()];
boolean[] isUsed = new boolean[newPos.length];
boolean[] zapRecords = new boolean[newPos.length];
+
+ // to speed up the optimisation for workbooks with a large number of
+ // styles we perform the isUserDefined() check only once as it is
+ // costly according to some profiling
+ boolean[] userDefined = new boolean[newPos.length];
+
+ // Get each style record, so we can do deletes
+ // without getting confused
+ ExtendedFormatRecord[] xfrs = new ExtendedFormatRecord[newPos.length];
+
for(int i=0; i<newPos.length; i++) {
isUsed[i] = false;
newPos[i] = (short)i;
zapRecords[i] = false;
- }
- // Get each style record, so we can do deletes
- // without getting confused
- ExtendedFormatRecord[] xfrs = new ExtendedFormatRecord[newPos.length];
- for(int i=0; i<newPos.length; i++) {
- xfrs[i] = workbook.getWorkbook().getExFormatAt(i);
+ userDefined[i] = isUserDefined(workbook, i);
+
+ xfrs[i] = workbook.getWorkbook().getExFormatAt(i);
}
// Loop over each style, seeing if it is the same
// Check this one for being a duplicate
// of an earlier one
int earlierDuplicate = -1;
- for (int j = 0; j < i && earlierDuplicate == -1; j++) {
+ for (int j = 0; j < i; j++) {
ExtendedFormatRecord xfCheck = workbook.getWorkbook().getExFormatAt(j);
if (xfCheck.equals(xfrs[i]) &&
- // newer duplicate user defined styles
- !isUserDefined(workbook, j)) {
+ // never duplicate user defined styles
+ !userDefined[j]) {
earlierDuplicate = j;
+ break;
}
}