Initial support for SpreadsheetML drawings,implemented XSSFPicture, added ability to add pictures to workbook, refactored XSSFPictureData to be a subclass of POIXMLDocumentPart. Also refactored misc odds and ends in order to produce xml better compatible with what MS Office produces

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@703490 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yegor Kozlov 2008-10-10 14:54:32 +00:00
parent 91d6061c07
commit b4e74b306c
24 changed files with 1713 additions and 182 deletions

View File

@ -672,7 +672,7 @@ public interface Sheet extends Iterable<Row> {
*
* @return The new patriarch.
*/
Patriarch createDrawingPatriarch();
//Patriarch createDrawingPatriarch();
/**
* Expands or collapses a column group.

View File

@ -43,6 +43,7 @@ public class POIXMLDocumentPart {
DEFAULT_XML_OPTIONS = new XmlOptions();
DEFAULT_XML_OPTIONS.setSaveOuter();
DEFAULT_XML_OPTIONS.setUseDefaultNamespace();
DEFAULT_XML_OPTIONS.setSaveAggressiveNamespaces();
}
protected PackagePart packagePart;
@ -158,16 +159,30 @@ public class POIXMLDocumentPart {
* @return the created child POIXMLDocumentPart
*/
protected POIXMLDocumentPart createRelationship(POIXMLRelation descriptor, Class<? extends POIXMLDocumentPart> cls, int idx){
return createRelationship(descriptor, cls, idx, false);
}
/**
* Create a new child POIXMLDocumentPart
*
* @param descriptor the part descriptor
* @param cls the Class object identifying the type of instance to create
* @param idx part number
* @param norel if true, then no relationship is added.
* @return the created child POIXMLDocumentPart
*/
protected POIXMLDocumentPart createRelationship(POIXMLRelation descriptor, Class<? extends POIXMLDocumentPart> cls, int idx, boolean norel){
try {
PackagePartName ppName = PackagingURIHelper.createPartName(descriptor.getFileName(idx));
PackageRelationship rel =
packagePart.addRelationship(ppName, TargetMode.INTERNAL, descriptor.getRelation());
PackageRelationship rel = null;
if(!norel) rel = packagePart.addRelationship(ppName, TargetMode.INTERNAL, descriptor.getRelation());
PackagePart part = packagePart.getPackage().createPart(ppName, descriptor.getContentType());
POIXMLDocumentPart doc = cls.newInstance();
doc.packageRel = rel;
doc.packagePart = part;
doc.parent = this;
addRelation(doc);
return doc;
} catch (Exception e){

View File

@ -23,22 +23,64 @@ package org.apache.poi;
*/
public class POIXMLRelation {
/**
* Describes the content stored in a part.
*/
protected String _type;
/**
* The kind of connection between a source part and a target part in a package.
*/
protected String _relation;
/**
* The path component of a pack URI.
*/
protected String _defaultName;
/**
* Instantiates a POIXMLRelation.
*
* @param type content type
* @param rel relationship
* @param defaultName default item name
*/
protected POIXMLRelation(String type, String rel, String defaultName) {
public POIXMLRelation(String type, String rel, String defaultName) {
_type = type;
_relation = rel;
_defaultName = defaultName;
}
public String getContentType() { return _type; }
public String getRelation() { return _relation; }
public String getDefaultFileName() { return _defaultName; }
/**
* Return the content type. Content types define a media type, a subtype, and an
* optional set of parameters, as defined in RFC 2616.
*
* @return the content type
*/
public String getContentType() {
return _type;
}
/**
* Return the relationship, the kind of connection between a source part and a target part in a package.
* Relationships make the connections between parts directly discoverable without looking at the content
* in the parts, and without altering the parts themselves.
*
* @return the relationship
*/
public String getRelation() {
return _relation;
}
/**
* Return the default part name. Part names are used to refer to a part in the context of a
* package, typically as part of a URI.
*
* @return the default part name
*/
public String getDefaultFileName() {
return _defaultName;
}
/**
* Returns the filename for the nth one of these,

View File

@ -31,7 +31,6 @@ public class XSSFSave {
for (int i = 0; i < args.length; i++) {
XSSFWorkbook wb = new XSSFWorkbook(args[i]);
System.out.println("wb.getNumberOfSheets(): " + wb.getNumberOfSheets());
int sep = args[i].lastIndexOf('.');
String outfile = args[i].substring(0, sep) + "-save.xlsx";
FileOutputStream out = new FileOutputStream(outfile);

View File

@ -16,7 +16,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDrawing;
* A drawing object in XSSF. May well have raw pictures
* attached to it as children.
*/
public class Drawing implements XSSFChildContainingModel {
public class Drawing implements XSSFModel {
private CTDrawing drawing;
private String originalId;
@ -77,20 +77,11 @@ public class Drawing implements XSSFChildContainingModel {
* Generates and adds XSSFActiveXData children
*/
public void generateChild(PackagePart childPart, String childRelId) {
XSSFPictureData pd = new XSSFPictureData(childPart, childRelId);
pictures.add(pd);
}
//XSSFPictureData pd = new XSSFPictureData(childPart, childRelId);
//pictures.add(pd);
throw new RuntimeException("deprecated");
}
public WritableChild getChildForWriting(int index) {
if(index >= pictures.size()) {
throw new IllegalArgumentException("Can't get child at " + index + " when size is " + getNumberOfChildren());
}
return new WritableChild(
pictures.get(index),
XSSFRelation.IMAGES
);
}
public ArrayList<XSSFPictureData> getPictures()
{
return this.pictures;

View File

@ -198,9 +198,7 @@ public class SharedStringsTable extends POIXMLDocumentPart implements XSSFModel,
* @throws IOException if an error occurs while writing.
*/
public void writeTo(OutputStream out) throws IOException {
XmlOptions options = new XmlOptions();
options.setSaveOuter();
options.setUseDefaultNamespace();
XmlOptions options = new XmlOptions(DEFAULT_XML_OPTIONS);
//re-create the sst table every time saving a workbook
SstDocument doc = SstDocument.Factory.newInstance();

View File

@ -330,13 +330,7 @@ public class StylesTable extends POIXMLDocumentPart implements StylesSource, XSS
* @throws IOException if an error occurs while writing.
*/
public void writeTo(OutputStream out) throws IOException {
XmlOptions options = new XmlOptions();
options.setSaveOuter();
options.setUseDefaultNamespace();
// Requests use of whitespace for easier reading
options.setSavePrettyPrint();
XmlOptions options = new XmlOptions(DEFAULT_XML_OPTIONS);
// Work on the current one
// Need to do this, as we don't handle

View File

@ -0,0 +1,212 @@
/* ====================================================================
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.usermodel;
/**
* All know type of automatic shapes in DrawingML
*
* @author Yegor Kozlov
*/
public class ShapeTypes {
public static final int LINE = 1;
public static final int LINE_INV = 2;
public static final int TRIANGLE = 3;
public static final int RT_TRIANGLE = 4;
public static final int RECT = 5;
public static final int DIAMOND = 6;
public static final int PARALLELOGRAM = 7;
public static final int TRAPEZOID = 8;
public static final int NON_ISOSCELES_TRAPEZOID = 9;
public static final int PENTAGON = 10;
public static final int HEXAGON = 11;
public static final int HEPTAGON = 12;
public static final int OCTAGON = 13;
public static final int DECAGON = 14;
public static final int DODECAGON = 15;
public static final int STAR_4 = 16;
public static final int STAR_5 = 17;
public static final int STAR_6 = 18;
public static final int STAR_7 = 19;
public static final int STAR_8 = 20;
public static final int STAR_10 = 21;
public static final int STAR_12 = 22;
public static final int STAR_16 = 23;
public static final int STAR_24 = 24;
public static final int STAR_32 = 25;
public static final int ROUND_RECT = 26;
public static final int ROUND_1_RECT = 27;
public static final int ROUND_2_SAME_RECT = 28;
public static final int ROUND_2_DIAG_RECT = 29;
public static final int SNIP_ROUND_RECT = 30;
public static final int SNIP_1_RECT = 31;
public static final int SNIP_2_SAME_RECT = 32;
public static final int SNIP_2_DIAG_RECT = 33;
public static final int PLAQUE = 34;
public static final int ELLIPSE = 35;
public static final int TEARDROP = 36;
public static final int HOME_PLATE = 37;
public static final int CHEVRON = 38;
public static final int PIE_WEDGE = 39;
public static final int PIE = 40;
public static final int BLOCK_ARC = 41;
public static final int DONUT = 42;
public static final int NO_SMOKING = 43;
public static final int RIGHT_ARROW = 44;
public static final int LEFT_ARROW = 45;
public static final int UP_ARROW = 46;
public static final int DOWN_ARROW = 47;
public static final int STRIPED_RIGHT_ARROW = 48;
public static final int NOTCHED_RIGHT_ARROW = 49;
public static final int BENT_UP_ARROW = 50;
public static final int LEFT_RIGHT_ARROW = 51;
public static final int UP_DOWN_ARROW = 52;
public static final int LEFT_UP_ARROW = 53;
public static final int LEFT_RIGHT_UP_ARROW = 54;
public static final int QUAD_ARROW = 55;
public static final int LEFT_ARROW_CALLOUT = 56;
public static final int RIGHT_ARROW_CALLOUT = 57;
public static final int UP_ARROW_CALLOUT = 58;
public static final int DOWN_ARROW_CALLOUT = 59;
public static final int LEFT_RIGHT_ARROW_CALLOUT = 60;
public static final int UP_DOWN_ARROW_CALLOUT = 61;
public static final int QUAD_ARROW_CALLOUT = 62;
public static final int BENT_ARROW = 63;
public static final int UTURN_ARROW = 64;
public static final int CIRCULAR_ARROW = 65;
public static final int LEFT_CIRCULAR_ARROW = 66;
public static final int LEFT_RIGHT_CIRCULAR_ARROW = 67;
public static final int CURVED_RIGHT_ARROW = 68;
public static final int CURVED_LEFT_ARROW = 69;
public static final int CURVED_UP_ARROW = 70;
public static final int CURVED_DOWN_ARROW = 71;
public static final int SWOOSH_ARROW = 72;
public static final int CUBE = 73;
public static final int CAN = 74;
public static final int LIGHTNING_BOLT = 75;
public static final int HEART = 76;
public static final int SUN = 77;
public static final int MOON = 78;
public static final int SMILEY_FACE = 79;
public static final int IRREGULAR_SEAL_1 = 80;
public static final int IRREGULAR_SEAL_2 = 81;
public static final int FOLDED_CORNER = 82;
public static final int BEVEL = 83;
public static final int FRAME = 84;
public static final int HALF_FRAME = 85;
public static final int CORNER = 86;
public static final int DIAG_STRIPE = 87;
public static final int CHORD = 88;
public static final int ARC = 89;
public static final int LEFT_BRACKET = 90;
public static final int RIGHT_BRACKET = 91;
public static final int LEFT_BRACE = 92;
public static final int RIGHT_BRACE = 93;
public static final int BRACKET_PAIR = 94;
public static final int BRACE_PAIR = 95;
public static final int STRAIGHT_CONNECTOR_1 = 96;
public static final int BENT_CONNECTOR_2 = 97;
public static final int BENT_CONNECTOR_3 = 98;
public static final int BENT_CONNECTOR_4 = 99;
public static final int BENT_CONNECTOR_5 = 100;
public static final int CURVED_CONNECTOR_2 = 101;
public static final int CURVED_CONNECTOR_3 = 102;
public static final int CURVED_CONNECTOR_4 = 103;
public static final int CURVED_CONNECTOR_5 = 104;
public static final int CALLOUT_1 = 105;
public static final int CALLOUT_2 = 106;
public static final int CALLOUT_3 = 107;
public static final int ACCENT_CALLOUT_1 = 108;
public static final int ACCENT_CALLOUT_2 = 109;
public static final int ACCENT_CALLOUT_3 = 110;
public static final int BORDER_CALLOUT_1 = 111;
public static final int BORDER_CALLOUT_2 = 112;
public static final int BORDER_CALLOUT_3 = 113;
public static final int ACCENT_BORDER_CALLOUT_1 = 114;
public static final int ACCENT_BORDER_CALLOUT_2 = 115;
public static final int ACCENT_BORDER_CALLOUT_3 = 116;
public static final int WEDGE_RECT_CALLOUT = 117;
public static final int WEDGE_ROUND_RECT_CALLOUT = 118;
public static final int WEDGE_ELLIPSE_CALLOUT = 119;
public static final int CLOUD_CALLOUT = 120;
public static final int CLOUD = 121;
public static final int RIBBON = 122;
public static final int RIBBON_2 = 123;
public static final int ELLIPSE_RIBBON = 124;
public static final int ELLIPSE_RIBBON_2 = 125;
public static final int LEFT_RIGHT_RIBBON = 126;
public static final int VERTICAL_SCROLL = 127;
public static final int HORIZONTAL_SCROLL = 128;
public static final int WAVE = 129;
public static final int DOUBLE_WAVE = 130;
public static final int PLUS = 131;
public static final int FLOW_CHART_PROCESS = 132;
public static final int FLOW_CHART_DECISION = 133;
public static final int FLOW_CHART_INPUT_OUTPUT = 134;
public static final int FLOW_CHART_PREDEFINED_PROCESS = 135;
public static final int FLOW_CHART_INTERNAL_STORAGE = 136;
public static final int FLOW_CHART_DOCUMENT = 137;
public static final int FLOW_CHART_MULTIDOCUMENT = 138;
public static final int FLOW_CHART_TERMINATOR = 139;
public static final int FLOW_CHART_PREPARATION = 140;
public static final int FLOW_CHART_MANUAL_INPUT = 141;
public static final int FLOW_CHART_MANUAL_OPERATION = 142;
public static final int FLOW_CHART_CONNECTOR = 143;
public static final int FLOW_CHART_PUNCHED_CARD = 144;
public static final int FLOW_CHART_PUNCHED_TAPE = 145;
public static final int FLOW_CHART_SUMMING_JUNCTION = 146;
public static final int FLOW_CHART_OR = 147;
public static final int FLOW_CHART_COLLATE = 148;
public static final int FLOW_CHART_SORT = 149;
public static final int FLOW_CHART_EXTRACT = 150;
public static final int FLOW_CHART_MERGE = 151;
public static final int FLOW_CHART_OFFLINE_STORAGE = 152;
public static final int FLOW_CHART_ONLINE_STORAGE = 153;
public static final int FLOW_CHART_MAGNETIC_TAPE = 154;
public static final int FLOW_CHART_MAGNETIC_DISK = 155;
public static final int FLOW_CHART_MAGNETIC_DRUM = 156;
public static final int FLOW_CHART_DISPLAY = 157;
public static final int FLOW_CHART_DELAY = 158;
public static final int FLOW_CHART_ALTERNATE_PROCESS = 159;
public static final int FLOW_CHART_OFFPAGE_CONNECTOR = 160;
public static final int ACTION_BUTTON_BLANK = 161;
public static final int ACTION_BUTTON_HOME = 162;
public static final int ACTION_BUTTON_HELP = 163;
public static final int ACTION_BUTTON_INFORMATION = 164;
public static final int ACTION_BUTTON_FORWARD_NEXT = 165;
public static final int ACTION_BUTTON_BACK_PREVIOUS = 166;
public static final int ACTION_BUTTON_END = 167;
public static final int ACTION_BUTTON_BEGINNING = 168;
public static final int ACTION_BUTTON_RETURN = 169;
public static final int ACTION_BUTTON_DOCUMENT = 170;
public static final int ACTION_BUTTON_SOUND = 171;
public static final int ACTION_BUTTON_MOVIE = 172;
public static final int GEAR_6 = 173;
public static final int GEAR_9 = 174;
public static final int FUNNEL = 175;
public static final int MATH_PLUS = 176;
public static final int MATH_MINUS = 177;
public static final int MATH_MULTIPLY = 178;
public static final int MATH_DIVIDE = 179;
public static final int MATH_EQUAL = 180;
public static final int MATH_NOT_EQUAL = 181;
public static final int CORNER_TABS = 182;
public static final int SQUARE_TABS = 183;
public static final int PLAQUE_TABS = 184;
public static final int CHART_X = 185;
public static final int CHART_STAR = 186;
public static final int CHART_PLUS = 187;
}

View File

@ -0,0 +1,187 @@
/* ====================================================================
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.usermodel;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
/**
* A client anchor is attached to an excel worksheet. It anchors against
* top-left and buttom-right cells.
*
* @author Yegor Kozlov
*/
public class XSSFClientAnchor {
/**
* Starting anchor point
*/
private CTMarker cell1;
/**
* Ending anchor point
*/
private CTMarker cell2;
/**
* Creates a new client anchor and defaults all the anchor positions to 0.
*/
public XSSFClientAnchor() {
cell1 = CTMarker.Factory.newInstance();
cell1.setCol(0);
cell1.setColOff(0);
cell1.setRow(0);
cell1.setRowOff(0);
cell2 = CTMarker.Factory.newInstance();
cell2.setCol(0);
cell2.setColOff(0);
cell2.setRow(0);
cell2.setRowOff(0);
}
/**
* Creates a new client anchor and sets the top-left and bottom-right
* coordinates of the anchor.
*
* @param dx1 the x coordinate within the first cell.
* @param dy1 the y coordinate within the first cell.
* @param dx2 the x coordinate within the second cell.
* @param dy2 the y coordinate within the second cell.
* @param col1 the column (0 based) of the first cell.
* @param row1 the row (0 based) of the first cell.
* @param col2 the column (0 based) of the second cell.
* @param row2 the row (0 based) of the second cell.
*/
public XSSFClientAnchor(int dx1, int dy1, int dx2, int dy2, int col1, int row1, int col2, int row2) {
this();
cell1.setCol(col1);
cell1.setColOff(dx1);
cell1.setRow(row1);
cell1.setRowOff(dy1);
cell2.setCol(col2);
cell2.setColOff(dx2);
cell2.setRow(row2);
cell2.setRowOff(dy2);
}
/**
* Create XSSFClientAnchor from existing xml beans
*
* @param cell1 starting anchor point
* @param cell2 ending anchor point
*/
protected XSSFClientAnchor(CTMarker cell1, CTMarker cell2) {
this.cell1 = cell1;
this.cell2 = cell2;
}
public int getCol1() {
return cell1.getCol();
}
public void setCol1(short col1) {
cell1.setCol(col1);
}
public int getCol2() {
return cell2.getCol();
}
public void setCol2(short col2) {
cell2.setCol(col2);
}
public int getRow1() {
return cell1.getRow();
}
public void setRow1(int row1) {
cell1.setRow(row1);
}
public int getRow2() {
return cell2.getRow();
}
public void setRow2(int row2) {
cell2.setRow(row2);
}
public int getDx1() {
return (int)cell1.getColOff();
}
public void setDx1(int dx1) {
cell1.setColOff(dx1);
}
public int getDy1() {
return (int)cell1.getRowOff();
}
public void setDy1(int dy1) {
cell1.setRowOff(dy1);
}
public int getDy2() {
return (int)cell2.getRowOff();
}
public void setDy2(int dy2) {
cell2.setRowOff(dy2);
}
public int getDx2() {
return (int)cell2.getColOff();
}
public void setDx2(int dx2) {
cell2.setColOff(dx2);
}
@Override
public boolean equals(Object o) {
if (o == null || !(o instanceof XSSFClientAnchor)) return false;
XSSFClientAnchor anchor = (XSSFClientAnchor) o;
return cell1.toString().equals(anchor.getFrom().toString()) &&
cell2.toString().equals(anchor.getTo().toString()) ;
}
@Override
public String toString(){
return "from : " + cell1.toString() + "; to: " + cell2.toString();
}
/**
* Return starting anchor point
*
* @return starting anchor point
*/
public CTMarker getFrom(){
return cell1;
}
/**
* Return ending anchor point
*
* @return ending anchor point
*/
public CTMarker getTo(){
return cell2;
}
}

View File

@ -0,0 +1,155 @@
/* ====================================================================
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.usermodel;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions;
import org.openxml4j.opc.*;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.STEditAs;
import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
import javax.xml.namespace.QName;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.HashMap;
/**
* Represents a SpreadsheetML drawing
*
* @author Yegor Kozlov
*/
public class XSSFDrawing extends POIXMLDocumentPart {
/**
* Root element of the SpreadsheetML Drawing part
*/
private CTDrawing drawing;
/**
* Create a new SpreadsheetML drawing
*
* @see org.apache.poi.xssf.usermodel.XSSFWorksheet#createDrawingPatriarch()
*/
public XSSFDrawing() {
super(null, null);
drawing = newDrawing();
}
/**
* Construct a SpreadsheetML drawing from a package part
*
* @param part the package part holding the drawing data,
* the content type must be <code>application/vnd.openxmlformats-officedocument.drawing+xml</code>
* @param rel the package relationship holding this drawing,
* the relationship type must be http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing
*/
public XSSFDrawing(PackagePart part, PackageRelationship rel) throws IOException, XmlException {
super(part, rel);
drawing = CTDrawing.Factory.parse(part.getInputStream());
}
/**
* Construct a new CTDrawing bean. By default, it's just an empty placeholder for drawing objects
*
* @return a new CTDrawing bean
*/
private static CTDrawing newDrawing(){
return CTDrawing.Factory.newInstance();
}
/**
* Return the underlying CTDrawing bean, the root element of the SpreadsheetML Drawing part.
*
* @return the underlying CTDrawing bean
*/
public CTDrawing getCTDrawing(){
return drawing;
}
@Override
protected void commit() throws IOException {
XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
/*
Saved drawings must have the following namespaces set:
<xdr:wsDr
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing">
*/
xmlOptions.setSaveSyntheticDocumentElement(new QName(CTDrawing.type.getName().getNamespaceURI(), "wsDr", "xdr"));
Map map = new HashMap();
map.put("http://schemas.openxmlformats.org/drawingml/2006/main", "a");
map.put(STRelationshipId.type.getName().getNamespaceURI(), "r");
xmlOptions.setSaveSuggestedPrefixes(map);
PackagePart part = getPackagePart();
OutputStream out = part.getOutputStream();
drawing.save(out, xmlOptions);
out.close();
}
/**
* Creates a picture.
*
* @param anchor the client anchor describes how this picture is attached to the sheet.
* @param pictureIndex the index of the picture in the workbook collection of pictures,
* {@link org.apache.poi.xssf.usermodel.XSSFWorkbook#getAllPictures()} .
*
* @return the newly created picture shape.
*/
public XSSFPicture createPicture(XSSFClientAnchor anchor, int pictureIndex)
{
XSSFWorkbook wb = (XSSFWorkbook)getParent().getParent();
XSSFPictureData data = wb.getAllPictures().get(pictureIndex);
PackagePartName ppName = data.getPackagePart().getPartName();
PackageRelationship rel = packagePart.addRelationship(ppName, TargetMode.INTERNAL, XSSFRelation.IMAGES.getRelation());
addRelation(new XSSFPictureData(data.getPackagePart(), rel));
CTTwoCellAnchor ctAnchor = createTwoCellAnchor(anchor);
return new XSSFPicture(this, rel, ctAnchor);
}
/**
* Creates a simple shape. This includes such shapes as lines, rectangles,
* and ovals.
*
* @param anchor the client anchor describes how this group is attached
* to the sheet.
* @return the newly created shape.
*/
public XSSFSimpleShape createSimpleShape(XSSFClientAnchor anchor)
{
CTTwoCellAnchor ctAnchor = createTwoCellAnchor(anchor);
return new XSSFSimpleShape(this, ctAnchor);
}
/**
* Create and initialize a CTTwoCellAnchor that anchors a shape against top-left and bottom-right cells.
*
* @return a new CTTwoCellAnchor
*/
private CTTwoCellAnchor createTwoCellAnchor(XSSFClientAnchor anchor){
CTTwoCellAnchor ctAnchor = drawing.addNewTwoCellAnchor();
ctAnchor.setEditAs(STEditAs.ONE_CELL);
ctAnchor.setFrom(anchor.getFrom());
ctAnchor.setTo(anchor.getTo());
ctAnchor.addNewClientData();
return ctAnchor;
}
}

View File

@ -41,6 +41,8 @@ public class XSSFFactory extends POIXMLFactory {
parts.put(XSSFRelation.SHARED_STRINGS.getRelation(), SharedStringsTable.class);
parts.put(XSSFRelation.STYLES.getRelation(), StylesTable.class);
parts.put(XSSFRelation.SHEET_COMMENTS.getRelation(), CommentsTable.class);
parts.put(XSSFRelation.DRAWINGS.getRelation(), XSSFDrawing.class);
parts.put(XSSFRelation.IMAGES.getRelation(), XSSFPictureData.class);
}
public POIXMLDocumentPart create(PackageRelationship rel, PackagePart p){

View File

@ -0,0 +1,325 @@
/* ====================================================================
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.usermodel;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.*;
import org.openxmlformats.schemas.drawingml.x2006.main.*;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.POIXMLDocumentPart;
import org.openxml4j.opc.PackageRelationship;
import org.openxml4j.opc.PackagePart;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Iterator;
/**
* Represents a picture shape in a SpreadsheetML drawing.
*
* @author Yegor Kozlov
*/
public class XSSFPicture extends XSSFShape {
private static final POILogger logger = POILogFactory.getLogger(XSSFPicture.class);
/**
* width of 1px in columns with default width
*/
private static final float PX_DEFAULT = 0.125f;
/**
* width of 1px in columns with overridden width
*/
private static final float PX_MODIFIED = 0.143f;
/**
* Height of 1px of a row
*/
private static final int PX_ROW = 15;
/**
* This object specifies a picture object and all its properties
*/
private CTPicture ctPicture;
/**
* Construct a new XSSFPicture object. This constructor is called from
* {@link XSSFDrawing#createPicture(XSSFClientAnchor, int)}
*
* @param parent the XSSFDrawing that owns this picture
* @param rel the relationship to the picture data
* @param anchor the two cell anchor placeholder for this picture,
* this object encloses the CTPicture bean that holds all the picture properties
*/
protected XSSFPicture(XSSFDrawing parent, PackageRelationship rel, CTTwoCellAnchor anchor){
super(parent, anchor);
//Create a new picture and attach it to the specified two-cell anchor
ctPicture = newPicture(rel);
anchor.setPic(ctPicture);
}
/**
* Create a new CTPicture bean and initialize its required attributes
*
* @param rel the relationship to the picture data
* @return a new CTPicture bean
*/
private static CTPicture newPicture(PackageRelationship rel){
CTPicture pic = CTPicture.Factory.newInstance();
CTPictureNonVisual nvpr = pic.addNewNvPicPr();
CTNonVisualDrawingProps nvProps = nvpr.addNewCNvPr();
//YK: TODO shape IDs must be unique across workbook
int shapeId = 1;
nvProps.setId(shapeId);
nvProps.setName("Picture " + shapeId);
nvProps.setDescr(rel.getTargetURI().toString());
CTNonVisualPictureProperties nvPicProps = nvpr.addNewCNvPicPr();
nvPicProps.addNewPicLocks().setNoChangeAspect(true);
CTBlipFillProperties blip = pic.addNewBlipFill();
blip.addNewBlip().setEmbed(rel.getId());
blip.addNewStretch().addNewFillRect();
CTShapeProperties sppr = pic.addNewSpPr();
CTTransform2D t2d = sppr.addNewXfrm();
CTPositiveSize2D ext = t2d.addNewExt();
//should be original picture width and height expressed in EMUs
ext.setCx(0);
ext.setCy(0);
CTPoint2D off = t2d.addNewOff();
off.setX(0);
off.setY(0);
CTPresetGeometry2D prstGeom = sppr.addNewPrstGeom();
prstGeom.setPrst(STShapeType.RECT);
prstGeom.addNewAvLst();
return pic;
}
/**
* Return the underlying CTPicture bean that holds all properties for this picture
*
* @return the underlying CTPicture bean
*/
public CTPicture getCTPicture(){
return ctPicture;
}
/**
* Reset the image to the original size.
*/
public void resize(){
XSSFClientAnchor anchor = getAnchor();
XSSFClientAnchor pref = getPreferredSize();
int row2 = anchor.getRow1() + (pref.getRow2() - pref.getRow1());
int col2 = anchor.getCol1() + (pref.getCol2() - pref.getCol1());
anchor.setCol2((short)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
*/
public XSSFClientAnchor getPreferredSize(){
XSSFClientAnchor anchor = getAnchor();
XSSFPictureData data = getPictureData();
Dimension size = getImageDimension(data.getPackagePart(), data.getPictureType());
float w = 0;
//space in the leftmost cell
w += anchor.getDx1()/EMU_PER_POINT;
short col2 = (short)(anchor.getCol1() + 1);
int dx2 = 0;
while(w < size.width){
w += getColumnWidthInPixels(col2++);
}
if(w > size.width) {
//calculate dx2, offset in the rightmost cell
col2--;
float cw = getColumnWidthInPixels(col2);
float delta = w - size.width;
dx2 = (int)(EMU_PER_POINT*(cw-delta));
}
anchor.setCol2(col2);
anchor.setDx2(dx2);
float h = 0;
h += (1 - anchor.getDy1()/256)* getRowHeightInPixels(anchor.getRow1());
int row2 = anchor.getRow1() + 1;
int dy2 = 0;
while(h < size.height){
h += getRowHeightInPixels(row2++);
}
if(h > size.height) {
row2--;
float ch = getRowHeightInPixels(row2);
float delta = h - size.height;
dy2 = (int)((ch-delta)/ch*256);
}
anchor.setRow2(row2);
anchor.setDy2(dy2);
return anchor;
}
private float getColumnWidthInPixels(int column){
XSSFSheet sheet = (XSSFSheet)getDrawing().getParent();
int cw = sheet.getColumnWidth(column);
float px = getPixelWidth(column);
return cw/px;
}
private float getRowHeightInPixels(int i){
XSSFSheet sheet = (XSSFSheet)getDrawing().getParent();
XSSFRow row = sheet.getRow(i);
float height;
if(row != null) height = row.getHeight();
else height = sheet.getDefaultRowHeight();
return height/PX_ROW;
}
private float getPixelWidth(int column){
XSSFSheet sheet = (XSSFSheet)getDrawing().getParent();
int def = sheet.getDefaultColumnWidth();
int cw = sheet.getColumnWidth(column);
return cw == def ? PX_DEFAULT : PX_MODIFIED;
}
/**
* 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, Workbook#PICTURE_TYPE_PNG or Workbook#PICTURE_TYPE_DIB)
*
* @return image dimension in pixels
*/
protected static Dimension getImageDimension(PackagePart part, int type){
Dimension size = new Dimension();
switch (type){
//we can calculate the preferred size only for JPEG and PNG
//other formats like WMF, EMF and PICT are not supported in Java
case Workbook.PICTURE_TYPE_JPEG:
case Workbook.PICTURE_TYPE_PNG:
case Workbook.PICTURE_TYPE_DIB:
try {
//read the image using javax.imageio.*
ImageInputStream iis = ImageIO.createImageInputStream( part.getInputStream() );
Iterator i = ImageIO.getImageReaders( iis );
ImageReader r = (ImageReader) i.next();
r.setInput( iis );
BufferedImage img = r.read(0);
int[] dpi = getResolution(r);
//if DPI is zero then assume standard 96 DPI
//since cannot divide by zero
if (dpi[0] == 0) dpi[0] = 96;
if (dpi[1] == 0) dpi[1] = 96;
size.width = img.getWidth()*96/dpi[0];
size.height = img.getHeight()*96/dpi[1];
} catch (IOException e){
//silently return if ImageIO failed to read the image
logger.log(POILogger.WARN, e);
}
break;
default:
logger.log(POILogger.WARN, "Only JPEG, PNG and DIB pictures can be automatically sized");
}
return size;
}
/**
* The metadata of PNG and JPEG can contain the width of a pixel in millimeters.
* Return the the "effective" dpi calculated as <code>25.4/HorizontalPixelSize</code>
* and <code>25.4/VerticalPixelSize</code>. Where 25.4 is the number of mm in inch.
*
* @return array of two elements: <code>{horisontalPdi, verticalDpi}</code>.
* {96, 96} is the default.
*/
protected static int[] getResolution(ImageReader r) throws IOException {
int hdpi=96, vdpi=96;
double mm2inch = 25.4;
NodeList lst;
Element node = (Element)r.getImageMetadata(0).getAsTree("javax_imageio_1.0");
lst = node.getElementsByTagName("HorizontalPixelSize");
if(lst != null && lst.getLength() == 1) hdpi = (int)(mm2inch/Float.parseFloat(((Element)lst.item(0)).getAttribute("value")));
lst = node.getElementsByTagName("VerticalPixelSize");
if(lst != null && lst.getLength() == 1) vdpi = (int)(mm2inch/Float.parseFloat(((Element)lst.item(0)).getAttribute("value")));
return new int[]{hdpi, vdpi};
}
/**
* return the anchor that is used by this shape.
*
* @return the anchor that is used by this shape.
*/
public XSSFClientAnchor getAnchor(){
CTTwoCellAnchor ctAnchor = (CTTwoCellAnchor)getShapeContainer();
return new XSSFClientAnchor(ctAnchor.getFrom(), ctAnchor.getTo());
}
/**
* Return picture data for this shape
*
* @return picture data for this shape
*/
public XSSFPictureData getPictureData() {
String blipId = ctPicture.getBlipFill().getBlip().getEmbed();
for (POIXMLDocumentPart part : getDrawing().getRelations()) {
if(part.getPackageRelationship().getId().equals(blipId)){
return (XSSFPictureData)part;
}
}
logger.log(POILogger.WARN, "Picture data was not found for blipId=" + blipId);
return null;
}
}

View File

@ -18,51 +18,105 @@
package org.apache.poi.xssf.usermodel;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.poi.ss.usermodel.PictureData;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.model.XSSFWritableModel;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLException;
import org.apache.poi.POIXMLRelation;
import org.openxml4j.opc.PackagePart;
import org.openxml4j.opc.PackageRelationship;
/**
* Raw picture data, normally attached to a
* vmlDrawing
* Raw picture data, normally attached to a SpreadsheetML Drawing.
* As a rule, pictures are stored in the /xl/media/ part of a SpreadsheetML package.
*/
public class XSSFPictureData implements PictureData, XSSFWritableModel {
private PackagePart packagePart;
private String originalId;
public class XSSFPictureData extends POIXMLDocumentPart implements PictureData {
public XSSFPictureData(PackagePart packagePart, String originalId) {
this(packagePart);
this.originalId = originalId;
}
public XSSFPictureData(PackagePart packagePart) {
this.packagePart = packagePart;
/**
* Relationships for each known picture type
*/
protected static final POIXMLRelation[] RELATIONS;
static {
RELATIONS = new POIXMLRelation[8];
RELATIONS[Workbook.PICTURE_TYPE_EMF] = new POIXMLRelation("image/x-emf", XSSFRelation.IMAGES.getRelation(), "/xl/media/image#.emf");
RELATIONS[Workbook.PICTURE_TYPE_WMF] = new POIXMLRelation("image/x-wmf", XSSFRelation.IMAGES.getRelation(), "/xl/media/image#.wmf");
RELATIONS[Workbook.PICTURE_TYPE_PICT] = new POIXMLRelation("image/pict", XSSFRelation.IMAGES.getRelation(), "/xl/media/image#.pict");
RELATIONS[Workbook.PICTURE_TYPE_JPEG] = new POIXMLRelation("image/jpeg", XSSFRelation.IMAGES.getRelation(), "/xl/media/image#.jpeg");
RELATIONS[Workbook.PICTURE_TYPE_PNG] = new POIXMLRelation("image/png", XSSFRelation.IMAGES.getRelation(), "/xl/media/image#.png");
RELATIONS[Workbook.PICTURE_TYPE_DIB] = new POIXMLRelation("image/dib", XSSFRelation.IMAGES.getRelation(), "/xl/media/image#.dib");
}
public String getOriginalId() {
return originalId;
/**
* Create a new XSSFPictureData node
*
* @see org.apache.poi.xssf.usermodel.XSSFWorkbook#addPicture(byte[], int)
*/
public XSSFPictureData() {
super(null, null);
}
protected PackagePart getPart() {
return packagePart;
}
public void writeTo(OutputStream out) throws IOException {
IOUtils.copy(packagePart.getInputStream(), out);
}
/**
* Construct XSSFPictureData from a package part
*
* @param part the package part holding the drawing data,
* @param rel the package relationship holding this drawing,
* the relationship type must be http://schemas.openxmlformats.org/officeDocument/2006/relationships/image
*/
public XSSFPictureData(PackagePart part, PackageRelationship rel) {
super(part, rel);
}
/**
* Gets the picture data as a byte array.
* <p>
* Note, that this call might be expensive since all the picture data is copied into a temporary byte array.
* You can grab the picture data directly from the underlying package part as follows:
* <br/>
* <code>
* InputStream is = getPackagePart().getInputStream();
* </code>
* </p>
*
* @return the picture data.
*/
public byte[] getData() {
try {
return IOUtils.toByteArray(packagePart.getInputStream());
} catch(IOException e) {
throw new RuntimeException(e);
}
try {
return IOUtils.toByteArray(getPackagePart().getInputStream());
} catch(IOException e) {
throw new POIXMLException(e);
}
}
/**
* Suggests a file extension for this image.
*
* @return the file extension.
*/
public String suggestFileExtension() {
return packagePart.getPartName().getExtension();
return getPackagePart().getPartName().getExtension();
}
/**
* Return an integer constant that specifies type of this picture
*
* @return an integer constant that specifies type of this picture
* @see Workbook#PICTURE_TYPE_EMF
* @see Workbook#PICTURE_TYPE_WMF
* @see Workbook#PICTURE_TYPE_PICT
* @see Workbook#PICTURE_TYPE_JPEG
* @see Workbook#PICTURE_TYPE_PNG
* @see Workbook#PICTURE_TYPE_DIB
*/
public int getPictureType(){
String contentType = getPackagePart().getContentType();
for (int i = 0; i < RELATIONS.length; i++) {
if(RELATIONS[i] == null) continue;
if(RELATIONS[i].getContentType().equals(contentType)){
return i;
}
}
return 0;
}
}

View File

@ -83,7 +83,7 @@ public final class XSSFRelation<W extends XSSFModel> extends POIXMLRelation {
StylesTable.class
);
public static final XSSFRelation DRAWINGS = new XSSFRelation(
"application/vnd.openxmlformats-officedocument.drawingml.chart+xml",
"application/vnd.openxmlformats-officedocument.drawing+xml",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing",
"/xl/drawings/drawing#.xml",
null
@ -95,9 +95,10 @@ public final class XSSFRelation<W extends XSSFModel> extends POIXMLRelation {
Drawing.class
);
public static final XSSFRelation IMAGES = new XSSFRelation(
"image/x-emf", // TODO
//client will substitute $type and $ext with the appropriate values depending on the passed data
"image/$type",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
"/xl/media/image#.emf",
"/xl/media/image#.$ext",
null
);
public static final XSSFRelation<CommentsTable> SHEET_COMMENTS = create(

View File

@ -0,0 +1,93 @@
/* ====================================================================
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.usermodel;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTAbsoluteAnchor;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTOneCellAnchor;
import org.openxmlformats.schemas.drawingml.x2006.chartDrawing.CTGroupShape;
/**
* Represents a shape in a SpreadsheetML drawing.
*
* @author Yegor Kozlov
*/
public abstract class XSSFShape {
public static final int EMU_PER_POINT = 12700;
/**
* Shape container. Can be CTTwoCellAnchor, CTOneCellAnchor, CTAbsoluteAnchor or CTGroupShape
*/
private XmlObject spContainer;
/**
* Parent drawing
*/
private XSSFDrawing drawing;
/**
* The parent shape, always not-null for shapes in groups
*/
private XSSFShape parent;
/**
* Construct a new XSSFSimpleShape object.
*
* @param parent the XSSFDrawing that owns this shape
* @param anchor an object that encloses the shape bean,
* can be CTTwoCellAnchor, CTOneCellAnchor, CTAbsoluteAnchor or CTGroupShape
*/
protected XSSFShape(XSSFDrawing parent, XmlObject anchor){
drawing = parent;
if(!(anchor instanceof CTTwoCellAnchor) && !(anchor instanceof CTOneCellAnchor) &&
!(anchor instanceof CTAbsoluteAnchor) && !(anchor instanceof CTGroupShape)) {
throw new IllegalArgumentException("anchor must be one of the following types: " +
"CTTwoCellAnchor, CTOneCellAnchor, CTAbsoluteAnchor or CTGroupShape");
}
spContainer = anchor;
}
/**
* Return the anchor bean that encloses this shape.
* Can be CTTwoCellAnchor, CTOneCellAnchor, CTAbsoluteAnchor or CTGroupShape.
*
* @return the anchor bean that encloses this shape
*/
public XmlObject getShapeContainer(){
return spContainer;
}
/**
* Return the drawing that owns this shape
*
* @return the parent drawing that owns this shape
*/
public XSSFDrawing getDrawing(){
return drawing;
}
/**
* Gets the parent shape.
*/
public XSSFShape getParent()
{
return parent;
}
}

View File

@ -19,11 +19,7 @@ package org.apache.poi.xssf.usermodel;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.*;
import javax.xml.namespace.QName;
import org.apache.poi.hssf.util.PaneInformation;
@ -31,7 +27,6 @@ import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CommentsSource;
import org.apache.poi.ss.usermodel.Footer;
import org.apache.poi.ss.usermodel.Header;
import org.apache.poi.ss.usermodel.Patriarch;
import org.apache.poi.ss.usermodel.PrintSetup;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
@ -40,16 +35,18 @@ import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.util.Region;
import org.apache.poi.xssf.model.CommentsTable;
import org.apache.poi.xssf.model.Control;
import org.apache.poi.xssf.model.Drawing;
import org.apache.poi.xssf.usermodel.helpers.ColumnHelper;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLException;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.POILogFactory;
import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.XmlException;
import org.openxml4j.opc.PackagePart;
import org.openxml4j.opc.PackageRelationship;
import org.openxml4j.opc.PackageRelationshipCollection;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
/**
@ -62,6 +59,8 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
* </p>
*/
public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
private static POILogger logger = POILogFactory.getLogger(XSSFSheet.class);
protected CTSheet sheet;
protected CTWorksheet worksheet;
protected CTDialogsheet dialogsheet;
@ -72,7 +71,6 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
protected CTMergeCells ctMergeCells;
protected List<Drawing> drawings;
protected List<Control> controls;
@ -149,7 +147,6 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
ctFormat.setDefaultRowHeight(15.0);
CTSheetView ctView = worksheet.addNewSheetViews().addNewSheetView();
ctView.setTabSelected(true);
ctView.setWorkbookViewId(0);
worksheet.addNewDimension().setRef("A1");
@ -167,11 +164,6 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
return worksheet;
}
public List<Drawing> getDrawings()
{
return drawings;
}
public List<Control> getControls()
{
return controls;
@ -263,9 +255,42 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
columnHelper.setColBestFit(column, true);
}
public Patriarch createDrawingPatriarch() {
// TODO Auto-generated method stub
return null;
/**
* Create a new SpreadsheetML drawing. If this sheet already contains a drawing - return that.
*
* @return a SpreadsheetML drawing
*/
public XSSFDrawing createDrawingPatriarch() {
XSSFDrawing drawing = null;
CTDrawing ctDrawing = worksheet.getDrawing();
if(ctDrawing == null) {
//drawingNumber = #drawings.size() + 1
int drawingNumber = getPackagePart().getPackage().getPartsByRelationshipType(XSSFRelation.DRAWINGS.getRelation()).size() + 1;
drawing = (XSSFDrawing)createRelationship(XSSFRelation.DRAWINGS, XSSFDrawing.class, drawingNumber);
String relId = drawing.getPackageRelationship().getId();
//add CT_Drawing element which indicates that this sheet contains drawing components built on the drawingML platform.
//The relationship Id references the part containing the drawingML definitions.
ctDrawing = worksheet.addNewDrawing();
ctDrawing.setId(relId);
} else {
//search the referenced drawing in the list of the sheet's relations
for(POIXMLDocumentPart p : getRelations()){
if(p instanceof XSSFDrawing) {
XSSFDrawing dr = (XSSFDrawing)p;
String drId = dr.getPackageRelationship().getId();
if(drId.equals(ctDrawing.getId())){
drawing = dr;
break;
}
break;
}
}
if(drawing == null){
logger.log(POILogger.ERROR, "Can't find drawing with id=" + ctDrawing.getId() + " in the list of the sheet's relationships");
}
}
return drawing;
}
/**
@ -406,14 +431,16 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
}
public int getColumnWidth(int columnIndex) {
return (int) columnHelper.getColumn(columnIndex, false).getWidth();
CTCol col = columnHelper.getColumn(columnIndex, false);
return col == null ? getDefaultColumnWidth() : (int)col.getWidth();
}
public short getColumnWidth(short column) {
return (short) getColumnWidth(column & 0xFFFF);
}
public int getDefaultColumnWidth() {
return (int)getSheetTypeSheetFormatPr().getDefaultColWidth();
CTSheetFormatPr pr = getSheetTypeSheetFormatPr();
return pr.isSetDefaultColWidth() ? (int)pr.getDefaultColWidth() : (int)pr.getBaseColWidth();
}
public short getDefaultRowHeight() {
@ -1570,14 +1597,15 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
xmlOptions.setSaveSyntheticDocumentElement(new QName(CTWorksheet.type.getName().getNamespaceURI(), "worksheet"));
Map map = new HashMap();
map.put(STRelationshipId.type.getName().getNamespaceURI(), "r");
xmlOptions.setSaveSuggestedPrefixes(map);
PackagePart part = getPackagePart();
OutputStream out = part.getOutputStream();
worksheet.save(out, xmlOptions);
out.close();
}
protected void setParent(POIXMLDocumentPart p){
this.parent = p;
}
}

View File

@ -0,0 +1,178 @@
/* ====================================================================
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.usermodel;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShape;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShapeNonVisual;
import org.openxmlformats.schemas.drawingml.x2006.main.*;
/**
* Represents an auto-shape in a SpreadsheetML drawing.
*
* @author Yegor Kozlov
*/
public class XSSFSimpleShape extends XSSFShape {
private CTShape ctShape;
/**
* Construct a new XSSFSimpleShape object.
*
* @param parent the XSSFDrawing that owns this shape
* @param anchor the two cell anchor placeholder for this shape,
* this object encloses the shape bean that holds all the shape properties
*/
protected XSSFSimpleShape(XSSFDrawing parent, CTTwoCellAnchor anchor) {
super(parent, anchor);
ctShape = anchor.addNewSp();
newShape(ctShape);
}
/**
* Initialize default structure of a new auto-shape
*
* @param shape newly created shape to initialize
*/
private static void newShape(CTShape shape) {
CTShapeNonVisual nv = shape.addNewNvSpPr();
CTNonVisualDrawingProps nvp = nv.addNewCNvPr();
int shapeId = 1;
nvp.setId(shapeId);
nvp.setName("Shape " + shapeId);
nv.addNewCNvSpPr();
CTShapeProperties sp = shape.addNewSpPr();
CTTransform2D t2d = sp.addNewXfrm();
CTPositiveSize2D p1 = t2d.addNewExt();
p1.setCx(0);
p1.setCy(0);
CTPoint2D p2 = t2d.addNewOff();
p2.setX(0);
p2.setY(0);
CTPresetGeometry2D geom = sp.addNewPrstGeom();
geom.setPrst(STShapeType.RECT);
geom.addNewAvLst();
CTShapeStyle style = shape.addNewStyle();
CTSchemeColor scheme = style.addNewLnRef().addNewSchemeClr();
scheme.setVal(STSchemeColorVal.ACCENT_1);
scheme.addNewShade().setVal(50000);
style.getLnRef().setIdx(2);
CTStyleMatrixReference fillref = style.addNewFillRef();
fillref.setIdx(1);
fillref.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_1);
CTStyleMatrixReference effectRef = style.addNewEffectRef();
effectRef.setIdx(0);
effectRef.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_1);
CTFontReference fontRef = style.addNewFontRef();
fontRef.setIdx(STFontCollectionIndex.MINOR);
fontRef.addNewSchemeClr().setVal(STSchemeColorVal.LT_1);
CTTextBody body = shape.addNewTxBody();
CTTextBodyProperties bodypr = body.addNewBodyPr();
bodypr.setAnchor(STTextAnchoringType.CTR);
bodypr.setRtlCol(false);
CTTextParagraph p = body.addNewP();
p.addNewPPr().setAlgn(STTextAlignType.CTR);
body.addNewLstStyle();
}
/**
* Gets the shape type, one of the constants defined in {@link ShapeTypes}.
*
* @return the shape type
* @see ShapeTypes
*/
public int getShapeType() {
return ctShape.getSpPr().getPrstGeom().getPrst().intValue();
}
/**
* Sets the shape types.
*
* @param type the shape type, one of the constants defined in {@link ShapeTypes}.
* @see ShapeTypes
*/
public void setShapeType(int type) {
ctShape.getSpPr().getPrstGeom().setPrst(STShapeType.Enum.forInt(type));
}
/**
* Whether this shape is not filled with a color
*
* @return true if this shape is not filled with a color.
*/
public boolean isNoFill() {
return ctShape.getSpPr().isSetNoFill();
}
/**
* Sets whether this shape is filled or transparent.
*
* @param noFill if true then no fill will be applied to the shape element.
*/
public void setNoFill(boolean noFill) {
CTShapeProperties props = ctShape.getSpPr();
//unset solid and pattern fills if they are set
if (props.isSetPattFill()) props.unsetPattFill();
if (props.isSetSolidFill()) props.unsetSolidFill();
props.setNoFill(CTNoFillProperties.Factory.newInstance());
}
/**
* Sets the color used to fill this shape using the solid fill pattern.
*/
public void setFillColor(int red, int green, int blue) {
CTShapeProperties props = ctShape.getSpPr();
CTSolidColorFillProperties fill = props.isSetSolidFill() ? props.getSolidFill() : props.addNewSolidFill();
CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();
rgb.setVal(new byte[]{(byte)red, (byte)green, (byte)blue});
fill.setSrgbClr(rgb);
}
/**
* The color applied to the lines of this shape.
*/
public void setLineStyleColor( int red, int green, int blue ) {
CTShapeProperties props = ctShape.getSpPr();
CTLineProperties ln = props.isSetLn() ? props.getLn() : props.addNewLn();
CTSolidColorFillProperties fill = ln.isSetSolidFill() ? ln.getSolidFill() : ln.addNewSolidFill();
CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();
rgb.setVal(new byte[]{(byte)red, (byte)green, (byte)blue});
fill.setSrgbClr(rgb);
}
/**
* Specifies the width to be used for the underline stroke.
*
* @param lineWidth width in points
*/
public void setLineWidth( double lineWidth ) {
CTShapeProperties props = ctShape.getSpPr();
CTLineProperties ln = props.isSetLn() ? props.getLn() : props.addNewLn();
ln.setW((int)(lineWidth*EMU_PER_POINT));
}
}

View File

@ -19,10 +19,9 @@ package org.apache.poi.xssf.usermodel;
import java.io.IOException;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.HashMap;
import java.util.Iterator;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.util.*;
import javax.xml.namespace.QName;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.POIXMLDocumentPart;
@ -35,6 +34,7 @@ import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.PackageHelper;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.model.*;
import org.apache.poi.POIXMLException;
import org.apache.xmlbeans.XmlObject;
@ -44,6 +44,7 @@ import org.openxml4j.exceptions.OpenXML4JException;
import org.openxml4j.opc.*;
import org.openxml4j.opc.Package;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
/**
* High level representation of a SpreadsheetML workbook. This is the first object most users
@ -93,6 +94,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
*/
private MissingCellPolicy missingCellPolicy = Row.RETURN_NULL_AND_BLANK;
/**
* array of pictures for this workbook
*/
private List<XSSFPictureData> pictures;
private static POILogger log = POILogFactory.getLogger(XSSFWorkbook.class);
/**
@ -250,9 +256,33 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
return this.workbook;
}
/**
* Adds a picture to the workbook.
*
* @param pictureData The bytes of the picture
* @param format The format of the picture.
*
* @return the index to this picture (0 based), the added picture can be obtained from {@link #getAllPictures()} .
* @see #PICTURE_TYPE_EMF
* @see #PICTURE_TYPE_WMF
* @see #PICTURE_TYPE_PICT
* @see #PICTURE_TYPE_JPEG
* @see #PICTURE_TYPE_PNG
* @see #PICTURE_TYPE_DIB
* @see #getAllPictures()
*/
public int addPicture(byte[] pictureData, int format) {
// TODO Auto-generated method stub
return 0;
int imageNumber = getAllPictures().size() + 1;
XSSFPictureData img = (XSSFPictureData)createRelationship(XSSFPictureData.RELATIONS[format], XSSFPictureData.class, imageNumber, true);
try {
OutputStream out = img.getPackagePart().getOutputStream();
out.write(pictureData);
out.close();
} catch (IOException e){
throw new POIXMLException(e);
}
pictures.add(img);
return imageNumber - 1;
}
public XSSFSheet cloneSheet(int sheetNum) {
@ -363,13 +393,12 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
int sheetNumber = getNumberOfSheets() + 1;
XSSFSheet wrapper = (XSSFSheet)createRelationship(XSSFRelation.WORKSHEET, XSSFSheet.class, sheetNumber);
wrapper.setParent(this);
CTSheet sheet = addSheet(sheetname);
wrapper.sheet = sheet;
sheet.setId(wrapper.getPackageRelationship().getId());
sheet.setSheetId(sheetNumber);
if(sheets.size() == 0) wrapper.setSelected(true);
this.sheets.add(wrapper);
return wrapper;
}
@ -438,27 +467,21 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
*
* @return the list of pictures (a list of {@link XSSFPictureData} objects.)
*/
public List<PictureData> getAllPictures() {
// In OOXML pictures are referred to in sheets
List<PictureData> pictures = new LinkedList<PictureData>();
for(POIXMLDocumentPart p : getRelations()){
if (p instanceof XSSFSheet) {
PackagePart sheetPart = p.getPackagePart();
try {
PackageRelationshipCollection prc = sheetPart.getRelationshipsByType(XSSFRelation.DRAWINGS.getRelation());
for (PackageRelationship rel : prc) {
PackagePart drawingPart = getTargetPart(rel);
PackageRelationshipCollection prc2 = drawingPart.getRelationshipsByType(XSSFRelation.IMAGES.getRelation());
for (PackageRelationship rel2 : prc2) {
PackagePart imagePart = getTargetPart(rel2);
XSSFPictureData pd = new XSSFPictureData(imagePart);
pictures.add(pd);
public List<XSSFPictureData> getAllPictures() {
if(pictures == null) {
//In OOXML pictures are referred to in sheets,
//dive into sheet's relations, select drawings and their images
pictures = new ArrayList();
for(XSSFSheet sh : sheets){
for(POIXMLDocumentPart dr : sh.getRelations()){
if(dr instanceof XSSFDrawing){
for(POIXMLDocumentPart img : dr.getRelations()){
if(img instanceof XSSFPictureData){
pictures.add((XSSFPictureData)img);
}
}
}
} catch (InvalidFormatException e) {
throw new POIXMLException(e.getMessage(), e);
}
}
}
return pictures;
@ -705,7 +728,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
*/
public void removeSheetAt(int index) {
validateSheetIndex(index);
this.sheets.remove(index);
this.workbook.getSheets().removeSheet(index);
}
@ -878,6 +901,10 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
xmlOptions.setSaveSyntheticDocumentElement(new QName(CTWorkbook.type.getName().getNamespaceURI(), "workbook"));
Map map = new HashMap();
map.put(STRelationshipId.type.getName().getNamespaceURI(), "r");
xmlOptions.setSaveSuggestedPrefixes(map);
PackagePart part = getPackagePart();
OutputStream out = part.getOutputStream();
workbook.save(out, xmlOptions);

View File

@ -28,6 +28,7 @@ import org.apache.poi.ss.usermodel.PictureData;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFPictureData;
public class TestLoadSaveXSSF extends TestCase {
@ -42,7 +43,7 @@ public class TestLoadSaveXSSF extends TestCase {
filename = "src/ooxml/testcases/org/apache/poi/xssf/data";
}
}
public void testLoadSample() throws Exception {
XSSFWorkbook workbook = new XSSFWorkbook(new File(filename, "sample.xlsx").getAbsolutePath());
assertEquals(3, workbook.getNumberOfSheets());
@ -55,7 +56,7 @@ public class TestLoadSaveXSSF extends TestCase {
cell = row.getCell((short) 0);
assertEquals("Lorem", cell.getRichStringCellValue().getString());
}
// TODO filename string hard coded in XSSFWorkbook constructor in order to make ant test-ooxml target be successfull.
public void testLoadStyles() throws Exception {
XSSFWorkbook workbook = new XSSFWorkbook(new File(filename, "styles.xlsx").getAbsolutePath());
@ -69,7 +70,7 @@ public class TestLoadSaveXSSF extends TestCase {
// TODO filename string hard coded in XSSFWorkbook constructor in order to make ant test-ooxml target be successfull.
public void testLoadPictures() throws Exception {
XSSFWorkbook workbook = new XSSFWorkbook(new File(filename, "picture.xlsx").getAbsolutePath());
List<PictureData> pictures = workbook.getAllPictures();
List<XSSFPictureData> pictures = workbook.getAllPictures();
assertEquals(1, pictures.size());
}

View File

@ -0,0 +1,70 @@
/* ====================================================================
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.usermodel;
import junit.framework.TestCase;
import org.apache.poi.xssf.XSSFTestDataSamples;
import org.apache.poi.POIXMLDocumentPart;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing;
import java.util.List;
import java.io.IOException;
/**
* @author Yegor Kozlov
*/
public class TestXSSFDrawing extends TestCase {
public void testRead(){
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("WithDrawing.xlsx");
XSSFSheet sheet = wb.getSheetAt(0);
//the sheet has one relationship and it is XSSFDrawing
List<POIXMLDocumentPart> rels = sheet.getRelations();
assertEquals(1, rels.size());
assertTrue(rels.get(0) instanceof XSSFDrawing);
XSSFDrawing drawing = (XSSFDrawing)rels.get(0);
//sheet.createDrawingPatriarch() should return the same instance of XSSFDrawing
assertSame(drawing, sheet.createDrawingPatriarch());
String drawingId = drawing.getPackageRelationship().getId();
//there should be a relation to this drawing in the worksheet
assertTrue(sheet.getWorksheet().isSetDrawing());
assertEquals(drawingId, sheet.getWorksheet().getDrawing().getId());
}
public void testNew(){
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sheet = wb.createSheet();
//multiple calls of createDrawingPatriarch should return the same instance of XSSFDrawing
XSSFDrawing dr1 = sheet.createDrawingPatriarch();
XSSFDrawing dr2 = sheet.createDrawingPatriarch();
assertSame(dr1, dr2);
List<POIXMLDocumentPart> rels = sheet.getRelations();
assertEquals(1, rels.size());
assertTrue(rels.get(0) instanceof XSSFDrawing);
XSSFDrawing drawing = (XSSFDrawing)rels.get(0);
String drawingId = drawing.getPackageRelationship().getId();
//there should be a relation to this drawing in the worksheet
assertTrue(sheet.getWorksheet().isSetDrawing());
assertEquals(drawingId, sheet.getWorksheet().getDrawing().getId());
}
}

View File

@ -0,0 +1,55 @@
/* ====================================================================
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.usermodel;
import junit.framework.TestCase;
import org.apache.poi.xssf.XSSFTestDataSamples;
import org.apache.poi.POIXMLDocumentPart;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing;
import java.util.List;
import java.util.Arrays;
import java.io.IOException;
/**
* @author Yegor Kozlov
*/
public class TestXSSFPicture extends TestCase {
public void testCreate(){
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sheet = wb.createSheet();
XSSFDrawing drawing = sheet.createDrawingPatriarch();
byte[] jpegData = "test jpeg data".getBytes();
List<XSSFPictureData> pictures = wb.getAllPictures();
assertEquals(0, pictures.size());
int jpegIdx = wb.addPicture(jpegData, XSSFWorkbook.PICTURE_TYPE_JPEG);
assertEquals(1, pictures.size());
assertEquals("jpeg", pictures.get(jpegIdx).suggestFileExtension());
assertTrue(Arrays.equals(jpegData, pictures.get(jpegIdx).getData()));
XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, 1, 1, 10, 30);
XSSFPicture shape = drawing.createPicture(anchor, jpegIdx);
assertTrue(anchor.equals(shape.getAnchor()));
assertNotNull(shape.getPictureData());
assertTrue(Arrays.equals(jpegData, shape.getPictureData().getData()));
}
}

View File

@ -0,0 +1,104 @@
/* ====================================================================
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.usermodel;
import junit.framework.TestCase;
import org.apache.poi.xssf.XSSFTestDataSamples;
import org.apache.poi.POIXMLDocumentPart;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing;
import java.util.List;
import java.util.Arrays;
import java.io.IOException;
/**
* @author Yegor Kozlov
*/
public class TestXSSFPictureData extends TestCase {
public void testRead(){
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("WithDrawing.xlsx");
List<XSSFPictureData> pictures = wb.getAllPictures();
//wb.getAllPictures() should return the same instance across multiple calls
assertSame(pictures, wb.getAllPictures());
assertEquals(5, pictures.size());
String[] ext = {"jpeg", "emf", "png", "emf", "wmf"};
for (int i = 0; i < pictures.size(); i++) {
assertEquals(ext[i], pictures.get(i).suggestFileExtension());
}
int num = pictures.size();
byte[] pictureData = {0xA, 0xB, 0XC, 0xD, 0xE, 0xF};
int idx = wb.addPicture(pictureData, XSSFWorkbook.PICTURE_TYPE_JPEG);
assertEquals(num + 1, pictures.size());
//idx is 0-based index in the #pictures array
assertEquals(pictures.size() - 1, idx);
XSSFPictureData pict = pictures.get(idx);
assertEquals("jpeg", pict.suggestFileExtension());
assertTrue(Arrays.equals(pictureData, pict.getData()));
}
public void testNew(){
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sheet = wb.createSheet();
XSSFDrawing drawing = sheet.createDrawingPatriarch();
byte[] jpegData = "test jpeg data".getBytes();
byte[] wmfData = "test wmf data".getBytes();
byte[] pngData = "test png data".getBytes();
List<XSSFPictureData> pictures = wb.getAllPictures();
assertEquals(0, pictures.size());
int jpegIdx = wb.addPicture(jpegData, XSSFWorkbook.PICTURE_TYPE_JPEG);
assertEquals(1, pictures.size());
assertEquals("jpeg", pictures.get(jpegIdx).suggestFileExtension());
assertTrue(Arrays.equals(jpegData, pictures.get(jpegIdx).getData()));
int wmfIdx = wb.addPicture(wmfData, XSSFWorkbook.PICTURE_TYPE_WMF);
assertEquals(2, pictures.size());
assertEquals("wmf", pictures.get(wmfIdx).suggestFileExtension());
assertTrue(Arrays.equals(wmfData, pictures.get(wmfIdx).getData()));
int pngIdx = wb.addPicture(pngData, XSSFWorkbook.PICTURE_TYPE_PNG);
assertEquals(3, pictures.size());
assertEquals("png", pictures.get(pngIdx).suggestFileExtension());
assertTrue(Arrays.equals(pngData, pictures.get(pngIdx).getData()));
//TODO finish usermodel API for XSSFPicture
XSSFPicture p1 = drawing.createPicture(new XSSFClientAnchor(), jpegIdx);
XSSFPicture p2 = drawing.createPicture(new XSSFClientAnchor(), wmfIdx);
XSSFPicture p3 = drawing.createPicture(new XSSFClientAnchor(), pngIdx);
//check that the added pictures are accessible after write
wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
List<XSSFPictureData> pictures2 = wb.getAllPictures();
assertEquals(3, pictures2.size());
assertEquals("jpeg", pictures2.get(jpegIdx).suggestFileExtension());
assertTrue(Arrays.equals(jpegData, pictures2.get(jpegIdx).getData()));
assertEquals("wmf", pictures2.get(wmfIdx).suggestFileExtension());
assertTrue(Arrays.equals(wmfData, pictures2.get(wmfIdx).getData()));
assertEquals("png", pictures2.get(pngIdx).suggestFileExtension());
assertTrue(Arrays.equals(pngData, pictures2.get(pngIdx).getData()));
}
}

View File

@ -41,7 +41,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane;
public class TestXSSFSheet extends TestCase {
public void testRowIterator() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");
@ -55,7 +55,7 @@ public class TestXSSFSheet extends TestCase {
assertEquals(row2, it.next());
assertFalse(it.hasNext());
}
public void testGetRow() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");
@ -63,17 +63,17 @@ public class TestXSSFSheet extends TestCase {
Cell cell = row1.createCell((short) 0);
cell.setCellType(Cell.CELL_TYPE_NUMERIC);
cell.setCellValue((double) 1000);
// Test getting a row and check its cell's value
Row row_got = sheet.getRow(0);
Cell cell_got = row_got.getCell((short) 0);
assertEquals((double) 1000, cell_got.getNumericCellValue());
}
public void testCreateRow() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");
// Test row creation with consecutive indexes
Row row1 = sheet.createRow(0);
Row row2 = sheet.createRow(1);
@ -84,11 +84,11 @@ public class TestXSSFSheet extends TestCase {
assertEquals(row1, it.next());
assertTrue(it.hasNext());
assertEquals(row2, it.next());
// Test row creation with non consecutive index
Row row101 = sheet.createRow(100);
assertNotNull(row101);
// Test overwriting an existing row
Row row2_ovrewritten = sheet.createRow(1);
Cell cell = row2_ovrewritten.createCell((short) 0);
@ -102,7 +102,7 @@ public class TestXSSFSheet extends TestCase {
assertEquals(row2_ovrewritten, row2_overwritten_copy);
assertEquals(row2_overwritten_copy.getCell((short) 0).getNumericCellValue(), (double) 100);
}
public void testRemoveRow() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");
@ -114,7 +114,7 @@ public class TestXSSFSheet extends TestCase {
assertNull(sheet.getRow(2));
assertNotNull(sheet.getRow(1));
}
public void testGetSetDefaultRowHeight() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");
@ -131,17 +131,17 @@ public class TestXSSFSheet extends TestCase {
sheet.setDefaultRowHeightInPoints((short) 17);
assertEquals((short) 340, sheet.getDefaultRowHeight());
}
public void testGetSetDefaultColumnWidth() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");
// Test that default column width set by the constructor
assertEquals((short) 0, sheet.getDefaultColumnWidth());
assertEquals((short) 8, sheet.getDefaultColumnWidth());
// Set a new default column width and get its value
sheet.setDefaultColumnWidth((short) 14);
assertEquals((short) 14, sheet.getDefaultColumnWidth());
}
public void testGetFirstLastRowNum() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");
@ -149,9 +149,9 @@ public class TestXSSFSheet extends TestCase {
Row row1 = sheet.createRow(0);
Row row2 = sheet.createRow(1);
assertEquals(0, sheet.getFirstRowNum());
assertEquals(9, sheet.getLastRowNum());
assertEquals(9, sheet.getLastRowNum());
}
public void testGetPhysicalNumberOfRows() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");
@ -160,7 +160,7 @@ public class TestXSSFSheet extends TestCase {
Row row2 = sheet.createRow(1);
assertEquals(3, sheet.getPhysicalNumberOfRows());
}
public void testGetSetRowBreaks() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");
@ -173,7 +173,7 @@ public class TestXSSFSheet extends TestCase {
sheet.setRowBreak(1);
assertEquals(2, sheet.getRowBreaks().length);
}
public void testRemoveRowBreak() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");
@ -184,7 +184,7 @@ public class TestXSSFSheet extends TestCase {
sheet.removeRowBreak(1);
assertEquals(1, sheet.getRowBreaks().length);
}
public void testGetSetColumnBreaks() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");
@ -195,7 +195,7 @@ public class TestXSSFSheet extends TestCase {
sheet.setColumnBreak((short) 11223);
assertEquals(2, sheet.getColumnBreaks().length);
}
public void testRemoveColumnBreak() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");
@ -209,7 +209,7 @@ public class TestXSSFSheet extends TestCase {
sheet.removeColumnBreak((short) 15);
assertEquals(1, sheet.getColumnBreaks().length);
}
public void testIsRowColumnBroken() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");
@ -220,7 +220,7 @@ public class TestXSSFSheet extends TestCase {
sheet.setColumnBreak((short) 3);
assertTrue(sheet.isColumnBroken((short) 3));
}
public void testGetSetAutoBreaks() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");
@ -228,7 +228,7 @@ public class TestXSSFSheet extends TestCase {
sheet.setAutobreaks(false);
assertFalse(sheet.getAutobreaks());
}
public void testIsSetFitToPage() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");
@ -238,7 +238,7 @@ public class TestXSSFSheet extends TestCase {
sheet.setFitToPage(false);
assertFalse(sheet.getFitToPage());
}
public void testGetSetMargin() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");
@ -270,7 +270,7 @@ public class TestXSSFSheet extends TestCase {
assertEquals((double) 14, sheet.getMargin((short) 5));
sheet.setMargin((short) 5, 15);
assertEquals((double) 15, sheet.getMargin((short) 5));
// Test that nothing happens if another margin constant is given (E.G. 65)
sheet.setMargin((short) 65, 15);
assertEquals((double) 10, sheet.getMargin((short) 0));
@ -280,83 +280,83 @@ public class TestXSSFSheet extends TestCase {
assertEquals((double) 14, sheet.getMargin((short) 4));
assertEquals((double) 15, sheet.getMargin((short) 5));
}
public void testGetFooter() {
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = (XSSFSheet)workbook.createSheet("Sheet 1");
assertNotNull(sheet.getFooter());
sheet.getFooter().setCenter("test center footer");
assertEquals("test center footer", sheet.getFooter().getCenter());
// Default is odd footer
assertNotNull(sheet.getOddFooter());
assertEquals("test center footer", sheet.getOddFooter().getCenter());
}
public void testExistingHeaderFooter() throws Exception {
File xml = new File(
System.getProperty("HSSF.testdata.path") +
File.separator + "45540_classic_Header.xlsx"
);
assertTrue(xml.exists());
XSSFWorkbook workbook = new XSSFWorkbook(xml.toString());
XSSFOddHeader hdr;
XSSFOddFooter ftr;
// Sheet 1 has a header with center and right text
XSSFSheet s1 = (XSSFSheet)workbook.getSheetAt(0);
assertNotNull(s1.getHeader());
assertNotNull(s1.getFooter());
hdr = (XSSFOddHeader)s1.getHeader();
ftr = (XSSFOddFooter)s1.getFooter();
hdr = (XSSFOddHeader)s1.getHeader();
ftr = (XSSFOddFooter)s1.getFooter();
assertEquals("&Ctestdoc&Rtest phrase", hdr.getText());
assertEquals(null, ftr.getText());
assertEquals("", hdr.getLeft());
assertEquals("testdoc", hdr.getCenter());
assertEquals("test phrase", hdr.getRight());
assertEquals("", ftr.getLeft());
assertEquals("", ftr.getCenter());
assertEquals("", ftr.getRight());
// Sheet 2 has a footer, but it's empty
XSSFSheet s2 = (XSSFSheet)workbook.getSheetAt(1);
assertNotNull(s2.getHeader());
assertNotNull(s2.getFooter());
hdr = (XSSFOddHeader)s2.getHeader();
ftr = (XSSFOddFooter)s2.getFooter();
hdr = (XSSFOddHeader)s2.getHeader();
ftr = (XSSFOddFooter)s2.getFooter();
assertEquals(null, hdr.getText());
assertEquals("&L&F", ftr.getText());
assertEquals("", hdr.getLeft());
assertEquals("", hdr.getCenter());
assertEquals("", hdr.getRight());
assertEquals("&F", ftr.getLeft());
assertEquals("", ftr.getCenter());
assertEquals("", ftr.getRight());
// Save and reload
XSSFWorkbook wb = XSSFTestDataSamples.writeOutAndReadBack(workbook);
hdr = (XSSFOddHeader)wb.getSheetAt(0).getHeader();
ftr = (XSSFOddFooter)wb.getSheetAt(0).getFooter();
ftr = (XSSFOddFooter)wb.getSheetAt(0).getFooter();
assertEquals("", hdr.getLeft());
assertEquals("testdoc", hdr.getCenter());
assertEquals("test phrase", hdr.getRight());
assertEquals("", ftr.getLeft());
assertEquals("", ftr.getCenter());
assertEquals("", ftr.getRight());
}
public void testGetAllHeadersFooters() {
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = (XSSFSheet) workbook.createSheet("Sheet 1");
@ -366,27 +366,27 @@ public class TestXSSFSheet extends TestCase {
assertNotNull(sheet.getOddHeader());
assertNotNull(sheet.getEvenHeader());
assertNotNull(sheet.getFirstHeader());
assertEquals("", sheet.getOddFooter().getLeft());
sheet.getOddFooter().setLeft("odd footer left");
assertEquals("odd footer left", sheet.getOddFooter().getLeft());
assertEquals("", sheet.getEvenFooter().getLeft());
sheet.getEvenFooter().setLeft("even footer left");
assertEquals("even footer left", sheet.getEvenFooter().getLeft());
assertEquals("", sheet.getFirstFooter().getLeft());
sheet.getFirstFooter().setLeft("first footer left");
assertEquals("first footer left", sheet.getFirstFooter().getLeft());
assertEquals("", sheet.getOddHeader().getLeft());
sheet.getOddHeader().setLeft("odd header left");
assertEquals("odd header left", sheet.getOddHeader().getLeft());
assertEquals("", sheet.getOddHeader().getRight());
sheet.getOddHeader().setRight("odd header right");
assertEquals("odd header right", sheet.getOddHeader().getRight());
assertEquals("", sheet.getOddHeader().getCenter());
sheet.getOddHeader().setCenter("odd header center");
assertEquals("odd header center", sheet.getOddHeader().getCenter());
@ -395,49 +395,49 @@ public class TestXSSFSheet extends TestCase {
assertEquals("odd footer left", sheet.getFooter().getLeft());
assertEquals("odd header center", sheet.getHeader().getCenter());
}
public void testGetSetColumnWidth() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");
sheet.setColumnWidth((short) 1,(short) 22);
assertEquals(22, sheet.getColumnWidth((short) 1));
// Now check the low level stuff, and check that's all
// been set correctly
XSSFSheet xs = (XSSFSheet)sheet;
CTWorksheet cts = xs.getWorksheet();
CTCols[] cols_s = cts.getColsArray();
assertEquals(1, cols_s.length);
CTCols cols = cols_s[0];
assertEquals(1, cols.sizeOfColArray());
CTCol col = cols.getColArray(0);
// XML is 1 based, POI is 0 based
assertEquals(2, col.getMin());
assertEquals(2, col.getMax());
assertEquals(22.0, col.getWidth());
// Now set another
sheet.setColumnWidth((short) 3,(short) 33);
cols_s = cts.getColsArray();
assertEquals(1, cols_s.length);
cols = cols_s[0];
assertEquals(2, cols.sizeOfColArray());
col = cols.getColArray(0);
assertEquals(2, col.getMin()); // POI 1
assertEquals(2, col.getMax());
assertEquals(22.0, col.getWidth());
col = cols.getColArray(1);
assertEquals(4, col.getMin()); // POI 3
assertEquals(4, col.getMax());
assertEquals(33.0, col.getWidth());
}
public void testGetSetColumnHidden() {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet 1");

Binary file not shown.