Fixed typos. Bugfix: when crop-offset wasn't specified, but bleed was, the media box was wrong. Tried to fix encapsulation problem mentioned by Vincent. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@800401 13f79535-47bb-0310-9956-ffa450edef68tags/fop-1_0
@@ -19,8 +19,10 @@ | |||
package org.apache.fop.render.extensions.prepress; | |||
import java.awt.Dimension; | |||
import java.awt.Rectangle; | |||
import java.text.MessageFormat; | |||
import java.util.Map; | |||
import java.util.regex.Matcher; | |||
import java.util.regex.Pattern; | |||
@@ -29,29 +31,27 @@ import org.apache.xmlgraphics.util.QName; | |||
import org.apache.fop.fo.extensions.ExtensionElementMapping; | |||
import org.apache.fop.fo.properties.FixedLength; | |||
/** | |||
* This class contains definition of page boundaries FOF's extension attributes for XSL-FO. | |||
* That is: bleedBox, trimBox and cropBox. | |||
* Also this class provides method to parse the possible values of these attributes | |||
* and to generate original size of bounded area. | |||
* This class is used to calculate the effective boundaries of a page including special-purpose | |||
* boxes used in prepress. These are specified using extension attributes: | |||
* bleedBox, trimBox and cropBox. The semantics are further described on the website. | |||
*/ | |||
public final class PageBoundariesAttributes { | |||
public class PageBoundaries { | |||
/** | |||
* The extension attribute for calculating the PDF BleedBox area - specifies the bleed width | |||
* The extension attribute for calculating the PDF BleedBox area - specifies the bleed width. | |||
*/ | |||
public static final QName EXT_BLEED | |||
= new QName(ExtensionElementMapping.URI, null, "bleed"); | |||
/** | |||
* The extension attribute for the PDF CropBox area | |||
* The extension attribute for the PDF CropBox area. | |||
*/ | |||
public static final QName EXT_CROP_OFFSET | |||
= new QName(ExtensionElementMapping.URI, null, "crop-offset"); | |||
/** | |||
* The extension attribute for the PDF CropBox area | |||
* The extension attribute for the PDF CropBox area. | |||
*/ | |||
public static final QName EXT_CROP_BOX | |||
= new QName(ExtensionElementMapping.URI, null, "crop-box"); | |||
@@ -60,10 +60,98 @@ public final class PageBoundariesAttributes { | |||
private static final Pattern SIZE_UNIT_PATTERN | |||
= Pattern.compile("^(-?\\d*\\.?\\d*)(px|in|cm|mm|pt|pc|mpt)$"); | |||
private Rectangle trimBox; | |||
private Rectangle bleedBox; | |||
private Rectangle mediaBox; | |||
private Rectangle cropBox; | |||
/** | |||
* Creates a new instance. | |||
* @param pageSize the page size (in mpt) defined by the simple-page-master. | |||
* @param bleed the bleed value (raw value as given in the property value) | |||
* @param cropOffset the crop-offset value (raw value as given in the property value) | |||
* @param cropBoxSelector the crop-box, valid values: (trim-box|bleed-box|media-box) | |||
*/ | |||
public PageBoundaries(Dimension pageSize, String bleed, String cropOffset, | |||
String cropBoxSelector) { | |||
calculate(pageSize, bleed, cropOffset, cropBoxSelector); | |||
} | |||
/** | |||
* Creates a new instance. | |||
* @param pageSize the page size (in mpt) defined by the simple-page-master. | |||
* @param foreignAttributes the foreign attributes for the page | |||
* (used to extract the extension attribute values) | |||
*/ | |||
public PageBoundaries(Dimension pageSize, Map foreignAttributes) { | |||
String bleed = (String)foreignAttributes.get(EXT_BLEED); | |||
String cropOffset = (String)foreignAttributes.get(EXT_CROP_OFFSET); | |||
String cropBoxSelector = (String)foreignAttributes.get(EXT_CROP_BOX); | |||
calculate(pageSize, bleed, cropOffset, cropBoxSelector); | |||
} | |||
private void calculate(Dimension pageSize, String bleed, String cropOffset, | |||
String cropBoxSelector) { | |||
this.trimBox = new Rectangle(pageSize); | |||
this.bleedBox = getBleedBoxRectangle(this.trimBox, bleed); | |||
Rectangle cropMarksBox = getCropMarksAreaRectangle(trimBox, cropOffset); | |||
//MediaBox includes all of the following three rectangles | |||
this.mediaBox = new Rectangle(); | |||
this.mediaBox.add(this.trimBox); | |||
this.mediaBox.add(this.bleedBox); | |||
this.mediaBox.add(cropMarksBox); | |||
if ("trim-box".equals(cropBoxSelector)) { | |||
this.cropBox = this.trimBox; | |||
} else if ("bleed-box".equals(cropBoxSelector)) { | |||
this.cropBox = this.bleedBox; | |||
} else if ("media-box".equals(cropBoxSelector) | |||
|| cropBoxSelector == null | |||
|| "".equals(cropBoxSelector)) { | |||
this.cropBox = this.mediaBox; | |||
} else { | |||
final String err = "The crop-box has invalid value: {0}, " | |||
+ "possible values of crop-box: (trim-box|bleed-box|media-box)"; | |||
throw new IllegalArgumentException(MessageFormat.format(err, | |||
new Object[]{cropBoxSelector})); | |||
} | |||
} | |||
/** | |||
* Utility classes should not have a public or default constructor. | |||
* Returns the trim box for the page. This is equal to the page size given in XSL-FO. | |||
* After production the printed media is trimmed to this rectangle. | |||
* @return the trim box | |||
*/ | |||
private PageBoundariesAttributes() { | |||
public Rectangle getTrimBox() { | |||
return this.trimBox; | |||
} | |||
/** | |||
* Returns the bleed box for the page. | |||
* @return the bleed box | |||
*/ | |||
public Rectangle getBleedBox() { | |||
return this.bleedBox; | |||
} | |||
/** | |||
* Returns the media box for the page. | |||
* @return the media box | |||
*/ | |||
public Rectangle getMediaBox() { | |||
return this.mediaBox; | |||
} | |||
/** | |||
* Returns the crop box for the page. The crop box is used by Adobe Acrobat to select which | |||
* parts of the document shall be displayed and it also defines the rectangle to which a | |||
* RIP will clip the document. For bitmap output, this defines the size of the size of | |||
* the bitmap. | |||
* @return the crop box | |||
*/ | |||
public Rectangle getCropBox() { | |||
return this.cropBox; | |||
} | |||
/** | |||
@@ -84,67 +172,17 @@ public final class PageBoundariesAttributes { | |||
* @param cropOffsets the given crop offsets | |||
* @return the calculated MediaBox rectangle | |||
*/ | |||
public static Rectangle getMediaBoxRectangle(Rectangle trimBox, String cropOffsets) { | |||
public static Rectangle getCropMarksAreaRectangle(Rectangle trimBox, String cropOffsets) { | |||
return getRectagleUsingOffset(trimBox, cropOffsets); | |||
} | |||
/** | |||
* The crop box controls how Acrobat display the page or how the Java2DRenderer | |||
* sizes the output media. The PDF spec defines that the CropBox defaults to the MediaBox. | |||
* <p/> | |||
* The possible values of crop-box: (trim-box|bleed-box|media-box) | |||
* Default value: media-box | |||
* | |||
* @param trimBox the TrimBox rectangle | |||
* @param bleedBox the BleedBox rectangle | |||
* @param mediaBox the MediaBox rectangle | |||
* @param value the crop-box value | |||
* @return the calculated CropBox rectangle | |||
*/ | |||
public static Rectangle getCropBoxRectangle(final Rectangle trimBox, final Rectangle bleedBox, | |||
final Rectangle mediaBox, final String value) { | |||
final String err = "The crop-box has invalid value: {0}, " | |||
+ "possible values of crop-box: (trim-box|bleed-box|media-box)"; | |||
if ("trim-box".equals(value)) { | |||
return trimBox; | |||
} else if ("bleed-box".equals(value)) { | |||
return bleedBox; | |||
} else if ("media-box".equals(value) || value == null || "".equals(value)) { | |||
return mediaBox; | |||
} else { | |||
throw new IllegalArgumentException(MessageFormat.format(err, new Object[]{value})); | |||
} | |||
} | |||
/** | |||
* The crop box controls how Acrobat display the page or how the Java2DRenderer | |||
* sizes the output media. The PDF spec defines that the CropBox defaults to the MediaBox | |||
* <p/> | |||
* The possible values of crop-box: (trim-box|bleed-box|media-box) | |||
* Default value: media-box | |||
* | |||
* @param trimBox the TrimBox rectangle | |||
* @param bleed the given bleed widths | |||
* @param cropOffset the given crop offsets | |||
* @param value the crop-box value | |||
* @return the calculated CropBox rectangle | |||
*/ | |||
public static Rectangle getCropBoxRectangle(final Rectangle trimBox, final String bleed, | |||
final String cropOffset, final String value) { | |||
Rectangle bleedBox = getBleedBoxRectangle(trimBox, bleed); | |||
Rectangle mediaBox = getMediaBoxRectangle(trimBox, cropOffset); | |||
return getCropBoxRectangle(trimBox, bleedBox, mediaBox, value); | |||
} | |||
private static Rectangle getRectagleUsingOffset(Rectangle originalRect, String offset) { | |||
if (offset == null || "".equals(offset) || originalRect == null) { | |||
return originalRect; | |||
} | |||
String[] bleeds = offset.split(" "); | |||
int[] coords = new int[4]; // top, rigth, bottom, left | |||
int[] coords = new int[4]; // top, right, bottom, left | |||
if (bleeds.length == 1) { | |||
coords[0] = getLengthIntValue(bleeds[0]); | |||
coords[1] = coords[0]; | |||
@@ -183,4 +221,5 @@ public final class PageBoundariesAttributes { | |||
throw new IllegalArgumentException(MessageFormat.format(err, new Object[]{length})); | |||
} | |||
} | |||
} |
@@ -26,15 +26,13 @@ import org.apache.xmlgraphics.util.QName; | |||
import org.apache.fop.fo.extensions.ExtensionElementMapping; | |||
/** | |||
* This class contains definition of 'scale' FOF's extension attribute for XSL-FO, and provides | |||
* utility method to parse the possible values of this attibute | |||
* This class provides utility methods to parse the 'fox:scale' extension attribute. | |||
*/ | |||
public final class PageScaleAttributes { | |||
/** | |||
* The extension 'scale' attribute for simple-page-master element | |||
* The extension 'scale' attribute for the simple-page-master element. | |||
*/ | |||
public static final QName EXT_PAGE_SCALE | |||
= new QName(ExtensionElementMapping.URI, null, "scale"); | |||
@@ -47,8 +45,8 @@ public final class PageScaleAttributes { | |||
} | |||
/** | |||
* Compute scale parameters from given fox:scale attribute which has format: scaleX [scaleY] | |||
* If scaleY is not defined, it equals scaleX | |||
* Compute scale parameters from given fox:scale attribute which has the format: scaleX [scaleY] | |||
* If scaleY is not defined, it equals scaleX. | |||
* @param scale scale attribute, input format: scaleX [scaleY] | |||
* @return the pair of (sx, sy) values | |||
*/ |
@@ -24,6 +24,7 @@ import java.awt.BasicStroke; | |||
import java.awt.Color; | |||
import java.awt.Graphics; | |||
import java.awt.Graphics2D; | |||
import java.awt.Rectangle; | |||
import java.awt.RenderingHints; | |||
import java.awt.font.GlyphVector; | |||
import java.awt.geom.AffineTransform; | |||
@@ -75,7 +76,7 @@ import org.apache.fop.fonts.Typeface; | |||
import org.apache.fop.render.AbstractPathOrientedRenderer; | |||
import org.apache.fop.render.Graphics2DAdapter; | |||
import org.apache.fop.render.RendererContext; | |||
import org.apache.fop.render.extensions.prepress.PageBoundariesAttributes; | |||
import org.apache.fop.render.extensions.prepress.PageBoundaries; | |||
import org.apache.fop.render.extensions.prepress.PageScaleAttributes; | |||
import org.apache.fop.render.pdf.CTMHelper; | |||
import org.apache.fop.util.CharUtilities; | |||
@@ -292,20 +293,10 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem | |||
this.currentPageViewport = pageViewport; | |||
try { | |||
String bleed = (String) currentPageViewport.getForeignAttributes().get( | |||
PageBoundariesAttributes.EXT_BLEED); | |||
String cropOffset = (String) currentPageViewport.getForeignAttributes().get( | |||
PageBoundariesAttributes.EXT_CROP_OFFSET); | |||
String cropBoxValue = (String) currentPageViewport.getForeignAttributes().get( | |||
PageBoundariesAttributes.EXT_CROP_BOX); | |||
Rectangle2D bounds = PageBoundariesAttributes.getCropBoxRectangle( | |||
pageViewport.getViewArea(), | |||
bleed, | |||
cropOffset, | |||
cropBoxValue | |||
); | |||
Rectangle2D bleedBox = PageBoundariesAttributes.getBleedBoxRectangle( | |||
pageViewport.getViewArea(), bleed); | |||
PageBoundaries boundaries = new PageBoundaries( | |||
pageViewport.getViewArea().getSize(), pageViewport.getForeignAttributes()); | |||
Rectangle bounds = boundaries.getCropBox(); | |||
Rectangle bleedBox = boundaries.getBleedBox(); | |||
this.pageWidth = (int) Math.round(bounds.getWidth() / 1000f); | |||
this.pageHeight = (int) Math.round(bounds.getHeight() / 1000f); | |||
@@ -325,7 +316,6 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem | |||
scaleY *= scales.getY(); | |||
} | |||
scaleX = scaleX | |||
* (25.4f / FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION) | |||
/ userAgent.getTargetPixelUnitToMillimeter(); |
@@ -24,6 +24,7 @@ import java.awt.Rectangle; | |||
import java.awt.geom.AffineTransform; | |||
import java.awt.geom.Point2D; | |||
import java.awt.geom.Rectangle2D; | |||
import java.awt.geom.Rectangle2D.Double; | |||
import java.io.IOException; | |||
import java.util.Map; | |||
@@ -40,7 +41,7 @@ import org.apache.fop.pdf.PDFPage; | |||
import org.apache.fop.pdf.PDFReference; | |||
import org.apache.fop.pdf.PDFResourceContext; | |||
import org.apache.fop.pdf.PDFResources; | |||
import org.apache.fop.render.extensions.prepress.PageBoundariesAttributes; | |||
import org.apache.fop.render.extensions.prepress.PageBoundaries; | |||
import org.apache.fop.render.extensions.prepress.PageScaleAttributes; | |||
import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler; | |||
import org.apache.fop.render.intermediate.IFContext; | |||
@@ -171,22 +172,12 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { | |||
throws IFException { | |||
this.pdfResources = this.pdfDoc.getResources(); | |||
String bleedWidth = (String) getContext().getForeignAttribute( | |||
PageBoundariesAttributes.EXT_BLEED); | |||
String cropOffset = (String) getContext().getForeignAttribute( | |||
PageBoundariesAttributes.EXT_CROP_OFFSET); | |||
String cropBoxValue = (String) getContext().getForeignAttribute( | |||
PageBoundariesAttributes.EXT_CROP_BOX); | |||
PageBoundaries boundaries = new PageBoundaries(size, getContext().getForeignAttributes()); | |||
Rectangle trimBox = new Rectangle(0, 0, | |||
(int) size.getWidth(), (int) size.getHeight()); | |||
Rectangle bleedBox | |||
= PageBoundariesAttributes.getBleedBoxRectangle(trimBox, bleedWidth); | |||
Rectangle mediaBox | |||
= PageBoundariesAttributes.getMediaBoxRectangle(trimBox, cropOffset); | |||
Rectangle cropBox = PageBoundariesAttributes.getCropBoxRectangle( | |||
trimBox, bleedBox, mediaBox, cropBoxValue); | |||
Rectangle trimBox = boundaries.getTrimBox(); | |||
Rectangle bleedBox = boundaries.getBleedBox(); | |||
Rectangle mediaBox = boundaries.getMediaBox(); | |||
Rectangle cropBox = boundaries.getCropBox(); | |||
// set scale attributes | |||
double scaleX = 1; | |||
@@ -202,22 +193,10 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { | |||
this.currentPage = this.pdfDoc.getFactory().makePage( | |||
this.pdfResources, | |||
index, | |||
new Rectangle2D.Double(mediaBox.getX() * scaleX / 1000, | |||
mediaBox.getY() * scaleY / 1000, | |||
mediaBox.getWidth() * scaleX / 1000, | |||
mediaBox.getHeight() * scaleY / 1000), | |||
new Rectangle2D.Double(cropBox.getX() * scaleX / 1000, | |||
cropBox.getY() * scaleY / 1000, | |||
cropBox.getWidth() * scaleX / 1000, | |||
cropBox.getHeight() * scaleY / 1000), | |||
new Rectangle2D.Double(bleedBox.getX() * scaleX / 1000, | |||
bleedBox.getY() * scaleY / 1000, | |||
bleedBox.getWidth() * scaleX / 1000, | |||
bleedBox.getHeight() * scaleY / 1000), | |||
new Rectangle2D.Double(trimBox.getX() * scaleX / 1000, | |||
trimBox.getY() * scaleY / 1000, | |||
trimBox.getWidth() * scaleX / 1000, | |||
trimBox.getHeight() * scaleY / 1000)); | |||
toPointAndScale(mediaBox, scaleX, scaleY), | |||
toPointAndScale(cropBox, scaleX, scaleY), | |||
toPointAndScale(bleedBox, scaleX, scaleY), | |||
toPointAndScale(trimBox, scaleX, scaleY)); | |||
pdfUtil.generatePageLabel(index, name); | |||
@@ -232,6 +211,13 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { | |||
generator.concatenate(basicPageTransform); | |||
} | |||
private Double toPointAndScale(Rectangle box, double scaleX, double scaleY) { | |||
return new Rectangle2D.Double(box.getX() * scaleX / 1000, | |||
box.getY() * scaleY / 1000, | |||
box.getWidth() * scaleX / 1000, | |||
box.getHeight() * scaleY / 1000); | |||
} | |||
/** {@inheritDoc} */ | |||
public IFPainter startPageContent() throws IFException { | |||
return new PDFPainter(this); |
@@ -24,7 +24,7 @@ import java.awt.geom.Point2D; | |||
import junit.framework.TestCase; | |||
import org.apache.fop.render.extensions.prepress.PageBoundariesAttributes; | |||
import org.apache.fop.render.extensions.prepress.PageBoundaries; | |||
import org.apache.fop.render.extensions.prepress.PageScaleAttributes; | |||
/** | |||
@@ -80,47 +80,59 @@ public class PrepressTest extends TestCase { | |||
* Tests for page boundaries | |||
*/ | |||
public void testBoxOk1() throws Exception { | |||
Rectangle res = PageBoundariesAttributes.getBleedBoxRectangle(TEST_AREA, null); | |||
Rectangle res = PageBoundaries.getBleedBoxRectangle(TEST_AREA, null); | |||
assertSame("Result should be the same as TEST_AREA object", res, TEST_AREA); | |||
res = PageBoundariesAttributes.getBleedBoxRectangle(null, BLEED1); | |||
res = PageBoundaries.getBleedBoxRectangle(null, BLEED1); | |||
assertNull(res); | |||
} | |||
public void testBoxOk2() throws Exception { | |||
Rectangle res1 = PageBoundariesAttributes.getBleedBoxRectangle(TEST_AREA, BLEED1); | |||
assertNotNull("Expected not null object", res1); | |||
assertEquals(-5000, res1.getX(), 1); | |||
assertEquals(-5000, res1.getY(), 1); | |||
assertEquals(30000, res1.getWidth(), 1); | |||
assertEquals(25000, res1.getHeight(), 1); | |||
Rectangle res2 = PageBoundariesAttributes.getMediaBoxRectangle(TEST_AREA, CROP_OFFSET1); | |||
assertNotNull("Expected not null object", res2); | |||
assertEquals(-8000, res2.getX(), 1); | |||
assertEquals(-8000, res2.getY(), 1); | |||
assertEquals(36000, res2.getWidth(), 1); | |||
assertEquals(31000, res2.getHeight(), 1); | |||
Rectangle res3 = PageBoundariesAttributes.getCropBoxRectangle( | |||
TEST_AREA, res1, res2, "media-box"); | |||
assertNotNull("Expected not null object", res3); | |||
assertEquals(res3, res2); | |||
res3 = PageBoundariesAttributes.getCropBoxRectangle( | |||
TEST_AREA, res1, res2, "bleed-box"); | |||
assertNotNull("Expected not null object", res3); | |||
assertEquals(res3, res1); | |||
res3 = PageBoundariesAttributes.getCropBoxRectangle( | |||
TEST_AREA, res1, res2, "trim-box"); | |||
assertNotNull("Expected not null object", res3); | |||
assertEquals(res3, TEST_AREA); | |||
PageBoundaries boundaries = new PageBoundaries( | |||
TEST_AREA.getSize(), BLEED1, CROP_OFFSET1, null); | |||
assertNotNull("Expected not null object", boundaries.getBleedBox()); | |||
assertEquals(-5000, boundaries.getBleedBox().getX(), 1); | |||
assertEquals(-5000, boundaries.getBleedBox().getY(), 1); | |||
assertEquals(30000, boundaries.getBleedBox().getWidth(), 1); | |||
assertEquals(25000, boundaries.getBleedBox().getHeight(), 1); | |||
assertNotNull("Expected not null object", boundaries.getMediaBox()); | |||
assertEquals(-8000, boundaries.getMediaBox().getX(), 1); | |||
assertEquals(-8000, boundaries.getMediaBox().getY(), 1); | |||
assertEquals(36000, boundaries.getMediaBox().getWidth(), 1); | |||
assertEquals(31000, boundaries.getMediaBox().getHeight(), 1); | |||
assertEquals(TEST_AREA, boundaries.getTrimBox()); | |||
assertEquals(boundaries.getMediaBox(), boundaries.getCropBox()); | |||
boundaries = new PageBoundaries( | |||
TEST_AREA.getSize(), BLEED1, CROP_OFFSET1, "media-box"); | |||
assertEquals(boundaries.getMediaBox(), boundaries.getCropBox()); | |||
boundaries = new PageBoundaries( | |||
TEST_AREA.getSize(), BLEED1, CROP_OFFSET1, "bleed-box"); | |||
assertEquals(boundaries.getBleedBox(), boundaries.getCropBox()); | |||
boundaries = new PageBoundaries( | |||
TEST_AREA.getSize(), BLEED1, CROP_OFFSET1, "trim-box"); | |||
assertEquals(boundaries.getTrimBox(), boundaries.getCropBox()); | |||
assertEquals(TEST_AREA, boundaries.getCropBox()); | |||
boundaries = new PageBoundaries( | |||
TEST_AREA.getSize(), BLEED1, null, null); | |||
assertNotNull("Expected not null object", boundaries.getBleedBox()); | |||
assertEquals(-5000, boundaries.getBleedBox().getX(), 1); | |||
assertEquals(-5000, boundaries.getBleedBox().getY(), 1); | |||
assertEquals(30000, boundaries.getBleedBox().getWidth(), 1); | |||
assertEquals(25000, boundaries.getBleedBox().getHeight(), 1); | |||
assertEquals(boundaries.getBleedBox(), boundaries.getCropBox()); | |||
assertEquals(boundaries.getBleedBox(), boundaries.getMediaBox()); | |||
} | |||
public void testBoxIllArgExc() throws Exception { | |||
try { | |||
Rectangle res = PageBoundariesAttributes.getBleedBoxRectangle(TEST_AREA, "0"); | |||
PageBoundaries boundaries = new PageBoundaries( | |||
TEST_AREA.getSize(), "0", null, null); | |||
fail("Expected IllegalArgumentException. Box should have units"); | |||
} catch (IllegalArgumentException iae) { | |||
// Good! |