Browse Source

New addition: postscript renderer

Submitted by: Jeremias Maerki <jeremias.maerki@outline.ch>


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@194310 13f79535-47bb-0310-9956-ffa450edef68
pull/33/head
Keiron Liddle 23 years ago
parent
commit
01afddcb78

+ 149
- 0
src/org/apache/fop/render/ps/ASCII85EncodeFilter.java View File

@@ -0,0 +1,149 @@
/* $Id$
* Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
* For details on use and redistribution please refer to the
* LICENSE file included with these sources.
*/

package org.apache.fop.render.ps;

import java.io.*;

public class ASCII85EncodeFilter implements Filter {

private static final char ASCII85_ZERO = 'z';
private static final char ASCII85_START = '!';
private static final char ASCII85_EOL = '\n';
private static final String ASCII85_EOD = "~>";
private static final String ENCODING = "US-ASCII";

private static final long base85_4 = 85;
private static final long base85_3 = base85_4 * base85_4;
private static final long base85_2 = base85_3 * base85_4;
private static final long base85_1 = base85_2 * base85_4;

protected ASCII85EncodeFilter() {
}

public long write(OutputStream out, byte[] buf, int len,
long bw) throws IOException {
//Assumption: len<80
int line = (int)(bw % 80) + len;
if (line >= 80) {
int first = len - (line - 80);
out.write(buf, 0, first);
out.write(ASCII85_EOL);
out.write(buf, first, len - first);
} else {
out.write(buf, 0, len);
}
return bw + len;
}

public void doFilter(InputStream in,
OutputStream out) throws IOException {
int total = 0;
int diff = 0;
long bw = 0;

// first encode the majority of the data
// each 4 byte group becomes a 5 byte group
byte[] data = new byte[4];
int bytes_read;
while ((bytes_read = in.read(data)) == data.length) {
long val = ((data[0] << 24) & 0xff000000L)// note: must have the L at the
+ ((data[1] << 16) & 0xff0000L)// end, otherwise you get into
+ ((data[2] << 8) & 0xff00L)// weird signed value problems
+ (data[3] & 0xffL); // cause we're using a full 32 bits
byte[] conv = convertWord(val);

bw = write(out, conv, conv.length, bw);
}

// now take care of the trailing few bytes.
// with n leftover bytes, we append 0 bytes to make a full group of 4
// then convert like normal (except not applying the special zero rule)
// and write out the first n+1 bytes from the result
if ((bytes_read < data.length) && (bytes_read >= 0)) {
int n = data.length - bytes_read;
byte[] lastdata = new byte[4];
int i = 0;
for (int j = 0; j < 4; j++) {
if (j < n) {
lastdata[j] = data[i++];
} else {
lastdata[j] = 0;
}
}

long val = ((lastdata[0] << 24) & 0xff000000L) +
((lastdata[1] << 16) & 0xff0000L) +
((lastdata[2] << 8) & 0xff00L) + (lastdata[3] & 0xffL);

byte[] conv;
// special rule for handling zeros at the end
if (val != 0) {
conv = convertWord(val);
} else {
conv = new byte[5];
for (int j = 0; j < 5; j++) {
conv[j] = (byte)'!';
}
}
// assert n+1 <= 5
bw = write(out, conv, n + 1, bw);
// System.out.println("ASCII85 end of data was "+n+" bytes long");

}
// finally write the two character end of data marker
byte[] EOD = ASCII85_EOD.getBytes();
bw = write(out, EOD, EOD.length, bw);
}

/**
* This converts a 32 bit value (4 bytes) into 5 bytes using base 85.
* each byte in the result starts with zero at the '!' character so
* the resulting base85 number fits into printable ascii chars
*
* @param word the 32 bit unsigned (hence the long datatype) word
* @return 5 bytes (or a single byte of the 'z' character for word
* values of 0)
*/
private byte[] convertWord(long word) {
word = word & 0xffffffff;
if (word < 0) {
word = -word;
}

if (word == 0) {
byte[] result = { (byte) ASCII85_ZERO };
return result;
} else {
byte c1 = (byte)((word / base85_1) & 0xFF);
byte c2 = (byte)(((word - (c1 * base85_1)) / base85_2) & 0xFF);
byte c3 = (byte)( ((word - (c1 * base85_1) - (c2 * base85_2)) /
base85_3) & 0xFF);
byte c4 = (byte)( ((word - (c1 * base85_1) - (c2 * base85_2) -
(c3 * base85_3)) / base85_4) & 0xFF);
byte c5 = (byte)( ((word - (c1 * base85_1) - (c2 * base85_2) -
(c3 * base85_3) - (c4 * base85_4))) & 0xFF);

byte[] ret = {(byte)(c1 + ASCII85_START),
(byte)(c2 + ASCII85_START), (byte)(c3 + ASCII85_START),
(byte)(c4 + ASCII85_START), (byte)(c5 + ASCII85_START)};

for (int i = 0; i < ret.length; i++) {
if (ret[i] < 33 || ret[i] > 117) {
System.out.println("Illegal char value "+
new Integer(ret[i]));
}
}
return ret;
}
}


public static InputStream filter(InputStream in) throws IOException {
ASCII85EncodeFilter myfilter = new ASCII85EncodeFilter();
return FilterThread.filter(in, myfilter);
}
}

+ 68
- 0
src/org/apache/fop/render/ps/ASCIIHexEncodeFilter.java View File

@@ -0,0 +1,68 @@
/* $Id$
* Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
* For details on use and redistribution please refer to the
* LICENSE file included with these sources.
*/

package org.apache.fop.render.ps;

import java.io.*;

public class ASCIIHexEncodeFilter implements Filter {

private static final char ASCIIHEX_EOL = '\n';
private static final String ASCIIHEX_EOD = ">";
private static final String ENCODING = "US-ASCII";

protected ASCIIHexEncodeFilter() {
}

public long write(OutputStream out, byte[] buf, int len,
long bw) throws IOException {
boolean last = false;
int pos = 0;
int rest = len;
while (rest > 0) {
int restofline = 80 - (int)((bw + pos) % 80);
if (rest < restofline) {
//last line
restofline = rest;
last = true;
}
if (restofline > 0) {
out.write(buf, pos, restofline);
pos += restofline;
if (!last)
out.write(ASCIIHEX_EOL);
}
rest = len - pos;
}
return bw + len;
}

public void doFilter(InputStream in,
OutputStream out) throws IOException {
long bw = 0;
byte[] buf = new byte[2048];
int bytes_read;
StringBuffer sb = new StringBuffer(2048 * 2);
while ((bytes_read = in.read(buf)) != -1) {
sb.setLength(0);
for (int i = 0; i < bytes_read; i++) {
int val = (int)(buf[i] & 0xFF);
if (val < 16)
sb.append("0");
sb.append(Integer.toHexString(val));
}
bw = write(out, sb.toString().getBytes(ENCODING),
bytes_read * 2, bw);
}
byte[] eod = ASCIIHEX_EOD.getBytes(ENCODING);
bw = write(out, eod, eod.length, bw);
}

public static InputStream filter(InputStream in) throws IOException {
ASCIIHexEncodeFilter myfilter = new ASCIIHexEncodeFilter();
return FilterThread.filter(in, myfilter);
}
}

+ 18
- 0
src/org/apache/fop/render/ps/Filter.java View File

@@ -0,0 +1,18 @@
/* $Id$
* Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
* For details on use and redistribution please refer to the
* LICENSE file included with these sources.
*/

package org.apache.fop.render.ps;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;

public interface Filter {

public void doFilter(InputStream in,
OutputStream out) throws IOException;
}


+ 45
- 0
src/org/apache/fop/render/ps/FilterThread.java View File

@@ -0,0 +1,45 @@
/* $Id$
* Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
* For details on use and redistribution please refer to the
* LICENSE file included with these sources.
*/

package org.apache.fop.render.ps;

import java.io.*;

public class FilterThread extends Thread {

private Filter filter;
private InputStream in;
private OutputStream out;

private FilterThread(Filter filter, InputStream in, OutputStream out) {
this.filter = filter;
this.in = in;
this.out = out;
}

public void run() {
try {
try {
this.filter.doFilter(in, out);
this.out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
finally { this.filter = null;
this.in = null;
this.out = null;
} }

public static InputStream filter(InputStream in,
Filter filter) throws IOException {
PipedInputStream pin = new PipedInputStream();
PipedOutputStream pout = new PipedOutputStream(pin);
FilterThread thread = new FilterThread(filter, in, pout);
thread.start();
return pin;
}
}

+ 41
- 0
src/org/apache/fop/render/ps/FlateEncodeFilter.java View File

@@ -0,0 +1,41 @@
/* $Id$
* Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
* For details on use and redistribution please refer to the
* LICENSE file included with these sources.
*/

package org.apache.fop.render.ps;

import java.io.*;
import java.util.zip.DeflaterOutputStream;

public class FlateEncodeFilter implements Filter {

protected FlateEncodeFilter() {
}

private long copyStream(InputStream in, OutputStream out,
int bufferSize) throws IOException {
long bytes_total = 0;
byte[] buf = new byte[bufferSize];
int bytes_read;
while ((bytes_read = in.read(buf)) != -1) {
bytes_total += bytes_read;
out.write(buf, 0, bytes_read);
}
return bytes_total;
}

public void doFilter(InputStream in,
OutputStream out) throws IOException {
DeflaterOutputStream dout = new DeflaterOutputStream(out);
copyStream(in, dout, 2048);
//dout.flush();
dout.close();
}

public static InputStream filter(InputStream in) throws IOException {
FlateEncodeFilter myfilter = new FlateEncodeFilter();
return FilterThread.filter(in, myfilter);
}
}

+ 856
- 0
src/org/apache/fop/render/ps/PSRenderer.java View File

@@ -0,0 +1,856 @@
/* $Id$
* Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
* For details on use and redistribution please refer to the
* LICENSE file included with these sources.
*/

package org.apache.fop.render.ps;

// FOP
import org.apache.fop.messaging.MessageHandler;
import org.apache.fop.svg.SVGArea;
import org.apache.fop.render.Renderer;
import org.apache.fop.image.ImageArea;
import org.apache.fop.image.FopImage;
import org.apache.fop.image.FopImageException;
import org.apache.fop.layout.*;
import org.apache.fop.layout.inline.*;
import org.apache.fop.datatypes.*;
import org.apache.fop.fo.properties.*;
import org.apache.fop.render.pdf.Font;

// SVG
import org.w3c.dom.svg.SVGSVGElement;
import org.w3c.dom.svg.SVGDocument;

// Java
import java.io.*;
import java.util.*;

/**
* Renderer that renders to PostScript.
* <br>
* This class currently generates PostScript Level 2 code. The only exception
* is the FlateEncode filter which is a Level 3 feature. The filters in use
* are hardcoded at the moment.
* <br>
* This class follows the Document Structuring Conventions (DSC) version 3.0
* (If I did everything right). If anyone modifies this renderer please make
* sure to also follow the DSC to make it simpler to programmatically modify
* the generated Postscript files (ex. extract pages etc.).
* <br>
* TODO: Character size/spacing, SVG Transcoder for Batik, configuration, move
* to PrintRenderer, maybe improve filters (I'm not very proud of them), add a
* RunLengthEncode filter (useful for Level 2 Postscript), Improve
* DocumentProcessColors stuff (probably needs to be configurable, then maybe
* add a color to grayscale conversion for bitmaps to make output smaller (See
* PCLRenderer), font embedding, support different character encodings, try to
* implement image transparency, positioning of images is wrong etc.
*
* @author Jeremias Märki
*/
public class PSRenderer implements Renderer {

/** the application producing the PostScript */
protected String producer;

int imagecount = 0; //DEBUG

private boolean enableComments = true;

/** the stream used to output the PostScript */
protected PSStream out;
private boolean ioTrouble = false;

private String currentFontName;
private int currentFontSize;
private int pageHeight;
private int pageWidth;
private int currentXPosition = 0;
private int currentYPosition = 0;
private int currentAreaContainerXPosition = 0;
private float currRed;
private float currGreen;
private float currBlue;

protected Hashtable options;


/**
* set the document's producer
*
* @param producer string indicating application producing the PostScript
*/
public void setProducer(String producer) {
this.producer = producer;
}


/** set up renderer options */
public void setOptions(Hashtable options) {
this.options = options;
}


/**
* render the areas into PostScript
*
* @param areaTree the laid-out area tree
* @param stream the OutputStream to give the PostScript to
*/
public void render(AreaTree areaTree,
OutputStream stream) throws IOException {
MessageHandler.logln("rendering areas to PostScript");
this.out = new PSStream(stream);
write("%!PS-Adobe-3.0");
write("%%Creator: "+this.producer);
write("%%Pages: "+areaTree.getPages().size());
write("%%DocumentProcessColors: Black");
write("%%DocumentSuppliedResources: procset FOPFonts");
write("%%EndComments");
write("%%BeginDefaults");
write("%%EndDefaults");
write("%%BeginProlog");
write("%%EndProlog");
write("%%BeginSetup");
writeFontDict(areaTree.getFontInfo());
write("%%EndSetup");
write("FOPFonts begin");

comment("% --- AreaTree begin");
Enumeration e = areaTree.getPages().elements();
while (e.hasMoreElements()) {
this.renderPage((Page) e.nextElement());
}
comment("% --- AreaTree end");
write("%%Trailer");
write("%%EOF");
this.out.flush();
MessageHandler.logln("written out PostScript");
}


/**
* write out a command
*/
protected void write(String cmd) {
try {
out.write(cmd);
} catch (IOException e) {
if (!ioTrouble)
e.printStackTrace();
ioTrouble = true;
}
}


/**
* write out a comment
*/
protected void comment(String comment) {
if (this.enableComments)
write(comment);
}


protected void writeFontDict(FontInfo fontInfo) {
write("%%BeginResource: procset FOPFonts");
write("%%Title: Font setup (shortcuts) for this file");
write("/FOPFonts 100 dict dup begin");
write("/bd{bind def}bind def");
write("/ld{load def}bd");
write("/M/moveto ld");
write("/RM/rmoveto ld");
write("/t/show ld");

write("/ux 0.0 def");
write("/uy 0.0 def");
//write("/cf /Helvetica def");
//write("/cs 12000 def");

//<font> <size> F
write("/F {");
write(" /Tp exch def");
//write(" currentdict exch get");
write(" /Tf exch def");
write(" Tf findfont Tp scalefont setfont");
write(" /cf Tf def /cs Tp def /cw ( ) stringwidth pop def");
write("} bd");

write("/ULS {currentpoint /uy exch def /ux exch def} bd");
write("/ULE {");
write(" /Tcx currentpoint pop def");
write(" gsave");
write(" newpath");
write(" cf findfont cs scalefont dup");
write(" /FontMatrix get 0 get /Ts exch def /FontInfo get dup");
write(" /UnderlinePosition get Ts mul /To exch def");
write(" /UnderlineThickness get Ts mul /Tt exch def");
write(" ux uy To add moveto Tcx uy To add lineto");
write(" Tt setlinewidth stroke");
write(" grestore");
write("} bd");

write("/OLE {");
write(" /Tcx currentpoint pop def");
write(" gsave");
write(" newpath");
write(" cf findfont cs scalefont dup");
write(" /FontMatrix get 0 get /Ts exch def /FontInfo get dup");
write(" /UnderlinePosition get Ts mul /To exch def");
write(" /UnderlineThickness get Ts mul /Tt exch def");
write(" ux uy To add cs add moveto Tcx uy To add cs add lineto");
write(" Tt setlinewidth stroke");
write(" grestore");
write("} bd");

write("/SOE {");
write(" /Tcx currentpoint pop def");
write(" gsave");
write(" newpath");
write(" cf findfont cs scalefont dup");
write(" /FontMatrix get 0 get /Ts exch def /FontInfo get dup");
write(" /UnderlinePosition get Ts mul /To exch def");
write(" /UnderlineThickness get Ts mul /Tt exch def");
write(" ux uy To add cs 10 mul 26 idiv add moveto Tcx uy To add cs 10 mul 26 idiv add lineto");
write(" Tt setlinewidth stroke");
write(" grestore");
write("} bd");



//write("/gfF1{/Helvetica findfont} bd");
//write("/gfF3{/Helvetica-Bold findfont} bd");
Hashtable fonts = fontInfo.getFonts();
Enumeration enum = fonts.keys();
while (enum.hasMoreElements()) {
String key = (String) enum.nextElement();
Font fm = (Font) fonts.get(key);
write("/"+key + " /"+fm.fontName() + " def");
}
write("end def");
write("%%EndResource");
enum = fonts.keys();
while (enum.hasMoreElements()) {
String key = (String) enum.nextElement();
Font fm = (Font) fonts.get(key);
write("/"+fm.fontName() + " findfont");
write("dup length dict begin");
write(" {1 index /FID ne {def} {pop pop} ifelse} forall");
write(" /Encoding ISOLatin1Encoding def");
write(" currentdict");
write("end");
write("/"+fm.fontName() + " exch definefont pop");
}
}

protected void movetoCurrPosition() {
write(this.currentXPosition + " "+this.currentYPosition + " M");
}

/**
* set up the font info
*
* @param fontInfo the font info object to set up
*/
public void setupFontInfo(FontInfo fontInfo) {
/* use PDF's font setup to get PDF metrics */
org.apache.fop.render.pdf.FontSetup.setup(fontInfo);
}

/**
* render an area container to PostScript
*
* @param area the area container to render
*/
public void renderAreaContainer(AreaContainer area) {
int saveY = this.currentYPosition;
int saveX = this.currentAreaContainerXPosition;
if (area.getPosition() == Position.ABSOLUTE) {
// Y position is computed assuming positive Y axis, adjust for negative postscript one
this.currentYPosition =
area.getYPosition() - 2 * area.getPaddingTop() -
2 * area.getBorderTopWidth();
this.currentAreaContainerXPosition = area.getXPosition();
} else if (area.getPosition() == Position.RELATIVE) {
this.currentYPosition -= area.getYPosition();
this.currentAreaContainerXPosition += area.getXPosition();
} else if (area.getPosition() == Position.STATIC) {
this.currentYPosition -=
area.getPaddingTop() + area.getBorderTopWidth();
this.currentAreaContainerXPosition +=
area.getPaddingLeft() + area.getBorderLeftWidth();
}

this.currentXPosition = this.currentAreaContainerXPosition;

//comment("% --- AreaContainer begin");
doFrame(area);
Enumeration e = area.getChildren().elements();
while (e.hasMoreElements()) {
Box b = (Box) e.nextElement();
b.render(this);
}
//comment("% --- AreaContainer end");

if (area.getPosition() != Position.STATIC) {
this.currentYPosition = saveY;
this.currentAreaContainerXPosition = saveX;
} else {
this.currentYPosition -= area.getHeight();
}
}

/**
* render a body area container to PostScript
*
* @param area the body area container to render
*/
public void renderBodyAreaContainer(BodyAreaContainer area) {
int saveY = this.currentYPosition;
int saveX = this.currentAreaContainerXPosition;

if (area.getPosition() == Position.ABSOLUTE) {
// Y position is computed assuming positive Y axis, adjust for negative postscript one
this.currentYPosition = area.getYPosition();
this.currentAreaContainerXPosition = area.getXPosition();
} else if (area.getPosition() == Position.RELATIVE) {
this.currentYPosition -= area.getYPosition();
this.currentAreaContainerXPosition += area.getXPosition();
}

this.currentXPosition = this.currentAreaContainerXPosition;
int w, h;
int rx = this.currentAreaContainerXPosition;
w = area.getContentWidth();
h = area.getContentHeight();
int ry = this.currentYPosition;

//comment("% --- BodyAreaContainer begin");
doFrame(area);
//movetoCurrPosition();

Enumeration e = area.getChildren().elements();
while (e.hasMoreElements()) {
Box b = (Box) e.nextElement();
b.render(this);
}
//comment("% --- BodyAreaContainer end");

if (area.getPosition() != Position.STATIC) {
this.currentYPosition = saveY;
this.currentAreaContainerXPosition = saveX;
} else {
this.currentYPosition -= area.getHeight();
}
}

/**
* render a span area to PostScript
*
* @param area the span area to render
*/
public void renderSpanArea(SpanArea area) {
//comment("% --- SpanArea begin");
Enumeration e = area.getChildren().elements();
while (e.hasMoreElements()) {
Box b = (Box) e.nextElement();
b.render(this);
}
//comment("% --- SpanArea end");
}

/**
* render a block area to PostScript
*
* @param area the block area to render
*/
public void renderBlockArea(BlockArea area) {
//comment("% --- BlockArea begin");
doFrame(area);
Enumeration e = area.getChildren().elements();
while (e.hasMoreElements()) {
Box b = (Box) e.nextElement();
b.render(this);
}
//comment("% --- BlockArea end");
}

/**
* render a display space to PostScript
*
* @param space the space to render
*/
public void renderDisplaySpace(DisplaySpace space) {
//write("% --- DisplaySpace size="+space.getSize());
this.currentYPosition -= space.getSize();
movetoCurrPosition();
}

/** render a foreign object area */
public void renderForeignObjectArea(ForeignObjectArea area) {
// if necessary need to scale and align the content
area.getObject().render(this);
}

/**
* render an SVG area to PostScript
*
* @param area the area to render
*/
public void renderSVGArea(SVGArea area) {
int x = this.currentXPosition;
int y = this.currentYPosition;
SVGSVGElement svg =
((SVGDocument) area.getSVGDocument()).getRootElement();
int w = (int)(svg.getWidth().getBaseVal().getValue() * 1000);
int h = (int)(svg.getHeight().getBaseVal().getValue() * 1000);

comment("% --- SVG Area");
/**@todo Implement SVG */
comment("% --- SVG Area end");
movetoCurrPosition();
}

public void renderBitmap(FopImage img, int x, int y, int w, int h) {
try {
boolean iscolor = img.getColorSpace().getColorSpace() !=
ColorSpace.DEVICE_GRAY;
byte[] imgmap = img.getBitmaps();

write("gsave");
write("/DeviceRGB setcolorspace");
write(x + " "+(y - h) + " translate");
write(w + " "+h + " scale");
write("<<");
write(" /ImageType 1");
write(" /Width "+img.getWidth());
write(" /Height "+img.getHeight());
write(" /BitsPerComponent 8");
if (iscolor) {
write(" /Decode [0 1 0 1 0 1]");
} else {
write(" /Decode [0 1]");
}
//Setup scanning for left-to-right and top-to-bottom
write(" /ImageMatrix ["+img.getWidth() + " 0 0 -"+
img.getHeight() + " 0 "+img.getHeight() + "]");
write(" /DataSource currentfile /ASCII85Decode filter /FlateDecode filter");
//write(" /DataSource currentfile /ASCIIHexDecode filter /FlateDecode filter");
//write(" /DataSource currentfile /ASCII85Decode filter /RunLengthDecode filter");
//write(" /DataSource currentfile /ASCIIHexDecode filter /RunLengthDecode filter");
//write(" /DataSource currentfile /ASCIIHexDecode filter");
//write(" /DataSource currentfile /ASCII85Decode filter");
//write(" /DataSource currentfile /RunLengthDecode filter");
write(">>");
write("image");

/*
for (int y=0; y<img.getHeight(); y++) {
int indx = y * img.getWidth();
if (iscolor) indx*= 3;
for (int x=0; x<img.getWidth(); x++) {
if (iscolor) {
writeASCIIHex(imgmap[indx++] & 0xFF);
writeASCIIHex(imgmap[indx++] & 0xFF);
writeASCIIHex(imgmap[indx++] & 0xFF);
} else {
writeASCIIHex(imgmap[indx++] & 0xFF);
}
}
}*/
try {
//imgmap[0] = 1;
InputStream bain = new ByteArrayInputStream(imgmap);
InputStream in;
in = bain;
in = FlateEncodeFilter.filter(in);
//in = RunLengthEncodeFilter.filter(in);
//in = ASCIIHexEncodeFilter.filter(in);
in = ASCII85EncodeFilter.filter(in);
copyStream(in, this.out);
} catch (IOException e) {
if (!ioTrouble)
e.printStackTrace();
ioTrouble = true;
}

write("");
write("grestore");
}
catch (FopImageException e) {
e.printStackTrace();
MessageHandler.errorln(
"PSRenderer.renderImageArea(): Error rendering bitmap (" +
e.toString() + ")");
}
}

/**
* render an image area to PostScript
*
* @param area the area to render
*/
public void renderImageArea(ImageArea area) {
int x = this.currentAreaContainerXPosition + area.getXOffset();
int y = this.currentYPosition;
int w = area.getContentWidth();
int h = area.getHeight();
this.currentYPosition -= area.getHeight();

imagecount++;
//if (imagecount!=4) return;

comment("% --- ImageArea");
renderBitmap(area.getImage(), x, y, w, h);
comment("% --- ImageArea end");
}

private long copyStream(InputStream in, OutputStream out,
int bufferSize) throws IOException {
long bytes_total = 0;
byte[] buf = new byte[bufferSize];
int bytes_read;
while ((bytes_read = in.read(buf)) != -1) {
bytes_total += bytes_read;
out.write(buf, 0, bytes_read);
}
return bytes_total;
}


private long copyStream(InputStream in,
OutputStream out) throws IOException {
return copyStream(in, out, 4096);
}

/**
* render an inline area to PostScript
*
* @param area the area to render
*/
public void renderWordArea(WordArea area) {
FontState fs = area.getFontState();
String fontWeight = fs.getFontWeight();
StringBuffer sb = new StringBuffer();
String s = area.getText();
int l = s.length();
for (int i = 0; i < l; i++) {
char ch = s.charAt(i);
char mch = fs.mapChar(ch);
if (mch > 127) {
sb = sb.append("\\"+Integer.toOctalString(mch));
} else {
String escape = "\\()[]{}";
if (escape.indexOf(mch) >= 0) {
sb.append("\\");
}
sb = sb.append(mch);
}
}
//System.out.println("["+s+"] --> ["+sb.toString()+"]");

//comment("% --- InlineArea font-weight="+fontWeight+": " + sb.toString());
useFont(fs.getFontName(), fs.getFontSize());
useColor(area.getRed(), area.getGreen(), area.getBlue());
if (area.getUnderlined() || area.getLineThrough() ||
area.getOverlined())
write("ULS");
write("("+sb.toString() + ") t");
if (area.getUnderlined())
write("ULE");
if (area.getLineThrough())
write("SOE");
if (area.getOverlined())
write("OLE");
this.currentXPosition += area.getContentWidth();
}

public void useFont(String name, int size) {
if ((currentFontName != name) || (currentFontSize != size)) {
write(name + " "+size + " F");
currentFontName = name;
currentFontSize = size;
}
}

/**
* render an inline space to PostScript
*
* @param space the space to render
*/
public void renderInlineSpace(InlineSpace space) {
//write("% --- InlineSpace size="+space.getSize());
this.currentXPosition += space.getSize();
if (space.getUnderlined() || space.getLineThrough() ||
space.getOverlined())
write("ULS");
write(space.getSize() + " 0 RM");
if (space.getUnderlined())
write("ULE");
if (space.getLineThrough())
write("SOE");
if (space.getOverlined())
write("OLE");
}

/**
* render a line area to PostScript
*
* @param area the area to render
*/
public void renderLineArea(LineArea area) {
int rx = this.currentAreaContainerXPosition + area.getStartIndent();
int ry = this.currentYPosition;
int w = area.getContentWidth();
int h = area.getHeight();

this.currentYPosition -= area.getPlacementOffset();
this.currentXPosition = rx;

int bl = this.currentYPosition;
movetoCurrPosition();

String fontWeight = area.getFontState().getFontWeight();
//comment("% --- LineArea begin font-weight="+fontWeight);
Enumeration e = area.getChildren().elements();
while (e.hasMoreElements()) {
Box b = (Box) e.nextElement();
this.currentYPosition = ry - area.getPlacementOffset();
b.render(this);
}
//comment("% --- LineArea end");

this.currentYPosition = ry - h;
this.currentXPosition = rx;
}

/**
* render a page to PostScript
*
* @param page the page to render
*/
public void renderPage(Page page) {
BodyAreaContainer body;
AreaContainer before, after;
write("%%Page: "+page.getNumber() + " "+page.getNumber());
write("%%BeginPageSetup");
write("FOPFonts begin");
write("0.001 0.001 scale");
write("%%EndPageSetup");
body = page.getBody();
before = page.getBefore();
after = page.getAfter();
if (before != null) {
renderAreaContainer(before);
}
renderBodyAreaContainer(body);
if (after != null) {
renderAreaContainer(after);
}
write("showpage");
write("%%PageTrailer");
write("%%EndPage");
}

/**
* render a leader area to PostScript
*
* @param area the area to render
*/
public void renderLeaderArea(LeaderArea area) {
int rx = this.currentXPosition;
int ry = this.currentYPosition;
int w = area.getContentWidth();
int th = area.getRuleThickness();
int th2 = th / 2;
int th3 = th / 3;
int th4 = th / 4;

switch (area.getLeaderPattern()) {
case LeaderPattern.SPACE:
//NOP
break;
case LeaderPattern.RULE:
if (area.getRuleStyle() == RuleStyle.NONE)
break;
useColor(area.getRed(), area.getGreen(), area.getBlue());
write("gsave");
write("0 setlinecap");
switch (area.getRuleStyle()) {
case RuleStyle.DOTTED:
write("newpath");
write("[1000 3000] 0 setdash");
write(th + " setlinewidth");
write(rx + " "+ry + " M");
write(w + " 0 rlineto");
useColor(area.getRed(), area.getGreen(),
area.getBlue());
write("stroke");
break;
case RuleStyle.DASHED:
write("newpath");
write("[3000 3000] 0 setdash");
write(th + " setlinewidth");
write(rx + " "+ry + " M");
write(w + " 0 rlineto");
useColor(area.getRed(), area.getGreen(),
area.getBlue());
write("stroke");
break;
case RuleStyle.SOLID:
write("newpath");
write(th + " setlinewidth");
write(rx + " "+ry + " M");
write(w + " 0 rlineto");
useColor(area.getRed(), area.getGreen(),
area.getBlue());
write("stroke");
break;
case RuleStyle.DOUBLE:
write("newpath");
write(th3 + " setlinewidth");
write(rx + " "+(ry - th3) + " M");
write(w + " 0 rlineto");
write(rx + " "+(ry + th3) + " M");
write(w + " 0 rlineto");
useColor(area.getRed(), area.getGreen(),
area.getBlue());
write("stroke");
break;
case RuleStyle.GROOVE:
write(th2 + " setlinewidth");
write("newpath");
write(rx + " "+(ry - th4) + " M");
write(w + " 0 rlineto");
useColor(area.getRed(), area.getGreen(),
area.getBlue());
write("stroke");
write("newpath");
write(rx + " "+(ry + th4) + " M");
write(w + " 0 rlineto");
useColor(1, 1, 1); //white
write("stroke");
break;
case RuleStyle.RIDGE:
write(th2 + " setlinewidth");
write("newpath");
write(rx + " "+(ry - th4) + " M");
write(w + " 0 rlineto");
useColor(1, 1, 1); //white
write("stroke");
write("newpath");
write(rx + " "+(ry + th4) + " M");
write(w + " 0 rlineto");
useColor(area.getRed(), area.getGreen(),
area.getBlue());
write("stroke");
break;
}
write("grestore");
break;
case LeaderPattern.DOTS:
comment("% --- Leader dots NYI");
MessageHandler.errorln("Leader dots: Not yet implemented");
break;
case LeaderPattern.USECONTENT:
comment("% --- Leader use-content NYI");
MessageHandler.errorln("Leader use-content: Not yet implemented");
break;
}
this.currentXPosition += area.getContentWidth();
write(area.getContentWidth() + " 0 RM");
}

private void doFrame(Area area) {
int w, h;
int rx = this.currentAreaContainerXPosition;
w = area.getContentWidth();
BorderAndPadding bap = area.getBorderAndPadding();

if (area instanceof BlockArea)
rx += ((BlockArea) area).getStartIndent();

h = area.getContentHeight();
int ry = this.currentYPosition;

rx = rx - area.getPaddingLeft();
ry = ry + area.getPaddingTop();
w = w + area.getPaddingLeft() + area.getPaddingRight();
h = h + area.getPaddingTop() + area.getPaddingBottom();

rx = rx - area.getBorderLeftWidth();
ry = ry + area.getBorderTopWidth();
w = w + area.getBorderLeftWidth() + area.getBorderRightWidth();
h = h + area.getBorderTopWidth() + area.getBorderBottomWidth();

//Create a textrect with these dimensions.
//The y co-ordinate is measured +ve downwards so subtract page-height

ColorType bg = area.getBackgroundColor();
if ((bg != null) && (bg.alpha() == 0)) {
write("newpath");
write(rx + " "+ry + " M");
write(w + " 0 rlineto");
write("0 "+(-h) + " rlineto");
write((-w) + " 0 rlineto");
write("0 "+h + " rlineto");
write("closepath");
useColor(bg);
write("fill");
}


if (area.getBorderTopWidth() != 0) {
write("newpath");
write(rx + " "+ry + " M");
write(w + " 0 rlineto");
write(area.getBorderTopWidth() + " setlinewidth");
write("0 setlinecap");
useColor(bap.getBorderColor(BorderAndPadding.TOP));
write("stroke");
}
if (area.getBorderLeftWidth() != 0) {
write("newpath");
write(rx + " "+ry + " M");
write("0 "+(-h) + " rlineto");
write(area.getBorderLeftWidth() + " setlinewidth");
write("0 setlinecap");
useColor(bap.getBorderColor(BorderAndPadding.LEFT));
write("stroke");
}
if (area.getBorderRightWidth() != 0) {
write("newpath");
write((rx + w) + " "+ry + " M");
write("0 "+(-h) + " rlineto");
write(area.getBorderRightWidth() + " setlinewidth");
write("0 setlinecap");
useColor(bap.getBorderColor(BorderAndPadding.RIGHT));
write("stroke");
}
if (area.getBorderBottomWidth() != 0) {
write("newpath");
write(rx + " "+(ry - h) + " M");
write(w + " 0 rlineto");
write(area.getBorderBottomWidth() + " setlinewidth");
write("0 setlinecap");
useColor(bap.getBorderColor(BorderAndPadding.BOTTOM));
write("stroke");
}
}

private void useColor(ColorType col) {
useColor(col.red(), col.green(), col.blue());
}

private void useColor(float red, float green, float blue) {
if ((red != currRed) || (green != currGreen) ||
(blue != currBlue)) {
write(red + " "+green + " "+blue + " setrgbcolor");
currRed = red;
currGreen = green;
currBlue = blue;
}
}

}

+ 24
- 0
src/org/apache/fop/render/ps/PSStream.java View File

@@ -0,0 +1,24 @@
/* $Id$
* Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
* For details on use and redistribution please refer to the
* LICENSE file included with these sources.
*/

package org.apache.fop.render.ps;

import java.io.*;

public class PSStream extends FilterOutputStream {

public PSStream(OutputStream out) {
super(out);
}

public void write(String cmd) throws IOException {
if (cmd.length() > 255)
throw new RuntimeException("PostScript command exceeded limit of 255 characters");
write(cmd.getBytes("US-ASCII"));
write('\n');
}

}

Loading…
Cancel
Save