diff options
author | Mehdi Houshmand <mehdi@apache.org> | 2012-05-11 13:14:17 +0000 |
---|---|---|
committer | Mehdi Houshmand <mehdi@apache.org> | 2012-05-11 13:14:17 +0000 |
commit | c46fafb223e69046ffba3dd8c46314058f8091f2 (patch) | |
tree | 42eb7c74e5aed47a1d02d752fc260130adc25195 /src/java/org | |
parent | 1c9c25bd5bef114bdc176ee8554fe0cd34183be2 (diff) | |
download | xmlgraphics-fop-c46fafb223e69046ffba3dd8c46314058f8091f2.tar.gz xmlgraphics-fop-c46fafb223e69046ffba3dd8c46314058f8091f2.zip |
Changed the way AFP PTOCA TransparentData control sequences are written so that they end on character byte boundaries
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1337142 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org')
7 files changed, 267 insertions, 187 deletions
diff --git a/src/java/org/apache/fop/afp/fonts/CharactersetEncoder.java b/src/java/org/apache/fop/afp/fonts/CharactersetEncoder.java index 229123a82..6d85c0f52 100644 --- a/src/java/org/apache/fop/afp/fonts/CharactersetEncoder.java +++ b/src/java/org/apache/fop/afp/fonts/CharactersetEncoder.java @@ -105,9 +105,9 @@ public abstract class CharactersetEncoder { @Override EncodedChars getEncodedChars(byte[] byteArray, int length) { if (byteArray[0] == 0x0E && byteArray[length - 1] == 0x0F) { - return new EncodedChars(byteArray, 1, length - 2); + return new EncodedChars(byteArray, 1, length - 2, true); } - return new EncodedChars(byteArray); + return new EncodedChars(byteArray, true); } } @@ -123,7 +123,7 @@ public abstract class CharactersetEncoder { @Override EncodedChars getEncodedChars(byte[] byteArray, int length) { - return new EncodedChars(byteArray); + return new EncodedChars(byteArray, false); } } @@ -145,36 +145,25 @@ public abstract class CharactersetEncoder { /** * A container for encoded character bytes */ - public static final class EncodedChars { + public static class EncodedChars { private final byte[] bytes; - private final int offset; - private final int length; + private final boolean isDBCS; - private EncodedChars(byte[] bytes, int offset, int length) { - if (offset < 0) { - throw new IllegalArgumentException(); - } - - if (length < 0) { - throw new IllegalArgumentException(); - } - - if (offset + length > bytes.length) { + private EncodedChars(byte[] bytes, int offset, int length, boolean isDBCS) { + if (offset < 0 || length < 0 || offset + length > bytes.length) { throw new IllegalArgumentException(); } - this.bytes = bytes; - this.offset = offset; - this.length = length; + this.isDBCS = isDBCS; } - private EncodedChars(byte[] bytes) { - this(bytes, 0, bytes.length); + private EncodedChars(byte[] bytes, boolean isDBCS) { + this(bytes, 0, bytes.length, isDBCS); } /** @@ -186,18 +175,9 @@ public abstract class CharactersetEncoder { * @throws IOException if an I/O error occurs */ public void writeTo(OutputStream out, int offset, int length) throws IOException { - if (offset < 0) { + if (offset < 0 || length < 0 || offset + length > bytes.length) { throw new IllegalArgumentException(); } - - if (length < 0) { - throw new IllegalArgumentException(); - } - - if (offset + length > this.length) { - throw new IllegalArgumentException(); - } - out.write(bytes, this.offset + offset, length); } @@ -211,6 +191,15 @@ public abstract class CharactersetEncoder { } /** + * Indicates whether or not the EncodedChars object wraps double byte characters. + * + * @return true if the wrapped characters are double byte (DBCSs) + */ + public boolean isDBCS() { + return isDBCS; + } + + /** * The bytes * * @return the bytes diff --git a/src/java/org/apache/fop/afp/modca/AxisOrientation.java b/src/java/org/apache/fop/afp/modca/AxisOrientation.java new file mode 100644 index 000000000..a017fe5e3 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/AxisOrientation.java @@ -0,0 +1,82 @@ +/* + * 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.modca; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Represents the 4 bytes that specify the axis-area rotation reference coordinate system + */ +public enum AxisOrientation { + + RIGHT_HANDED_0(Rotation.ROTATION_0, Rotation.ROTATION_90), + RIGHT_HANDED_90(Rotation.ROTATION_90, Rotation.ROTATION_180), + RIGHT_HANDED_180(Rotation.ROTATION_180, Rotation.ROTATION_270), + RIGHT_HANDED_270(Rotation.ROTATION_270, Rotation.ROTATION_0); + + /** + * The object area's X-axis rotation from the X axis of the reference coordinate system + */ + private final Rotation xoaOrent; + /** + * The object area's Y-axis rotation from the Y axis of the reference coordinate system + */ + private final Rotation yoaOrent; + + public void writeTo(byte[] out, int offset) { + xoaOrent.writeTo(out, offset); + yoaOrent.writeTo(out, offset + 2); + } + + private AxisOrientation(Rotation xoaOrent, Rotation yoaOrent) { + this.xoaOrent = xoaOrent; + this.yoaOrent = yoaOrent; + } + + /** + * Writes the axis orientation area bytes to the output stream. + * + * @param stream the output stream to write to + * @throws IOException if an I/O error occurs + */ + public void writeTo(OutputStream stream) throws IOException { + byte[] data = new byte[4]; + writeTo(data, 0); + stream.write(data); + } + + /** + * Gets the right-handed axis orientation object for a given orientation in degrees. + * + * @param orientation the orientation in degrees + * @return the {@link AxisOrientation} object + */ + public static AxisOrientation getRightHandedAxisOrientationFor(int orientation) { + switch (orientation) { + case 0: return RIGHT_HANDED_0; + case 90: return RIGHT_HANDED_90; + case 180: return RIGHT_HANDED_180; + case 270: return RIGHT_HANDED_270; + default: throw new IllegalArgumentException( + "The orientation must be one of the values 0, 90, 180, 270"); + } + } +} diff --git a/src/java/org/apache/fop/afp/modca/IncludeObject.java b/src/java/org/apache/fop/afp/modca/IncludeObject.java index 68fa72688..4dca1b357 100644 --- a/src/java/org/apache/fop/afp/modca/IncludeObject.java +++ b/src/java/org/apache/fop/afp/modca/IncludeObject.java @@ -67,7 +67,7 @@ public class IncludeObject extends AbstractNamedAFPObject { private int yoaOset = 0; /** the orientation of the referenced object */ - private ObjectAreaRotation oaOrent = ObjectAreaRotation.RIGHT_HANDED_0; + private AxisOrientation oaOrent = AxisOrientation.RIGHT_HANDED_0; /** the X-axis origin defined in the object */ private int xocaOset = -1; @@ -93,7 +93,7 @@ public class IncludeObject extends AbstractNamedAFPObject { * The orientation (0,90, 180, 270) */ public void setObjectAreaOrientation(int orientation) { - this.oaOrent = ObjectAreaRotation.objectAreaRotationFor(orientation); + this.oaOrent = AxisOrientation.getRightHandedAxisOrientationFor(orientation); } /** @@ -234,69 +234,4 @@ public class IncludeObject extends AbstractNamedAFPObject { addTriplet(new MeasurementUnitsTriplet(xRes, xRes)); } - /** - * Represents the 4 bytes that specify the area rotation reference coordinate system - * - */ - private enum ObjectAreaRotation { - - RIGHT_HANDED_0(Rotation.ROTATION_0, Rotation.ROTATION_90), - RIGHT_HANDED_90(Rotation.ROTATION_90, Rotation.ROTATION_180), - RIGHT_HANDED_180(Rotation.ROTATION_180, Rotation.ROTATION_270), - RIGHT_HANDED_270(Rotation.ROTATION_270, Rotation.ROTATION_0); - - /** - * The object area's X-axis rotation from the X axis of the reference coordinate system - */ - private final Rotation xoaOrent; - /** - * The object area's Y-axis rotation from the Y axis of the reference coordinate system - */ - private final Rotation yoaOrent; - - public void writeTo(byte[] out, int offset) { - xoaOrent.writeTo(out, offset); - yoaOrent.writeTo(out, offset + 2); - } - - ObjectAreaRotation(Rotation xoaOrent, Rotation yoaOrent) { - this.xoaOrent = xoaOrent; - this.yoaOrent = yoaOrent; - } - - private static ObjectAreaRotation objectAreaRotationFor(int orientation) { - switch (orientation) { - case 0: return RIGHT_HANDED_0; - case 90: return RIGHT_HANDED_90; - case 180: return RIGHT_HANDED_180; - case 270: return RIGHT_HANDED_270; - default: throw new IllegalArgumentException( - "The orientation must be one of the values 0, 90, 180, 270"); - } - } - } - - /** - * Represents a rotation value - * - */ - private enum Rotation { - - ROTATION_0(0), - ROTATION_90(0x2D), - ROTATION_180(0x5A), - ROTATION_270(0x87); - - private final byte firstByte; - - public void writeTo(byte[] out, int offset) { - out[offset] = firstByte; - out[offset + 1] = (byte)0; - } - - Rotation(int firstByte) { - this.firstByte = (byte) firstByte; - } - } - } diff --git a/src/java/org/apache/fop/afp/modca/Rotation.java b/src/java/org/apache/fop/afp/modca/Rotation.java new file mode 100644 index 000000000..a307e1cf9 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/Rotation.java @@ -0,0 +1,46 @@ +/* + * 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.modca; + +/** + * Represents a rotation value + * + */ +public enum Rotation { + ROTATION_0(0), + ROTATION_90(0x2D), + ROTATION_180(0x5A), + ROTATION_270(0x87); + + private final byte firstByte; + + public void writeTo(byte[] out, int offset) { + out[offset] = firstByte; + out[offset + 1] = (byte)0; + } + + private Rotation(int firstByte) { + this.firstByte = (byte) firstByte; + } + + public byte getByte() { + return firstByte; + } +} diff --git a/src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java b/src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java index 1ea63c7f9..befd2cc1a 100644 --- a/src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java +++ b/src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java @@ -31,6 +31,8 @@ import org.apache.xmlgraphics.java2d.color.ColorUtil; import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives; import org.apache.fop.afp.fonts.CharactersetEncoder.EncodedChars; +import org.apache.fop.afp.modca.AxisOrientation; +import org.apache.fop.afp.ptoca.TransparentDataControlSequence.TransparentData; /** * Generator class for PTOCA data structures. @@ -87,8 +89,10 @@ public abstract class PtocaBuilder implements PtocaConstants { baout.writeTo(out); } - private void writeByte(int data) { - baout.write(data); + private void writeBytes(int... data) { + for (int d : data) { + baout.write(d); + } } private void writeShort(int data) { @@ -123,7 +127,7 @@ public abstract class PtocaBuilder implements PtocaConstants { } newControlSequence(); - writeByte(font); + writeBytes(font); commit(chained(SCFL)); } @@ -187,26 +191,11 @@ public abstract class PtocaBuilder implements PtocaConstants { * @throws IOException if an I/O error occurs */ public void addTransparentData(EncodedChars encodedChars) throws IOException { - - // data size greater than TRANSPARENT_MAX_SIZE, so slice - int numTransData = encodedChars.getLength() / TRANSPARENT_DATA_MAX_SIZE; - int currIndex = 0; - for (int transDataCnt = 0; transDataCnt < numTransData; transDataCnt++) { - addTransparentDataChunk(encodedChars, currIndex, TRANSPARENT_DATA_MAX_SIZE); - currIndex += TRANSPARENT_DATA_MAX_SIZE; + for (TransparentData trn : new TransparentDataControlSequence(encodedChars)) { + newControlSequence(); + trn.writeTo(baout); + commit(chained(TRN)); } - int left = encodedChars.getLength() - currIndex; - addTransparentDataChunk(encodedChars, currIndex, left); - - } - - - - private void addTransparentDataChunk(EncodedChars encodedChars, int offset, int length) - throws IOException { - newControlSequence(); - encodedChars.writeTo(baout, offset, length); - commit(chained(TRN)); } /** @@ -222,7 +211,7 @@ public abstract class PtocaBuilder implements PtocaConstants { newControlSequence(); writeShort(length); // Rule length writeShort(width); // Rule width - writeByte(0); // Rule width fraction is always null. enough? + writeBytes(0); // Rule width fraction is always null. enough? commit(chained(DBR)); } @@ -239,7 +228,7 @@ public abstract class PtocaBuilder implements PtocaConstants { newControlSequence(); writeShort(length); // Rule length writeShort(width); // Rule width - writeByte(0); // Rule width fraction is always null. enough? + writeBytes(0); // Rule width fraction is always null. enough? commit(chained(DIR)); } @@ -260,32 +249,7 @@ public abstract class PtocaBuilder implements PtocaConstants { return; } newControlSequence(); - switch (orientation) { - case 90: - writeByte(0x2D); - writeByte(0x00); - writeByte(0x5A); - writeByte(0x00); - break; - case 180: - writeByte(0x5A); - writeByte(0x00); - writeByte(0x87); - writeByte(0x00); - break; - case 270: - writeByte(0x87); - writeByte(0x00); - writeByte(0x00); - writeByte(0x00); - break; - default: - writeByte(0x00); - writeByte(0x00); - writeByte(0x2D); - writeByte(0x00); - break; - } + AxisOrientation.getRightHandedAxisOrientationFor(orientation).writeTo(baout); commit(chained(STO)); this.currentOrientation = orientation; currentX = -1; @@ -317,55 +281,30 @@ public abstract class PtocaBuilder implements PtocaConstants { newControlSequence(); if (col.getColorSpace().getType() == ColorSpace.TYPE_CMYK) { - writeByte(0x00); // Reserved; must be zero - writeByte(0x04); // Color space - 0x04 = CMYK - writeByte(0x00); // Reserved; must be zero - writeByte(0x00); // Reserved; must be zero - writeByte(0x00); // Reserved; must be zero - writeByte(0x00); // Reserved; must be zero - writeByte(8); // Number of bits in component 1 - writeByte(8); // Number of bits in component 2 - writeByte(8); // Number of bits in component 3 - writeByte(8); // Number of bits in component 4 + // Color space - 0x04 = CMYK, all else are reserved and must be zero + writeBytes(0x00, 0x04, 0x00, 0x00, 0x00, 0x00); + writeBytes(8, 8, 8, 8); // Number of bits in component 1, 2, 3 & 4 respectively float[] comps = col.getColorComponents(null); assert comps.length == 4; for (int i = 0; i < 4; i++) { int component = Math.round(comps[i] * 255); - writeByte(component); + writeBytes(component); } } else if (cs instanceof CIELabColorSpace) { - writeByte(0x00); // Reserved; must be zero - writeByte(0x08); // Color space - 0x08 = CIELAB - writeByte(0x00); // Reserved; must be zero - writeByte(0x00); // Reserved; must be zero - writeByte(0x00); // Reserved; must be zero - writeByte(0x00); // Reserved; must be zero - writeByte(8); // Number of bits in component 1 - writeByte(8); // Number of bits in component 2 - writeByte(8); // Number of bits in component 3 - writeByte(0); // Number of bits in component 4 + // Color space - 0x08 = CIELAB, all else are reserved and must be zero + writeBytes(0x00, 0x08, 0x00, 0x00, 0x00, 0x00); + writeBytes(8, 8, 8, 0); // Number of bits in component 1,2,3 & 4 //Sadly, 16 bit components don't seem to work float[] colorComponents = col.getColorComponents(null); int l = Math.round(colorComponents[0] * 255f); int a = Math.round(colorComponents[1] * 255f) - 128; int b = Math.round(colorComponents[2] * 255f) - 128; - writeByte(l); // L* - writeByte(a); // a* - writeByte(b); // b* + writeBytes(l, a, b); // l*, a* and b* } else { - writeByte(0x00); // Reserved; must be zero - writeByte(0x01); // Color space - 0x01 = RGB - writeByte(0x00); // Reserved; must be zero - writeByte(0x00); // Reserved; must be zero - writeByte(0x00); // Reserved; must be zero - writeByte(0x00); // Reserved; must be zero - writeByte(8); // Number of bits in component 1 - writeByte(8); // Number of bits in component 2 - writeByte(8); // Number of bits in component 3 - writeByte(0); // Number of bits in component 4 - writeByte(col.getRed()); // Red intensity - writeByte(col.getGreen()); // Green intensity - writeByte(col.getBlue()); // Blue intensity + // Color space - 0x01 = RGB, all else are reserved and must be zero + writeBytes(0x00, 0x01, 0x00, 0x00, 0x00, 0x00); + writeBytes(8, 8, 8, 0); // Number of bits in component 1, 2, 3 & 4 respectively + writeBytes(col.getRed(), col.getGreen(), col.getBlue()); // RGB intensity } commit(chained(SEC)); this.currentColor = col; @@ -407,7 +346,7 @@ public abstract class PtocaBuilder implements PtocaConstants { assert incr >= Short.MIN_VALUE && incr <= Short.MAX_VALUE; newControlSequence(); writeShort(Math.abs(incr)); //Increment - writeByte(incr >= 0 ? 0 : 1); // Direction + writeBytes(incr >= 0 ? 0 : 1); // Direction commit(chained(SIA)); this.currentInterCharacterAdjustment = incr; diff --git a/src/java/org/apache/fop/afp/ptoca/PtocaConstants.java b/src/java/org/apache/fop/afp/ptoca/PtocaConstants.java index 2e692af2c..c53b97fd0 100644 --- a/src/java/org/apache/fop/afp/ptoca/PtocaConstants.java +++ b/src/java/org/apache/fop/afp/ptoca/PtocaConstants.java @@ -64,6 +64,6 @@ public interface PtocaConstants { byte NOP = (byte)0xF8; /** Maximum size of transparent data chunks */ - int TRANSPARENT_DATA_MAX_SIZE = 253; + int TRANSPARENT_DATA_MAX_SIZE = 253; // max length = 255 (minus the ControlSequence length) } diff --git a/src/java/org/apache/fop/afp/ptoca/TransparentDataControlSequence.java b/src/java/org/apache/fop/afp/ptoca/TransparentDataControlSequence.java new file mode 100644 index 000000000..4b4276880 --- /dev/null +++ b/src/java/org/apache/fop/afp/ptoca/TransparentDataControlSequence.java @@ -0,0 +1,89 @@ +/* + * 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.ptoca; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.apache.fop.afp.fonts.CharactersetEncoder.EncodedChars; +import org.apache.fop.afp.ptoca.TransparentDataControlSequence.TransparentData; + +import static org.apache.fop.afp.ptoca.PtocaConstants.TRANSPARENT_DATA_MAX_SIZE; + +/** + * This object represents a series of PTOCA TransparentData (TRN) control sequences. This implements + * {@link Iterable} to enable iteration through the TRNs. + */ +final class TransparentDataControlSequence implements Iterable<TransparentData> { + + private static final int MAX_SBCS_TRN_SIZE = TRANSPARENT_DATA_MAX_SIZE; + // The maximum size of a TRN must be an EVEN number so that we're splitting TRNs on character + // boundaries rather than in the middle of a double-byte character + private static final int MAX_DBCS_TRN_SIZE = MAX_SBCS_TRN_SIZE - 1; + + static final class TransparentData { + private final int offset; + private final int length; + private final EncodedChars encodedChars; + + private TransparentData(int offset, int length, EncodedChars encChars) { + this.offset = offset; + this.length = length; + this.encodedChars = encChars; + } + + void writeTo(OutputStream outStream) throws IOException { + encodedChars.writeTo(outStream, offset, length); + } + } + + private final List<TransparentData> trns; + + /** + * Converts an encoded String wrapped in an {@link EncodedChars} into a series of + * {@link TransparentData} control sequences. + * + * @param encChars the encoded characters to convert to TRNs + */ + public TransparentDataControlSequence(EncodedChars encChars) { + int maxTrnLength = encChars.isDBCS() ? MAX_DBCS_TRN_SIZE : MAX_SBCS_TRN_SIZE; + int numTransData = encChars.getLength() / maxTrnLength; + int currIndex = 0; + List<TransparentData> trns = new ArrayList<TransparentData>(); + for (int transDataCnt = 0; transDataCnt < numTransData; transDataCnt++) { + trns.add(new TransparentData(currIndex, maxTrnLength, encChars)); + currIndex += maxTrnLength; + } + int left = encChars.getLength() - currIndex; + trns.add(new TransparentData(currIndex, left, encChars)); + this.trns = Collections.unmodifiableList(trns); + } + + /** + * The {@link Iterator} for retrieving the series of TRN control sequences. + */ + public Iterator<TransparentData> iterator() { + return trns.iterator(); + } +} |