git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1339442 13f79535-47bb-0310-9956-ffa450edef68tags/fop-1_1rc1old
--> | --> | ||||
<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> |
<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). |
<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 <line-width-correction/> 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. |
* 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; | |||||
} | } | ||||
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. :-( | ||||
/** 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 |
/* | |||||
* 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; | |||||
} | |||||
} |
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); | ||||
} | } |
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; |
*/ | */ | ||||
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 |
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(); |
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); |
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> |
/* | |||||
* 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); | |||||
} | |||||
} |
/* | |||||
* 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()); | |||||
} | |||||
} |
/* | |||||
* 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()); | |||||
} | |||||
} |