git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1861952 13f79535-47bb-0310-9956-ffa450edef68pull/158/head
@@ -23,6 +23,7 @@ import java.awt.Graphics2D; | |||
import java.awt.Insets; | |||
import java.awt.Shape; | |||
import java.awt.geom.AffineTransform; | |||
import java.awt.geom.Dimension2D; | |||
import java.awt.geom.Rectangle2D; | |||
import java.awt.image.AffineTransformOp; | |||
import java.awt.image.BufferedImage; | |||
@@ -237,7 +238,7 @@ public class BitmapImageRenderer implements ImageRenderer { | |||
} | |||
@Override | |||
public BufferedImage getImage(Dimension dim) { | |||
public BufferedImage getImage(Dimension2D dim) { | |||
double w_old = img.getWidth(); | |||
double h_old = img.getHeight(); | |||
BufferedImage scaled = new BufferedImage((int)w_old, (int)h_old, BufferedImage.TYPE_INT_ARGB); |
@@ -234,46 +234,50 @@ public class DrawPaint { | |||
@SuppressWarnings("WeakerAccess") | |||
protected Paint getTexturePaint(TexturePaint fill, Graphics2D graphics) { | |||
InputStream is = fill.getImageData(); | |||
if (is == null) { | |||
return TRANSPARENT; | |||
} | |||
assert(graphics != null); | |||
ImageRenderer renderer = DrawPictureShape.getImageRenderer(graphics, fill.getContentType()); | |||
final String contentType = fill.getContentType(); | |||
try { | |||
try { | |||
renderer.loadImage(is, fill.getContentType()); | |||
} finally { | |||
is.close(); | |||
} | |||
} catch (IOException e) { | |||
LOG.log(POILogger.ERROR, "Can't load image data - using transparent color", e); | |||
return TRANSPARENT; | |||
} | |||
ImageRenderer renderer = DrawPictureShape.getImageRenderer(graphics, contentType); | |||
int alpha = fill.getAlpha(); | |||
if (0 <= alpha && alpha < 100000) { | |||
renderer.setAlpha(alpha/100000.f); | |||
} | |||
// TODO: handle tile settings, currently the pattern is always streched 100% in height/width | |||
Rectangle2D textAnchor = shape.getAnchor(); | |||
BufferedImage image; | |||
if ("image/x-wmf".equals(fill.getContentType())) { | |||
// don't rely on wmf dimensions, use dimension of anchor | |||
// TODO: check pixels vs. points for image dimension | |||
image = renderer.getImage(new Dimension((int)textAnchor.getWidth(), (int)textAnchor.getHeight())); | |||
} else { | |||
image = renderer.getImage(); | |||
} | |||
if(image == null) { | |||
LOG.log(POILogger.ERROR, "Can't load image data"); | |||
try (InputStream is = fill.getImageData()) { | |||
if (is == null) { | |||
return TRANSPARENT; | |||
} | |||
renderer.loadImage(is, contentType); | |||
final BufferedImage image; | |||
switch (contentType) { | |||
case "image/x-wmf": | |||
case "image/x-emf": | |||
// don't rely on wmf dimensions, use dimension of anchor | |||
// TODO: check pixels vs. points for image dimension | |||
image = renderer.getImage(new Dimension((int)textAnchor.getWidth(), (int)textAnchor.getHeight())); | |||
break; | |||
default: | |||
image = renderer.getImage(); | |||
break; | |||
} | |||
if(image == null) { | |||
LOG.log(POILogger.ERROR, "Can't load image data"); | |||
return TRANSPARENT; | |||
} | |||
return new java.awt.TexturePaint(image, textAnchor); | |||
} catch (IOException e) { | |||
LOG.log(POILogger.ERROR, "Can't load image data - using transparent color", e); | |||
return TRANSPARENT; | |||
} | |||
return new java.awt.TexturePaint(image, textAnchor); | |||
} | |||
/** |
@@ -56,9 +56,10 @@ public class DrawPictureShape extends DrawSimpleShape { | |||
} | |||
try { | |||
ImageRenderer renderer = getImageRenderer(graphics, data.getContentType()); | |||
if (renderer.canRender(data.getContentType())) { | |||
renderer.loadImage(data.getData(), data.getContentType()); | |||
String ct = data.getContentType(); | |||
ImageRenderer renderer = getImageRenderer(graphics, ct); | |||
if (renderer.canRender(ct)) { | |||
renderer.loadImage(data.getData(), ct); | |||
renderer.drawImage(graphics, anchor, insets); | |||
return; | |||
} |
@@ -27,23 +27,10 @@ import java.awt.geom.AffineTransform; | |||
import java.awt.geom.Ellipse2D; | |||
import java.awt.geom.Path2D; | |||
import java.awt.geom.Rectangle2D; | |||
import java.io.InputStream; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import javax.xml.bind.JAXBContext; | |||
import javax.xml.bind.JAXBElement; | |||
import javax.xml.bind.Unmarshaller; | |||
import javax.xml.stream.EventFilter; | |||
import javax.xml.stream.XMLEventReader; | |||
import javax.xml.stream.XMLInputFactory; | |||
import javax.xml.stream.events.StartElement; | |||
import javax.xml.stream.events.XMLEvent; | |||
import org.apache.poi.sl.draw.binding.CTCustomGeometry2D; | |||
import org.apache.poi.sl.draw.geom.Context; | |||
import org.apache.poi.sl.draw.geom.CustomGeometry; | |||
import org.apache.poi.sl.draw.geom.Outline; | |||
@@ -54,8 +41,6 @@ import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize; | |||
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; | |||
import org.apache.poi.sl.usermodel.Shadow; | |||
import org.apache.poi.sl.usermodel.SimpleShape; | |||
import org.apache.poi.util.IOUtils; | |||
import org.apache.poi.util.StaxHelper; | |||
import org.apache.poi.util.Units; | |||
@@ -18,9 +18,9 @@ | |||
*/ | |||
package org.apache.poi.sl.draw; | |||
import java.awt.Dimension; | |||
import java.awt.Graphics2D; | |||
import java.awt.Insets; | |||
import java.awt.geom.Dimension2D; | |||
import java.awt.geom.Rectangle2D; | |||
import java.awt.image.BufferedImage; | |||
import java.io.IOException; | |||
@@ -101,7 +101,7 @@ public interface ImageRenderer { | |||
/** | |||
* @return the dimension of the buffered image | |||
*/ | |||
Dimension getDimension(); | |||
Dimension2D getDimension(); | |||
/** | |||
* @param alpha the alpha [0..1] to be added to the image (possibly already containing an alpha channel) | |||
@@ -119,7 +119,7 @@ public interface ImageRenderer { | |||
* | |||
* @since POI 3.15-beta2 | |||
*/ | |||
BufferedImage getImage(Dimension dim); | |||
BufferedImage getImage(Dimension2D dim); | |||
/** | |||
* Render picture data into the supplied graphics |
@@ -16,9 +16,8 @@ | |||
==================================================================== */ | |||
package org.apache.poi.util; | |||
/** | |||
* @author Yegor Kozlov | |||
*/ | |||
import java.awt.geom.Dimension2D; | |||
public class Units { | |||
/** | |||
* In Escher absolute distances are specified in | |||
@@ -146,7 +145,13 @@ public class Units { | |||
points /= PIXEL_DPI; | |||
return points; | |||
} | |||
public static Dimension2D pointsToPixel(Dimension2D pointsDim) { | |||
double width = pointsDim.getWidth() * PIXEL_DPI / POINT_DPI; | |||
double height = pointsDim.getHeight() * PIXEL_DPI / POINT_DPI; | |||
return new Dimension2DDouble(width, height); | |||
} | |||
public static int charactersToEMU(double characters) { | |||
return (int) characters * EMU_PER_CHARACTER; | |||
} |
@@ -17,11 +17,11 @@ | |||
package org.apache.poi.xslf.draw; | |||
import java.awt.Dimension; | |||
import java.awt.Graphics2D; | |||
import java.awt.Insets; | |||
import java.awt.RenderingHints; | |||
import java.awt.geom.AffineTransform; | |||
import java.awt.geom.Dimension2D; | |||
import java.awt.geom.Rectangle2D; | |||
import java.awt.image.BufferedImage; | |||
import java.io.ByteArrayInputStream; | |||
@@ -42,6 +42,7 @@ import org.apache.batik.util.XMLResourceDescriptor; | |||
import org.apache.poi.sl.draw.Drawable; | |||
import org.apache.poi.sl.draw.ImageRenderer; | |||
import org.apache.poi.sl.usermodel.PictureData; | |||
import org.apache.poi.util.Dimension2DDouble; | |||
import org.w3c.dom.Document; | |||
public class SVGImageRenderer implements ImageRenderer { | |||
@@ -75,9 +76,9 @@ public class SVGImageRenderer implements ImageRenderer { | |||
} | |||
@Override | |||
public Dimension getDimension() { | |||
public Dimension2D getDimension() { | |||
Rectangle2D r = svgRoot.getPrimitiveBounds(); | |||
return new Dimension((int)Math.ceil(r.getWidth()), (int)Math.ceil(r.getHeight())); | |||
return new Dimension2DDouble(Math.ceil(r.getWidth()), Math.ceil(r.getHeight())); | |||
} | |||
@Override | |||
@@ -91,7 +92,7 @@ public class SVGImageRenderer implements ImageRenderer { | |||
} | |||
@Override | |||
public BufferedImage getImage(Dimension dim) { | |||
public BufferedImage getImage(Dimension2D dim) { | |||
BufferedImage bi = new BufferedImage((int)dim.getWidth(), (int)dim.getHeight(), BufferedImage.TYPE_INT_ARGB); | |||
Graphics2D g2d = (Graphics2D) bi.getGraphics(); | |||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | |||
@@ -101,7 +102,7 @@ public class SVGImageRenderer implements ImageRenderer { | |||
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); | |||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); | |||
g2d.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE, new WeakReference(bi)); | |||
Dimension dimSVG = getDimension(); | |||
Dimension2D dimSVG = getDimension(); | |||
double scaleX = dim.getWidth() / dimSVG.getWidth(); | |||
double scaleY = dim.getHeight() / dimSVG.getHeight(); | |||
@@ -122,7 +123,7 @@ public class SVGImageRenderer implements ImageRenderer { | |||
public boolean drawImage(Graphics2D graphics, Rectangle2D anchor, Insets clip) { | |||
graphics.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE, graphics.getRenderingHint(Drawable.BUFFERED_IMAGE)); | |||
Dimension bounds = getDimension(); | |||
Dimension2D bounds = getDimension(); | |||
AffineTransform at = new AffineTransform(); | |||
at.translate(anchor.getX(), anchor.getY()); |
@@ -21,8 +21,8 @@ package org.apache.poi.xslf.usermodel; | |||
import static org.apache.poi.openxml4j.opc.PackageRelationshipTypes.CORE_PROPERTIES_ECMA376_NS; | |||
import java.awt.Dimension; | |||
import java.awt.Insets; | |||
import java.awt.geom.Dimension2D; | |||
import java.awt.geom.Rectangle2D; | |||
import java.awt.image.BufferedImage; | |||
import java.io.ByteArrayInputStream; | |||
@@ -305,7 +305,7 @@ public class XSLFPictureShape extends XSLFSimpleShape | |||
renderer.loadImage(is, svgPic.getType().contentType); | |||
} | |||
Dimension dim = renderer.getDimension(); | |||
Dimension2D dim = renderer.getDimension(); | |||
Rectangle2D anc = (anchor != null) ? anchor | |||
: new Rectangle2D.Double(0,0, Units.pixelToPoints((int)dim.getWidth()), Units.pixelToPoints((int)dim.getHeight())); | |||
@@ -60,6 +60,7 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.STPathShadeType; | |||
import org.openxmlformats.schemas.presentationml.x2006.main.CTBackgroundProperties; | |||
import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture; | |||
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; | |||
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; | |||
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; | |||
@@ -149,6 +150,15 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { | |||
PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() { | |||
@Override | |||
public boolean fetch(XSLFShape shape) { | |||
PackagePart pp = shape.getSheet().getPackagePart(); | |||
if (shape instanceof XSLFPictureShape) { | |||
CTPicture pic = (CTPicture)shape.getXmlObject(); | |||
if (pic.getBlipFill() != null) { | |||
setValue(selectPaint(pic.getBlipFill(), pp)); | |||
return true; | |||
} | |||
} | |||
XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(shape.getShapeProperties()); | |||
if (fp == null) { | |||
return false; | |||
@@ -159,7 +169,6 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { | |||
return true; | |||
} | |||
PackagePart pp = shape.getSheet().getPackagePart(); | |||
PaintStyle paint = selectPaint(fp, null, pp, theme, hasPlaceholder); | |||
if (paint != null) { | |||
setValue(paint); |
@@ -29,6 +29,7 @@ import java.util.List; | |||
import java.util.Locale; | |||
import java.util.Set; | |||
import java.util.TreeSet; | |||
import java.util.regex.Pattern; | |||
import javax.imageio.ImageIO; | |||
@@ -39,21 +40,30 @@ import org.apache.poi.sl.usermodel.SlideShowFactory; | |||
/** | |||
* An utility to convert slides of a .pptx slide show to a PNG image | |||
* | |||
* @author Yegor Kozlov | |||
*/ | |||
public class PPTX2PNG { | |||
static void usage(String error){ | |||
private static final String INPUT_PAT_REGEX = | |||
"(?<slideno>[^|]+)\\|(?<format>[^|]+)\\|(?<basename>.+)\\.(?<ext>[^.]++)"; | |||
private static final Pattern INPUT_PATTERN = Pattern.compile(INPUT_PAT_REGEX); | |||
private static final String OUTPUT_PAT_REGEX = "${basename}-${slideno}.${format}"; | |||
private static void usage(String error){ | |||
String msg = | |||
"Usage: PPTX2PNG [options] <ppt or pptx file>\n" + | |||
(error == null ? "" : ("Error: "+error+"\n")) + | |||
"Options:\n" + | |||
" -scale <float> scale factor\n" + | |||
" -slide <integer> 1-based index of a slide to render\n" + | |||
" -format <type> png,gif,jpg (,null for testing)" + | |||
" -outdir <dir> output directory, defaults to origin of the ppt/pptx file" + | |||
" -quiet do not write to console (for normal processing)"; | |||
" -scale <float> scale factor\n" + | |||
" -slide <integer> 1-based index of a slide to render\n" + | |||
" -format <type> png,gif,jpg (,null for testing)\n" + | |||
" -outdir <dir> output directory, defaults to origin of the ppt/pptx file\n" + | |||
" -outfile <file> output filename, defaults to '"+OUTPUT_PAT_REGEX+"'\n" + | |||
" -outpat <pattern> output filename pattern, defaults to '"+OUTPUT_PAT_REGEX+"'\n" + | |||
" patterns: basename, slideno, format, ext\n" + | |||
" -quiet do not write to console (for normal processing)"; | |||
System.out.println(msg); | |||
// no System.exit here, as we also run in junit tests! | |||
@@ -70,23 +80,43 @@ public class PPTX2PNG { | |||
File file = null; | |||
String format = "png"; | |||
File outdir = null; | |||
String outfile = null; | |||
boolean quiet = false; | |||
String outpattern = OUTPUT_PAT_REGEX; | |||
for (int i = 0; i < args.length; i++) { | |||
if (args[i].startsWith("-")) { | |||
if ("-scale".equals(args[i])) { | |||
scale = Float.parseFloat(args[++i]); // lgtm[java/index-out-of-bounds] | |||
} else if ("-slide".equals(args[i])) { | |||
slidenumStr = args[++i]; // lgtm[java/index-out-of-bounds] | |||
} else if ("-format".equals(args[i])) { | |||
format = args[++i]; // lgtm[java/index-out-of-bounds] | |||
} else if ("-outdir".equals(args[i])) { | |||
outdir = new File(args[++i]); // lgtm[java/index-out-of-bounds] | |||
} else if ("-quiet".equals(args[i])) { | |||
String opt = (i+1 < args.length) ? args[i+1] : null; | |||
switch (args[i]) { | |||
case "-scale": | |||
scale = Float.parseFloat(opt); | |||
i++; | |||
break; | |||
case "-slide": | |||
slidenumStr = opt; | |||
i++; | |||
break; | |||
case "-format": | |||
format = opt; | |||
i++; | |||
break; | |||
case "-outdir": | |||
outdir = new File(opt); | |||
i++; | |||
break; | |||
case "-outfile": | |||
outfile = opt; | |||
i++; | |||
break; | |||
case "-outpat": | |||
outpattern = opt; | |||
i++; | |||
break; | |||
case "-quiet": | |||
quiet = true; | |||
} | |||
} else { | |||
file = new File(args[i]); | |||
break; | |||
default: | |||
file = new File(args[i]); | |||
break; | |||
} | |||
} | |||
@@ -135,7 +165,7 @@ public class PPTX2PNG { | |||
Slide<?, ?> slide = slides.get(slideNo); | |||
String title = slide.getTitle(); | |||
if (!quiet) { | |||
System.out.println("Rendering slide " + slideNo + (title == null ? "" : ": " + title)); | |||
System.out.println("Rendering slide " + (slideNo+1) + (title == null ? "" : ": " + title.trim())); | |||
} | |||
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); | |||
@@ -155,10 +185,9 @@ public class PPTX2PNG { | |||
// save the result | |||
if (!"null".equals(format)) { | |||
String outname = file.getName().replaceFirst(".pptx?", ""); | |||
outname = String.format(Locale.ROOT, "%1$s-%2$04d.%3$s", outname, slideNo, format); | |||
File outfile = new File(outdir, outname); | |||
ImageIO.write(img, format, outfile); | |||
String inname = String.format(Locale.ROOT, "%04d|%s|%s", slideNo+1, format, file.getName()); | |||
String outname = (outfile != null) ? outfile : INPUT_PATTERN.matcher(inname).replaceAll(outpattern); | |||
ImageIO.write(img, format, new File(outdir, outname)); | |||
} | |||
graphics.dispose(); |
@@ -94,9 +94,10 @@ public class TestPPTX2PNG { | |||
assumeFalse("ignore HSLF / .ppt files in no-scratchpad run", xslfOnly && pptFile.toLowerCase(Locale.ROOT).endsWith("ppt")); | |||
String[] args = { | |||
"-format", "null", // png,gif,jpg or null for test | |||
"-format", "png", // png,gif,jpg or null for test | |||
"-slide", "-1", // -1 for all | |||
"-outdir", new File("build/tmp/").getCanonicalPath(), | |||
"-outpat", "${basename}-${slideno}-${ext}.${format}", | |||
"-quiet", | |||
(basedir == null ? samples.getFile(pptFile) : new File(basedir, pptFile)).getAbsolutePath() | |||
}; |
@@ -60,15 +60,8 @@ public class HemfImageRenderer implements ImageRenderer { | |||
} | |||
@Override | |||
public Dimension getDimension() { | |||
int width = 0, height = 0; | |||
if (image != null) { | |||
Dimension2D dim = image.getSize(); | |||
width = Units.pointsToPixel(dim.getWidth()); | |||
// keep aspect ratio for height | |||
height = Units.pointsToPixel(dim.getHeight()); | |||
} | |||
return new Dimension(width, height); | |||
public Dimension2D getDimension() { | |||
return Units.pointsToPixel(image == null ? new Dimension() : image.getSize()); | |||
} | |||
@Override | |||
@@ -82,7 +75,7 @@ public class HemfImageRenderer implements ImageRenderer { | |||
} | |||
@Override | |||
public BufferedImage getImage(Dimension dim) { | |||
public BufferedImage getImage(Dimension2D dim) { | |||
if (image == null) { | |||
return new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); | |||
} |
@@ -19,6 +19,7 @@ package org.apache.poi.hemf.usermodel; | |||
import java.awt.Graphics2D; | |||
import java.awt.Shape; | |||
import java.awt.geom.AffineTransform; | |||
import java.awt.geom.Dimension2D; | |||
import java.awt.geom.Rectangle2D; | |||
@@ -152,9 +153,10 @@ public class HemfPicture implements Iterable<HemfRecord> { | |||
} | |||
public void draw(Graphics2D ctx, Rectangle2D graphicsBounds) { | |||
HemfHeader header = (HemfHeader)getRecords().get(0); | |||
final HemfHeader header = (HemfHeader)getRecords().get(0); | |||
AffineTransform at = ctx.getTransform(); | |||
final Shape clip = ctx.getClip(); | |||
final AffineTransform at = ctx.getTransform(); | |||
try { | |||
Rectangle2D emfBounds = header.getBoundsRectangle(); | |||
@@ -175,6 +177,7 @@ public class HemfPicture implements Iterable<HemfRecord> { | |||
} | |||
} finally { | |||
ctx.setTransform(at); | |||
ctx.setClip(clip); | |||
} | |||
} | |||
@@ -415,9 +415,9 @@ public final class HSLFFill { | |||
EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST); | |||
int propVal = (p == null) ? 0 : p.getPropertyValue(); | |||
return (FILL_USE_FILLED.isSet(propVal) && !FILL_FILLED.isSet(propVal)) | |||
? null | |||
: shape.getColor(EscherProperties.FILL__FILLCOLOR, EscherProperties.FILL__FILLOPACITY); | |||
return (FILL_USE_FILLED.isSet(propVal) && FILL_FILLED.isSet(propVal)) | |||
? shape.getColor(EscherProperties.FILL__FILLCOLOR, EscherProperties.FILL__FILLOPACITY) | |||
: null; | |||
} | |||
/** | |||
@@ -459,9 +459,9 @@ public final class HSLFFill { | |||
EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST); | |||
int propVal = (p == null) ? 0 : p.getPropertyValue(); | |||
return (FILL_USE_FILLED.isSet(propVal) && !FILL_FILLED.isSet(propVal)) | |||
? null | |||
: shape.getColor(EscherProperties.FILL__FILLBACKCOLOR, EscherProperties.FILL__FILLOPACITY); | |||
return (FILL_USE_FILLED.isSet(propVal) && FILL_FILLED.isSet(propVal)) | |||
? shape.getColor(EscherProperties.FILL__FILLBACKCOLOR, EscherProperties.FILL__FILLOPACITY) | |||
: null; | |||
} | |||
/** |
@@ -43,6 +43,7 @@ import java.util.BitSet; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import java.util.NoSuchElementException; | |||
import java.util.Objects; | |||
import java.util.TreeMap; | |||
import org.apache.commons.codec.Charsets; | |||
@@ -352,8 +353,9 @@ public class HwmfGraphics { | |||
case MM_ISOTROPIC: | |||
// TODO: to be validated ... | |||
// like anisotropic, but use x-axis as reference | |||
graphicsCtx.translate(bbox.getCenterX(), bbox.getCenterY()); | |||
graphicsCtx.scale(bbox.getWidth()/win.getWidth(), bbox.getWidth()/win.getWidth()); | |||
graphicsCtx.translate(-win.getX(), -win.getY()); | |||
graphicsCtx.translate(-win.getCenterX(), -win.getCenterY()); | |||
break; | |||
case MM_LOMETRIC: | |||
case MM_HIMETRIC: | |||
@@ -407,11 +409,8 @@ public class HwmfGraphics { | |||
} | |||
} | |||
String textString = ""; | |||
if (text != null) { | |||
textString = new String(text, charset).trim(); | |||
textString = textString.substring(0, Math.min(textString.length(), length)); | |||
} | |||
String textString = new String(text, charset).trim(); | |||
textString = textString.substring(0, Math.min(textString.length(), length)); | |||
if (textString.isEmpty()) { | |||
return; | |||
@@ -504,7 +503,7 @@ public class HwmfGraphics { | |||
final Shape clipShape = graphicsCtx.getClip(); | |||
try { | |||
if (clip != null) { | |||
if (clip != null && !clip.getBounds2D().isEmpty()) { | |||
graphicsCtx.translate(-clip.getCenterX(), -clip.getCenterY()); | |||
graphicsCtx.rotate(angle); | |||
graphicsCtx.translate(clip.getCenterX(), clip.getCenterY()); | |||
@@ -647,59 +646,28 @@ public class HwmfGraphics { | |||
graphicsCtx.setTransform(tx); | |||
} | |||
private static int clipCnt = 0; | |||
/** | |||
* Set the new clipping region | |||
* | |||
* @param clip the next clipping region to be processed | |||
* @param regionMode the mode and operation of how to apply the next clipping region | |||
* @param useInitialAT if true, the clipping is applied on the initial (world) coordinate system | |||
*/ | |||
public void setClip(Shape clip, HwmfRegionMode regionMode, boolean useInitialAT) { | |||
final AffineTransform at = graphicsCtx.getTransform(); | |||
if (useInitialAT) { | |||
graphicsCtx.setTransform(initialAT); | |||
} | |||
final Shape oldClip = graphicsCtx.getClip(); | |||
final boolean isEmpty = clip.getBounds2D().isEmpty(); | |||
switch (regionMode) { | |||
case RGN_AND: | |||
if (!isEmpty) { | |||
graphicsCtx.clip(clip); | |||
} | |||
break; | |||
case RGN_OR: | |||
if (!isEmpty) { | |||
if (oldClip == null) { | |||
graphicsCtx.setClip(clip); | |||
} else { | |||
Area area = new Area(oldClip); | |||
area.add(new Area(clip)); | |||
graphicsCtx.setClip(area); | |||
} | |||
} | |||
break; | |||
case RGN_XOR: | |||
if (!isEmpty) { | |||
if (oldClip == null) { | |||
graphicsCtx.setClip(clip); | |||
} else { | |||
Area area = new Area(oldClip); | |||
area.exclusiveOr(new Area(clip)); | |||
graphicsCtx.setClip(area); | |||
} | |||
} | |||
break; | |||
case RGN_DIFF: | |||
if (!isEmpty) { | |||
if (oldClip != null) { | |||
Area area = new Area(oldClip); | |||
area.subtract(new Area(clip)); | |||
graphicsCtx.setClip(area); | |||
} | |||
} | |||
break; | |||
case RGN_COPY: { | |||
graphicsCtx.setClip(isEmpty ? null : clip); | |||
break; | |||
} | |||
final Shape newClip = regionMode.applyOp(oldClip, clip); | |||
if (!Objects.equals(oldClip, newClip)) { | |||
graphicsCtx.setClip(newClip); | |||
} | |||
if (useInitialAT) { | |||
graphicsCtx.setTransform(at); | |||
} | |||
prop.setClip(graphicsCtx.getClip()); | |||
} | |||
} |
@@ -21,6 +21,7 @@ import java.awt.Dimension; | |||
import java.awt.Graphics2D; | |||
import java.awt.Insets; | |||
import java.awt.RenderingHints; | |||
import java.awt.geom.Dimension2D; | |||
import java.awt.geom.Rectangle2D; | |||
import java.awt.image.BufferedImage; | |||
import java.awt.image.RescaleOp; | |||
@@ -64,15 +65,8 @@ public class HwmfImageRenderer implements ImageRenderer { | |||
} | |||
@Override | |||
public Dimension getDimension() { | |||
int width = 0, height = 0; | |||
if (image != null) { | |||
Dimension dim = image.getSize(); | |||
width = Units.pointsToPixel(dim.getWidth()); | |||
// keep aspect ratio for height | |||
height = Units.pointsToPixel(dim.getHeight()); | |||
} | |||
return new Dimension(width, height); | |||
public Dimension2D getDimension() { | |||
return Units.pointsToPixel(image == null ? new Dimension() : image.getSize()); | |||
} | |||
@Override | |||
@@ -86,7 +80,7 @@ public class HwmfImageRenderer implements ImageRenderer { | |||
} | |||
@Override | |||
public BufferedImage getImage(Dimension dim) { | |||
public BufferedImage getImage(Dimension2D dim) { | |||
if (image == null) { | |||
return new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); | |||
} |
@@ -715,7 +715,17 @@ public class HwmfFill { | |||
} | |||
} | |||
public static class WmfDibStretchBlt implements HwmfRecord, HwmfImageRecord, HwmfObjectTableEntry { | |||
/** | |||
* The META_DIBSTRETCHBLT record specifies the transfer of a block of pixels in device-independent format | |||
* according to a raster operation, with possible expansion or contraction. | |||
* | |||
* The destination of the transfer is the current output region in the playback device context. | |||
* There are two forms of META_DIBSTRETCHBLT, one which specifies a device-independent bitmap (DIB) as the source, | |||
* and the other which uses the playback device context as the source. Definitions follow for the fields that are | |||
* the same in the two forms of META_DIBSTRETCHBLT. The subsections that follow specify the packet structures of | |||
* the two forms of META_DIBSTRETCHBLT. | |||
*/ | |||
public static class WmfDibStretchBlt implements HwmfRecord, HwmfImageRecord { | |||
/** | |||
* A 32-bit unsigned integer that defines how the source pixels, the current brush | |||
* in the playback device context, and the destination pixels are to be combined to form the | |||
@@ -748,7 +758,7 @@ public class HwmfFill { | |||
int rasterOpIndex = leis.readUShort(); | |||
rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex); | |||
assert(rasterOpCode == rasterOperation.opCode); | |||
assert(rasterOperation != null && rasterOpCode == rasterOperation.opCode); | |||
int size = 2*LittleEndianConsts.SHORT_SIZE; | |||
@@ -769,12 +779,18 @@ public class HwmfFill { | |||
@Override | |||
public void draw(HwmfGraphics ctx) { | |||
ctx.addObjectTableEntry(this); | |||
} | |||
@Override | |||
public void applyObject(HwmfGraphics ctx) { | |||
HwmfDrawProperties prop = ctx.getProperties(); | |||
prop.setRasterOp(rasterOperation); | |||
// TODO: implement second operation based on playback device context | |||
if (target != null) { | |||
HwmfBkMode mode = prop.getBkMode(); | |||
prop.setBkMode(HwmfBkMode.TRANSPARENT); | |||
Color fgColor = prop.getPenColor().getColor(); | |||
Color bgColor = prop.getBackgroundColor().getColor(); | |||
BufferedImage bi = target.getImage(fgColor, bgColor, true); | |||
ctx.drawImage(bi, srcBounds, dstBounds); | |||
prop.setBkMode(mode); | |||
} | |||
} | |||
@Override |
@@ -17,37 +17,42 @@ | |||
package org.apache.poi.hwmf.record; | |||
import org.apache.poi.hemf.record.emf.HemfFill; | |||
import java.awt.Shape; | |||
import java.awt.geom.Area; | |||
import java.util.function.BiFunction; | |||
public enum HwmfRegionMode { | |||
/** | |||
* The new clipping region includes the intersection (overlapping areas) | |||
* of the current clipping region and the current path (or new region). | |||
*/ | |||
RGN_AND(0x01), | |||
RGN_AND(0x01, HwmfRegionMode::andOp), | |||
/** | |||
* The new clipping region includes the union (combined areas) | |||
* of the current clipping region and the current path (or new region). | |||
*/ | |||
RGN_OR(0x02), | |||
RGN_OR(0x02, HwmfRegionMode::orOp), | |||
/** | |||
* The new clipping region includes the union of the current clipping region | |||
* and the current path (or new region) but without the overlapping areas | |||
*/ | |||
RGN_XOR(0x03), | |||
RGN_XOR(0x03, HwmfRegionMode::xorOp), | |||
/** | |||
* The new clipping region includes the areas of the current clipping region | |||
* with those of the current path (or new region) excluded. | |||
*/ | |||
RGN_DIFF(0x04), | |||
RGN_DIFF(0x04, HwmfRegionMode::diffOp), | |||
/** | |||
* The new clipping region is the current path (or the new region). | |||
*/ | |||
RGN_COPY(0x05); | |||
RGN_COPY(0x05, HwmfRegionMode::copyOp); | |||
int flag; | |||
HwmfRegionMode(int flag) { | |||
private final int flag; | |||
private final BiFunction<Shape,Shape,Shape> op; | |||
HwmfRegionMode(int flag, BiFunction<Shape,Shape,Shape> op) { | |||
this.flag = flag; | |||
this.op = op; | |||
} | |||
public static HwmfRegionMode valueOf(int flag) { | |||
@@ -56,4 +61,68 @@ public enum HwmfRegionMode { | |||
} | |||
return null; | |||
} | |||
public int getFlag() { | |||
return flag; | |||
} | |||
public Shape applyOp(Shape oldClip, Shape newClip) { | |||
return op.apply(oldClip, newClip); | |||
} | |||
private static Shape andOp(final Shape oldClip, final Shape newClip) { | |||
assert(newClip != null); | |||
if (newClip.getBounds2D().isEmpty()) { | |||
return oldClip; | |||
} else if (oldClip == null) { | |||
return newClip; | |||
} else { | |||
Area newArea = new Area(oldClip); | |||
newArea.intersect(new Area(newClip)); | |||
return newArea.getBounds2D().isEmpty() ? newClip : newArea; | |||
} | |||
} | |||
private static Shape orOp(final Shape oldClip, final Shape newClip) { | |||
assert(newClip != null); | |||
if (newClip.getBounds2D().isEmpty()) { | |||
return oldClip; | |||
} else if (oldClip == null) { | |||
return newClip; | |||
} else { | |||
Area newArea = new Area(oldClip); | |||
newArea.add(new Area(newClip)); | |||
return newArea; | |||
} | |||
} | |||
private static Shape xorOp(final Shape oldClip, final Shape newClip) { | |||
assert(newClip != null); | |||
if (newClip.getBounds2D().isEmpty()) { | |||
return oldClip; | |||
} else if (oldClip == null) { | |||
return newClip; | |||
} else { | |||
Area newArea = new Area(oldClip); | |||
newArea.exclusiveOr(new Area(newClip)); | |||
return newArea; | |||
} | |||
} | |||
private static Shape diffOp(final Shape oldClip, final Shape newClip) { | |||
assert(newClip != null); | |||
if (newClip.getBounds2D().isEmpty()) { | |||
return oldClip; | |||
} else if (oldClip == null) { | |||
return newClip; | |||
} else { | |||
Area newArea = new Area(oldClip); | |||
newArea.subtract(new Area(newClip)); | |||
return newArea; | |||
} | |||
} | |||
private static Shape copyOp(final Shape oldClip, final Shape newClip) { | |||
return (newClip == null || newClip.getBounds2D().isEmpty()) ? null : newClip; | |||
} | |||
} |
@@ -25,6 +25,7 @@ import static org.apache.poi.hwmf.record.HwmfDraw.readBounds; | |||
import static org.apache.poi.hwmf.record.HwmfDraw.readPointS; | |||
import java.awt.Shape; | |||
import java.awt.geom.AffineTransform; | |||
import java.awt.geom.Area; | |||
import java.awt.geom.Dimension2D; | |||
import java.awt.geom.Point2D; | |||
@@ -380,7 +381,7 @@ public class HwmfWindowing { | |||
* The META_OFFSETCLIPRGN record moves the clipping region in the playback device context by the | |||
* specified offsets. | |||
*/ | |||
public static class WmfOffsetClipRgn implements HwmfRecord, HwmfObjectTableEntry { | |||
public static class WmfOffsetClipRgn implements HwmfRecord { | |||
protected final Point2D offset = new Point2D.Double(); | |||
@@ -396,11 +397,14 @@ public class HwmfWindowing { | |||
@Override | |||
public void draw(HwmfGraphics ctx) { | |||
ctx.addObjectTableEntry(this); | |||
} | |||
@Override | |||
public void applyObject(HwmfGraphics ctx) { | |||
final Shape oldClip = ctx.getProperties().getClip(); | |||
if (oldClip == null) { | |||
return; | |||
} | |||
AffineTransform at = new AffineTransform(); | |||
at.translate(offset.getX(),offset.getY()); | |||
final Shape newClip = at.createTransformedShape(oldClip); | |||
ctx.setClip(newClip, HwmfRegionMode.RGN_COPY, false); | |||
} | |||
@Override | |||
@@ -413,7 +417,7 @@ public class HwmfWindowing { | |||
* The META_EXCLUDECLIPRECT record sets the clipping region in the playback device context to the | |||
* existing clipping region minus the specified rectangle. | |||
*/ | |||
public static class WmfExcludeClipRect implements HwmfRecord, HwmfObjectTableEntry { | |||
public static class WmfExcludeClipRect implements HwmfRecord { | |||
/** a rectangle in logical units */ | |||
protected final Rectangle2D bounds = new Rectangle2D.Double(); | |||
@@ -430,14 +434,9 @@ public class HwmfWindowing { | |||
@Override | |||
public void draw(HwmfGraphics ctx) { | |||
ctx.addObjectTableEntry(this); | |||
} | |||
@Override | |||
public void applyObject(HwmfGraphics ctx) { | |||
ctx.setClip(normalizeBounds(bounds), HwmfRegionMode.RGN_DIFF, false); | |||
} | |||
@Override | |||
public String toString() { | |||
return boundsToString(bounds); | |||
@@ -449,7 +448,7 @@ public class HwmfWindowing { | |||
* The META_INTERSECTCLIPRECT record sets the clipping region in the playback device context to the | |||
* intersection of the existing clipping region and the specified rectangle. | |||
*/ | |||
public static class WmfIntersectClipRect implements HwmfRecord, HwmfObjectTableEntry { | |||
public static class WmfIntersectClipRect implements HwmfRecord { | |||
/** a rectangle in logical units */ | |||
protected final Rectangle2D bounds = new Rectangle2D.Double(); | |||
@@ -466,14 +465,9 @@ public class HwmfWindowing { | |||
@Override | |||
public void draw(HwmfGraphics ctx) { | |||
ctx.addObjectTableEntry(this); | |||
ctx.setClip(bounds, HwmfRegionMode.RGN_AND, false); | |||
} | |||
@Override | |||
public void applyObject(HwmfGraphics ctx) { | |||
ctx.setClip(bounds, HwmfRegionMode.RGN_AND, true); | |||
} | |||
@Override | |||
public String toString() { | |||
return boundsToString(bounds); |
@@ -17,17 +17,19 @@ | |||
package org.apache.poi.hwmf.usermodel; | |||
import java.awt.Dimension; | |||
import java.awt.Graphics2D; | |||
import java.awt.Shape; | |||
import java.awt.geom.AffineTransform; | |||
import java.awt.geom.Dimension2D; | |||
import java.awt.geom.Rectangle2D; | |||
import java.io.BufferedInputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.Objects; | |||
import org.apache.poi.hwmf.draw.HwmfDrawProperties; | |||
import org.apache.poi.hwmf.draw.HwmfGraphics; | |||
import org.apache.poi.hwmf.record.HwmfHeader; | |||
import org.apache.poi.hwmf.record.HwmfPlaceableHeader; | |||
@@ -35,6 +37,7 @@ import org.apache.poi.hwmf.record.HwmfRecord; | |||
import org.apache.poi.hwmf.record.HwmfRecordType; | |||
import org.apache.poi.hwmf.record.HwmfWindowing.WmfSetWindowExt; | |||
import org.apache.poi.hwmf.record.HwmfWindowing.WmfSetWindowOrg; | |||
import org.apache.poi.util.Dimension2DDouble; | |||
import org.apache.poi.util.IOUtils; | |||
import org.apache.poi.util.LittleEndianInputStream; | |||
import org.apache.poi.util.POILogFactory; | |||
@@ -110,7 +113,7 @@ public class HwmfPicture { | |||
} | |||
public void draw(Graphics2D ctx) { | |||
Dimension dim = getSize(); | |||
Dimension2D dim = getSize(); | |||
int width = Units.pointsToPixel(dim.getWidth()); | |||
// keep aspect ratio for height | |||
int height = Units.pointsToPixel(dim.getHeight()); | |||
@@ -119,52 +122,86 @@ public class HwmfPicture { | |||
} | |||
public void draw(Graphics2D ctx, Rectangle2D graphicsBounds) { | |||
AffineTransform at = ctx.getTransform(); | |||
final Shape clip = ctx.getClip(); | |||
final AffineTransform at = ctx.getTransform(); | |||
try { | |||
Rectangle2D wmfBounds = getBounds(); | |||
Rectangle2D innerBounds = getInnnerBounds(); | |||
if (innerBounds == null) { | |||
innerBounds = wmfBounds; | |||
} | |||
// scale output bounds to image bounds | |||
ctx.translate(graphicsBounds.getX(), graphicsBounds.getY()); | |||
ctx.scale(graphicsBounds.getWidth()/wmfBounds.getWidth(), graphicsBounds.getHeight()/wmfBounds.getHeight()); | |||
HwmfGraphics g = new HwmfGraphics(ctx, wmfBounds); | |||
ctx.translate(-wmfBounds.getX(), -wmfBounds.getY()); | |||
ctx.translate(innerBounds.getCenterX(), innerBounds.getCenterY()); | |||
ctx.scale(wmfBounds.getWidth()/innerBounds.getWidth(), wmfBounds.getHeight()/innerBounds.getHeight()); | |||
ctx.translate(-wmfBounds.getCenterX(), -wmfBounds.getCenterY()); | |||
HwmfGraphics g = new HwmfGraphics(ctx, innerBounds); | |||
HwmfDrawProperties prop = g.getProperties(); | |||
prop.setViewportOrg(innerBounds.getX(), innerBounds.getY()); | |||
prop.setViewportExt(innerBounds.getWidth(), innerBounds.getHeight()); | |||
int idx = 0; | |||
for (HwmfRecord r : records) { | |||
prop = g.getProperties(); | |||
Shape propClip = prop.getClip(); | |||
Shape ctxClip = ctx.getClip(); | |||
if (!Objects.equals(propClip, ctxClip)) { | |||
int a = 5; | |||
} | |||
r.draw(g); | |||
idx++; | |||
} | |||
} finally { | |||
ctx.setTransform(at); | |||
ctx.setClip(clip); | |||
} | |||
} | |||
/** | |||
* Returns the bounding box in device-independent units. Usually this is taken from the placeable header. | |||
* | |||
* | |||
* @return the bounding box | |||
* | |||
* @throws RuntimeException if neither WmfSetWindowOrg/Ext nor the placeableHeader are set | |||
*/ | |||
public Rectangle2D getBounds() { | |||
if (placeableHeader != null) { | |||
return placeableHeader.getBounds(); | |||
} else { | |||
WmfSetWindowOrg wOrg = null; | |||
WmfSetWindowExt wExt = null; | |||
for (HwmfRecord r : getRecords()) { | |||
if (wOrg != null && wExt != null) { | |||
break; | |||
} | |||
if (r instanceof WmfSetWindowOrg) { | |||
wOrg = (WmfSetWindowOrg)r; | |||
} else if (r instanceof WmfSetWindowExt) { | |||
wExt = (WmfSetWindowExt)r; | |||
} | |||
} | |||
if (wOrg == null || wExt == null) { | |||
throw new RuntimeException("invalid wmf file - window records are incomplete."); | |||
} | |||
Rectangle2D inner = getInnnerBounds(); | |||
if (inner != null) { | |||
return inner; | |||
} | |||
throw new RuntimeException("invalid wmf file - window records are incomplete."); | |||
} | |||
/** | |||
* Returns the bounding box in device-independent units taken from the WmfSetWindowOrg/Ext records | |||
* | |||
* @return the bounding box or null, if the WmfSetWindowOrg/Ext records aren't set | |||
*/ | |||
public Rectangle2D getInnnerBounds() { | |||
WmfSetWindowOrg wOrg = null; | |||
WmfSetWindowExt wExt = null; | |||
for (HwmfRecord r : getRecords()) { | |||
if (r instanceof WmfSetWindowOrg) { | |||
wOrg = (WmfSetWindowOrg)r; | |||
} else if (r instanceof WmfSetWindowExt) { | |||
wExt = (WmfSetWindowExt)r; | |||
} | |||
return new Rectangle2D.Double(wOrg.getX(), wOrg.getY(), wExt.getSize().getWidth(), wExt.getSize().getHeight()); | |||
} | |||
if (wOrg != null && wExt != null) { | |||
return new Rectangle2D.Double(wOrg.getX(), wOrg.getY(), wExt.getSize().getWidth(), wExt.getSize().getHeight()); | |||
} | |||
} | |||
return null; | |||
} | |||
public HwmfPlaceableHeader getPlaceableHeader() { | |||
return placeableHeader; | |||
} | |||
@@ -178,13 +215,13 @@ public class HwmfPicture { | |||
* | |||
* @return the image size in points | |||
*/ | |||
public Dimension getSize() { | |||
public Dimension2D getSize() { | |||
double inch = (placeableHeader == null) ? 1440 : placeableHeader.getUnitsPerInch(); | |||
Rectangle2D bounds = getBounds(); | |||
//coefficient to translate from WMF dpi to 72dpi | |||
double coeff = Units.POINT_DPI/inch; | |||
return new Dimension((int)Math.round(bounds.getWidth()*coeff), (int)Math.round(bounds.getHeight()*coeff)); | |||
return new Dimension2DDouble(bounds.getWidth()*coeff, bounds.getHeight()*coeff); | |||
} | |||
public Iterable<HwmfEmbedded> getEmbeddings() { |
@@ -20,16 +20,16 @@ package org.apache.poi.hwmf; | |||
import static org.apache.poi.POITestCase.assertContains; | |||
import static org.junit.Assert.assertEquals; | |||
import javax.imageio.ImageIO; | |||
import java.awt.Dimension; | |||
import java.awt.Graphics2D; | |||
import java.awt.RenderingHints; | |||
import java.awt.geom.Dimension2D; | |||
import java.awt.geom.Rectangle2D; | |||
import java.awt.image.BufferedImage; | |||
import java.io.File; | |||
import java.io.FileFilter; | |||
import java.io.FileInputStream; | |||
import java.io.FileOutputStream; | |||
import java.io.FileWriter; | |||
import java.io.FilterInputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
@@ -41,6 +41,8 @@ import java.util.Locale; | |||
import java.util.zip.ZipEntry; | |||
import java.util.zip.ZipInputStream; | |||
import javax.imageio.ImageIO; | |||
import org.apache.poi.POIDataSamples; | |||
import org.apache.poi.hwmf.record.HwmfFill.HwmfImageRecord; | |||
import org.apache.poi.hwmf.record.HwmfFont; | |||
@@ -84,22 +86,22 @@ public class TestHwmfParsing { | |||
@Ignore("This is work-in-progress and not a real unit test ...") | |||
public void paint() throws IOException { | |||
boolean dumpEmbedded = true; | |||
boolean dumpRecords = false; | |||
// File f = samples.getFile("santa.wmf"); | |||
File f = new File("testme.wmf"); | |||
File f = new File("testme.wmf"); | |||
FileInputStream fis = new FileInputStream(f); | |||
HwmfPicture wmf = new HwmfPicture(fis); | |||
fis.close(); | |||
Dimension dim = wmf.getSize(); | |||
int width = Units.pointsToPixel(dim.getWidth()); | |||
Dimension2D dim = wmf.getSize(); | |||
double width = Units.pointsToPixel(dim.getWidth()); | |||
// keep aspect ratio for height | |||
int height = Units.pointsToPixel(dim.getHeight()); | |||
double height = Units.pointsToPixel(dim.getHeight()); | |||
double scale = (width > height) ? 1500 / width : 1500 / width; | |||
width *= scale; | |||
height *= scale; | |||
width = Math.abs(width * scale); | |||
height = Math.abs(height * scale); | |||
BufferedImage bufImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); | |||
BufferedImage bufImg = new BufferedImage((int)width, (int)height, BufferedImage.TYPE_INT_ARGB); | |||
Graphics2D g = bufImg.createGraphics(); | |||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | |||
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); | |||
@@ -122,6 +124,17 @@ public class TestHwmfParsing { | |||
embIdx++; | |||
} | |||
} | |||
if (dumpRecords) { | |||
try (FileWriter fw = new FileWriter("wmf-records.log")) { | |||
for (HwmfRecord r : wmf.getRecords()) { | |||
fw.write(r.getWmfRecordType().name()); | |||
fw.write(":"); | |||
fw.write(r.toString()); | |||
fw.write("\n"); | |||
} | |||
} | |||
} | |||
} | |||
@Test | |||
@@ -198,7 +211,7 @@ public class TestHwmfParsing { | |||
} | |||
if (renderWmf) { | |||
Dimension dim = wmf.getSize(); | |||
Dimension2D dim = wmf.getSize(); | |||
int width = Units.pointsToPixel(dim.getWidth()); | |||
// keep aspect ratio for height | |||
int height = Units.pointsToPixel(dim.getHeight()); |