1 /*
2  * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.imageio.plugins.jpeg;
27 
28 //import javax.imageio.IIOException;
29 import javax.imageio.metadata.IIOInvalidTreeException;
30 import javax.imageio.metadata.IIOMetadataNode;
31 import javax.imageio.stream.ImageOutputStream;
32 
33 import java.io.IOException;
34 
35 import org.w3c.dom.Node;
36 import org.w3c.dom.NodeList;
37 import org.w3c.dom.NamedNodeMap;
38 
39 /**
40  * An SOS (Start Of Scan) marker segment.
41  */
42 class SOSMarkerSegment extends MarkerSegment {
43     int startSpectralSelection;
44     int endSpectralSelection;
45     int approxHigh;
46     int approxLow;
47     ScanComponentSpec [] componentSpecs; // Array size is numScanComponents
48 
SOSMarkerSegment(boolean willSubsample, byte[] componentIDs, int numComponents)49     SOSMarkerSegment(boolean willSubsample,
50                      byte[] componentIDs,
51                      int numComponents) {
52         super(JPEG.SOS);
53         startSpectralSelection = 0;
54         endSpectralSelection = 63;
55         approxHigh = 0;
56         approxLow = 0;
57         componentSpecs = new ScanComponentSpec[numComponents];
58         for (int i = 0; i < numComponents; i++) {
59             int tableSel = 0;
60             if (willSubsample) {
61                 if ((i == 1) || (i == 2)) {
62                     tableSel = 1;
63                 }
64             }
65             componentSpecs[i] = new ScanComponentSpec(componentIDs[i],
66                                                       tableSel);
67         }
68     }
69 
SOSMarkerSegment(JPEGBuffer buffer)70     SOSMarkerSegment(JPEGBuffer buffer) throws IOException {
71         super(buffer);
72         int numComponents = buffer.buf[buffer.bufPtr++];
73         componentSpecs = new ScanComponentSpec[numComponents];
74         for (int i = 0; i < numComponents; i++) {
75             componentSpecs[i] = new ScanComponentSpec(buffer);
76         }
77         startSpectralSelection = buffer.buf[buffer.bufPtr++];
78         endSpectralSelection = buffer.buf[buffer.bufPtr++];
79         approxHigh = buffer.buf[buffer.bufPtr] >> 4;
80         approxLow = buffer.buf[buffer.bufPtr++] &0xf;
81         buffer.bufAvail -= length;
82     }
83 
SOSMarkerSegment(Node node)84     SOSMarkerSegment(Node node) throws IIOInvalidTreeException {
85         super(JPEG.SOS);
86         startSpectralSelection = 0;
87         endSpectralSelection = 63;
88         approxHigh = 0;
89         approxLow = 0;
90         updateFromNativeNode(node, true);
91     }
92 
clone()93     protected Object clone () {
94         SOSMarkerSegment newGuy = (SOSMarkerSegment) super.clone();
95         if (componentSpecs != null) {
96             newGuy.componentSpecs = componentSpecs.clone();
97             for (int i = 0; i < componentSpecs.length; i++) {
98                 newGuy.componentSpecs[i] =
99                     (ScanComponentSpec) componentSpecs[i].clone();
100             }
101         }
102         return newGuy;
103     }
104 
getNativeNode()105     IIOMetadataNode getNativeNode() {
106         IIOMetadataNode node = new IIOMetadataNode("sos");
107         node.setAttribute("numScanComponents",
108                           Integer.toString(componentSpecs.length));
109         node.setAttribute("startSpectralSelection",
110                           Integer.toString(startSpectralSelection));
111         node.setAttribute("endSpectralSelection",
112                           Integer.toString(endSpectralSelection));
113         node.setAttribute("approxHigh",
114                           Integer.toString(approxHigh));
115         node.setAttribute("approxLow",
116                           Integer.toString(approxLow));
117         for (int i = 0; i < componentSpecs.length; i++) {
118             node.appendChild(componentSpecs[i].getNativeNode());
119         }
120 
121         return node;
122     }
123 
updateFromNativeNode(Node node, boolean fromScratch)124     void updateFromNativeNode(Node node, boolean fromScratch)
125         throws IIOInvalidTreeException {
126         NamedNodeMap attrs = node.getAttributes();
127         int numComponents = getAttributeValue(node, attrs, "numScanComponents",
128                                               1, 4, true);
129         int value = getAttributeValue(node, attrs, "startSpectralSelection",
130                                       0, 63, false);
131         startSpectralSelection = (value != -1) ? value : startSpectralSelection;
132         value = getAttributeValue(node, attrs, "endSpectralSelection",
133                                   0, 63, false);
134         endSpectralSelection = (value != -1) ? value : endSpectralSelection;
135         value = getAttributeValue(node, attrs, "approxHigh", 0, 15, false);
136         approxHigh = (value != -1) ? value : approxHigh;
137         value = getAttributeValue(node, attrs, "approxLow", 0, 15, false);
138         approxLow = (value != -1) ? value : approxLow;
139 
140         // Now the children
141         NodeList children = node.getChildNodes();
142         if (children.getLength() != numComponents) {
143             throw new IIOInvalidTreeException
144                 ("numScanComponents must match the number of children", node);
145         }
146         componentSpecs = new ScanComponentSpec[numComponents];
147         for (int i = 0; i < numComponents; i++) {
148             componentSpecs[i] = new ScanComponentSpec(children.item(i));
149         }
150     }
151 
152     /**
153      * Writes the data for this segment to the stream in
154      * valid JPEG format.
155      */
write(ImageOutputStream ios)156     void write(ImageOutputStream ios) throws IOException {
157         // We don't write SOS segments; the IJG library does.
158     }
159 
print()160     void print () {
161         printTag("SOS");
162         System.out.print("Start spectral selection: ");
163         System.out.println(startSpectralSelection);
164         System.out.print("End spectral selection: ");
165         System.out.println(endSpectralSelection);
166         System.out.print("Approx high: ");
167         System.out.println(approxHigh);
168         System.out.print("Approx low: ");
169         System.out.println(approxLow);
170         System.out.print("Num scan components: ");
171         System.out.println(componentSpecs.length);
172         for (int i = 0; i< componentSpecs.length; i++) {
173             componentSpecs[i].print();
174         }
175     }
176 
getScanComponentSpec(byte componentSel, int tableSel)177     ScanComponentSpec getScanComponentSpec(byte componentSel, int tableSel) {
178         return new ScanComponentSpec(componentSel, tableSel);
179     }
180 
181     /**
182      * A scan component spec within an SOS marker segment.
183      */
184     class ScanComponentSpec implements Cloneable {
185         int componentSelector;
186         int dcHuffTable;
187         int acHuffTable;
188 
ScanComponentSpec(byte componentSel, int tableSel)189         ScanComponentSpec(byte componentSel, int tableSel) {
190             componentSelector = componentSel;
191             dcHuffTable = tableSel;
192             acHuffTable = tableSel;
193         }
194 
ScanComponentSpec(JPEGBuffer buffer)195         ScanComponentSpec(JPEGBuffer buffer) {
196             // Parent already loaded the buffer
197             componentSelector = buffer.buf[buffer.bufPtr++];
198             dcHuffTable = buffer.buf[buffer.bufPtr] >> 4;
199             acHuffTable = buffer.buf[buffer.bufPtr++] & 0xf;
200         }
201 
ScanComponentSpec(Node node)202         ScanComponentSpec(Node node) throws IIOInvalidTreeException {
203             NamedNodeMap attrs = node.getAttributes();
204             componentSelector = getAttributeValue(node, attrs, "componentSelector",
205                                                   0, 255, true);
206             dcHuffTable = getAttributeValue(node, attrs, "dcHuffTable",
207                                             0, 3, true);
208             acHuffTable = getAttributeValue(node, attrs, "acHuffTable",
209                                             0, 3, true);
210         }
211 
clone()212         protected Object clone() {
213             try {
214                 return super.clone();
215             } catch (CloneNotSupportedException e) {} // won't happen
216             return null;
217         }
218 
getNativeNode()219         IIOMetadataNode getNativeNode() {
220             IIOMetadataNode node = new IIOMetadataNode("scanComponentSpec");
221             node.setAttribute("componentSelector",
222                               Integer.toString(componentSelector));
223             node.setAttribute("dcHuffTable",
224                               Integer.toString(dcHuffTable));
225             node.setAttribute("acHuffTable",
226                               Integer.toString(acHuffTable));
227             return node;
228         }
229 
print()230         void print () {
231             System.out.print("Component Selector: ");
232             System.out.println(componentSelector);
233             System.out.print("DC huffman table: ");
234             System.out.println(dcHuffTable);
235             System.out.print("AC huffman table: ");
236             System.out.println(acHuffTable);
237         }
238     }
239 
240 }
241