Browse Source

Java2D Renderer:

Symbol and ZapfDingbats now work due to a little change in FontSetup.java
Made the class a subclass of AbstractPathOrientedRenderer. This enables to remove some redundant code.
Border painting on a Graphics2D is now available to other renderers.

PCL Renderer:
Improved Graphics2D implementation.
PCLGraphic2D throws an UnsupportedOperationException if it encounters a feature it cannot properly handle. The Graphics2DAdapter can then fall back to painting a graphic in-memory and then as a bitmap.
Added border painting.
PCLRenderer supports to modes "quality" and "speed". The user can configure the mode depending on his needs. In "speed" mode borders are painted as shaded rectangles only. In "quality" mode it uses border rendering of the Java2DRenderer.




git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@398945 13f79535-47bb-0310-9956-ffa450edef68
pull/25/head
Jeremias Maerki 18 years ago
parent
commit
970141d853

+ 19
- 33
src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java View File

@@ -1,5 +1,5 @@
/*
* Copyright 2005 The Apache Software Foundation.
* Copyright 2005-2006 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.
@@ -18,7 +18,6 @@

package org.apache.fop.render;

import java.awt.Color;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.util.List;
@@ -30,9 +29,6 @@ import org.apache.fop.area.CTM;
import org.apache.fop.area.RegionViewport;
import org.apache.fop.area.Trait;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.InlineBlockParent;
import org.apache.fop.area.inline.InlineParent;
import org.apache.fop.area.inline.Space;
import org.apache.fop.area.inline.Viewport;
import org.apache.fop.datatypes.ColorType;
import org.apache.fop.fo.Constants;
@@ -46,15 +42,6 @@ import org.apache.fop.traits.BorderProps;
*/
public abstract class AbstractPathOrientedRenderer extends PrintRenderer {

/**
* Converts a ColorType to a java.awt.Color (sRGB).
* @param col the color
* @return the converted color
*/
protected Color toColor(ColorType col) {
return new Color(col.getRed(), col.getGreen(), col.getBlue());
}
/**
* Handle block traits.
* The block could be any sort of block with any positioning
@@ -208,6 +195,24 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer {
}
}

Rectangle2D.Float borderRect = new Rectangle2D.Float(startx, starty, width, height);
drawBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
}

/**
* Draws borders.
* @param borderRect the border rectangle
* @param bpsBefore the border specification on the before side
* @param bpsAfter the border specification on the after side
* @param bpsStart the border specification on the start side
* @param bpsEnd the border specification on the end side
*/
protected void drawBorders(Rectangle2D.Float borderRect,
BorderProps bpsBefore, BorderProps bpsAfter, BorderProps bpsStart, BorderProps bpsEnd) {
float startx = borderRect.x;
float starty = borderRect.y;
float width = borderRect.width;
float height = borderRect.height;
boolean[] b = new boolean[] {
(bpsBefore != null), (bpsEnd != null),
(bpsAfter != null), (bpsStart != null)};
@@ -394,25 +399,6 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer {
}
/** @see org.apache.fop.render.AbstractRenderer#renderInlineSpace(Space) */
protected void renderInlineSpace(Space space) {
space.setBPD(0);
renderInlineAreaBackAndBorders(space);
super.renderInlineSpace(space);
}
/** @see org.apache.fop.render.AbstractRenderer#renderInlineParent(InlineParent) */
protected void renderInlineParent(InlineParent ip) {
renderInlineAreaBackAndBorders(ip);
super.renderInlineParent(ip);
}

/** @see org.apache.fop.render.AbstractRenderer */
protected void renderInlineBlockParent(InlineBlockParent ibp) {
renderInlineAreaBackAndBorders(ibp);
super.renderInlineBlockParent(ibp);
}
/**
* @see org.apache.fop.render.AbstractRenderer#renderBlockViewport(BlockViewport, List)
*/

+ 23
- 0
src/java/org/apache/fop/render/AbstractRenderer.java View File

@@ -19,6 +19,7 @@
package org.apache.fop.render;

// Java
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
@@ -63,6 +64,7 @@ import org.apache.fop.area.inline.TextArea;
import org.apache.fop.area.inline.WordArea;
import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.datatypes.ColorType;
import org.apache.fop.fo.Constants;
import org.apache.fop.fonts.FontInfo;
import org.apache.commons.logging.Log;
@@ -646,11 +648,21 @@ public abstract class AbstractRenderer
currentIPPosition += ch.getAllocIPD();
}

/**
* Common method to render the background and borders for any inline area.
* The all borders and padding are drawn outside the specified area.
* @param area the inline area for which the background, border and padding is to be
* rendered
*/
protected abstract void renderInlineAreaBackAndBorders(InlineArea area);
/**
* Render the given Space.
* @param space the space to render
*/
protected void renderInlineSpace(Space space) {
space.setBPD(0);
renderInlineAreaBackAndBorders(space);
// an inline space moves the inline progression position
// for the current block by the width or height of the space
// it may also have styling (only on this object) that needs
@@ -701,6 +713,7 @@ public abstract class AbstractRenderer
* @param ip the inline parent to render
*/
protected void renderInlineParent(InlineParent ip) {
renderInlineAreaBackAndBorders(ip);
int saveIP = currentIPPosition;
int saveBP = currentBPPosition;
currentIPPosition += ip.getBorderAndPaddingWidthStart();
@@ -718,6 +731,7 @@ public abstract class AbstractRenderer
* @param ibp the inline block parent to render
*/
protected void renderInlineBlockParent(InlineBlockParent ibp) {
renderInlineAreaBackAndBorders(ibp);
currentIPPosition += ibp.getBorderAndPaddingWidthStart();
// For inline content the BP position is updated by the enclosing line area
int saveBP = currentBPPosition;
@@ -867,5 +881,14 @@ public abstract class AbstractRenderer
public String getMimeType() {
return null;
}

/**
* Converts a ColorType to a java.awt.Color (sRGB).
* @param col the color
* @return the converted color
*/
protected Color toColor(ColorType col) {
return new Color(col.getRed(), col.getGreen(), col.getBlue());
}
}


+ 1
- 1
src/java/org/apache/fop/render/PrintRenderer.java View File

@@ -79,7 +79,7 @@ public abstract class PrintRenderer extends AbstractRenderer {
* @param factor factor by which to lighten up (negative values darken the color)
* @return the modified color
*/
protected Color lightenColor(Color col, float factor) {
public static Color lightenColor(Color col, float factor) {
float[] cols = new float[3];
cols = col.getColorComponents(cols);
if (factor > 0) {

+ 6
- 4
src/java/org/apache/fop/render/awt/AWTRenderer.java View File

@@ -113,9 +113,10 @@ public class AWTRenderer extends Java2DRenderer implements Pageable {
dialogDisplay = show;
}

/** @see org.apache.fop.render.Renderer#renderPage(org.apache.fop.area.PageViewport) */
public void renderPage(PageViewport pageViewport)
throws IOException, FOPException {
/**
* @see org.apache.fop.render.Renderer#renderPage(org.apache.fop.area.PageViewport)
*/
public void renderPage(PageViewport pageViewport) throws IOException {

super.renderPage(pageViewport);
if (frame != null) {
@@ -263,7 +264,7 @@ public class AWTRenderer extends Java2DRenderer implements Pageable {
state.push();

ColorType ct = new ColorTypeProperty(0.7f, 0.7f, 0.7f);
state.updateColor(ct, true, null);
state.updateColor(ct);
state.updateStroke(0.4f, EN_SOLID);
state.getGraph().draw(
new Rectangle2D.Float(startx, starty, width, height));
@@ -271,4 +272,5 @@ public class AWTRenderer extends Java2DRenderer implements Pageable {
// restores the last graphics state from the stack
state.pop();
}

}

+ 1
- 1
src/java/org/apache/fop/render/awt/viewer/PreviewPanel.java View File

@@ -290,7 +290,7 @@ public class PreviewPanel extends JPanel {
private class Reloader extends Thread {

public void run() {
if (!renderer.renderingDone) {
if (!renderer.isRenderingDone()) {
// do not allow the reloading while FOP is still rendering
JOptionPane.showMessageDialog(previewArea,
"Cannot perform the requested operation until "

+ 4
- 3
src/java/org/apache/fop/render/bitmap/PNGRenderer_onthefly.java View File

@@ -95,9 +95,10 @@ public class PNGRenderer_onthefly extends Java2DRenderer {
fileSyntax = s.substring(0, i);
}

/** @see org.apache.fop.render.Renderer#renderPage(org.apache.fop.area.PageViewport) */
public void renderPage(PageViewport pageViewport) throws IOException,
FOPException {
/**
* @see org.apache.fop.render.Renderer#renderPage(org.apache.fop.area.PageViewport)
*/
public void renderPage(PageViewport pageViewport) throws IOException {

// Do the rendering: get the image for this page
RenderedImage image = (RenderedImage) getPageImage(pageViewport);

+ 17
- 8
src/java/org/apache/fop/render/java2d/FontMetricsMapper.java View File

@@ -1,5 +1,5 @@
/*
* Copyright 1999-2004 The Apache Software Foundation.
* Copyright 1999-2006 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.
@@ -25,6 +25,7 @@ import java.util.Map;
// FOP
import org.apache.fop.fonts.FontMetrics;
import org.apache.fop.fonts.FontType;
import org.apache.fop.fonts.Typeface;


/**
@@ -35,13 +36,7 @@ import org.apache.fop.fonts.FontType;
* style as member varibles
*/

public class FontMetricsMapper implements FontMetrics {

/**
* The first and last non space-character
*/
private static final int FIRST_CHAR = 32;
private static final int LAST_CHAR = 255;
public class FontMetricsMapper extends Typeface implements FontMetrics {

/**
* This is a Java2DFontMetrics that does the real calculation.
@@ -157,6 +152,20 @@ public class FontMetricsMapper implements FontMetrics {
return false;
}

/** @see org.apache.fop.fonts.Typeface#getEncoding() */
public String getEncoding() {
return null; //Not applicable to Java2D rendering
}

/** @see org.apache.fop.fonts.Typeface#mapChar(char) */
public char mapChar(char c) {
return c;
}

/** @see org.apache.fop.fonts.Typeface#hasChar(char) */
public boolean hasChar(char c) {
return metric.hasChar(family, style, Java2DFontMetrics.FONT_SIZE, c);
}

}


+ 3
- 2
src/java/org/apache/fop/render/java2d/FontSetup.java View File

@@ -1,5 +1,5 @@
/*
* Copyright 1999-2004 The Apache Software Foundation.
* Copyright 1999-2006 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.
@@ -98,7 +98,8 @@ public class FontSetup {
// --> goes to F12
fontInfo.addMetrics("F12", metric);

metric = new FontMetricsMapper("Symbol", bolditalic, graphics);
metric = new FontMetricsMapper("Serif", normal, graphics);
//"Symbol" doesn't seem to work here, but "Serif" does the job just fine. *shrug*
// --> goes to F13 and F14
fontInfo.addMetrics("F13", metric);
fontInfo.addMetrics("F14", metric);

+ 15
- 2
src/java/org/apache/fop/render/java2d/Java2DFontMetrics.java View File

@@ -1,5 +1,5 @@
/*
* Copyright 1999-2004 The Apache Software Foundation.
* Copyright 1999-2006 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.
@@ -53,7 +53,7 @@ public class Java2DFontMetrics {
/**
* The width of all 256 character, if requested
*/
private int width[] = null;
private int[] width = null;

/**
* The typical height of a small cap latter
@@ -291,6 +291,19 @@ public class Java2DFontMetrics {
*/
}

/**
* Indicates whether the font contains a particular character/glyph.
* @param family font family (jave name) to use
* @param style font style (jave def.) to use
* @param size font size
* @param c the glyph to check
* @return true if the character is supported
*/
public boolean hasChar(String family, int style, int size, char c) {
setFont(family, style, size);
return f1.canDisplay(c);
}

}



+ 7
- 19
src/java/org/apache/fop/render/java2d/Java2DGraphicsState.java View File

@@ -140,18 +140,6 @@ public class Java2DGraphicsState implements Constants, RendererState {
return new Color(col.getRed(), col.getGreen(), col.getBlue());
}

/**
* @see org.apache.fop.render.java2d.RendererState#updateColor(org.apache.fop.datatypes.ColorType,
* boolean, java.lang.StringBuffer)
*/
public boolean updateColor(ColorType col, boolean fill, StringBuffer pdf) {
if (col == null) {
return false;
}
Color newCol = toColor(col);
return updateColor(newCol);
}

/**
* Update the current Color
* @param col the ColorType
@@ -177,13 +165,13 @@ public class Java2DGraphicsState implements Constants, RendererState {
*/
public boolean updateFont(String name, int size, StringBuffer pdf) {

boolean updateName = (!name.equals(getGraph().getFont().getFontName()));
boolean updateSize = (size != (getGraph().getFont().getSize()));
FontMetricsMapper mapper = (FontMetricsMapper)fontInfo.getMetricsFor(name);
boolean updateName = (!mapper.getFontName().equals(
getGraph().getFont().getFontName()));
boolean updateSize = (size != (getGraph().getFont().getSize() * 1000));

if (updateName || updateSize) {
// the font name and/or the font size have changed
FontMetricsMapper mapper = (FontMetricsMapper) fontInfo
.getMetricsFor(name);
java.awt.Font font = mapper.getFont(size);

currentGraphics.setFont(font);
@@ -215,8 +203,8 @@ public class Java2DGraphicsState implements Constants, RendererState {
switch (style) {
case EN_DOTTED:

currentStroke = new BasicStroke(width, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_BEVEL, 0f, new float[] { 2f }, 0f);
currentStroke = new BasicStroke(width, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_BEVEL, 0f, new float[] {0, 2 * width}, width);
currentGraphics.setStroke(currentStroke);

currentStrokeWidth = width;
@@ -227,7 +215,7 @@ public class Java2DGraphicsState implements Constants, RendererState {
case EN_DASHED:

currentStroke = new BasicStroke(width, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_BEVEL, 0f, new float[] { 8f, 2f }, 0f);
BasicStroke.JOIN_BEVEL, 0f, new float[] {8f, 2f}, 0f);
currentGraphics.setStroke(currentStroke);

currentStrokeWidth = width;

+ 333
- 588
src/java/org/apache/fop/render/java2d/Java2DRenderer.java
File diff suppressed because it is too large
View File


+ 0
- 9
src/java/org/apache/fop/render/java2d/RendererState.java View File

@@ -48,15 +48,6 @@ public interface RendererState {
*/
public abstract int getStackLevel();

/**
* Establishes a new foreground or fill color.
* @param col the color to apply (null skips this operation)
* @param fill true to set the fill color, false for the foreground color
* @param pdf only used by the PDFRenderer, is set to null.
* @return true if the new Color changes the current Color
*/
public abstract boolean updateColor(ColorType col, boolean fill, StringBuffer pdf);

/**
* Set the current font name. Check if the font name will change and then
* set the new name.

+ 8
- 0
src/java/org/apache/fop/render/xml/XMLRenderer.java View File

@@ -604,6 +604,14 @@ public class XMLRenderer extends PrintRenderer {
//only necessary for graphical output
}

/**
* @see org.apache.fop.render.AbstractRenderer#renderInlineAreaBackAndBorders(
* org.apache.fop.area.inline.InlineArea)
*/
protected void renderInlineAreaBackAndBorders(InlineArea area) {
//only necessary for graphical output
}

/**
* @see org.apache.fop.render.AbstractRenderer#renderBeforeFloat(BeforeFloat)
*/

+ 38
- 21
src/sandbox/org/apache/fop/render/pcl/PCLGenerator.java View File

@@ -160,10 +160,45 @@ public class PCLGenerator {
* @param y the Y coordinate (in millipoints)
* @throws IOException In case of an I/O error
*/
public void setCursorPos(int x, int y) throws IOException {
writeCommand("*p" + (x / 100) + "h" + (y / 100) + "V");
public void setCursorPos(double x, double y) throws IOException {
if (x < 0) {
//A negative x value will result in a relative movement so go to "0" first.
//But this will most probably have no effect anyway since you can't paint to the left
//of the logical page
writeCommand("&a0h" + formatDouble2(x / 100) + "h" + formatDouble2(y / 100) + "V");
} else {
writeCommand("&a" + formatDouble2(x / 100) + "h" + formatDouble2(y / 100) + "V");
}
}

/**
* Enters the HP GL/2 mode.
* @param restorePreviousHPGL2Cursor true if the previous HP GL/2 pen position should be
* restored, false if the current position is maintained
* @throws IOException In case of an I/O error
*/
public void enterHPGL2Mode(boolean restorePreviousHPGL2Cursor) throws IOException {
if (restorePreviousHPGL2Cursor) {
writeCommand("%0B");
} else {
writeCommand("%1B");
}
}
/**
* Enters the PCL mode.
* @param restorePreviousPCLCursor true if the previous PCL cursor position should be restored,
* false if the current position is maintained
* @throws IOException In case of an I/O error
*/
public void enterPCLMode(boolean restorePreviousPCLCursor) throws IOException {
if (restorePreviousPCLCursor) {
writeCommand("%0A");
} else {
writeCommand("%1A");
}
}
/**
* Generate a filled rectangle
*
@@ -428,24 +463,6 @@ public class PCLGenerator {
int lastcount = -1;
byte lastbyte = 0;
int rlewidth = 0;
/*
int xres = (iw * 72000) / w;
int yres = (ih * 72000) / h;
int resolution = xres;
if (yres > xres)
resolution = yres;

if (resolution > 300)
resolution = 600;
else if (resolution > 150)
resolution = 300;
else if (resolution > 100)
resolution = 150;
else if (resolution > 75)
resolution = 100;
else
resolution = 75;
*/

// Transfer graphics data
for (y = 0; y < imgh; y++) {
@@ -498,5 +515,5 @@ public class PCLGenerator {
// End raster graphics
writeCommand("*rB");
}
}

+ 258
- 82
src/sandbox/org/apache/fop/render/pcl/PCLGraphics2D.java View File

@@ -20,6 +20,7 @@ package org.apache.fop.render.pcl;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
@@ -28,6 +29,8 @@ import java.awt.Image;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
@@ -50,6 +53,9 @@ public class PCLGraphics2D extends AbstractGraphics2D {
/** The PCL generator */
protected PCLGenerator gen;
private boolean failOnUnsupportedFeature = true;
private boolean clippingDisabled = false;
/**
* Create a new PCLGraphics2D.
* @param gen the PCL Generator to paint with
@@ -70,7 +76,9 @@ public class PCLGraphics2D extends AbstractGraphics2D {

/** @see java.awt.Graphics#create() */
public Graphics create() {
return new PCLGraphics2D(this);
PCLGraphics2D copy = new PCLGraphics2D(this);
copy.setGraphicContext((GraphicContext)getGraphicContext().clone());
return copy;
}

/** @see java.awt.Graphics#dispose() */
@@ -95,6 +103,18 @@ public class PCLGraphics2D extends AbstractGraphics2D {
ioe.printStackTrace();
}

/**
* Raises an UnsupportedOperationException if this instance is configured to do so and an
* unsupported feature has been requested. Clients can make use of this to fall back to
* a more compatible way of painting a PCL graphic.
* @param msg the error message to be displayed
*/
protected void handleUnsupportedFeature(String msg) {
if (this.failOnUnsupportedFeature) {
throw new UnsupportedOperationException(msg);
}
}
/** @see java.awt.Graphics2D#getDeviceConfiguration() */
public GraphicsConfiguration getDeviceConfiguration() {
return GraphicsEnvironment.getLocalGraphicsEnvironment().
@@ -114,18 +134,35 @@ public class PCLGraphics2D extends AbstractGraphics2D {
if (da != null) {
gen.writeText("UL1,");
for (int idx = 0, len = Math.min(20, da.length); idx < len; idx++) {
gen.writeText(gen.formatDouble4(da[idx]));
int len = Math.min(20, da.length);
float patternLen = 0.0f;
for (int idx = 0; idx < len; idx++) {
patternLen += da[idx];
}
if (len == 1) {
patternLen *= 2;
}
for (int idx = 0; idx < len; idx++) {
float perc = da[idx] * 100 / patternLen;
gen.writeText(gen.formatDouble2(perc));
if (idx < da.length - 1) {
gen.writeText(",");
}
}
if (len == 1) {
gen.writeText("," + gen.formatDouble2(da[0] * 100 / patternLen ));
}
gen.writeText(";");
/* TODO Dash phase NYI
float offset = bs.getDashPhase();
gen.writeln(gen.formatDouble4(offset) + " setdash");
*/
gen.writeText("LT1;");
Point2D ptLen = new Point2D.Double(patternLen, 0);
//interpret as absolute length
getTransform().deltaTransform(ptLen, ptLen);
double transLen = UnitConv.pt2mm(ptLen.distance(0, 0));
gen.writeText("LT1," + gen.formatDouble4(transLen) + ",1;");
} else {
gen.writeText("LT;");
}
@@ -166,13 +203,13 @@ public class PCLGraphics2D extends AbstractGraphics2D {
float lw = bs.getLineWidth();
Point2D ptSrc = new Point2D.Double(lw, 0);
//Pen widths are set as absolute metric values (WU0;)
Point2D ptDest = getTransform().transform(ptSrc, null);
Point2D ptDest = getTransform().deltaTransform(ptSrc, null);
double transDist = UnitConv.pt2mm(ptDest.distance(0, 0));
//System.out.println("--" + ptDest.distance(0, 0) + " " + transDist);
gen.writeText(";PW" + gen.formatDouble4(transDist) + ";");
} else {
System.err.println("Unsupported Stroke: " + stroke.getClass().getName());
handleUnsupportedFeature("Unsupported Stroke: " + stroke.getClass().getName());
}
}

@@ -187,7 +224,31 @@ public class PCLGraphics2D extends AbstractGraphics2D {
int shade = gen.convertToPCLShade(col);
gen.writeText("TR0;FT10," + shade + ";");
} else {
System.err.println("Unsupported Paint: " + paint.getClass().getName());
handleUnsupportedFeature("Unsupported Paint: " + paint.getClass().getName());
}
}

private void writeClip(Shape imclip) throws IOException {
if (clippingDisabled) {
return;
}
if (imclip == null) {
//gen.writeText("IW;");
} else {
handleUnsupportedFeature("Clipping is not supported. Shape: " + imclip);
/* This is an attempt to clip using the "InputWindow" (IW) but this only allows to
* clip a rectangular area. Force falling back to bitmap mode for now.
Rectangle2D bounds = imclip.getBounds2D();
Point2D p1 = new Point2D.Double(bounds.getX(), bounds.getY());
Point2D p2 = new Point2D.Double(
bounds.getX() + bounds.getWidth(), bounds.getY() + bounds.getHeight());
getTransform().transform(p1, p1);
getTransform().transform(p2, p2);
gen.writeText("IW" + gen.formatDouble4(p1.getX())
+ "," + gen.formatDouble4(p2.getY())
+ "," + gen.formatDouble4(p2.getX())
+ "," + gen.formatDouble4(p1.getY()) + ";");
*/
}
}

@@ -197,16 +258,17 @@ public class PCLGraphics2D extends AbstractGraphics2D {
AffineTransform trans = getTransform();
Shape imclip = getClip();
//writeClip(imclip);
//establishColor(getColor());
writeClip(imclip);
applyPaint(getPaint());
if (!Color.black.equals(getColor())) {
//TODO PCL 5 doesn't support colored pens, PCL5c has a pen color (PC) command
handleUnsupportedFeature("Only black is supported as stroke color: " + getColor());
}
applyStroke(getStroke());
//gen.writeln("newpath");
PathIterator iter = s.getPathIterator(trans);
processPathIterator(iter);
gen.writeText("EP;");
processPathIteratorStroke(iter);
writeClip(null);
} catch (IOException ioe) {
handleIOException(ioe);
}
@@ -217,16 +279,13 @@ public class PCLGraphics2D extends AbstractGraphics2D {
try {
AffineTransform trans = getTransform();
Shape imclip = getClip();
//writeClip(imclip);
writeClip(imclip);
//establishColor(getColor());

applyPaint(getPaint());

PathIterator iter = s.getPathIterator(trans);
processPathIterator(iter);
int fillMethod = (iter.getWindingRule() == PathIterator.WIND_EVEN_ODD ? 0 : 1);
gen.writeText("FP" + fillMethod + ";");
processPathIteratorFill(iter);
writeClip(null);
} catch (IOException ioe) {
handleIOException(ioe);
}
@@ -237,97 +296,163 @@ public class PCLGraphics2D extends AbstractGraphics2D {
* @param iter PathIterator to process
* @throws IOException In case of an I/O problem.
*/
public void processPathIterator(PathIterator iter) throws IOException {
public void processPathIteratorStroke(PathIterator iter) throws IOException {
gen.writeText("\n");
double[] vals = new double[6];
boolean penDown = false;
boolean hasFirst = false;
double x = 0, firstX = 0;
double y = 0, firstY = 0;
boolean pendingPM0 = true;
penUp();
double x = 0;
double y = 0;
StringBuffer sb = new StringBuffer(256);
penUp(sb);
while (!iter.isDone()) {
int type = iter.currentSegment(vals);
if (type == PathIterator.SEG_CLOSE) {
hasFirst = false;
/*
if (firstX != x && firstY != y) {
plotAbsolute(firstX, firstY);
}*/
//penUp();
gen.writeText("PM1;");
gen.writeText("PM;");
gen.writeText(sb.toString());
gen.writeText("PM2;EP;");
sb.setLength(0);
iter.next();
continue;
}
if (type == PathIterator.SEG_MOVETO) {
} else if (type == PathIterator.SEG_MOVETO) {
gen.writeText(sb.toString());
sb.setLength(0);
if (penDown) {
penUp();
penUp(sb);
penDown = false;
}
} else {
if (!penDown) {
penDown();
penDown(sb);
penDown = true;
}
}
switch (type) {
case PathIterator.SEG_CLOSE:
break;
case PathIterator.SEG_MOVETO:
x = vals[0];
y = vals[1];
plotAbsolute(x, y, sb);
gen.writeText(sb.toString());
sb.setLength(0);
break;
case PathIterator.SEG_LINETO:
x = vals[0];
y = vals[1];
plotAbsolute(x, y, sb);
break;
case PathIterator.SEG_CUBICTO:
x = vals[4];
y = vals[5];
bezierAbsolute(vals[0], vals[1], vals[2], vals[3], x, y);
bezierAbsolute(vals[0], vals[1], vals[2], vals[3], x, y, sb);
break;
case PathIterator.SEG_LINETO:
case PathIterator.SEG_QUADTO:
double originX = x;
double originY = y;
x = vals[2];
y = vals[3];
quadraticBezierAbsolute(originX, originY, vals[0], vals[1], x, y, sb);
break;
default:
break;
}
iter.next();
}
sb.append("\n");
gen.writeText(sb.toString());
}
/**
* Processes a path iterator generating the nexessary painting operations.
* @param iter PathIterator to process
* @throws IOException In case of an I/O problem.
*/
public void processPathIteratorFill(PathIterator iter) throws IOException {
gen.writeText("\n");
double[] vals = new double[6];
boolean penDown = false;
double x = 0;
double y = 0;
boolean pendingPM0 = true;
StringBuffer sb = new StringBuffer(256);
penUp(sb);
while (!iter.isDone()) {
int type = iter.currentSegment(vals);
if (type == PathIterator.SEG_CLOSE) {
sb.append("PM1;");
iter.next();
continue;
} else if (type == PathIterator.SEG_MOVETO) {
if (penDown) {
penUp(sb);
penDown = false;
}
} else {
if (!penDown) {
penDown(sb);
penDown = true;
}
}
switch (type) {
case PathIterator.SEG_MOVETO:
x = vals[0];
y = vals[1];
plotAbsolute(x, y);
plotAbsolute(x, y, sb);
break;
case PathIterator.SEG_MOVETO:
case PathIterator.SEG_LINETO:
x = vals[0];
y = vals[1];
plotAbsolute(x, y);
plotAbsolute(x, y, sb);
break;
case PathIterator.SEG_CUBICTO:
x = vals[4];
y = vals[5];
bezierAbsolute(vals[0], vals[1], vals[2], vals[3], x, y, sb);
break;
case PathIterator.SEG_QUADTO:
double originX = x;
double originY = y;
x = vals[2];
y = vals[3];
quadraticBezierAbsolute(originX, originY, vals[0], vals[1], x, y);
break;
case PathIterator.SEG_CLOSE:
quadraticBezierAbsolute(originX, originY, vals[0], vals[1], x, y, sb);
break;
default:
break;
throw new IllegalStateException("Must not get here");
}
if (pendingPM0) {
pendingPM0 = false;
gen.writeText("PM;");
}
if (!hasFirst) {
firstX = x;
firstY = y;
sb.append("PM;");
}
iter.next();
}
gen.writeText("PM2;");
sb.append("PM2;");
fillPolygon(iter.getWindingRule(), sb);
sb.append("\n");
gen.writeText(sb.toString());
}
private void fillPolygon(int windingRule, StringBuffer sb) {
int fillMethod = (windingRule == PathIterator.WIND_EVEN_ODD ? 0 : 1);
sb.append("FP").append(fillMethod).append(";");
}

private void plotAbsolute(double x, double y) throws IOException {
gen.writeText("PA" + gen.formatDouble4(x) + ","
+ gen.formatDouble4(y) + ";");
private void plotAbsolute(double x, double y, StringBuffer sb) {
sb.append("PA").append(gen.formatDouble4(x));
sb.append(",").append(gen.formatDouble4(y)).append(";");
}

private void bezierAbsolute(double x1, double y1, double x2, double y2, double x3, double y3)
throws IOException {
gen.writeText("BZ" + gen.formatDouble4(x1) + ","
+ gen.formatDouble4(y1) + ","
+ gen.formatDouble4(x2) + ","
+ gen.formatDouble4(y2) + ","
+ gen.formatDouble4(x3) + ","
+ gen.formatDouble4(y3) + ";");
private void bezierAbsolute(double x1, double y1, double x2, double y2, double x3, double y3,
StringBuffer sb) {
sb.append("BZ").append(gen.formatDouble4(x1));
sb.append(",").append(gen.formatDouble4(y1));
sb.append(",").append(gen.formatDouble4(x2));
sb.append(",").append(gen.formatDouble4(y2));
sb.append(",").append(gen.formatDouble4(x3));
sb.append(",").append(gen.formatDouble4(y3)).append(";");
}

private void quadraticBezierAbsolute(double originX, double originY,
double x1, double y1, double x2, double y2)
throws IOException {
double x1, double y1, double x2, double y2, StringBuffer sb) {
//Quadratic Bezier curve can be mapped to a normal bezier curve
//See http://pfaedit.sourceforge.net/bezier.html
double nx1 = originX + (2.0 / 3.0) * (x1 - originX);
@@ -336,28 +461,31 @@ public class PCLGraphics2D extends AbstractGraphics2D {
double nx2 = nx1 + (1.0 / 3.0) * (x2 - originX);
double ny2 = ny1 + (1.0 / 3.0) * (y2 - originY);
bezierAbsolute(nx1, ny1, nx2, ny2, x2, y2);
bezierAbsolute(nx1, ny1, nx2, ny2, x2, y2, sb);
}

private void penDown() throws IOException {
gen.writeText("PD;");
private void penDown(StringBuffer sb) {
sb.append("PD;");
}

private void penUp() throws IOException {
gen.writeText("PU;");
private void penUp(StringBuffer sb) {
sb.append("PU;");
}

/** @see java.awt.Graphics2D#drawString(java.lang.String, float, float) */
public void drawString(String s, float x, float y) {
// TODO Auto-generated method stub
System.err.println("drawString NYI");
java.awt.Font awtFont = getFont();
FontRenderContext frc = getFontRenderContext();
GlyphVector gv = awtFont.createGlyphVector(frc, s);
Shape glyphOutline = gv.getOutline(x, y);
fill(glyphOutline);
}

/** @see java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float) */
public void drawString(AttributedCharacterIterator iterator, float x,
float y) {
// TODO Auto-generated method stub
System.err.println("drawString NYI");
handleUnsupportedFeature("drawString NYI");
}

/**
@@ -365,8 +493,7 @@ public class PCLGraphics2D extends AbstractGraphics2D {
* java.awt.geom.AffineTransform)
*/
public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
// TODO Auto-generated method stub
System.err.println("drawRenderedImage NYI");
handleUnsupportedFeature("Bitmap images are not supported");
}

/**
@@ -374,8 +501,7 @@ public class PCLGraphics2D extends AbstractGraphics2D {
* java.awt.geom.AffineTransform)
*/
public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
// TODO Auto-generated method stub
System.err.println("drawRenderedImage NYI");
handleUnsupportedFeature("Bitmap images are not supported");
}

/**
@@ -384,8 +510,7 @@ public class PCLGraphics2D extends AbstractGraphics2D {
*/
public boolean drawImage(Image img, int x, int y, int width, int height,
ImageObserver observer) {
// TODO Auto-generated method stub
System.err.println("drawImage NYI");
handleUnsupportedFeature("Bitmap images are not supported");
return false;
}

@@ -393,21 +518,62 @@ public class PCLGraphics2D extends AbstractGraphics2D {
* @see java.awt.Graphics#drawImage(java.awt.Image, int, int, java.awt.image.ImageObserver)
*/
public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
// TODO Auto-generated method stub
System.err.println("drawImage NYI");
handleUnsupportedFeature("Bitmap images are not supported");
return false;
/*
* First attempt disabled.
* Reasons: Lack of transparency control, positioning and rotation issues
final int width = img.getWidth(observer);
final int height = img.getHeight(observer);
if (width == -1 || height == -1) {
return false;
}

Dimension size = new Dimension(width, height);
BufferedImage buf = buildBufferedImage(size);

java.awt.Graphics2D g = buf.createGraphics();
try {
g.setComposite(AlphaComposite.SrcOver);
g.setBackground(new Color(255, 255, 255));
g.setPaint(new Color(255, 255, 255));
g.fillRect(0, 0, width, height);
g.clip(new Rectangle(0, 0, buf.getWidth(), buf.getHeight()));

if (!g.drawImage(img, 0, 0, observer)) {
return false;
}
} finally {
g.dispose();
}

try {
AffineTransform at = getTransform();
gen.enterPCLMode(false);
//Shape imclip = getClip(); Clipping is not available in PCL
Point2D p1 = new Point2D.Double(x, y);
at.transform(p1, p1);
pclContext.getTransform().transform(p1, p1);
gen.setCursorPos(p1.getX(), p1.getY());
gen.paintBitmap(buf, 72);
gen.enterHPGL2Mode(false);
} catch (IOException ioe) {
handleIOException(ioe);
}

return true;*/
}

/** @see java.awt.Graphics#copyArea(int, int, int, int, int, int) */
public void copyArea(int x, int y, int width, int height, int dx, int dy) {
// TODO Auto-generated method stub
System.err.println("copyArea NYI");
handleUnsupportedFeature("copyArea NYI");
}

/** @see java.awt.Graphics#setXORMode(java.awt.Color) */
public void setXORMode(Color c1) {
// TODO Auto-generated method stub
System.err.println("setXORMode NYI");
handleUnsupportedFeature("setXORMode NYI");
}

/**
@@ -422,6 +588,16 @@ public class PCLGraphics2D extends AbstractGraphics2D {
fmg = bi.createGraphics();
}

/**
* Creates a buffered image.
* @param size dimensions of the image to be created
* @return the buffered image
*/
protected BufferedImage buildBufferedImage(Dimension size) {
return new BufferedImage(size.width, size.height,
BufferedImage.TYPE_BYTE_GRAY);
}
/** @see java.awt.Graphics#getFontMetrics(java.awt.Font) */
public java.awt.FontMetrics getFontMetrics(java.awt.Font f) {
return fmg.getFontMetrics(f);

+ 69
- 59
src/sandbox/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java View File

@@ -27,6 +27,9 @@ import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;

import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.render.Graphics2DAdapter;
import org.apache.fop.render.Graphics2DImagePainter;
import org.apache.fop.render.RendererContext;
@@ -38,6 +41,9 @@ import org.apache.xmlgraphics.java2d.GraphicContext;
*/
public class PCLGraphics2DAdapter implements Graphics2DAdapter {

/** logging instance */
private static Log log = LogFactory.getLog(PCLGraphics2DAdapter.class);

/**
* Main constructor
*/
@@ -57,80 +63,84 @@ public class PCLGraphics2DAdapter implements Graphics2DAdapter {
float imw = (float)dim.getWidth();
float imh = (float)dim.getHeight();

boolean painted = false;
boolean paintAsBitmap = pclContext.paintAsBitmap();
if (paintAsBitmap) {
if (!paintAsBitmap) {
ByteArrayOutputStream baout = new ByteArrayOutputStream();
PCLGenerator tempGen = new PCLGenerator(baout);
try {
GraphicContext ctx = (GraphicContext)pcl.getGraphicContext().clone();

AffineTransform prepareHPGL2 = new AffineTransform();
prepareHPGL2.scale(0.001, 0.001);
ctx.setTransform(prepareHPGL2);

PCLGraphics2D graphics = new PCLGraphics2D(tempGen);
graphics.setGraphicContext(ctx);
Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh);
painter.paint(graphics, area);
//If we arrive here, the graphic is natively paintable, so write the graphic
pcl.saveGraphicsState();
pcl.setCursorPos(x, y);
gen.writeCommand("*c" + gen.formatDouble4(width / 100f) + "x"
+ gen.formatDouble4(height / 100f) + "Y");
gen.writeCommand("*c0T");
gen.enterHPGL2Mode(false);
gen.writeText("\nIN;");
gen.writeText("SP1;");
//One Plotter unit is 0.025mm!
double scale = imw / UnitConv.mm2pt(imw * 0.025);
gen.writeText("SC0," + gen.formatDouble4(scale)
+ ",0,-" + gen.formatDouble4(scale) + ",2;");
gen.writeText("IR0,100,0,100;");
gen.writeText("PU;PA0,0;\n");
baout.writeTo(gen.getOutputStream()); //Buffer is written to output stream
gen.writeText("\n");

gen.enterPCLMode(false);
pcl.restoreGraphicsState();
painted = true;
} catch (UnsupportedOperationException uoe) {
log.debug(
"Cannot paint graphic natively. Falling back to bitmap painting. Reason: "
+ uoe.getMessage());
}
}
if (!painted) {
int resolution = 300; //TODO not hard-coded, please!
int bmw = UnitConv.mpt2px(pclContext.getWidth(), resolution);
int bmh = UnitConv.mpt2px(pclContext.getHeight(), resolution);
BufferedImage bi = new BufferedImage(
bmw, bmh,
BufferedImage.TYPE_INT_RGB);
BufferedImage.TYPE_BYTE_GRAY);
Graphics2D g2d = bi.createGraphics();
try {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_OFF);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_ENABLE);
g2d.setBackground(Color.white);
g2d.setColor(Color.black);
g2d.clearRect(0, 0, bmw, bmh);
double sx = (double)bmw / pclContext.getWidth() * 1000;
double sy = (double)bmh / pclContext.getHeight() * 1000;
g2d.scale(sx, sy);
RenderingHints.VALUE_ANTIALIAS_OFF);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setBackground(Color.white);
g2d.setColor(Color.black);
g2d.clearRect(0, 0, bmw, bmh);
double sx = (double)bmw / pclContext.getWidth();
double sy = (double)bmh / pclContext.getHeight();
g2d.scale(sx, sy);

//Paint the SVG on the BufferedImage
Rectangle2D area = new Rectangle2D.Double(
0.0, 0.0, pclContext.getWidth(), pclContext.getHeight());
painter.paint(g2d, area);
//Paint the SVG on the BufferedImage
Rectangle2D area = new Rectangle2D.Double(
0.0, 0.0, pclContext.getWidth(), pclContext.getHeight());
painter.paint(g2d, area);
} finally {
g2d.dispose();
}

pcl.moveTo(x, y);
pcl.setCursorPos(x, y);
gen.paintBitmap(bi, resolution);
} else {
pcl.saveGraphicsState();
GraphicContext ctx = (GraphicContext)pcl.getGraphicContext().clone();

// Clip to the image area.
//gen.writeln("newpath");
//gen.defineRect(fx, fy, fwidth, fheight);
//gen.writeln("clip");
AffineTransform prepareHPGL2 = new AffineTransform();
//prepareHPGL2.scale(1, 1);
ctx.setTransform(prepareHPGL2);

pcl.moveTo(x, y);
gen.writeCommand("*c" + gen.formatDouble4(width / 100f) + "x"
+ gen.formatDouble4(height / 100f) + "Y");
gen.writeCommand("*c0T");
gen.writeCommand("%0B");
gen.writeText("IN;");
gen.writeText("SP1;");
//One Plotter unit is 0.025mm!
double scale = imw / UnitConv.mm2pt(imw * 0.025);
gen.writeText("SC0," + gen.formatDouble4(scale)
+ ",0,-" + gen.formatDouble4(scale) + ",2;");
gen.writeText("IR0,100,0,100;");
gen.writeText("PU;PA0,0;");
PCLGraphics2D graphics = new PCLGraphics2D(gen);
graphics.setGraphicContext(ctx);
Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh);
painter.paint(graphics, area);

gen.writeCommand("%0A");
pcl.restoreGraphicsState();
}
}


+ 578
- 180
src/sandbox/org/apache/fop/render/pcl/PCLRenderer.java View File

@@ -18,7 +18,38 @@
package org.apache.fop.render.pcl;

//Java
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.PixelInterleavedSampleModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import org.w3c.dom.Document;

import org.apache.xmlgraphics.java2d.GraphicContext;

// FOP
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.area.Area;
@@ -31,44 +62,25 @@ import org.apache.fop.area.Trait.Color;
import org.apache.fop.area.inline.AbstractTextArea;
import org.apache.fop.area.inline.ForeignObject;
import org.apache.fop.area.inline.Image;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.area.inline.Viewport;
import org.apache.fop.area.inline.WordArea;
import org.apache.fop.fo.extensions.ExtensionElementMapping;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontSetup;
import org.apache.fop.image.EPSImage;
import org.apache.fop.image.FopImage;
import org.apache.fop.image.ImageFactory;
import org.apache.fop.image.XMLImage;
import org.apache.fop.render.Graphics2DAdapter;
import org.apache.fop.render.Graphics2DImagePainter;
import org.apache.fop.render.PrintRenderer;
import org.apache.fop.render.RendererContext;
import org.apache.fop.render.RendererContextConstants;
import org.apache.fop.render.java2d.Java2DRenderer;
import org.apache.fop.traits.BorderProps;
import org.apache.xmlgraphics.java2d.GraphicContext;
import org.w3c.dom.Document;

// Java
import java.awt.Rectangle;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.PixelInterleavedSampleModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import org.apache.fop.util.QName;

/**
* Renderer for the PCL 5 printer language. It also uses HP GL/2 for certain graphic elements.
@@ -87,6 +99,15 @@ public class PCLRenderer extends PrintRenderer {

private Stack graphicContextStack = new Stack();
private GraphicContext graphicContext = new GraphicContext();

private GeneralPath currentPath = null;
private java.awt.Color currentFillColor = null;
/**
* Controls whether appearance is more important than speed. False can cause some FO feature
* to be ignored (like the advanced borders).
*/
private boolean qualityBeforeSpeed = false;
/**
* Create the PCL renderer
@@ -94,6 +115,23 @@ public class PCLRenderer extends PrintRenderer {
public PCLRenderer() {
}

/**
* @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
*/
public void configure(Configuration cfg) throws ConfigurationException {
super.configure(cfg);
String rendering = cfg.getChild("rendering").getValue(null);
if ("quality".equalsIgnoreCase(rendering)) {
this.qualityBeforeSpeed = true;
} else if ("speed".equalsIgnoreCase(rendering)) {
this.qualityBeforeSpeed = false;
} else if (rendering != null) {
throw new ConfigurationException(
"Valid values for 'rendering' are 'quality' and 'speed'. Value found: "
+ rendering);
}
}

/**
* Central exception handler for I/O exceptions.
* @param ioe IOException to handle
@@ -229,6 +267,8 @@ public class PCLRenderer extends PrintRenderer {
this.gen = new PCLGenerator(out);

gen.universalEndOfLanguage();
gen.writeText("@PJL JOB NAME = \"" + userAgent.getTitle() + "\"\n");
gen.writeText("@PJL ENTER LANGUAGE = PCL\n");
gen.resetPrinter();
}

@@ -253,19 +293,6 @@ public class PCLRenderer extends PrintRenderer {
final long pageheight = Math.round(page.getViewArea().getHeight());
selectPageFormat(pagewidth, pageheight);
if (false) { //TODO DEBUG CODE! Remove me.
//gen.fillRect(0, 0, (int)pagewidth, (int)pageheight, java.awt.Color.yellow);
//gen.fillRect(5000, 5000, (int)pagewidth - 10000, (int)pageheight - 10000, java.awt.Color.yellow);
//gen.fillRect(10000, 10000, (int)pagewidth / 4 - 20000, (int)pageheight / 4 - 20000, java.awt.Color.red);
for (int i = 0; i < 29; i++) {
if (i % 2 == 0) {
int w = (int)(10 * 2.835 * 1000);
Point2D p = transformedPoint(i * w, 0);
gen.fillRect((int)p.getX(), (int)p.getY(), w, w, java.awt.Color.yellow);
}
}
}
super.renderPage(page);
gen.formFeed();
restoreGraphicsState();
@@ -389,7 +416,7 @@ public class PCLRenderer extends PrintRenderer {
saveGraphicsState();
updatePrintDirection();
graphicContext.translate(rx, bl);
moveTo(0, 0);
setCursorPos(0, 0);
super.renderText(area); //Updates IPD
@@ -400,10 +427,83 @@ public class PCLRenderer extends PrintRenderer {
}
}

void moveTo(int x, int y) throws IOException {
Point2D transPoint = transformedPoint(x, y);
gen.writeCommand("&a" + gen.formatDouble2(transPoint.getX() / 100) + "h"
+ gen.formatDouble2(transPoint.getY() / 100) + "V");
/**
* Sets the current cursor position. The coordinates are transformed to the absolute position
* on the logical PCL page and then passed on to the PCLGenerator.
* @param x the x coordinate (in millipoints)
* @param y the y coordinate (in millipoints)
*/
void setCursorPos(float x, float y) {
try {
Point2D transPoint = transformedPoint(x, y);
gen.setCursorPos(transPoint.getX(), transPoint.getY());
} catch (IOException ioe) {
handleIOTrouble(ioe);
}
}

/**
* @see org.apache.fop.render.AbstractPathOrientedRenderer#clip()
*/
protected void clip() {
if (currentPath == null) {
throw new IllegalStateException("No current path available!");
}
//TODO Find a good way to do clipping
currentPath = null;
}

/**
* @see org.apache.fop.render.AbstractPathOrientedRenderer#closePath()
*/
protected void closePath() {
currentPath.closePath();
}

/**
* @see org.apache.fop.render.AbstractPathOrientedRenderer#lineTo(float, float)
*/
protected void lineTo(float x, float y) {
if (currentPath == null) {
currentPath = new GeneralPath();
}
currentPath.lineTo(x, y);
}

/**
* @see org.apache.fop.render.AbstractPathOrientedRenderer#moveTo(float, float)
*/
protected void moveTo(float x, float y) {
if (currentPath == null) {
currentPath = new GeneralPath();
}
currentPath.moveTo(x, y);
}
/**
* Fill a rectangular area.
* @param x the x coordinate (in pt)
* @param y the y coordinate (in pt)
* @param width the width of the rectangle
* @param height the height of the rectangle
*/
protected void fillRect(float x, float y, float width, float height) {
try {
Point2D p = transformedPoint(x * 1000, y * 1000);
gen.fillRect((int)p.getX(), (int)p.getY(),
(int)width * 1000, (int)height * 1000,
this.currentFillColor);
} catch (IOException ioe) {
handleIOTrouble(ioe);
}
}
/**
* Sets the new current fill color.
* @param color the color
*/
protected void updateFillColor(java.awt.Color color) {
this.currentFillColor = color;
}

private void updatePrintDirection() throws IOException {
@@ -481,37 +581,6 @@ public class PCLRenderer extends PrintRenderer {
super.renderSpace(space);
}

/**
* @see org.apache.fop.render.AbstractRenderer#renderViewport(org.apache.fop.area.inline.Viewport)
*/
public void renderViewport(Viewport viewport) {

float x = currentIPPosition / 1000f;
float y = (currentBPPosition + viewport.getOffset()) / 1000f;
float width = viewport.getIPD() / 1000f;
float height = viewport.getBPD() / 1000f;
// TODO: Calculate the border rect correctly.
float borderPaddingStart = viewport.getBorderAndPaddingWidthStart() / 1000f;
float borderPaddingBefore = viewport.getBorderAndPaddingWidthBefore() / 1000f;
float bpwidth = borderPaddingStart
+ (viewport.getBorderAndPaddingWidthEnd() / 1000f);
float bpheight = borderPaddingBefore
+ (viewport.getBorderAndPaddingWidthAfter() / 1000f);

drawBackAndBorders(viewport, x, y, width + bpwidth, height + bpheight);

if (viewport.getClip()) {
saveGraphicsState();

clipRect(x + borderPaddingStart, y + borderPaddingBefore, width, height);
}
super.renderViewport(viewport);

if (viewport.getClip()) {
restoreGraphicsState();
}
}

/**
* @see org.apache.fop.render.AbstractRenderer#renderBlockViewport(BlockViewport, List)
*/
@@ -625,7 +694,17 @@ public class PCLRenderer extends PrintRenderer {
* @see org.apache.fop.render.AbstractRenderer#renderImage(Image, Rectangle2D)
*/
public void renderImage(Image image, Rectangle2D pos) {
String url = ImageFactory.getURL(image.getURL());
drawImage(image.getURL(), pos, image.getForeignAttributes());
}

/**
* Draw an image at the indicated location.
* @param url the URI/URL of the image
* @param pos the position of the image
* @param foreignAttributes an optional Map with foreign attributes, may be null
*/
protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes) {
url = ImageFactory.getURL(url);
ImageFactory fact = userAgent.getFactory().getImageFactory();
FopImage fopimage = fact.getImage(url, userAgent);
if (fopimage == null) {
@@ -642,7 +721,7 @@ public class PCLRenderer extends PrintRenderer {
Document doc = ((XMLImage) fopimage).getDocument();
String ns = ((XMLImage) fopimage).getNameSpace();

renderDocument(doc, ns, pos, image.getForeignAttributes());
renderDocument(doc, ns, pos, foreignAttributes);
} else if ("image/svg+xml".equals(mime)) {
if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
return;
@@ -650,7 +729,7 @@ public class PCLRenderer extends PrintRenderer {
Document doc = ((XMLImage) fopimage).getDocument();
String ns = ((XMLImage) fopimage).getNameSpace();

renderDocument(doc, ns, pos, image.getForeignAttributes());
renderDocument(doc, ns, pos, foreignAttributes);
} else if (fopimage instanceof EPSImage) {
log.warn("EPS images are not supported by this renderer");
} else {
@@ -678,7 +757,7 @@ public class PCLRenderer extends PrintRenderer {
RenderedImage img = new BufferedImage(cm, raster, false, null);

try {
moveTo(this.currentIPPosition + (int)pos.getX(),
setCursorPos(this.currentIPPosition + (int)pos.getX(),
this.currentBPPosition + (int)pos.getY());
int resolution = (int)Math.round(Math.max(fopimage.getHorizontalResolution(),
fopimage.getVerticalResolution()));
@@ -706,27 +785,72 @@ public class PCLRenderer extends PrintRenderer {
* @param foreignAttributes the foreign attributes containing rendering hints, or null
*/
public void renderDocument(Document doc, String ns, Rectangle2D pos, Map foreignAttributes) {
int x = currentIPPosition + (int) pos.getX();
int y = currentBPPosition + (int) pos.getY();
int width = (int)pos.getWidth();
int height = (int)pos.getHeight();
RendererContext context = createRendererContext(x, y, width, height, foreignAttributes);
renderXML(context, doc, ns);
}

/**
* Creates a RendererContext for an image.
* @param x the x coordinate (in millipoints)
* @param y the y coordinate (in millipoints)
* @param width the width of the image (in millipoints)
* @param height the height of the image (in millipoints)
* @param foreignAttributes a Map or foreign attributes, may be null
* @return the RendererContext
*/
protected RendererContext createRendererContext(int x, int y, int width, int height,
Map foreignAttributes) {
RendererContext context;
context = new RendererContext(this, MIME_TYPE);
context.setUserAgent(userAgent);

context.setProperty(RendererContextConstants.WIDTH,
new Integer((int) pos.getWidth()));
new Integer(width));
context.setProperty(RendererContextConstants.HEIGHT,
new Integer((int) pos.getHeight()));
new Integer(height));
context.setProperty(RendererContextConstants.XPOS,
new Integer(currentIPPosition + (int) pos.getX()));
new Integer(x));
context.setProperty(RendererContextConstants.YPOS,
new Integer(currentBPPosition + (int) pos.getY()));
new Integer(y));
context.setProperty(RendererContextConstants.PAGE_VIEWPORT,
getCurrentPageViewport());
if (foreignAttributes != null) {
context.setProperty(RendererContextConstants.FOREIGN_ATTRIBUTES, foreignAttributes);
}
renderXML(context, doc, ns);
return context;
}

/**
* Common method to render the background and borders for any inline area.
* The all borders and padding are drawn outside the specified area.
* @param area the inline area for which the background, border and padding is to be
* rendered
* @todo Copied from AbstractPathOrientedRenderer
*/
protected void renderInlineAreaBackAndBorders(InlineArea area) {
float x = currentIPPosition / 1000f;
float y = (currentBPPosition + area.getOffset()) / 1000f;
float width = area.getIPD() / 1000f;
float height = area.getBPD() / 1000f;
float borderPaddingStart = area.getBorderAndPaddingWidthStart() / 1000f;
float borderPaddingBefore = area.getBorderAndPaddingWidthBefore() / 1000f;
float bpwidth = borderPaddingStart
+ (area.getBorderAndPaddingWidthEnd() / 1000f);
float bpheight = borderPaddingBefore
+ (area.getBorderAndPaddingWidthAfter() / 1000f);
if (height != 0.0f || bpheight != 0.0f && bpwidth != 0.0f) {
drawBackAndBorders(area, x, y - borderPaddingBefore
, width + bpwidth
, height + bpheight);
}
}
/**
* Draw the background and borders. This draws the background and border
* traits for an area given the position.
@@ -742,127 +866,401 @@ public class PCLRenderer extends PrintRenderer {
try {
updatePrintDirection();
BorderProps bpsBefore = (BorderProps) area.getTrait(Trait.BORDER_BEFORE);
BorderProps bpsAfter = (BorderProps) area.getTrait(Trait.BORDER_AFTER);
BorderProps bpsStart = (BorderProps) area.getTrait(Trait.BORDER_START);
BorderProps bpsEnd = (BorderProps) area.getTrait(Trait.BORDER_END);
// draw background
Trait.Background back;
back = (Trait.Background) area.getTrait(Trait.BACKGROUND);
if (back != null) {
// Calculate padding rectangle
float sx = startx;
float sy = starty;
float paddRectWidth = width;
float paddRectHeight = height;
if (bpsStart != null) {
sx += bpsStart.width / 1000f;
paddRectWidth -= bpsStart.width / 1000f;
}
if (bpsBefore != null) {
sy += bpsBefore.width / 1000f;
paddRectHeight -= bpsBefore.width / 1000f;
}
if (bpsEnd != null) {
paddRectWidth -= bpsEnd.width / 1000f;
}
if (bpsAfter != null) {
paddRectHeight -= bpsAfter.width / 1000f;
}
if (back.getColor() != null) {
Point2D p = transformedPoint(sx * 1000, sy * 1000);
gen.fillRect((int)p.getX(), (int)p.getY(),
(int)paddRectWidth * 1000, (int)paddRectHeight * 1000,
back.getColor().getAWTColor());
}
// background image
if (back.getFopImage() != null) {
FopImage fopimage = back.getFopImage();
if (fopimage != null && fopimage.load(FopImage.DIMENSIONS)) {
saveGraphicsState();
clipRect(sx, sy, paddRectWidth, paddRectHeight);
int horzCount = (int) ((paddRectWidth * 1000 / fopimage
.getIntrinsicWidth()) + 1.0f);
int vertCount = (int) ((paddRectHeight * 1000 / fopimage
.getIntrinsicHeight()) + 1.0f);
if (back.getRepeat() == EN_NOREPEAT) {
horzCount = 1;
vertCount = 1;
} else if (back.getRepeat() == EN_REPEATX) {
vertCount = 1;
} else if (back.getRepeat() == EN_REPEATY) {
horzCount = 1;
}
// change from points to millipoints
sx *= 1000;
sy *= 1000;
if (horzCount == 1) {
sx += back.getHoriz();
}
if (vertCount == 1) {
sy += back.getVertical();
}
for (int x = 0; x < horzCount; x++) {
for (int y = 0; y < vertCount; y++) {
// place once
Rectangle2D pos;
pos = new Rectangle2D.Float(sx
+ (x * fopimage.getIntrinsicWidth()), sy
+ (y * fopimage.getIntrinsicHeight()),
fopimage.getIntrinsicWidth(), fopimage
.getIntrinsicHeight());
//putImage(back.getURL(), pos); // TODO test
BorderProps bpsAfter = (BorderProps) area.getTrait(Trait.BORDER_AFTER);
BorderProps bpsStart = (BorderProps) area.getTrait(Trait.BORDER_START);
BorderProps bpsEnd = (BorderProps) area.getTrait(Trait.BORDER_END);
// draw background
Trait.Background back;
back = (Trait.Background) area.getTrait(Trait.BACKGROUND);
if (back != null) {
// Calculate padding rectangle
float sx = startx;
float sy = starty;
float paddRectWidth = width;
float paddRectHeight = height;
if (bpsStart != null) {
sx += bpsStart.width / 1000f;
paddRectWidth -= bpsStart.width / 1000f;
}
if (bpsBefore != null) {
sy += bpsBefore.width / 1000f;
paddRectHeight -= bpsBefore.width / 1000f;
}
if (bpsEnd != null) {
paddRectWidth -= bpsEnd.width / 1000f;
}
if (bpsAfter != null) {
paddRectHeight -= bpsAfter.width / 1000f;
}
if (back.getColor() != null) {
updateFillColor(back.getColor().getAWTColor());
fillRect(sx, sy, paddRectWidth, paddRectHeight);
}
// background image
if (back.getFopImage() != null) {
FopImage fopimage = back.getFopImage();
if (fopimage != null && fopimage.load(FopImage.DIMENSIONS)) {
saveGraphicsState();
clipRect(sx, sy, paddRectWidth, paddRectHeight);
int horzCount = (int) ((paddRectWidth * 1000 / fopimage
.getIntrinsicWidth()) + 1.0f);
int vertCount = (int) ((paddRectHeight * 1000 / fopimage
.getIntrinsicHeight()) + 1.0f);
if (back.getRepeat() == EN_NOREPEAT) {
horzCount = 1;
vertCount = 1;
} else if (back.getRepeat() == EN_REPEATX) {
vertCount = 1;
} else if (back.getRepeat() == EN_REPEATY) {
horzCount = 1;
}
// change from points to millipoints
sx *= 1000;
sy *= 1000;
if (horzCount == 1) {
sx += back.getHoriz();
}
if (vertCount == 1) {
sy += back.getVertical();
}
for (int x = 0; x < horzCount; x++) {
for (int y = 0; y < vertCount; y++) {
// place once
Rectangle2D pos;
// Image positions are relative to the currentIP/BP
pos = new Rectangle2D.Float(
sx - currentIPPosition
+ (x * fopimage.getIntrinsicWidth()),
sy - currentBPPosition
+ (y * fopimage.getIntrinsicHeight()),
fopimage.getIntrinsicWidth(),
fopimage.getIntrinsicHeight());
drawImage(back.getURL(), pos, null);
}
}
restoreGraphicsState();
} else {
log.warn(
"Can't find background image: " + back.getURL());
}
restoreGraphicsState();
} else {
log.warn(
"Can't find background image: " + back.getURL());
}
}
Rectangle2D.Float borderRect = new Rectangle2D.Float(startx, starty, width, height);
drawBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
} catch (IOException ioe) {
handleIOTrouble(ioe);
}
/*
// draw border
// BORDER_BEFORE
}

/**
* Draws borders.
* @param borderRect the border rectangle
* @param bpsBefore the border specification on the before side
* @param bpsAfter the border specification on the after side
* @param bpsStart the border specification on the start side
* @param bpsEnd the border specification on the end side
*/
protected void drawBorders(Rectangle2D.Float borderRect,
final BorderProps bpsBefore, final BorderProps bpsAfter,
final BorderProps bpsStart, final BorderProps bpsEnd) {
if (bpsBefore == null && bpsAfter == null && bpsStart == null && bpsEnd == null) {
return; //no borders to paint
}
if (qualityBeforeSpeed) {
drawQualityBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
} else {
drawFastBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
}
}
/**
* Draws borders. Borders are drawn as shaded rectangles with no clipping.
* @param borderRect the border rectangle
* @param bpsBefore the border specification on the before side
* @param bpsAfter the border specification on the after side
* @param bpsStart the border specification on the start side
* @param bpsEnd the border specification on the end side
*/
protected void drawFastBorders(Rectangle2D.Float borderRect,
final BorderProps bpsBefore, final BorderProps bpsAfter,
final BorderProps bpsStart, final BorderProps bpsEnd) {
float startx = borderRect.x;
float starty = borderRect.y;
float width = borderRect.width;
float height = borderRect.height;
if (bpsBefore != null) {
int borderWidth = (int) Math.round((bpsBefore.width / 1000f));
state.updateColor(bpsBefore.color);
state.getGraph().fillRect((int) startx, (int) starty, (int) width,
updateFillColor(bpsBefore.color.getAWTColor());
fillRect((int) startx, (int) starty, (int) width,
borderWidth);
}
// BORDER_AFTER
if (bpsAfter != null) {
int borderWidth = (int) Math.round((bpsAfter.width / 1000f));
float sy = starty + height;
state.updateColor(bpsAfter.color);
state.getGraph().fillRect((int) startx,
updateFillColor(bpsAfter.color.getAWTColor());
fillRect((int) startx,
(int) (starty + height - borderWidth), (int) width,
borderWidth);
}
// BORDER_START
if (bpsStart != null) {
int borderWidth = (int) Math.round((bpsStart.width / 1000f));
state.updateColor(bpsStart.color);
state.getGraph().fillRect((int) startx, (int) starty, borderWidth,
updateFillColor(bpsStart.color.getAWTColor());
fillRect((int) startx, (int) starty, borderWidth,
(int) height);
}
// BORDER_END
if (bpsEnd != null) {
int borderWidth = (int) Math.round((bpsEnd.width / 1000f));
float sx = startx + width;
state.updateColor(bpsEnd.color);
state.getGraph().fillRect((int) (startx + width - borderWidth),
updateFillColor(bpsEnd.color.getAWTColor());
fillRect((int) (startx + width - borderWidth),
(int) starty, borderWidth, (int) height);
}
*/
}
/**
* Draws borders. Borders are drawn in-memory and painted as a bitmap.
* @param borderRect the border rectangle
* @param bpsBefore the border specification on the before side
* @param bpsAfter the border specification on the after side
* @param bpsStart the border specification on the start side
* @param bpsEnd the border specification on the end side
*/
protected void drawQualityBorders(Rectangle2D.Float borderRect,
final BorderProps bpsBefore, final BorderProps bpsAfter,
final BorderProps bpsStart, final BorderProps bpsEnd) {
Graphics2DAdapter g2a = getGraphics2DAdapter();
final Rectangle.Float effBorderRect = new Rectangle2D.Float(
borderRect.x - (currentIPPosition / 1000f),
borderRect.y - (currentBPPosition / 1000f),
borderRect.width, borderRect.height);
final Rectangle paintRect = new Rectangle(
(int)Math.round(borderRect.x * 1000),
(int)Math.round(borderRect.y * 1000),
(int)Math.floor(borderRect.width * 1000) + 1,
(int)Math.floor(borderRect.height * 1000) + 1);
int xoffset = (bpsStart != null ? bpsStart.width : 0);
paintRect.x += xoffset;
paintRect.width += xoffset;
paintRect.width += (bpsEnd != null ? bpsEnd.width : 0);
RendererContext rc = createRendererContext(paintRect.x, paintRect.y,
paintRect.width, paintRect.height, null);
if (false) {
Map atts = new java.util.HashMap();
atts.put(new QName(ExtensionElementMapping.URI, null, "conversion-mode"), "bitmap");
rc.setProperty(RendererContextConstants.FOREIGN_ATTRIBUTES, atts);
}
Graphics2DImagePainter painter = new Graphics2DImagePainter() {

public void paint(Graphics2D g2d, Rectangle2D area) {
g2d.translate((bpsStart != null ? bpsStart.width : 0), 0);
g2d.scale(1000, 1000);
float startx = effBorderRect.x;
float starty = effBorderRect.y;
float width = effBorderRect.width;
float height = effBorderRect.height;
boolean[] b = new boolean[] {
(bpsBefore != null), (bpsEnd != null),
(bpsAfter != null), (bpsStart != null)};
if (!b[0] && !b[1] && !b[2] && !b[3]) {
return;
}
float[] bw = new float[] {
(b[0] ? bpsBefore.width / 1000f : 0.0f),
(b[1] ? bpsEnd.width / 1000f : 0.0f),
(b[2] ? bpsAfter.width / 1000f : 0.0f),
(b[3] ? bpsStart.width / 1000f : 0.0f)};
float[] clipw = new float[] {
BorderProps.getClippedWidth(bpsBefore) / 1000f,
BorderProps.getClippedWidth(bpsEnd) / 1000f,
BorderProps.getClippedWidth(bpsAfter) / 1000f,
BorderProps.getClippedWidth(bpsStart) / 1000f};
starty += clipw[0];
height -= clipw[0];
height -= clipw[2];
startx += clipw[3];
width -= clipw[3];
width -= clipw[1];
boolean[] slant = new boolean[] {
(b[3] && b[0]), (b[0] && b[1]), (b[1] && b[2]), (b[2] && b[3])};
if (bpsBefore != null) {
//endTextObject();

float sx1 = startx;
float sx2 = (slant[0] ? sx1 + bw[3] - clipw[3] : sx1);
float ex1 = startx + width;
float ex2 = (slant[1] ? ex1 - bw[1] + clipw[1] : ex1);
float outery = starty - clipw[0];
float clipy = outery + clipw[0];
float innery = outery + bw[0];

//saveGraphicsState();
Graphics2D g = (Graphics2D)g2d.create();
moveTo(sx1, clipy);
float sx1a = sx1;
float ex1a = ex1;
if (bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
sx1a -= clipw[3];
}
if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
ex1a += clipw[1];
}
lineTo(sx1a, outery);
lineTo(ex1a, outery);
}
lineTo(ex1, clipy);
lineTo(ex2, innery);
lineTo(sx2, innery);
closePath();
//clip();
g.clip(currentPath);
currentPath = null;
Rectangle2D.Float lineRect = new Rectangle2D.Float(
sx1a, outery, ex1a - sx1a, innery - outery);
Java2DRenderer.drawBorderLine(lineRect, true, true,
bpsBefore.style, toColor(bpsBefore.color), g);
//restoreGraphicsState();
}
if (bpsEnd != null) {
//endTextObject();

float sy1 = starty;
float sy2 = (slant[1] ? sy1 + bw[0] - clipw[0] : sy1);
float ey1 = starty + height;
float ey2 = (slant[2] ? ey1 - bw[2] + clipw[2] : ey1);
float outerx = startx + width + clipw[1];
float clipx = outerx - clipw[1];
float innerx = outerx - bw[1];
//saveGraphicsState();
Graphics2D g = (Graphics2D)g2d.create();
moveTo(clipx, sy1);
float sy1a = sy1;
float ey1a = ey1;
if (bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
sy1a -= clipw[0];
}
if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
ey1a += clipw[2];
}
lineTo(outerx, sy1a);
lineTo(outerx, ey1a);
}
lineTo(clipx, ey1);
lineTo(innerx, ey2);
lineTo(innerx, sy2);
closePath();
//clip();
g.setClip(currentPath);
currentPath = null;
Rectangle2D.Float lineRect = new Rectangle2D.Float(
innerx, sy1a, outerx - innerx, ey1a - sy1a);
Java2DRenderer.drawBorderLine(lineRect, false, false,
bpsEnd.style, toColor(bpsEnd.color), g);
//restoreGraphicsState();
}
if (bpsAfter != null) {
//endTextObject();

float sx1 = startx;
float sx2 = (slant[3] ? sx1 + bw[3] - clipw[3] : sx1);
float ex1 = startx + width;
float ex2 = (slant[2] ? ex1 - bw[1] + clipw[1] : ex1);
float outery = starty + height + clipw[2];
float clipy = outery - clipw[2];
float innery = outery - bw[2];

//saveGraphicsState();
Graphics2D g = (Graphics2D)g2d.create();
moveTo(ex1, clipy);
float sx1a = sx1;
float ex1a = ex1;
if (bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
sx1a -= clipw[3];
}
if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
ex1a += clipw[1];
}
lineTo(ex1a, outery);
lineTo(sx1a, outery);
}
lineTo(sx1, clipy);
lineTo(sx2, innery);
lineTo(ex2, innery);
closePath();
//clip();
g.setClip(currentPath);
currentPath = null;
Rectangle2D.Float lineRect = new Rectangle2D.Float(
sx1a, innery, ex1a - sx1a, outery - innery);
Java2DRenderer.drawBorderLine(lineRect, true, false,
bpsAfter.style, toColor(bpsAfter.color), g);
//restoreGraphicsState();
}
if (bpsStart != null) {
//endTextObject();

float sy1 = starty;
float sy2 = (slant[0] ? sy1 + bw[0] - clipw[0] : sy1);
float ey1 = sy1 + height;
float ey2 = (slant[3] ? ey1 - bw[2] + clipw[2] : ey1);
float outerx = startx - clipw[3];
float clipx = outerx + clipw[3];
float innerx = outerx + bw[3];

//saveGraphicsState();
Graphics2D g = (Graphics2D)g2d.create();
moveTo(clipx, ey1);
float sy1a = sy1;
float ey1a = ey1;
if (bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
sy1a -= clipw[0];
}
if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
ey1a += clipw[2];
}
lineTo(outerx, ey1a);
lineTo(outerx, sy1a);
}
lineTo(clipx, sy1);
lineTo(innerx, sy2);
lineTo(innerx, ey2);
closePath();
//clip();
g.setClip(currentPath);
currentPath = null;
Rectangle2D.Float lineRect = new Rectangle2D.Float(
outerx, sy1a, innerx - outerx, ey1a - sy1a);
Java2DRenderer.drawBorderLine(lineRect, false, false,
bpsStart.style, toColor(bpsStart.color), g);
//restoreGraphicsState();
}
}

public Dimension getImageSize() {
return paintRect.getSize();
}
};
try {
g2a.paintImage(painter, rc,
paintRect.x - xoffset, paintRect.y, paintRect.width, paintRect.height);
} catch (IOException ioe) {
handleIOTrouble(ioe);
}
}

}

+ 26
- 24
src/sandbox/org/apache/fop/render/pcl/PCLSVGHandler.java View File

@@ -86,33 +86,35 @@ public class PCLSVGHandler implements XMLHandler, RendererContextConstants {
int x = pclContext.getCurrentXPosition();
int y = pclContext.getCurrentYPosition();

SVGUserAgent ua = new SVGUserAgent(
context.getUserAgent().getSourcePixelUnitToMillimeter(),
new AffineTransform());
GVTBuilder builder = new GVTBuilder();
final BridgeContext ctx = new BridgeContext(ua);

final GraphicsNode root;
try {
root = builder.build(ctx, doc);
} catch (Exception e) {
log.error("SVG graphic could not be built: "
+ e.getMessage(), e);
return;
}

Graphics2DImagePainter painter = new Graphics2DImagePainter() {

public void paint(Graphics2D g2d, Rectangle2D area) {
SVGUserAgent ua = new SVGUserAgent(
context.getUserAgent().getSourcePixelUnitToMillimeter(),
new AffineTransform());
GVTBuilder builder = new GVTBuilder();
BridgeContext ctx = new BridgeContext(ua);

GraphicsNode root;
try {
root = builder.build(ctx, doc);
// If no viewbox is defined in the svg file, a viewbox of 100x100 is
// assumed, as defined in SVGUserAgent.getViewportSize()
float iw = (float) ctx.getDocumentSize().getWidth() * 1000f;
float ih = (float) ctx.getDocumentSize().getHeight() * 1000f;
float w = (float) area.getWidth();
float h = (float) area.getHeight();
g2d.scale(w / iw, h / ih);

root.paint(g2d);
} catch (Exception e) {
log.error("SVG graphic could not be built: "
+ e.getMessage(), e);
return;
}
// If no viewbox is defined in the svg file, a viewbox of 100x100 is
// assumed, as defined in SVGUserAgent.getViewportSize()
float iw = (float) ctx.getDocumentSize().getWidth();
float ih = (float) ctx.getDocumentSize().getHeight();
float w = (float) area.getWidth();
float h = (float) area.getHeight();
g2d.scale(w / iw, h / ih);

root.paint(g2d);
}

public Dimension getImageSize() {

+ 6
- 1
src/sandbox/org/apache/fop/render/svg/SVGRenderer.java View File

@@ -1,5 +1,5 @@
/*
* Copyright 1999-2005 The Apache Software Foundation.
* Copyright 1999-2006 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.
@@ -23,6 +23,7 @@ import org.apache.fop.area.CTM;
import org.apache.fop.area.PageViewport;
import org.apache.fop.area.LineArea;
import org.apache.fop.area.inline.ForeignObject;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.Leader;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.svg.SVGUtilities;
@@ -433,5 +434,9 @@ public class SVGRenderer extends AbstractRenderer {
// TODO Auto-generated method stub
}

protected void renderInlineAreaBackAndBorders(InlineArea area) {
// TODO Auto-generated method stub
}

}


Loading…
Cancel
Save