provide font mapping with PPTX2PNG fix record enums references fix alignment of asian fonts git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1883883 13f79535-47bb-0310-9956-ffa450edef68tags/before_ooxml_3rd_edition
@@ -28,9 +28,12 @@ import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.nio.charset.Charset; | |||
import java.util.Arrays; | |||
import java.util.Locale; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.regex.Pattern; | |||
import java.util.stream.Collectors; | |||
import org.apache.poi.common.usermodel.GenericRecord; | |||
import org.apache.poi.poifs.filesystem.FileMagic; | |||
@@ -77,7 +80,8 @@ public final class PPTX2PNG { | |||
" -emfHeaderBounds force the usage of the emf header bounds to calculate the bounding box\n" + | |||
" -fontdir <dir> (PDF only) font directories separated by \";\" - use $HOME for current users home dir\n" + | |||
" defaults to the usual plattform directories\n" + | |||
" -fontTtf <regex> (PDF only) regex to match the .ttf filenames"; | |||
" -fontTtf <regex> (PDF only) regex to match the .ttf filenames\n" + | |||
" -fontMap <map> \";\"-separated list of font mappings <typeface from>:<typeface to>"; | |||
System.out.println(msg); | |||
// no System.exit here, as we also run in junit tests! | |||
@@ -109,6 +113,7 @@ public final class PPTX2PNG { | |||
private boolean emfHeaderBounds = false; | |||
private String fontDir = null; | |||
private String fontTtf = null; | |||
private String fontMap = null; | |||
private PPTX2PNG() { | |||
} | |||
@@ -213,6 +218,14 @@ public final class PPTX2PNG { | |||
fontTtf = null; | |||
} | |||
break; | |||
case "-fontmap": | |||
if (opt != null) { | |||
fontMap = opt; | |||
i++; | |||
} else { | |||
fontMap = null; | |||
} | |||
break; | |||
default: | |||
file = new File(args[i]); | |||
break; | |||
@@ -303,6 +316,12 @@ public final class PPTX2PNG { | |||
graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); | |||
graphics.setRenderingHint(Drawable.DEFAULT_CHARSET, getDefaultCharset()); | |||
graphics.setRenderingHint(Drawable.EMF_FORCE_HEADER_BOUNDS, emfHeaderBounds); | |||
if (fontMap != null) { | |||
Map<String,String> fmap = Arrays.stream(fontMap.split(";")) | |||
.map(s -> s.split(":")) | |||
.collect(Collectors.toMap(s -> s[0], s -> s[1])); | |||
graphics.setRenderingHint(Drawable.FONT_MAP, fmap); | |||
} | |||
graphics.scale(scale / lenSide, scale / lenSide); | |||
@@ -450,13 +450,13 @@ public final class HemfPlusDraw { | |||
AffineTransform txSaved = ctx.getTransform(); | |||
AffineTransform tx = (AffineTransform)txSaved.clone(); | |||
HwmfTernaryRasterOp oldOp = prop.getRasterOp(); | |||
HwmfTernaryRasterOp oldOp = prop.getRasterOp3(); | |||
HwmfBkMode oldBk = prop.getBkMode(); | |||
try { | |||
tx.concatenate(trans); | |||
ctx.setTransform(tx); | |||
prop.setRasterOp(HwmfTernaryRasterOp.SRCCOPY); | |||
prop.setRasterOp3(HwmfTernaryRasterOp.SRCCOPY); | |||
prop.setBkMode(HwmfBkMode.TRANSPARENT); | |||
// transformation from srcRect to destRect was already applied, | |||
@@ -464,7 +464,7 @@ public final class HemfPlusDraw { | |||
ctx.drawImage(ir, srcRect, srcRect); | |||
} finally { | |||
prop.setBkMode(oldBk); | |||
prop.setRasterOp(oldOp); | |||
prop.setRasterOp3(oldOp); | |||
ctx.setTransform(txSaved); | |||
} | |||
} | |||
@@ -539,7 +539,7 @@ public final class HemfPlusDraw { | |||
ctx.applyPlusObjectTableEntry(getObjectId()); | |||
HemfDrawProperties prop = ctx.getProperties(); | |||
prop.setRasterOp(HwmfTernaryRasterOp.SRCCOPY); | |||
prop.setRasterOp3(HwmfTernaryRasterOp.SRCCOPY); | |||
prop.setBkMode(HwmfBkMode.TRANSPARENT); | |||
ctx.drawImage(prop.getEmfPlusImage(), srcRect, rectData); |
@@ -68,7 +68,7 @@ public class HwmfDrawProperties { | |||
private HwmfTextVerticalAlignment textVAlignLatin; | |||
private HwmfTextAlignment textAlignAsian; | |||
private HwmfTextVerticalAlignment textVAlignAsian; | |||
private HwmfTernaryRasterOp rasterOp; | |||
private HwmfTernaryRasterOp rasterOp3; | |||
protected Shape clip; | |||
protected final AffineTransform transform = new AffineTransform(); | |||
@@ -92,7 +92,7 @@ public class HwmfDrawProperties { | |||
textVAlignLatin = HwmfTextVerticalAlignment.TOP; | |||
textAlignAsian = HwmfTextAlignment.RIGHT; | |||
textVAlignAsian = HwmfTextVerticalAlignment.TOP; | |||
rasterOp = HwmfTernaryRasterOp.PATCOPY; | |||
rasterOp3 = HwmfTernaryRasterOp.PATCOPY; | |||
clip = null; | |||
font = new HwmfFont(); | |||
font.initDefaults(); | |||
@@ -128,7 +128,7 @@ public class HwmfDrawProperties { | |||
this.textVAlignLatin = other.textVAlignLatin; | |||
this.textAlignAsian = other.textAlignAsian; | |||
this.textVAlignAsian = other.textVAlignAsian; | |||
this.rasterOp = other.rasterOp; | |||
this.rasterOp3 = other.rasterOp3; | |||
this.transform.setTransform(other.transform); | |||
this.clip = other.clip; | |||
} | |||
@@ -388,12 +388,12 @@ public class HwmfDrawProperties { | |||
return getPolyfillMode().awtFlag; | |||
} | |||
public HwmfTernaryRasterOp getRasterOp() { | |||
return rasterOp; | |||
public HwmfTernaryRasterOp getRasterOp3() { | |||
return rasterOp3; | |||
} | |||
public void setRasterOp(HwmfTernaryRasterOp rasterOp) { | |||
this.rasterOp = rasterOp; | |||
public void setRasterOp3(HwmfTernaryRasterOp rasterOp3) { | |||
this.rasterOp3 = rasterOp3; | |||
} | |||
public AffineTransform getTransform() { |
@@ -48,6 +48,7 @@ import java.util.BitSet; | |||
import java.util.HashMap; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import java.util.Locale; | |||
import java.util.Map; | |||
import java.util.NoSuchElementException; | |||
import java.util.Objects; | |||
@@ -461,7 +462,8 @@ public class HwmfGraphics implements HwmfCharsetAware { | |||
return; | |||
} | |||
String textString = trimText(font, isUnicode, text, length); | |||
final Charset charset = getCharset(font, isUnicode); | |||
String textString = trimText(charset, text, length); | |||
if (textString.isEmpty()) { | |||
return; | |||
} | |||
@@ -481,7 +483,12 @@ public class HwmfGraphics implements HwmfCharsetAware { | |||
final double angle = Math.toRadians(-font.getEscapement()/10.); | |||
final Point2D dst = getRotatedOffset(angle, frc, as); | |||
// TODO: find out when to use asian align | |||
boolean useAsianAlign = (opts == null) && | |||
textString.codePoints().anyMatch(Character::isIdeographic) && | |||
charset.displayName(Locale.ROOT). startsWith("GB"); | |||
final Point2D dst = getRotatedOffset(angle, frc, as, useAsianAlign); | |||
final Shape clipShape = graphicsCtx.getClip(); | |||
try { | |||
@@ -640,8 +647,7 @@ public class HwmfGraphics implements HwmfCharsetAware { | |||
charsetProvider = provider; | |||
} | |||
private String trimText(HwmfFont font, boolean isUnicode, byte[] text, int length) { | |||
final Charset charset = getCharset(font, isUnicode); | |||
private String trimText(Charset charset, byte[] text, int length) { | |||
int trimLen; | |||
for (trimLen=0; trimLen<text.length; trimLen+=2) { | |||
@@ -660,7 +666,8 @@ public class HwmfGraphics implements HwmfCharsetAware { | |||
return textString.substring(0, Math.min(textString.length(), length)); | |||
} | |||
private void updateHorizontalAlign(AffineTransform tx, TextLayout layout) { | |||
private void updateHorizontalAlign(AffineTransform tx, TextLayout layout, boolean useAsianAlign) { | |||
// TODO: using prop.getTextAlignAsian doesn't look good ... | |||
switch (prop.getTextAlignLatin()) { | |||
default: | |||
case LEFT: | |||
@@ -674,9 +681,9 @@ public class HwmfGraphics implements HwmfCharsetAware { | |||
} | |||
} | |||
private void updateVerticalAlign(AffineTransform tx, TextLayout layout) { | |||
private void updateVerticalAlign(AffineTransform tx, TextLayout layout, boolean useAsianAlign) { | |||
// TODO: check min/max orientation | |||
switch (prop.getTextVAlignLatin()) { | |||
switch (useAsianAlign ? prop.getTextVAlignAsian() : prop.getTextVAlignLatin()) { | |||
case TOP: | |||
tx.translate(0, layout.getAscent()); | |||
break; | |||
@@ -710,11 +717,11 @@ public class HwmfGraphics implements HwmfCharsetAware { | |||
graphicsCtx.setTransform(at); | |||
} | |||
private Point2D getRotatedOffset(double angle, FontRenderContext frc, AttributedString as) { | |||
private Point2D getRotatedOffset(double angle, FontRenderContext frc, AttributedString as, boolean useAsianAlign) { | |||
final TextLayout layout = new TextLayout(as.getIterator(), frc); | |||
final AffineTransform tx = new AffineTransform(); | |||
updateHorizontalAlign(tx, layout); | |||
updateVerticalAlign(tx, layout); | |||
updateHorizontalAlign(tx, layout, useAsianAlign); | |||
updateVerticalAlign(tx, layout, useAsianAlign); | |||
tx.rotate(angle); | |||
Point2D src = new Point2D.Double(); | |||
@@ -736,7 +743,7 @@ public class HwmfGraphics implements HwmfCharsetAware { | |||
// are not supported, as we would need to extract the destination image area from the underlying buffered image | |||
// and therefore would make it mandatory that the graphics context must be from a buffered image | |||
// furthermore I doubt the purpose of bitwise image operations on non-black/white images | |||
switch (prop.getRasterOp()) { | |||
switch (prop.getRasterOp3()) { | |||
case D: | |||
// keep destination, i.e. do nothing | |||
break; | |||
@@ -785,7 +792,7 @@ public class HwmfGraphics implements HwmfCharsetAware { | |||
// of the referenced image and can be also negative | |||
Composite old = graphicsCtx.getComposite(); | |||
int newComp; | |||
switch (prop.getRasterOp()) { | |||
switch (prop.getRasterOp3()) { | |||
default: | |||
case SRCCOPY: | |||
newComp = AlphaComposite.SRC_OVER; |
@@ -476,7 +476,7 @@ public final class HwmfDraw { | |||
@Override | |||
public HwmfRecordType getWmfRecordType() { | |||
return HwmfRecordType.frameRegion; | |||
return HwmfRecordType.rectangle; | |||
} | |||
@Override |
@@ -611,7 +611,7 @@ public class HwmfFill { | |||
@Override | |||
public void draw(HwmfGraphics ctx) { | |||
HwmfDrawProperties prop = ctx.getProperties(); | |||
prop.setRasterOp(rasterOperation); | |||
prop.setRasterOp3(rasterOperation); | |||
if (bitmap.isValid()) { | |||
BufferedImage bi = bitmap.getImage(prop.getPenColor().getColor(), prop.getBackgroundColor().getColor(), | |||
prop.getBkMode() == HwmfBkMode.TRANSPARENT); | |||
@@ -912,7 +912,7 @@ public class HwmfFill { | |||
@Override | |||
public void draw(HwmfGraphics ctx) { | |||
HwmfDrawProperties prop = ctx.getProperties(); | |||
prop.setRasterOp(rasterOperation); | |||
prop.setRasterOp3(rasterOperation); | |||
// TODO: implement second operation based on playback device context | |||
if (target != null) { | |||
HwmfBkMode oldMode = prop.getBkMode(); |
@@ -146,7 +146,7 @@ public class HwmfText { | |||
@Override | |||
public HwmfRecordType getWmfRecordType() { | |||
return HwmfRecordType.setBkColor; | |||
return HwmfRecordType.setTextJustification; | |||
} | |||
@Override | |||
@@ -236,7 +236,7 @@ public class HwmfText { | |||
@Override | |||
public Map<String, Supplier<?>> getGenericProperties() { | |||
return GenericRecordUtil.getGenericProperties( | |||
"text", () -> getText(StandardCharsets.US_ASCII), | |||
"text", () -> getText(charsetProvider.get()), | |||
"reference", () -> reference | |||
); | |||
} |