123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568 |
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /* $Id$ */
-
- package org.apache.fop.render.txt;
-
- import java.awt.Color;
- import java.awt.Point;
- import java.awt.geom.Rectangle2D;
- import java.io.IOException;
- import java.io.OutputStream;
- import java.util.List;
- import java.util.Map;
-
- import org.apache.fop.apps.FOPException;
- import org.apache.fop.area.Area;
- import org.apache.fop.area.CTM;
- import org.apache.fop.area.PageViewport;
- import org.apache.fop.area.inline.Image;
- import org.apache.fop.area.inline.TextArea;
- import org.apache.fop.render.AbstractPathOrientedRenderer;
- import org.apache.fop.render.txt.border.AbstractBorderElement;
- import org.apache.fop.render.txt.border.BorderManager;
-
- /**
- * Renderer that renders areas to plain text.
- *
- * @author Art Welch
- * @author <a href="mailto:mark-fop@inomial.com">Mark Lillywhite</a> (to use
- * the new Renderer interface)
- */
- public class TXTRenderer extends AbstractPathOrientedRenderer {
-
- private static final char LIGHT_SHADE = '\u2591';
-
- private static final char MEDIUM_SHADE = '\u2592';
-
- private static final char DARK_SHADE = '\u2593';
-
- private static final char FULL_BLOCK = '\u2588';
-
- private static final char IMAGE_CHAR = '#';
-
- /**The stream for output */
- private OutputStream outputStream;
-
- /** The current stream to add Text commands to. */
- private TXTStream currentStream;
-
- /** Buffer for text. */
- private StringBuffer[] charData;
-
- /** Buffer for background and images. */
- private StringBuffer[] decoData;
-
- /** Height of one symbol in Courier font size of 10pt. */
- public static final int CHAR_HEIGHT = 7860;
-
- /** Width of one symbol in Courier font size of 10pt. */
- public static final int CHAR_WIDTH = 6000;
-
- /** Current processing page width. */
- private int pageWidth;
-
- /** Current processing page height. */
- private int pageHeight;
-
- /**
- * Every line except the last line on a page (which will end with
- * pageEnding) will be terminated with this string.
- */
- private String lineEnding = "\r\n";
-
- /** Every page except the last one will end with this string. */
- private String pageEnding = "\f";
-
- /** Equals true, if current page is first. */
- private boolean firstPage = false;
-
- /** Manager for storing border's information. */
- private BorderManager bm;
-
- /** Char for current filling. */
- private char fillChar;
-
- /** Saves current coordinate transformation. */
- private TXTState currentState = new TXTState();
-
- private String encoding;
-
- /**
- * Constructs a newly allocated <code>TXTRenderer</code> object.
- */
- public TXTRenderer() {
- }
-
- /** @see org.apache.fop.render.AbstractRenderer#getMimeType() */
- public String getMimeType() {
- return "text/plain";
- }
-
- /**
- * Sets the encoding of the target file.
- * @param encoding the encoding, null to select the default encoding (UTF-8)
- */
- public void setEncoding(String encoding) {
- this.encoding = encoding;
- }
-
- /**
- * Indicates if point (x, y) lay inside currentPage.
- *
- * @param x x coordinate
- * @param y y coordinate
- * @return <b>true</b> if point lay inside page
- */
- public boolean isLayInside(int x, int y) {
- return (x >= 0) && (x < pageWidth) && (y >= 0) && (y < pageHeight);
- }
-
- /**
- * Add char to text buffer.
- *
- * @param x x coordinate
- * @param y y coordinate
- * @param ch char to add
- * @param ischar boolean, repersenting is character adding to text buffer
- */
- protected void addChar(int x, int y, char ch, boolean ischar) {
- Point point = currentState.transformPoint(x, y);
- putChar(point.x, point.y, ch, ischar);
- }
-
- /**
- * Add char to text or background buffer.
- *
- * @param x x coordinate
- * @param y x coordinate
- * @param ch char to add
- * @param ischar indicates if it char or background
- */
- protected void putChar(int x, int y, char ch, boolean ischar) {
- if (isLayInside(x, y)) {
- StringBuffer sb = ischar ? charData[y] : decoData[y];
- while (sb.length() <= x) {
- sb.append(' ');
- }
- sb.setCharAt(x, ch);
- }
- }
-
- /**
- * Adds string to text buffer (<code>charData</code>). <p>
- * Chars of string map in turn.
- *
- * @param row x coordinate
- * @param col y coordinate
- * @param s string to add
- */
- protected void addString(int row, int col, String s) {
- for (int l = 0; l < s.length(); l++) {
- addChar(col + l, row, s.charAt(l), true);
- }
- }
-
- /**
- * Render TextArea to Text.
- *
- * @param area inline area to render
- */
- protected void renderText(TextArea area) {
- int col = Helper.ceilPosition(this.currentIPPosition, CHAR_WIDTH);
- int row = Helper.ceilPosition(this.currentBPPosition, CHAR_HEIGHT);
-
- String s = area.getText();
-
- addString(row, col, s);
-
- super.renderText(area);
- }
-
- /**
- * @see org.apache.fop.render.Renderer#renderPage(PageViewport)
- */
- public void renderPage(PageViewport page) throws IOException, FOPException {
- if (firstPage) {
- firstPage = false;
- } else {
- currentStream.add(pageEnding);
- }
-
- Rectangle2D bounds = page.getViewArea();
- double width = bounds.getWidth();
- double height = bounds.getHeight();
-
- pageWidth = Helper.ceilPosition((int) width, CHAR_WIDTH);
- pageHeight = Helper.ceilPosition((int) height, CHAR_HEIGHT);
-
- // init buffers
- charData = new StringBuffer[pageHeight];
- decoData = new StringBuffer[pageHeight];
- for (int i = 0; i < pageHeight; i++) {
- charData[i] = new StringBuffer();
- decoData[i] = new StringBuffer();
- }
-
- bm = new BorderManager(pageWidth, pageHeight, currentState);
-
- super.renderPage(page);
-
- flushBorderToBuffer();
- flushBuffer();
- }
-
- /**
- * Projects current page borders (i.e.<code>bm</code>) to buffer for
- * background and images (i.e.<code>decoData</code>).
- */
- private void flushBorderToBuffer() {
- for (int x = 0; x < pageWidth; x++) {
- for (int y = 0; y < pageHeight; y++) {
- Character c = bm.getCharacter(x, y);
- if (c != null) {
- putChar(x, y, c.charValue(), false);
- }
- }
- }
- }
-
- /**
- * Write out the buffer to output stream.
- */
- private void flushBuffer() {
- for (int row = 0; row < pageHeight; row++) {
- StringBuffer cr = charData[row];
- StringBuffer dr = decoData[row];
- StringBuffer outr = null;
-
- if (cr != null && dr == null) {
- outr = cr;
- } else if (dr != null && cr == null) {
- outr = dr;
- } else if (cr != null && dr != null) {
- int len = dr.length();
- if (cr.length() > len) {
- len = cr.length();
- }
- outr = new StringBuffer();
- for (int countr = 0; countr < len; countr++) {
- if (countr < cr.length() && cr.charAt(countr) != ' ') {
- outr.append(cr.charAt(countr));
- } else if (countr < dr.length()) {
- outr.append(dr.charAt(countr));
- } else {
- outr.append(' ');
- }
- }
- }
-
- if (outr != null) {
- currentStream.add(outr.toString());
- }
- if (row < pageHeight) {
- currentStream.add(lineEnding);
- }
- }
- }
-
- /**
- * @see org.apache.fop.render.Renderer#startRenderer(java.io.OutputStream)
- */
- public void startRenderer(OutputStream os) throws IOException {
- log.info("Rendering areas to TEXT.");
- this.outputStream = os;
- currentStream = new TXTStream(os);
- currentStream.setEncoding(this.encoding);
- firstPage = true;
- }
-
- /**
- * @see org.apache.fop.render.Renderer#stopRenderer()
- */
- public void stopRenderer() throws IOException {
- log.info("writing out TEXT");
- outputStream.flush();
- super.stopRenderer();
- }
-
- /**
- * Does nothing.
- * @see org.apache.fop.render.AbstractPathOrientedRenderer
- */
- protected void restoreStateStackAfterBreakOut(List breakOutList) {
- }
-
- /**
- * Does nothing.
- * @return null
- * @see org.apache.fop.render.AbstractPathOrientedRenderer
- */
- protected List breakOutOfStateStack() {
- return null;
- }
-
- /**
- * Does nothing.
- * @see org.apache.fop.render.AbstractPathOrientedRenderer
- */
- protected void saveGraphicsState() {
- }
-
- /**
- * Does nothing.
- * @see org.apache.fop.render.AbstractPathOrientedRenderer
- */
- protected void restoreGraphicsState() {
- }
-
- /**
- * Does nothing.
- * @see org.apache.fop.render.AbstractPathOrientedRenderer
- */
- protected void beginTextObject() {
- }
-
- /**
- * Does nothing.
- * @see org.apache.fop.render.AbstractPathOrientedRenderer
- */
- protected void endTextObject() {
- }
-
- /**
- * Does nothing.
- * @see org.apache.fop.render.AbstractPathOrientedRenderer
- */
- protected void clip() {
- }
-
- /**
- * Does nothing.
- * @see org.apache.fop.render.AbstractPathOrientedRenderer
- */
- protected void clipRect(float x, float y, float width, float height) {
- }
-
- /**
- * Does nothing.
- * @see org.apache.fop.render.AbstractPathOrientedRenderer
- */
- protected void moveTo(float x, float y) {
- }
-
- /**
- * Does nothing.
- * @see org.apache.fop.render.AbstractPathOrientedRenderer
- */
- protected void lineTo(float x, float y) {
- }
-
- /**
- * Does nothing.
- * @see org.apache.fop.render.AbstractPathOrientedRenderer
- */
- protected void closePath() {
- }
-
- /**
- * Fills rectangle startX, startY, width, height with char
- * <code>charToFill</code>.
- *
- * @param startX x-coordinate of upper left point
- * @param startY y-coordinate of upper left point
- * @param width width of rectangle
- * @param height height of rectangle
- * @param charToFill filling char
- */
- private void fillRect(int startX, int startY, int width, int height,
- char charToFill) {
- for (int x = startX; x < startX + width; x++) {
- for (int y = startY; y < startY + height; y++) {
- addChar(x, y, charToFill, false);
- }
- }
- }
-
- /**
- * Fills a rectangular area with the current filling char.
- * @see org.apache.fop.render.AbstractPathOrientedRenderer
- */
- protected void fillRect(float x, float y, float width, float height) {
- fillRect(bm.getStartX(), bm.getStartY(), bm.getWidth(), bm.getHeight(),
- fillChar);
- }
-
- /**
- * Changes current filling char.
- * @see org.apache.fop.render.AbstractPathOrientedRenderer
- */
- protected void updateColor(Color col, boolean fill) {
- if (col == null) {
- return;
- }
- // fillShade evaluation was taken from fop-0.20.5
- // TODO: This fillShase is catually the luminance component of the color
- // transformed to the YUV (YPrBb) Colorspace. It should use standard
- // Java methods for its conversion instead of the formula given here.
- double fillShade = 0.30f / 255f * col.getRed()
- + 0.59f / 255f * col.getGreen()
- + 0.11f / 255f * col.getBlue();
- fillShade = 1 - fillShade;
-
- if (fillShade > 0.8f) {
- fillChar = FULL_BLOCK;
- } else if (fillShade > 0.6f) {
- fillChar = DARK_SHADE;
- } else if (fillShade > 0.4f) {
- fillChar = MEDIUM_SHADE;
- } else if (fillShade > 0.2f) {
- fillChar = LIGHT_SHADE;
- } else {
- fillChar = ' ';
- }
- }
-
- /**
- * @see org.apache.fop.render.AbstractPathOrientedRenderer#drawImage(
- * java.lang.String, java.awt.geom.Rectangle2D, java.util.Map)
- */
- protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes) {
- //No images are painted here
- }
-
- /**
- * Fills image rectangle with a <code>IMAGE_CHAR</code>.
- * @see org.apache.fop.render.AbstractPathOrientedRenderer
- */
- public void renderImage(Image image, Rectangle2D pos) {
- int x1 = Helper.ceilPosition(currentIPPosition, CHAR_WIDTH);
- int y1 = Helper.ceilPosition(currentBPPosition, CHAR_HEIGHT);
- int width = Helper.ceilPosition((int) pos.getWidth(), CHAR_WIDTH);
- int height = Helper.ceilPosition((int) pos.getHeight(), CHAR_HEIGHT);
-
- fillRect(x1, y1, width, height, IMAGE_CHAR);
- }
-
-
- /**
- * Returns the closest integer to the multiplication of a number and 1000.
- *
- * @param x the value of the argument, multiplied by
- * 1000 and rounded
- * @return the value of the argument multiplied by
- * 1000 and rounded to the nearest integer
- */
- protected int toMilli(float x) {
- return Math.round(x * 1000f);
- }
-
- /**
- * Adds one element of border.
- *
- * @param x x coordinate
- * @param y y coordinate
- * @param style integer, representing border style
- * @param type integer, representing border element type
- */
- private void addBitOfBorder(int x, int y, int style, int type) {
- Point point = currentState.transformPoint(x, y);
- if (isLayInside(point.x, point.y)) {
- bm.addBorderElement(point.x, point.y, style, type);
- }
- }
-
- /**
- * @see org.apache.fop.render.AbstractPathOrientedRenderer
- */
- protected void drawBorderLine(float x1, float y1, float x2, float y2,
- boolean horz, boolean startOrBefore, int style, Color col) {
-
- int borderHeight = bm.getHeight();
- int borderWidth = bm.getWidth();
- int borderStartX = bm.getStartX();
- int borderStartY = bm.getStartY();
-
- int x, y;
- if (horz && startOrBefore) { // BEFORE
- x = borderStartX;
- y = borderStartY;
- } else if (horz && !startOrBefore) { // AFTER
- x = borderStartX;
- y = borderStartY + borderHeight - 1;
- } else if (!horz && startOrBefore) { // START
- x = borderStartX;
- y = borderStartY;
- } else { // END
- x = borderStartX + borderWidth - 1;
- y = borderStartY;
- }
-
- int dx, dy, length, startType, endType;
- if (horz) {
- length = borderWidth;
- dx = 1;
- dy = 0;
- startType = 1 << AbstractBorderElement.RIGHT;
- endType = 1 << AbstractBorderElement.LEFT;
- } else {
- length = borderHeight;
- dx = 0;
- dy = 1;
- startType = 1 << AbstractBorderElement.DOWN;
- endType = 1 << AbstractBorderElement.UP;
- }
-
- addBitOfBorder(x, y, style, startType);
- for (int i = 0; i < length - 2; i++) {
- x += dx;
- y += dy;
- addBitOfBorder(x, y, style, startType + endType);
- }
- x += dx;
- y += dy;
- addBitOfBorder(x, y, style, endType);
- }
-
- /**
- * @see org.apache.fop.render.AbstractPathOrientedRenderer
- */
- protected void drawBackAndBorders(Area area, float startx, float starty,
- float width, float height) {
- bm.setWidth(Helper.ceilPosition(toMilli(width), CHAR_WIDTH));
- bm.setHeight(Helper.ceilPosition(toMilli(height), CHAR_HEIGHT));
- bm.setStartX(Helper.ceilPosition(toMilli(startx), CHAR_WIDTH));
- bm.setStartY(Helper.ceilPosition(toMilli(starty), CHAR_HEIGHT));
-
- super.drawBackAndBorders(area, startx, starty, width, height);
- }
-
- /**
- * @see org.apache.fop.render.AbstractRenderer#startVParea(CTM, Rectangle2D)
- */
- protected void startVParea(CTM ctm, Rectangle2D clippingRect) {
- currentState.push(ctm);
- }
-
- /**
- * @see org.apache.fop.render.AbstractRenderer#endVParea()
- */
- protected void endVParea() {
- currentState.pop();
- }
- }
|