/* * Copyright 2001-2015 Aspose Pty Ltd. All Rights Reserved. * * This file is part of Aspose.Words. The source code in this file * is only intended as a supplement to the documentation, and is provided * "as is", without warranty of any kind, either expressed or implied. */ package com.aspose.words.examples.rendering_printing; import com.aspose.words.*; import com.aspose.words.Shape; import com.aspose.words.examples.Utils; import javax.imageio.ImageIO; import java.awt.*; import java.awt.geom.Point2D; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; public class RenderShapes { public static void main(String[] args) throws Exception { // The path to the documents directory. String dataDir = Utils.getDataDir(RenderShapes.class); // Load the documents which store the shapes we want to render. Document doc = new Document(dataDir + "TestFile.doc"); Document doc2 = new Document(dataDir + "TestFile.docx"); // Retrieve the target shape from the document. In our sample document this is the first shape. Shape shape = (Shape)doc.getChild(NodeType.SHAPE, 0, true); Shape drawingML = (Shape)doc2.getChild(NodeType.SHAPE, 0, true); // Test rendering of different types of nodes. RenderShapeToDisk(dataDir, shape); RenderShapeToStream(dataDir, shape); RenderShapeToGraphics(dataDir, shape); RenderDrawingMLToDisk(dataDir, drawingML); RenderCellToImage(dataDir, doc); RenderRowToImage(dataDir, doc); RenderParagraphToImage(dataDir, doc); FindShapeSizes(shape); } public static void RenderShapeToDisk(String dataDir, Shape shape) throws Exception { ShapeRenderer r = shape.getShapeRenderer(); // Define custom options which control how the image is rendered. Render the shape to the JPEG raster format. ImageSaveOptions imageOptions = new ImageSaveOptions(SaveFormat.JPEG); imageOptions.setScale(1.5f); // Save the rendered image to disk. r.save(dataDir + "TestFile.RenderToDisk Out.jpg", imageOptions); System.out.println("Shape rendered to disk successfully."); } public static void RenderShapeToStream(String dataDir, Shape shape) throws Exception { ShapeRenderer r = new ShapeRenderer(shape); // Define custom options which control how the image is rendered. Render the shape to the vector format EMF. ImageSaveOptions imageOptions = new ImageSaveOptions(SaveFormat.PNG) { }; // Output the image in gray scale imageOptions.setImageColorMode(ImageColorMode.GRAYSCALE); // Reduce the brightness a bit (default is 0.5f). imageOptions.setImageBrightness(0.45f); FileOutputStream stream = new FileOutputStream(dataDir + "TestFile.RenderToStream Out.jpg"); // Save the rendered image to the stream using different options. r.save(stream, imageOptions); System.out.println("Shape rendered to stream successfully."); } public static void RenderDrawingMLToDisk(String dataDir, Shape drawingML) throws Exception { // Save the DrawingML image to disk in JPEG format and using default options. drawingML.getShapeRenderer().save(dataDir + "TestFile.RenderDrawingML Out.jpg", null); System.out.println("Shape rendered to disk successfully."); } public static void RenderShapeToGraphics(String dataDir, Shape shape) throws Exception { // The shape renderer is retrieved using this method. This is made into a separate object from the shape as it internally // caches the rendered shape. ShapeRenderer r = shape.getShapeRenderer(); // Find the size that the shape will be rendered to at the specified scale and resolution. Dimension shapeSizeInPixels = r.getSizeInPixels(1.0f, 96.0f); // Rotating the shape may result in clipping as the image canvas is too small. Find the longest side // and make sure that the graphics canvas is large enough to compensate for this. int maxSide = Math.max(shapeSizeInPixels.width, shapeSizeInPixels.height); BufferedImage image = new BufferedImage((int) (maxSide * 1.25), (int) (maxSide * 1.25), BufferedImage.TYPE_INT_ARGB); // Rendering to a graphics object means we can specify settings and transformations to be applied to // the shape that is rendered. In our case we will rotate the rendered shape. Graphics2D gr = (Graphics2D)image.getGraphics(); // Clear the shape with the background color of the document. gr.setBackground(shape.getDocument().getPageColor()); gr.clearRect(0, 0, image.getWidth(), image.getHeight()); // Center the rotation using translation method below gr.translate(image.getWidth() / 8, image.getHeight() / 2); // Rotate the image by 45 degrees. gr.rotate(45 * Math.PI / 180); // Undo the translation. gr.translate(-image.getWidth() / 8, -image.getHeight() / 2); // Render the shape onto the graphics object. r.renderToSize(gr, 0, 0, shapeSizeInPixels.width, shapeSizeInPixels.height); ImageIO.write(image, "png", new File(dataDir + "TestFile.RenderToGraphics.png")); gr.dispose(); System.out.println("Shape rendered to Graphics successfully."); } public static void RenderCellToImage(String dataDir, Document doc) throws Exception { Cell cell = (Cell)doc.getChild(NodeType.CELL, 2, true); // The third cell in the first table. RenderNode(cell, dataDir + "TestFile.RenderCell Out.png", null); System.out.println("Cell rendered to image successfully."); } public static void RenderRowToImage(String dataDir, Document doc) throws Exception { Row row = (Row)doc.getChild(NodeType.ROW, 0, true); // The first row in the first table. RenderNode(row, dataDir + "TestFile.RenderRow Out.png", null); System.out.println("Row rendered to image successfully."); } public static void RenderParagraphToImage(String dataDir, Document doc) throws Exception { Shape shape = (Shape)doc.getChild(NodeType.SHAPE, 0, true); Paragraph paragraph = shape.getLastParagraph(); // Save the node with a light pink background. ImageSaveOptions options = new ImageSaveOptions(SaveFormat.PNG); options.setPaperColor(new Color(255, 182, 193)); RenderNode(paragraph, dataDir + "TestFile.RenderParagraph Out.png", options); System.out.println("Paragraph rendered to image successfully."); } public static void FindShapeSizes(Shape shape) throws Exception { Point2D.Float shapeSizeInDocument = shape.getShapeRenderer().getSizeInPoints(); float width = shapeSizeInDocument.x; // The width of the shape. float height = shapeSizeInDocument.y; // The height of the shape. Dimension shapeRenderedSize = shape.getShapeRenderer().getSizeInPixels(1.0f, 96.0f); BufferedImage image = new BufferedImage(shapeRenderedSize.width, shapeRenderedSize.height, BufferedImage.TYPE_INT_RGB); Graphics gr = image.getGraphics(); // Render shape onto the graphics object using the RenderToScale or RenderToSize methods of ShapeRenderer class. gr.dispose(); } /// <summary> /// Renders any node in a document to the path specified using the image save options. /// </summary> /// <param name="node">The node to render.</param> /// <param name="path">The path to save the rendered image to.</param> /// <param name="imageOptions">The image options to use during rendering. This can be null.</param> public static void RenderNode(Node node, String filePath, ImageSaveOptions imageOptions) throws Exception { // Run some argument checks. if (node == null) throw new IllegalArgumentException("Node cannot be null"); // If no image options are supplied, create default options. if (imageOptions == null) imageOptions = new ImageSaveOptions(FileFormatUtil.extensionToSaveFormat((filePath.split("\\.")[filePath.split("\\.").length - 1]))); // Store the paper color to be used on the final image and change to transparent. // This will cause any content around the rendered node to be removed later on. Color savePaperColor = imageOptions.getPaperColor(); //imageOptions.PaperColor = Color.Transparent; imageOptions.setPaperColor(new Color(0, 0, 0, 0)); // There a bug which affects the cache of a cloned node. To avoid this we instead clone the entire document including all nodes, // find the matching node in the cloned document and render that instead. Document doc = (Document)node.getDocument().deepClone(true); node = doc.getChild(NodeType.ANY, node.getDocument().getChildNodes(NodeType.ANY, true).indexOf(node), true); // Create a temporary shape to store the target node in. This shape will be rendered to retrieve // the rendered content of the node. Shape shape = new Shape(doc, ShapeType.TEXT_BOX); Section parentSection = (Section)node.getAncestor(NodeType.SECTION); // Assume that the node cannot be larger than the page in size. shape.setWidth(parentSection.getPageSetup().getPageWidth()); shape.setHeight(parentSection.getPageSetup().getPageHeight()); shape.setFillColor(new Color(0, 0, 0, 0)); // We must make the shape and paper color transparent. // Don't draw a surrounding line on the shape. shape.setStroked(false); // Move up through the DOM until we find node which is suitable to insert into a Shape (a node with a parent can contain paragraph, tables the same as a shape). // Each parent node is cloned on the way up so even a descendant node passed to this method can be rendered. // Since we are working with the actual nodes of the document we need to clone the target node into the temporary shape. Node currentNode = node; while (!(currentNode.getParentNode() instanceof InlineStory || currentNode.getParentNode() instanceof Story || currentNode.getParentNode() instanceof ShapeBase)) { CompositeNode parent = (CompositeNode)currentNode.getParentNode().deepClone(false); currentNode = currentNode.getParentNode(); parent.appendChild(node.deepClone(true)); node = parent; // Store this new node to be inserted into the shape. } // We must add the shape to the document tree to have it rendered. shape.appendChild(node.deepClone(true)); parentSection.getBody().getFirstParagraph().appendChild(shape); // Render the shape to stream so we can take advantage of the effects of the ImageSaveOptions class. // Retrieve the rendered image and remove the shape from the document. ByteArrayOutputStream stream = new ByteArrayOutputStream(); shape.getShapeRenderer().save(stream, imageOptions); shape.remove(); // Load the image into a new bitmap. BufferedImage renderedImage = ImageIO.read(new ByteArrayInputStream(stream.toByteArray())); // Extract the actual content of the image by cropping transparent space around // the rendered shape. Rectangle cropRectangle = FindBoundingBoxAroundNode(renderedImage); BufferedImage croppedImage = new BufferedImage(cropRectangle.width, cropRectangle.height, BufferedImage.TYPE_INT_RGB); // Create the final image with the proper background color. Graphics2D g = croppedImage.createGraphics(); g.setBackground(savePaperColor); g.clearRect(0, 0, croppedImage.getWidth(), croppedImage.getHeight()); g.drawImage(renderedImage, 0, 0, croppedImage.getWidth(), croppedImage.getHeight(), cropRectangle.x, cropRectangle.y, cropRectangle.x + cropRectangle.width, cropRectangle.y + cropRectangle.height, null); ImageIO.write(croppedImage, "png", new File(filePath)); } /// <summary> /// Finds the minimum bounding box around non-transparent pixels in a Bitmap. /// </summary> public static Rectangle FindBoundingBoxAroundNode(BufferedImage originalBitmap) { Point min = new Point(Integer.MAX_VALUE, Integer.MAX_VALUE); Point max = new Point(Integer.MIN_VALUE, Integer.MIN_VALUE); for (int x = 0; x < originalBitmap.getWidth(); ++x) { for (int y = 0; y < originalBitmap.getHeight(); ++y) { // For each pixel that is not transparent calculate the bounding box around it. if (originalBitmap.getRGB(x, y) != 0) { min.x = Math.min(x, min.x); min.y = Math.min(y, min.y); max.x = Math.max(x, max.x); max.y = Math.max(y, max.y); } } } // Add one pixel to the width and height to avoid clipping. return new Rectangle(min.x, min.y, (max.x - min.x) + 1, (max.y - min.y) + 1); } }