mirror of https://github.com/apache/poi.git
bug 55075,51233: create drawings with correct height when rows are custom height
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1763950 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
7c141433f7
commit
63b9090007
|
@ -98,7 +98,6 @@ public final class OOXMLLite {
|
|||
"BaseTestXCell",
|
||||
"BaseTestXSSFPivotTable",
|
||||
"TestSXSSFWorkbook\\$\\d",
|
||||
"TestSXSSFWorkbook\\$NullOutputStream",
|
||||
"TestUnfixedBugs",
|
||||
"MemoryUsage",
|
||||
"TestDataProvider",
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.xssf.streaming;
|
||||
|
||||
import org.apache.poi.ss.usermodel.Chart;
|
||||
import org.apache.poi.ss.usermodel.ClientAnchor;
|
||||
import org.apache.poi.ss.usermodel.Comment;
|
||||
import org.apache.poi.ss.usermodel.Drawing;
|
||||
import org.apache.poi.xssf.usermodel.XSSFDrawing;
|
||||
import org.apache.poi.xssf.usermodel.XSSFPicture;
|
||||
|
||||
/**
|
||||
* Streaming version of Drawing.
|
||||
* Delegates most tasks to the non-streaming XSSF code.
|
||||
* TODO: Potentially, Comment and Chart need a similar streaming wrapper like Picture.
|
||||
*/
|
||||
public class SXSSFDrawing implements Drawing {
|
||||
private final SXSSFWorkbook _wb;
|
||||
private final XSSFDrawing _drawing;
|
||||
|
||||
public SXSSFDrawing(SXSSFWorkbook workbook, XSSFDrawing drawing) {
|
||||
this._wb = workbook;
|
||||
this._drawing = drawing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SXSSFPicture createPicture(ClientAnchor anchor, int pictureIndex) {
|
||||
XSSFPicture pict = _drawing.createPicture(anchor, pictureIndex);
|
||||
return new SXSSFPicture(_wb, pict);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comment createCellComment(ClientAnchor anchor) {
|
||||
return _drawing.createCellComment(anchor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chart createChart(ClientAnchor anchor) {
|
||||
return _drawing.createChart(anchor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientAnchor createAnchor(int dx1, int dy1, int dx2, int dy2, int col1, int row1, int col2, int row2) {
|
||||
return _drawing.createAnchor(dx1, dy1, dx2, dy2, col1, row1, col2, row2);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,274 @@
|
|||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.xssf.streaming;
|
||||
|
||||
import org.apache.poi.openxml4j.opc.PackagePart;
|
||||
import org.apache.poi.ss.usermodel.ClientAnchor;
|
||||
import org.apache.poi.ss.usermodel.Picture;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.ss.util.ImageUtils;
|
||||
import org.apache.poi.util.Internal;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
import org.apache.poi.xssf.usermodel.*;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTPicture;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Streaming version of Picture.
|
||||
* Most of the code is a copy of the non-streaming XSSFPicture code.
|
||||
* This is necessary as a private method getRowHeightInPixels of that class needs to be changed, which is called by a method call chain nested several levels.
|
||||
*
|
||||
* The main change is to access the rows in the SXSSF sheet, not the always empty rows in the XSSF sheet when checking the row heights.
|
||||
*/
|
||||
public final class SXSSFPicture implements Picture {
|
||||
private static final POILogger logger = POILogFactory.getLogger(SXSSFPicture.class);
|
||||
/**
|
||||
* Column width measured as the number of characters of the maximum digit width of the
|
||||
* numbers 0, 1, 2, ..., 9 as rendered in the normal style's font. There are 4 pixels of margin
|
||||
* padding (two on each side), plus 1 pixel padding for the gridlines.
|
||||
*
|
||||
* This value is the same for default font in Office 2007 (Calibry) and Office 2003 and earlier (Arial)
|
||||
*/
|
||||
private static float DEFAULT_COLUMN_WIDTH = 9.140625f;
|
||||
|
||||
private final SXSSFWorkbook _wb;
|
||||
private final XSSFPicture _picture;
|
||||
|
||||
SXSSFPicture(SXSSFWorkbook _wb, XSSFPicture _picture) {
|
||||
this._wb = _wb;
|
||||
this._picture = _picture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying CTPicture bean that holds all properties for this picture
|
||||
*
|
||||
* @return the underlying CTPicture bean
|
||||
*/
|
||||
@Internal
|
||||
public CTPicture getCTPicture(){
|
||||
return _picture.getCTPicture();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the image to the original size.
|
||||
*
|
||||
* <p>
|
||||
* Please note, that this method works correctly only for workbooks
|
||||
* with the default font size (Calibri 11pt for .xlsx).
|
||||
* If the default font is changed the resized image can be streched vertically or horizontally.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public void resize(){
|
||||
resize(1.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the image to the original size.
|
||||
* <p>
|
||||
* Please note, that this method works correctly only for workbooks
|
||||
* with the default font size (Calibri 11pt for .xlsx).
|
||||
* If the default font is changed the resized image can be streched vertically or horizontally.
|
||||
* </p>
|
||||
*
|
||||
* @param scale the amount by which image dimensions are multiplied relative to the original size.
|
||||
* <code>resize(1.0)</code> sets the original size, <code>resize(0.5)</code> resize to 50% of the original,
|
||||
* <code>resize(2.0)</code> resizes to 200% of the original.
|
||||
*/
|
||||
@Override
|
||||
public void resize(double scale){
|
||||
XSSFClientAnchor anchor = getAnchor();
|
||||
|
||||
XSSFClientAnchor pref = getPreferredSize(scale);
|
||||
|
||||
int row2 = anchor.getRow1() + (pref.getRow2() - pref.getRow1());
|
||||
int col2 = anchor.getCol1() + (pref.getCol2() - pref.getCol1());
|
||||
|
||||
anchor.setCol2(col2);
|
||||
anchor.setDx1(0);
|
||||
anchor.setDx2(pref.getDx2());
|
||||
|
||||
anchor.setRow2(row2);
|
||||
anchor.setDy1(0);
|
||||
anchor.setDy2(pref.getDy2());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the preferred size for this picture.
|
||||
*
|
||||
* @return XSSFClientAnchor with the preferred size for this image
|
||||
*/
|
||||
@Override
|
||||
public XSSFClientAnchor getPreferredSize(){
|
||||
return getPreferredSize(1.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the preferred size for this picture.
|
||||
*
|
||||
* @param scale the amount by which image dimensions are multiplied relative to the original size.
|
||||
* @return XSSFClientAnchor with the preferred size for this image
|
||||
*/
|
||||
public XSSFClientAnchor getPreferredSize(double scale){
|
||||
XSSFClientAnchor anchor = getAnchor();
|
||||
|
||||
XSSFPictureData data = getPictureData();
|
||||
Dimension size = getImageDimension(data.getPackagePart(), data.getPictureType());
|
||||
double scaledWidth = size.getWidth() * scale;
|
||||
double scaledHeight = size.getHeight() * scale;
|
||||
|
||||
float w = 0;
|
||||
int col2 = anchor.getCol1();
|
||||
int dx2 = 0;
|
||||
|
||||
for (;;) {
|
||||
w += getColumnWidthInPixels(col2);
|
||||
if(w > scaledWidth) break;
|
||||
col2++;
|
||||
}
|
||||
|
||||
if(w > scaledWidth) {
|
||||
double cw = getColumnWidthInPixels(col2 );
|
||||
double delta = w - scaledWidth;
|
||||
dx2 = (int)(XSSFShape.EMU_PER_PIXEL * (cw - delta));
|
||||
}
|
||||
anchor.setCol2(col2);
|
||||
anchor.setDx2(dx2);
|
||||
|
||||
double h = 0;
|
||||
int row2 = anchor.getRow1();
|
||||
int dy2 = 0;
|
||||
|
||||
for (;;) {
|
||||
h += getRowHeightInPixels(row2);
|
||||
if(h > scaledHeight) break;
|
||||
row2++;
|
||||
}
|
||||
|
||||
if(h > scaledHeight) {
|
||||
double ch = getRowHeightInPixels(row2);
|
||||
double delta = h - scaledHeight;
|
||||
dy2 = (int)(XSSFShape.EMU_PER_PIXEL * (ch - delta));
|
||||
}
|
||||
anchor.setRow2(row2);
|
||||
anchor.setDy2(dy2);
|
||||
|
||||
CTPositiveSize2D size2d = getCTPicture().getSpPr().getXfrm().getExt();
|
||||
size2d.setCx((long)(scaledWidth * XSSFShape.EMU_PER_PIXEL));
|
||||
size2d.setCy((long)(scaledHeight * XSSFShape.EMU_PER_PIXEL));
|
||||
|
||||
return anchor;
|
||||
}
|
||||
|
||||
private float getColumnWidthInPixels(int columnIndex){
|
||||
XSSFSheet sheet = getParent();
|
||||
|
||||
CTCol col = sheet.getColumnHelper().getColumn(columnIndex, false);
|
||||
double numChars = col == null || !col.isSetWidth() ? DEFAULT_COLUMN_WIDTH : col.getWidth();
|
||||
|
||||
return (float)numChars*XSSFWorkbook.DEFAULT_CHARACTER_WIDTH;
|
||||
}
|
||||
|
||||
private float getRowHeightInPixels(int rowIndex) {
|
||||
// THE FOLLOWING THREE LINES ARE THE MAIN CHANGE compared to the non-streaming version: use the SXSSF sheet,
|
||||
// not the XSSF sheet (which never contais rows when using SXSSF)
|
||||
XSSFSheet xssfSheet = getParent();
|
||||
SXSSFSheet sheet = _wb.getSXSSFSheet(xssfSheet);
|
||||
Row row = sheet.getRow(rowIndex);
|
||||
float height = row != null ? row.getHeightInPoints() : sheet.getDefaultRowHeightInPoints();
|
||||
return height * XSSFShape.PIXEL_DPI / XSSFShape.POINT_DPI;
|
||||
}
|
||||
/**
|
||||
* Return the dimension of this image
|
||||
*
|
||||
* @param part the package part holding raw picture data
|
||||
* @param type type of the picture: {@link Workbook#PICTURE_TYPE_JPEG},
|
||||
* {@link Workbook#PICTURE_TYPE_PNG} or {@link Workbook#PICTURE_TYPE_DIB}
|
||||
*
|
||||
* @return image dimension in pixels
|
||||
*/
|
||||
protected static Dimension getImageDimension(PackagePart part, int type){
|
||||
try {
|
||||
return ImageUtils.getImageDimension(part.getInputStream(), type);
|
||||
} catch (IOException e){
|
||||
//return a "singulariry" if ImageIO failed to read the image
|
||||
logger.log(POILogger.WARN, e);
|
||||
return new Dimension();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return picture data for this shape
|
||||
*
|
||||
* @return picture data for this shape
|
||||
*/
|
||||
@Override
|
||||
public XSSFPictureData getPictureData() {
|
||||
return _picture.getPictureData();
|
||||
}
|
||||
|
||||
protected CTShapeProperties getShapeProperties(){
|
||||
return getCTPicture().getSpPr();
|
||||
}
|
||||
|
||||
private XSSFSheet getParent() {
|
||||
return (XSSFSheet)_picture.getDrawing().getParent();
|
||||
}
|
||||
|
||||
private XSSFClientAnchor getAnchor() {
|
||||
return (XSSFClientAnchor)_picture.getAnchor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(double scaleX, double scaleY) {
|
||||
_picture.resize(scaleX, scaleY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XSSFClientAnchor getPreferredSize(double scaleX, double scaleY) {
|
||||
return _picture.getPreferredSize(scaleX, scaleY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getImageDimension() {
|
||||
return _picture.getImageDimension();
|
||||
}
|
||||
|
||||
@Override
|
||||
public XSSFClientAnchor getClientAnchor() {
|
||||
XSSFAnchor a = getAnchor();
|
||||
return (a instanceof XSSFClientAnchor) ? (XSSFClientAnchor)a : null;
|
||||
}
|
||||
|
||||
public XSSFDrawing getDrawing() {
|
||||
return _picture.getDrawing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public XSSFSheet getSheet() {
|
||||
return _picture.getSheet();
|
||||
}
|
||||
}
|
|
@ -1704,7 +1704,7 @@ public class SXSSFSheet implements Sheet
|
|||
@Override
|
||||
public Drawing createDrawingPatriarch()
|
||||
{
|
||||
return _sh.createDrawingPatriarch();
|
||||
return new SXSSFDrawing((SXSSFWorkbook)getWorkbook(), _sh.createDrawingPatriarch());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ import org.apache.poi.util.IOUtils;
|
|||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.RecordFormatException;
|
||||
import org.apache.poi.util.TempFile;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
|
@ -1315,4 +1316,12 @@ public final class TestHSSFWorkbook extends BaseTestWorkbook {
|
|||
assertEquals(3, wb.getNumberOfSheets());
|
||||
wb.close();
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
@Override
|
||||
public void createDrawing() throws Exception {
|
||||
super.createDrawing();
|
||||
// the dimensions for this image are different than for XSSF and SXSSF
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,15 +26,19 @@ import static org.junit.Assert.assertSame;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.apache.poi.POIDataSamples;
|
||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.ss.ITestDataProvider;
|
||||
import org.apache.poi.ss.usermodel.ClientAnchor.AnchorType;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.util.NullOutputStream;
|
||||
import org.apache.poi.util.TempFile;
|
||||
import org.junit.Test;
|
||||
|
||||
public abstract class BaseTestWorkbook {
|
||||
|
@ -895,5 +899,59 @@ public abstract class BaseTestWorkbook {
|
|||
|
||||
wb.close();
|
||||
}
|
||||
|
||||
// bug 51233 and 55075: correctly size image if added to a row with a custom height
|
||||
@Test
|
||||
public void createDrawing() throws Exception {
|
||||
Workbook wb = _testDataProvider.createWorkbook();
|
||||
Sheet sheet = wb.createSheet("Main Sheet");
|
||||
Row row0 = sheet.createRow(0);
|
||||
Row row1 = sheet.createRow(1);
|
||||
Cell cell = row1.createCell(0);
|
||||
row0.createCell(1);
|
||||
row1.createCell(0);
|
||||
row1.createCell(1);
|
||||
|
||||
byte[] pictureData = _testDataProvider.getTestDataFileContent("logoKarmokar4.png");
|
||||
|
||||
int handle = wb.addPicture(pictureData, Workbook.PICTURE_TYPE_PNG);
|
||||
Drawing drawing = sheet.createDrawingPatriarch();
|
||||
CreationHelper helper = wb.getCreationHelper();
|
||||
ClientAnchor anchor = helper.createClientAnchor();
|
||||
anchor.setAnchorType(AnchorType.DONT_MOVE_AND_RESIZE);
|
||||
anchor.setCol1(0);
|
||||
anchor.setRow1(0);
|
||||
Picture picture = drawing.createPicture(anchor, handle);
|
||||
|
||||
row0.setHeightInPoints(144);
|
||||
// set a column width so that XSSF and SXSSF have the same width (default widths may be different otherwise)
|
||||
sheet.setColumnWidth(0, 100*256);
|
||||
picture.resize();
|
||||
|
||||
// The actual dimensions don't matter as much as having XSSF and SXSSF produce the same size drawings
|
||||
|
||||
// Check drawing height
|
||||
assertEquals(0, anchor.getRow1());
|
||||
assertEquals(0, anchor.getRow2());
|
||||
assertEquals(0, anchor.getDy1());
|
||||
assertEquals(1609725, anchor.getDy2()); //HSSF: 225
|
||||
|
||||
// Check drawing width
|
||||
assertEquals(0, anchor.getCol1());
|
||||
assertEquals(0, anchor.getCol2());
|
||||
assertEquals(0, anchor.getDx1());
|
||||
assertEquals(1114425, anchor.getDx2()); //HSSF: 171
|
||||
|
||||
final boolean writeOut = false;
|
||||
if (writeOut) {
|
||||
String ext = "." + _testDataProvider.getStandardFileNameExtension();
|
||||
String prefix = wb.getClass().getName() + "-createDrawing";
|
||||
File f = TempFile.createTempFile(prefix, ext);
|
||||
FileOutputStream out = new FileOutputStream(f);
|
||||
wb.write(out);
|
||||
out.close();
|
||||
}
|
||||
wb.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue