All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.maven.doxia.module.rtf.RtfSink Maven / Gradle / Ivy

package org.apache.maven.doxia.module.rtf;

/*
 * 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.
 */

import java.awt.Color;

import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.Vector;

import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.doxia.sink.SinkEventAttributes;
import org.apache.maven.doxia.sink.impl.AbstractTextSink;

/**
 * RTF Sink implementation.
 *
 * @version $Id: RtfSink.java 1726411 2016-01-23 16:34:09Z hboutemy $
 * @since 1.0
 */
public class RtfSink
    extends AbstractTextSink
{
    /** Paper width, 21 cm */
    public static final double DEFAULT_PAPER_WIDTH = 21.;   /*cm*/

    /** Paper height, 29.7 cm */
    public static final double DEFAULT_PAPER_HEIGHT = 29.7; /*cm*/

    /** Paper top margin, 2 cm */
    public static final double DEFAULT_TOP_MARGIN = 2.;    /*cm*/

    /** Paper bottom margin, 2 cm */
    public static final double DEFAULT_BOTTOM_MARGIN = 2.; /*cm*/

    /** Paper left margin, 2 cm */
    public static final double DEFAULT_LEFT_MARGIN = 2.;   /*cm*/

    /** Paper right margin, 2 cm */
    public static final double DEFAULT_RIGHT_MARGIN = 2.;  /*cm*/

    /** Font size, 10 pts */
    public static final int DEFAULT_FONT_SIZE = 10; /*pts*/

    /** Spacing, 10 pts */
    public static final int DEFAULT_SPACING = 10;   /*pts*/

    /** Resolution, 72 dpi */
    public static final int DEFAULT_RESOLUTION = 72; /*dpi*/

    /** Image format, bmp */
    public static final String DEFAULT_IMAGE_FORMAT = "bmp";

    /** Image type, palette */
    public static final String DEFAULT_IMAGE_TYPE = "palette";

    /** Data format, ascii */
    public static final String DEFAULT_DATA_FORMAT = "ascii";

    /** Codepage, 1252 */
    public static final int DEFAULT_CODE_PAGE = 1252;

    /** Constant DEFAULT_CHAR_SET=0 */
    public static final int DEFAULT_CHAR_SET = 0;

    /** Constant IMG_FORMAT_BMP="bmp" */
    public static final String IMG_FORMAT_BMP = "bmp";

    /** Constant IMG_FORMAT_WMF="wmf" */
    public static final String IMG_FORMAT_WMF = "wmf";

    /** Constant IMG_TYPE_PALETTE="palette" */
    public static final String IMG_TYPE_PALETTE = "palette";

    /** Constant IMG_TYPE_RGB="rgb" */
    public static final String IMG_TYPE_RGB = "rgb";

    /** Constant IMG_DATA_ASCII="ascii" */
    public static final String IMG_DATA_ASCII = "ascii";

    /** Constant IMG_DATA_RAW="raw" */
    public static final String IMG_DATA_RAW = "raw";

    /** Constant STYLE_ROMAN=0 */
    public static final int STYLE_ROMAN = 0;

    /** Constant STYLE_ITALIC=1 */
    public static final int STYLE_ITALIC = 1;

    /** Constant STYLE_BOLD=2 */
    public static final int STYLE_BOLD = 2;

    /** Constant STYLE_TYPEWRITER=3 */
    public static final int STYLE_TYPEWRITER = 3;

    private static final int CONTEXT_UNDEFINED = 0;

    private static final int CONTEXT_VERBATIM = 1;

    private static final int CONTEXT_TABLE = 2;

    private static final int UNIT_MILLIMETER = 1;

    private static final int UNIT_CENTIMETER = 2;

    private static final int UNIT_INCH = 3;

    private static final int UNIT_PIXEL = 4;

    private static final int LIST_INDENT = 300; /*twips*/

    private static final String LIST_ITEM_HEADER = "-  ";

    private static final int DEFINITION_INDENT = 300; /*twips*/

    private static final int CELL_HORIZONTAL_PAD = 60; /*twips*/

    private static final int CELL_VERTICAL_PAD = 20;   /*twips*/

    private static final int BORDER_WIDTH = 15; /*twips*/

    private double paperWidth = DEFAULT_PAPER_WIDTH;

    private double paperHeight = DEFAULT_PAPER_HEIGHT;

    private double topMargin = DEFAULT_TOP_MARGIN;

    private double bottomMargin = DEFAULT_BOTTOM_MARGIN;

    private double leftMargin = DEFAULT_LEFT_MARGIN;

    private double rightMargin = DEFAULT_RIGHT_MARGIN;

    protected int fontSize = DEFAULT_FONT_SIZE;

    private int resolution = DEFAULT_RESOLUTION;

    private String imageFormat = DEFAULT_IMAGE_FORMAT;

    private String imageType = DEFAULT_IMAGE_TYPE;

    private String imageDataFormat = DEFAULT_DATA_FORMAT;

    private boolean imageCompression = true;

    private int codePage = DEFAULT_CODE_PAGE;

    private int charSet = DEFAULT_CHAR_SET;

    private final Hashtable fontTable;

    private Context context;

    private Paragraph paragraph;

    protected Indentation indentation;

    protected Space space;

    private int listItemIndent;

    private final Vector numbering;

    private final Vector itemNumber;

    private int style = STYLE_ROMAN;

    private int sectionLevel;

    private boolean emptyHeader;

    private StringBuilder verbatim;

    private boolean frame;

    private Table table;

    private Row row;

    private Cell cell;

    private Line line;

    protected PrintWriter writer;

    protected OutputStream stream; // for raw image data

    /** Map of warn messages with a String as key to describe the error type and a Set as value.
     * Using to reduce warn messages. */
    private Map warnMessages;

    // -----------------------------------------------------------------------

    /**
     * 

Constructor for RtfSink.

* * @throws java.io.IOException if any */ protected RtfSink() throws IOException { this( System.out ); } /** *

Constructor for RtfSink.

* * @param output not null * @throws java.io.IOException if any */ protected RtfSink( OutputStream output ) throws IOException { this( output, null ); } /** *

Constructor for RtfSink.

* * @param output not null * @param encoding a valid charset * @throws java.io.IOException if any */ protected RtfSink( OutputStream output, String encoding ) throws IOException { this.fontTable = new Hashtable(); this.numbering = new Vector(); this.itemNumber = new Vector(); Writer w; this.stream = new BufferedOutputStream( output ); // TODO: encoding should be consistent with codePage if ( encoding != null ) { w = new OutputStreamWriter( stream, encoding ); } else { w = new OutputStreamWriter( stream ); } this.writer = new PrintWriter( new BufferedWriter( w ) ); init(); } /** * setPaperSize. * * @param width in cm. * @param height in cm. */ public void setPaperSize( double width /*cm*/, double height /*cm*/ ) { paperWidth = width; paperHeight = height; } /** *

Setter for the field topMargin.

* * @param margin margin. */ public void setTopMargin( double margin ) { topMargin = margin; } /** *

Setter for the field bottomMargin.

* * @param margin margin. */ public void setBottomMargin( double margin ) { bottomMargin = margin; } /** *

Setter for the field leftMargin.

* * @param margin margin */ public void setLeftMargin( double margin ) { leftMargin = margin; } /** *

Setter for the field rightMargin.

* * @param margin margin */ public void setRightMargin( double margin ) { rightMargin = margin; } /** *

Setter for the field fontSize.

* * @param size in pts */ public void setFontSize( int size /*pts*/ ) { fontSize = size; } /** *

setSpacing.

* * @param spacing in pts. */ public void setSpacing( int spacing /*pts*/ ) { space.set( 20 * spacing ); } /** *

Setter for the field resolution.

* * @param resolution in dpi */ public void setResolution( int resolution /*dpi*/ ) { this.resolution = resolution; } /** *

Setter for the field imageFormat.

* * @param format */ public void setImageFormat( String format ) { imageFormat = format; } /** *

Setter for the field imageType.

* * @param type */ public void setImageType( String type ) { imageType = type; } /** *

Setter for the field imageDataFormat.

* * @param format */ public void setImageDataFormat( String format ) { imageDataFormat = format; } /** *

Setter for the field imageCompression.

* * @param compression */ public void setImageCompression( boolean compression ) { imageCompression = compression; } /** *

Setter for the field codePage.

* * @param cp */ public void setCodePage( int cp ) { codePage = cp; } /** *

Setter for the field charSet.

* * @param cs */ public void setCharSet( int cs ) { charSet = cs; } /** {@inheritDoc} */ public void head() { init(); writer.println( "{\\rtf1\\ansi\\ansicpg" + codePage + "\\deff0" ); writer.println( "{\\fonttbl" ); writer.println( "{\\f0\\froman\\fcharset" + charSet + " Times;}" ); writer.println( "{\\f1\\fmodern\\fcharset" + charSet + " Courier;}" ); writer.println( "}" ); writer.println( "{\\stylesheet" ); for ( int level = 1; level <= 5; ++level ) { writer.print( "{\\s" + styleNumber( level ) ); writer.print( "\\outlinelevel" + level ); writer.print( " Section Title " + level ); writer.println( ";}" ); } writer.println( "}" ); writer.println( "\\paperw" + toTwips( paperWidth, UNIT_CENTIMETER ) ); writer.println( "\\paperh" + toTwips( paperHeight, UNIT_CENTIMETER ) ); writer.println( "\\margl" + toTwips( leftMargin, UNIT_CENTIMETER ) ); writer.println( "\\margr" + toTwips( rightMargin, UNIT_CENTIMETER ) ); writer.println( "\\margt" + toTwips( topMargin, UNIT_CENTIMETER ) ); writer.println( "\\margb" + toTwips( bottomMargin, UNIT_CENTIMETER ) ); space.set( space.get() / 2 ); space.setNext( 0 ); emptyHeader = true; } /** {@inheritDoc} */ public void head_() { space.restore(); if ( emptyHeader ) { space.setNext( 0 ); } else { space.setNext( 2 * space.get() ); } } /** *

toTwips.

* * @param length a double. * @param unit a int. * @return a int. */ protected int toTwips( double length, int unit ) { double points; switch ( unit ) { case UNIT_MILLIMETER: points = ( length / 25.4 ) * 72.; break; case UNIT_CENTIMETER: points = ( length / 2.54 ) * 72.; break; case UNIT_INCH: points = length * 72.; break; case UNIT_PIXEL: default: points = ( length / resolution ) * 72.; break; } return (int) Math.rint( points * 20. ); } /** {@inheritDoc} */ public void title() { Paragraph p = new Paragraph( STYLE_BOLD, fontSize + 6 ); p.justification = Sink.JUSTIFY_CENTER; beginParagraph( p ); emptyHeader = false; } /** {@inheritDoc} */ public void title_() { endParagraph(); } /** {@inheritDoc} */ public void author() { Paragraph p = new Paragraph( STYLE_ROMAN, fontSize + 2 ); p.justification = Sink.JUSTIFY_CENTER; beginParagraph( p ); emptyHeader = false; } /** {@inheritDoc} */ public void author_() { endParagraph(); } /** {@inheritDoc} */ public void date() { Paragraph p = new Paragraph( STYLE_ROMAN, fontSize ); p.justification = Sink.JUSTIFY_CENTER; beginParagraph( p ); emptyHeader = false; } /** {@inheritDoc} */ public void date_() { endParagraph(); } /** {@inheritDoc} */ public void body() { // nop } /** {@inheritDoc} */ public void body_() { writer.println( "}" ); writer.flush(); } /** {@inheritDoc} */ public void section1() { sectionLevel = 1; } /** {@inheritDoc} */ public void section1_() { // nop } /** {@inheritDoc} */ public void section2() { sectionLevel = 2; } /** {@inheritDoc} */ public void section2_() { // nop } /** {@inheritDoc} */ public void section3() { sectionLevel = 3; } /** {@inheritDoc} */ public void section3_() { // nop } /** {@inheritDoc} */ public void section4() { sectionLevel = 4; } /** {@inheritDoc} */ public void section4_() { // nop } /** {@inheritDoc} */ public void section5() { sectionLevel = 5; } /** {@inheritDoc} */ public void section5_() { // nop } /** {@inheritDoc} */ public void sectionTitle() { int stl = STYLE_BOLD; int size = fontSize; switch ( sectionLevel ) { case 1: size = fontSize + 6; break; case 2: size = fontSize + 4; break; case 3: size = fontSize + 2; break; case 4: break; case 5: stl = STYLE_ROMAN; break; default: } Paragraph p = new Paragraph( stl, size ); p.style = styleNumber( sectionLevel ); beginParagraph( p ); } /** {@inheritDoc} */ public void sectionTitle_() { endParagraph(); } private int styleNumber( int level ) { return level; } /** {@inheritDoc} */ public void list() { indentation.add( LIST_INDENT ); space.set( space.get() / 2 ); } /** {@inheritDoc} */ public void list_() { indentation.restore(); space.restore(); } /** {@inheritDoc} */ public void listItem() { Paragraph p = new Paragraph(); p.leftIndent = indentation.get() + listItemIndent; p.firstLineIndent = ( -listItemIndent ); beginParagraph( p ); beginStyle( STYLE_BOLD ); writer.println( LIST_ITEM_HEADER ); endStyle(); indentation.add( listItemIndent ); space.set( space.get() / 2 ); } /** {@inheritDoc} */ public void listItem_() { endParagraph(); indentation.restore(); space.restore(); } /** {@inheritDoc} */ public void numberedList( int numbering ) { this.numbering.addElement( Integer.valueOf( numbering ) ); itemNumber.addElement( new Counter( 0 ) ); indentation.add( LIST_INDENT ); space.set( space.get() / 2 ); } /** {@inheritDoc} */ public void numberedList_() { numbering.removeElementAt( numbering.size() - 1 ); itemNumber.removeElementAt( itemNumber.size() - 1 ); indentation.restore(); space.restore(); } /** {@inheritDoc} */ public void numberedListItem() { ( (Counter) itemNumber.lastElement() ).increment(); int indent = 0; String header = getItemHeader(); Font font = getFont( STYLE_TYPEWRITER, fontSize ); if ( font != null ) { indent = textWidth( header, font ); } Paragraph p = new Paragraph(); p.leftIndent = indentation.get() + indent; p.firstLineIndent = ( -indent ); beginParagraph( p ); beginStyle( STYLE_TYPEWRITER ); writer.println( header ); endStyle(); indentation.add( indent ); space.set( space.get() / 2 ); } /** {@inheritDoc} */ public void numberedListItem_() { endParagraph(); indentation.restore(); space.restore(); } private String getItemHeader() { int nmb = ( (Integer) this.numbering.lastElement() ).intValue(); int iNmb = ( (Counter) this.itemNumber.lastElement() ).get(); StringBuilder buf = new StringBuilder(); switch ( nmb ) { case Sink.NUMBERING_DECIMAL: default: buf.append( iNmb ); buf.append( ". " ); while ( buf.length() < 4 ) { buf.append( ' ' ); } break; case Sink.NUMBERING_LOWER_ALPHA: buf.append( AlphaNumerals.toString( iNmb, true ) ); buf.append( ") " ); break; case Sink.NUMBERING_UPPER_ALPHA: buf.append( AlphaNumerals.toString( iNmb, false ) ); buf.append( ". " ); break; case Sink.NUMBERING_LOWER_ROMAN: buf.append( RomanNumerals.toString( iNmb, true ) ); buf.append( ") " ); while ( buf.length() < 6 ) { buf.append( ' ' ); } break; case Sink.NUMBERING_UPPER_ROMAN: buf.append( RomanNumerals.toString( iNmb, false ) ); buf.append( ". " ); while ( buf.length() < 6 ) { buf.append( ' ' ); } break; } return buf.toString(); } /** {@inheritDoc} */ public void definitionList() { int next = space.getNext(); indentation.add( LIST_INDENT ); space.set( space.get() / 2 ); space.setNext( next ); } /** {@inheritDoc} */ public void definitionList_() { indentation.restore(); space.restore(); } /** {@inheritDoc} */ public void definitionListItem() { int next = space.getNext(); space.set( space.get() / 2 ); space.setNext( next ); } /** {@inheritDoc} */ public void definitionListItem_() { space.restore(); } /** {@inheritDoc} */ public void definedTerm() { // nop } /** {@inheritDoc} */ public void definedTerm_() { endParagraph(); } /** {@inheritDoc} */ public void definition() { int next = space.getNext(); indentation.add( DEFINITION_INDENT ); space.set( space.get() / 2 ); space.setNext( next ); } /** {@inheritDoc} */ public void definition_() { endParagraph(); indentation.restore(); space.restore(); } /** {@inheritDoc} */ public void table() { // nop } /** {@inheritDoc} */ public void table_() { // nop } /** {@inheritDoc} */ public void tableRows( int[] justification, boolean grid ) { table = new Table( justification, grid ); context.set( CONTEXT_TABLE ); } /** {@inheritDoc} */ public void tableRows_() { boolean bb = false; boolean br = false; int offset = ( pageWidth() - ( table.width() + indentation.get() ) ) / 2; int x0 = indentation.get() + offset; space.skip(); for ( int i = 0; i < table.rows.size(); ++i ) { Row r = (Row) table.rows.elementAt( i ); writer.print( "\\trowd" ); writer.print( "\\trleft" + x0 ); writer.print( "\\trgaph" + CELL_HORIZONTAL_PAD ); writer.println( "\\trrh" + r.height() ); if ( table.grid ) { if ( i == ( table.rows.size() - 1 ) ) { bb = true; } br = false; } for ( int j = 0, x = x0; j < table.numColumns; ++j ) { if ( table.grid ) { if ( j == ( table.numColumns - 1 ) ) { br = true; } setBorder( true, bb, true, br ); x += BORDER_WIDTH; } x += table.columnWidths[j]; writer.println( "\\clvertalc\\cellx" + x ); } for ( int j = 0; j < table.numColumns; ++j ) { if ( j >= r.cells.size() ) { break; } Cell c = (Cell) r.cells.elementAt( j ); writer.print( "\\pard\\intbl" ); setJustification( table.justification[j] ); writer.println( "\\plain\\f0\\fs" + ( 2 * fontSize ) ); for ( int k = 0; k < c.lines.size(); ++k ) { if ( k > 0 ) { writer.println( "\\line" ); } Line l = (Line) c.lines.elementAt( k ); for ( int n = 0; n < l.items.size(); ++n ) { Item item = (Item) l.items.elementAt( n ); writer.print( "{" ); setStyle( item.style ); writer.println( escape( item.text ) ); writer.println( "}" ); } } writer.println( "\\cell" ); } writer.println( "\\row" ); } context.restore(); } private int pageWidth() { double width = paperWidth - ( leftMargin + rightMargin ); return toTwips( width, UNIT_CENTIMETER ); } private void setBorder( boolean bt, boolean bb, boolean bl, boolean br ) { if ( bt ) { writer.println( "\\clbrdrt\\brdrs\\brdrw" + BORDER_WIDTH ); } if ( bb ) { writer.println( "\\clbrdrb\\brdrs\\brdrw" + BORDER_WIDTH ); } if ( bl ) { writer.println( "\\clbrdrl\\brdrs\\brdrw" + BORDER_WIDTH ); } if ( br ) { writer.println( "\\clbrdrr\\brdrs\\brdrw" + BORDER_WIDTH ); } } private void setJustification( int justification ) { switch ( justification ) { case Sink.JUSTIFY_LEFT: default: writer.println( "\\ql" ); break; case Sink.JUSTIFY_CENTER: writer.println( "\\qc" ); break; case Sink.JUSTIFY_RIGHT: writer.println( "\\qr" ); break; } } private void setStyle( int style ) { switch ( style ) { case STYLE_ITALIC: writer.println( "\\i" ); break; case STYLE_BOLD: writer.println( "\\b" ); break; case STYLE_TYPEWRITER: writer.println( "\\f1" ); break; default: break; } } /** {@inheritDoc} */ public void tableRow() { row = new Row(); } /** {@inheritDoc} */ public void tableRow_() { table.add( row ); } /** {@inheritDoc} */ public void tableHeaderCell() { tableCell(); } /** {@inheritDoc} */ public void tableHeaderCell_() { tableCell_(); } /** {@inheritDoc} */ public void tableCell() { cell = new Cell(); line = new Line(); } /** {@inheritDoc} */ public void tableCell_() { cell.add( line ); row.add( cell ); } /** {@inheritDoc} */ public void tableCaption() { Paragraph p = new Paragraph(); p.justification = Sink.JUSTIFY_CENTER; p.spaceBefore /= 2; beginParagraph( p ); } /** {@inheritDoc} */ public void tableCaption_() { endParagraph(); } /** {@inheritDoc} */ public void paragraph() { if ( paragraph == null ) { beginParagraph( new Paragraph() ); } } /** {@inheritDoc} */ public void paragraph_() { endParagraph(); } private void beginParagraph( Paragraph p ) { p.begin(); this.paragraph = p; if ( style != STYLE_ROMAN ) { beginStyle( style ); } } private void endParagraph() { if ( paragraph != null ) { if ( style != STYLE_ROMAN ) { endStyle(); } paragraph.end(); paragraph = null; } } /** {@inheritDoc} */ public void verbatim( boolean boxed ) { verbatim = new StringBuilder(); frame = boxed; context.set( CONTEXT_VERBATIM ); } /** {@inheritDoc} */ public void verbatim_() { String text = verbatim.toString(); Paragraph p = new Paragraph(); p.fontStyle = STYLE_TYPEWRITER; p.frame = frame; beginParagraph( p ); StringTokenizer t = new StringTokenizer( text, EOL, true ); while ( t.hasMoreTokens() ) { String s = t.nextToken(); if ( s.equals( EOL ) && t.hasMoreTokens() ) { writer.println( "\\line" ); } else { writer.println( escape( s ) ); } } endParagraph(); context.restore(); } /** {@inheritDoc} */ public void figure() { // nop } /** {@inheritDoc} */ public void figure_() { // nop } /** {@inheritDoc} */ public void figureGraphics( String name ) { Paragraph p = new Paragraph(); p.justification = Sink.JUSTIFY_CENTER; beginParagraph( p ); try { writeImage( name ); } catch ( Exception e ) { getLog().error( e.getMessage(), e ); } endParagraph(); } private void writeImage( String source ) throws Exception { if ( !source.toLowerCase().endsWith( ".ppm" ) ) { // TODO support more image types! String msg = "Unsupported image type for image file: '" + source + "'. Only PPM image type is " + "currently supported."; logMessage( "unsupportedImage", msg ); return; } int bytesPerLine; PBMReader ppm = new PBMReader( source ); WMFWriter.Dib dib = new WMFWriter.Dib(); WMFWriter wmf = new WMFWriter(); int srcWidth = ppm.width(); int srcHeight = ppm.height(); dib.biWidth = srcWidth; dib.biHeight = srcHeight; dib.biXPelsPerMeter = (int) ( resolution * 100. / 2.54 ); dib.biYPelsPerMeter = dib.biXPelsPerMeter; if ( imageType.equals( IMG_TYPE_RGB ) ) { dib.biBitCount = 24; dib.biCompression = WMFWriter.Dib.BI_RGB; // no compression bytesPerLine = 4 * ( ( 3 * srcWidth + 3 ) / 4 ); dib.bitmap = new byte[srcHeight * bytesPerLine]; byte[] l = new byte[3 * srcWidth]; for ( int i = ( srcHeight - 1 ); i >= 0; --i ) { ppm.read( l, 0, l.length ); for ( int j = 0, k = ( i * bytesPerLine ); j < l.length; j += 3 ) { // component order = BGR dib.bitmap[k++] = l[j + 2]; dib.bitmap[k++] = l[j + 1]; dib.bitmap[k++] = l[j]; } } } else { dib.biBitCount = 8; bytesPerLine = 4 * ( ( srcWidth + 3 ) / 4 ); byte[] bitmap = new byte[srcHeight * bytesPerLine]; Vector colors = new Vector( 256 ); colors.addElement( Color.white ); colors.addElement( Color.black ); byte[] l = new byte[3 * srcWidth]; for ( int i = ( srcHeight - 1 ); i >= 0; --i ) { ppm.read( l, 0, l.length ); for ( int j = 0, k = ( i * bytesPerLine ); j < l.length; ) { int r = (int) l[j++] & 0xff; int g = (int) l[j++] & 0xff; int b = (int) l[j++] & 0xff; Color color = new Color( r, g, b ); int index = colors.indexOf( color ); if ( index < 0 ) { if ( colors.size() < colors.capacity() ) { colors.addElement( color ); index = colors.size() - 1; } else { index = 1; } } bitmap[k++] = (byte) index; } } dib.biClrUsed = colors.size(); dib.biClrImportant = dib.biClrUsed; dib.palette = new byte[4 * dib.biClrUsed]; for ( int i = 0, j = 0; i < dib.biClrUsed; ++i, ++j ) { Color color = (Color) colors.elementAt( i ); dib.palette[j++] = (byte) color.getBlue(); dib.palette[j++] = (byte) color.getGreen(); dib.palette[j++] = (byte) color.getRed(); } if ( imageCompression ) { dib.biCompression = WMFWriter.Dib.BI_RLE8; dib.bitmap = new byte[bitmap.length + ( 2 * ( bitmap.length / 255 + 1 ) )]; dib.biSizeImage = WMFWriter.Dib.rlEncode8( bitmap, 0, bitmap.length, dib.bitmap, 0 ); } else { dib.biCompression = WMFWriter.Dib.BI_RGB; dib.bitmap = bitmap; } } if ( imageFormat.equals( IMG_FORMAT_WMF ) ) { int[] parameters; WMFWriter.Record record; /* * See the libwmf library documentation * (http://www.wvware.com/wmf_doc_index.html) * for a description of WMF records. */ // set mapping mode to MM_TEXT (logical unit = pixel) parameters = new int[1]; parameters[0] = 1; record = new WMFWriter.Record( 0x0103, parameters ); wmf.add( record ); // set window origin and dimensions parameters = new int[2]; record = new WMFWriter.Record( 0x020b, parameters ); wmf.add( record ); parameters = new int[2]; parameters[0] = srcHeight; parameters[1] = srcWidth; record = new WMFWriter.Record( 0x020c, parameters ); wmf.add( record ); parameters = new int[WMFWriter.DibBitBltRecord.P_COUNT]; // raster operation = SRCCOPY (0x00cc0020) parameters[WMFWriter.DibBitBltRecord.P_ROP_H] = 0x00cc; parameters[WMFWriter.DibBitBltRecord.P_ROP_L] = 0x0020; parameters[WMFWriter.DibBitBltRecord.P_WIDTH] = srcWidth; parameters[WMFWriter.DibBitBltRecord.P_HEIGHT] = srcHeight; record = new WMFWriter.DibBitBltRecord( parameters, dib ); wmf.add( record ); } if ( imageFormat.equals( IMG_FORMAT_WMF ) ) { writer.print( "{\\pict\\wmetafile1" ); writer.println( "\\picbmp\\picbpp" + dib.biBitCount ); } else { writer.print( "{\\pict\\dibitmap0\\wbmplanes1" ); writer.print( "\\wbmbitspixel" + dib.biBitCount ); writer.println( "\\wbmwidthbytes" + bytesPerLine ); } writer.print( "\\picw" + srcWidth ); writer.print( "\\pich" + srcHeight ); writer.print( "\\picwgoal" + toTwips( srcWidth, UNIT_PIXEL ) ); writer.println( "\\pichgoal" + toTwips( srcHeight, UNIT_PIXEL ) ); if ( imageFormat.equals( IMG_FORMAT_WMF ) ) { if ( imageDataFormat.equals( IMG_DATA_RAW ) ) { writer.print( "\\bin" + ( 2 * wmf.size() ) + " " ); writer.flush(); wmf.write( stream ); stream.flush(); } else { wmf.print( writer ); } } else { if ( imageDataFormat.equals( IMG_DATA_RAW ) ) { writer.print( "\\bin" + ( 2 * dib.size() ) + " " ); writer.flush(); dib.write( stream ); stream.flush(); } else { dib.print( writer ); } } writer.println( "}" ); } /** {@inheritDoc} */ public void figureCaption() { Paragraph p = new Paragraph(); p.justification = Sink.JUSTIFY_CENTER; p.spaceBefore /= 2; beginParagraph( p ); } /** {@inheritDoc} */ public void figureCaption_() { endParagraph(); } /** {@inheritDoc} */ public void horizontalRule() { writer.print( "\\pard\\li" + indentation.get() ); int skip = space.getNext(); if ( skip > 0 ) { writer.print( "\\sb" + skip ); } space.setNext( skip ); writer.print( "\\brdrb\\brdrs\\brdrw" + BORDER_WIDTH ); writer.println( "\\plain\\fs1\\par" ); } /** {@inheritDoc} */ public void pageBreak() { writer.println( "\\page" ); } /** {@inheritDoc} */ public void anchor( String name ) { // nop } /** {@inheritDoc} */ public void anchor_() { // nop } /** {@inheritDoc} */ public void link( String name ) { // nop } /** {@inheritDoc} */ public void link_() { // nop } /** {@inheritDoc} */ public void italic() { beginStyle( STYLE_ITALIC ); } /** {@inheritDoc} */ public void italic_() { endStyle(); } /** {@inheritDoc} */ public void bold() { beginStyle( STYLE_BOLD ); } /** {@inheritDoc} */ public void bold_() { endStyle(); } /** {@inheritDoc} */ public void monospaced() { beginStyle( STYLE_TYPEWRITER ); } /** {@inheritDoc} */ public void monospaced_() { endStyle(); } private void beginStyle( int style ) { this.style = style; switch ( context.get() ) { case CONTEXT_TABLE: break; default: if ( paragraph != null ) { switch ( style ) { case STYLE_ITALIC: writer.println( "{\\i" ); break; case STYLE_BOLD: writer.println( "{\\b" ); break; case STYLE_TYPEWRITER: writer.println( "{\\f1" ); break; default: writer.println( "{" ); break; } } break; } } private void endStyle() { style = STYLE_ROMAN; switch ( context.get() ) { case CONTEXT_TABLE: break; default: if ( paragraph != null ) { writer.println( "}" ); } break; } } /** {@inheritDoc} */ public void lineBreak() { switch ( context.get() ) { case CONTEXT_TABLE: cell.add( line ); line = new Line(); break; default: writer.println( "\\line" ); break; } } /** {@inheritDoc} */ public void nonBreakingSpace() { switch ( context.get() ) { case CONTEXT_TABLE: line.add( new Item( style, " " ) ); break; default: writer.println( "\\~" ); break; } } /** {@inheritDoc} */ public void text( String text ) { switch ( context.get() ) { case CONTEXT_VERBATIM: verbatim.append( text ); break; case CONTEXT_TABLE: StringTokenizer t = new StringTokenizer( text, EOL, true ); while ( t.hasMoreTokens() ) { String token = t.nextToken(); if ( token.equals( EOL ) ) { cell.add( line ); line = new Line(); } else { line.add( new Item( style, normalize( token ) ) ); } } break; default: if ( paragraph == null ) { beginParagraph( new Paragraph() ); } writer.println( escape( normalize( text ) ) ); } } /** * {@inheritDoc} * * Unkown events just log a warning message but are ignored otherwise. * @see org.apache.maven.doxia.sink.Sink#unknown(String,Object[],SinkEventAttributes) */ public void unknown( String name, Object[] requiredParams, SinkEventAttributes attributes ) { String msg = "Unknown Sink event: '" + name + "', ignoring!"; logMessage( "unknownEvent", msg ); } private static String normalize( String s ) { int length = s.length(); StringBuilder buffer = new StringBuilder( length ); for ( int i = 0; i < length; ++i ) { char c = s.charAt( i ); if ( Character.isWhitespace( c ) ) { if ( buffer.length() == 0 || buffer.charAt( buffer.length() - 1 ) != ' ' ) { buffer.append( ' ' ); } } else { buffer.append( c ); } } return buffer.toString(); } private static String escape( String s ) { int length = s.length(); StringBuilder buffer = new StringBuilder( length ); for ( int i = 0; i < length; ++i ) { char c = s.charAt( i ); switch ( c ) { case '\\': buffer.append( "\\\\" ); break; case '{': buffer.append( "\\{" ); break; case '}': buffer.append( "\\}" ); break; default: buffer.append( c ); } } return buffer.toString(); } /** *

getFont.

* * @param style a int. * @param size a int. * @return a {@link org.apache.maven.doxia.module.rtf.Font} object. */ protected Font getFont( int style, int size ) { Font font = null; StringBuilder buf = new StringBuilder(); buf.append( style ); buf.append( size ); String key = buf.toString(); Object object = fontTable.get( key ); if ( object == null ) { try { font = new Font( style, size ); fontTable.put( key, font ); } catch ( Exception ignored ) { if ( getLog().isDebugEnabled() ) { getLog().debug( ignored.getMessage(), ignored ); } } } else { font = (Font) object; } return font; } private static int textWidth( String text, Font font ) { int width = 0; StringTokenizer t = new StringTokenizer( text, EOL ); while ( t.hasMoreTokens() ) { int w = font.textExtents( t.nextToken() ).width; if ( w > width ) { width = w; } } return width; } /** {@inheritDoc} */ public void flush() { writer.flush(); } /** {@inheritDoc} */ public void close() { writer.close(); if ( getLog().isWarnEnabled() && this.warnMessages != null ) { for ( Iterator it = this.warnMessages.entrySet().iterator(); it.hasNext(); ) { Map.Entry entry = (Map.Entry) it.next(); Set set = (Set) entry.getValue(); for ( Iterator it2 = set.iterator(); it2.hasNext(); ) { String msg = (String) it2.next(); getLog().warn( msg ); } } this.warnMessages = null; } init(); } /** * If debug mode is enabled, log the msg as is, otherwise add unique msg in warnMessages. * * @param key not null * @param msg not null * @see #close() * @since 1.1.1 */ private void logMessage( String key, String msg ) { msg = "[RTF Sink] " + msg; if ( getLog().isDebugEnabled() ) { getLog().debug( msg ); return; } if ( warnMessages == null ) { warnMessages = new HashMap(); } Set set = (Set) warnMessages.get( key ); if ( set == null ) { set = new TreeSet(); } set.add( msg ); warnMessages.put( key, set ); } /** {@inheritDoc} */ protected void init() { super.init(); this.fontTable.clear(); this.context = new Context(); this.paragraph = null; this.indentation = new Indentation( 0 ); this.space = new Space( 20 * DEFAULT_SPACING ); Font font = getFont( STYLE_BOLD, fontSize ); if ( font != null ) { this.listItemIndent = textWidth( LIST_ITEM_HEADER, font ); } this.numbering.clear(); this.itemNumber.clear(); this.style = STYLE_ROMAN; this.sectionLevel = 0; this.emptyHeader = false; this.verbatim = null; this.frame = false; this.table = null; this.row = null; this.cell = null; this.line = null; this.warnMessages = null; } // ----------------------------------------------------------------------- static class Counter { private int value; Counter( int value ) { set( value ); } void set( int value ) { this.value = value; } int get() { return value; } void increment() { increment( 1 ); } void increment( int value ) { this.value += value; } } static class Context { private int context = CONTEXT_UNDEFINED; private Vector stack = new Vector(); void set( int context ) { stack.addElement( Integer.valueOf( this.context ) ); this.context = context; } void restore() { if ( !stack.isEmpty() ) { context = ( (Integer) stack.lastElement() ).intValue(); stack.removeElementAt( stack.size() - 1 ); } } int get() { return context; } } class Paragraph { int style = 0; int justification = Sink.JUSTIFY_LEFT; int leftIndent = indentation.get(); int rightIndent = 0; int firstLineIndent = 0; int spaceBefore = space.getNext(); int spaceAfter = 0; boolean frame = false; int fontStyle = STYLE_ROMAN; int fontSize = RtfSink.this.fontSize; Paragraph() { // nop } Paragraph( int style, int size ) { fontStyle = style; fontSize = size; } void begin() { writer.print( "\\pard" ); if ( style > 0 ) { writer.print( "\\s" + style ); } switch ( justification ) { case Sink.JUSTIFY_LEFT: default: break; case Sink.JUSTIFY_CENTER: writer.print( "\\qc" ); break; case Sink.JUSTIFY_RIGHT: writer.print( "\\qr" ); break; } if ( leftIndent != 0 ) { writer.print( "\\li" + leftIndent ); } if ( rightIndent != 0 ) { writer.print( "\\ri" + rightIndent ); } if ( firstLineIndent != 0 ) { writer.print( "\\fi" + firstLineIndent ); } if ( spaceBefore != 0 ) { writer.print( "\\sb" + spaceBefore ); } if ( spaceAfter != 0 ) { writer.print( "\\sa" + spaceAfter ); } if ( frame ) { writer.print( "\\box\\brdrs\\brdrw" + BORDER_WIDTH ); } writer.print( "\\plain" ); switch ( fontStyle ) { case STYLE_ROMAN: default: writer.print( "\\f0" ); break; case STYLE_ITALIC: writer.print( "\\f0\\i" ); break; case STYLE_BOLD: writer.print( "\\f0\\b" ); break; case STYLE_TYPEWRITER: writer.print( "\\f1" ); break; } writer.println( "\\fs" + ( 2 * fontSize ) ); } void end() { writer.println( "\\par" ); } } class Space { private int space; private int next; private Vector stack = new Vector(); Space( int space /*twips*/ ) { this.space = space; next = space; } void set( int space /*twips*/ ) { stack.addElement( Integer.valueOf( this.space ) ); this.space = space; next = space; } int get() { return space; } void restore() { if ( !stack.isEmpty() ) { space = ( (Integer) stack.lastElement() ).intValue(); stack.removeElementAt( stack.size() - 1 ); next = space; } } void setNext( int space /*twips*/ ) { next = space; } int getNext() { int nxt = this.next; this.next = space; return nxt; } void skip() { skip( getNext() ); } void skip( int space /*twips*/ ) { writer.print( "\\pard" ); if ( ( space -= 10 ) > 0 ) { writer.print( "\\sb" + space ); } writer.println( "\\plain\\fs1\\par" ); } } static class Indentation { private int indent; private Vector stack = new Vector(); Indentation( int indent /*twips*/ ) { this.indent = indent; } void set( int indent /*twips*/ ) { stack.addElement( Integer.valueOf( this.indent ) ); this.indent = indent; } int get() { return indent; } void restore() { if ( !stack.isEmpty() ) { indent = ( (Integer) stack.lastElement() ).intValue(); stack.removeElementAt( stack.size() - 1 ); } } void add( int indent /*twips*/ ) { set( this.indent + indent ); } } static class Table { int numColumns; int[] columnWidths; int[] justification; boolean grid; Vector rows; Table( int[] justification, boolean grid ) { numColumns = justification.length; columnWidths = new int[numColumns]; this.justification = justification; this.grid = grid; rows = new Vector(); } void add( Row row ) { rows.addElement( row ); for ( int i = 0; i < numColumns; ++i ) { if ( i >= row.cells.size() ) { break; } Cell cell = (Cell) row.cells.elementAt( i ); int width = cell.boundingBox().width; if ( width > columnWidths[i] ) { columnWidths[i] = width; } } } int width() { int width = 0; for ( int i = 0; i < numColumns; ++i ) { width += columnWidths[i]; } if ( grid ) { width += ( numColumns + 1 ) * BORDER_WIDTH; } return width; } } static class Row { Vector cells = new Vector(); void add( Cell cell ) { cells.addElement( cell ); } int height() { int height = 0; int numCells = cells.size(); for ( int i = 0; i < numCells; ++i ) { Cell cell = (Cell) cells.elementAt( i ); Box box = cell.boundingBox(); if ( box.height > height ) { height = box.height; } } return height; } } class Cell { Vector lines = new Vector(); void add( Line line ) { lines.addElement( line ); } Box boundingBox() { int width = 0; int height = 0; for ( int i = 0; i < lines.size(); ++i ) { int w = 0; int h = 0; Line line = (Line) lines.elementAt( i ); for ( int j = 0; j < line.items.size(); ++j ) { Item item = (Item) line.items.elementAt( j ); Font font = getFont( item.style, fontSize ); if ( font == null ) { continue; } Font.TextExtents x = font.textExtents( item.text ); w += x.width; if ( x.height > h ) { h = x.height; } } if ( w > width ) { width = w; } height += h; } width += ( 2 * CELL_HORIZONTAL_PAD ); height += ( 2 * CELL_VERTICAL_PAD ); // allow one more pixel for grid outline width += toTwips( 1., UNIT_PIXEL ); return new Box( width, height ); } } static class Line { Vector items = new Vector(); void add( Item item ) { items.addElement( item ); } } static class Item { int style; String text; Item( int style, String text ) { this.style = style; this.text = text; } } static class Box { int width; int height; Box( int width, int height ) { this.width = width; this.height = height; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy