| /* |
| * 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.ioca; |
| |
| import java.io.IOException; |
| import java.io.OutputStream; |
| |
| import org.apache.fop.afp.modca.AbstractStructuredObject; |
| import org.apache.fop.afp.util.BinaryUtils; |
| |
| public class Tile extends AbstractStructuredObject { |
| |
| private static final int MAX_DATA_LEN = 8191; |
| private TilePosition tilePosition; |
| private TileSize tileSize; |
| private BandImage bandImage; |
| private TransparencyMask transparencyMask; |
| private byte[] data; |
| |
| private IDEStructureParameter ideStructureParameter; |
| private byte encoding = (byte) 0x03; |
| private byte ideSize = 1; |
| // private byte compression = (byte) 0xC0; // Baseline DCT in case of JPEG compression |
| |
| @Override |
| public void writeContent(OutputStream os) throws IOException { |
| tilePosition.writeToStream(os); |
| tileSize.writeToStream(os); |
| os.write(getImageEncodingParameter()); |
| os.write(getImageIDESizeParameter()); |
| if (bandImage != null) { |
| bandImage.writeToStream(os); |
| } |
| if (ideStructureParameter != null) { |
| ideStructureParameter.writeToStream(os); |
| } |
| if (transparencyMask != null) { |
| transparencyMask.writeToStream(os); |
| } |
| if (data != null) { |
| writeData(os); |
| } |
| } |
| |
| private void writeData(OutputStream os) throws IOException { |
| final byte[] dataHeader = new byte[]{(byte) 0xFE, // ID |
| (byte) 0x9C, // ID |
| 0x00, // length |
| 0x00, // length |
| 0x00, // bandnum |
| 0x00, // reserved |
| 0x00 // reserved |
| }; |
| final int lengthOffset = 2; |
| if (ideSize == 24) { |
| byte[] red = new byte[data.length / 3]; |
| byte[] green = new byte[data.length / 3]; |
| byte[] blue = new byte[data.length / 3]; |
| for (int j = 0; j < data.length / 3; j++) { |
| red[j] = data[3 * j]; |
| green[j] = data[3 * j + 1]; |
| blue[j] = data[3 * j + 2]; |
| } |
| dataHeader[4] = (byte) 0x01; |
| writeChunksToStream(red, dataHeader, lengthOffset, MAX_DATA_LEN, os); |
| dataHeader[4] = (byte) 0x02; |
| writeChunksToStream(green, dataHeader, lengthOffset, MAX_DATA_LEN, os); |
| dataHeader[4] = (byte) 0x03; |
| writeChunksToStream(blue, dataHeader, lengthOffset, MAX_DATA_LEN, os); |
| } else { |
| byte[] c = new byte[data.length / 4]; |
| byte[] m = new byte[data.length / 4]; |
| byte[] y = new byte[data.length / 4]; |
| byte[] k = new byte[data.length / 4]; |
| for (int j = 0; j < data.length / 4; j++) { |
| c[j] = data[4 * j]; |
| m[j] = data[4 * j + 1]; |
| y[j] = data[4 * j + 2]; |
| k[j] = data[4 * j + 3]; |
| } |
| dataHeader[4] = (byte) 0x01; |
| writeChunksToStream(c, dataHeader, lengthOffset, MAX_DATA_LEN, os); |
| dataHeader[4] = (byte) 0x02; |
| writeChunksToStream(m, dataHeader, lengthOffset, MAX_DATA_LEN, os); |
| dataHeader[4] = (byte) 0x03; |
| writeChunksToStream(y, dataHeader, lengthOffset, MAX_DATA_LEN, os); |
| dataHeader[4] = (byte) 0x04; |
| writeChunksToStream(k, dataHeader, lengthOffset, MAX_DATA_LEN, os); |
| } |
| } |
| |
| @Override |
| protected void writeStart(OutputStream os) throws IOException { |
| final byte[] startData = new byte[] {(byte) 0x8C, // ID |
| 0x00 // Length |
| }; |
| os.write(startData); |
| } |
| |
| @Override |
| protected void writeEnd(OutputStream os) throws IOException { |
| final byte[] endData = new byte[] {(byte) 0x8D, // ID |
| 0x00, // Length |
| }; |
| os.write(endData); |
| } |
| |
| public void setPosition(TilePosition tilePosition) { |
| this.tilePosition = tilePosition; |
| } |
| |
| public void setSize(TileSize tileSize) { |
| this.tileSize = tileSize; |
| } |
| |
| public void setImageData(byte[] imageData) { |
| this.data = imageData.clone(); |
| } |
| |
| protected static void writeChunksToStream(byte[] data, byte[] dataHeader, int lengthOffset, |
| int maxChunkLength, OutputStream os) throws IOException { |
| int dataLength = data.length; |
| maxChunkLength -= 3; |
| int numFullChunks = dataLength / maxChunkLength; |
| int lastChunkLength = dataLength % maxChunkLength; |
| |
| byte[] len = {(byte) 0x1f, (byte) 0xff}; |
| int off = 0; |
| if (numFullChunks > 0) { |
| // write out full data chunks |
| dataHeader[lengthOffset] = len[0]; // Length byte 1 |
| dataHeader[lengthOffset + 1] = len[1]; // Length byte 2 |
| for (int i = 0; i < numFullChunks; i++, off += maxChunkLength) { |
| os.write(dataHeader); |
| os.write(data, off, maxChunkLength); |
| } |
| } |
| |
| if (lastChunkLength > 0) { |
| // write last data chunk |
| len = BinaryUtils.convert(3 + lastChunkLength, 2); |
| dataHeader[lengthOffset] = len[0]; // Length byte 1 |
| dataHeader[lengthOffset + 1] = len[1]; // Length byte 2 |
| os.write(dataHeader); |
| os.write(data, off, lastChunkLength); |
| } |
| } |
| |
| public void setImageEncodingParameter(byte encoding) { |
| this.encoding = encoding; |
| } |
| |
| public void setImageIDESizeParameter(byte ideSize) { |
| this.ideSize = ideSize; |
| } |
| |
| public void setIDEStructureParameter(IDEStructureParameter ideStructureParameter) { |
| this.ideStructureParameter = ideStructureParameter; |
| } |
| |
| private byte[] getImageEncodingParameter() { |
| final byte[] encodingData = new byte[] {(byte) 0x95, // ID |
| 0x02, // Length |
| encoding, (byte) (encoding == ImageContent.COMPID_JPEG ? 0xFE : 0x01), // RECID |
| }; |
| return encodingData; |
| } |
| |
| private byte[] getImageIDESizeParameter() { |
| if (ideSize != 1) { |
| final byte[] ideSizeData = new byte[] {(byte) 0x96, // ID |
| 0x01, // Length |
| ideSize}; |
| return ideSizeData; |
| } else { |
| return new byte[0]; |
| } |
| } |
| |
| public void setBandImage(BandImage bandImage) { |
| this.bandImage = bandImage; |
| } |
| |
| public void setTransparencyMask(TransparencyMask transparencyMask) { |
| this.transparencyMask = transparencyMask; |
| } |
| } |