001: /*
002: * $RCSfile: FileFormatWriter.java,v $
003: * $Revision: 1.2 $
004: * $Date: 2006/08/21 22:58:22 $
005: * $State: Exp $
006: *
007: * Class: FileFormatWriter
008: *
009: * Description: Writes the file format
010: *
011: *
012: *
013: * COPYRIGHT:
014: *
015: * This software module was originally developed by Raphaël Grosbois and
016: * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
017: * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
018: * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
019: * Centre France S.A) in the course of development of the JPEG2000
020: * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
021: * software module is an implementation of a part of the JPEG 2000
022: * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
023: * Systems AB and Canon Research Centre France S.A (collectively JJ2000
024: * Partners) agree not to assert against ISO/IEC and users of the JPEG
025: * 2000 Standard (Users) any of their rights under the copyright, not
026: * including other intellectual property rights, for this software module
027: * with respect to the usage by ISO/IEC and Users of this software module
028: * or modifications thereof for use in hardware or software products
029: * claiming conformance to the JPEG 2000 Standard. Those intending to use
030: * this software module in hardware or software products are advised that
031: * their use may infringe existing patents. The original developers of
032: * this software module, JJ2000 Partners and ISO/IEC assume no liability
033: * for use of this software module or modifications thereof. No license
034: * or right to this software module is granted for non JPEG 2000 Standard
035: * conforming products. JJ2000 Partners have full right to use this
036: * software module for his/her own purpose, assign or donate this
037: * software module to any third party and to inhibit third parties from
038: * using this software module for non JPEG 2000 Standard conforming
039: * products. This copyright notice must be included in all copies or
040: * derivative works of this software module.
041: *
042: * Copyright (c) 1999/2000 JJ2000 Partners.
043: * */
044: package jj2000.j2k.fileformat.writer;
045:
046: import java.awt.image.ColorModel;
047: import java.awt.image.DataBuffer;
048: import java.awt.image.IndexColorModel;
049: import java.awt.image.SampleModel;
050:
051: import jj2000.j2k.codestream.*;
052: import jj2000.j2k.fileformat.*;
053: import jj2000.j2k.io.*;
054:
055: import java.io.*;
056:
057: import javax.imageio.stream.ImageOutputStream;
058: import javax.imageio.metadata.IIOMetadataNode;
059: import org.w3c.dom.NodeList;
060: import com.sun.media.imageioimpl.plugins.jpeg2000.Box;
061: import com.sun.media.imageioimpl.plugins.jpeg2000.J2KMetadata;
062: import com.sun.media.imageioimpl.plugins.jpeg2000.J2KMetadataFormat;
063:
064: /**
065: * This class writes the file format wrapper that may or may not exist around
066: * a valid JPEG 2000 codestream. This class writes the simple possible legal
067: * fileformat
068: *
069: * @see jj2000.j2k.fileformat.reader.FileFormatReader
070: * */
071: public class FileFormatWriter implements FileFormatBoxes {
072:
073: /** The name of the file from which to read the codestream and to write
074: * the JP2 file*/
075: private File file;
076:
077: private ImageOutputStream stream;
078:
079: /** Image height */
080: private int height;
081:
082: /** Image width */
083: private int width;
084:
085: /** Number of components */
086: private int nc;
087:
088: /** Bits per component */
089: private int bpc[];
090:
091: /** Flag indicating whether number of bits per component varies */
092: private boolean bpcVaries;
093:
094: /** Length of codestream */
095: private int clength;
096:
097: /** Length of Colour Specification Box */
098: private static final int CSB_LENGTH = 15;
099:
100: /** Length of File Type Box */
101: private static final int FTB_LENGTH = 20;
102:
103: /** Length of Image Header Box */
104: private static final int IHB_LENGTH = 22;
105:
106: /** base length of Bits Per Component box */
107: private static final int BPC_LENGTH = 8;
108:
109: /** The color model of the image to be compressed. */
110: private ColorModel colorModel;
111:
112: /** The sample model of the image to be compressed. */
113: private SampleModel sampleModel;
114:
115: /** The sample model of the image to be compressed. */
116: private J2KMetadata metadata;
117:
118: /** Indicates that the <code>colorModel</code> is a
119: * <code>IndexColorModel</code>
120: */
121: private boolean isIndexed = false;
122:
123: /** The length not counted by the orginal JJ2000 packages. */
124: private int otherLength;
125:
126: /** cache the <code>J2KMetadataFormat</code> */
127: J2KMetadataFormat format;
128:
129: /**
130: * The constructor of the FileFormatWriter. It receives all the
131: * information necessary about a codestream to generate a legal JP2 file
132: *
133: * @param filename The name of the file that is to be made a JP2 file
134: *
135: * @param height The height of the image
136: *
137: * @param width The width of the image
138: *
139: * @param nc The number of components
140: *
141: * @param bpc The number of bits per component
142: *
143: * @param clength Length of codestream
144: * @param colorModel The color model of the image to be compressed.
145: */
146: public FileFormatWriter(File file, ImageOutputStream stream,
147: int height, int width, int nc, int[] bpc, int clength,
148: ColorModel colorModel, SampleModel sampleModel,
149: J2KMetadata metadata) {
150: this .height = height;
151: this .width = width;
152: this .nc = nc;
153: this .bpc = bpc;
154: this .file = file;
155: this .stream = stream;
156: this .clength = clength;
157: this .colorModel = colorModel;
158: this .sampleModel = sampleModel;
159: this .metadata = metadata;
160:
161: if (colorModel instanceof IndexColorModel)
162: isIndexed = true;
163:
164: bpcVaries = false;
165: int fixbpc = bpc[0];
166: for (int i = nc - 1; i > 0; i--) {
167: if (bpc[i] != fixbpc)
168: bpcVaries = true;
169: }
170: }
171:
172: /**
173: * This method reads the codestream and writes the file format wrapper and
174: * the codestream to the same file
175: *
176: * @return The number of bytes increases because of the file format
177: *
178: * @exception java.io.IOException If an I/O error ocurred.
179: * */
180: public int writeFileFormat() throws IOException {
181: writeMetadata(metadata);
182:
183: // Write the Codestream box
184: writeContiguousCodeStreamBox();
185:
186: return CSB_LENGTH + otherLength;
187: }
188:
189: private void writeMetadata(J2KMetadata metadata) throws IOException {
190: if (metadata == null)
191: return;
192:
193: IIOMetadataNode root = (IIOMetadataNode) metadata
194: .getAsTree("com_sun_media_imageio_plugins_jpeg2000_image_1.0");
195: if (root == null)
196: return;
197: format = (J2KMetadataFormat) metadata
198: .getMetadataFormat("com_sun_media_imageio_plugins_jpeg2000_image_1.0");
199: writeSuperBox(root);
200: }
201:
202: private void writeSuperBox(IIOMetadataNode node) throws IOException {
203: NodeList list = node.getChildNodes();
204:
205: String name = node.getNodeName();
206: if (name.startsWith("JPEG2000")) {
207: stream.writeInt(computeLength(node));
208: stream.writeInt(Box.getTypeInt((String) Box
209: .getTypeByName(name)));
210: otherLength += 8;
211: }
212:
213: for (int i = 0; i < list.getLength(); i++) {
214: IIOMetadataNode child = (IIOMetadataNode) list.item(i);
215:
216: name = child.getNodeName();
217: if (name.startsWith("JPEG2000") && format.isLeaf(name))
218: writeBox(child);
219: else
220: writeSuperBox(child);
221: }
222: }
223:
224: private void writeBox(IIOMetadataNode node) throws IOException {
225: int type = Box.getTypeInt((String) Box.getAttribute(node,
226: "Type"));
227: int length = new Integer((String) Box.getAttribute(node,
228: "Length")).intValue();
229: Box box = Box.createBox(type, node);
230: otherLength += length;
231: stream.writeInt(length);
232: stream.writeInt(type);
233: byte[] data = box.getContent();
234: stream.write(data, 0, data.length);
235: }
236:
237: private int computeLength(IIOMetadataNode root) {
238: NodeList list = root.getChildNodes();
239: int length = 0;
240: for (int i = 0; i < list.getLength(); i++) {
241: IIOMetadataNode node = (IIOMetadataNode) list.item(i);
242: String name = node.getNodeName();
243:
244: if (format.isLeaf(name))
245: length += new Integer((String) Box.getAttribute(node,
246: "Length")).intValue();
247: else
248: length += computeLength(node);
249:
250: }
251:
252: return length
253: + (root.getNodeName().startsWith("JPEG2000") ? 8 : 0);
254: }
255:
256: /**
257: * This method writes the Contiguous codestream box
258: *
259: * @param cs The contiguous codestream
260: *
261: * @exception java.io.IOException If an I/O error ocurred.
262: * */
263: public void writeContiguousCodeStreamBox() throws IOException {
264:
265: //when write a jp2 file
266: if (metadata != null) {
267: // Write box length (LBox)
268: // This value is set to 0 since in this implementation, this box is
269: // always last
270: stream.writeInt(clength + 8);
271:
272: // Write contiguous codestream box name (TBox)
273: stream.writeInt(CONTIGUOUS_CODESTREAM_BOX);
274: }
275: // Read and buffer the codestream
276: BEBufferedRandomAccessFile fi = new BEBufferedRandomAccessFile(
277: file, "rw+");
278: int remainder = clength;
279: byte[] codestream = new byte[1024];
280:
281: while (remainder > 0) {
282: int len = remainder > 1024 ? 1024 : remainder;
283: fi.readFully(codestream, 0, len);
284:
285: // Write codestream
286: stream.write(codestream, 0, len);
287: remainder -= len;
288: }
289:
290: // Close the file.
291: fi.close();
292: }
293: }
|