/* * Copyright (c) 2006 Wisconsin Court System and Patrick Wright * Copyright (c) 2007 Cay S. Horstmann * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package com.horstmann.slidy2png; import java.awt.*; import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.List; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xhtmlrenderer.context.AWTFontResolver; import org.xhtmlrenderer.css.style.CalculatedStyle; import org.xhtmlrenderer.extend.UserAgentCallback; import org.xhtmlrenderer.extend.UserInterface; import org.xhtmlrenderer.layout.BoxBuilder; import org.xhtmlrenderer.layout.Layer; import org.xhtmlrenderer.layout.LayoutContext; import org.xhtmlrenderer.layout.SharedContext; import org.xhtmlrenderer.render.BlockBox; import org.xhtmlrenderer.render.Box; import org.xhtmlrenderer.render.PageBox; import org.xhtmlrenderer.render.RenderingContext; import org.xhtmlrenderer.render.ViewportBox; import org.xhtmlrenderer.simple.extend.XhtmlNamespaceHandler; import org.xhtmlrenderer.swing.Java2DFontContext; import org.xhtmlrenderer.swing.Java2DOutputDevice; import org.xhtmlrenderer.swing.Java2DTextRenderer; import org.xhtmlrenderer.swing.NaiveUserAgent; import org.xhtmlrenderer.swing.SwingReplacedElementFactory; import org.xhtmlrenderer.util.FSImageWriter; import org.xhtmlrenderer.util.ImageUtil; public class MultiPageRenderer { private SharedContext sharedContext; private Java2DOutputDevice outputDevice; private Document doc; private Box root; public MultiPageRenderer(File file) throws IOException { String url = file.toURI().toURL().toExternalForm(); BufferedImage outputImage = ImageUtil.createCompatibleBufferedImage(1, 1); outputDevice = new Java2DOutputDevice(outputImage); UserAgentCallback userAgent = new NaiveUserAgent(); sharedContext = new SharedContext(userAgent); AWTFontResolver fontResolver = new AWTFontResolver(); sharedContext.setFontResolver(fontResolver); SwingReplacedElementFactory replacedElementFactory = new SwingReplacedElementFactory(); sharedContext.setReplacedElementFactory(replacedElementFactory); sharedContext.setTextRenderer(new Java2DTextRenderer()); sharedContext.setDPI(72); sharedContext.setDotsPerPixel(1); sharedContext.setPrint(true); sharedContext.setInteractive(false); doc = sharedContext.getUac().getXMLResource(url).getDocument(); sharedContext.setBaseURL(url); sharedContext.setNamespaceHandler(new XhtmlNamespaceHandler()); sharedContext.getCss().setDocumentContext(sharedContext, sharedContext.getNamespaceHandler(), doc, new NullUserInterface()); } public void renderImages(String outputPath, String extension) throws IOException { layout(); RenderingContext rc = sharedContext.newRenderingContextInstance(); root.getLayer().assignPagePaintingPositions(rc, Layer.PAGED_MODE_PRINT); List pages = root.getLayer().getPages(); PageBox first = Layer.createPageBox(rc, null); int width = first.getWidth(rc); int height = first.getHeight(rc); BufferedImage outputImage = ImageUtil.createCompatibleBufferedImage( width, height, BufferedImage.TYPE_INT_RGB); FSImageWriter fsw = new FSImageWriter(); for (int i = 0; i < pages.size(); i++) { outputDevice = new Java2DOutputDevice(outputImage); Graphics2D newG = (Graphics2D) outputImage.getGraphics(); newG.getRenderingHints().put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); rc.setFontContext(new Java2DFontContext(newG)); rc.setOutputDevice(outputDevice); sharedContext.getTextRenderer().setup(rc.getFontContext()); sharedContext.getTextRenderer().setSmoothingThreshold(8); PageBox page = (PageBox) pages.get(i); rc.setPage(i, page); ImageUtil.clearImage(outputImage); paintPage(rc, page); newG.dispose(); String num = "000" + (i + 1); num = num.substring(num.length() - 3); String name = outputPath + num + extension; System.out.println(name); OutputStream os = new BufferedOutputStream(new FileOutputStream( name)); ; try { fsw.write(outputImage, os); } finally { os.close(); } outputImage.flush(); } } private void layout() { LayoutContext result = sharedContext.newLayoutContextInstance(); Graphics2D g = outputDevice.getGraphics(); result.setFontContext(new Java2DFontContext(g)); sharedContext.getTextRenderer().setup(result.getFontContext()); LayoutContext c = result; BlockBox root = BoxBuilder.createRootBox(c, doc); PageBox first = Layer.createPageBox(c, null); Rectangle rect = new Rectangle(0, 0, first.getContentWidth(c), first .getContentHeight(c)); root.setContainingBlock(new ViewportBox(rect)); root.layout(c); Dimension dim = root.getLayer().getPaintingDimension(c); root.getLayer().trimEmptyPages(c, dim.height); this.root = root; } private void paintPage(RenderingContext c, PageBox page) { Shape working = outputDevice.getClip(); Rectangle content = page.getPrintingClippingBounds(c); outputDevice.clip(content); int top = -page.getPaintingTop() + page.getMarginBorderPadding(c, CalculatedStyle.TOP); int left = page.getMarginBorderPadding(c, CalculatedStyle.LEFT); outputDevice.translate(left, top); root.getLayer().paint(c, 0, 0); outputDevice.translate(-left, -top); outputDevice.setClip(working); page.paintAlternateFlows(c, root.getLayer(), Layer.PAGED_MODE_PRINT, 0); page.paintBorder(c, 0, Layer.PAGED_MODE_PRINT); outputDevice.setClip(working); } private static final class NullUserInterface implements UserInterface { public boolean isHover(Element e) { return false; } public boolean isActive(Element e) { return false; } public boolean isFocus(Element e) { return false; } } public static void main(String[] args) throws IOException { if (args.length != 1) { System.err.println("Usage: ... slidyfile"); } File f = new File(args[0]); if (f.exists()) { String outputPath = f.getAbsolutePath(); outputPath = outputPath.substring(0, outputPath.lastIndexOf(".")); new MultiPageRenderer(f).renderImages(outputPath, ".png"); } else System.err.println("File not found: " + args[0]); } }