Browse Source

Bugzilla #53242: Support fractional line widths in AFP renderer, fixing problem with SVG line drawing. Submitted by Luis Bernardo.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1339442 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-1_1rc1old
Glenn Adams 12 years ago
parent
commit
5a0e10ae9d

+ 1
- 0
conf/fop.xconf View File

--> -->
<images mode="b+w" bits-per-pixel="8"/> <images mode="b+w" bits-per-pixel="8"/>
<renderer-resolution>240</renderer-resolution> <renderer-resolution>240</renderer-resolution>
<line-width-correction>2.5</line-width-correction>
<resource-group-file>resources.afp</resource-group-file> <resource-group-file>resources.afp</resource-group-file>


<fonts> <fonts>

+ 4
- 0
src/documentation/content/xdocs/trunk/configuration.xml View File

<source><![CDATA[<renderer mime="application/x-afp"> <source><![CDATA[<renderer mime="application/x-afp">
<images mode="b+w" bits-per-pixel="8" native="true"/> <images mode="b+w" bits-per-pixel="8" native="true"/>
<renderer-resolution>240</renderer-resolution> <renderer-resolution>240</renderer-resolution>
<line-width-correction>2.5</line-width-correction>
<!-- a default external resource group file --> <!-- a default external resource group file -->
<resource-group-file>resources.afp</resource-group-file> <resource-group-file>resources.afp</resource-group-file>
<p> <p>
The default value for the "renderer-resolution" is 240 dpi. The default value for the "renderer-resolution" is 240 dpi.
</p> </p>
<p>
The default line width is device dependent and may need to be fine tuned so that the output matches the expected result. The default correction value is 2.5.
</p>
<!-- <!--
<p> <p>
The default value for the MO:DCA "interchange-set" is "MO:DCA-L". Other compliance settings include presentation interchange sets "MO:DCA-P IS/1" and "MO:DCA-P IS/2" (Resource Groups). The default value for the MO:DCA "interchange-set" is "MO:DCA-L". Other compliance settings include presentation interchange sets "MO:DCA-P IS/1" and "MO:DCA-P IS/2" (Resource Groups).

+ 8
- 0
src/documentation/content/xdocs/trunk/output.xml View File

<source><![CDATA[ <source><![CDATA[
<renderer-resolution>240</renderer-resolution>]]></source> <renderer-resolution>240</renderer-resolution>]]></source>
</section> </section>
<section id="afp-line-width-correction-config">
<title>Line Width Correction</title>
<p>The default line width in AFP is device dependent. This means that a line width specified in, say,
a SVG source file may not render the way it was intended. The output AFP line with can be corrected
by the &lt;line-width-correction/&gt; configuration element. Example:</p>
<source><![CDATA[
<line-width-correction>2.5</line-width-correction>]]></source>
</section>
<section id="afp-image-config"> <section id="afp-image-config">
<title>Images</title> <title>Images</title>
<p>By default the AFP Renderer converts all images to 8 bit grey level. <p>By default the AFP Renderer converts all images to 8 bit grey level.

+ 11
- 0
src/java/org/apache/fop/afp/AFPConstants.java View File

* 72dpi in millipoints * 72dpi in millipoints
*/ */
int DPI_72_MPTS = DPI_72 * 1000; int DPI_72_MPTS = DPI_72 * 1000;

/**
* The line width is set as a multiplier of a default line with; the width of the default
* line width is implementation defined, which probably means different devices use different
* actual widths; this means that the source line width (as specified in, say, a SVG line
* element) needs to be corrected by a fudge factor that depends on the output device so that
* the final output (print to paper, screen viewer) looks as intended.
*/
float LINE_WIDTH_CORRECTION = 2.5f;

} }


+ 4
- 18
src/java/org/apache/fop/afp/AFPGraphics2D.java View File

return length * factor; return length * factor;
} }


/** IBM's AFP Workbench paints lines that are wider than expected. We correct manually. */
private static final double GUESSED_WIDTH_CORRECTION = 1.7;

private static final double SPEC_NORMAL_LINE_WIDTH = UnitConv.in2pt(0.01); //"approx" 0.01 inch
private static final double NORMAL_LINE_WIDTH
= SPEC_NORMAL_LINE_WIDTH * GUESSED_WIDTH_CORRECTION;


/** /**
* Apply the stroke to the AFP graphics object. * Apply the stroke to the AFP graphics object.
* This takes the java stroke and outputs the appropriate settings * This takes the java stroke and outputs the appropriate settings
if (stroke instanceof BasicStroke) { if (stroke instanceof BasicStroke) {
BasicStroke basicStroke = (BasicStroke) stroke; BasicStroke basicStroke = (BasicStroke) stroke;


// set line width
// set line width and correct it; NOTE: apparently we need to correct the width so that the
// output looks OK since the default with depends on the output device
float lineWidth = basicStroke.getLineWidth(); float lineWidth = basicStroke.getLineWidth();
if (false) {
//Old approach. Retained until verified problems with 1440 resolution
graphicsObj.setLineWidth(Math.round(lineWidth / 2));
} else {
double absoluteLineWidth = lineWidth * Math.abs(getTransform().getScaleY());
double multiplier = absoluteLineWidth / NORMAL_LINE_WIDTH;
graphicsObj.setLineWidth((int)Math.round(multiplier));
//TODO Use GSFLW instead of GSLW for higher accuracy?
}
float correction = paintingState.getLineWidthCorrection();
graphicsObj.setLineWidth(lineWidth * correction);


//No line join, miter limit and end cap support in GOCA. :-( //No line join, miter limit and end cap support in GOCA. :-(



+ 26
- 0
src/java/org/apache/fop/afp/AFPPaintingState.java View File

/** the output resolution */ /** the output resolution */
private int resolution = 240; // 240 dpi private int resolution = 240; // 240 dpi


/**
* A configurable value to correct the line width so that the output matches the expected. Different
* devices may need different values.
*/
private float lineWidthCorrection = AFPConstants.LINE_WIDTH_CORRECTION;

/** determines whether GOCA is enabled or disabled */ /** determines whether GOCA is enabled or disabled */
private boolean gocaEnabled = true; private boolean gocaEnabled = true;
/** determines whether to stroke text in GOCA mode or to use text operators where possible */ /** determines whether to stroke text in GOCA mode or to use text operators where possible */
this.resolution = resolution; this.resolution = resolution;
} }


/**
* Sets the line width correction
*
* @param correction the line width multiplying factor correction
*/
public void setLineWidthCorrection(float correction) {
if (log.isDebugEnabled()) {
log.debug("line width correction set to: " + correction);
}
this.lineWidthCorrection = correction;
}

/** /**
* Returns the output/device resolution. * Returns the output/device resolution.
* *
return this.resolution; return this.resolution;
} }


/**
* Returns the line width correction.
* @return the correction
*/
public float getLineWidthCorrection() {
return this.lineWidthCorrection;
}

/** /**
* Controls whether GOCA is enabled or disabled. * Controls whether GOCA is enabled or disabled.
* @param enabled true if GOCA is enabled, false if it is disabled * @param enabled true if GOCA is enabled, false if it is disabled

+ 69
- 0
src/java/org/apache/fop/afp/goca/GraphicsSetFractionalLineWidth.java View File

/*
* 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.afp.goca;

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

/**
* Sets the line width to use when stroking GOCA shapes (structured fields)
*/
public class GraphicsSetFractionalLineWidth extends AbstractGraphicsDrawingOrder {

/** line width multiplier */
private final float multiplier;

/**
* Main constructor
*
* @param multiplier the line width multiplier
*/
public GraphicsSetFractionalLineWidth(float multiplier) {
this.multiplier = multiplier;
}

/** {@inheritDoc} */
public int getDataLength() {
return 4;
}

/** {@inheritDoc} */
public void writeToStream(OutputStream os) throws IOException {
int integral = (int) multiplier;
int fractional = (int) ((multiplier - (float) integral) * 256);
byte[] data = new byte[] {
getOrderCode(), // GSLW order code
0x02, // two bytes next
(byte) integral, // integral line with
(byte) fractional // and fractional
};
os.write(data);
}

/** {@inheritDoc} */
public String toString() {
return "GraphicsSetFractionalLineWidth{multiplier=" + multiplier + "}";
}

/** {@inheritDoc} */
byte getOrderCode() {
return 0x11;
}
}

+ 2
- 2
src/java/org/apache/fop/afp/goca/GraphicsSetLineWidth.java View File

public class GraphicsSetLineWidth extends AbstractGraphicsDrawingOrder { public class GraphicsSetLineWidth extends AbstractGraphicsDrawingOrder {


/** line width multiplier */ /** line width multiplier */
private int multiplier = 1;
private final int multiplier;


/** /**
* Main constructor * Main constructor
public void writeToStream(OutputStream os) throws IOException { public void writeToStream(OutputStream os) throws IOException {
byte[] data = new byte[] { byte[] data = new byte[] {
getOrderCode(), // GSLW order code getOrderCode(), // GSLW order code
(byte)multiplier // MH (line-width)
(byte) multiplier // MH (line-width)
}; };
os.write(data); os.write(data);
} }

+ 15
- 2
src/java/org/apache/fop/afp/modca/GraphicsObject.java View File

import org.apache.fop.afp.goca.GraphicsSetArcParameters; import org.apache.fop.afp.goca.GraphicsSetArcParameters;
import org.apache.fop.afp.goca.GraphicsSetCharacterSet; import org.apache.fop.afp.goca.GraphicsSetCharacterSet;
import org.apache.fop.afp.goca.GraphicsSetCurrentPosition; import org.apache.fop.afp.goca.GraphicsSetCurrentPosition;
import org.apache.fop.afp.goca.GraphicsSetFractionalLineWidth;
import org.apache.fop.afp.goca.GraphicsSetLineType; import org.apache.fop.afp.goca.GraphicsSetLineType;
import org.apache.fop.afp.goca.GraphicsSetLineWidth; import org.apache.fop.afp.goca.GraphicsSetLineWidth;
import org.apache.fop.afp.goca.GraphicsSetPatternSymbol; import org.apache.fop.afp.goca.GraphicsSetPatternSymbol;
* @param lineWidth the line width multiplier * @param lineWidth the line width multiplier
*/ */
public void setLineWidth(int lineWidth) { public void setLineWidth(int lineWidth) {
if (lineWidth != graphicsState.lineWidth) {
if ((float) lineWidth != graphicsState.lineWidth) {
addObject(new GraphicsSetLineWidth(lineWidth)); addObject(new GraphicsSetLineWidth(lineWidth));
graphicsState.lineWidth = (float) lineWidth;
}
}

/**
* Sets the line width
*
* @param lineWidth the line width multiplier
*/
public void setLineWidth(float lineWidth) {
if (lineWidth != graphicsState.lineWidth) {
addObject(new GraphicsSetFractionalLineWidth(lineWidth));
graphicsState.lineWidth = lineWidth; graphicsState.lineWidth = lineWidth;
} }
} }
private byte lineType; private byte lineType;


/** the current line width */ /** the current line width */
private int lineWidth;
private float lineWidth;


/** the current fill pattern */ /** the current fill pattern */
private byte patternSymbol; private byte patternSymbol;

+ 7
- 0
src/java/org/apache/fop/render/afp/AFPCustomizable.java View File

*/ */
void setResolution(int resolution); void setResolution(int resolution);


/**
* Sets the line width correction
*
* @param correction the line width multiplying factor correction
*/
void setLineWidthCorrection(float correction);

/** /**
* Sets whether FS11 and FS45 non-inline images should be wrapped in a page segment * Sets whether FS11 and FS45 non-inline images should be wrapped in a page segment
* @param pSeg true iff images should be wrapped * @param pSeg true iff images should be wrapped

+ 5
- 0
src/java/org/apache/fop/render/afp/AFPDocumentHandler.java View File

paintingState.setResolution(resolution); paintingState.setResolution(resolution);
} }


/** {@inheritDoc} */
public void setLineWidthCorrection(float correction) {
paintingState.setLineWidthCorrection(correction);
}

/** {@inheritDoc} */ /** {@inheritDoc} */
public int getResolution() { public int getResolution() {
return paintingState.getResolution(); return paintingState.getResolution();

+ 8
- 0
src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java View File

import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.avalon.framework.configuration.ConfigurationException;


import org.apache.fop.afp.AFPConstants;
import org.apache.fop.afp.AFPEventProducer; import org.apache.fop.afp.AFPEventProducer;
import org.apache.fop.afp.AFPResourceLevel; import org.apache.fop.afp.AFPResourceLevel;
import org.apache.fop.afp.AFPResourceLevelDefaults; import org.apache.fop.afp.AFPResourceLevelDefaults;
customizable.setResolution(rendererResolutionCfg.getValueAsInteger(240)); customizable.setResolution(rendererResolutionCfg.getValueAsInteger(240));
} }


// renderer resolution
Configuration lineWidthCorrectionCfg = cfg.getChild("line-width-correction", false);
if (lineWidthCorrectionCfg != null) {
customizable.setLineWidthCorrection(lineWidthCorrectionCfg
.getValueAsFloat(AFPConstants.LINE_WIDTH_CORRECTION));
}

// a default external resource group file setting // a default external resource group file setting
Configuration resourceGroupFileCfg Configuration resourceGroupFileCfg
= cfg.getChild("resource-group-file", false); = cfg.getChild("resource-group-file", false);

+ 3
- 0
status.xml View File

documents. Example: the fix of marks layering will be such a case when it's done. documents. Example: the fix of marks layering will be such a case when it's done.
--> -->
<release version="FOP Trunk" date="TBD"> <release version="FOP Trunk" date="TBD">
<action context="Renderers" dev="GA" type="fix" fixes-bug="53242" due-to="Luis Bernardo">
Support fractional line widths in AFP renderer, fixing problem with SVG line drawing.
</action>
<action context="Config" dev="GA" type="fix" fixes-bug="53248" due-to="Luis Bernardo"> <action context="Config" dev="GA" type="fix" fixes-bug="53248" due-to="Luis Bernardo">
Fix exception thrown from use of -print option in CLI. Fix exception thrown from use of -print option in CLI.
</action> </action>

+ 57
- 0
test/java/org/apache/fop/afp/AFPGraphics2DTestCase.java View File

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

import java.awt.BasicStroke;

import org.junit.Test;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import org.apache.fop.afp.modca.GraphicsObject;
import org.apache.fop.fonts.FontInfo;

public class AFPGraphics2DTestCase {

private final float lineWidth = 1.0f;
private final float correction = 2.5f;
private final BasicStroke stroke = mock(BasicStroke.class);
private final GraphicsObject gObject = mock(GraphicsObject.class);
private final AFPPaintingState paintingState = mock(AFPPaintingState.class);
private final AFPResourceManager resourceManager = mock(AFPResourceManager.class);
private final AFPResourceInfo resourceInfo = mock(AFPResourceInfo.class);
private final FontInfo fontInfo = mock(FontInfo.class);
private AFPGraphics2D graphics2D = new AFPGraphics2D(false, paintingState, resourceManager, resourceInfo,
fontInfo);

@Test
public void testApplyStroke() {
// note: this only tests the setLineWidth in the GraphicsObject
float correctedLineWidth = lineWidth * correction;
when(stroke.getLineWidth()).thenReturn(lineWidth);
when(paintingState.getLineWidthCorrection()).thenReturn(correction);
graphics2D.setGraphicsObject(gObject);
graphics2D.applyStroke(stroke);
verify(gObject).setLineWidth(correctedLineWidth);
}

}

+ 59
- 0
test/java/org/apache/fop/afp/goca/GraphicsSetFractionalLineWidthTestCase.java View File

/*
* 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.afp.goca;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;

import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class GraphicsSetFractionalLineWidthTestCase {

private final float multiplier = 5.25f;
private final GraphicsSetFractionalLineWidth gsflw = new GraphicsSetFractionalLineWidth(multiplier);

@Test
public void testGetDataLength() {
assertEquals(4, gsflw.getDataLength());
}

@Test
public void testWriteToStream() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
gsflw.writeToStream(baos);
baos.close();
// note: 0.25 = 64/256 and 64 = 4*16, so 0x40
// expected: 0x11 (order code), 0x02 (2 bytes next), 0x05 (integral multiplier), 0x40 (fractional
// multiplier)
byte[] expected = new byte[] {0x11, 0x02, 0x05, 0x40};
assertTrue(Arrays.equals(expected, baos.toByteArray()));
}

@Test
public void testToString() {
// lets make sure we keep good coverage...
assertEquals("GraphicsSetFractionalLineWidth{multiplier=" + multiplier + "}", gsflw.toString());
}

}

+ 57
- 0
test/java/org/apache/fop/afp/goca/GraphicsSetLineWidthTestCase.java View File

/*
* 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.afp.goca;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;

import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class GraphicsSetLineWidthTestCase {

private final int multiplier = 5;
private final GraphicsSetLineWidth gslw = new GraphicsSetLineWidth(multiplier);

@Test
public void testGetDataLength() {
assertEquals(2, gslw.getDataLength());
}

@Test
public void testWriteToStream() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
gslw.writeToStream(baos);
baos.close();
// expected: 0x19 (order code), 0x05 (integral multiplier)
byte[] expected = new byte[] {0x19, 0x05};
assertTrue(Arrays.equals(expected, baos.toByteArray()));
}

@Test
public void testToString() {
// lets make sure we keep good coverage...
assertEquals("GraphicsSetLineWidth{multiplier=" + multiplier + "}", gslw.toString());
}

}

Loading…
Cancel
Save