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 SOF (Start Of Frame) marker segment. 41 */ 42 class SOFMarkerSegment extends MarkerSegment { 43 int samplePrecision; 44 int numLines; 45 int samplesPerLine; 46 ComponentSpec [] componentSpecs; // Array size is num components 47 48 SOFMarkerSegment(boolean wantProg, 49 boolean wantExtended, 50 boolean willSubsample, 51 byte[] componentIDs, 52 int numComponents) { 53 super(wantProg ? JPEG.SOF2 54 : wantExtended ? JPEG.SOF1 55 : JPEG.SOF0); 56 samplePrecision = 8; 57 numLines = 0; 58 samplesPerLine = 0; 59 componentSpecs = new ComponentSpec[numComponents]; 60 for(int i = 0; i < numComponents; i++) { 61 int factor = 1; 62 int qsel = 0; 63 if (willSubsample) { 64 factor = 2; 65 if ((i == 1) || (i == 2)) { 66 factor = 1; 67 qsel = 1; 68 } 69 } 70 componentSpecs[i] = new ComponentSpec(componentIDs[i], factor, qsel); 71 } 72 } 73 74 SOFMarkerSegment(JPEGBuffer buffer) throws IOException{ 75 super(buffer); 76 samplePrecision = buffer.buf[buffer.bufPtr++]; 77 numLines = (buffer.buf[buffer.bufPtr++] & 0xff) << 8; 78 numLines |= buffer.buf[buffer.bufPtr++] & 0xff; 79 samplesPerLine = (buffer.buf[buffer.bufPtr++] & 0xff) << 8; 80 samplesPerLine |= buffer.buf[buffer.bufPtr++] & 0xff; 81 int numComponents = buffer.buf[buffer.bufPtr++] & 0xff; 82 componentSpecs = new ComponentSpec [numComponents]; 83 for (int i = 0; i < numComponents; i++) { 84 componentSpecs[i] = new ComponentSpec(buffer); 85 } 86 buffer.bufAvail -= length; 87 } 88 89 SOFMarkerSegment(Node node) throws IIOInvalidTreeException { 90 // All attributes are optional, so setup defaults first 91 super(JPEG.SOF0); 92 samplePrecision = 8; 93 numLines = 0; 94 samplesPerLine = 0; 95 updateFromNativeNode(node, true); 96 } 97 98 protected SOFMarkerSegment clone() { 99 SOFMarkerSegment newGuy = (SOFMarkerSegment) super.clone(); 100 if (componentSpecs != null) { 101 newGuy.componentSpecs = componentSpecs.clone(); 102 for (int i = 0; i < componentSpecs.length; i++) { 103 newGuy.componentSpecs[i] = 104 (ComponentSpec) componentSpecs[i].clone(); 105 } 106 } 107 return newGuy; 108 } 109 110 IIOMetadataNode getNativeNode() { 111 IIOMetadataNode node = new IIOMetadataNode("sof"); 112 node.setAttribute("process", Integer.toString(tag-JPEG.SOF0)); 113 node.setAttribute("samplePrecision", 114 Integer.toString(samplePrecision)); 115 node.setAttribute("numLines", 116 Integer.toString(numLines)); 117 node.setAttribute("samplesPerLine", 118 Integer.toString(samplesPerLine)); 119 node.setAttribute("numFrameComponents", 120 Integer.toString(componentSpecs.length)); 121 for (int i = 0; i < componentSpecs.length; i++) { 122 node.appendChild(componentSpecs[i].getNativeNode()); 123 } 124 125 return node; 126 } 127 128 void updateFromNativeNode(Node node, boolean fromScratch) 129 throws IIOInvalidTreeException { 130 NamedNodeMap attrs = node.getAttributes(); 131 int value = getAttributeValue(node, attrs, "process", 0, 2, false); 132 tag = (value != -1) ? value+JPEG.SOF0 : tag; 133 // If samplePrecision is present, it must be 8. 134 // This just checks. We don't bother to assign the value. 135 value = getAttributeValue(node, attrs, "samplePrecision", 8, 8, false); 136 value = getAttributeValue(node, attrs, "numLines", 0, 65535, false); 137 numLines = (value != -1) ? value : numLines; 138 value = getAttributeValue(node, attrs, "samplesPerLine", 0, 65535, false); 139 samplesPerLine = (value != -1) ? value : samplesPerLine; 140 int numComponents = getAttributeValue(node, attrs, "numFrameComponents", 141 1, 4, false); 142 NodeList children = node.getChildNodes(); 143 if (children.getLength() != numComponents) { 144 throw new IIOInvalidTreeException 145 ("numFrameComponents must match number of children", node); 146 } 147 componentSpecs = new ComponentSpec [numComponents]; 148 for (int i = 0; i < numComponents; i++) { 149 componentSpecs[i] = new ComponentSpec(children.item(i)); 150 } 151 } 152 153 /** 154 * Writes the data for this segment to the stream in 155 * valid JPEG format. 156 */ 157 void write(ImageOutputStream ios) throws IOException { 158 // We don't write SOF segments; the IJG library does. 159 } 160 161 void print () { 162 printTag("SOF"); 163 System.out.print("Sample precision: "); 164 System.out.println(samplePrecision); 165 System.out.print("Number of lines: "); 166 System.out.println(numLines); 167 System.out.print("Samples per line: "); 168 System.out.println(samplesPerLine); 169 System.out.print("Number of components: "); 170 System.out.println(componentSpecs.length); 171 for(int i = 0; i<componentSpecs.length; i++) { 172 componentSpecs[i].print(); 173 } 174 } 175 176 int getIDencodedCSType () { 177 for (int i = 0; i < componentSpecs.length; i++) { 178 if (componentSpecs[i].componentId < 'A') { 179 return JPEG.JCS_UNKNOWN; 180 } 181 } 182 switch(componentSpecs.length) { 183 case 3: 184 if ((componentSpecs[0].componentId == 'R') 185 &&(componentSpecs[0].componentId == 'G') 186 &&(componentSpecs[0].componentId == 'B')) { 187 return JPEG.JCS_RGB; 188 } 189 if ((componentSpecs[0].componentId == 'Y') 190 &&(componentSpecs[0].componentId == 'C') 191 &&(componentSpecs[0].componentId == 'c')) { 192 return JPEG.JCS_YCC; 193 } 194 break; 195 case 4: 196 if ((componentSpecs[0].componentId == 'R') 197 &&(componentSpecs[0].componentId == 'G') 198 &&(componentSpecs[0].componentId == 'B') 199 &&(componentSpecs[0].componentId == 'A')) { 200 return JPEG.JCS_RGBA; 201 } 202 if ((componentSpecs[0].componentId == 'Y') 203 &&(componentSpecs[0].componentId == 'C') 204 &&(componentSpecs[0].componentId == 'c') 205 &&(componentSpecs[0].componentId == 'A')) { 206 return JPEG.JCS_YCCA; 207 } 208 } 209 210 return JPEG.JCS_UNKNOWN; 211 } 212 213 ComponentSpec getComponentSpec(byte id, int factor, int qSelector) { 214 return new ComponentSpec(id, factor, qSelector); 215 } 216 217 /** 218 * A component spec within an SOF marker segment. 219 */ 220 class ComponentSpec implements Cloneable { 221 int componentId; 222 int HsamplingFactor; 223 int VsamplingFactor; 224 int QtableSelector; 225 226 ComponentSpec(byte id, int factor, int qSelector) { 227 componentId = id; 228 HsamplingFactor = factor; 229 VsamplingFactor = factor; 230 QtableSelector = qSelector; 231 } 232 233 ComponentSpec(JPEGBuffer buffer) { 234 // Parent already did a loadBuf 235 componentId = buffer.buf[buffer.bufPtr++]; 236 HsamplingFactor = buffer.buf[buffer.bufPtr] >>> 4; 237 VsamplingFactor = buffer.buf[buffer.bufPtr++] & 0xf; 238 QtableSelector = buffer.buf[buffer.bufPtr++]; 239 } 240 241 ComponentSpec(Node node) throws IIOInvalidTreeException { 242 NamedNodeMap attrs = node.getAttributes(); 243 componentId = getAttributeValue(node, attrs, "componentId", 0, 255, true); 244 HsamplingFactor = getAttributeValue(node, attrs, "HsamplingFactor", 245 1, 255, true); 246 VsamplingFactor = getAttributeValue(node, attrs, "VsamplingFactor", 247 1, 255, true); 248 QtableSelector = getAttributeValue(node, attrs, "QtableSelector", 249 0, 3, true); 250 } 251 252 protected Object clone() { 253 try { 254 return super.clone(); 255 } catch (CloneNotSupportedException e) {} // won't happen 256 return null; 257 } 258 259 IIOMetadataNode getNativeNode() { 260 IIOMetadataNode node = new IIOMetadataNode("componentSpec"); 261 node.setAttribute("componentId", 262 Integer.toString(componentId)); 263 node.setAttribute("HsamplingFactor", 264 Integer.toString(HsamplingFactor)); 265 node.setAttribute("VsamplingFactor", 266 Integer.toString(VsamplingFactor)); 267 node.setAttribute("QtableSelector", 268 Integer.toString(QtableSelector)); 269 return node; 270 } 271 272 void print () { 273 System.out.print("Component ID: "); 274 System.out.println(componentId); 275 System.out.print("H sampling factor: "); 276 System.out.println(HsamplingFactor); 277 System.out.print("V sampling factor: "); 278 System.out.println(VsamplingFactor); 279 System.out.print("Q table selector: "); 280 System.out.println(QtableSelector); 281 } 282 } 283 284 }