mirror of https://github.com/apache/poi.git
Patches from Yegor (Bug #39097), along with some sorting out of indenting, method positioning etc
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@388920 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
f7f8c9e270
commit
a6b1ef6d07
|
@ -23,7 +23,6 @@ import java.util.*;
|
|||
import java.io.*;
|
||||
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.apache.poi.poifs.filesystem.POIFSDocument;
|
||||
import org.apache.poi.poifs.filesystem.DocumentEntry;
|
||||
import org.apache.poi.poifs.filesystem.DocumentInputStream;
|
||||
|
||||
|
@ -33,10 +32,8 @@ import org.apache.poi.hpsf.MutablePropertySet;
|
|||
import org.apache.poi.hpsf.SummaryInformation;
|
||||
import org.apache.poi.hpsf.DocumentSummaryInformation;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import org.apache.poi.hslf.usermodel.Picture;
|
||||
import org.apache.poi.hslf.usermodel.PictureData;
|
||||
|
||||
/**
|
||||
* This class contains the main functionality for the Powerpoint file
|
||||
|
@ -47,78 +44,91 @@ import org.apache.poi.hslf.usermodel.Picture;
|
|||
|
||||
public class HSLFSlideShow
|
||||
{
|
||||
private InputStream istream;
|
||||
private POIFSFileSystem filesystem;
|
||||
private InputStream istream;
|
||||
private POIFSFileSystem filesystem;
|
||||
|
||||
// Holds metadata on our document
|
||||
private SummaryInformation sInf;
|
||||
private DocumentSummaryInformation dsInf;
|
||||
private CurrentUserAtom currentUser;
|
||||
// Holds metadata on our document
|
||||
private SummaryInformation sInf;
|
||||
private DocumentSummaryInformation dsInf;
|
||||
private CurrentUserAtom currentUser;
|
||||
|
||||
// Low level contents of the file
|
||||
private byte[] _docstream;
|
||||
// Low level contents of the file
|
||||
private byte[] _docstream;
|
||||
|
||||
// Low level contents
|
||||
private Record[] _records;
|
||||
// Low level contents
|
||||
private Record[] _records;
|
||||
|
||||
/**
|
||||
* Constructs a Powerpoint document from fileName. Parses the document
|
||||
* and places all the important stuff into data structures.
|
||||
*
|
||||
* @param fileName The name of the file to read.
|
||||
* @throws IOException if there is a problem while parsing the document.
|
||||
*/
|
||||
public HSLFSlideShow(String fileName) throws IOException
|
||||
{
|
||||
this(new FileInputStream(fileName));
|
||||
}
|
||||
// Raw Pictures contained in the pictures stream
|
||||
private PictureData[] _pictures;
|
||||
|
||||
/**
|
||||
* Constructs a Powerpoint document from fileName. Parses the document
|
||||
* and places all the important stuff into data structures.
|
||||
*
|
||||
* @param fileName The name of the file to read.
|
||||
* @throws IOException if there is a problem while parsing the document.
|
||||
*/
|
||||
public HSLFSlideShow(String fileName) throws IOException
|
||||
{
|
||||
this(new FileInputStream(fileName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Powerpoint document from an input stream. Parses the
|
||||
* document and places all the important stuff into data structures.
|
||||
*
|
||||
* @param inputStream the source of the data
|
||||
* @throws IOException if there is a problem while parsing the document.
|
||||
*/
|
||||
public HSLFSlideShow(InputStream inputStream) throws IOException
|
||||
{
|
||||
//do Ole stuff
|
||||
/**
|
||||
* Constructs a Powerpoint document from an input stream. Parses the
|
||||
* document and places all the important stuff into data structures.
|
||||
*
|
||||
* @param inputStream the source of the data
|
||||
* @throws IOException if there is a problem while parsing the document.
|
||||
*/
|
||||
public HSLFSlideShow(InputStream inputStream) throws IOException
|
||||
{
|
||||
//do Ole stuff
|
||||
this(new POIFSFileSystem(inputStream));
|
||||
istream = inputStream;
|
||||
}
|
||||
istream = inputStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Powerpoint document from a POIFS Filesystem. Parses the
|
||||
* document and places all the important stuff into data structures.
|
||||
*
|
||||
* @param filesystem the POIFS FileSystem to read from
|
||||
* @throws IOException if there is a problem while parsing the document.
|
||||
*/
|
||||
public HSLFSlideShow(POIFSFileSystem filesystem) throws IOException
|
||||
{
|
||||
/**
|
||||
* Constructs a Powerpoint document from a POIFS Filesystem. Parses the
|
||||
* document and places all the important stuff into data structures.
|
||||
*
|
||||
* @param filesystem the POIFS FileSystem to read from
|
||||
* @throws IOException if there is a problem while parsing the document.
|
||||
*/
|
||||
public HSLFSlideShow(POIFSFileSystem filesystem) throws IOException
|
||||
{
|
||||
this.filesystem = filesystem;
|
||||
|
||||
// Go find a PowerPoint document in the stream
|
||||
// Save anything useful we come across
|
||||
readFIB();
|
||||
// Go find a PowerPoint document in the stream
|
||||
// Save anything useful we come across
|
||||
readFIB();
|
||||
|
||||
// Look for Property Streams:
|
||||
readProperties();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shuts things down. Closes underlying streams etc
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void close() throws IOException
|
||||
{
|
||||
if(istream != null) {
|
||||
istream.close();
|
||||
// Look for Picture Streams:
|
||||
readPictures();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new, empty, Powerpoint document.
|
||||
*/
|
||||
public HSLFSlideShow() throws IOException
|
||||
{
|
||||
this(HSLFSlideShow.class.getResourceAsStream("/org/apache/poi/hslf/data/empty.ppt"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts things down. Closes underlying streams etc
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void close() throws IOException
|
||||
{
|
||||
if(istream != null) {
|
||||
istream.close();
|
||||
}
|
||||
filesystem = null;
|
||||
}
|
||||
filesystem = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -175,24 +185,52 @@ public class HSLFSlideShow
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the properties from the filesystem, and load them
|
||||
*/
|
||||
public void readProperties() {
|
||||
// DocumentSummaryInformation
|
||||
dsInf = (DocumentSummaryInformation)getPropertySet("\005DocumentSummaryInformation");
|
||||
/**
|
||||
* Find the properties from the filesystem, and load them
|
||||
*/
|
||||
public void readProperties() {
|
||||
// DocumentSummaryInformation
|
||||
dsInf = (DocumentSummaryInformation)getPropertySet("\005DocumentSummaryInformation");
|
||||
|
||||
// SummaryInformation
|
||||
sInf = (SummaryInformation)getPropertySet("\005SummaryInformation");
|
||||
// SummaryInformation
|
||||
sInf = (SummaryInformation)getPropertySet("\005SummaryInformation");
|
||||
|
||||
// Current User
|
||||
try {
|
||||
currentUser = new CurrentUserAtom(filesystem);
|
||||
} catch(IOException ie) {
|
||||
System.err.println("Error finding Current User Atom:\n" + ie);
|
||||
currentUser = new CurrentUserAtom();
|
||||
// Current User
|
||||
try {
|
||||
currentUser = new CurrentUserAtom(filesystem);
|
||||
} catch(IOException ie) {
|
||||
System.err.println("Error finding Current User Atom:\n" + ie);
|
||||
currentUser = new CurrentUserAtom();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and read in pictures contained in this presentation
|
||||
*/
|
||||
private void readPictures() throws IOException {
|
||||
byte[] pictstream;
|
||||
|
||||
try {
|
||||
DocumentEntry entry = (DocumentEntry)filesystem.getRoot().getEntry("Pictures");
|
||||
pictstream = new byte[entry.getSize()];
|
||||
DocumentInputStream is = filesystem.createDocumentInputStream("Pictures");
|
||||
is.read(pictstream);
|
||||
} catch (FileNotFoundException e){
|
||||
// Silently catch exceptions if the presentation doesn't
|
||||
// contain pictures - will use a null set instead
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList p = new ArrayList();
|
||||
int pos = 0;
|
||||
while (pos < pictstream.length) {
|
||||
PictureData pict = new PictureData(pictstream, pos);
|
||||
p.add(pict);
|
||||
pos += PictureData.HEADER_SIZE + pict.getSize();
|
||||
}
|
||||
|
||||
_pictures = (PictureData[])p.toArray(new PictureData[p.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -287,6 +325,17 @@ public class HSLFSlideShow
|
|||
currentUser.setCurrentEditOffset(newLastUserEditAtomPos.intValue());
|
||||
currentUser.writeToFS(outFS);
|
||||
|
||||
|
||||
// Write any pictures, into another stream
|
||||
if (_pictures != null) {
|
||||
ByteArrayOutputStream pict = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < _pictures.length; i++ ) {
|
||||
_pictures[i].write(pict);
|
||||
}
|
||||
outFS.createDocument(
|
||||
new ByteArrayInputStream(pict.toByteArray()), "Pictures"
|
||||
);
|
||||
}
|
||||
|
||||
// Send the POIFSFileSystem object out to the underlying stream
|
||||
outFS.writeFilesystem(out);
|
||||
|
@ -311,87 +360,86 @@ public class HSLFSlideShow
|
|||
}
|
||||
|
||||
|
||||
/* ******************* fetching methods follow ********************* */
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of all the records found in the slideshow
|
||||
*/
|
||||
public Record[] getRecords() { return _records; }
|
||||
|
||||
/**
|
||||
* Adds a new root level record, at the end, but before the last
|
||||
* PersistPtrIncrementalBlock.
|
||||
*/
|
||||
public synchronized int appendRootLevelRecord(Record newRecord) {
|
||||
int addedAt = -1;
|
||||
Record[] r = new Record[_records.length+1];
|
||||
boolean added = false;
|
||||
for(int i=(_records.length-1); i>=0; i--) {
|
||||
if(added) {
|
||||
// Just copy over
|
||||
r[i] = _records[i];
|
||||
} else {
|
||||
r[(i+1)] = _records[i];
|
||||
if(_records[i] instanceof PersistPtrHolder) {
|
||||
r[i] = newRecord;
|
||||
added = true;
|
||||
addedAt = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
_records = r;
|
||||
return addedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of the bytes of the file. Only correct after a
|
||||
* call to open or write - at all other times might be wrong!
|
||||
*/
|
||||
public byte[] getUnderlyingBytes() { return _docstream; }
|
||||
|
||||
/**
|
||||
* Fetch the Document Summary Information of the document
|
||||
*/
|
||||
public DocumentSummaryInformation getDocumentSummaryInformation() { return dsInf; }
|
||||
|
||||
/**
|
||||
* Fetch the Summary Information of the document
|
||||
*/
|
||||
public SummaryInformation getSummaryInformation() { return sInf; }
|
||||
|
||||
/**
|
||||
* Fetch the Current User Atom of the document
|
||||
*/
|
||||
public CurrentUserAtom getCurrentUserAtom() { return currentUser; }
|
||||
/* ******************* adding methods follow ********************* */
|
||||
|
||||
/**
|
||||
* Read pictures contained in this presentation
|
||||
* Adds a new root level record, at the end, but before the last
|
||||
* PersistPtrIncrementalBlock.
|
||||
*/
|
||||
public synchronized int appendRootLevelRecord(Record newRecord) {
|
||||
int addedAt = -1;
|
||||
Record[] r = new Record[_records.length+1];
|
||||
boolean added = false;
|
||||
for(int i=(_records.length-1); i>=0; i--) {
|
||||
if(added) {
|
||||
// Just copy over
|
||||
r[i] = _records[i];
|
||||
} else {
|
||||
r[(i+1)] = _records[i];
|
||||
if(_records[i] instanceof PersistPtrHolder) {
|
||||
r[i] = newRecord;
|
||||
added = true;
|
||||
addedAt = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
_records = r;
|
||||
return addedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new picture to this presentation.
|
||||
*/
|
||||
public void addPicture(PictureData img) {
|
||||
// Copy over the existing pictures, into an array one bigger
|
||||
PictureData[] lst;
|
||||
if(_pictures == null) {
|
||||
lst = new PictureData[1];
|
||||
} else {
|
||||
lst = new PictureData[(_pictures.length+1)];
|
||||
System.arraycopy(_pictures,0,lst,0,_pictures.length);
|
||||
}
|
||||
// Add in the new image
|
||||
lst[lst.length - 1] = img;
|
||||
_pictures = lst;
|
||||
}
|
||||
|
||||
/* ******************* fetching methods follow ********************* */
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of all the records found in the slideshow
|
||||
*/
|
||||
public Record[] getRecords() { return _records; }
|
||||
|
||||
/**
|
||||
* Returns an array of the bytes of the file. Only correct after a
|
||||
* call to open or write - at all other times might be wrong!
|
||||
*/
|
||||
public byte[] getUnderlyingBytes() { return _docstream; }
|
||||
|
||||
/**
|
||||
* Fetch the Document Summary Information of the document
|
||||
*/
|
||||
public DocumentSummaryInformation getDocumentSummaryInformation() { return dsInf; }
|
||||
|
||||
/**
|
||||
* Fetch the Summary Information of the document
|
||||
*/
|
||||
public SummaryInformation getSummaryInformation() { return sInf; }
|
||||
|
||||
/**
|
||||
* Fetch the Current User Atom of the document
|
||||
*/
|
||||
public CurrentUserAtom getCurrentUserAtom() { return currentUser; }
|
||||
|
||||
/**
|
||||
* Return array of pictures contained in this presentation
|
||||
*
|
||||
* @return array with the read pictures ot <code>null</code> if the
|
||||
* @return array with the read pictures or <code>null</code> if the
|
||||
* presentation doesn't contain pictures.
|
||||
*/
|
||||
public Picture[] getPictures() throws IOException {
|
||||
byte[] pictstream;
|
||||
|
||||
try {
|
||||
DocumentEntry entry = (DocumentEntry)filesystem.getRoot().getEntry("Pictures");
|
||||
pictstream = new byte[entry.getSize()];
|
||||
DocumentInputStream is = filesystem.createDocumentInputStream("Pictures");
|
||||
is.read(pictstream);
|
||||
} catch (FileNotFoundException e){
|
||||
//silently catch exceptions if the presentation doesn't contain pictures
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList p = new ArrayList();
|
||||
int pos = 0;
|
||||
while (pos < pictstream.length) {
|
||||
Picture pict = new Picture(pictstream, pos);
|
||||
p.add(pict);
|
||||
pos += Picture.HEADER_SIZE + pict.getSize();
|
||||
}
|
||||
|
||||
return (Picture[])p.toArray(new Picture[p.size()]);
|
||||
public PictureData[] getPictures() {
|
||||
return _pictures;
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -33,16 +33,15 @@ public class Ellipse extends SimpleShape {
|
|||
|
||||
public Ellipse(Shape parent){
|
||||
super(null, parent);
|
||||
_escherContainer = create(parent instanceof ShapeGroup);
|
||||
_escherContainer = createSpContainer(parent instanceof ShapeGroup);
|
||||
}
|
||||
|
||||
public Ellipse(){
|
||||
this(null);
|
||||
}
|
||||
|
||||
protected EscherContainerRecord create(boolean isChild){
|
||||
EscherContainerRecord spcont = super.create(isChild);
|
||||
spcont.setOptions((short)15);
|
||||
protected EscherContainerRecord createSpContainer(boolean isChild){
|
||||
EscherContainerRecord spcont = super.createSpContainer(isChild);
|
||||
|
||||
EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);
|
||||
short type = (ShapeTypes.Ellipse << 4) + 2;
|
||||
|
|
|
@ -96,16 +96,15 @@ public class Line extends SimpleShape {
|
|||
|
||||
public Line(Shape parent){
|
||||
super(null, parent);
|
||||
_escherContainer = create(parent instanceof ShapeGroup);
|
||||
_escherContainer = createSpContainer(parent instanceof ShapeGroup);
|
||||
}
|
||||
|
||||
public Line(){
|
||||
this(null);
|
||||
}
|
||||
|
||||
protected EscherContainerRecord create(boolean isChild){
|
||||
EscherContainerRecord spcont = super.create(isChild);
|
||||
spcont.setOptions((short)15);
|
||||
protected EscherContainerRecord createSpContainer(boolean isChild){
|
||||
EscherContainerRecord spcont = super.createSpContainer(isChild);
|
||||
|
||||
EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);
|
||||
short type = (ShapeTypes.Line << 4) + 2;
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
package org.apache.poi.hslf.model;
|
||||
|
||||
import org.apache.poi.ddf.*;
|
||||
import org.apache.poi.hslf.usermodel.PictureData;
|
||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a picture in a PowerPoint document.
|
||||
* <p>
|
||||
* The information about an image in PowerPoint document is stored in
|
||||
* two places:
|
||||
* <li> EscherBSE container in the Document keeps information about image
|
||||
* type, image index to refer by slides etc.
|
||||
* <li> "Pictures" OLE stream holds the actual data of the image.
|
||||
* </p>
|
||||
* <p>
|
||||
* Data in the "Pictures" OLE stream is organized as follows:<br>
|
||||
* For each image there is an entry: 25 byte header + image data.
|
||||
* Image data is the exact content of the JPEG file, i.e. PowerPoint
|
||||
* puts the whole jpeg file there without any modifications.<br>
|
||||
* Header format:
|
||||
* <li> 2 byte: image type. For JPEGs it is 0x46A0, for PNG it is 0x6E00.
|
||||
* <li> 2 byte: unknown.
|
||||
* <li> 4 byte : image size + 17. Looks like shift from the end of
|
||||
* header but why to add it to the image size?
|
||||
* <li> next 16 bytes. Unique identifier of this image which is used by
|
||||
* EscherBSE record.
|
||||
* </p>
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class Picture extends SimpleShape {
|
||||
|
||||
/**
|
||||
* Windows Metafile
|
||||
* ( NOT YET SUPPORTED )
|
||||
*/
|
||||
public static final int WMF = 3;
|
||||
|
||||
/**
|
||||
* Macintosh PICT
|
||||
* ( NOT YET SUPPORTED )
|
||||
*/
|
||||
public static final int PICT = 4;
|
||||
|
||||
/**
|
||||
* JPEG
|
||||
*/
|
||||
public static final int JPEG = 5;
|
||||
|
||||
/**
|
||||
* PNG
|
||||
*/
|
||||
public static final int PNG = 6;
|
||||
|
||||
/**
|
||||
* Windows DIB (BMP)
|
||||
*/
|
||||
public static final int DIB = 7;
|
||||
|
||||
/**
|
||||
* Create a new <code>Picture</code>
|
||||
*
|
||||
* @param idx the index of the picture
|
||||
*/
|
||||
public Picture(int idx){
|
||||
super(null, null);
|
||||
_escherContainer = createSpContainer(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a <code>Picture</code> object
|
||||
*
|
||||
* @param escherRecord the <code>EscherSpContainer</code> record which holds information about
|
||||
* this picture in the <code>Slide</code>
|
||||
* @param parent the parent shape of this picture
|
||||
*/
|
||||
protected Picture(EscherContainerRecord escherRecord, Shape parent){
|
||||
super(escherRecord, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns index associated with this picture.
|
||||
* Index starts with 1 and points to a EscherBSE record which
|
||||
* holds information about this picture.
|
||||
*
|
||||
* @return the index to this picture (1 based).
|
||||
*/
|
||||
public int getPictureIndex(){
|
||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.BLIP__BLIPTODISPLAY + 0x4000);
|
||||
return prop.getPropertyValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Picture and populate the inital structure of the <code>EscherSp</code> record which holds information about this picture.
|
||||
|
||||
* @param idx the index of the picture which referes to <code>EscherBSE</code> container.
|
||||
* @return the create Picture object
|
||||
*/
|
||||
protected EscherContainerRecord createSpContainer(int idx) {
|
||||
EscherContainerRecord spContainer = super.createSpContainer(false);
|
||||
spContainer.setOptions((short)15);
|
||||
|
||||
EscherSpRecord spRecord = spContainer.getChildById(EscherSpRecord.RECORD_ID);
|
||||
spRecord.setOptions((short)((ShapeTypes.PictureFrame << 4) | 0x2));
|
||||
|
||||
//set default properties for a picture
|
||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
|
||||
setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 8388736);
|
||||
|
||||
//another weird feature of powerpoint: for picture id we must add 0x4000.
|
||||
setEscherProperty(opt, (short)(EscherProperties.BLIP__BLIPTODISPLAY + 0x4000), idx);
|
||||
|
||||
return spContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default size of the picture
|
||||
*
|
||||
* @param ppt presentation which holds the picture
|
||||
*/
|
||||
public void setDefaultSize(SlideShow ppt) throws IOException {
|
||||
int idx = getPictureIndex();
|
||||
|
||||
PictureData pict = ppt.getPictures()[idx-1];
|
||||
BufferedImage img = ImageIO.read(new ByteArrayInputStream(pict.getData()));
|
||||
|
||||
setAnchor(new java.awt.Rectangle(0, 0, img.getWidth()*6, img.getHeight()*6));
|
||||
}
|
||||
}
|
|
@ -33,15 +33,15 @@ public class Rectangle extends SimpleShape {
|
|||
|
||||
public Rectangle(Shape parent){
|
||||
super(null, parent);
|
||||
_escherContainer = create(parent instanceof ShapeGroup);
|
||||
_escherContainer = createSpContainer(parent instanceof ShapeGroup);
|
||||
}
|
||||
|
||||
public Rectangle(){
|
||||
this(null);
|
||||
}
|
||||
|
||||
protected EscherContainerRecord create(boolean isChild){
|
||||
EscherContainerRecord spcont = super.create(isChild);
|
||||
protected EscherContainerRecord createSpContainer(boolean isChild){
|
||||
EscherContainerRecord spcont = super.createSpContainer(isChild);
|
||||
spcont.setOptions((short)15);
|
||||
|
||||
EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);
|
||||
|
|
|
@ -26,25 +26,37 @@ import java.util.Iterator;
|
|||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class Shape {
|
||||
public abstract class Shape {
|
||||
|
||||
public static final int EMU_PER_POINT = 12700;
|
||||
|
||||
/**
|
||||
* The parent of the shape
|
||||
*/
|
||||
protected Shape _parent;
|
||||
|
||||
/**
|
||||
* Either EscherSpContainer or EscheSpgrContainer record
|
||||
* which holds information about this shape.
|
||||
*/
|
||||
protected EscherContainerRecord _escherContainer;
|
||||
|
||||
protected Shape(EscherContainerRecord escherRecord, Shape parent){
|
||||
/**
|
||||
* Parent of this shape.
|
||||
* <code>null</code> for the topmost shapes.
|
||||
*/
|
||||
protected Shape _parent;
|
||||
|
||||
/**
|
||||
* Create a Shape object. This constructor is used when an existing Shape is read from from a PowerPoint document.
|
||||
*
|
||||
* @param escherRecord <code>EscherSpContainer</code> container which holds information about this shape
|
||||
* @param parent the parent of this Shape
|
||||
*/
|
||||
protected Shape(EscherContainerRecord escherRecord, Shape parent){
|
||||
_escherContainer = escherRecord;
|
||||
_parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the lowerlevel escher records for this shape.
|
||||
*/
|
||||
protected abstract EscherContainerRecord createSpContainer(boolean isChild);
|
||||
|
||||
/**
|
||||
* @return the parent of this shape
|
||||
|
@ -128,17 +140,27 @@ public class Shape {
|
|||
setAnchor(anchor);
|
||||
}
|
||||
|
||||
protected static EscherRecord getEscherChild(EscherContainerRecord owner, int recordId){
|
||||
/**
|
||||
* Helper method to return escher child by record ID
|
||||
*
|
||||
* @return escher record or <code>null</code> if not found.
|
||||
*/
|
||||
public static EscherRecord getEscherChild(EscherContainerRecord owner, int recordId){
|
||||
for ( Iterator iterator = owner.getChildRecords().iterator(); iterator.hasNext(); )
|
||||
{
|
||||
EscherRecord escherRecord = (EscherRecord) iterator.next();
|
||||
if (escherRecord.getRecordId() == recordId)
|
||||
return (EscherRecord) escherRecord;
|
||||
return escherRecord;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static EscherProperty getEscherProperty(EscherOptRecord opt, int propId){
|
||||
/**
|
||||
* Returns escher property by id.
|
||||
*
|
||||
* @return escher property or <code>null</code> if not found.
|
||||
*/
|
||||
public static EscherProperty getEscherProperty(EscherOptRecord opt, int propId){
|
||||
for ( Iterator iterator = opt.getEscherProperties().iterator(); iterator.hasNext(); )
|
||||
{
|
||||
EscherProperty prop = (EscherProperty) iterator.next();
|
||||
|
@ -148,7 +170,14 @@ public class Shape {
|
|||
return null;
|
||||
}
|
||||
|
||||
protected static void setEscherProperty(EscherOptRecord opt, short propId, int value){
|
||||
/**
|
||||
* Set an escher property in the opt record.
|
||||
*
|
||||
* @param opt The opt record to set the properties to.
|
||||
* @param propId The id of the property. One of the constants defined in EscherOptRecord.
|
||||
* @param value value of the property
|
||||
*/
|
||||
public static void setEscherProperty(EscherOptRecord opt, short propId, int value){
|
||||
java.util.List props = opt.getEscherProperties();
|
||||
for ( Iterator iterator = props.iterator(); iterator.hasNext(); ) {
|
||||
EscherProperty prop = (EscherProperty) iterator.next();
|
||||
|
@ -163,10 +192,10 @@ public class Shape {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return escher container which holds information about this shape
|
||||
* @return The shape container and it's children that can represent this
|
||||
* shape.
|
||||
*/
|
||||
public EscherContainerRecord getShapeRecord(){
|
||||
public EscherContainerRecord getSpContainer(){
|
||||
return _escherContainer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,10 +37,10 @@ public class ShapeFactory {
|
|||
switch (type){
|
||||
case ShapeTypes.TextBox:
|
||||
case ShapeTypes.Rectangle:
|
||||
shape = new Shape(spContainer, parent);
|
||||
shape = new Rectangle(spContainer, parent);
|
||||
break;
|
||||
case ShapeTypes.PictureFrame:
|
||||
shape = new Shape(spContainer, parent);
|
||||
shape = new Picture(spContainer, parent);
|
||||
break;
|
||||
case ShapeTypes.Line:
|
||||
shape = new Line(spContainer, parent);
|
||||
|
@ -52,7 +52,7 @@ public class ShapeFactory {
|
|||
shape = new ShapeGroup(spContainer, parent);
|
||||
break;
|
||||
default:
|
||||
shape = new Shape(spContainer, parent);
|
||||
shape = new SimpleShape(spContainer, parent);
|
||||
break;
|
||||
}
|
||||
return shape;
|
||||
|
|
|
@ -27,13 +27,9 @@ import java.util.List;
|
|||
*/
|
||||
public class ShapeGroup extends Shape{
|
||||
|
||||
public ShapeGroup(Shape parent){
|
||||
super(null, parent);
|
||||
_escherContainer = create();
|
||||
}
|
||||
|
||||
public ShapeGroup(){
|
||||
this(null);
|
||||
this(null, null);
|
||||
_escherContainer = createSpContainer(false);
|
||||
}
|
||||
|
||||
protected ShapeGroup(EscherContainerRecord escherRecord, Shape parent){
|
||||
|
@ -91,7 +87,7 @@ public class ShapeGroup extends Shape{
|
|||
/**
|
||||
* Create a new ShapeGroup and create an instance of <code>EscherSpgrContainer</code> which represents a group of shapes
|
||||
*/
|
||||
protected EscherContainerRecord create() {
|
||||
protected EscherContainerRecord createSpContainer(boolean isChild) {
|
||||
EscherContainerRecord spgr = new EscherContainerRecord();
|
||||
spgr.setRecordId(EscherContainerRecord.SPGR_CONTAINER);
|
||||
spgr.setOptions((short)15);
|
||||
|
@ -124,7 +120,7 @@ public class ShapeGroup extends Shape{
|
|||
* @param shape - the Shape to add
|
||||
*/
|
||||
public void addShape(Shape shape){
|
||||
_escherContainer.addChildRecord(shape.getShapeRecord());
|
||||
_escherContainer.addChildRecord(shape.getSpContainer());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -158,7 +158,7 @@ public abstract class Sheet
|
|||
|
||||
EscherContainerRecord dgContainer = (EscherContainerRecord)ppdrawing.getEscherRecords()[0];
|
||||
EscherContainerRecord spgr = (EscherContainerRecord)Shape.getEscherChild(dgContainer, EscherContainerRecord.SPGR_CONTAINER);
|
||||
spgr.addChildRecord(shape.getShapeRecord());
|
||||
spgr.addChildRecord(shape.getSpContainer());
|
||||
|
||||
EscherDgRecord dg = (EscherDgRecord)Shape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID);
|
||||
dg.setNumShapes(dg.getNumShapes()+1);
|
||||
|
|
|
@ -39,10 +39,10 @@ public class SimpleShape extends Shape {
|
|||
* @param isChild <code>true</code> if the Line is inside a group, <code>false</code> otherwise
|
||||
* @return the record container which holds this shape
|
||||
*/
|
||||
protected EscherContainerRecord create(boolean isChild) {
|
||||
protected EscherContainerRecord createSpContainer(boolean isChild) {
|
||||
EscherContainerRecord spContainer = new EscherContainerRecord();
|
||||
spContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
|
||||
//spContainer.setOptions((short)15);
|
||||
spContainer.setOptions((short)15);
|
||||
|
||||
EscherSpRecord sp = new EscherSpRecord();
|
||||
int flags = EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE;
|
||||
|
|
|
@ -36,6 +36,7 @@ public class Document extends PositionDependentRecordContainer
|
|||
// Links to our more interesting children
|
||||
private DocumentAtom documentAtom;
|
||||
private Environment environment;
|
||||
private PPDrawingGroup ppDrawing;
|
||||
private SlideListWithText[] slwts;
|
||||
|
||||
/**
|
||||
|
@ -47,6 +48,11 @@ public class Document extends PositionDependentRecordContainer
|
|||
* settings for the document in it
|
||||
*/
|
||||
public Environment getEnvironment() { return environment; }
|
||||
/**
|
||||
* Returns the PPDrawingGroup, which holds an Escher Structure
|
||||
* that contains information on pictures in the slides.
|
||||
*/
|
||||
public PPDrawingGroup getPPDrawingGroup() { return ppDrawing; }
|
||||
/**
|
||||
* Returns all the SlideListWithTexts that are defined for
|
||||
* this Document. They hold the text, and some of the text
|
||||
|
@ -82,6 +88,9 @@ public class Document extends PositionDependentRecordContainer
|
|||
if(_children[i] instanceof Environment) {
|
||||
environment = (Environment)_children[i];
|
||||
}
|
||||
if(_children[i] instanceof PPDrawingGroup) {
|
||||
ppDrawing = (PPDrawingGroup)_children[i];
|
||||
}
|
||||
}
|
||||
// Now grab them all
|
||||
slwts = new SlideListWithText[slwtcount];
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
package org.apache.poi.hslf.record;
|
||||
|
||||
import org.apache.poi.ddf.*;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Container records which always exists inside Document.
|
||||
* It always acts as a holder for escher DGG container
|
||||
* which may contain which Escher BStore container information
|
||||
* about pictures containes in the presentation (if any).
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class PPDrawingGroup extends RecordAtom {
|
||||
|
||||
private byte[] _header;
|
||||
private EscherContainerRecord dggContainer;
|
||||
|
||||
protected PPDrawingGroup(byte[] source, int start, int len) {
|
||||
// Get the header
|
||||
_header = new byte[8];
|
||||
System.arraycopy(source,start,_header,0,8);
|
||||
|
||||
// Get the contents for now
|
||||
byte[] contents = new byte[len];
|
||||
System.arraycopy(source,start,contents,0,len);
|
||||
|
||||
DefaultEscherRecordFactory erf = new DefaultEscherRecordFactory();
|
||||
EscherRecord child = erf.createRecord(contents, 0);
|
||||
child.fillFields( contents, 0, erf );
|
||||
dggContainer = (EscherContainerRecord)child.getChild(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* We are type 1035
|
||||
*/
|
||||
public long getRecordType() {
|
||||
return RecordTypes.PPDrawingGroup.typeID;
|
||||
}
|
||||
|
||||
/**
|
||||
* We're pretending to be an atom, so return null
|
||||
*/
|
||||
public Record[] getChildRecords() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
List child = dggContainer.getChildRecords();
|
||||
for (int i = 0; i < child.size(); i++) {
|
||||
EscherRecord r = (EscherRecord)child.get(i);
|
||||
if (r.getRecordId() == EscherContainerRecord.BSTORE_CONTAINER){
|
||||
EscherContainerRecord bstore = (EscherContainerRecord)r;
|
||||
|
||||
ByteArrayOutputStream b2 = new ByteArrayOutputStream();
|
||||
List blip = bstore.getChildRecords();
|
||||
for (Iterator it=blip.iterator(); it.hasNext();) {
|
||||
EscherBSERecord bse = (EscherBSERecord)it.next();
|
||||
byte[] b = new byte[36+8];
|
||||
bse.serialize(0, b);
|
||||
b2.write(b);
|
||||
}
|
||||
byte[] bstorehead = new byte[8];
|
||||
LittleEndian.putShort(bstorehead, 0, bstore.getOptions());
|
||||
LittleEndian.putShort(bstorehead, 2, bstore.getRecordId());
|
||||
LittleEndian.putInt(bstorehead, 4, b2.size());
|
||||
bout.write(bstorehead);
|
||||
bout.write(b2.toByteArray());
|
||||
|
||||
} else {
|
||||
bout.write(r.serialize());
|
||||
}
|
||||
}
|
||||
int size = bout.size();
|
||||
|
||||
// Update the size (header bytes 5-8)
|
||||
LittleEndian.putInt(_header,4,size+8);
|
||||
|
||||
// Write out our header
|
||||
out.write(_header);
|
||||
|
||||
byte[] dgghead = new byte[8];
|
||||
LittleEndian.putShort(dgghead, 0, dggContainer.getOptions());
|
||||
LittleEndian.putShort(dgghead, 2, dggContainer.getRecordId());
|
||||
LittleEndian.putInt(dgghead, 4, size);
|
||||
out.write(dgghead);
|
||||
|
||||
// Finally, write out the children
|
||||
out.write(bout.toByteArray());
|
||||
|
||||
}
|
||||
|
||||
public EscherContainerRecord getDggContainer(){
|
||||
return dggContainer;
|
||||
}
|
||||
}
|
|
@ -60,7 +60,7 @@ public class RecordTypes {
|
|||
public static final Type SorterViewInfo = new Type(1032,null);
|
||||
public static final Type ExObjList = new Type(1033,null);
|
||||
public static final Type ExObjListAtom = new Type(1034,null);
|
||||
public static final Type PPDrawingGroup = new Type(1035,null);
|
||||
public static final Type PPDrawingGroup = new Type(1035,PPDrawingGroup.class);
|
||||
public static final Type PPDrawing = new Type(1036,PPDrawing.class);
|
||||
public static final Type NamedShows = new Type(1040,null);
|
||||
public static final Type NamedShow = new Type(1041,null);
|
||||
|
|
|
@ -1,140 +0,0 @@
|
|||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.hslf.usermodel;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* Represents a picture in a PowerPoint document.
|
||||
* <p>
|
||||
* The information about an image in PowerPoint document is stored in
|
||||
* two places:
|
||||
* <li> EscherBSE container in the Document keeps information about image
|
||||
* type, image index to refer by slides etc.
|
||||
* <li> "Pictures" OLE stream holds the actual data of the image.
|
||||
* </p>
|
||||
* <p>
|
||||
* Data in the "Pictures" OLE stream is organized as follows:<br>
|
||||
* For each image there is an entry: 25 byte header + image data.
|
||||
* Image data is the exact content of the JPEG file, i.e. PowerPoint
|
||||
* puts the whole jpeg file there without any modifications.<br>
|
||||
* Header format:
|
||||
* <li> 2 byte: image type. For JPEGs it is 0x46A0, for PNG it is 0x6E00.
|
||||
* <li> 2 byte: unknown.
|
||||
* <li> 4 byte : image size + 17. Looks like shift from the end of
|
||||
* header but why to add it to the image size?
|
||||
* <li> next 16 bytes. Unique identifier of this image which is used by
|
||||
* EscherBSE record.
|
||||
* </p>
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class Picture {
|
||||
|
||||
/**
|
||||
* Windows Metafile
|
||||
*/
|
||||
public static final int WMF = 0x2160;
|
||||
|
||||
/**
|
||||
* Macintosh PICT
|
||||
*/
|
||||
public static final int PICT = 0x5420;
|
||||
|
||||
/**
|
||||
* JPEG
|
||||
*/
|
||||
public static final int JPEG = 0x46A0;
|
||||
|
||||
/**
|
||||
* PNG
|
||||
*/
|
||||
public static final int PNG = 0x6E00;
|
||||
|
||||
/**
|
||||
* Windows DIB (BMP)
|
||||
*/
|
||||
public static final int DIB = 0x7A80;
|
||||
|
||||
/**
|
||||
* The size of the header
|
||||
*/
|
||||
public static final int HEADER_SIZE = 25;
|
||||
|
||||
/**
|
||||
* Binary data of the picture
|
||||
*/
|
||||
protected byte[] pictdata;
|
||||
|
||||
/**
|
||||
* Header which holds information about this picture
|
||||
*/
|
||||
protected byte[] header;
|
||||
|
||||
/**
|
||||
* Read a picture from "Pictures" OLE stream
|
||||
*
|
||||
* @param pictstream the bytes to read
|
||||
* @param offset the index of the first byte to read
|
||||
*/
|
||||
public Picture(byte[] pictstream, int offset){
|
||||
header = new byte[Picture.HEADER_SIZE];
|
||||
System.arraycopy(pictstream, offset, header, 0, header.length);
|
||||
|
||||
int size = LittleEndian.getInt(header, 4) - 17;
|
||||
pictdata = new byte[size];
|
||||
System.arraycopy(pictstream, offset + Picture.HEADER_SIZE, pictdata, 0, pictdata.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the binary data of this picture
|
||||
*/
|
||||
public byte[] getData(){
|
||||
return pictdata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return image size in bytes
|
||||
*
|
||||
* @return the size of the picture in bytes
|
||||
*/
|
||||
public int getSize(){
|
||||
return pictdata.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique identifier (UID) of this picture.
|
||||
* The UID is a checksum of the picture data. Its length is 16 bytes
|
||||
* and it must be unique across the presentation.
|
||||
*
|
||||
* @return the unique identifier of this picture
|
||||
*/
|
||||
public byte[] getUID(){
|
||||
byte[] uid = new byte[16];
|
||||
System.arraycopy(header, 8, uid, 0, uid.length);
|
||||
return uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of this picture. Must be one of the static constans defined in this class.
|
||||
*
|
||||
* @return type of this picture.
|
||||
*/
|
||||
public int getType(){
|
||||
int type = LittleEndian.getShort(header, 0);
|
||||
return type;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.hslf.usermodel;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.hslf.model.Picture;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* A class that represents the image data contained in the Presentation.
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class PictureData {
|
||||
|
||||
/**
|
||||
* The size of the header
|
||||
*/
|
||||
public static final int HEADER_SIZE = 25;
|
||||
|
||||
/**
|
||||
* Binary data of the picture
|
||||
*/
|
||||
protected byte[] pictdata;
|
||||
|
||||
/**
|
||||
* Header which holds information about this picture
|
||||
*/
|
||||
protected byte[] header;
|
||||
|
||||
public PictureData(){
|
||||
header = new byte[PictureData.HEADER_SIZE];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a picture from "Pictures" OLE stream
|
||||
*
|
||||
* @param pictstream the bytes to read
|
||||
* @param offset the index of the first byte to read
|
||||
*/
|
||||
public PictureData(byte[] pictstream, int offset){
|
||||
header = new byte[PictureData.HEADER_SIZE];
|
||||
System.arraycopy(pictstream, offset, header, 0, header.length);
|
||||
|
||||
int size = LittleEndian.getInt(header, 4) - 17;
|
||||
pictdata = new byte[size];
|
||||
System.arraycopy(pictstream, offset + PictureData.HEADER_SIZE, pictdata, 0, pictdata.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the binary data of this picture
|
||||
*/
|
||||
public byte[] getData(){
|
||||
return pictdata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set picture data
|
||||
*/
|
||||
public void setData(byte[] data) {
|
||||
pictdata = data;
|
||||
LittleEndian.putInt(header, 4, data.length + 17);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return image size in bytes
|
||||
*
|
||||
* @return the size of the picture in bytes
|
||||
*/
|
||||
public int getSize(){
|
||||
return pictdata.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique identifier (UID) of this picture.
|
||||
* The UID is a checksum of the picture data. Its length is 16 bytes
|
||||
* and it must be unique across the presentation.
|
||||
*
|
||||
* @return the unique identifier of this picture
|
||||
*/
|
||||
public byte[] getUID(){
|
||||
byte[] uid = new byte[16];
|
||||
System.arraycopy(header, 8, uid, 0, uid.length);
|
||||
return uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the unique identifier (UID) of this picture.
|
||||
*
|
||||
* @param uid checksum of the picture data
|
||||
*/
|
||||
public void setUID(byte[] uid){
|
||||
System.arraycopy(uid, 0, header, 8, uid.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of this picture.
|
||||
*
|
||||
* @return type of this picture.
|
||||
* Must be one of the static constans defined in the <code>Picture<code> class.
|
||||
*/
|
||||
public void setType(int format){
|
||||
switch (format){
|
||||
case Picture.JPEG: LittleEndian.putInt(header, 0, -266516832); break;
|
||||
case Picture.PNG: LittleEndian.putInt(header, 0, -266441216); break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the header of the Picture
|
||||
*
|
||||
* @return the header of the Picture
|
||||
*/
|
||||
public byte[] getHeader(){
|
||||
return header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute 16-byte checksum of this picture
|
||||
*/
|
||||
public static byte[] getChecksum(byte[] data) {
|
||||
MessageDigest sha;
|
||||
try {
|
||||
sha = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e){
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
sha.update(data);
|
||||
return sha.digest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write this picture into <code>OutputStream</code>
|
||||
*/
|
||||
public void write(OutputStream out) throws IOException {
|
||||
out.write(header);
|
||||
out.write(pictdata);
|
||||
}
|
||||
|
||||
}
|
|
@ -23,6 +23,10 @@ import java.util.*;
|
|||
import java.awt.Dimension;
|
||||
import java.io.*;
|
||||
|
||||
import org.apache.poi.ddf.EscherBSERecord;
|
||||
import org.apache.poi.ddf.EscherContainerRecord;
|
||||
import org.apache.poi.ddf.EscherOptRecord;
|
||||
import org.apache.poi.ddf.EscherRecord;
|
||||
import org.apache.poi.hslf.*;
|
||||
import org.apache.poi.hslf.model.*;
|
||||
import org.apache.poi.hslf.record.Document;
|
||||
|
@ -50,6 +54,7 @@ import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
|
|||
* - handle Slide creation cleaner
|
||||
*
|
||||
* @author Nick Burch
|
||||
* @author Yegor kozlov
|
||||
*/
|
||||
|
||||
public class SlideShow
|
||||
|
@ -74,6 +79,12 @@ public class SlideShow
|
|||
// MetaSheets (eg masters) not yet supported
|
||||
// private MetaSheets[] _msheets;
|
||||
|
||||
|
||||
/* ===============================================================
|
||||
* Setup Code
|
||||
* ===============================================================
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a Powerpoint document from the underlying
|
||||
|
@ -86,7 +97,6 @@ public class SlideShow
|
|||
// Get useful things from our base slideshow
|
||||
_hslfSlideShow = hslfSlideShow;
|
||||
_records = _hslfSlideShow.getRecords();
|
||||
byte[] _docstream = _hslfSlideShow.getUnderlyingBytes();
|
||||
|
||||
// Handle Parent-aware Reocrds
|
||||
for(int i=0; i<_records.length; i++) {
|
||||
|
@ -100,6 +110,12 @@ public class SlideShow
|
|||
buildSlidesAndNotes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new, empty, Powerpoint document.
|
||||
*/
|
||||
public SlideShow() throws IOException {
|
||||
this(new HSLFSlideShow());
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the records that are parent-aware, and tell them
|
||||
|
@ -373,6 +389,77 @@ public class SlideShow
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes out the slideshow file the is represented by an instance of
|
||||
* this class
|
||||
* @param out The OutputStream to write to.
|
||||
* @throws IOException If there is an unexpected IOException from the passed
|
||||
* in OutputStream
|
||||
*/
|
||||
public void write(OutputStream out) throws IOException {
|
||||
_hslfSlideShow.write(out);
|
||||
}
|
||||
|
||||
|
||||
/* ===============================================================
|
||||
* Accessor Code
|
||||
* ===============================================================
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of the most recent version of all the interesting
|
||||
* records
|
||||
*/
|
||||
public Record[] getMostRecentCoreRecords() { return _mostRecentCoreRecords; }
|
||||
|
||||
/**
|
||||
* Returns an array of all the normal Slides found in the slideshow
|
||||
*/
|
||||
public Slide[] getSlides() { return _slides; }
|
||||
|
||||
/**
|
||||
* Returns an array of all the normal Notes found in the slideshow
|
||||
*/
|
||||
public Notes[] getNotes() { return _notes; }
|
||||
|
||||
/**
|
||||
* Returns an array of all the meta Sheets (master sheets etc)
|
||||
* found in the slideshow
|
||||
*/
|
||||
//public MetaSheet[] getMetaSheets() { return _msheets; }
|
||||
|
||||
/**
|
||||
* Returns all the pictures attached to the SlideShow
|
||||
*/
|
||||
public PictureData[] getPictures() throws IOException {
|
||||
return _hslfSlideShow.getPictures();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current page size
|
||||
*/
|
||||
public Dimension getPageSize(){
|
||||
DocumentAtom docatom = _documentRecord.getDocumentAtom();
|
||||
return new Dimension((int)docatom.getSlideSizeX(), (int)docatom.getSlideSizeY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for usermodel: Get the font collection
|
||||
*/
|
||||
protected FontCollection getFontCollection() { return _fonts; }
|
||||
/**
|
||||
* Helper method for usermodel: Get the document record
|
||||
*/
|
||||
protected Document getDocumentRecord() { return _documentRecord; }
|
||||
|
||||
|
||||
/* ===============================================================
|
||||
* Addition Code
|
||||
* ===============================================================
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Create a blank <code>Slide</code>.
|
||||
*
|
||||
|
@ -476,63 +563,87 @@ public class SlideShow
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes out the slideshow file the is represented by an instance of
|
||||
* this class
|
||||
* @param out The OutputStream to write to.
|
||||
* @throws IOException If there is an unexpected IOException from the passed
|
||||
* in OutputStream
|
||||
*/
|
||||
public void write(OutputStream out) throws IOException {
|
||||
_hslfSlideShow.write(out);
|
||||
}
|
||||
/**
|
||||
* Adds a picture to this presentation and returns the associated index.
|
||||
*
|
||||
* @param data picture data
|
||||
* @param format the format of the picture. One of constans defined in the <code>Picture</code> class.
|
||||
* @return the index to this picture (1 based).
|
||||
*/
|
||||
public int addPicture(byte[] data, int format) {
|
||||
byte[] uid = PictureData.getChecksum(data);
|
||||
|
||||
EscherContainerRecord bstore;
|
||||
int offset = 0;
|
||||
|
||||
// Accesser methods follow
|
||||
EscherContainerRecord dggContainer = _documentRecord.getPPDrawingGroup().getDggContainer();
|
||||
bstore = (EscherContainerRecord)Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
|
||||
if (bstore == null){
|
||||
bstore = new EscherContainerRecord();
|
||||
bstore.setRecordId( EscherContainerRecord.BSTORE_CONTAINER);
|
||||
|
||||
/**
|
||||
* Returns an array of the most recent version of all the interesting
|
||||
* records
|
||||
*/
|
||||
public Record[] getMostRecentCoreRecords() { return _mostRecentCoreRecords; }
|
||||
List child = dggContainer.getChildRecords();
|
||||
for ( int i = 0; i < child.size(); i++ ) {
|
||||
EscherRecord rec = (EscherRecord)child.get(i);
|
||||
if (rec.getRecordId() == EscherOptRecord.RECORD_ID){
|
||||
child.add(i, bstore);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
dggContainer.setChildRecords(child);
|
||||
} else {
|
||||
List lst = bstore.getChildRecords();
|
||||
for ( int i = 0; i < lst.size(); i++ ) {
|
||||
EscherBSERecord bse = (EscherBSERecord) lst.get(i);
|
||||
if (Arrays.equals(bse.getUid(), uid)){
|
||||
return i + 1;
|
||||
}
|
||||
offset += bse.getSize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all the normal Slides found in the slideshow
|
||||
*/
|
||||
public Slide[] getSlides() { return _slides; }
|
||||
EscherBSERecord bse = new EscherBSERecord();
|
||||
bse.setRecordId(EscherBSERecord.RECORD_ID);
|
||||
bse.setOptions( (short) ( 0x0002 | ( format << 4 ) ) );
|
||||
bse.setSize(data.length + PictureData.HEADER_SIZE);
|
||||
bse.setUid(uid);
|
||||
bse.setBlipTypeMacOS((byte)format);
|
||||
bse.setBlipTypeWin32((byte)format);
|
||||
|
||||
/**
|
||||
* Returns an array of all the normal Notes found in the slideshow
|
||||
*/
|
||||
public Notes[] getNotes() { return _notes; }
|
||||
bse.setRef(1);
|
||||
bse.setOffset(offset);
|
||||
|
||||
/**
|
||||
* Returns an array of all the meta Sheets (master sheets etc)
|
||||
* found in the slideshow
|
||||
*/
|
||||
//public MetaSheet[] getMetaSheets() { return _msheets; }
|
||||
bstore.addChildRecord(bse);
|
||||
int count = bstore.getChildRecords().size();
|
||||
bstore.setOptions((short)( (count << 4) | 0xF ));
|
||||
|
||||
/**
|
||||
* Returns all the pictures attached to the SlideShow
|
||||
*/
|
||||
public Picture[] getPictures() throws IOException {
|
||||
return _hslfSlideShow.getPictures();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current page size
|
||||
*/
|
||||
public Dimension getPageSize(){
|
||||
DocumentAtom docatom = _documentRecord.getDocumentAtom();
|
||||
return new Dimension((int)docatom.getSlideSizeX(), (int)docatom.getSlideSizeY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for usermodel: Get the font collection
|
||||
*/
|
||||
protected FontCollection getFontCollection() { return _fonts; }
|
||||
/**
|
||||
* Helper method for usermodel: Get the document record
|
||||
*/
|
||||
protected Document getDocumentRecord() { return _documentRecord; }
|
||||
PictureData pict = new PictureData();
|
||||
pict.setUID(uid);
|
||||
pict.setData(data);
|
||||
pict.setType(format);
|
||||
|
||||
_hslfSlideShow.addPicture(pict);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a picture to this presentation and returns the associated index.
|
||||
*
|
||||
* @param pict the file containing the image to add
|
||||
* @param format the format of the picture. One of constans defined in the <code>Picture</code> class.
|
||||
* @return the index to this picture (1 based).
|
||||
*/
|
||||
public int addPicture(File pict, int format) {
|
||||
int length = (int)pict.length();
|
||||
byte[] data = new byte[length];
|
||||
try {
|
||||
FileInputStream is = new FileInputStream(pict);
|
||||
is.read(data);
|
||||
is.close();
|
||||
} catch (IOException e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return addPicture(data, format);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue