/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed 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.
*/
/* $Id$ */
package org.apache.fop.render.awt;
/*
* originally contributed by
* Juergen Verwohlt: Juergen.Verwohlt@jCatalog.com,
* Rainer Steinkuhle: Rainer.Steinkuhle@jCatalog.com,
* Stanislav Gorkhover: Stanislav.Gorkhover@jCatalog.com
*/
// Java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Pageable;
import java.awt.print.Printable;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.Vector;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.InputHandler;
import org.apache.fop.area.Area;
import org.apache.fop.area.Page;
import org.apache.fop.area.PageViewport;
import org.apache.fop.area.RegionViewport;
import org.apache.fop.area.Trait;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.datatypes.ColorType;
import org.apache.fop.fo.FOTreeControl;
import org.apache.fop.image.FopImage;
import org.apache.fop.image.ImageFactory;
import org.apache.fop.render.AbstractRenderer;
import org.apache.fop.traits.BorderProps;
import org.apache.fop.render.awt.FontMetricsMapper;
import org.apache.fop.render.awt.viewer.PreviewDialog;
import org.apache.fop.render.awt.viewer.Translator;
/**
* This is FOP's AWT renderer.
*/
public class AWTRenderer extends AbstractRenderer implements Printable, Pageable {
protected double scaleFactor = 100.0;
protected int pageNumber = 0;
private int pageWidth = 0;
private int pageHeight = 0;
private Vector pageViewportList = new java.util.Vector();
private Vector pageList = new java.util.Vector();
private Vector bufferedImageList = new java.util.Vector();
private BufferedImage currentPageImage = null;
/** Font configuration */
protected FontInfo fontInfo;
/**
The InputHandler associated with this Renderer.
Sent to the PreviewDialog for document reloading.
*/
private InputHandler inputHandler;
/**
* The resource bundle used for AWT messages.
*/
protected Translator translator = null;
private Map fontNames = new java.util.Hashtable();
private Map fontStyles = new java.util.Hashtable();
private Color saveColor = null;
/**
* The preview dialog frame used for display of the documents.
* Also used as the AWT Component for FontSetup in generating
* valid font measures.
*/
protected PreviewDialog frame;
public AWTRenderer(InputHandler handler) {
inputHandler = handler;
translator = new Translator();
createPreviewDialog(inputHandler);
}
public AWTRenderer() {
translator = new Translator();
createPreviewDialog(null);
}
/**
* @see org.apache.fop.render.Renderer
*/
public boolean supportsOutOfOrder() {
return false;
}
public Translator getTranslator() {
return translator;
}
public void setupFontInfo(FontInfo inFontInfo) {
// create a temp Image to test font metrics on
fontInfo = inFontInfo;
BufferedImage fontImage =
new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
FontSetup.setup(fontInfo, fontImage.createGraphics());
}
public int getPageNumber() {
return pageNumber;
}
public void setPageNumber(int aValue) {
pageNumber = aValue;
}
public void setScaleFactor(double newScaleFactor) {
scaleFactor = newScaleFactor;
}
public double getScaleFactor() {
return scaleFactor;
}
public void startRenderer(OutputStream out)
throws IOException {
// empty pageViewportList, in case of a reload from PreviewDialog
pageViewportList.removeAllElements();
pageList.removeAllElements();
bufferedImageList.removeAllElements();
System.out.println("\nRegion Types: 0-Before/Top, 1-Start/Left, 2-Body, 3-End/Right, 4-After/Bottom");
}
public void stopRenderer()
throws IOException {
frame.setStatus(translator.getString("Status.Show"));
frame.showPage();
}
// Printable Interface
public PageFormat getPageFormat(int pos) {
return null;
}
public Printable getPrintable(int pos) {
return null;
}
public int getNumberOfPages() {
return pageViewportList.size();
}
public int print(Graphics g, PageFormat format, int pos) {
return 0;
}
private PreviewDialog createPreviewDialog(InputHandler handler) {
frame = new PreviewDialog(this, handler);
frame.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent we) {
System.exit(0);
}
});
//Centers the window
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = frame.getSize();
if (frameSize.height > screenSize.height) {
frameSize.height = screenSize.height;
}
if (frameSize.width > screenSize.width) {
frameSize.width = screenSize.width;
}
frame.setLocation((screenSize.width - frameSize.width) / 2,
(screenSize.height - frameSize.height) / 2);
frame.setVisible(true);
frame.setStatus(translator.getString("Status.Build.FO.tree"));
return frame;
}
/** This method override only stores the PageViewport in a vector.
* No actual rendering performed -- this is done by getPageImage(pageNum) instead.
* @param pageViewport the PageViewport
object supplied by the Area Tree
* @see org.apache.fop.render.Renderer
*/
public void renderPage(PageViewport pageViewport) throws IOException, FOPException {
pageViewportList.add(pageViewport);
pageList.add(pageViewport.getPage().clone());
bufferedImageList.add(getPageImage(pageViewport));
}
public BufferedImage getBufferedPageImage(int pageNum) throws FOPException {
return (BufferedImage) bufferedImageList.get(pageNum);
}
/** Generates a desired page from the renderer's page viewport vector.
* @param pageNum the 0-based page number to generate
* @return the java.awt.image.BufferedImage
corresponding to the page
* @throws FOPException in case of an out-of-range page number requested
*/
public BufferedImage getPageImage(PageViewport pageViewport) throws FOPException {
Page page = pageViewport.getPage();
Rectangle2D bounds = pageViewport.getViewArea();
pageWidth = (int) Math.round(bounds.getWidth() / 1000f );
pageHeight = (int) Math.round(bounds.getHeight() / 1000f );
/*
System.out.println("(Page) X, Y, Width, Height: " + bounds.getX()
+ " " + bounds.getY()
+ " " + bounds.getWidth()
+ " " + bounds.getHeight());
*/
currentPageImage =
new BufferedImage((int)((pageWidth * (int)scaleFactor) / 100),
(int)((pageHeight * (int)scaleFactor) / 100),
BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = currentPageImage.createGraphics();
graphics.setRenderingHint (RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
// transform page based on scale factor supplied
AffineTransform at = graphics.getTransform();
at.scale(scaleFactor / 100.0, scaleFactor / 100.0);
graphics.setTransform(at);
// draw page frame
graphics.setColor(Color.white);
graphics.fillRect(0, 0, pageWidth, pageHeight);
graphics.setColor(Color.black);
graphics.drawRect(-1, -1, pageWidth + 2, pageHeight + 2);
graphics.drawLine(pageWidth + 2, 0, pageWidth + 2, pageHeight + 2);
graphics.drawLine(pageWidth + 3, 1, pageWidth + 3, pageHeight + 3);
graphics.drawLine(0, pageHeight + 2, pageWidth + 2, pageHeight + 2);
graphics.drawLine(1, pageHeight + 3, pageWidth + 3, pageHeight + 3);
renderPageAreas(page);
return currentPageImage;
}
/** Generates a desired page from the renderer's page viewport vector.
* @param pageNum the 0-based page number to generate
* @return the java.awt.image.BufferedImage
corresponding to the page
* @throws FOPException in case of an out-of-range page number requested
*/
public BufferedImage getPageImage(int pageNum) throws FOPException {
if (pageNum < 0 || pageNum >= pageViewportList.size()) {
throw new FOPException("out-of-range page number (" + pageNum
+ ") requested; only " + pageViewportList.size()
+ " page(s) available.");
}
PageViewport pageViewport = (PageViewport) pageViewportList.get(pageNum);
Page page = (Page) pageList.get(pageNum);
Rectangle2D bounds = pageViewport.getViewArea();
pageWidth = (int) Math.round(bounds.getWidth() / 1000f );
pageHeight = (int) Math.round(bounds.getHeight() / 1000f );
/*
System.out.println("(Page) X, Y, Width, Height: " + bounds.getX()
+ " " + bounds.getY()
+ " " + bounds.getWidth()
+ " " + bounds.getHeight());
*/
currentPageImage =
new BufferedImage((int)((pageWidth * (int)scaleFactor) / 100),
(int)((pageHeight * (int)scaleFactor) / 100),
BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = currentPageImage.createGraphics();
graphics.setRenderingHint (RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
// transform page based on scale factor supplied
AffineTransform at = graphics.getTransform();
at.scale(scaleFactor / 100.0, scaleFactor / 100.0);
graphics.setTransform(at);
// draw page frame
graphics.setColor(Color.white);
graphics.fillRect(0, 0, pageWidth, pageHeight);
graphics.setColor(Color.black);
graphics.drawRect(-1, -1, pageWidth + 2, pageHeight + 2);
graphics.drawLine(pageWidth + 2, 0, pageWidth + 2, pageHeight + 2);
graphics.drawLine(pageWidth + 3, 1, pageWidth + 3, pageHeight + 3);
graphics.drawLine(0, pageHeight + 2, pageWidth + 2, pageHeight + 2);
graphics.drawLine(1, pageHeight + 3, pageWidth + 3, pageHeight + 3);
renderPageAreas(page);
return currentPageImage;
}
/**
* Handle the traits for a region
* This is used to draw the traits for the given page region.
* (See Sect. 6.4.1.2 of XSL-FO spec.)
* @param region the RegionViewport whose region is to be drawn
*/
protected void handleRegionTraits(RegionViewport region) {
Rectangle2D viewArea = region.getViewArea();
int startX = (int) Math.round((viewArea.getX() / 1000f)
* (scaleFactor / 100f));
int startY = (int) Math.round((viewArea.getY() / 1000f)
* (scaleFactor / 100f));
// for rounding to work correctly, need to take into account
// fractional portion of X and Y.
int width = (int) Math.round(((viewArea.getX() + viewArea.getWidth()) / 1000f)
* (scaleFactor / 100f)) - startX;
int height = (int) Math.round(((viewArea.getY() + viewArea.getHeight()) / 1000f)
* (scaleFactor / 100f)) - startY;
if (region.getRegion() != null) {
System.out.print("\nRegion type = " + region.getRegion().getRegionClass());
}
System.out.println(" X, Width, Y, Height: " + startX
+ " " + width
+ " " + startY
+ " " + height
);
drawBackAndBorders(region, startX, startY, width, height);
}
/**
* Draw the background and borders.
* This draws the background and border traits for an area given
* the position.
*
* @param block the area to get the traits from
* @param startx the start x position
* @param starty the start y position
* @param width the width of the area
* @param height the height of the area
*/
protected void drawBackAndBorders(Area block,
int startx, int starty,
int width, int height) {
// draw background then border
Graphics2D graphics = currentPageImage.createGraphics();
Trait.Background back;
back = (Trait.Background) block.getTrait(Trait.BACKGROUND);
if (back != null) {
if (back.getColor() != null) {
graphics.setColor(back.getColor().getAWTColor());
graphics.fillRect(startx, starty, width, height);
}
if (back.getURL() != null) { // TODO: implement
ImageFactory fact = ImageFactory.getInstance();
FopImage fopimage = fact.getImage(back.getURL(), userAgent);
if (fopimage != null && fopimage.load(FopImage.DIMENSIONS, userAgent.getLogger())) {
if (back.getRepeat() == BackgroundRepeat.REPEAT) {
// create a pattern for the image
} else {
// place once
Rectangle2D pos;
pos = new Rectangle2D.Float((startx + back.getHoriz()) * 1000,
(starty + back.getVertical()) * 1000,
fopimage.getWidth() * 1000,
fopimage.getHeight() * 1000);
// putImage(back.getURL(), pos);
}
}
}
}
BorderProps bps = (BorderProps) block.getTrait(Trait.BORDER_BEFORE);
if (bps != null) {
int borderWidth = (int) Math.round((bps.width / 1000f) * (scaleFactor / 100f));
graphics.setColor(bps.color.getAWTColor());
graphics.fillRect(startx, starty, width, borderWidth);
}
bps = (BorderProps) block.getTrait(Trait.BORDER_AFTER);
if (bps != null) {
int borderWidth = (int) Math.round((bps.width / 1000f) * (scaleFactor / 100f));
int sy = starty + height;
graphics.setColor(bps.color.getAWTColor());
graphics.fillRect(startx, starty + height - borderWidth,
width, borderWidth);
}
bps = (BorderProps) block.getTrait(Trait.BORDER_START);
if (bps != null) {
int borderWidth = (int) Math.round((bps.width / 1000f) * (scaleFactor / 100f));
graphics.setColor(bps.color.getAWTColor());
graphics.fillRect(startx, starty, borderWidth, height);
}
bps = (BorderProps) block.getTrait(Trait.BORDER_END);
if (bps != null) {
int borderWidth = (int) Math.round((bps.width / 1000f) * (scaleFactor / 100f));
int sx = startx + width;
graphics.setColor(bps.color.getAWTColor());
graphics.fillRect(startx + width - borderWidth, starty,
borderWidth, height);
}
}
/**
* @see org.apache.fop.render.Renderer#renderText(TextArea)
*/
public void renderText(TextArea text) {
System.out.println("In render text: " + text.getTextArea());
Graphics2D graphics = currentPageImage.createGraphics();
String fontName = (String) text.getTrait(Trait.FONT_NAME);
int size = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue();
// Typeface f = (Typeface) fontInfo.getFonts().get(fontName);
ColorType ct = (ColorType) text.getTrait(Trait.COLOR);
FontMetricsMapper mapper = (FontMetricsMapper)
fontInfo.getMetricsFor(fontName);
if (mapper == null) {
mapper = new FontMetricsMapper("MonoSpaced", java.awt.Font.PLAIN,
graphics);
}
// graphics.setColor(ct.getAWTColor());
// graphics.setFont(mapper.getFont(size));
graphics.setColor(java.awt.Color.black);
graphics.setFont(new java.awt.Font("monospaced", java.awt.Font.PLAIN,
10));
int rx = currentBlockIPPosition;
int bl = currentBPPosition + text.getOffset();
int newx = (int) (rx + 500) / 1000;
int newy = (int) (pageHeight - (bl + 500) / 1000);
String s = text.getTextArea();
// graphics.drawString(s, newx, newy);
graphics.drawString(s, 220, 200);
// TODO: render text decorations
currentBlockIPPosition += text.getWidth();
}
}