Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-639241,639243-639253,639255-639486,639488-639601,639603-639835,639837-639917,639919-640056,640058-640710,640712-641156,641158-641184,641186-641795,641797-641798,641800-641933,641935-641963,641965-641966,641968-641995,641997-642230,642232-642562,642564-642565,642568-642570,642572-642573,642576-642736,642739-642877,642879,642881-642890,642892-642903,642905-642945,642947-643624,643626-643653,643655-643669,643671,643673-643830,643832-643833,643835-644342,644344-644472,644474-644508,644510-645347,645349-645351,645353-645559,645561-645565,645568-645951,645953-646193,646195-646311,646313-646404,646406-646665,646667-646853,646855-646869,646871-647151,647153-647185,647187-647277,647279-647566,647568-647573,647575,647578-647711,647714-647737,647739-647823,647825-648155,648157-648202,648204-648273,648275,648277-648302,648304-648333,648335-650914,650916-650920 via svnmerge from
https://svn.apache.org:443/repos/asf/poi/trunk ........ r648589 | yegor | 2008-04-16 08:47:16 +0100 (Wed, 16 Apr 2008) | 1 line bug #41071 is fixed in trunk. Added a unit test and resolved. ........ r648623 | yegor | 2008-04-16 09:43:08 +0100 (Wed, 16 Apr 2008) | 1 line Rich text in HSSFTextbox must have at least one format run. Make sure it is so and apply th default fopnt if no formats were applied. ........ r648624 | yegor | 2008-04-16 09:44:07 +0100 (Wed, 16 Apr 2008) | 1 line Misc improvements in Freeform shape ........ r648674 | yegor | 2008-04-16 12:57:15 +0100 (Wed, 16 Apr 2008) | 1 line Support for getting OLE object data from slide show ........ r649142 | yegor | 2008-04-17 16:06:01 +0100 (Thu, 17 Apr 2008) | 1 line added a unit test and closed bug #28774 ........ r649143 | yegor | 2008-04-17 16:08:03 +0100 (Thu, 17 Apr 2008) | 1 line initial support for rendering powerpoint slides into images ........ r649145 | yegor | 2008-04-17 16:09:37 +0100 (Thu, 17 Apr 2008) | 1 line updated the list of changes ........ r649557 | yegor | 2008-04-18 15:57:07 +0100 (Fri, 18 Apr 2008) | 1 line improved rendering of text ........ r649796 | yegor | 2008-04-19 12:09:59 +0100 (Sat, 19 Apr 2008) | 1 line Support for getting embedded sounds from slide show ........ r649797 | yegor | 2008-04-19 12:16:53 +0100 (Sat, 19 Apr 2008) | 1 line properly set shapeId for new shapes ........ r649798 | yegor | 2008-04-19 12:17:37 +0100 (Sat, 19 Apr 2008) | 1 line misc improvements in slide rendering ........ r649800 | yegor | 2008-04-19 12:52:36 +0100 (Sat, 19 Apr 2008) | 1 line updated the docs ........ r649911 | yegor | 2008-04-20 12:17:48 +0100 (Sun, 20 Apr 2008) | 1 line more improvements in slide rendering ........ r649914 | yegor | 2008-04-20 12:58:08 +0100 (Sun, 20 Apr 2008) | 1 line set version.id=3.0.3-beta1 ........ r650129 | yegor | 2008-04-21 13:51:47 +0100 (Mon, 21 Apr 2008) | 1 line more improvements in slide rendering ........ r650130 | yegor | 2008-04-21 13:52:23 +0100 (Mon, 21 Apr 2008) | 1 line a couple of HSLF examples ........ r650133 | yegor | 2008-04-21 14:10:33 +0100 (Mon, 21 Apr 2008) | 1 line update current version to 3.1-beta1 ........ r650138 | yegor | 2008-04-21 14:29:59 +0100 (Mon, 21 Apr 2008) | 1 line unfinished release guide. It would be nice to have a html version. ........ r650139 | yegor | 2008-04-21 14:31:53 +0100 (Mon, 21 Apr 2008) | 1 line unfinished release guide. It would be nice to have a html version. ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@650938 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
eebb380b95
commit
c6a1c586b5
@ -43,7 +43,13 @@
|
||||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
|
||||
</release>
|
||||
<release version="3.0.3-beta1" date="2008-04-??">
|
||||
<release version="3.1-beta1" date="2008-04-??">
|
||||
<action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting embedded sounds from slide show </action>
|
||||
<action dev="POI-DEVELOPERS" type="add">HSLF: Initial support for rendering slides into images</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting OLE object data from slide show </action>
|
||||
<action dev="POI-DEVELOPERS" type="add">HSLF: Implemented more methods in PPGraphics2D</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">HSLF: Added Freeform shape which can contain both lines and Bezier curves</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">41071 - Improved text extraction in HSLF</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">30311 - Conditional Formatting - improved API, added HSSFSheetConditionalFormatting</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">Update the formula parser code to use a HSSFWorkbook, rather than the low level model.Workbook, to make things cleaner and make supporting XSSF formulas in future much easier</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">Fix the logger used by POIFSFileSystem, so that commons-logging isn't required when not used</action>
|
||||
|
@ -136,8 +136,7 @@
|
||||
</section>
|
||||
<section><title>HSLF for PowerPoint Documents</title>
|
||||
<p>HSLF is our port of the Microsoft PowerPoint 97(-2003) file format to pure
|
||||
Java. It supports read and write capabilities of some, but not yet all
|
||||
of the core records. Please see <link
|
||||
Java. It supports read and write capabilities. Please see <link
|
||||
href="./slideshow/index.html">the HSLF project page for more
|
||||
information</link>.</p>
|
||||
</section>
|
||||
|
@ -61,9 +61,9 @@
|
||||
<section><title>Files embeded in PowerPoint</title>
|
||||
<p>PowerPoint does not normally store embeded files
|
||||
in the OLE2 layer. Instead, they are held within records
|
||||
of the main PowerPoint file. To get at them, you need to
|
||||
find the appropriate data within the PowerPoint stream,
|
||||
and work from that.</p>
|
||||
of the main PowerPoint file.
|
||||
<br/>See the <link href="./../hslf/how-to-shapes.html#OLE">HSLF Tutorial</link>
|
||||
for how to retrieve embedded OLE objects from a presentation</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
@ -40,6 +40,12 @@
|
||||
<li><link href="#Bullets">How to create bulleted lists</link></li>
|
||||
<li><link href="#Hyperlinks">Hyperlinks</link></li>
|
||||
<li><link href="#Tables">Tables</link></li>
|
||||
<li><link href="#RemoveShape">How to remove shapes</link></li>
|
||||
<li><link href="#OLE">How to retrieve embedded OLE objects</link></li>
|
||||
<li><link href="#Sound">How to retrieve embedded sounds</link></li>
|
||||
<li><link href="#Freeform">How to create shapes of arbitrary geometry</link></li>
|
||||
<li><link href="#Graphics2D">Shapes and Graphics2D</link></li>
|
||||
<li><link href="#Render">How to convert slides into images</link></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section><title>Features</title>
|
||||
@ -80,14 +86,8 @@
|
||||
</section>
|
||||
<anchor id="GetShapes"/>
|
||||
<section><title>How to get shapes contained in a particular slide</title>
|
||||
<p>The superclass of all shapes in HSLF is the Shape class - the elemental object that composes a drawing.
|
||||
The following pictute shows the class tree of HSLF shapes:
|
||||
</p>
|
||||
<p>
|
||||
<img src="images/hslf_shapes.gif" alt="Class Tree of HSLF Shapes" width="611" height="412"/>
|
||||
</p>
|
||||
<p>
|
||||
The following fragment demonstrates how to iterate over shapes for each slide.
|
||||
The following code demonstrates how to iterate over shapes for each slide.
|
||||
</p>
|
||||
<source>
|
||||
SlideShow ppt = new SlideShow(new HSLFSlideShow("slideshow.ppt"));
|
||||
@ -440,7 +440,186 @@
|
||||
</source>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
<anchor id="RemoveShape"/>
|
||||
<section><title>How to remove shapes from a slide</title>
|
||||
<source>
|
||||
|
||||
Shape[] shape = slide.getShapes();
|
||||
for (int i = 0; i < shape.length; i++) {
|
||||
|
||||
//remove the shape
|
||||
boolean ok = slide.removeShape(shape[i]);
|
||||
if(ok){
|
||||
//the shape was removed. Do something.
|
||||
}
|
||||
}
|
||||
</source>
|
||||
</section>
|
||||
<anchor id="OLE"/>
|
||||
<section><title>How to retrieve embedded OLE objects</title>
|
||||
<source>
|
||||
|
||||
Shape[] shape = slide.getShapes();
|
||||
for (int i = 0; i < shape.length; i++) {
|
||||
if (shape[i] instanceof OLEShape) {
|
||||
OLEShape ole = (OLEShape) shape[i];
|
||||
ObjectData data = ole.getObjectData();
|
||||
String name = ole.getInstanceName();
|
||||
if ("Worksheet".equals(name)) {
|
||||
HSSFWorkbook wb = new HSSFWorkbook(data.getData());
|
||||
} else if ("Document".equals(name)) {
|
||||
HWPFDocument doc = new HWPFDocument(data.getData());
|
||||
}
|
||||
}
|
||||
}
|
||||
</source>
|
||||
</section>
|
||||
|
||||
<anchor id="Sound"/>
|
||||
<section><title>How to retrieve embedded sounds</title>
|
||||
<source>
|
||||
|
||||
FileInputStream is = new FileInputStream(args[0]);
|
||||
SlideShow ppt = new SlideShow(is);
|
||||
is.close();
|
||||
|
||||
SoundData[] sound = ppt.getSoundData();
|
||||
for (int i = 0; i < sound.length; i++) {
|
||||
//save *WAV sounds on disk
|
||||
if(sound[i].getSoundType().equals(".WAV")){
|
||||
FileOutputStream out = new FileOutputStream(sound[i].getSoundName());
|
||||
out.write(sound[i].getData());
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
</source>
|
||||
</section>
|
||||
|
||||
<anchor id="Freeform"/>
|
||||
<section><title>How to create shapes of arbitrary geometry</title>
|
||||
<source>
|
||||
|
||||
SlideShow ppt = new SlideShow();
|
||||
Slide slide = ppt.createSlide();
|
||||
|
||||
java.awt.geom.GeneralPath path = new java.awt.geom.GeneralPath();
|
||||
path.moveTo(100, 100);
|
||||
path.lineTo(200, 100);
|
||||
path.curveTo(50, 45, 134, 22, 78, 133);
|
||||
path.curveTo(10, 45, 134, 56, 78, 100);
|
||||
path.lineTo(100, 200);
|
||||
path.closePath();
|
||||
|
||||
Freeform shape = new Freeform();
|
||||
shape.setPath(path);
|
||||
slide.addShape(shape);
|
||||
</source>
|
||||
</section>
|
||||
|
||||
<anchor id="Graphics2D"/>
|
||||
<section><title>How to draw into a slide using Graphics2D</title>
|
||||
<warning>
|
||||
Current implementation of the PowerPoint Graphics2D driver is not fully compliant with the java.awt.Graphics2D specification.
|
||||
Some features like clipping, drawing of images are not yet supported.
|
||||
</warning>
|
||||
<source>
|
||||
SlideShow ppt = new SlideShow();
|
||||
Slide slide = ppt.createSlide();
|
||||
|
||||
//draw a simple bar graph
|
||||
//bar chart data. The first value is the bar color, the second is the width
|
||||
Object[] def = new Object[]{
|
||||
Color.yellow, new Integer(100),
|
||||
Color.green, new Integer(150),
|
||||
Color.gray, new Integer(75),
|
||||
Color.red, new Integer(200),
|
||||
};
|
||||
|
||||
//all objects are drawn into a shape group so we need to create one
|
||||
|
||||
ShapeGroup group = new ShapeGroup();
|
||||
//define position of the drawing in the slide
|
||||
Rectangle bounds = new java.awt.Rectangle(200, 100, 350, 300);
|
||||
//if you want to draw in the entire slide area then define the anchor as follows:
|
||||
//Dimension pgsize = ppt.getPageSize();
|
||||
//java.awt.Rectangle bounds = new java.awt.Rectangle(0, 0, pgsize.width, pgsize.height);
|
||||
|
||||
group.setAnchor(bounds);
|
||||
slide.addShape(group);
|
||||
|
||||
//draw a simple bar chart
|
||||
Graphics2D graphics = new PPGraphics2D(group);
|
||||
int x = bounds.x + 50, y = bounds.y + 50;
|
||||
graphics.setFont(new Font("Arial", Font.BOLD, 10));
|
||||
for (int i = 0, idx = 1; i < def.length; i+=2, idx++) {
|
||||
graphics.setColor(Color.black);
|
||||
int width = ((Integer)def[i+1]).intValue();
|
||||
graphics.drawString("Q" + idx, x-20, y+20);
|
||||
graphics.drawString(width + "%", x + width + 10, y + 20);
|
||||
graphics.setColor((Color)def[i]);
|
||||
graphics.fill(new Rectangle(x, y, width, 30));
|
||||
y += 40;
|
||||
}
|
||||
graphics.setColor(Color.black);
|
||||
graphics.setFont(new Font("Arial", Font.BOLD, 14));
|
||||
graphics.draw(bounds);
|
||||
graphics.drawString("Performance", x + 70, y + 40);
|
||||
|
||||
FileOutputStream out = new FileOutputStream("hslf-graphics2d.ppt");
|
||||
ppt.write(out);
|
||||
out.close();
|
||||
|
||||
</source>
|
||||
</section>
|
||||
|
||||
<anchor id="Render"/>
|
||||
<section><title>Export PowerPoint slides into java.awt.Graphics2D</title>
|
||||
<p>
|
||||
HSLF provides a way to export slides into images. You can capture slides into java.awt.Graphics2D object (or any other)
|
||||
and serialize it into a PNG or JPEG format. Please note, although HSLF attempts to render slides as close to PowerPoint as possible,
|
||||
the output may look differently from PowerPoint due to the following reasons:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Java2D renders fonts differently vs PowerPoint. There are always some differences in the way the font glyphs are painted</li>
|
||||
<li>HSLF uses java.awt.font.LineBreakMeasurer to break text into lines. PowerPoint may do it in a different way.</li>
|
||||
<li>If a font from the presentation is not avaiable, then the JDK default font will be used.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Current Limitations:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Some types of shapes are not yet supported (WordArt, complex auto-shapes)</li>
|
||||
<li>Only Bitmap images (PNG, JPEG, DIB) can be rendered in Java</li>
|
||||
</ul>
|
||||
<source>
|
||||
FileInputStream is = new FileInputStream("slideshow.ppt");
|
||||
SlideShow ppt = new SlideShow(is);
|
||||
is.close();
|
||||
|
||||
Dimension pgsize = ppt.getPageSize();
|
||||
|
||||
Slide[] slide = ppt.getSlides();
|
||||
for (int i = 0; i < slide.length; i++) {
|
||||
|
||||
BufferedImage img = new BufferedImage(pgsize.width, pgsize.height, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D graphics = img.createGraphics();
|
||||
//clear the drawing area
|
||||
graphics.setPaint(Color.white);
|
||||
graphics.fill(new Rectangle2D.Float(0, 0, pgsize.width, pgsize.height));
|
||||
|
||||
//render
|
||||
slide[i].draw(graphics);
|
||||
|
||||
//save the output
|
||||
FileOutputStream out = new FileOutputStream("slide-" + (i+1) + ".png");
|
||||
javax.imageio.ImageIO.write(img, "png", out);
|
||||
out.close();
|
||||
}
|
||||
|
||||
</source>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
</section>
|
||||
</body>
|
||||
</document>
|
||||
|
@ -26,6 +26,7 @@
|
||||
<authors>
|
||||
<person name="Avik Sengupta" email="avik at apache dot org"/>
|
||||
<person name="Nick Burch" email="nick at apache dot org"/>
|
||||
<person name="Yegor Kozlov" email="yegor at apache dot org"/>
|
||||
</authors>
|
||||
</header>
|
||||
|
||||
@ -37,9 +38,12 @@
|
||||
Powerpoint '97(-2007) file format. It <em>does not</em> support
|
||||
the new PowerPoint 2007 .pptx file format, which is not OLE2
|
||||
based.</p>
|
||||
<p>HSLF provides a way to read powerpoint presentations, and extract text from it.
|
||||
It also provides some (currently limited) edit capabilities.
|
||||
<p>HSLF provides a way to read, create or modify PowerPoint presentations. In particular, it provides:
|
||||
</p>
|
||||
<ul>
|
||||
<li>api for data extraction (text, pictures, embedded objects, sounds)</li>
|
||||
<li>usermodel api for creating, reading and modifying ppt files</li>
|
||||
</ul>
|
||||
<note>
|
||||
This code currently lives the
|
||||
<link href="http://svn.apache.org/viewcvs.cgi/poi/trunk/src/scratchpad/">scratchpad area</link>
|
||||
|
@ -40,7 +40,13 @@
|
||||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
|
||||
</release>
|
||||
<release version="3.0.3-beta1" date="2008-04-??">
|
||||
<release version="3.1-beta1" date="2008-04-??">
|
||||
<action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting embedded sounds from slide show </action>
|
||||
<action dev="POI-DEVELOPERS" type="add">HSLF: Initial support for rendering slides into images</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting OLE object data from slide show </action>
|
||||
<action dev="POI-DEVELOPERS" type="add">HSLF: Implemented more methods in PPGraphics2D</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">HSLF: Added Freeform shape which can contain both lines and Bezier curves</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">41071 - Improved text extraction in HSLF</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">30311 - Conditional Formatting - improved API, added HSSFSheetConditionalFormatting</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">Update the formula parser code to use a HSSFWorkbook, rather than the low level model.Workbook, to make things cleaner and make supporting XSSF formulas in future much easier</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">Fix the logger used by POIFSFileSystem, so that commons-logging isn't required when not used</action>
|
||||
|
135
src/documentation/release-guide.txt
Executable file
135
src/documentation/release-guide.txt
Executable file
@ -0,0 +1,135 @@
|
||||
POI Release Guide
|
||||
|
||||
|
||||
(I) Prerequisites
|
||||
|
||||
1. You should read the <a href="http://apache.org/dev/release.html">Apache Release FAQ</a>
|
||||
2. You must have shell access to people.apache.org
|
||||
3. Release manager must have his public key appended to the KEYS file checked in to SVN and the key published on one of the public key servers.
|
||||
More info can be found here: <a href="http://www.apache.org/dev/release-signing.html">http://www.apache.org/dev/release-signing.html</a>
|
||||
4. You must have <a href="java.sun.com">JDK 1.4 / 1.5</a>
|
||||
5. You must have the following utilities installed on your local machine and available in your path:
|
||||
* <a href="www.openssh.com">ssh</a>
|
||||
* <a href="www.gnupg.org">gnupg</a>
|
||||
* <a href="www.openssl.org">openssl</a>
|
||||
For Windows users, install Cygwin and make sure you have the above utilities
|
||||
6. The POI build system requires two components to perform a build
|
||||
* <a href="ant.apache.org">Ant</a>
|
||||
* <a href="http://forrest.apache.org/">Forrest</a>.
|
||||
POI 3.0.2 and 3.1 were built using Ant 1.6.2 and Forrest 0.5
|
||||
|
||||
(II) Making release artefacts
|
||||
1. Update version id in build.xml.
|
||||
2. Tag current version. Include the current revision number in the comment
|
||||
|
||||
{code}
|
||||
$ svn cp https://svn.apache.org/repos/asf/poi/trunk \
|
||||
https://svn.apache.org/repos/asf/poi/tags/$TAG \
|
||||
-m "tag r649911 as 3.1-beta1"
|
||||
{code}
|
||||
|
||||
where $TAG is the release tag, for example, REL_3_1_BETA1
|
||||
|
||||
3. Checkout the tagged version
|
||||
{code}
|
||||
cd tags
|
||||
svn checkout https://svn.apache.org/repos/asf/poi/tags/TAG
|
||||
{code}
|
||||
|
||||
4. Merge (if required)
|
||||
|
||||
{code}
|
||||
cd $TAG
|
||||
$ svn merge https://svn.apache.org/repos/asf/poi/tags/TAG \
|
||||
https://svn.apache.org/repos/asf/poi/trunk
|
||||
{code}
|
||||
|
||||
5. Start a new section in sites.xml and status.xml.
|
||||
|
||||
6. Build as if the vote had passed. The buid date must be +7 days from current.
|
||||
{code}
|
||||
ant build
|
||||
{code}
|
||||
After build you should have the following files in the build/dist:
|
||||
|
||||
{code}
|
||||
poi-$TAG-$DATE.jar
|
||||
poi-bin-$TAG-$DATE.tar.gz
|
||||
poi-bin-$TAG-$DATE.zip
|
||||
poi-contrib-$TAG-$DATE.jar
|
||||
poi-scratchpad-$TAG-$DATE.jar
|
||||
poi-src-$TAG-$DATE.tar.gz
|
||||
poi-src-$TAG-$DATE.zip
|
||||
{code}
|
||||
|
||||
where $TAG is the release tag specified in build.xml in the version.id property, $DATE is the release date (typically +7 days from the actual build date).
|
||||
7. Build Mavn POM files
|
||||
{code}
|
||||
ant maven-dist
|
||||
{code}
|
||||
|
||||
8. Signing the release artifacts:
|
||||
{code}
|
||||
cd build/dist
|
||||
for i in *.zip ; do
|
||||
gpg --armor --output $i.asc --detach-sig $i;
|
||||
done
|
||||
for i in *.gz ; do
|
||||
gpg --armor --output $i.asc --detach-sig $i;
|
||||
done
|
||||
{code}
|
||||
|
||||
Verify the signatures:
|
||||
|
||||
{code}
|
||||
gpg --multifile --verify *.asc
|
||||
{code}
|
||||
|
||||
9. Create MD5 checksums for all artifacts to be published:
|
||||
|
||||
{code}
|
||||
for i in *.zip ; do
|
||||
openssl md5 < $i > $i.md5
|
||||
done
|
||||
for i in *.gz ; do
|
||||
openssl md5 < $i > $i.md5
|
||||
done
|
||||
{code}
|
||||
|
||||
10. Upload to your area at people.apache.org.
|
||||
There should be two directories:
|
||||
main
|
||||
maven
|
||||
|
||||
Make sure that the all files have read permission.
|
||||
|
||||
(III) After the vote:
|
||||
|
||||
Log-in on people.apache.org
|
||||
|
||||
1. Go to ~/POI-3.1-BETA1
|
||||
|
||||
cd ~/POI-3.1-BETA1/main
|
||||
|
||||
BETA and ALPHA releases:
|
||||
cp *-src-* /www/www.apache.org/dist/poi/dev/src
|
||||
cp *-bin-* /www/www.apache.org/dist/poi/dev/bin
|
||||
|
||||
FINAL release:
|
||||
cp *-src-* /www/www.apache.org/dist/poi/release/src
|
||||
cp *-bin-* /www/www.apache.org/dist/poi/release/bin
|
||||
|
||||
cd ~/POI-3.1-BETA1/maven
|
||||
|
||||
cp -r org.apache.poi /www/people.apache.org/repo/m1-ibiblio-rsync-repository/
|
||||
cp -r poi/poms /www/people.apache.org/repo/m1-ibiblio-rsync-repository/poi
|
||||
|
||||
|
||||
2. Make sure that the files are owned by the unix group apcvs and that they are writable by this group.
|
||||
|
||||
3. Wait for the distributions to appear on your favourite mirror
|
||||
|
||||
4. Send announcements:
|
||||
- to poi-user and poi-dev lists
|
||||
- send announcements to announcement@apache.org, announcements@jakarta.apache.org
|
||||
|
@ -83,7 +83,12 @@ public class HSSFTextbox
|
||||
*/
|
||||
public void setString( RichTextString string )
|
||||
{
|
||||
this.string = (HSSFRichTextString) string;
|
||||
HSSFRichTextString rtr = (HSSFRichTextString)string;
|
||||
|
||||
// If font is not set we must set the default one
|
||||
if (rtr.numFormattingRuns() == 0) rtr.applyFont((short)0);
|
||||
|
||||
this.string = rtr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
148
src/scratchpad/examples/src/org/apache/poi/hslf/examples/DataExtraction.java
Executable file
148
src/scratchpad/examples/src/org/apache/poi/hslf/examples/DataExtraction.java
Executable file
@ -0,0 +1,148 @@
|
||||
|
||||
/* ====================================================================
|
||||
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.hslf.examples;
|
||||
|
||||
import org.apache.poi.hslf.usermodel.*;
|
||||
import org.apache.poi.hslf.model.*;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.hwpf.HWPFDocument;
|
||||
import org.apache.poi.hwpf.usermodel.Range;
|
||||
import org.apache.poi.hwpf.usermodel.Paragraph;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Demonstrates how you can extract misc embedded data from a ppt file
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class DataExtraction {
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
|
||||
if (args.length == 0) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
FileInputStream is = new FileInputStream(args[0]);
|
||||
SlideShow ppt = new SlideShow(is);
|
||||
is.close();
|
||||
|
||||
//extract all sound files embedded in this presentation
|
||||
SoundData[] sound = ppt.getSoundData();
|
||||
for (int i = 0; i < sound.length; i++) {
|
||||
String type = sound[i].getSoundType(); //*.wav
|
||||
String name = sound[i].getSoundName(); //typically file name
|
||||
byte[] data = sound[i].getData(); //raw bytes
|
||||
|
||||
//save the sound on disk
|
||||
FileOutputStream out = new FileOutputStream(name + type);
|
||||
out.write(data);
|
||||
out.close();
|
||||
}
|
||||
|
||||
//extract embedded OLE documents
|
||||
Slide[] slide = ppt.getSlides();
|
||||
for (int i = 0; i < slide.length; i++) {
|
||||
Shape[] shape = slide[i].getShapes();
|
||||
for (int j = 0; j < shape.length; j++) {
|
||||
if (shape[j] instanceof OLEShape) {
|
||||
OLEShape ole = (OLEShape) shape[j];
|
||||
ObjectData data = ole.getObjectData();
|
||||
String name = ole.getInstanceName();
|
||||
if ("Worksheet".equals(name)) {
|
||||
|
||||
//save xls on disk
|
||||
FileOutputStream out = new FileOutputStream(name + "-("+(j)+").xls");
|
||||
InputStream dis = data.getData();
|
||||
byte[] chunk = new byte[2048];
|
||||
int count;
|
||||
while ((count = dis.read(chunk)) >= 0) {
|
||||
out.write(chunk,0,count);
|
||||
}
|
||||
is.close();
|
||||
out.close();
|
||||
} else if ("Document".equals(name)) {
|
||||
HWPFDocument doc = new HWPFDocument(data.getData());
|
||||
//read the word document
|
||||
Range r = doc.getRange();
|
||||
for(int k = 0; k < r.numParagraphs(); k++) {
|
||||
Paragraph p = r.getParagraph(k);
|
||||
System.out.println(p.text());
|
||||
}
|
||||
|
||||
//save on disk
|
||||
FileOutputStream out = new FileOutputStream(name + "-("+(j)+").doc");
|
||||
doc.write(out);
|
||||
out.close();
|
||||
} else {
|
||||
System.err.println("Processing " + name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//Pictures
|
||||
for (int i = 0; i < slide.length; i++) {
|
||||
Shape[] shape = slide[i].getShapes();
|
||||
for (int j = 0; j < shape.length; j++) {
|
||||
if (shape[j] instanceof Picture) {
|
||||
Picture p = (Picture) shape[j];
|
||||
PictureData data = p.getPictureData();
|
||||
String name = p.getPictureName();
|
||||
int type = data.getType();
|
||||
String ext;
|
||||
switch (type) {
|
||||
case Picture.JPEG:
|
||||
ext = ".jpg";
|
||||
break;
|
||||
case Picture.PNG:
|
||||
ext = ".png";
|
||||
break;
|
||||
case Picture.WMF:
|
||||
ext = ".wmf";
|
||||
break;
|
||||
case Picture.EMF:
|
||||
ext = ".emf";
|
||||
break;
|
||||
case Picture.PICT:
|
||||
ext = ".pict";
|
||||
break;
|
||||
case Picture.DIB:
|
||||
ext = ".dib";
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
FileOutputStream out = new FileOutputStream("pict-" + j + ext);
|
||||
out.write(data.getData());
|
||||
out.close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void usage(){
|
||||
System.out.println("Usage: DataExtraction ppt");
|
||||
}
|
||||
}
|
80
src/scratchpad/examples/src/org/apache/poi/hslf/examples/Graphics2DDemo.java
Executable file
80
src/scratchpad/examples/src/org/apache/poi/hslf/examples/Graphics2DDemo.java
Executable file
@ -0,0 +1,80 @@
|
||||
|
||||
/* ====================================================================
|
||||
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.hslf.examples;
|
||||
|
||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||
import org.apache.poi.hslf.model.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
|
||||
/**
|
||||
* Demonstrates how to draw into a slide using the HSLF Graphics2D driver.
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class Graphics2DDemo {
|
||||
|
||||
/**
|
||||
* A simple bar chart demo
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
SlideShow ppt = new SlideShow();
|
||||
|
||||
//bar chart data. The first value is the bar color, the second is the width
|
||||
Object[] def = new Object[]{
|
||||
Color.yellow, new Integer(40),
|
||||
Color.green, new Integer(60),
|
||||
Color.gray, new Integer(30),
|
||||
Color.red, new Integer(80),
|
||||
};
|
||||
|
||||
Slide slide = ppt.createSlide();
|
||||
|
||||
ShapeGroup group = new ShapeGroup();
|
||||
//define position of the drawing in the slide
|
||||
Rectangle bounds = new java.awt.Rectangle(200, 100, 350, 300);
|
||||
group.setAnchor(bounds);
|
||||
group.setCoordinates(new java.awt.Rectangle(0, 0, 100, 100));
|
||||
slide.addShape(group);
|
||||
Graphics2D graphics = new PPGraphics2D(group);
|
||||
|
||||
//draw a simple bar graph
|
||||
int x = 10, y = 10;
|
||||
graphics.setFont(new Font("Arial", Font.BOLD, 10));
|
||||
for (int i = 0, idx = 1; i < def.length; i+=2, idx++) {
|
||||
graphics.setColor(Color.black);
|
||||
int width = ((Integer)def[i+1]).intValue();
|
||||
graphics.drawString("Q" + idx, x-5, y+10);
|
||||
graphics.drawString(width + "%", x + width+3, y + 10);
|
||||
graphics.setColor((Color)def[i]);
|
||||
graphics.fill(new Rectangle(x, y, width, 10));
|
||||
y += 15;
|
||||
}
|
||||
graphics.setColor(Color.black);
|
||||
graphics.setFont(new Font("Arial", Font.BOLD, 14));
|
||||
graphics.draw(group.getCoordinates());
|
||||
graphics.drawString("Performance", x + 30, y + 10);
|
||||
|
||||
FileOutputStream out = new FileOutputStream("hslf-graphics.ppt");
|
||||
ppt.write(out);
|
||||
out.close();
|
||||
}
|
||||
|
||||
}
|
108
src/scratchpad/examples/src/org/apache/poi/hslf/examples/PPT2PNG.java
Executable file
108
src/scratchpad/examples/src/org/apache/poi/hslf/examples/PPT2PNG.java
Executable file
@ -0,0 +1,108 @@
|
||||
|
||||
/* ====================================================================
|
||||
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.hslf.examples;
|
||||
|
||||
import org.apache.poi.hslf.usermodel.*;
|
||||
import org.apache.poi.hslf.model.*;
|
||||
import org.apache.poi.hslf.record.TextHeaderAtom;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.io.IOException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
* Demonstrates how you can use HSLF to convert each slide into a PNG image
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class PPT2PNG {
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
|
||||
if (args.length == 0) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
int slidenum = -1;
|
||||
float scale = 1;
|
||||
String file = null;
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i].startsWith("-")) {
|
||||
if ("-scale".equals(args[i])){
|
||||
scale = Float.parseFloat(args[++i]);
|
||||
} else if ("-slide".equals(args[i])) {
|
||||
slidenum = Integer.parseInt(args[++i]);
|
||||
}
|
||||
} else {
|
||||
file = args[i];
|
||||
}
|
||||
}
|
||||
if(file == null){
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
FileInputStream is = new FileInputStream(file);
|
||||
SlideShow ppt = new SlideShow(is);
|
||||
is.close();
|
||||
|
||||
Dimension pgsize = ppt.getPageSize();
|
||||
int width = (int)(pgsize.width*scale);
|
||||
int height = (int)(pgsize.height*scale);
|
||||
|
||||
Slide[] slide = ppt.getSlides();
|
||||
for (int i = 0; i < slide.length; i++) {
|
||||
if (slidenum != -1 && slidenum != (i+1)) continue;
|
||||
|
||||
String title = slide[i].getTitle();
|
||||
System.out.println("Rendering slide "+slide[i].getSlideNumber() + (title == null ? "" : ": " + title));
|
||||
|
||||
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D graphics = img.createGraphics();
|
||||
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||
graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
|
||||
|
||||
graphics.setPaint(Color.white);
|
||||
graphics.fill(new Rectangle2D.Float(0, 0, width, height));
|
||||
|
||||
graphics.scale((double)width/pgsize.width, (double)height/pgsize.height);
|
||||
|
||||
slide[i].draw(graphics);
|
||||
|
||||
String fname = file.replaceAll("\\.ppt", "-" + (i+1) + ".png");
|
||||
FileOutputStream out = new FileOutputStream(fname);
|
||||
ImageIO.write(img, "png", out);
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void usage(){
|
||||
System.out.println("Usage: PPT2PNG [-scale <scale> -slide <num>] ppt");
|
||||
}
|
||||
}
|
@ -27,22 +27,13 @@ import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.poi.POIDocument;
|
||||
import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
|
||||
import org.apache.poi.hslf.exceptions.EncryptedPowerPointFileException;
|
||||
import org.apache.poi.hslf.exceptions.HSLFException;
|
||||
import org.apache.poi.hslf.record.CurrentUserAtom;
|
||||
import org.apache.poi.hslf.record.ExOleObjStg;
|
||||
import org.apache.poi.hslf.record.PersistPtrHolder;
|
||||
import org.apache.poi.hslf.record.PositionDependentRecord;
|
||||
import org.apache.poi.hslf.record.Record;
|
||||
import org.apache.poi.hslf.record.UserEditAtom;
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import org.apache.poi.hslf.usermodel.ObjectData;
|
||||
import org.apache.poi.hslf.usermodel.PictureData;
|
||||
import org.apache.poi.hslf.model.Shape;
|
||||
@ -253,6 +244,7 @@ public class HSLFSlideShow extends POIDocument
|
||||
|
||||
private Record[] read(byte[] docstream, int usrOffset){
|
||||
ArrayList lst = new ArrayList();
|
||||
HashMap offset2id = new HashMap();
|
||||
while (usrOffset != 0){
|
||||
UserEditAtom usr = (UserEditAtom) Record.buildRecordAtOffset(docstream, usrOffset);
|
||||
lst.add(new Integer(usrOffset));
|
||||
@ -266,6 +258,7 @@ public class HSLFSlideShow extends POIDocument
|
||||
Integer offset = (Integer)entries.get(id);
|
||||
|
||||
lst.add(offset);
|
||||
offset2id.put(offset, id);
|
||||
}
|
||||
|
||||
usrOffset = usr.getLastUserEditAtomOffset();
|
||||
@ -278,6 +271,11 @@ public class HSLFSlideShow extends POIDocument
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
Integer offset = (Integer)a[i];
|
||||
rec[i] = (Record)Record.buildRecordAtOffset(docstream, offset.intValue());
|
||||
if(rec[i] instanceof PersistRecord) {
|
||||
PersistRecord psr = (PersistRecord)rec[i];
|
||||
Integer id = (Integer)offset2id.get(offset);
|
||||
psr.setPersistId(id.intValue());
|
||||
}
|
||||
}
|
||||
|
||||
return rec;
|
||||
|
@ -18,6 +18,9 @@
|
||||
package org.apache.poi.hslf.model;
|
||||
|
||||
import org.apache.poi.ddf.*;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
* Represents an AutoShape.
|
||||
@ -102,4 +105,17 @@ public class AutoShape extends TextShape {
|
||||
|
||||
setEscherProperty((short)(EscherProperties.GEOMETRY__ADJUSTVALUE + idx), val);
|
||||
}
|
||||
|
||||
public java.awt.Shape getOutline(){
|
||||
ShapeOutline outline = AutoShapes.getShapeOutline(getShapeType());
|
||||
Rectangle2D anchor = getLogicalAnchor2D();
|
||||
if(outline == null){
|
||||
logger.log(POILogger.WARN, "Outline not found for " + ShapeTypes.typeName(getShapeType()));
|
||||
return anchor;
|
||||
} else {
|
||||
java.awt.Shape shape = outline.getOutline(this);
|
||||
return AutoShapes.transform(shape, anchor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
373
src/scratchpad/src/org/apache/poi/hslf/model/AutoShapes.java
Executable file
373
src/scratchpad/src/org/apache/poi/hslf/model/AutoShapes.java
Executable file
@ -0,0 +1,373 @@
|
||||
/* ====================================================================
|
||||
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.hslf.model;
|
||||
|
||||
import org.apache.poi.ddf.EscherProperties;
|
||||
|
||||
import java.awt.geom.*;
|
||||
|
||||
/**
|
||||
* Stores definition of auto-shapes.
|
||||
* See the Office Drawing 97-2007 Binary Format Specification for details.
|
||||
*
|
||||
* TODO: follow the spec and define all the auto-shapes
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class AutoShapes {
|
||||
protected static ShapeOutline[] shapes;
|
||||
|
||||
|
||||
/**
|
||||
* Return shape outline by shape type
|
||||
* @param type shape type see {@link ShapeTypes}
|
||||
*
|
||||
* @return the shape outline
|
||||
*/
|
||||
public static ShapeOutline getShapeOutline(int type){
|
||||
ShapeOutline outline = shapes[type];
|
||||
return outline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-shapes are defined in the [0,21600] coordinate system.
|
||||
* We need to transform it into normal slide coordinates
|
||||
*
|
||||
*/
|
||||
public static java.awt.Shape transform(java.awt.Shape outline, Rectangle2D anchor){
|
||||
AffineTransform at = new AffineTransform();
|
||||
at.translate(anchor.getX(), anchor.getY());
|
||||
at.scale(
|
||||
1.0f/21600*anchor.getWidth(),
|
||||
1.0f/21600*anchor.getHeight()
|
||||
);
|
||||
return at.createTransformedShape(outline);
|
||||
}
|
||||
|
||||
static {
|
||||
shapes = new ShapeOutline[255];
|
||||
|
||||
shapes[ShapeTypes.Rectangle] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
Rectangle2D path = new Rectangle2D.Float(0, 0, 21600, 21600);
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
shapes[ShapeTypes.RoundRectangle] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);
|
||||
RoundRectangle2D path = new RoundRectangle2D.Float(0, 0, 21600, 21600, adjval, adjval);
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
shapes[ShapeTypes.Ellipse] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
Ellipse2D path = new Ellipse2D.Float(0, 0, 21600, 21600);
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
shapes[ShapeTypes.Diamond] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
GeneralPath path = new GeneralPath();
|
||||
path.moveTo(10800, 0);
|
||||
path.lineTo(21600, 10800);
|
||||
path.lineTo(10800, 21600);
|
||||
path.lineTo(0, 10800);
|
||||
path.closePath();
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
//m@0,l,21600r21600
|
||||
shapes[ShapeTypes.IsocelesTriangle] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 10800);
|
||||
GeneralPath path = new GeneralPath();
|
||||
path.moveTo(adjval, 0);
|
||||
path.lineTo(0, 21600);
|
||||
path.lineTo(21600, 21600);
|
||||
path.closePath();
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
shapes[ShapeTypes.RightTriangle] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
GeneralPath path = new GeneralPath();
|
||||
path.moveTo(0, 0);
|
||||
path.lineTo(21600, 21600);
|
||||
path.lineTo(0, 21600);
|
||||
path.closePath();
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
shapes[ShapeTypes.Parallelogram] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);
|
||||
|
||||
GeneralPath path = new GeneralPath();
|
||||
path.moveTo(adjval, 0);
|
||||
path.lineTo(21600, 0);
|
||||
path.lineTo(21600 - adjval, 21600);
|
||||
path.lineTo(0, 21600);
|
||||
path.closePath();
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
shapes[ShapeTypes.Trapezoid] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);
|
||||
|
||||
GeneralPath path = new GeneralPath();
|
||||
path.moveTo(0, 0);
|
||||
path.lineTo(adjval, 21600);
|
||||
path.lineTo(21600 - adjval, 21600);
|
||||
path.lineTo(21600, 0);
|
||||
path.closePath();
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
shapes[ShapeTypes.Hexagon] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);
|
||||
|
||||
GeneralPath path = new GeneralPath();
|
||||
path.moveTo(adjval, 0);
|
||||
path.lineTo(21600 - adjval, 0);
|
||||
path.lineTo(21600, 10800);
|
||||
path.lineTo(21600 - adjval, 21600);
|
||||
path.lineTo(adjval, 21600);
|
||||
path.lineTo(0, 10800);
|
||||
path.closePath();
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
shapes[ShapeTypes.Octagon] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 6326);
|
||||
|
||||
GeneralPath path = new GeneralPath();
|
||||
path.moveTo(adjval, 0);
|
||||
path.lineTo(21600 - adjval, 0);
|
||||
path.lineTo(21600, adjval);
|
||||
path.lineTo(21600, 21600-adjval);
|
||||
path.lineTo(21600-adjval, 21600);
|
||||
path.lineTo(adjval, 21600);
|
||||
path.lineTo(0, 21600-adjval);
|
||||
path.lineTo(0, adjval);
|
||||
path.closePath();
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
shapes[ShapeTypes.Plus] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);
|
||||
|
||||
GeneralPath path = new GeneralPath();
|
||||
path.moveTo(adjval, 0);
|
||||
path.lineTo(21600 - adjval, 0);
|
||||
path.lineTo(21600 - adjval, adjval);
|
||||
path.lineTo(21600, adjval);
|
||||
path.lineTo(21600, 21600-adjval);
|
||||
path.lineTo(21600-adjval, 21600-adjval);
|
||||
path.lineTo(21600-adjval, 21600);
|
||||
path.lineTo(adjval, 21600);
|
||||
path.lineTo(adjval, 21600-adjval);
|
||||
path.lineTo(0, 21600-adjval);
|
||||
path.lineTo(0, adjval);
|
||||
path.lineTo(adjval, adjval);
|
||||
path.closePath();
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
shapes[ShapeTypes.Pentagon] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
|
||||
GeneralPath path = new GeneralPath();
|
||||
path.moveTo(10800, 0);
|
||||
path.lineTo(21600, 8259);
|
||||
path.lineTo(21600 - 4200, 21600);
|
||||
path.lineTo(4200, 21600);
|
||||
path.lineTo(0, 8259);
|
||||
path.closePath();
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
shapes[ShapeTypes.DownArrow] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
//m0@0 l@1@0 @1,0 @2,0 @2@0,21600@0,10800,21600xe
|
||||
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 16200);
|
||||
int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 5400);
|
||||
GeneralPath path = new GeneralPath();
|
||||
path.moveTo(0, adjval);
|
||||
path.lineTo(adjval2, adjval);
|
||||
path.lineTo(adjval2, 0);
|
||||
path.lineTo(21600-adjval2, 0);
|
||||
path.lineTo(21600-adjval2, adjval);
|
||||
path.lineTo(21600, adjval);
|
||||
path.lineTo(10800, 21600);
|
||||
path.closePath();
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
shapes[ShapeTypes.UpArrow] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
//m0@0 l@1@0 @1,21600@2,21600@2@0,21600@0,10800,xe
|
||||
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);
|
||||
int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 5400);
|
||||
GeneralPath path = new GeneralPath();
|
||||
path.moveTo(0, adjval);
|
||||
path.lineTo(adjval2, adjval);
|
||||
path.lineTo(adjval2, 21600);
|
||||
path.lineTo(21600-adjval2, 21600);
|
||||
path.lineTo(21600-adjval2, adjval);
|
||||
path.lineTo(21600, adjval);
|
||||
path.lineTo(10800, 0);
|
||||
path.closePath();
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
shapes[ShapeTypes.Arrow] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
//m@0, l@0@1 ,0@1,0@2@0@2@0,21600,21600,10800xe
|
||||
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 16200);
|
||||
int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 5400);
|
||||
GeneralPath path = new GeneralPath();
|
||||
path.moveTo(adjval, 0);
|
||||
path.lineTo(adjval, adjval2);
|
||||
path.lineTo(0, adjval2);
|
||||
path.lineTo(0, 21600-adjval2);
|
||||
path.lineTo(adjval, 21600-adjval2);
|
||||
path.lineTo(adjval, 21600);
|
||||
path.lineTo(21600, 10800);
|
||||
path.closePath();
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
shapes[ShapeTypes.LeftArrow] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
//m@0, l@0@1,21600@1,21600@2@0@2@0,21600,,10800xe
|
||||
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);
|
||||
int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 5400);
|
||||
GeneralPath path = new GeneralPath();
|
||||
path.moveTo(adjval, 0);
|
||||
path.lineTo(adjval, adjval2);
|
||||
path.lineTo(21600, adjval2);
|
||||
path.lineTo(21600, 21600-adjval2);
|
||||
path.lineTo(adjval, 21600-adjval2);
|
||||
path.lineTo(adjval, 21600);
|
||||
path.lineTo(0, 10800);
|
||||
path.closePath();
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
shapes[ShapeTypes.Can] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
//m10800,qx0@1l0@2qy10800,21600,21600@2l21600@1qy10800,xem0@1qy10800@0,21600@1nfe
|
||||
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);
|
||||
|
||||
GeneralPath path = new GeneralPath();
|
||||
|
||||
path.append(new Arc2D.Float(0, 0, 21600, adjval, 0, 180, Arc2D.OPEN), false);
|
||||
path.moveTo(0, adjval/2);
|
||||
|
||||
path.lineTo(0, 21600 - adjval/2);
|
||||
path.closePath();
|
||||
|
||||
path.append(new Arc2D.Float(0, 21600 - adjval, 21600, adjval, 180, 180, Arc2D.OPEN), false);
|
||||
path.moveTo(21600, 21600 - adjval/2);
|
||||
|
||||
path.lineTo(21600, adjval/2);
|
||||
path.append(new Arc2D.Float(0, 0, 21600, adjval, 180, 180, Arc2D.OPEN), false);
|
||||
path.moveTo(0, adjval/2);
|
||||
path.closePath();
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
shapes[ShapeTypes.LeftBrace] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
//m21600,qx10800@0l10800@2qy0@11,10800@3l10800@1qy21600,21600e
|
||||
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 1800);
|
||||
int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 10800);
|
||||
|
||||
GeneralPath path = new GeneralPath();
|
||||
path.moveTo(21600, 0);
|
||||
|
||||
path.append(new Arc2D.Float(10800, 0, 21600, adjval*2, 90, 90, Arc2D.OPEN), false);
|
||||
path.moveTo(10800, adjval);
|
||||
|
||||
path.lineTo(10800, adjval2 - adjval);
|
||||
|
||||
path.append(new Arc2D.Float(-10800, adjval2 - 2*adjval, 21600, adjval*2, 270, 90, Arc2D.OPEN), false);
|
||||
path.moveTo(0, adjval2);
|
||||
|
||||
path.append(new Arc2D.Float(-10800, adjval2, 21600, adjval*2, 0, 90, Arc2D.OPEN), false);
|
||||
path.moveTo(10800, adjval2 + adjval);
|
||||
|
||||
path.lineTo(10800, 21600 - adjval);
|
||||
|
||||
path.append(new Arc2D.Float(10800, 21600 - 2*adjval, 21600, adjval*2, 180, 90, Arc2D.OPEN), false);
|
||||
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
shapes[ShapeTypes.RightBrace] = new ShapeOutline(){
|
||||
public java.awt.Shape getOutline(Shape shape){
|
||||
//m,qx10800@0 l10800@2qy21600@11,10800@3l10800@1qy,21600e
|
||||
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 1800);
|
||||
int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 10800);
|
||||
|
||||
GeneralPath path = new GeneralPath();
|
||||
path.moveTo(0, 0);
|
||||
|
||||
path.append(new Arc2D.Float(-10800, 0, 21600, adjval*2, 0, 90, Arc2D.OPEN), false);
|
||||
path.moveTo(10800, adjval);
|
||||
|
||||
path.lineTo(10800, adjval2 - adjval);
|
||||
|
||||
path.append(new Arc2D.Float(10800, adjval2 - 2*adjval, 21600, adjval*2, 180, 90, Arc2D.OPEN), false);
|
||||
path.moveTo(21600, adjval2);
|
||||
|
||||
path.append(new Arc2D.Float(10800, adjval2, 21600, adjval*2, 90, 90, Arc2D.OPEN), false);
|
||||
path.moveTo(10800, adjval2 + adjval);
|
||||
|
||||
path.lineTo(10800, 21600 - adjval);
|
||||
|
||||
path.append(new Arc2D.Float(-10800, 21600 - 2*adjval, 21600, adjval*2, 270, 90, Arc2D.OPEN), false);
|
||||
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -19,6 +18,14 @@
|
||||
package org.apache.poi.hslf.model;
|
||||
|
||||
import org.apache.poi.ddf.EscherContainerRecord;
|
||||
import org.apache.poi.hslf.usermodel.PictureData;
|
||||
import org.apache.poi.hslf.blip.Bitmap;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
/**
|
||||
* Background shape
|
||||
@ -27,12 +34,42 @@ import org.apache.poi.ddf.EscherContainerRecord;
|
||||
*/
|
||||
public class Background extends Shape {
|
||||
|
||||
protected Background(EscherContainerRecord escherRecord, Shape parent){
|
||||
protected Background(EscherContainerRecord escherRecord, Shape parent) {
|
||||
super(escherRecord, parent);
|
||||
}
|
||||
|
||||
protected EscherContainerRecord createSpContainer(boolean isChild){
|
||||
protected EscherContainerRecord createSpContainer(boolean isChild) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void draw(Graphics2D graphics) {
|
||||
Fill f = getFill();
|
||||
Dimension pg = getSheet().getSlideShow().getPageSize();
|
||||
Rectangle anchor = new Rectangle(0, 0, pg.width, pg.height);
|
||||
switch (f.getFillType()) {
|
||||
case Fill.FILL_SOLID:
|
||||
Color color = f.getForegroundColor();
|
||||
graphics.setPaint(color);
|
||||
graphics.fill(anchor);
|
||||
break;
|
||||
case Fill.FILL_PICTURE:
|
||||
PictureData data = f.getPictureData();
|
||||
if (data instanceof Bitmap) {
|
||||
BufferedImage img = null;
|
||||
try {
|
||||
img = ImageIO.read(new ByteArrayInputStream(data.getData()));
|
||||
} catch (Exception e) {
|
||||
logger.log(POILogger.WARN, "ImageIO failed to create image. image.type: " + data.getType());
|
||||
return;
|
||||
}
|
||||
Image scaledImg = img.getScaledInstance(anchor.width, anchor.height, Image.SCALE_SMOOTH);
|
||||
graphics.drawImage(scaledImg, anchor.x, anchor.y, null);
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.log(POILogger.WARN, "unsuported fill type: " + f.getFillType());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,12 +22,10 @@ import org.apache.poi.ddf.*;
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import org.apache.poi.hslf.usermodel.PictureData;
|
||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||
import org.apache.poi.hslf.exceptions.HSLFException;
|
||||
import org.apache.poi.util.POILogger;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Represents functionality provided by the 'Fill Effects' dialog in PowerPoint.
|
||||
@ -137,13 +135,15 @@ public class Fill {
|
||||
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
|
||||
EscherSimpleProperty p1 = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__FILLCOLOR);
|
||||
EscherSimpleProperty p2 = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
|
||||
EscherSimpleProperty p3 = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__FILLOPACITY);
|
||||
|
||||
int p2val = p2 == null ? 0 : p2.getPropertyValue();
|
||||
int alpha = p3 == null ? 255 : ((p3.getPropertyValue() >> 8) & 0xFF);
|
||||
|
||||
Color clr = null;
|
||||
if (p1 != null && (p2val & 0x10) != 0){
|
||||
int rgb = p1.getPropertyValue();
|
||||
clr = shape.getColor(rgb);
|
||||
clr = shape.getColor(rgb, alpha);
|
||||
}
|
||||
return clr;
|
||||
}
|
||||
@ -176,7 +176,7 @@ public class Fill {
|
||||
Color clr = null;
|
||||
if (p1 != null && (p2val & 0x10) != 0){
|
||||
int rgb = p1.getPropertyValue();
|
||||
clr = shape.getColor(rgb);
|
||||
clr = shape.getColor(rgb, 255);
|
||||
}
|
||||
return clr;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import org.apache.poi.util.POILogger;
|
||||
|
||||
import java.awt.geom.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* A "Freeform" shape.
|
||||
@ -33,6 +34,16 @@ import java.util.ArrayList;
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class Freeform extends AutoShape {
|
||||
|
||||
public static final byte[] SEGMENTINFO_MOVETO = new byte[]{0x00, 0x40};
|
||||
public static final byte[] SEGMENTINFO_LINETO = new byte[]{0x00, (byte)0xAC};
|
||||
public static final byte[] SEGMENTINFO_ESCAPE = new byte[]{0x01, 0x00};
|
||||
public static final byte[] SEGMENTINFO_ESCAPE2 = new byte[]{0x01, 0x20};
|
||||
public static final byte[] SEGMENTINFO_CUBICTO = new byte[]{0x00, (byte)0xAD};
|
||||
public static final byte[] SEGMENTINFO_CUBICTO2 = new byte[]{0x00, (byte)0xB3}; //OpenOffice inserts 0xB3 instead of 0xAD.
|
||||
public static final byte[] SEGMENTINFO_CLOSE = new byte[]{0x01, (byte)0x60};
|
||||
public static final byte[] SEGMENTINFO_END = new byte[]{0x00, (byte)0x80};
|
||||
|
||||
/**
|
||||
* Create a Freeform object and initialize it from the supplied Record container.
|
||||
*
|
||||
@ -82,36 +93,37 @@ public class Freeform extends AutoShape {
|
||||
switch (type) {
|
||||
case PathIterator.SEG_MOVETO:
|
||||
pntInfo.add(new Point2D.Double(vals[0], vals[1]));
|
||||
segInfo.add(new byte[]{0x00, 0x40});
|
||||
segInfo.add(SEGMENTINFO_MOVETO);
|
||||
break;
|
||||
case PathIterator.SEG_LINETO:
|
||||
pntInfo.add(new Point2D.Double(vals[0], vals[1]));
|
||||
segInfo.add(new byte[]{0x00, (byte)0xAC});
|
||||
segInfo.add(new byte[]{0x01, 0x00 });
|
||||
segInfo.add(SEGMENTINFO_LINETO);
|
||||
segInfo.add(SEGMENTINFO_ESCAPE);
|
||||
break;
|
||||
case PathIterator.SEG_CUBICTO:
|
||||
pntInfo.add(new Point2D.Double(vals[0], vals[1]));
|
||||
pntInfo.add(new Point2D.Double(vals[2], vals[3]));
|
||||
pntInfo.add(new Point2D.Double(vals[4], vals[5]));
|
||||
segInfo.add(new byte[]{0x00, (byte)0xAD});
|
||||
segInfo.add(new byte[]{0x01, 0x20 });
|
||||
segInfo.add(SEGMENTINFO_CUBICTO);
|
||||
segInfo.add(SEGMENTINFO_ESCAPE2);
|
||||
break;
|
||||
case PathIterator.SEG_QUADTO:
|
||||
//TODO: figure out how to convert SEG_QUADTO into SEG_CUBICTO
|
||||
logger.log(POILogger.WARN, "SEG_QUADTO is not supported");
|
||||
break;
|
||||
case PathIterator.SEG_CLOSE:
|
||||
pntInfo.add(pntInfo.get(0));
|
||||
segInfo.add(new byte[]{0x00, (byte)0xAC});
|
||||
segInfo.add(new byte[]{0x01, 0x00 });
|
||||
segInfo.add(new byte[]{0x00, (byte)0xAC});
|
||||
segInfo.add(new byte[]{0x01, (byte)0x60});
|
||||
segInfo.add(SEGMENTINFO_LINETO);
|
||||
segInfo.add(SEGMENTINFO_ESCAPE);
|
||||
segInfo.add(SEGMENTINFO_LINETO);
|
||||
segInfo.add(SEGMENTINFO_CLOSE);
|
||||
isClosed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
it.next();
|
||||
}
|
||||
if(!isClosed) segInfo.add(new byte[]{0x00, (byte)0xAC});
|
||||
if(!isClosed) segInfo.add(SEGMENTINFO_LINETO);
|
||||
segInfo.add(new byte[]{0x00, (byte)0x80});
|
||||
|
||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||
@ -147,4 +159,85 @@ public class Freeform extends AutoShape {
|
||||
|
||||
setAnchor(bounds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the freeform path
|
||||
*
|
||||
* @return the freeform path
|
||||
*/
|
||||
public GeneralPath getPath(){
|
||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 0x4));
|
||||
|
||||
EscherArrayProperty verticesProp = (EscherArrayProperty)getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__VERTICES + 0x4000));
|
||||
if(verticesProp == null) verticesProp = (EscherArrayProperty)getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__VERTICES));
|
||||
|
||||
EscherArrayProperty segmentsProp = (EscherArrayProperty)getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__SEGMENTINFO + 0x4000));
|
||||
if(segmentsProp == null) segmentsProp = (EscherArrayProperty)getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__SEGMENTINFO));
|
||||
|
||||
//sanity check
|
||||
if(verticesProp == null) {
|
||||
logger.log(POILogger.WARN, "Freeform is missing GEOMETRY__VERTICES ");
|
||||
return null;
|
||||
}
|
||||
if(segmentsProp == null) {
|
||||
logger.log(POILogger.WARN, "Freeform is missing GEOMETRY__SEGMENTINFO ");
|
||||
return null;
|
||||
}
|
||||
|
||||
Rectangle2D bounds = getAnchor2D();
|
||||
float right = (float)bounds.getX();
|
||||
float bottom = (float)bounds.getY();
|
||||
|
||||
GeneralPath path = new GeneralPath();
|
||||
int numPoints = verticesProp.getNumberOfElementsInArray();
|
||||
int numSegments = segmentsProp.getNumberOfElementsInArray();
|
||||
for (int i = 0, j = 0; i < numSegments && j < numPoints; i++) {
|
||||
byte[] elem = segmentsProp.getElement(i);
|
||||
if(Arrays.equals(elem, SEGMENTINFO_MOVETO)){
|
||||
byte[] p = verticesProp.getElement(j++);
|
||||
short x = LittleEndian.getShort(p, 0);
|
||||
short y = LittleEndian.getShort(p, 2);
|
||||
path.moveTo(
|
||||
((float)x*POINT_DPI/MASTER_DPI + right),
|
||||
((float)y*POINT_DPI/MASTER_DPI + bottom));
|
||||
} else if (Arrays.equals(elem, SEGMENTINFO_CUBICTO) || Arrays.equals(elem, SEGMENTINFO_CUBICTO2)){
|
||||
i++;
|
||||
byte[] p1 = verticesProp.getElement(j++);
|
||||
short x1 = LittleEndian.getShort(p1, 0);
|
||||
short y1 = LittleEndian.getShort(p1, 2);
|
||||
byte[] p2 = verticesProp.getElement(j++);
|
||||
short x2 = LittleEndian.getShort(p2, 0);
|
||||
short y2 = LittleEndian.getShort(p2, 2);
|
||||
byte[] p3 = verticesProp.getElement(j++);
|
||||
short x3 = LittleEndian.getShort(p3, 0);
|
||||
short y3 = LittleEndian.getShort(p3, 2);
|
||||
path.curveTo(
|
||||
((float)x1*POINT_DPI/MASTER_DPI + right), ((float)y1*POINT_DPI/MASTER_DPI + bottom),
|
||||
((float)x2*POINT_DPI/MASTER_DPI + right), ((float)y2*POINT_DPI/MASTER_DPI + bottom),
|
||||
((float)x3*POINT_DPI/MASTER_DPI + right), ((float)y3*POINT_DPI/MASTER_DPI + bottom));
|
||||
|
||||
} else if (Arrays.equals(elem, SEGMENTINFO_LINETO)){
|
||||
i++;
|
||||
byte[] pnext = segmentsProp.getElement(i);
|
||||
if(Arrays.equals(pnext, SEGMENTINFO_ESCAPE)){
|
||||
if(j + 1 < numPoints){
|
||||
byte[] p = verticesProp.getElement(j++);
|
||||
short x = LittleEndian.getShort(p, 0);
|
||||
short y = LittleEndian.getShort(p, 2);
|
||||
path.lineTo(
|
||||
((float)x*POINT_DPI/MASTER_DPI + right), ((float)y*POINT_DPI/MASTER_DPI + bottom));
|
||||
}
|
||||
} else if (Arrays.equals(pnext, SEGMENTINFO_CLOSE)){
|
||||
path.closePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public java.awt.Shape getOutline(){
|
||||
return getPath();
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,9 @@ package org.apache.poi.hslf.model;
|
||||
|
||||
import org.apache.poi.ddf.*;
|
||||
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.Line2D;
|
||||
|
||||
/**
|
||||
* Represents a line in a PowerPoint drawing
|
||||
*
|
||||
@ -126,4 +129,8 @@ public class Line extends SimpleShape {
|
||||
return _escherContainer;
|
||||
}
|
||||
|
||||
public java.awt.Shape getOutline(){
|
||||
Rectangle2D anchor = getLogicalAnchor2D();
|
||||
return new Line2D.Double(anchor.getX(), anchor.getY(), anchor.getX() + anchor.getWidth(), anchor.getY() + anchor.getHeight());
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
package org.apache.poi.hslf.model;
|
||||
|
||||
import org.apache.poi.hslf.record.SheetContainer;
|
||||
import org.apache.poi.hslf.record.Record;
|
||||
import org.apache.poi.hslf.record.RecordTypes;
|
||||
import org.apache.poi.hslf.model.textproperties.TextProp;
|
||||
|
||||
/**
|
||||
@ -37,4 +39,32 @@ public abstract class MasterSheet extends Sheet {
|
||||
*/
|
||||
public abstract TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) ;
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the shape is a placeholder.
|
||||
* (placeholders aren't normal shapes, they are visible only in the Edit Master mode)
|
||||
*
|
||||
*
|
||||
* @return true if the shape is a placeholder
|
||||
*/
|
||||
public static boolean isPlaceholder(Shape shape){
|
||||
if(!(shape instanceof TextShape)) return false;
|
||||
|
||||
TextShape tx = (TextShape)shape;
|
||||
TextRun run = tx.getTextRun();
|
||||
if(run == null) return false;
|
||||
|
||||
Record[] records = run._records;
|
||||
for (int i = 0; i < records.length; i++) {
|
||||
int type = (int)records[i].getRecordType();
|
||||
if (type == RecordTypes.BaseTextPropAtom.typeID ||
|
||||
type == RecordTypes.DateTimeMCAtom.typeID ||
|
||||
type == RecordTypes.GenericDateMCAtom.typeID ||
|
||||
type == RecordTypes.FooterMCAtom.typeID ||
|
||||
type == RecordTypes.SlideNumberMCAtom.typeID
|
||||
) return true;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
160
src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java
Executable file
160
src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java
Executable file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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.hslf.model;
|
||||
|
||||
import org.apache.poi.ddf.*;
|
||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||
import org.apache.poi.hslf.usermodel.ObjectData;
|
||||
import org.apache.poi.hslf.record.ExObjList;
|
||||
import org.apache.poi.hslf.record.Record;
|
||||
import org.apache.poi.hslf.record.ExEmbed;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
|
||||
/**
|
||||
* A shape representing embedded OLE obejct.
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class OLEShape extends Picture {
|
||||
protected ExEmbed _exEmbed;
|
||||
|
||||
/**
|
||||
* Create a new <code>OLEShape</code>
|
||||
*
|
||||
* @param idx the index of the picture
|
||||
*/
|
||||
public OLEShape(int idx){
|
||||
super(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new <code>OLEShape</code>
|
||||
*
|
||||
* @param idx the index of the picture
|
||||
* @param parent the parent shape
|
||||
*/
|
||||
public OLEShape(int idx, Shape parent) {
|
||||
super(idx, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a <code>OLEShape</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 OLEShape(EscherContainerRecord escherRecord, Shape parent){
|
||||
super(escherRecord, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns unique identifier for the OLE object.
|
||||
*
|
||||
* @return the unique identifier for the OLE object
|
||||
*/
|
||||
public int getObjectID(){
|
||||
return getEscherProperty(EscherProperties.BLIP__PICTUREID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns unique identifier for the OLE object.
|
||||
*
|
||||
* @return the unique identifier for the OLE object
|
||||
*/
|
||||
public ObjectData getObjectData(){
|
||||
SlideShow ppt = getSheet().getSlideShow();
|
||||
ObjectData[] ole = ppt.getEmbeddedObjects();
|
||||
|
||||
//persist reference
|
||||
int ref = getExEmbed().getExOleObjAtom().getObjStgDataRef();
|
||||
for (int i = 0; i < ole.length; i++) {
|
||||
if(ole[i].getExOleObjStg().getPersistId() == ref) return ole[i];
|
||||
|
||||
}
|
||||
logger.log(POILogger.WARN, "OLE data not found");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the record container for this embedded object.
|
||||
*
|
||||
* <p>
|
||||
* It contains:
|
||||
* 1. ExEmbedAtom.(4045)
|
||||
* 2. ExOleObjAtom (4035)
|
||||
* 3. CString (4026), Instance MenuName (1) used for menus and the Links dialog box.
|
||||
* 4. CString (4026), Instance ProgID (2) that stores the OLE Programmatic Identifier.
|
||||
* A ProgID is a string that uniquely identifies a given object.
|
||||
* 5. CString (4026), Instance ClipboardName (3) that appears in the paste special dialog.
|
||||
* 6. MetaFile( 4033), optional
|
||||
* </p>
|
||||
* @return
|
||||
*/
|
||||
public ExEmbed getExEmbed(){
|
||||
if(_exEmbed == null){
|
||||
SlideShow ppt = getSheet().getSlideShow();
|
||||
|
||||
ExObjList lst = ppt.getDocumentRecord().getExObjList();
|
||||
if(lst == null){
|
||||
logger.log(POILogger.WARN, "ExObjList not found");
|
||||
return null;
|
||||
}
|
||||
|
||||
int id = getObjectID();
|
||||
Record[] ch = lst.getChildRecords();
|
||||
for (int i = 0; i < ch.length; i++) {
|
||||
if(ch[i] instanceof ExEmbed){
|
||||
ExEmbed embd = (ExEmbed)ch[i];
|
||||
if( embd.getExOleObjAtom().getObjID() == id) _exEmbed = embd;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _exEmbed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the instance name of the embedded object, e.g. "Document" or "Workbook".
|
||||
*
|
||||
* @return the instance name of the embedded object
|
||||
*/
|
||||
public String getInstanceName(){
|
||||
return getExEmbed().getMenuName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full name of the embedded object,
|
||||
* e.g. "Microsoft Word Document" or "Microsoft Office Excel Worksheet".
|
||||
*
|
||||
* @return the full name of the embedded object
|
||||
*/
|
||||
public String getFullName(){
|
||||
return getExEmbed().getClipboardName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ProgID that stores the OLE Programmatic Identifier.
|
||||
* A ProgID is a string that uniquely identifies a given object, for example,
|
||||
* "Word.Document.8" or "Excel.Sheet.8".
|
||||
*
|
||||
* @return the ProgID
|
||||
*/
|
||||
public String getProgID(){
|
||||
return getExEmbed().getProgId();
|
||||
}
|
||||
}
|
@ -27,7 +27,6 @@ import java.awt.image.renderable.RenderableImage;
|
||||
import java.awt.geom.*;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.util.Map;
|
||||
import java.util.ArrayList;
|
||||
import org.apache.poi.hslf.usermodel.RichTextRun;
|
||||
import org.apache.poi.hslf.exceptions.HSLFException;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
@ -21,13 +21,16 @@ import org.apache.poi.hslf.usermodel.PictureData;
|
||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||
import org.apache.poi.hslf.record.Document;
|
||||
import org.apache.poi.hslf.blip.Bitmap;
|
||||
import org.apache.poi.hslf.exceptions.HSLFException;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
|
||||
@ -128,7 +131,7 @@ public class Picture extends SimpleShape {
|
||||
|
||||
//set default properties for a picture
|
||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||
setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 8388736);
|
||||
setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x800080);
|
||||
|
||||
//another weird feature of powerpoint: for picture id we must add 0x4000.
|
||||
setEscherProperty(opt, (short)(EscherProperties.BLIP__BLIPTODISPLAY + 0x4000), idx);
|
||||
@ -192,14 +195,70 @@ public class Picture extends SimpleShape {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of this picture.
|
||||
*
|
||||
* @return name of this picture
|
||||
*/
|
||||
public String getPictureName(){
|
||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||
EscherComplexProperty prop = (EscherComplexProperty)getEscherProperty(opt, EscherProperties.BLIP__BLIPFILENAME);
|
||||
String name = null;
|
||||
if(prop != null){
|
||||
try {
|
||||
name = new String(prop.getComplexData(), "UTF-16LE");
|
||||
int idx = name.indexOf('\u0000');
|
||||
return idx == -1 ? name : name.substring(0, idx);
|
||||
} catch (UnsupportedEncodingException e){
|
||||
throw new HSLFException(e);
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of this picture.
|
||||
*
|
||||
* @param name of this picture
|
||||
*/
|
||||
public void setPictureName(String name){
|
||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||
try {
|
||||
byte[] data = (name + '\u0000').getBytes("UTF-16LE");
|
||||
EscherComplexProperty prop = new EscherComplexProperty(EscherProperties.BLIP__BLIPFILENAME, false, data);
|
||||
opt.addEscherProperty(prop);
|
||||
} catch (UnsupportedEncodingException e){
|
||||
throw new HSLFException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* By default set the orininal image size
|
||||
*/
|
||||
protected void afterInsert(Sheet sh){
|
||||
super.afterInsert(sh);
|
||||
java.awt.Rectangle anchor = getAnchor();
|
||||
if (anchor.equals(new java.awt.Rectangle())){
|
||||
setDefaultSize();
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(Graphics2D graphics){
|
||||
PictureData data = getPictureData();
|
||||
if (data instanceof Bitmap){
|
||||
BufferedImage img = null;
|
||||
try {
|
||||
img = ImageIO.read(new ByteArrayInputStream(data.getData()));
|
||||
}
|
||||
catch (Exception e){
|
||||
logger.log(POILogger.WARN, "ImageIO failed to create image. image.type: " + data.getType());
|
||||
return;
|
||||
}
|
||||
Rectangle anchor = getAnchor();
|
||||
Image scaledImg = img.getScaledInstance(anchor.width, anchor.height, Image.SCALE_SMOOTH);
|
||||
graphics.drawImage(scaledImg, anchor.x, anchor.y, null);
|
||||
} else {
|
||||
logger.log(POILogger.WARN, "Rendering of metafiles is not yet supported. image.type: " + (data == null ? "NA" : data.getClass().getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,12 +17,12 @@
|
||||
package org.apache.poi.hslf.model;
|
||||
|
||||
import org.apache.poi.ddf.*;
|
||||
import org.apache.poi.hslf.model.ShapeTypes;
|
||||
import org.apache.poi.hslf.record.ColorSchemeAtom;
|
||||
import org.apache.poi.hslf.record.PPDrawing;
|
||||
import org.apache.poi.util.POILogger;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.*;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
@ -166,12 +166,24 @@ public abstract class Shape {
|
||||
if ((flags & EscherSpRecord.FLAG_CHILD) != 0){
|
||||
EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID);
|
||||
anchor = new java.awt.Rectangle();
|
||||
anchor = new Rectangle2D.Float(
|
||||
(float)rec.getDx1()*POINT_DPI/MASTER_DPI,
|
||||
(float)rec.getDy1()*POINT_DPI/MASTER_DPI,
|
||||
(float)(rec.getDx2()-rec.getDx1())*POINT_DPI/MASTER_DPI,
|
||||
(float)(rec.getDy2()-rec.getDy1())*POINT_DPI/MASTER_DPI
|
||||
);
|
||||
if(rec == null){
|
||||
logger.log(POILogger.WARN, "EscherSpRecord.FLAG_CHILD is set but EscherChildAnchorRecord was not found");
|
||||
EscherClientAnchorRecord clrec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
|
||||
anchor = new java.awt.Rectangle();
|
||||
anchor = new Rectangle2D.Float(
|
||||
(float)clrec.getCol1()*POINT_DPI/MASTER_DPI,
|
||||
(float)clrec.getFlag()*POINT_DPI/MASTER_DPI,
|
||||
(float)(clrec.getDx1()-clrec.getCol1())*POINT_DPI/MASTER_DPI,
|
||||
(float)(clrec.getRow1()-clrec.getFlag())*POINT_DPI/MASTER_DPI
|
||||
);
|
||||
} else {
|
||||
anchor = new Rectangle2D.Float(
|
||||
(float)rec.getDx1()*POINT_DPI/MASTER_DPI,
|
||||
(float)rec.getDy1()*POINT_DPI/MASTER_DPI,
|
||||
(float)(rec.getDx2()-rec.getDx1())*POINT_DPI/MASTER_DPI,
|
||||
(float)(rec.getDy2()-rec.getDy1())*POINT_DPI/MASTER_DPI
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
|
||||
@ -186,6 +198,10 @@ public abstract class Shape {
|
||||
return anchor;
|
||||
}
|
||||
|
||||
public Rectangle2D getLogicalAnchor2D(){
|
||||
return getAnchor2D();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the anchor (the bounding box rectangle) of this shape.
|
||||
* All coordinates should be expressed in points (72 dpi).
|
||||
@ -245,7 +261,7 @@ public abstract class Shape {
|
||||
* @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(); )
|
||||
if(opt != null) for ( Iterator iterator = opt.getEscherProperties().iterator(); iterator.hasNext(); )
|
||||
{
|
||||
EscherProperty prop = (EscherProperty) iterator.next();
|
||||
if (prop.getPropertyNumber() == propId)
|
||||
@ -294,7 +310,18 @@ public abstract class Shape {
|
||||
public int getEscherProperty(short propId){
|
||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, propId);
|
||||
return prop == null ? 0 : prop.getPropertyNumber();
|
||||
return prop == null ? 0 : prop.getPropertyValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a simple escher property for this shape.
|
||||
*
|
||||
* @param propId The id of the property. One of the constants defined in EscherOptRecord.
|
||||
*/
|
||||
public int getEscherProperty(short propId, int defaultValue){
|
||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, propId);
|
||||
return prop == null ? defaultValue : prop.getPropertyValue();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -314,7 +341,58 @@ public abstract class Shape {
|
||||
* @param sh - owning shape
|
||||
*/
|
||||
protected void afterInsert(Sheet sh){
|
||||
PPDrawing ppdrawing = sh.getPPDrawing();
|
||||
|
||||
EscherContainerRecord dgContainer = (EscherContainerRecord) ppdrawing.getEscherRecords()[0];
|
||||
|
||||
EscherDgRecord dg = (EscherDgRecord) Shape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID);
|
||||
|
||||
int id = allocateShapeId(dg);
|
||||
setShapeId(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates new shape id for the new drawing group id.
|
||||
*
|
||||
* @param dg EscherDgRecord of the sheet that owns the shape being created
|
||||
*
|
||||
* @return a new shape id.
|
||||
*/
|
||||
protected int allocateShapeId(EscherDgRecord dg)
|
||||
{
|
||||
EscherDggRecord dgg = _sheet.getSlideShow().getDocumentRecord().getPPDrawingGroup().getEscherDggRecord();
|
||||
if(dgg == null){
|
||||
logger.log(POILogger.ERROR, "EscherDggRecord not found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dgg.setNumShapesSaved( dgg.getNumShapesSaved() + 1 );
|
||||
|
||||
// Add to existing cluster if space available
|
||||
for (int i = 0; i < dgg.getFileIdClusters().length; i++)
|
||||
{
|
||||
EscherDggRecord.FileIdCluster c = dgg.getFileIdClusters()[i];
|
||||
if (c.getDrawingGroupId() == dg.getDrawingGroupId() && c.getNumShapeIdsUsed() != 1024)
|
||||
{
|
||||
int result = c.getNumShapeIdsUsed() + (1024 * (i+1));
|
||||
c.incrementShapeId();
|
||||
dg.setNumShapes( dg.getNumShapes() + 1 );
|
||||
dg.setLastMSOSPID( result );
|
||||
if (result >= dgg.getShapeIdMax())
|
||||
dgg.setShapeIdMax( result + 1 );
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Create new cluster
|
||||
dgg.addCluster( dg.getDrawingGroupId(), 0 );
|
||||
dgg.getFileIdClusters()[dgg.getFileIdClusters().length-1].incrementShapeId();
|
||||
dg.setNumShapes( dg.getNumShapes() + 1 );
|
||||
int result = (1024 * dgg.getFileIdClusters().length);
|
||||
dg.setLastMSOSPID( result );
|
||||
if (result >= dgg.getShapeIdMax())
|
||||
dgg.setShapeIdMax( result + 1 );
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -333,14 +411,32 @@ public abstract class Shape {
|
||||
_sheet = sheet;
|
||||
}
|
||||
|
||||
protected Color getColor(int rgb){
|
||||
protected Color getColor(int rgb, int alpha){
|
||||
if (rgb >= 0x8000000) {
|
||||
int idx = rgb - 0x8000000;
|
||||
ColorSchemeAtom ca = getSheet().getColorScheme();
|
||||
if(idx >= 0 && idx <= 7) rgb = ca.getColor(idx);
|
||||
}
|
||||
Color tmp = new Color(rgb, true);
|
||||
return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());
|
||||
return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed(), alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return id for the shape.
|
||||
*/
|
||||
public int getShapeId(){
|
||||
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
|
||||
return spRecord == null ? 0 : spRecord.getShapeId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets shape ID
|
||||
*
|
||||
* @param id of the shape
|
||||
*/
|
||||
public void setShapeId(int id){
|
||||
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
|
||||
if(spRecord != null) spRecord.setShapeId(id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -364,4 +460,16 @@ public abstract class Shape {
|
||||
return Hyperlink.find(this);
|
||||
}
|
||||
|
||||
public void draw(Graphics2D graphics){
|
||||
logger.log(POILogger.INFO, "Rendering " + getShapeName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return shape outline as a java.awt.Shape object
|
||||
*
|
||||
* @return the shape outline
|
||||
*/
|
||||
public java.awt.Shape getOutline(){
|
||||
return getLogicalAnchor2D();
|
||||
}
|
||||
}
|
||||
|
@ -76,13 +76,19 @@ public class ShapeFactory {
|
||||
case ShapeTypes.TextBox:
|
||||
shape = new TextBox(spContainer, parent);
|
||||
break;
|
||||
case ShapeTypes.PictureFrame:
|
||||
shape = new Picture(spContainer, parent);
|
||||
case ShapeTypes.PictureFrame: {
|
||||
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
|
||||
EscherProperty prop = Shape.getEscherProperty(opt, EscherProperties.BLIP__PICTUREID);
|
||||
if(prop != null)
|
||||
shape = new OLEShape(spContainer, parent); //presence of BLIP__PICTUREID indicates it is an embedded object
|
||||
else
|
||||
shape = new Picture(spContainer, parent);
|
||||
break;
|
||||
}
|
||||
case ShapeTypes.Line:
|
||||
shape = new Line(spContainer, parent);
|
||||
break;
|
||||
case ShapeTypes.NotPrimitive:
|
||||
case ShapeTypes.NotPrimitive: {
|
||||
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
|
||||
EscherProperty prop = Shape.getEscherProperty(opt, EscherProperties.GEOMETRY__VERTICES);
|
||||
if(prop != null)
|
||||
@ -93,6 +99,7 @@ public class ShapeFactory {
|
||||
shape = new AutoShape(spContainer, parent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
shape = new AutoShape(spContainer, parent);
|
||||
break;
|
||||
|
@ -24,6 +24,8 @@ import org.apache.poi.hslf.record.EscherTextboxWrapper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* Represents a group of shapes.
|
||||
@ -113,6 +115,47 @@ public class ShapeGroup extends Shape{
|
||||
spgr.setRectY2((anchor.y + anchor.height)*MASTER_DPI/POINT_DPI);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the coordinate space of this group. All children are constrained
|
||||
* to these coordinates.
|
||||
*
|
||||
* @param anchor the coordinate space of this group
|
||||
*/
|
||||
public void setCoordinates(Rectangle2D anchor){
|
||||
EscherContainerRecord spContainer = (EscherContainerRecord)_escherContainer.getChildRecords().get(0);
|
||||
EscherSpgrRecord spgr = (EscherSpgrRecord)getEscherChild(spContainer, EscherSpgrRecord.RECORD_ID);
|
||||
|
||||
int x1 = (int)Math.round(anchor.getX()*MASTER_DPI/POINT_DPI);
|
||||
int y1 = (int)Math.round(anchor.getY()*MASTER_DPI/POINT_DPI);
|
||||
int x2 = (int)Math.round((anchor.getX() + anchor.getWidth())*MASTER_DPI/POINT_DPI);
|
||||
int y2 = (int)Math.round((anchor.getY() + anchor.getHeight())*MASTER_DPI/POINT_DPI);
|
||||
|
||||
spgr.setRectX1(x1);
|
||||
spgr.setRectY1(y1);
|
||||
spgr.setRectX2(x2);
|
||||
spgr.setRectY2(y2);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the coordinate space of this group. All children are constrained
|
||||
* to these coordinates.
|
||||
*
|
||||
* @return the coordinate space of this group
|
||||
*/
|
||||
public Rectangle2D getCoordinates(){
|
||||
EscherContainerRecord spContainer = (EscherContainerRecord)_escherContainer.getChildRecords().get(0);
|
||||
EscherSpgrRecord spgr = (EscherSpgrRecord)getEscherChild(spContainer, EscherSpgrRecord.RECORD_ID);
|
||||
|
||||
Rectangle2D.Float anchor = new Rectangle2D.Float();
|
||||
anchor.x = (float)spgr.getRectX1()*POINT_DPI/MASTER_DPI;
|
||||
anchor.y = (float)spgr.getRectY1()*POINT_DPI/MASTER_DPI;
|
||||
anchor.width = (float)(spgr.getRectX2() - spgr.getRectX1())*POINT_DPI/MASTER_DPI;
|
||||
anchor.height = (float)(spgr.getRectY2() - spgr.getRectY1())*POINT_DPI/MASTER_DPI;
|
||||
|
||||
return anchor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ShapeGroup and create an instance of <code>EscherSpgrContainer</code> which represents a group of shapes
|
||||
*/
|
||||
@ -190,14 +233,24 @@ public class ShapeGroup extends Shape{
|
||||
* @return the anchor of this shape group
|
||||
*/
|
||||
public Rectangle2D getAnchor2D(){
|
||||
EscherContainerRecord groupInfoContainer = (EscherContainerRecord)_escherContainer.getChild(0);
|
||||
EscherSpgrRecord spgr = (EscherSpgrRecord)getEscherChild(groupInfoContainer, EscherSpgrRecord.RECORD_ID);
|
||||
Rectangle2D anchor = new Rectangle2D.Float(
|
||||
(float)spgr.getRectX1()*POINT_DPI/MASTER_DPI,
|
||||
(float)spgr.getRectY1()*POINT_DPI/MASTER_DPI,
|
||||
(float)(spgr.getRectX2() - spgr.getRectX1())*POINT_DPI/MASTER_DPI,
|
||||
(float)(spgr.getRectY2() - spgr.getRectY1())*POINT_DPI/MASTER_DPI
|
||||
);
|
||||
EscherContainerRecord spContainer = (EscherContainerRecord)_escherContainer.getChildRecords().get(0);
|
||||
EscherClientAnchorRecord clientAnchor = (EscherClientAnchorRecord)getEscherChild(spContainer, EscherClientAnchorRecord.RECORD_ID);
|
||||
Rectangle2D.Float anchor = new Rectangle2D.Float();
|
||||
if(clientAnchor == null){
|
||||
logger.log(POILogger.INFO, "EscherClientAnchorRecord was not found for shape group. Searching for EscherChildAnchorRecord.");
|
||||
EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(spContainer, EscherChildAnchorRecord.RECORD_ID);
|
||||
anchor = new Rectangle2D.Float(
|
||||
(float)rec.getDx1()*POINT_DPI/MASTER_DPI,
|
||||
(float)rec.getDy1()*POINT_DPI/MASTER_DPI,
|
||||
(float)(rec.getDx2()-rec.getDx1())*POINT_DPI/MASTER_DPI,
|
||||
(float)(rec.getDy2()-rec.getDy1())*POINT_DPI/MASTER_DPI
|
||||
);
|
||||
} else {
|
||||
anchor.x = (float)clientAnchor.getCol1()*POINT_DPI/MASTER_DPI;
|
||||
anchor.y = (float)clientAnchor.getFlag()*POINT_DPI/MASTER_DPI;
|
||||
anchor.width = (float)(clientAnchor.getDx1() - clientAnchor.getCol1())*POINT_DPI/MASTER_DPI ;
|
||||
anchor.height = (float)(clientAnchor.getRow1() - clientAnchor.getFlag())*POINT_DPI/MASTER_DPI;
|
||||
}
|
||||
|
||||
return anchor;
|
||||
}
|
||||
@ -222,5 +275,27 @@ public class ShapeGroup extends Shape{
|
||||
public Hyperlink getHyperlink(){
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void draw(Graphics2D graphics){
|
||||
Rectangle2D anchor = getAnchor2D();
|
||||
Rectangle2D coords = getCoordinates();
|
||||
|
||||
//transform coordinates
|
||||
AffineTransform at = graphics.getTransform();
|
||||
/*
|
||||
if(!anchor.equals(coords)){
|
||||
graphics.scale(anchor.getWidth()/coords.getWidth(), anchor.getHeight()/coords.getHeight());
|
||||
|
||||
graphics.translate(
|
||||
anchor.getX()*coords.getWidth()/anchor.getWidth() - coords.getX(),
|
||||
anchor.getY()*coords.getHeight()/anchor.getHeight() - coords.getY());
|
||||
}
|
||||
*/
|
||||
Shape[] sh = getShapes();
|
||||
for (int i = 0; i < sh.length; i++) {
|
||||
sh[i].draw(graphics);
|
||||
}
|
||||
|
||||
graphics.setTransform(at);
|
||||
}
|
||||
}
|
||||
|
27
src/scratchpad/src/org/apache/poi/hslf/model/ShapeOutline.java
Executable file
27
src/scratchpad/src/org/apache/poi/hslf/model/ShapeOutline.java
Executable file
@ -0,0 +1,27 @@
|
||||
/* ====================================================================
|
||||
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.hslf.model;
|
||||
|
||||
/**
|
||||
* Date: Apr 17, 2008
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public interface ShapeOutline {
|
||||
java.awt.Shape getOutline(Shape shape);
|
||||
|
||||
}
|
102
src/scratchpad/src/org/apache/poi/hslf/model/ShapePainter.java
Executable file
102
src/scratchpad/src/org/apache/poi/hslf/model/ShapePainter.java
Executable file
@ -0,0 +1,102 @@
|
||||
/* ====================================================================
|
||||
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.hslf.model;
|
||||
|
||||
|
||||
import org.apache.poi.util.POILogger;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
* Paint a shape into java.awt.Graphics2D
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class ShapePainter {
|
||||
protected static POILogger logger = POILogFactory.getLogger(ShapePainter.class);
|
||||
|
||||
public static void paint(SimpleShape shape, Graphics2D graphics){
|
||||
Rectangle2D anchor = shape.getLogicalAnchor2D();
|
||||
java.awt.Shape outline = shape.getOutline();
|
||||
|
||||
//flip vertical
|
||||
if(shape.getFlipVertical()){
|
||||
graphics.translate(anchor.getX(), anchor.getY() + anchor.getHeight());
|
||||
graphics.scale(1, -1);
|
||||
graphics.translate(-anchor.getX(), -anchor.getY());
|
||||
}
|
||||
//flip horizontal
|
||||
if(shape.getFlipHorizontal()){
|
||||
graphics.translate(anchor.getX() + anchor.getWidth(), anchor.getY());
|
||||
graphics.scale(-1, 1);
|
||||
graphics.translate(-anchor.getX() , -anchor.getY());
|
||||
}
|
||||
|
||||
//rotate transform
|
||||
double angle = shape.getRotation();
|
||||
|
||||
if(angle != 0){
|
||||
double centerX = anchor.getX() + anchor.getWidth()/2;
|
||||
double centerY = anchor.getY() + anchor.getHeight()/2;
|
||||
|
||||
graphics.translate(centerX, centerY);
|
||||
graphics.rotate(Math.toRadians(angle));
|
||||
graphics.translate(-centerX, -centerY);
|
||||
}
|
||||
|
||||
//fill
|
||||
Color fillColor = shape.getFill().getForegroundColor();
|
||||
if (fillColor != null) {
|
||||
//TODO: implement gradient and texture fill patterns
|
||||
graphics.setPaint(fillColor);
|
||||
graphics.fill(outline);
|
||||
}
|
||||
|
||||
//border
|
||||
Color lineColor = shape.getLineColor();
|
||||
if (lineColor != null){
|
||||
graphics.setPaint(lineColor);
|
||||
float width = (float)shape.getLineWidth();
|
||||
if(width == 0) width = 0.75f;
|
||||
|
||||
int dashing = shape.getLineDashing();
|
||||
//TODO: implement more dashing styles
|
||||
float[] dashptrn = null;
|
||||
switch(dashing){
|
||||
case Line.PEN_SOLID:
|
||||
dashptrn = null;
|
||||
break;
|
||||
case Line.PEN_PS_DASH:
|
||||
dashptrn = new float[]{width, width};
|
||||
break;
|
||||
case Line.PEN_DOTGEL:
|
||||
dashptrn = new float[]{width*4, width*3};
|
||||
break;
|
||||
default:
|
||||
logger.log(POILogger.WARN, "unsupported dashing: " + dashing);
|
||||
dashptrn = new float[]{width, width};
|
||||
break;
|
||||
}
|
||||
|
||||
Stroke stroke = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dashptrn, 0.0f);
|
||||
graphics.setStroke(stroke);
|
||||
graphics.draw(outline);
|
||||
}
|
||||
}
|
||||
}
|
@ -29,6 +29,7 @@ import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* This class defines the common format of "Sheets" in a powerpoint
|
||||
@ -246,14 +247,6 @@ public abstract class Sheet {
|
||||
EscherContainerRecord spgr = (EscherContainerRecord) Shape.getEscherChild(dgContainer, EscherContainerRecord.SPGR_CONTAINER);
|
||||
spgr.addChildRecord(shape.getSpContainer());
|
||||
|
||||
EscherDgRecord dg = (EscherDgRecord) Shape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID);
|
||||
dg.setNumShapes(dg.getNumShapes() + 1);
|
||||
|
||||
int shapeId = dg.getLastMSOSPID()+1;
|
||||
dg.setLastMSOSPID(shapeId);
|
||||
|
||||
EscherSpRecord sp = shape.getSpContainer().getChildById(EscherSpRecord.RECORD_ID);
|
||||
if(sp != null) sp.setShapeId(shapeId);
|
||||
shape.setSheet(this);
|
||||
shape.afterInsert(this);
|
||||
|
||||
@ -329,4 +322,7 @@ public abstract class Sheet {
|
||||
return _background;
|
||||
}
|
||||
|
||||
public void draw(Graphics2D graphics){
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.hslf.record.ColorSchemeAtom;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
* An abstract simple (non-group) shape.
|
||||
@ -199,4 +201,87 @@ public class SimpleShape extends Shape {
|
||||
getFill().setForegroundColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the shape is horizontally flipped
|
||||
*
|
||||
* @return whether the shape is horizontally flipped
|
||||
*/
|
||||
public boolean getFlipHorizontal(){
|
||||
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
|
||||
return (spRecord.getFlags()& EscherSpRecord.FLAG_FLIPHORIZ) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the shape is vertically flipped
|
||||
*
|
||||
* @return whether the shape is vertically flipped
|
||||
*/
|
||||
public boolean getFlipVertical(){
|
||||
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
|
||||
return (spRecord.getFlags()& EscherSpRecord.FLAG_FLIPVERT) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotation angle in degrees
|
||||
*
|
||||
* @return rotation angle in degrees
|
||||
*/
|
||||
public int getRotation(){
|
||||
int rot = getEscherProperty(EscherProperties.TRANSFORM__ROTATION);
|
||||
int angle = (rot >> 16) % 360;
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
public Rectangle2D getLogicalAnchor2D(){
|
||||
Rectangle2D anchor = getAnchor2D();
|
||||
|
||||
//if it is a groupped shape see if we need to transform the coordinates
|
||||
if (_parent != null){
|
||||
Shape top = _parent;
|
||||
while(top.getParent() != null) top = top.getParent();
|
||||
|
||||
Rectangle2D clientAnchor = top.getAnchor2D();
|
||||
Rectangle2D spgrAnchor = ((ShapeGroup)top).getCoordinates();
|
||||
|
||||
double scalex = (double)spgrAnchor.getWidth()/clientAnchor.getWidth();
|
||||
double scaley = (double)spgrAnchor.getHeight()/clientAnchor.getHeight();
|
||||
|
||||
double x = clientAnchor.getX() + (anchor.getX() - spgrAnchor.getX())/scalex;
|
||||
double y = clientAnchor.getY() + (anchor.getY() - spgrAnchor.getY())/scaley;
|
||||
double width = anchor.getWidth()/scalex;
|
||||
double height = anchor.getHeight()/scaley;
|
||||
|
||||
anchor = new Rectangle2D.Double(x, y, width, height);
|
||||
|
||||
}
|
||||
|
||||
int angle = getRotation();
|
||||
if(angle != 0){
|
||||
double centerX = anchor.getX() + anchor.getWidth()/2;
|
||||
double centerY = anchor.getY() + anchor.getHeight()/2;
|
||||
|
||||
AffineTransform trans = new AffineTransform();
|
||||
trans.translate(centerX, centerY);
|
||||
trans.rotate(Math.toRadians(angle));
|
||||
trans.translate(-centerX, -centerY);
|
||||
|
||||
Rectangle2D rect = trans.createTransformedShape(anchor).getBounds2D();
|
||||
if((anchor.getWidth() < anchor.getHeight() && rect.getWidth() > rect.getHeight()) ||
|
||||
(anchor.getWidth() > anchor.getHeight() && rect.getWidth() < rect.getHeight()) ){
|
||||
trans = new AffineTransform();
|
||||
trans.translate(centerX, centerY);
|
||||
trans.rotate(Math.PI/2);
|
||||
trans.translate(-centerX, -centerY);
|
||||
anchor = trans.createTransformedShape(anchor).getBounds2D();
|
||||
}
|
||||
}
|
||||
return anchor;
|
||||
}
|
||||
|
||||
public void draw(Graphics2D graphics){
|
||||
AffineTransform at = graphics.getTransform();
|
||||
ShapePainter.paint(this, graphics);
|
||||
graphics.setTransform(at);
|
||||
}
|
||||
}
|
||||
|
@ -21,17 +21,12 @@
|
||||
package org.apache.poi.hslf.model;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
import java.util.ArrayList;
|
||||
import java.awt.*;
|
||||
|
||||
import org.apache.poi.hslf.record.PPDrawing;
|
||||
import org.apache.poi.hslf.record.SlideAtom;
|
||||
import org.apache.poi.hslf.record.TextHeaderAtom;
|
||||
import org.apache.poi.hslf.record.ColorSchemeAtom;
|
||||
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
|
||||
import org.apache.poi.ddf.EscherContainerRecord;
|
||||
import org.apache.poi.ddf.EscherRecord;
|
||||
|
||||
/**
|
||||
* This class represents a slide in a PowerPoint Document. It allows
|
||||
@ -263,10 +258,85 @@ public class Slide extends Sheet
|
||||
return sa.getFollowMasterBackground();
|
||||
}
|
||||
|
||||
public Background getBackground() {
|
||||
/**
|
||||
* Sets whether this slide draws master sheet objects
|
||||
*
|
||||
* @param flag <code>true</code> if the slide draws master sheet objects,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
public void setFollowMasterObjects(boolean flag){
|
||||
SlideAtom sa = getSlideRecord().getSlideAtom();
|
||||
sa.setFollowMasterObjects(flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this slide follows master color scheme
|
||||
*
|
||||
* @return <code>true</code> if the slide follows master color scheme,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
public boolean getFollowMasterScheme(){
|
||||
SlideAtom sa = getSlideRecord().getSlideAtom();
|
||||
return sa.getFollowMasterScheme();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this slide draws master color scheme
|
||||
*
|
||||
* @param flag <code>true</code> if the slide draws master color scheme,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
public void setFollowMasterScheme(boolean flag){
|
||||
SlideAtom sa = getSlideRecord().getSlideAtom();
|
||||
sa.setFollowMasterScheme(flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this slide draws master sheet objects
|
||||
*
|
||||
* @return <code>true</code> if the slide draws master sheet objects,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
public boolean getFollowMasterObjects(){
|
||||
SlideAtom sa = getSlideRecord().getSlideAtom();
|
||||
return sa.getFollowMasterObjects();
|
||||
}
|
||||
|
||||
/**
|
||||
* Background for this slide.
|
||||
*/
|
||||
public Background getBackground() {
|
||||
if(getFollowMasterBackground())
|
||||
return getMasterSheet().getBackground();
|
||||
else
|
||||
return super.getBackground();
|
||||
}
|
||||
|
||||
/**
|
||||
* Color scheme for this slide.
|
||||
*/
|
||||
public ColorSchemeAtom getColorScheme() {
|
||||
if(getFollowMasterScheme()){
|
||||
return getMasterSheet().getColorScheme();
|
||||
}
|
||||
return super.getColorScheme();
|
||||
}
|
||||
|
||||
public void draw(Graphics2D graphics){
|
||||
MasterSheet master = getMasterSheet();
|
||||
if(getFollowMasterBackground()) master.getBackground().draw(graphics);
|
||||
if(getFollowMasterObjects()){
|
||||
Shape[] sh = master.getShapes();
|
||||
for (int i = 0; i < sh.length; i++) {
|
||||
if(MasterSheet.isPlaceholder(sh[i])) continue;
|
||||
|
||||
sh[i].draw(graphics);
|
||||
}
|
||||
}
|
||||
Shape[] sh = getShapes();
|
||||
for (int i = 0; i < sh.length; i++) {
|
||||
sh[i].draw(graphics);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,12 +21,6 @@ import org.apache.poi.hslf.model.textproperties.TextProp;
|
||||
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||
import org.apache.poi.hslf.record.StyleTextPropAtom.*;
|
||||
import org.apache.poi.ddf.EscherContainerRecord;
|
||||
import org.apache.poi.ddf.EscherRecord;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* SlideMaster determines the graphics, layout, and formatting for all the slides in a given presentation.
|
||||
@ -82,17 +76,31 @@ public class SlideMaster extends MasterSheet {
|
||||
if (prop != null) break;
|
||||
}
|
||||
if (prop == null) {
|
||||
switch (txtype) {
|
||||
case TextHeaderAtom.CENTRE_BODY_TYPE:
|
||||
case TextHeaderAtom.HALF_BODY_TYPE:
|
||||
case TextHeaderAtom.QUARTER_BODY_TYPE:
|
||||
txtype = TextHeaderAtom.BODY_TYPE;
|
||||
break;
|
||||
case TextHeaderAtom.CENTER_TITLE_TYPE:
|
||||
txtype = TextHeaderAtom.TITLE_TYPE;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
if(isCharacter) {
|
||||
switch (txtype) {
|
||||
case TextHeaderAtom.CENTRE_BODY_TYPE:
|
||||
case TextHeaderAtom.HALF_BODY_TYPE:
|
||||
case TextHeaderAtom.QUARTER_BODY_TYPE:
|
||||
txtype = TextHeaderAtom.BODY_TYPE;
|
||||
break;
|
||||
case TextHeaderAtom.CENTER_TITLE_TYPE:
|
||||
txtype = TextHeaderAtom.TITLE_TYPE;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
switch (txtype) {
|
||||
case TextHeaderAtom.CENTRE_BODY_TYPE:
|
||||
case TextHeaderAtom.QUARTER_BODY_TYPE:
|
||||
txtype = TextHeaderAtom.BODY_TYPE;
|
||||
break;
|
||||
case TextHeaderAtom.CENTER_TITLE_TYPE:
|
||||
txtype = TextHeaderAtom.TITLE_TYPE;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
prop = getStyleAttribute(txtype, level, name, isCharacter);
|
||||
}
|
||||
@ -119,4 +127,34 @@ public class SlideMaster extends MasterSheet {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the shape is a placeholder.
|
||||
* (placeholders aren't normal shapes, they are visible only in the Edit Master mode)
|
||||
*
|
||||
*
|
||||
* @return true if the shape is a placeholder
|
||||
*/
|
||||
public static boolean isPlaceholder(Shape shape){
|
||||
if(!(shape instanceof TextShape)) return false;
|
||||
|
||||
TextShape tx = (TextShape)shape;
|
||||
TextRun run = tx.getTextRun();
|
||||
if(run == null) return false;
|
||||
|
||||
Record[] records = run._records;
|
||||
for (int i = 0; i < records.length; i++) {
|
||||
int type = (int)records[i].getRecordType();
|
||||
if (type == RecordTypes.OEPlaceholderAtom.typeID ||
|
||||
type == RecordTypes.SlideNumberMCAtom.typeID ||
|
||||
type == RecordTypes.DateTimeMCAtom.typeID ||
|
||||
type == RecordTypes.GenericDateMCAtom.typeID ||
|
||||
type == RecordTypes.FooterMCAtom.typeID ){
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ import org.apache.poi.util.LittleEndian;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
* Represents a table in a PowerPoint presentation
|
||||
@ -113,6 +112,8 @@ public class Table extends ShapeGroup {
|
||||
}
|
||||
|
||||
protected void afterInsert(Sheet sh){
|
||||
super.afterInsert(sh);
|
||||
|
||||
EscherContainerRecord spCont = (EscherContainerRecord) getSpContainer().getChild(0);
|
||||
List lst = spCont.getChildRecords();
|
||||
EscherOptRecord opt = (EscherOptRecord)lst.get(lst.size()-2);
|
||||
|
@ -18,9 +18,7 @@
|
||||
package org.apache.poi.hslf.model;
|
||||
|
||||
import org.apache.poi.ddf.*;
|
||||
import org.apache.poi.hslf.record.EscherTextboxWrapper;
|
||||
import org.apache.poi.hslf.record.TextHeaderAtom;
|
||||
import org.apache.poi.hslf.usermodel.RichTextRun;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
|
@ -19,15 +19,6 @@
|
||||
package org.apache.poi.hslf.model;
|
||||
|
||||
import org.apache.poi.ddf.*;
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import org.apache.poi.hslf.usermodel.RichTextRun;
|
||||
import org.apache.poi.hslf.exceptions.HSLFException;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.TextLayout;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Represents a TextFrame shape in PowerPoint.
|
||||
|
253
src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java
Executable file
253
src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java
Executable file
@ -0,0 +1,253 @@
|
||||
/* ====================================================================
|
||||
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.hslf.model;
|
||||
|
||||
import org.apache.poi.hslf.usermodel.RichTextRun;
|
||||
import org.apache.poi.util.POILogger;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
|
||||
import java.text.AttributedString;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.awt.font.TextAttribute;
|
||||
import java.awt.font.LineBreakMeasurer;
|
||||
import java.awt.font.TextLayout;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Paint text into java.awt.Graphics2D
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class TextPainter {
|
||||
protected POILogger logger = POILogFactory.getLogger(this.getClass());
|
||||
|
||||
protected TextShape _shape;
|
||||
|
||||
public TextPainter(TextShape shape){
|
||||
_shape = shape;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the underlying set of rich text runs into java.text.AttributedString
|
||||
*/
|
||||
public AttributedString getAttributedString(TextRun txrun){
|
||||
String text = txrun.getText();
|
||||
AttributedString at = new AttributedString(text);
|
||||
RichTextRun[] rt = txrun.getRichTextRuns();
|
||||
for (int i = 0; i < rt.length; i++) {
|
||||
int start = rt[i].getStartIndex();
|
||||
int end = rt[i].getEndIndex();
|
||||
if(start == end) {
|
||||
logger.log(POILogger.INFO, "Skipping RichTextRun with zero length");
|
||||
continue;
|
||||
}
|
||||
|
||||
at.addAttribute(TextAttribute.FAMILY, rt[i].getFontName(), start, end);
|
||||
at.addAttribute(TextAttribute.SIZE, new Float(rt[i].getFontSize()), start, end);
|
||||
at.addAttribute(TextAttribute.FOREGROUND, rt[i].getFontColor(), start, end);
|
||||
if(rt[i].isBold()) at.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, start, end);
|
||||
if(rt[i].isItalic()) at.addAttribute(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE, start, end);
|
||||
if(rt[i].isUnderlined()) {
|
||||
at.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, start, end);
|
||||
at.addAttribute(TextAttribute.INPUT_METHOD_UNDERLINE, TextAttribute.UNDERLINE_LOW_TWO_PIXEL, start, end);
|
||||
}
|
||||
if(rt[i].isStrikethrough()) at.addAttribute(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON, start, end);
|
||||
int superScript = rt[i].getSuperscript();
|
||||
if(superScript != 0) at.addAttribute(TextAttribute.SUPERSCRIPT, superScript > 0 ? TextAttribute.SUPERSCRIPT_SUPER : TextAttribute.SUPERSCRIPT_SUB, start, end);
|
||||
|
||||
}
|
||||
return at;
|
||||
}
|
||||
|
||||
public void paint(Graphics2D graphics){
|
||||
TextRun run = _shape.getTextRun();
|
||||
if (run == null) return;
|
||||
|
||||
String text = run.getText();
|
||||
if (text == null || text.equals("")) return;
|
||||
|
||||
AttributedString at = getAttributedString(run);
|
||||
|
||||
AttributedCharacterIterator it = at.getIterator();
|
||||
int paragraphStart = it.getBeginIndex();
|
||||
int paragraphEnd = it.getEndIndex();
|
||||
|
||||
Rectangle2D anchor = _shape.getLogicalAnchor2D();
|
||||
|
||||
float textHeight = 0;
|
||||
ArrayList lines = new ArrayList();
|
||||
LineBreakMeasurer measurer = new LineBreakMeasurer(it, graphics.getFontRenderContext());
|
||||
measurer.setPosition(paragraphStart);
|
||||
while (measurer.getPosition() < paragraphEnd) {
|
||||
int startIndex = measurer.getPosition();
|
||||
int nextBreak = text.indexOf('\n', measurer.getPosition() + 1);
|
||||
|
||||
boolean prStart = text.charAt(startIndex) == '\n';
|
||||
if(prStart) measurer.setPosition(startIndex++);
|
||||
|
||||
RichTextRun rt = run.getRichTextRunAt(startIndex == text.length() ? (startIndex-1) : startIndex);
|
||||
if(rt == null) {
|
||||
logger.log(POILogger.WARN, "RichTextRun not found at pos" + startIndex + "; text.length: " + text.length());
|
||||
break;
|
||||
}
|
||||
|
||||
float wrappingWidth = (float)anchor.getWidth() - _shape.getMarginLeft() - _shape.getMarginRight();
|
||||
wrappingWidth -= rt.getTextOffset();
|
||||
|
||||
if (_shape.getWordWrap() == TextShape.WrapNone) {
|
||||
wrappingWidth = _shape.getSheet().getSlideShow().getPageSize().width;
|
||||
}
|
||||
|
||||
TextLayout textLayout = measurer.nextLayout(wrappingWidth + 1,
|
||||
nextBreak == -1 ? paragraphEnd : nextBreak, true);
|
||||
if (textLayout == null) {
|
||||
textLayout = measurer.nextLayout((float)anchor.getWidth(),
|
||||
nextBreak == -1 ? paragraphEnd : nextBreak, false);
|
||||
}
|
||||
if(textLayout == null){
|
||||
logger.log(POILogger.WARN, "Failed to break text into lines: wrappingWidth: "+wrappingWidth+
|
||||
"; text: " + rt.getText());
|
||||
measurer.setPosition(rt.getEndIndex());
|
||||
continue;
|
||||
}
|
||||
int endIndex = measurer.getPosition();
|
||||
|
||||
float lineHeight = (float)textLayout.getBounds().getHeight();
|
||||
int linespacing = rt.getLineSpacing();
|
||||
if(linespacing == 0) linespacing = 100;
|
||||
|
||||
TextElement el = new TextElement();
|
||||
if(linespacing >= 0){
|
||||
el.ascent = textLayout.getAscent()*linespacing/100;
|
||||
} else {
|
||||
el.ascent = -linespacing*Shape.POINT_DPI/Shape.MASTER_DPI;
|
||||
}
|
||||
|
||||
el._align = rt.getAlignment();
|
||||
el._text = textLayout;
|
||||
el._textOffset = rt.getTextOffset();
|
||||
|
||||
if (prStart){
|
||||
int sp = rt.getSpaceBefore();
|
||||
float spaceBefore;
|
||||
if(sp >= 0){
|
||||
spaceBefore = lineHeight * sp/100;
|
||||
} else {
|
||||
spaceBefore = -sp*Shape.POINT_DPI/Shape.MASTER_DPI;
|
||||
}
|
||||
el.ascent += spaceBefore;
|
||||
}
|
||||
|
||||
float descent;
|
||||
if(linespacing >= 0){
|
||||
descent = (textLayout.getDescent() + textLayout.getLeading())*linespacing/100;
|
||||
} else {
|
||||
descent = -linespacing*Shape.POINT_DPI/Shape.MASTER_DPI;
|
||||
}
|
||||
if (prStart){
|
||||
int sp = rt.getSpaceAfter();
|
||||
float spaceAfter;
|
||||
if(sp >= 0){
|
||||
spaceAfter = lineHeight * sp/100;
|
||||
} else {
|
||||
spaceAfter = -sp*Shape.POINT_DPI/Shape.MASTER_DPI;
|
||||
}
|
||||
el.ascent += spaceAfter;
|
||||
}
|
||||
el.descent = descent;
|
||||
|
||||
textHeight += el.ascent + el.descent;
|
||||
|
||||
if(rt.isBullet() && (prStart || startIndex == 0)){
|
||||
it.setIndex(startIndex);
|
||||
|
||||
AttributedString bat = new AttributedString(Character.toString(rt.getBulletChar()));
|
||||
Color clr = rt.getBulletColor();
|
||||
if (clr != null) bat.addAttribute(TextAttribute.FOREGROUND, clr);
|
||||
else bat.addAttribute(TextAttribute.FOREGROUND, it.getAttribute(TextAttribute.FOREGROUND));
|
||||
bat.addAttribute(TextAttribute.FAMILY, it.getAttribute(TextAttribute.FAMILY));
|
||||
bat.addAttribute(TextAttribute.SIZE, it.getAttribute(TextAttribute.SIZE));
|
||||
|
||||
TextLayout bulletLayout = new TextLayout(bat.getIterator(), graphics.getFontRenderContext());
|
||||
if(text.substring(startIndex, endIndex).length() > 1){
|
||||
el._bullet = bulletLayout;
|
||||
el._bulletOffset = rt.getBulletOffset();
|
||||
}
|
||||
}
|
||||
lines.add(el);
|
||||
}
|
||||
|
||||
int valign = _shape.getVerticalAlignment();
|
||||
double y0 = anchor.getY();
|
||||
switch (valign){
|
||||
case TextShape.AnchorTopBaseline:
|
||||
case TextShape.AnchorTop:
|
||||
y0 += _shape.getMarginTop();
|
||||
break;
|
||||
case TextShape.AnchorBottom:
|
||||
y0 += anchor.getHeight() - textHeight - _shape.getMarginBottom();
|
||||
break;
|
||||
default:
|
||||
case TextShape.AnchorMiddle:
|
||||
float delta = (float)anchor.getHeight() - textHeight - _shape.getMarginTop() - _shape.getMarginBottom();
|
||||
y0 += _shape.getMarginTop() + delta/2;
|
||||
break;
|
||||
}
|
||||
|
||||
//finally draw the text fragments
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
TextElement elem = (TextElement)lines.get(i);
|
||||
y0 += elem.ascent;
|
||||
|
||||
Point2D.Double pen = new Point2D.Double();
|
||||
pen.y = y0;
|
||||
switch (elem._align) {
|
||||
default:
|
||||
case TextShape.AlignLeft:
|
||||
pen.x = anchor.getX() + _shape.getMarginLeft();
|
||||
break;
|
||||
case TextShape.AlignCenter:
|
||||
pen.x = anchor.getX() + _shape.getMarginLeft() +
|
||||
(anchor.getWidth() - elem._text.getAdvance() - _shape.getMarginLeft() - _shape.getMarginRight()) / 2;
|
||||
break;
|
||||
case TextShape.AlignRight:
|
||||
pen.x = anchor.getX() + _shape.getMarginLeft() +
|
||||
(anchor.getWidth() - elem._text.getAdvance() - _shape.getMarginLeft() - _shape.getMarginRight());
|
||||
break;
|
||||
}
|
||||
if(elem._bullet != null){
|
||||
elem._bullet.draw(graphics, (float)(pen.x + elem._bulletOffset), (float)pen.y);
|
||||
}
|
||||
elem._text.draw(graphics, (float)(pen.x + elem._textOffset), (float)pen.y);
|
||||
|
||||
y0 += elem.descent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class TextElement {
|
||||
public TextLayout _text;
|
||||
public int _textOffset;
|
||||
public TextLayout _bullet;
|
||||
public int _bulletOffset;
|
||||
public int _align;
|
||||
public float ascent, descent;
|
||||
}
|
||||
}
|
@ -534,6 +534,10 @@ public class TextRun
|
||||
// The messes things up on everything but a Mac, so translate
|
||||
// them to \n
|
||||
String text = rawText.replace('\r','\n');
|
||||
|
||||
//0xB acts like cariage return in page titles
|
||||
text = text.replace((char) 0x0B, '\n');
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
@ -635,4 +639,20 @@ public class TextRun
|
||||
public Hyperlink[] getHyperlinks(){
|
||||
return Hyperlink.find(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch RichTextRun at a given position
|
||||
*
|
||||
* @param pos 0-based index in the text
|
||||
* @return RichTextRun or null if not found
|
||||
*/
|
||||
public RichTextRun getRichTextRunAt(int pos){
|
||||
for (int i = 0; i < _rtRuns.length; i++) {
|
||||
int start = _rtRuns[i].getStartIndex();
|
||||
int end = _rtRuns[i].getEndIndex();
|
||||
if(pos >= start && pos < end) return _rtRuns[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -184,6 +184,8 @@ public abstract class TextShape extends SimpleShape {
|
||||
* @param sh the sheet we are adding to
|
||||
*/
|
||||
protected void afterInsert(Sheet sh){
|
||||
super.afterInsert(sh);
|
||||
|
||||
EscherTextboxWrapper _txtbox = getEscherTextboxWrapper();
|
||||
if(_txtbox != null){
|
||||
PPDrawing ppdrawing = sh.getPPDrawing();
|
||||
@ -513,4 +515,12 @@ public abstract class TextShape extends SimpleShape {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(Graphics2D graphics){
|
||||
AffineTransform at = graphics.getTransform();
|
||||
ShapePainter.paint(this, graphics);
|
||||
new TextPainter(this).paint(graphics);
|
||||
graphics.setTransform(at);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,7 +30,10 @@ import org.apache.poi.util.LittleEndian;
|
||||
*
|
||||
* @author Daniel Noll
|
||||
*/
|
||||
public class ExOleObjStg extends RecordAtom {
|
||||
public class ExOleObjStg extends RecordAtom implements PersistRecord {
|
||||
|
||||
private int _persistId; // Found from PersistPtrHolder
|
||||
|
||||
/**
|
||||
* Record header.
|
||||
*/
|
||||
@ -109,4 +112,19 @@ public class ExOleObjStg extends RecordAtom {
|
||||
out.write(_header);
|
||||
out.write(_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch our sheet ID, as found from a PersistPtrHolder.
|
||||
* Should match the RefId of our matching SlidePersistAtom
|
||||
*/
|
||||
public int getPersistId() {
|
||||
return _persistId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set our sheet ID, as found from a PersistPtrHolder
|
||||
*/
|
||||
public void setPersistId(int id) {
|
||||
_persistId = id;
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,8 @@ public class PPDrawingGroup extends RecordAtom {
|
||||
|
||||
private byte[] _header;
|
||||
private EscherContainerRecord dggContainer;
|
||||
//cached dgg
|
||||
private EscherDggRecord dgg;
|
||||
|
||||
protected PPDrawingGroup(byte[] source, int start, int len) {
|
||||
// Get the header
|
||||
@ -116,4 +118,17 @@ public class PPDrawingGroup extends RecordAtom {
|
||||
public EscherContainerRecord getDggContainer(){
|
||||
return dggContainer;
|
||||
}
|
||||
|
||||
public EscherDggRecord getEscherDggRecord(){
|
||||
if(dgg == null){
|
||||
for(Iterator it = dggContainer.getChildRecords().iterator(); it.hasNext();){
|
||||
EscherRecord r = (EscherRecord) it.next();
|
||||
if(r instanceof EscherDggRecord){
|
||||
dgg = (EscherDggRecord)r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dgg;
|
||||
}
|
||||
}
|
||||
|
37
src/scratchpad/src/org/apache/poi/hslf/record/PersistRecord.java
Executable file
37
src/scratchpad/src/org/apache/poi/hslf/record/PersistRecord.java
Executable file
@ -0,0 +1,37 @@
|
||||
|
||||
/* ====================================================================
|
||||
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.hslf.record;
|
||||
|
||||
/**
|
||||
* A record that can be referenced in PersistPtr storage.
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public interface PersistRecord {
|
||||
|
||||
/**
|
||||
* Fetch the persist ID
|
||||
*/
|
||||
public int getPersistId();
|
||||
|
||||
/**
|
||||
* Set the persist ID
|
||||
*/
|
||||
public void setPersistId(int id);
|
||||
}
|
@ -70,9 +70,10 @@ public class RecordTypes {
|
||||
public static final Type List = new Type(2000,null);
|
||||
public static final Type FontCollection = new Type(2005,FontCollection.class);
|
||||
public static final Type BookmarkCollection = new Type(2019,null);
|
||||
public static final Type SoundCollection = new Type(2020,SoundCollection.class);
|
||||
public static final Type SoundCollAtom = new Type(2021,null);
|
||||
public static final Type Sound = new Type(2022,null);
|
||||
public static final Type SoundData = new Type(2023,null);
|
||||
public static final Type Sound = new Type(2022,Sound.class);
|
||||
public static final Type SoundData = new Type(2023,SoundData.class);
|
||||
public static final Type BookmarkSeedAtom = new Type(2025,null);
|
||||
public static final Type ColorSchemeAtom = new Type(2032,ColorSchemeAtom.class);
|
||||
public static final Type ExObjRefAtom = new Type(3009,null);
|
||||
|
136
src/scratchpad/src/org/apache/poi/hslf/record/Sound.java
Executable file
136
src/scratchpad/src/org/apache/poi/hslf/record/Sound.java
Executable file
@ -0,0 +1,136 @@
|
||||
/* ====================================================================
|
||||
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.hslf.record;
|
||||
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A container holding information about a sound. It contains:
|
||||
* <p>
|
||||
* <li>1. CString (4026), Instance 0: Name of sound (e.g. "crash")
|
||||
* <li>2. CString (4026), Instance 1: Type of sound (e.g. ".wav")
|
||||
* <li>3. CString (4026), Instance 2: Reference id of sound in sound collection
|
||||
* <li>4. CString (4026), Instance 3, optional: Built-in id of sound, for sounds we ship. This is the id that?s in the reg file.
|
||||
* <li>5. SoundData (2023), optional
|
||||
* </p>
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class Sound extends RecordContainer {
|
||||
/**
|
||||
* Record header data.
|
||||
*/
|
||||
private byte[] _header;
|
||||
|
||||
// Links to our more interesting children
|
||||
private CString _name;
|
||||
private CString _type;
|
||||
private SoundData _data;
|
||||
|
||||
|
||||
/**
|
||||
* Set things up, and find our more interesting children
|
||||
*
|
||||
* @param source the source data as a byte array.
|
||||
* @param start the start offset into the byte array.
|
||||
* @param len the length of the slice in the byte array.
|
||||
*/
|
||||
protected Sound(byte[] source, int start, int len) {
|
||||
// Grab the header
|
||||
_header = new byte[8];
|
||||
System.arraycopy(source,start,_header,0,8);
|
||||
|
||||
// Find our children
|
||||
_children = Record.findChildRecords(source,start+8,len-8);
|
||||
findInterestingChildren();
|
||||
}
|
||||
|
||||
private void findInterestingChildren() {
|
||||
// First child should be the ExHyperlinkAtom
|
||||
if(_children[0] instanceof CString) {
|
||||
_name = (CString)_children[0];
|
||||
} else {
|
||||
logger.log(POILogger.ERROR, "First child record wasn't a CString, was of type " + _children[0].getRecordType());
|
||||
}
|
||||
|
||||
// Second child should be the ExOleObjAtom
|
||||
if (_children[1] instanceof CString) {
|
||||
_type = (CString)_children[1];
|
||||
} else {
|
||||
logger.log(POILogger.ERROR, "Second child record wasn't a CString, was of type " + _children[1].getRecordType());
|
||||
}
|
||||
|
||||
for (int i = 2; i < _children.length; i++) {
|
||||
if(_children[i] instanceof SoundData){
|
||||
_data = (SoundData)_children[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type (held as a little endian in bytes 3 and 4)
|
||||
* that this class handles.
|
||||
*
|
||||
* @return the record type.
|
||||
*/
|
||||
public long getRecordType() {
|
||||
return RecordTypes.Sound.typeID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Have the contents printer out into an OutputStream, used when
|
||||
* writing a file back out to disk.
|
||||
*
|
||||
* @param out the output stream.
|
||||
* @throws java.io.IOException if there was an error writing to the stream.
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
writeOut(_header[0],_header[1],getRecordType(),_children,out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the sound (e.g. "crash")
|
||||
*
|
||||
* @return name of the sound
|
||||
*/
|
||||
public String getSoundName(){
|
||||
return _name.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of the sound (e.g. ".wav")
|
||||
*
|
||||
* @return type of the sound
|
||||
*/
|
||||
public String getSoundType(){
|
||||
return _type.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* The sound data
|
||||
*
|
||||
* @return the sound data.
|
||||
*/
|
||||
public byte[] getSoundData(){
|
||||
return _data == null ? null : _data.getData();
|
||||
}
|
||||
}
|
73
src/scratchpad/src/org/apache/poi/hslf/record/SoundCollection.java
Executable file
73
src/scratchpad/src/org/apache/poi/hslf/record/SoundCollection.java
Executable file
@ -0,0 +1,73 @@
|
||||
/* ====================================================================
|
||||
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.hslf.record;
|
||||
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Is a container for all sound related atoms and containers. It contains:
|
||||
*<li>1. SoundCollAtom (2021)
|
||||
*<li>2. Sound (2022), for each sound, if any
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class SoundCollection extends RecordContainer {
|
||||
/**
|
||||
* Record header data.
|
||||
*/
|
||||
private byte[] _header;
|
||||
|
||||
/**
|
||||
* Set things up, and find our more interesting children
|
||||
*
|
||||
* @param source the source data as a byte array.
|
||||
* @param start the start offset into the byte array.
|
||||
* @param len the length of the slice in the byte array.
|
||||
*/
|
||||
protected SoundCollection(byte[] source, int start, int len) {
|
||||
// Grab the header
|
||||
_header = new byte[8];
|
||||
System.arraycopy(source,start,_header,0,8);
|
||||
|
||||
// Find our children
|
||||
_children = Record.findChildRecords(source,start+8,len-8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type (held as a little endian in bytes 3 and 4)
|
||||
* that this class handles.
|
||||
*
|
||||
* @return the record type.
|
||||
*/
|
||||
public long getRecordType() {
|
||||
return RecordTypes.SoundCollection.typeID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Have the contents printer out into an OutputStream, used when
|
||||
* writing a file back out to disk.
|
||||
*
|
||||
* @param out the output stream.
|
||||
* @throws java.io.IOException if there was an error writing to the stream.
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
writeOut(_header[0],_header[1],getRecordType(),_children,out);
|
||||
}
|
||||
}
|
103
src/scratchpad/src/org/apache/poi/hslf/record/SoundData.java
Executable file
103
src/scratchpad/src/org/apache/poi/hslf/record/SoundData.java
Executable file
@ -0,0 +1,103 @@
|
||||
/* ====================================================================
|
||||
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.hslf.record;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* Storage for embedded sounds.
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class SoundData extends RecordAtom {
|
||||
|
||||
/**
|
||||
* Record header.
|
||||
*/
|
||||
private byte[] _header;
|
||||
|
||||
/**
|
||||
* Record data.
|
||||
*/
|
||||
private byte[] _data;
|
||||
|
||||
/**
|
||||
* Constructs a new empty sound container.
|
||||
*/
|
||||
protected SoundData() {
|
||||
_header = new byte[8];
|
||||
_data = new byte[0];
|
||||
|
||||
LittleEndian.putShort(_header, 2, (short)getRecordType());
|
||||
LittleEndian.putInt(_header, 4, _data.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the link related atom record from its
|
||||
* source data.
|
||||
*
|
||||
* @param source the source data as a byte array.
|
||||
* @param start the start offset into the byte array.
|
||||
* @param len the length of the slice in the byte array.
|
||||
*/
|
||||
protected SoundData(byte[] source, int start, int len) {
|
||||
// Get the header.
|
||||
_header = new byte[8];
|
||||
System.arraycopy(source,start,_header,0,8);
|
||||
|
||||
// Get the record data.
|
||||
_data = new byte[len-8];
|
||||
System.arraycopy(source,start+8,_data,0,len-8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sound data.
|
||||
*
|
||||
* @return the sound data
|
||||
*/
|
||||
public byte[] getData() {
|
||||
return _data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the record type.
|
||||
*
|
||||
* @return the record type.
|
||||
*/
|
||||
public long getRecordType() {
|
||||
return RecordTypes.SoundData.typeID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the contents of the record back, so it can be written
|
||||
* to disk.
|
||||
*
|
||||
* @param out the output stream to write to.
|
||||
* @throws java.io.IOException if an error occurs.
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
out.write(_header);
|
||||
out.write(_data);
|
||||
}
|
||||
}
|
@ -150,7 +150,7 @@ public class StyleTextPropAtom extends RecordAtom
|
||||
new TextProp(2, 0x800000, "symbol"),
|
||||
new TextProp(2, 0x20000, "font.size"),
|
||||
new TextProp(4, 0x40000, "font.color"),
|
||||
new TextProp(2, 0x80000, "offset"),
|
||||
new TextProp(2, 0x80000, "superscript"),
|
||||
new TextProp(2, 0x100000, "char_unknown_1"),
|
||||
new TextProp(2, 0x1000000, "char_unknown_3"),
|
||||
new TextProp(2, 0x2000000, "char_unknown_4"),
|
||||
|
@ -48,4 +48,13 @@ public class ObjectData {
|
||||
public InputStream getData() {
|
||||
return storage.getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the record that contains the object data.
|
||||
*
|
||||
* @return the record that contains the object data.
|
||||
*/
|
||||
public ExOleObjStg getExOleObjStg() {
|
||||
return storage;
|
||||
}
|
||||
}
|
||||
|
@ -37,9 +37,6 @@ import org.apache.poi.hslf.record.ColorSchemeAtom;
|
||||
/**
|
||||
* Represents a run of text, all with the same style
|
||||
*
|
||||
* TODO: finish all the getters and setters to the
|
||||
* font/character/paragraph properties (currently only
|
||||
* has some of them)
|
||||
*/
|
||||
public class RichTextRun {
|
||||
/** The TextRun we belong to */
|
||||
@ -125,7 +122,25 @@ public class RichTextRun {
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The beginning index, inclusive.
|
||||
*
|
||||
* @return the beginning index, inclusive.
|
||||
*/
|
||||
public int getStartIndex(){
|
||||
return startPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* The ending index, exclusive.
|
||||
*
|
||||
* @return the ending index, exclusive.
|
||||
*/
|
||||
public int getEndIndex(){
|
||||
return startPos + length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the text, in output suitable form
|
||||
*/
|
||||
@ -313,35 +328,143 @@ public class RichTextRun {
|
||||
|
||||
|
||||
// --------------- Friendly getters / setters on rich text properties -------
|
||||
|
||||
|
||||
/**
|
||||
* Is the text bold?
|
||||
*/
|
||||
public boolean isBold() {
|
||||
return isCharFlagsTextPropVal(CharFlagsTextProp.BOLD_IDX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the text bold?
|
||||
*/
|
||||
public void setBold(boolean bold) {
|
||||
setCharFlagsTextPropVal(CharFlagsTextProp.BOLD_IDX, bold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the text italic?
|
||||
*/
|
||||
public boolean isItalic() {
|
||||
return isCharFlagsTextPropVal(CharFlagsTextProp.ITALIC_IDX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the text italic?
|
||||
*/
|
||||
public void setItalic(boolean italic) {
|
||||
setCharFlagsTextPropVal(CharFlagsTextProp.ITALIC_IDX, italic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the text underlined?
|
||||
*/
|
||||
public boolean isUnderlined() {
|
||||
return isCharFlagsTextPropVal(CharFlagsTextProp.UNDERLINE_IDX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the text underlined?
|
||||
*/
|
||||
public void setUnderlined(boolean underlined) {
|
||||
setCharFlagsTextPropVal(CharFlagsTextProp.UNDERLINE_IDX, underlined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Does the text have a shadow?
|
||||
*/
|
||||
public boolean isShadowed() {
|
||||
return isCharFlagsTextPropVal(CharFlagsTextProp.SHADOW_IDX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the text have a shadow?
|
||||
*/
|
||||
public void setShadowed(boolean flag) {
|
||||
setCharFlagsTextPropVal(CharFlagsTextProp.SHADOW_IDX, flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this text embossed?
|
||||
*/
|
||||
public boolean isEmbossed() {
|
||||
return isCharFlagsTextPropVal(CharFlagsTextProp.RELIEF_IDX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this text embossed?
|
||||
*/
|
||||
public void setEmbossed(boolean flag) {
|
||||
setCharFlagsTextPropVal(CharFlagsTextProp.RELIEF_IDX, flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the strikethrough flag
|
||||
*/
|
||||
public boolean isStrikethrough() {
|
||||
return isCharFlagsTextPropVal(CharFlagsTextProp.STRIKETHROUGH_IDX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strikethrough flag
|
||||
*/
|
||||
public void setStrikethrough(boolean flag) {
|
||||
setCharFlagsTextPropVal(CharFlagsTextProp.STRIKETHROUGH_IDX, flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the subscript/superscript option
|
||||
*
|
||||
* @return the percentage of the font size. If the value is positive, it is superscript, otherwise it is subscript
|
||||
*/
|
||||
public int getSuperscript() {
|
||||
int val = getCharTextPropVal("superscript");
|
||||
return val == -1 ? 0 : val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the subscript/superscript option
|
||||
*
|
||||
* @param val the percentage of the font size. If the value is positive, it is superscript, otherwise it is subscript
|
||||
*/
|
||||
public void setSuperscript(int val) {
|
||||
setCharTextPropVal("superscript", val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the font size
|
||||
*/
|
||||
public int getFontSize() {
|
||||
return getCharTextPropVal("font.size");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the font size
|
||||
*/
|
||||
public void setFontSize(int fontSize) {
|
||||
setCharTextPropVal("font.size", fontSize);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the font index
|
||||
*/
|
||||
public int getFontIndex() {
|
||||
return getCharTextPropVal("font.index");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the font index
|
||||
*/
|
||||
public void setFontIndex(int idx) {
|
||||
setCharTextPropVal("font.index", idx);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the font name to use
|
||||
*/
|
||||
public void setFontName(String fontName) {
|
||||
if (slideShow == null) {
|
||||
//we can't set font since slideshow is not assigned yet
|
||||
@ -352,6 +475,10 @@ public class RichTextRun {
|
||||
setCharTextPropVal("font.index", fontIdx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the font name
|
||||
*/
|
||||
public String getFontName() {
|
||||
if (slideShow == null) {
|
||||
return _fontname;
|
||||
@ -368,12 +495,12 @@ public class RichTextRun {
|
||||
*/
|
||||
public Color getFontColor() {
|
||||
int rgb = getCharTextPropVal("font.color");
|
||||
if (rgb >= 0x8000000) {
|
||||
int idx = rgb % 0x8000000;
|
||||
ColorSchemeAtom ca = parentRun.getSheet().getColorScheme();
|
||||
if(idx >= 0 && idx <= 7) rgb = ca.getColor(idx);
|
||||
}
|
||||
|
||||
int cidx = rgb >> 24;
|
||||
if (rgb % 0x1000000 == 0){
|
||||
ColorSchemeAtom ca = parentRun.getSheet().getColorScheme();
|
||||
if(cidx >= 0 && cidx <= 7) rgb = ca.getColor(cidx);
|
||||
}
|
||||
Color tmp = new Color(rgb, true);
|
||||
return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());
|
||||
}
|
||||
@ -427,7 +554,7 @@ public class RichTextRun {
|
||||
/**
|
||||
* Sets indentation level
|
||||
*
|
||||
* @param level indentation level. Must be in the range [0, 5]
|
||||
* @param level indentation level. Must be in the range [0, 4]
|
||||
*/
|
||||
public void setIndentLevel(int level) {
|
||||
if(paragraphStyle != null ) paragraphStyle.setReservedField((short)level);
|
||||
@ -488,6 +615,133 @@ public class RichTextRun {
|
||||
public int getTextOffset() {
|
||||
return getParaTextPropVal("text.offset")*Shape.POINT_DPI/Shape.MASTER_DPI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bullet size
|
||||
*/
|
||||
public void setBulletSize(int size) {
|
||||
setParaTextPropVal("bullet.size", size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bullet size
|
||||
*/
|
||||
public int getBulletSize() {
|
||||
return getParaTextPropVal("bullet.size");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bullet color
|
||||
*/
|
||||
public void setBulletColor(Color color) {
|
||||
int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 254).getRGB();
|
||||
setParaTextPropVal("bullet.color", rgb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bullet color
|
||||
*/
|
||||
public Color getBulletColor() {
|
||||
int rgb = getParaTextPropVal("bullet.color");
|
||||
if(rgb == -1) return getFontColor();
|
||||
|
||||
int cidx = rgb >> 24;
|
||||
if (rgb % 0x1000000 == 0){
|
||||
ColorSchemeAtom ca = parentRun.getSheet().getColorScheme();
|
||||
if(cidx >= 0 && cidx <= 7) rgb = ca.getColor(cidx);
|
||||
}
|
||||
Color tmp = new Color(rgb, true);
|
||||
return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bullet font
|
||||
*/
|
||||
public void setBulletFont(int idx) {
|
||||
setParaTextPropVal("bullet.font", idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bullet font
|
||||
*/
|
||||
public int getBulletFont() {
|
||||
return getParaTextPropVal("bullet.font");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the line spacing.
|
||||
* <p>
|
||||
* If linespacing >= 0, then linespacing is a percentage of normal line height.
|
||||
* If linespacing < 0, the absolute value of linespacing is the spacing in master coordinates.
|
||||
* </p>
|
||||
*/
|
||||
public void setLineSpacing(int val) {
|
||||
setParaTextPropVal("linespacing", val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the line spacing
|
||||
* <p>
|
||||
* If linespacing >= 0, then linespacing is a percentage of normal line height.
|
||||
* If linespacing < 0, the absolute value of linespacing is the spacing in master coordinates.
|
||||
* </p>
|
||||
*
|
||||
* @return the spacing between lines
|
||||
*/
|
||||
public int getLineSpacing() {
|
||||
int val = getParaTextPropVal("linespacing");
|
||||
return val == -1 ? 0 : val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets spacing before a paragraph.
|
||||
* <p>
|
||||
* If spacebefore >= 0, then spacebefore is a percentage of normal line height.
|
||||
* If spacebefore < 0, the absolute value of spacebefore is the spacing in master coordinates.
|
||||
* </p>
|
||||
*/
|
||||
public void setSpaceBefore(int val) {
|
||||
setParaTextPropVal("spacebefore", val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns spacing before a paragraph
|
||||
* <p>
|
||||
* If spacebefore >= 0, then spacebefore is a percentage of normal line height.
|
||||
* If spacebefore < 0, the absolute value of spacebefore is the spacing in master coordinates.
|
||||
* </p>
|
||||
*
|
||||
* @return the spacing before a paragraph
|
||||
*/
|
||||
public int getSpaceBefore() {
|
||||
int val = getParaTextPropVal("spacebefore");
|
||||
return val == -1 ? 0 : val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets spacing after a paragraph.
|
||||
* <p>
|
||||
* If spaceafter >= 0, then spaceafter is a percentage of normal line height.
|
||||
* If spaceafter < 0, the absolute value of spaceafter is the spacing in master coordinates.
|
||||
* </p>
|
||||
*/
|
||||
public void setSpaceAfter(int val) {
|
||||
setParaTextPropVal("spaceafter", val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns spacing after a paragraph
|
||||
* <p>
|
||||
* If spaceafter >= 0, then spaceafter is a percentage of normal line height.
|
||||
* If spaceafter < 0, the absolute value of spaceafter is the spacing in master coordinates.
|
||||
* </p>
|
||||
*
|
||||
* @return the spacing before a paragraph
|
||||
*/
|
||||
public int getSpaceAfter() {
|
||||
int val = getParaTextPropVal("spaceafter");
|
||||
return val == -1 ? 0 : val;
|
||||
}
|
||||
// --------------- Internal HSLF methods, not intended for end-user use! -------
|
||||
|
||||
/**
|
||||
|
@ -487,7 +487,21 @@ public class SlideShow
|
||||
public PictureData[] getPictureData() {
|
||||
return _hslfSlideShow.getPictures();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the data of all the embedded OLE object in the SlideShow
|
||||
*/
|
||||
public ObjectData[] getEmbeddedObjects() {
|
||||
return _hslfSlideShow.getEmbeddedObjects();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data of all the embedded sounds in the SlideShow
|
||||
*/
|
||||
public SoundData[] getSoundData() {
|
||||
return SoundData.find(_documentRecord);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current page size
|
||||
*/
|
||||
|
93
src/scratchpad/src/org/apache/poi/hslf/usermodel/SoundData.java
Executable file
93
src/scratchpad/src/org/apache/poi/hslf/usermodel/SoundData.java
Executable 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.hslf.usermodel;
|
||||
|
||||
import org.apache.poi.hslf.record.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* A class that represents sound data embedded in a slide show.
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class SoundData {
|
||||
/**
|
||||
* The record that contains the object data.
|
||||
*/
|
||||
private Sound _container;
|
||||
|
||||
/**
|
||||
* Creates the object data wrapping the record that contains the sound data.
|
||||
*
|
||||
* @param container the record that contains the sound data.
|
||||
*/
|
||||
public SoundData(Sound container) {
|
||||
this._container = container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the sound (e.g. "crash")
|
||||
*
|
||||
* @return name of the sound
|
||||
*/
|
||||
public String getSoundName(){
|
||||
return _container.getSoundName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of the sound (e.g. ".wav")
|
||||
*
|
||||
* @return type of the sound
|
||||
*/
|
||||
public String getSoundType(){
|
||||
return _container.getSoundType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an input stream which returns the binary of the sound data.
|
||||
*
|
||||
* @return the input stream which will contain the binary of the sound data.
|
||||
*/
|
||||
public byte[] getData() {
|
||||
return _container.getSoundData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all sound records in the supplied Document records
|
||||
*
|
||||
* @param document the document to find in
|
||||
* @return the array with the sound data
|
||||
*/
|
||||
public static SoundData[] find(Document document){
|
||||
ArrayList lst = new ArrayList();
|
||||
Record[] ch = document.getChildRecords();
|
||||
for (int i = 0; i < ch.length; i++) {
|
||||
if(ch[i].getRecordType() == RecordTypes.SoundCollection.typeID){
|
||||
RecordContainer col = (RecordContainer)ch[i];
|
||||
Record[] sr = col.getChildRecords();
|
||||
for (int j = 0; j < sr.length; j++) {
|
||||
if(sr[j] instanceof Sound){
|
||||
lst.add(new SoundData((Sound)sr[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return (SoundData[])lst.toArray(new SoundData[lst.size()]);
|
||||
}
|
||||
}
|
BIN
src/scratchpad/testcases/org/apache/poi/hslf/data/41071.ppt
Executable file
BIN
src/scratchpad/testcases/org/apache/poi/hslf/data/41071.ppt
Executable file
Binary file not shown.
BIN
src/scratchpad/testcases/org/apache/poi/hslf/data/ringin.wav
Executable file
BIN
src/scratchpad/testcases/org/apache/poi/hslf/data/ringin.wav
Executable file
Binary file not shown.
BIN
src/scratchpad/testcases/org/apache/poi/hslf/data/sound.ppt
Executable file
BIN
src/scratchpad/testcases/org/apache/poi/hslf/data/sound.ppt
Executable file
Binary file not shown.
80
src/scratchpad/testcases/org/apache/poi/hslf/model/TestFreeform.java
Executable file
80
src/scratchpad/testcases/org/apache/poi/hslf/model/TestFreeform.java
Executable file
@ -0,0 +1,80 @@
|
||||
/* ====================================================================
|
||||
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.hslf.model;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||
import org.apache.poi.hslf.usermodel.RichTextRun;
|
||||
import org.apache.poi.hslf.HSLFSlideShow;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.geom.*;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Test Freeform object.
|
||||
* The Freeform shape is constructed from java.awt.GeneralPath.
|
||||
* Check that the get/set path accessors are consistent.
|
||||
* (TODO: verification of Bezier curves is more difficult due to rounding error. Figure out a test approach for that)
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class TestFreeform extends TestCase {
|
||||
|
||||
public void testClosedPath() throws Exception {
|
||||
|
||||
GeneralPath path1 = new GeneralPath();
|
||||
path1.moveTo(100, 100);
|
||||
path1.lineTo(200, 100);
|
||||
path1.lineTo(200, 200);
|
||||
path1.lineTo(100, 200);
|
||||
path1.closePath();
|
||||
|
||||
Freeform p = new Freeform();
|
||||
p.setPath(path1);
|
||||
|
||||
GeneralPath path2 = p.getPath();
|
||||
assertTrue(new Area(path1).equals(new Area(path2)));
|
||||
}
|
||||
|
||||
public void testLine() throws Exception {
|
||||
|
||||
GeneralPath path1 = new GeneralPath(new Line2D.Double(100, 100, 200, 100));
|
||||
|
||||
Freeform p = new Freeform();
|
||||
p.setPath(path1);
|
||||
|
||||
GeneralPath path2 = p.getPath();
|
||||
assertTrue(new Area(path1).equals(new Area(path2)));
|
||||
}
|
||||
|
||||
public void testRectangle() throws Exception {
|
||||
|
||||
GeneralPath path1 = new GeneralPath(new Rectangle2D.Double(100, 100, 200, 50));
|
||||
|
||||
Freeform p = new Freeform();
|
||||
p.setPath(path1);
|
||||
|
||||
GeneralPath path2 = p.getPath();
|
||||
assertTrue(new Area(path1).equals(new Area(path2)));
|
||||
}
|
||||
}
|
@ -21,10 +21,19 @@
|
||||
package org.apache.poi.hslf.model;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.apache.poi.hslf.HSLFSlideShow;
|
||||
import org.apache.poi.hslf.usermodel.ObjectData;
|
||||
import org.apache.poi.hslf.usermodel.PictureData;
|
||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.apache.poi.hwpf.HWPFDocument;
|
||||
import org.apache.poi.hwpf.usermodel.Range;
|
||||
import org.apache.poi.hwpf.usermodel.Paragraph;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
@ -59,4 +68,41 @@ public class TestOleEmbedding extends TestCase
|
||||
slideShow.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void testOLEShape() throws Exception {
|
||||
String dirname = System.getProperty("HSLF.testdata.path");
|
||||
File file = new File(dirname, "ole2-embedding-2003.ppt");
|
||||
FileInputStream is = new FileInputStream(file);
|
||||
SlideShow ppt = new SlideShow(is);
|
||||
is.close();
|
||||
|
||||
Slide slide = ppt.getSlides()[0];
|
||||
Shape[] sh = slide.getShapes();
|
||||
int cnt = 0;
|
||||
for (int i = 0; i < sh.length; i++) {
|
||||
if(sh[i] instanceof OLEShape){
|
||||
cnt++;
|
||||
OLEShape ole = (OLEShape)sh[i];
|
||||
ObjectData data = ole.getObjectData();
|
||||
if("Worksheet".equals(ole.getInstanceName())){
|
||||
//Voila! we created a workbook from the embedded OLE data
|
||||
HSSFWorkbook wb = new HSSFWorkbook(data.getData());
|
||||
HSSFSheet sheet = wb.getSheetAt(0);
|
||||
//verify we can access the xls data
|
||||
assertEquals(1, sheet.getRow(0).getCell((short)0).getNumericCellValue(), 0);
|
||||
assertEquals(1, sheet.getRow(1).getCell((short)0).getNumericCellValue(), 0);
|
||||
assertEquals(2, sheet.getRow(2).getCell((short)0).getNumericCellValue(), 0);
|
||||
assertEquals(3, sheet.getRow(3).getCell((short)0).getNumericCellValue(), 0);
|
||||
assertEquals(8, sheet.getRow(5).getCell((short)0).getNumericCellValue(), 0);
|
||||
} else if ("Document".equals(ole.getInstanceName())){
|
||||
//creating a HWPF document
|
||||
HWPFDocument doc = new HWPFDocument(data.getData());
|
||||
String txt = doc.getRange().getParagraph(0).text();
|
||||
assertEquals("OLE embedding is thoroughly unremarkable.\r", txt);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
assertEquals("Expected 2 OLE shapes", 2, cnt);
|
||||
}
|
||||
}
|
||||
|
@ -307,4 +307,22 @@ public class TestShapes extends TestCase {
|
||||
sl = ppt.getSlides()[0];
|
||||
assertEquals("expected 0 shaped in " + file, 0, sl.getShapes().length);
|
||||
}
|
||||
|
||||
public void testShapeId() throws IOException {
|
||||
SlideShow ppt = new SlideShow();
|
||||
Slide slide = ppt.createSlide();
|
||||
Shape shape;
|
||||
|
||||
shape = new Line();
|
||||
assertEquals(0, shape.getShapeId());
|
||||
slide.addShape(shape);
|
||||
assertTrue(shape.getShapeId() > 0);
|
||||
|
||||
int shapeId = shape.getShapeId();
|
||||
|
||||
shape = new Line();
|
||||
assertEquals(0, shape.getShapeId());
|
||||
slide.addShape(shape);
|
||||
assertEquals(shapeId + 1, shape.getShapeId());
|
||||
}
|
||||
}
|
||||
|
86
src/scratchpad/testcases/org/apache/poi/hslf/record/TestSound.java
Executable file
86
src/scratchpad/testcases/org/apache/poi/hslf/record/TestSound.java
Executable file
@ -0,0 +1,86 @@
|
||||
|
||||
/* ====================================================================
|
||||
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.hslf.record;
|
||||
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.poi.hslf.HSLFSlideShow;
|
||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||
|
||||
/**
|
||||
* Tests Sound-related records: SoundCollection(2020), Sound(2022) and SoundData(2023)).
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class TestSound extends TestCase {
|
||||
public void testRealFile() throws Exception {
|
||||
String cwd = System.getProperty("HSLF.testdata.path");
|
||||
FileInputStream is = new FileInputStream(new File(cwd, "sound.ppt"));
|
||||
SlideShow ppt = new SlideShow(is);
|
||||
is.close();
|
||||
|
||||
// Get the document
|
||||
Document doc = ppt.getDocumentRecord();
|
||||
SoundCollection soundCollection = null;
|
||||
Record[] doc_ch = doc.getChildRecords();
|
||||
for (int i = 0; i < doc_ch.length; i++) {
|
||||
if(doc_ch[i] instanceof SoundCollection){
|
||||
soundCollection = (SoundCollection)doc_ch[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertNotNull(soundCollection);
|
||||
|
||||
Sound sound = null;
|
||||
Record[] sound_ch = soundCollection.getChildRecords();
|
||||
int k = 0;
|
||||
for (int i = 0; i < sound_ch.length; i++) {
|
||||
if(sound_ch[i] instanceof Sound){
|
||||
sound = (Sound)sound_ch[i];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
assertNotNull(sound);
|
||||
assertEquals(1, k);
|
||||
|
||||
assertEquals("ringin.wav", sound.getSoundName());
|
||||
assertEquals(".WAV", sound.getSoundType());
|
||||
assertNotNull(sound.getSoundData());
|
||||
|
||||
File f = new File(cwd, "ringin.wav");
|
||||
int length = (int)f.length();
|
||||
byte[] ref_data = new byte[length];
|
||||
is = new FileInputStream(f);
|
||||
is.read(ref_data);
|
||||
is.close();
|
||||
|
||||
assertTrue(Arrays.equals(ref_data, sound.getSoundData()));
|
||||
|
||||
}
|
||||
}
|
@ -360,4 +360,24 @@ public class TestBugs extends TestCase {
|
||||
|
||||
assertTrue("No Exceptions while reading file", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bug 41071: Will not extract text from Powerpoint TextBoxes
|
||||
*/
|
||||
public void test41071() throws Exception {
|
||||
FileInputStream is = new FileInputStream(new File(cwd, "41071.ppt"));
|
||||
SlideShow ppt = new SlideShow(is);
|
||||
is.close();
|
||||
|
||||
Slide slide = ppt.getSlides()[0];
|
||||
Shape[] sh = slide.getShapes();
|
||||
assertEquals(1, sh.length);
|
||||
assertTrue(sh[0] instanceof TextShape);
|
||||
TextShape tx = (TextShape)sh[0];
|
||||
assertEquals("Fundera, planera och involvera.", tx.getTextRun().getText());
|
||||
|
||||
TextRun[] run = slide.getTextRuns();
|
||||
assertEquals(1, run.length);
|
||||
assertEquals("Fundera, planera och involvera.", run[0].getText());
|
||||
}
|
||||
}
|
||||
|
@ -437,4 +437,33 @@ public class TestPictures extends TestCase{
|
||||
assertTrue(pdata instanceof WMF);
|
||||
assertEquals(Picture.WMF, pdata.getType());
|
||||
}
|
||||
|
||||
public void testGetPictureName() throws Exception {
|
||||
SlideShow ppt = new SlideShow(new HSLFSlideShow(new File(cwd, "ppt_with_png.ppt").getPath()));
|
||||
Slide slide = ppt.getSlides()[0];
|
||||
|
||||
Picture p = (Picture)slide.getShapes()[0]; //the first slide contains JPEG
|
||||
assertEquals("test", p.getPictureName());
|
||||
}
|
||||
|
||||
public void testSetPictureName() throws Exception {
|
||||
SlideShow ppt = new SlideShow();
|
||||
|
||||
Slide slide = ppt.createSlide();
|
||||
File img = new File(cwd, "tomcat.png");
|
||||
int idx = ppt.addPicture(img, Picture.PNG);
|
||||
Picture pict = new Picture(idx);
|
||||
pict.setPictureName("tomcat.png");
|
||||
slide.addShape(pict);
|
||||
|
||||
//serialize and read again
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ppt.write(out);
|
||||
out.close();
|
||||
|
||||
ppt = new SlideShow(new ByteArrayInputStream(out.toByteArray()));
|
||||
|
||||
Picture p = (Picture)ppt.getSlides()[0].getShapes()[0];
|
||||
assertEquals("tomcat.png", p.getPictureName());
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ public class TestSlideOrdering extends TestCase {
|
||||
"ROMANCE: AN ANALYSIS",
|
||||
"AGENDA",
|
||||
"You are an important supplier of various items that I need",
|
||||
(char)0x0B + "Although The Psycho set back my relationship process, recovery is luckily enough under way",
|
||||
'\n' + "Although The Psycho set back my relationship process, recovery is luckily enough under way",
|
||||
"Since the time that we seriously go out together, you rank highly among existing relationships",
|
||||
"Although our personal interests are mostly compatible, the greatest gap exists in Sex and Shopping",
|
||||
"Your physical characteristics are strong when compared with your competition",
|
||||
|
63
src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestSoundData.java
Executable file
63
src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestSoundData.java
Executable file
@ -0,0 +1,63 @@
|
||||
/* ====================================================================
|
||||
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.hslf.usermodel;
|
||||
|
||||
import org.apache.poi.hslf.*;
|
||||
import org.apache.poi.hslf.exceptions.HSLFException;
|
||||
import org.apache.poi.hslf.blip.*;
|
||||
import org.apache.poi.hslf.model.*;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Test reading sound data from a ppt
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class TestSoundData extends TestCase{
|
||||
|
||||
protected File cwd;
|
||||
|
||||
public void setUp() throws Exception {
|
||||
cwd = new File(System.getProperty("HSLF.testdata.path"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a reference sound file from disk and compare it from the data extracted from the slide show
|
||||
*/
|
||||
public void testSounds() throws Exception {
|
||||
//read the reference sound file
|
||||
File f = new File(cwd, "ringin.wav");
|
||||
int length = (int)f.length();
|
||||
byte[] ref_data = new byte[length];
|
||||
FileInputStream is = new FileInputStream(f);
|
||||
is.read(ref_data);
|
||||
is.close();
|
||||
|
||||
is = new FileInputStream(new File(cwd, "sound.ppt"));
|
||||
SlideShow ppt = new SlideShow(is);
|
||||
is.close();
|
||||
|
||||
SoundData[] sound = ppt.getSoundData();
|
||||
assertEquals("Expected 1 sound", 1, sound.length);
|
||||
|
||||
assertTrue(Arrays.equals(ref_data, sound[0].getData()));
|
||||
}
|
||||
}
|
BIN
src/testcases/org/apache/poi/hssf/data/28774.xls
Executable file
BIN
src/testcases/org/apache/poi/hssf/data/28774.xls
Executable file
Binary file not shown.
@ -878,4 +878,15 @@ public final class TestBugs extends TestCase {
|
||||
}
|
||||
assertEquals(713, rowsSeen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bug 28774: Excel will crash when opening xls-files with images.
|
||||
*/
|
||||
public void test28774() {
|
||||
|
||||
HSSFWorkbook wb = openSample("28774.xls");
|
||||
assertTrue("no errors reading sample xls", true);
|
||||
writeOutAndReadBack(wb);
|
||||
assertTrue("no errors writing sample xls", true);
|
||||
}
|
||||
}
|
||||
|
@ -49,4 +49,23 @@ public final class TestHSSFTextbox extends TestCase{
|
||||
assertEquals(HSSFTextbox.VERTICAL_ALIGNMENT_CENTER, textbox.getVerticalAlignment());
|
||||
}
|
||||
|
||||
/**
|
||||
* Excel requires at least one format run in HSSFTextbox.
|
||||
* When inserting text make sure that if font is not set we must set the default one.
|
||||
*/
|
||||
public void testSetDeafultTextFormat() {
|
||||
HSSFWorkbook wb = new HSSFWorkbook();
|
||||
HSSFSheet sheet = wb.createSheet();
|
||||
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
|
||||
|
||||
HSSFTextbox textbox1 = patriarch.createTextbox(new HSSFClientAnchor(0,0,0,0,(short)1,1,(short)3,3));
|
||||
HSSFRichTextString rt1 = new HSSFRichTextString("Hello, World!");
|
||||
assertEquals(0, rt1.numFormattingRuns());
|
||||
textbox1.setString(rt1);
|
||||
|
||||
HSSFRichTextString rt2 = textbox1.getString();
|
||||
assertEquals(1, rt2.numFormattingRuns());
|
||||
assertEquals(HSSFRichTextString.NO_FONT, rt2.getFontOfFormattingRun(0));
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user