1. /*
  2. * @(#)SOFMarkerSegment.java 1.5 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.imageio.plugins.jpeg;
  8. //import javax.imageio.IIOException;
  9. import javax.imageio.metadata.IIOInvalidTreeException;
  10. import javax.imageio.metadata.IIOMetadataNode;
  11. import javax.imageio.stream.ImageOutputStream;
  12. import java.io.IOException;
  13. import org.w3c.dom.Node;
  14. import org.w3c.dom.NodeList;
  15. import org.w3c.dom.NamedNodeMap;
  16. /**
  17. * An SOF (Start Of Frame) marker segment.
  18. */
  19. class SOFMarkerSegment extends MarkerSegment {
  20. int samplePrecision;
  21. int numLines;
  22. int samplesPerLine;
  23. ComponentSpec [] componentSpecs; // Array size is num components
  24. SOFMarkerSegment(boolean wantProg,
  25. boolean wantExtended,
  26. boolean willSubsample,
  27. byte[] componentIDs,
  28. int numComponents) {
  29. super(wantProg ? JPEG.SOF2
  30. : wantExtended ? JPEG.SOF1
  31. : JPEG.SOF0);
  32. samplePrecision = 8;
  33. numLines = 0;
  34. samplesPerLine = 0;
  35. componentSpecs = new ComponentSpec[numComponents];
  36. for(int i = 0; i < numComponents; i++) {
  37. int factor = 1;
  38. int qsel = 0;
  39. if (willSubsample) {
  40. factor = 2;
  41. if ((i == 1) || (i == 2)) {
  42. factor = 1;
  43. qsel = 1;
  44. }
  45. }
  46. componentSpecs[i] = new ComponentSpec(componentIDs[i], factor, qsel);
  47. }
  48. }
  49. SOFMarkerSegment(JPEGBuffer buffer) throws IOException{
  50. super(buffer);
  51. samplePrecision = buffer.buf[buffer.bufPtr++];
  52. numLines = (buffer.buf[buffer.bufPtr++] & 0xff) << 8;
  53. numLines |= buffer.buf[buffer.bufPtr++] & 0xff;
  54. samplesPerLine = (buffer.buf[buffer.bufPtr++] & 0xff) << 8;
  55. samplesPerLine |= buffer.buf[buffer.bufPtr++] & 0xff;
  56. int numComponents = buffer.buf[buffer.bufPtr++];
  57. componentSpecs = new ComponentSpec [numComponents];
  58. for (int i = 0; i < numComponents; i++) {
  59. componentSpecs[i] = new ComponentSpec(buffer);
  60. }
  61. buffer.bufAvail -= length;
  62. }
  63. SOFMarkerSegment(Node node) throws IIOInvalidTreeException {
  64. // All attributes are optional, so setup defaults first
  65. super(JPEG.SOF0);
  66. samplePrecision = 8;
  67. numLines = 0;
  68. samplesPerLine = 0;
  69. updateFromNativeNode(node, true);
  70. }
  71. protected Object clone() {
  72. SOFMarkerSegment newGuy = (SOFMarkerSegment) super.clone();
  73. if (componentSpecs != null) {
  74. newGuy.componentSpecs = (ComponentSpec []) componentSpecs.clone();
  75. for (int i = 0; i < componentSpecs.length; i++) {
  76. newGuy.componentSpecs[i] =
  77. (ComponentSpec) componentSpecs[i].clone();
  78. }
  79. }
  80. return newGuy;
  81. }
  82. IIOMetadataNode getNativeNode() {
  83. IIOMetadataNode node = new IIOMetadataNode("sof");
  84. node.setAttribute("process", Integer.toString(tag-JPEG.SOF0));
  85. node.setAttribute("samplePrecision",
  86. Integer.toString(samplePrecision));
  87. node.setAttribute("numLines",
  88. Integer.toString(numLines));
  89. node.setAttribute("samplesPerLine",
  90. Integer.toString(samplesPerLine));
  91. node.setAttribute("numFrameComponents",
  92. Integer.toString(componentSpecs.length));
  93. for (int i = 0; i < componentSpecs.length; i++) {
  94. node.appendChild(componentSpecs[i].getNativeNode());
  95. }
  96. return node;
  97. }
  98. void updateFromNativeNode(Node node, boolean fromScratch)
  99. throws IIOInvalidTreeException {
  100. NamedNodeMap attrs = node.getAttributes();
  101. int value = getAttributeValue(node, attrs, "process", 0, 2, false);
  102. tag = (value != -1) ? value+JPEG.SOF0 : tag;
  103. // If samplePrecision is present, it must be 8.
  104. // This just checks. We don't bother to assign the value.
  105. value = getAttributeValue(node, attrs, "samplePrecision", 8, 8, false);
  106. value = getAttributeValue(node, attrs, "numLines", 0, 65535, false);
  107. numLines = (value != -1) ? value : numLines;
  108. value = getAttributeValue(node, attrs, "samplesPerLine", 0, 65535, false);
  109. samplesPerLine = (value != -1) ? value : samplesPerLine;
  110. int numComponents = getAttributeValue(node, attrs, "numFrameComponents",
  111. 1, 4, false);
  112. NodeList children = node.getChildNodes();
  113. if (children.getLength() != numComponents) {
  114. throw new IIOInvalidTreeException
  115. ("numFrameComponents must match number of children", node);
  116. }
  117. componentSpecs = new ComponentSpec [numComponents];
  118. for (int i = 0; i < numComponents; i++) {
  119. componentSpecs[i] = new ComponentSpec(children.item(i));
  120. }
  121. }
  122. /**
  123. * Writes the data for this segment to the stream in
  124. * valid JPEG format.
  125. */
  126. void write(ImageOutputStream ios) throws IOException {
  127. // We don't write SOF segments; the IJG library does.
  128. }
  129. void print () {
  130. printTag("SOF");
  131. System.out.print("Sample precision: ");
  132. System.out.println(samplePrecision);
  133. System.out.print("Number of lines: ");
  134. System.out.println(numLines);
  135. System.out.print("Samples per line: ");
  136. System.out.println(samplesPerLine);
  137. System.out.print("Number of components: ");
  138. System.out.println(componentSpecs.length);
  139. for(int i = 0; i<componentSpecs.length; i++) {
  140. componentSpecs[i].print();
  141. }
  142. }
  143. int getIDencodedCSType () {
  144. for (int i = 0; i < componentSpecs.length; i++) {
  145. if (componentSpecs[i].componentId < 'A') {
  146. return JPEG.JCS_UNKNOWN;
  147. }
  148. }
  149. switch(componentSpecs.length) {
  150. case 3:
  151. if ((componentSpecs[0].componentId == 'R')
  152. &&(componentSpecs[0].componentId == 'G')
  153. &&(componentSpecs[0].componentId == 'B')) {
  154. return JPEG.JCS_RGB;
  155. }
  156. if ((componentSpecs[0].componentId == 'Y')
  157. &&(componentSpecs[0].componentId == 'C')
  158. &&(componentSpecs[0].componentId == 'c')) {
  159. return JPEG.JCS_YCC;
  160. }
  161. break;
  162. case 4:
  163. if ((componentSpecs[0].componentId == 'R')
  164. &&(componentSpecs[0].componentId == 'G')
  165. &&(componentSpecs[0].componentId == 'B')
  166. &&(componentSpecs[0].componentId == 'A')) {
  167. return JPEG.JCS_RGBA;
  168. }
  169. if ((componentSpecs[0].componentId == 'Y')
  170. &&(componentSpecs[0].componentId == 'C')
  171. &&(componentSpecs[0].componentId == 'c')
  172. &&(componentSpecs[0].componentId == 'A')) {
  173. return JPEG.JCS_YCCA;
  174. }
  175. }
  176. return JPEG.JCS_UNKNOWN;
  177. }
  178. ComponentSpec getComponentSpec(byte id, int factor, int qSelector) {
  179. return new ComponentSpec(id, factor, qSelector);
  180. }
  181. /**
  182. * A component spec within an SOF marker segment.
  183. */
  184. class ComponentSpec implements Cloneable {
  185. int componentId;
  186. int HsamplingFactor;
  187. int VsamplingFactor;
  188. int QtableSelector;
  189. ComponentSpec(byte id, int factor, int qSelector) {
  190. componentId = id;
  191. HsamplingFactor = factor;
  192. VsamplingFactor = factor;
  193. QtableSelector = qSelector;
  194. }
  195. ComponentSpec(JPEGBuffer buffer) {
  196. // Parent already did a loadBuf
  197. componentId = buffer.buf[buffer.bufPtr++];
  198. HsamplingFactor = buffer.buf[buffer.bufPtr] >>> 4;
  199. VsamplingFactor = buffer.buf[buffer.bufPtr++] & 0xf;
  200. QtableSelector = buffer.buf[buffer.bufPtr++];
  201. }
  202. ComponentSpec(Node node) throws IIOInvalidTreeException {
  203. NamedNodeMap attrs = node.getAttributes();
  204. componentId = getAttributeValue(node, attrs, "componentId", 0, 255, true);
  205. HsamplingFactor = getAttributeValue(node, attrs, "HsamplingFactor",
  206. 1, 255, true);
  207. VsamplingFactor = getAttributeValue(node, attrs, "VsamplingFactor",
  208. 1, 255, true);
  209. QtableSelector = getAttributeValue(node, attrs, "QtableSelector",
  210. 0, 3, true);
  211. }
  212. protected Object clone() {
  213. try {
  214. return super.clone();
  215. } catch (CloneNotSupportedException e) {} // won't happen
  216. return null;
  217. }
  218. IIOMetadataNode getNativeNode() {
  219. IIOMetadataNode node = new IIOMetadataNode("componentSpec");
  220. node.setAttribute("componentId",
  221. Integer.toString(componentId));
  222. node.setAttribute("HsamplingFactor",
  223. Integer.toString(HsamplingFactor));
  224. node.setAttribute("VsamplingFactor",
  225. Integer.toString(VsamplingFactor));
  226. node.setAttribute("QtableSelector",
  227. Integer.toString(QtableSelector));
  228. return node;
  229. }
  230. void print () {
  231. System.out.print("Component ID: ");
  232. System.out.println(componentId);
  233. System.out.print("H sampling factor: ");
  234. System.out.println(HsamplingFactor);
  235. System.out.print("V sampling factor: ");
  236. System.out.println(VsamplingFactor);
  237. System.out.print("Q table selector: ");
  238. System.out.println(QtableSelector);
  239. }
  240. }
  241. }