You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ki...@apache.org on 2014/02/12 00:16:54 UTC
svn commit: r1567455 - in /poi: site/src/documentation/content/xdocs/ trunk/
trunk/src/scratchpad/src/org/apache/poi/hslf/model/
trunk/src/scratchpad/testcases/org/apache/poi/hslf/
trunk/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/ trunk/tes...
Author: kiwiwings
Date: Tue Feb 11 23:16:54 2014
New Revision: 1567455
URL: http://svn.apache.org/r1567455
Log:
Bug 55902 - Mixed fonts issue with Chinese characters (unable to form images from ppt)
Added:
poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestFontRendering.java
poi/trunk/test-data/slideshow/bug55902-mixedChars.png (with props)
poi/trunk/test-data/slideshow/bug55902-mixedFontChineseCharacters.ppt (with props)
Modified:
poi/site/src/documentation/content/xdocs/status.xml
poi/trunk/build.xml
poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java
poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/AllHSLFTests.java
poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/AllHSLFUserModelTests.java
Modified: poi/site/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/site/src/documentation/content/xdocs/status.xml?rev=1567455&r1=1567454&r2=1567455&view=diff
==============================================================================
--- poi/site/src/documentation/content/xdocs/status.xml (original)
+++ poi/site/src/documentation/content/xdocs/status.xml Tue Feb 11 23:16:54 2014
@@ -36,6 +36,7 @@
<changes>
<release version="3.11-beta1" date="2014-??-??">
+ <action dev="poi-developers" type="fix">55902 - Mixed fonts issue with Chinese characters (unable to form images from ppt)</action>
<action dev="poi-developers" type="add">56022 - XSSF Event Text Extractor header/footer support</action>
<action dev="poi-developers" type="fix">53282 - Hyperlink with a non-breaking space throws java.lang.IllegalStateException</action>
<action dev="poi-developers" type="fix">55802 - Special Letters not exported correct</action>
Modified: poi/trunk/build.xml
URL: http://svn.apache.org/viewvc/poi/trunk/build.xml?rev=1567455&r1=1567454&r2=1567455&view=diff
==============================================================================
--- poi/trunk/build.xml (original)
+++ poi/trunk/build.xml Tue Feb 11 23:16:54 2014
@@ -834,7 +834,7 @@ under the License.
</uptodate>
</target>
- <target name="test-scratchpad" depends="compile-main,compile-scratchpad,-test-scratchpad-check,jacocotask"
+ <target name="test-scratchpad" depends="compile-main,compile-scratchpad,-test-scratchpad-check,jacocotask,test-scratchpad-download-resources"
unless="scratchpad.test.notRequired" xmlns:jacoco="antlib:org.jacoco.ant">
<jacoco:coverage enabled="${coverage.enabled}" excludes="${coverage.excludes}" destfile="build/jacoco-scratchpad.exec">
<junit printsummary="yes" fork="yes" forkmode="once" haltonfailure="${halt.on.test.failure}"
@@ -1383,7 +1383,6 @@ under the License.
</target>
<target name="findbugs"><!-- depends="assemble" -->
-
<antcall target="downloadfile">
<param name="sourcefile" value="http://prdownloads.sourceforge.net/findbugs/findbugs-noUpdateChecks-2.0.3.zip?download"/>
<param name="destfile" value="${main.lib}/findbugs-noUpdateChecks-2.0.3.zip"/>
@@ -1425,4 +1424,26 @@ under the License.
<sourcePath path="src/scratchpad/src" />
</findbugs>
</target>
+
+ <target name="test-scratchpad-download-resources">
+ <mkdir dir="build/scratchpad-test-resources"/>
+
+ <antcall target="downloadfile">
+ <param name="sourcefile" value="http://sourceforge.net/projects/monafont/files/monafont/monafont-2.90/monafont-ttf-2.90.zip/download"/>
+ <param name="destfile" value="build/scratchpad-test-resources/monafont-ttf-2.90.zip"/>
+ </antcall>
+
+ <unzip src="build/scratchpad-test-resources/monafont-ttf-2.90.zip"
+ dest="build/scratchpad-test-resources">
+ <patternset>
+ <include name="mona.ttf"/>
+ </patternset>
+ </unzip>
+
+ <antcall target="downloadfile">
+ <param name="sourcefile" value="https://googlefontdirectory.googlecode.com/hg-history/c5955de4df3e40f6ab705bbccbd1f5ad93998287/cabin/Cabin-Regular.ttf"/>
+ <param name="destfile" value="build/scratchpad-test-resources/Cabin-Regular.ttf"/>
+ </antcall>
+ </target>
+
</project>
Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java?rev=1567455&r1=1567454&r2=1567455&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java Tue Feb 11 23:16:54 2014
@@ -20,6 +20,7 @@ package org.apache.poi.hslf.model;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
+import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
@@ -31,6 +32,7 @@ import java.text.AttributedCharacterIter
import java.text.AttributedString;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import org.apache.poi.hslf.record.TextRulerAtom;
import org.apache.poi.hslf.usermodel.RichTextRun;
@@ -43,6 +45,9 @@ import org.apache.poi.util.POILogger;
* @author Yegor Kozlov
*/
public final class TextPainter {
+ public static final Key KEY_FONTFALLBACK = new Key(50, "Font fallback map");
+ public static final Key KEY_FONTMAP = new Key(51, "Font map");
+
protected POILogger logger = POILogFactory.getLogger(this.getClass());
/**
@@ -58,10 +63,14 @@ public final class TextPainter {
_shape = shape;
}
+ public AttributedString getAttributedString(TextRun txrun) {
+ return getAttributedString(txrun, null);
+ }
+
/**
* Convert the underlying set of rich text runs into java.text.AttributedString
*/
- public AttributedString getAttributedString(TextRun txrun){
+ public AttributedString getAttributedString(TextRun txrun, Graphics2D graphics){
String text = txrun.getText();
//TODO: properly process tabs
text = text.replace('\t', ' ');
@@ -77,7 +86,22 @@ public final class TextPainter {
continue;
}
- at.addAttribute(TextAttribute.FAMILY, rt[i].getFontName(), start, end);
+ String mappedFont = rt[i].getFontName();
+ String fallbackFont = Font.SANS_SERIF;
+ if (graphics != null) {
+ @SuppressWarnings("unchecked")
+ Map<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(KEY_FONTMAP);
+ if (fontMap != null && fontMap.containsKey(mappedFont)) {
+ mappedFont = fontMap.get(mappedFont);
+ }
+ @SuppressWarnings("unchecked")
+ Map<String,String> fallbackMap = (Map<String,String>)graphics.getRenderingHint(KEY_FONTFALLBACK);
+ if (fallbackMap != null && fallbackMap.containsKey(mappedFont)) {
+ fallbackFont = fallbackMap.get(mappedFont);
+ }
+ }
+
+ at.addAttribute(TextAttribute.FAMILY, mappedFont, 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);
@@ -89,7 +113,31 @@ public final class TextPainter {
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);
-
+
+
+ int style = (rt[i].isBold() ? Font.BOLD : 0) | (rt[i].isItalic() ? Font.ITALIC : 0);
+ Font f = new Font(mappedFont, style, rt[i].getFontSize());
+
+ // check for unsupported characters and add a fallback font for these
+ char textChr[] = text.toCharArray();
+ int nextEnd = f.canDisplayUpTo(textChr, start, end);
+ boolean isNextValid = nextEnd == start;
+ for (int last = start; nextEnd != -1 && nextEnd <= end; ) {
+ if (isNextValid) {
+ nextEnd = f.canDisplayUpTo(textChr, nextEnd, end);
+ isNextValid = false;
+ } else {
+ if (nextEnd >= end || f.canDisplay(Character.codePointAt(textChr, nextEnd, end)) ) {
+ at.addAttribute(TextAttribute.FAMILY, fallbackFont, last, Math.min(nextEnd,end));
+ if (nextEnd >= end) break;
+ last = nextEnd;
+ isNextValid = true;
+ } else {
+ boolean isHS = Character.isHighSurrogate(textChr[nextEnd]);
+ nextEnd+=(isHS?2:1);
+ }
+ }
+ }
}
return at;
}
@@ -98,7 +146,7 @@ public final class TextPainter {
AffineTransform tx = graphics.getTransform();
Rectangle2D anchor = _shape.getLogicalAnchor2D();
- TextElement[] elem = getTextElements((float)anchor.getWidth(), graphics.getFontRenderContext());
+ TextElement[] elem = getTextElements((float)anchor.getWidth(), graphics.getFontRenderContext(), graphics);
if(elem == null) return;
float textHeight = 0;
@@ -183,13 +231,17 @@ public final class TextPainter {
}
public TextElement[] getTextElements(float textWidth, FontRenderContext frc){
+ return getTextElements(textWidth, frc, null);
+ }
+
+ public TextElement[] getTextElements(float textWidth, FontRenderContext frc, Graphics2D graphics){
TextRun run = _shape.getTextRun();
if (run == null) return null;
String text = run.getText();
if (text == null || text.equals("")) return null;
- AttributedString at = getAttributedString(run);
+ AttributedString at = getAttributedString(run, graphics);
AttributedCharacterIterator it = at.getIterator();
int paragraphStart = it.getBeginIndex();
@@ -342,4 +394,25 @@ public final class TextPainter {
public float advance;
public int textStartIndex, textEndIndex;
}
+
+ public static class Key extends RenderingHints.Key {
+ String description;
+
+ public Key(int paramInt, String paramString) {
+ super(paramInt);
+ this.description = paramString;
+ }
+
+ public final int getIndex() {
+ return intKey();
+ }
+
+ public final String toString() {
+ return this.description;
+ }
+
+ public boolean isCompatibleValue(Object paramObject) {
+ return true;
+ }
+ }
}
Modified: poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/AllHSLFTests.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/AllHSLFTests.java?rev=1567455&r1=1567454&r2=1567455&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/AllHSLFTests.java (original)
+++ poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/AllHSLFTests.java Tue Feb 11 23:16:54 2014
@@ -17,35 +17,30 @@
package org.apache.poi.hslf;
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
import org.apache.poi.hslf.extractor.TestCruddyExtractor;
import org.apache.poi.hslf.extractor.TestExtractor;
import org.apache.poi.hslf.model.AllHSLFModelTests;
import org.apache.poi.hslf.record.AllHSLFRecordTests;
import org.apache.poi.hslf.usermodel.AllHSLFUserModelTests;
import org.apache.poi.hslf.util.TestSystemTimeUtils;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
/**
* Collects all tests from the package <tt>org.apache.poi.hslf</tt> and all sub-packages.
- *
- * @author Josh Micich
*/
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+ TestEncryptedFile.class,
+ TestRecordCounts.class,
+ TestReWrite.class,
+ TestReWriteSanity.class,
+ TestCruddyExtractor.class,
+ TestExtractor.class,
+ AllHSLFModelTests.class,
+ AllHSLFRecordTests.class,
+ AllHSLFUserModelTests.class,
+ TestSystemTimeUtils.class
+})
public class AllHSLFTests {
-
- public static Test suite() {
- TestSuite result = new TestSuite(AllHSLFTests.class.getName());
- result.addTestSuite(TestEncryptedFile.class);
- result.addTestSuite(TestRecordCounts.class);
- result.addTestSuite(TestReWrite.class);
- result.addTestSuite(TestReWriteSanity.class);
- result.addTestSuite(TestCruddyExtractor.class);
- result.addTestSuite(TestExtractor.class);
- result.addTest(AllHSLFModelTests.suite());
- result.addTest(AllHSLFRecordTests.suite());
- result.addTest(AllHSLFUserModelTests.suite());
- result.addTestSuite(TestSystemTimeUtils.class);
- return result;
- }
}
Modified: poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/AllHSLFUserModelTests.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/AllHSLFUserModelTests.java?rev=1567455&r1=1567454&r2=1567455&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/AllHSLFUserModelTests.java (original)
+++ poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/AllHSLFUserModelTests.java Tue Feb 11 23:16:54 2014
@@ -17,30 +17,27 @@
package org.apache.poi.hslf.usermodel;
-import junit.framework.Test;
-import junit.framework.TestSuite;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
/**
* Collects all tests from the package <tt>org.apache.poi.hslf.usermodel</tt>.
- *
- * @author Josh Micich
*/
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+ TestAddingSlides.class,
+ TestBugs.class,
+ TestCounts.class,
+ TestMostRecentRecords.class,
+ TestNotesText.class,
+ TestPictures.class,
+ TestReOrderingSlides.class,
+ TestRecordSetup.class,
+ TestRichTextRun.class,
+ TestSheetText.class,
+ TestSlideOrdering.class,
+ TestSoundData.class,
+ TestFontRendering.class
+})
public class AllHSLFUserModelTests {
-
- public static Test suite() {
- TestSuite result = new TestSuite(AllHSLFUserModelTests.class.getName());
- result.addTestSuite(TestAddingSlides.class);
- result.addTestSuite(TestBugs.class);
- result.addTestSuite(TestCounts.class);
- result.addTestSuite(TestMostRecentRecords.class);
- result.addTestSuite(TestNotesText.class);
- result.addTestSuite(TestPictures.class);
- result.addTestSuite(TestReOrderingSlides.class);
- result.addTestSuite(TestRecordSetup.class);
- result.addTestSuite(TestRichTextRun.class);
- result.addTestSuite(TestSheetText.class);
- result.addTestSuite(TestSlideOrdering.class);
- result.addTestSuite(TestSoundData.class);
- return result;
- }
}
Added: poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestFontRendering.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestFontRendering.java?rev=1567455&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestFontRendering.java (added)
+++ poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestFontRendering.java Tue Feb 11 23:16:54 2014
@@ -0,0 +1,112 @@
+/* ====================================================================
+ 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 static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferByte;
+import java.io.File;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.imageio.ImageIO;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.hslf.model.Slide;
+import org.apache.poi.hslf.model.TextPainter;
+import org.junit.Test;
+
+/**
+ * Test font rendering of alternative and fallback fonts
+ */
+public class TestFontRendering {
+ private static POIDataSamples slTests = POIDataSamples.getSlideShowInstance();
+
+ @Test
+ public void bug55902mixedFontWithChineseCharacters() throws Exception {
+ // font files need to be downloaded first via
+ // ant test-scratchpad-download-resources
+ String fontFiles[][] = {
+ // Calibri is not available on *nix systems, so we need to use another similar free font
+ { "build/scratchpad-test-resources/Cabin-Regular.ttf", "mapped", "Calibri" },
+
+ // use "MS PGothic" if available (Windows only) ...
+ // for the junit test not all chars are rendered
+ { "build/scratchpad-test-resources/mona.ttf", "fallback", "Cabin" }
+ };
+
+ // setup fonts (especially needed, when run under *nix systems)
+ GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ Map<String,String> fontMap = new HashMap<String,String>();
+ Map<String,String> fallbackMap = new HashMap<String,String>();
+
+ for (String fontFile[] : fontFiles) {
+ File f = new File(fontFile[0]);
+ assumeTrue("necessary font file "+f.getName()+" not downloaded.", f.exists());
+
+ Font font = Font.createFont(Font.TRUETYPE_FONT, f);
+ ge.registerFont(font);
+
+ Map<String,String> map = ("mapped".equals(fontFile[1]) ? fontMap : fallbackMap);
+ map.put(fontFile[2], font.getFamily());
+ }
+
+ InputStream is = slTests.openResourceAsStream("bug55902-mixedFontChineseCharacters.ppt");
+ SlideShow ss = new SlideShow(is);
+ is.close();
+
+ Dimension pgsize = ss.getPageSize();
+
+ Slide slide = ss.getSlides()[0];
+
+ // render it
+ double zoom = 1;
+ AffineTransform at = new AffineTransform();
+ at.setToScale(zoom, zoom);
+
+ BufferedImage imgActual = new BufferedImage((int)Math.ceil(pgsize.width*zoom), (int)Math.ceil(pgsize.height*zoom), BufferedImage.TYPE_3BYTE_BGR);
+ Graphics2D graphics = imgActual.createGraphics();
+ graphics.setRenderingHint(TextPainter.KEY_FONTFALLBACK, fallbackMap);
+ graphics.setRenderingHint(TextPainter.KEY_FONTMAP, fontMap);
+ 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.setTransform(at);
+ graphics.setPaint(Color.white);
+ graphics.fill(new Rectangle2D.Float(0, 0, pgsize.width, pgsize.height));
+ slide.draw(graphics);
+
+ BufferedImage imgExpected = ImageIO.read(slTests.getFile("bug55902-mixedChars.png"));
+ DataBufferByte expectedDB = (DataBufferByte)imgExpected.getRaster().getDataBuffer();
+ DataBufferByte actualDB = (DataBufferByte)imgActual.getRaster().getDataBuffer();
+ assertTrue(Arrays.equals(expectedDB.getData(0), actualDB.getData(0)));
+ }
+}
Added: poi/trunk/test-data/slideshow/bug55902-mixedChars.png
URL: http://svn.apache.org/viewvc/poi/trunk/test-data/slideshow/bug55902-mixedChars.png?rev=1567455&view=auto
==============================================================================
Binary file - no diff available.
Propchange: poi/trunk/test-data/slideshow/bug55902-mixedChars.png
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: poi/trunk/test-data/slideshow/bug55902-mixedFontChineseCharacters.ppt
URL: http://svn.apache.org/viewvc/poi/trunk/test-data/slideshow/bug55902-mixedFontChineseCharacters.ppt?rev=1567455&view=auto
==============================================================================
Binary file - no diff available.
Propchange: poi/trunk/test-data/slideshow/bug55902-mixedFontChineseCharacters.ppt
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org