aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop/render/extensions/prepress/PageBoundaries.java
diff options
context:
space:
mode:
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.java235
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}));
+ }
+ }
+
+}