Line 0
Link Here
|
|
|
1 |
/* ==================================================================== |
2 |
Licensed to the Apache Software Foundation (ASF) under one or more |
3 |
contributor license agreements. See the NOTICE file distributed with |
4 |
this work for additional information regarding copyright ownership. |
5 |
The ASF licenses this file to You under the Apache License, Version 2.0 |
6 |
(the "License"); you may not use this file except in compliance with |
7 |
the License. You may obtain a copy of the License at |
8 |
|
9 |
http://www.apache.org/licenses/LICENSE-2.0 |
10 |
|
11 |
Unless required by applicable law or agreed to in writing, software |
12 |
distributed under the License is distributed on an "AS IS" BASIS, |
13 |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 |
See the License for the specific language governing permissions and |
15 |
limitations under the License. |
16 |
==================================================================== */ |
17 |
|
18 |
package org.apache.poi.xssf.streaming; |
19 |
|
20 |
import org.apache.poi.openxml4j.opc.PackagePart; |
21 |
import org.apache.poi.ss.usermodel.Picture; |
22 |
import org.apache.poi.ss.usermodel.Row; |
23 |
import org.apache.poi.ss.usermodel.Workbook; |
24 |
import org.apache.poi.ss.util.ImageUtils; |
25 |
import org.apache.poi.util.Internal; |
26 |
import org.apache.poi.util.POILogFactory; |
27 |
import org.apache.poi.util.POILogger; |
28 |
import org.apache.poi.xssf.usermodel.*; |
29 |
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D; |
30 |
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties; |
31 |
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTPicture; |
32 |
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol; |
33 |
|
34 |
import java.awt.*; |
35 |
import java.io.IOException; |
36 |
|
37 |
/** |
38 |
* Streaming version of Picture. |
39 |
* Most of the code is a copy of the non-streaming XSSFPicture code. |
40 |
* 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. |
41 |
* |
42 |
* 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. |
43 |
* |
44 |
* @author: Frank Plößel, Beyond Data GmbH |
45 |
*/ |
46 |
public final class SXSSFPicture implements Picture { |
47 |
private static final POILogger logger = POILogFactory.getLogger(SXSSFPicture.class); |
48 |
/** |
49 |
* Column width measured as the number of characters of the maximum digit width of the |
50 |
* numbers 0, 1, 2, ..., 9 as rendered in the normal style's font. There are 4 pixels of margin |
51 |
* padding (two on each side), plus 1 pixel padding for the gridlines. |
52 |
* |
53 |
* This value is the same for default font in Office 2007 (Calibry) and Office 2003 and earlier (Arial) |
54 |
*/ |
55 |
private static float DEFAULT_COLUMN_WIDTH = 9.140625f; |
56 |
|
57 |
private final SXSSFWorkbook _wb; |
58 |
private final XSSFPicture _picture; |
59 |
|
60 |
SXSSFPicture(SXSSFWorkbook _wb, XSSFPicture _picture) { |
61 |
this._wb = _wb; |
62 |
this._picture = _picture; |
63 |
} |
64 |
|
65 |
/** |
66 |
* Return the underlying CTPicture bean that holds all properties for this picture |
67 |
* |
68 |
* @return the underlying CTPicture bean |
69 |
*/ |
70 |
@Internal |
71 |
public CTPicture getCTPicture(){ |
72 |
return _picture.getCTPicture(); |
73 |
} |
74 |
|
75 |
/** |
76 |
* Reset the image to the original size. |
77 |
* |
78 |
* <p> |
79 |
* Please note, that this method works correctly only for workbooks |
80 |
* with the default font size (Calibri 11pt for .xlsx). |
81 |
* If the default font is changed the resized image can be streched vertically or horizontally. |
82 |
* </p> |
83 |
*/ |
84 |
public void resize(){ |
85 |
resize(1.0); |
86 |
} |
87 |
|
88 |
/** |
89 |
* Reset the image to the original size. |
90 |
* <p> |
91 |
* Please note, that this method works correctly only for workbooks |
92 |
* with the default font size (Calibri 11pt for .xlsx). |
93 |
* If the default font is changed the resized image can be streched vertically or horizontally. |
94 |
* </p> |
95 |
* |
96 |
* @param scale the amount by which image dimensions are multiplied relative to the original size. |
97 |
* <code>resize(1.0)</code> sets the original size, <code>resize(0.5)</code> resize to 50% of the original, |
98 |
* <code>resize(2.0)</code> resizes to 200% of the original. |
99 |
*/ |
100 |
public void resize(double scale){ |
101 |
XSSFClientAnchor anchor = getAnchor(); |
102 |
|
103 |
XSSFClientAnchor pref = getPreferredSize(scale); |
104 |
|
105 |
int row2 = anchor.getRow1() + (pref.getRow2() - pref.getRow1()); |
106 |
int col2 = anchor.getCol1() + (pref.getCol2() - pref.getCol1()); |
107 |
|
108 |
anchor.setCol2(col2); |
109 |
anchor.setDx1(0); |
110 |
anchor.setDx2(pref.getDx2()); |
111 |
|
112 |
anchor.setRow2(row2); |
113 |
anchor.setDy1(0); |
114 |
anchor.setDy2(pref.getDy2()); |
115 |
} |
116 |
|
117 |
/** |
118 |
* Calculate the preferred size for this picture. |
119 |
* |
120 |
* @return XSSFClientAnchor with the preferred size for this image |
121 |
*/ |
122 |
public XSSFClientAnchor getPreferredSize(){ |
123 |
return getPreferredSize(1); |
124 |
} |
125 |
|
126 |
/** |
127 |
* Calculate the preferred size for this picture. |
128 |
* |
129 |
* @param scale the amount by which image dimensions are multiplied relative to the original size. |
130 |
* @return XSSFClientAnchor with the preferred size for this image |
131 |
*/ |
132 |
public XSSFClientAnchor getPreferredSize(double scale){ |
133 |
XSSFClientAnchor anchor = getAnchor(); |
134 |
|
135 |
XSSFPictureData data = getPictureData(); |
136 |
Dimension size = getImageDimension(data.getPackagePart(), data.getPictureType()); |
137 |
double scaledWidth = size.getWidth() * scale; |
138 |
double scaledHeight = size.getHeight() * scale; |
139 |
|
140 |
float w = 0; |
141 |
int col2 = anchor.getCol1(); |
142 |
int dx2 = 0; |
143 |
|
144 |
for (;;) { |
145 |
w += getColumnWidthInPixels(col2); |
146 |
if(w > scaledWidth) break; |
147 |
col2++; |
148 |
} |
149 |
|
150 |
if(w > scaledWidth) { |
151 |
double cw = getColumnWidthInPixels(col2 ); |
152 |
double delta = w - scaledWidth; |
153 |
dx2 = (int)(XSSFShape.EMU_PER_PIXEL * (cw - delta)); |
154 |
} |
155 |
anchor.setCol2(col2); |
156 |
anchor.setDx2(dx2); |
157 |
|
158 |
double h = 0; |
159 |
int row2 = anchor.getRow1(); |
160 |
int dy2 = 0; |
161 |
|
162 |
for (;;) { |
163 |
h += getRowHeightInPixels(row2); |
164 |
if(h > scaledHeight) break; |
165 |
row2++; |
166 |
} |
167 |
|
168 |
if(h > scaledHeight) { |
169 |
double ch = getRowHeightInPixels(row2); |
170 |
double delta = h - scaledHeight; |
171 |
dy2 = (int)(XSSFShape.EMU_PER_PIXEL * (ch - delta)); |
172 |
} |
173 |
anchor.setRow2(row2); |
174 |
anchor.setDy2(dy2); |
175 |
|
176 |
CTPositiveSize2D size2d = getCTPicture().getSpPr().getXfrm().getExt(); |
177 |
size2d.setCx((long)(scaledWidth * XSSFShape.EMU_PER_PIXEL)); |
178 |
size2d.setCy((long)(scaledHeight * XSSFShape.EMU_PER_PIXEL)); |
179 |
|
180 |
return anchor; |
181 |
} |
182 |
|
183 |
private float getColumnWidthInPixels(int columnIndex){ |
184 |
XSSFSheet sheet = getParent(); |
185 |
|
186 |
CTCol col = sheet.getColumnHelper().getColumn(columnIndex, false); |
187 |
double numChars = col == null || !col.isSetWidth() ? DEFAULT_COLUMN_WIDTH : col.getWidth(); |
188 |
|
189 |
return (float)numChars*XSSFWorkbook.DEFAULT_CHARACTER_WIDTH; |
190 |
} |
191 |
|
192 |
private float getRowHeightInPixels(int rowIndex) { |
193 |
// THE FOLLOWING THREE LINES ARE THE MAIN CHANGE compared to the non-streaming version: use the SXSSF sheet, |
194 |
// not the XSSF sheet (which never contais rows when using SXSSF) |
195 |
XSSFSheet xssfSheet = getParent(); |
196 |
SXSSFSheet sheet = _wb.getSXSSFSheet(xssfSheet); |
197 |
Row row = sheet.getRow(rowIndex); |
198 |
float height = row != null ? row.getHeightInPoints() : sheet.getDefaultRowHeightInPoints(); |
199 |
return height * XSSFShape.PIXEL_DPI / XSSFShape.POINT_DPI; |
200 |
} |
201 |
/** |
202 |
* Return the dimension of this image |
203 |
* |
204 |
* @param part the package part holding raw picture data |
205 |
* @param type type of the picture: {@link Workbook#PICTURE_TYPE_JPEG}, |
206 |
* {@link Workbook#PICTURE_TYPE_PNG} or {@link Workbook#PICTURE_TYPE_DIB} |
207 |
* |
208 |
* @return image dimension in pixels |
209 |
*/ |
210 |
protected static Dimension getImageDimension(PackagePart part, int type){ |
211 |
try { |
212 |
return ImageUtils.getImageDimension(part.getInputStream(), type); |
213 |
} catch (IOException e){ |
214 |
//return a "singulariry" if ImageIO failed to read the image |
215 |
logger.log(POILogger.WARN, e); |
216 |
return new Dimension(); |
217 |
} |
218 |
} |
219 |
|
220 |
/** |
221 |
* Return picture data for this shape |
222 |
* |
223 |
* @return picture data for this shape |
224 |
*/ |
225 |
public XSSFPictureData getPictureData() { |
226 |
return _picture.getPictureData(); |
227 |
} |
228 |
|
229 |
protected CTShapeProperties getShapeProperties(){ |
230 |
return getCTPicture().getSpPr(); |
231 |
} |
232 |
|
233 |
private XSSFSheet getParent() { |
234 |
return (XSSFSheet)_picture.getDrawing().getParent(); |
235 |
} |
236 |
|
237 |
private XSSFClientAnchor getAnchor() { |
238 |
return (XSSFClientAnchor)_picture.getAnchor(); |
239 |
} |
240 |
} |
241 |
native |