diff options
Diffstat (limited to 'src/java/org/apache/fop/render/extensions/prepress/PageBoundaries.java')
-rw-r--r-- | src/java/org/apache/fop/render/extensions/prepress/PageBoundaries.java | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/src/java/org/apache/fop/render/extensions/prepress/PageBoundaries.java b/src/java/org/apache/fop/render/extensions/prepress/PageBoundaries.java new file mode 100644 index 000000000..8001e1fc2 --- /dev/null +++ b/src/java/org/apache/fop/render/extensions/prepress/PageBoundaries.java @@ -0,0 +1,235 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.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; + +import org.apache.xmlgraphics.util.QName; + +import org.apache.fop.fo.extensions.ExtensionElementMapping; +import org.apache.fop.fo.properties.FixedLength; + +/** + * 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 class PageBoundaries { + + /** + * 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. + */ + public static final QName EXT_CROP_OFFSET + = new QName(ExtensionElementMapping.URI, null, "crop-offset"); + + /** + * The extension attribute for the PDF CropBox area. + */ + public static final QName EXT_CROP_BOX + = new QName(ExtensionElementMapping.URI, null, "crop-box"); + + + private static final Pattern SIZE_UNIT_PATTERN + = Pattern.compile("^(-?\\d*\\.?\\d*)(px|in|cm|mm|pt|pc|mpt)$"); + + private static final Pattern WHITESPACE_PATTERN = Pattern.compile("\\s+"); + + 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})); + } + } + + /** + * 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 + */ + 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 bitmap. + * @return the crop box + */ + public Rectangle getCropBox() { + return this.cropBox; + } + + /** + * The BleedBox is calculated by expanding the TrimBox by the bleed widths. + * + * @param trimBox the TrimBox rectangle + * @param bleed the given bleed widths + * @return the calculated BleedBox rectangle + */ + private static Rectangle getBleedBoxRectangle(Rectangle trimBox, String bleed) { + return getRectangleUsingOffset(trimBox, bleed); + } + + /** + * The MediaBox is calculated by expanding the TrimBox by the crop offsets. + * + * @param trimBox the TrimBox rectangle + * @param cropOffsets the given crop offsets + * @return the calculated MediaBox rectangle + */ + private static Rectangle getCropMarksAreaRectangle(Rectangle trimBox, String cropOffsets) { + return getRectangleUsingOffset(trimBox, cropOffsets); + } + + private static Rectangle getRectangleUsingOffset(Rectangle originalRect, String offset) { + if (offset == null || "".equals(offset) || originalRect == null) { + return originalRect; + } + + String[] offsets = WHITESPACE_PATTERN.split(offset); + int[] coords = new int[4]; // top, right, bottom, left + switch (offsets.length) { + case 1: + coords[0] = getLengthIntValue(offsets[0]); + coords[1] = coords[0]; + coords[2] = coords[0]; + coords[3] = coords[0]; + break; + case 2: + coords[0] = getLengthIntValue(offsets[0]); + coords[1] = getLengthIntValue(offsets[1]); + coords[2] = coords[0]; + coords[3] = coords[1]; + break; + case 3: + coords[0] = getLengthIntValue(offsets[0]); + coords[1] = getLengthIntValue(offsets[1]); + coords[2] = getLengthIntValue(offsets[2]); + coords[3] = coords[1]; + break; + case 4: + coords[0] = getLengthIntValue(offsets[0]); + coords[1] = getLengthIntValue(offsets[1]); + coords[2] = getLengthIntValue(offsets[2]); + coords[3] = getLengthIntValue(offsets[3]); + break; + default: + // TODO throw appropriate exception that can be caught by the event + // notification mechanism + throw new IllegalArgumentException("Too many arguments"); + } + return new Rectangle(originalRect.x - coords[3], + originalRect.y - coords[0], + originalRect.width + coords[3] + coords[1], + originalRect.height + coords[0] + coords[2]); + } + + private static int getLengthIntValue(final String length) { + final String err = "Incorrect length value: {0}"; + Matcher m = SIZE_UNIT_PATTERN.matcher(length); + + if (m.find()) { + return FixedLength.getInstance(Double.parseDouble(m.group(1)), + m.group(2)).getLength().getValue(); + } else { + throw new IllegalArgumentException(MessageFormat.format(err, new Object[]{length})); + } + } + +} |