From 6c4db5b3dec1eebca970daad2e2b8517739a284f Mon Sep 17 00:00:00 2001 From: Aron Nopanen Date: Wed, 21 Jan 2015 14:22:35 -0800 Subject: [PATCH] Refactor SheetUtil.getCellWidth for performance Refactor code so that when calling SheetUtil.getCellWidth across a range of rows, Sheet.getNumMergedRegions and Sheet.getMergedRegion are called as few times as possible. For large spreadsheets with many merged regions, this is a large performance savings. --- .gitignore | 5 +++ src/java/org/apache/poi/ss/util/SheetUtil.java | 47 +++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..886e52b --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/bin/ +/build/ +/compile-lib/ +/lib/ +/ooxml-lib/ diff --git a/src/java/org/apache/poi/ss/util/SheetUtil.java b/src/java/org/apache/poi/ss/util/SheetUtil.java index 6b55e22..91e3596 100644 --- a/src/java/org/apache/poi/ss/util/SheetUtil.java +++ b/src/java/org/apache/poi/ss/util/SheetUtil.java @@ -96,15 +96,50 @@ public int evaluateFormulaCell(Cell cell) { * @return the width in pixels */ public static double getCellWidth(Cell cell, int defaultCharWidth, DataFormatter formatter, boolean useMergedCells) { + Sheet sheet = cell.getSheet(); + + CellRangeAddress[] regions = getMergedRegionArray(sheet); + + return getCellWidth(cell, defaultCharWidth, formatter, useMergedCells, regions); + } + /** + * Get an array of 'merged regions' for the provided sheet + * + * @param sheet Sheet to evaluate + * @return Array of CellRangeAddresses for merged regions in the sheet + */ + private static CellRangeAddress[] getMergedRegionArray(Sheet sheet) { + int numMergedRegions = sheet.getNumMergedRegions(); + CellRangeAddress[] regions = new CellRangeAddress[numMergedRegions]; + for (int i = 0; i < numMergedRegions; i++) { + regions[i] = sheet.getMergedRegion(i); + } + return regions; + } + + /** + * + * Compute width of a single cell, passing in data on merged regions for performance reasons, if being called + * multiple times in succession. + * + * @param cell the cell whose width is to be calculated + * @param defaultCharWidth the width of a single character + * @param formatter formatter used to prepare the text to be measured + * @param useMergedCells whether to use merged cells + * @param regions array of 'merged regions' information for the sheet + * @return the width in pixels + */ + private static double getCellWidth(Cell cell, int defaultCharWidth, DataFormatter formatter, boolean useMergedCells, + CellRangeAddress[] regions) { Sheet sheet = cell.getSheet(); Workbook wb = sheet.getWorkbook(); Row row = cell.getRow(); int column = cell.getColumnIndex(); int colspan = 1; - for (int i = 0 ; i < sheet.getNumMergedRegions(); i++) { - CellRangeAddress region = sheet.getMergedRegion(i); + for (int i = 0 ; i < regions.length; i++) { + CellRangeAddress region = regions[i]; if (containsCell(region, row.getRowNum(), column)) { if (!useMergedCells) { // If we're not using merged cells, skip this one and move on to the next. @@ -218,6 +253,8 @@ public static double getColumnWidth(Sheet sheet, int column, boolean useMergedCe layout = new TextLayout(str.getIterator(), fontRenderContext); int defaultCharWidth = (int)layout.getAdvance(); + CellRangeAddress[] regions = getMergedRegionArray(sheet); + double width = -1; for (Row row : sheet) { Cell cell = row.getCell(column); @@ -226,7 +263,7 @@ public static double getColumnWidth(Sheet sheet, int column, boolean useMergedCe continue; } - double cellWidth = getCellWidth(cell, defaultCharWidth, formatter, useMergedCells); + double cellWidth = getCellWidth(cell, defaultCharWidth, formatter, useMergedCells, regions); width = Math.max(width, cellWidth); } return width; @@ -255,6 +292,8 @@ public static double getColumnWidth(Sheet sheet, int column, boolean useMergedCe layout = new TextLayout(str.getIterator(), fontRenderContext); int defaultCharWidth = (int)layout.getAdvance(); + CellRangeAddress[] regions = getMergedRegionArray(sheet); + double width = -1; for (int rowIdx = firstRow; rowIdx <= lastRow; ++rowIdx) { Row row = sheet.getRow(rowIdx); @@ -266,7 +305,7 @@ public static double getColumnWidth(Sheet sheet, int column, boolean useMergedCe continue; } - double cellWidth = getCellWidth(cell, defaultCharWidth, formatter, useMergedCells); + double cellWidth = getCellWidth(cell, defaultCharWidth, formatter, useMergedCells, regions); width = Math.max(width, cellWidth); } }