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 import javax.imageio.plugins.jpeg.JPEGQTable;
33
34 import java.io.IOException;
35 import java.util.List;
36 import java.util.ArrayList;
37 import java.util.Iterator;
38
39 import org.w3c.dom.Node;
40 import org.w3c.dom.NodeList;
41 import org.w3c.dom.NamedNodeMap;
42
43 /**
44 * A DQT (Define Quantization Table) marker segment.
45 */
46 class DQTMarkerSegment extends MarkerSegment {
47 List tables = new ArrayList(); // Could be 1 to 4
48
49 DQTMarkerSegment(float quality, boolean needTwo) {
50 super(JPEG.DQT);
51 tables.add(new Qtable(true, quality));
52 if (needTwo) {
53 tables.add(new Qtable(false, quality));
54 }
55 }
56
57 DQTMarkerSegment(JPEGBuffer buffer) throws IOException {
58 super(buffer);
59 int count = length;
60 while (count > 0) {
61 Qtable newGuy = new Qtable(buffer);
62 tables.add(newGuy);
63 count -= newGuy.data.length+1;
64 }
65 buffer.bufAvail -= length;
66 }
67
68 DQTMarkerSegment(JPEGQTable[] qtables) {
69 super(JPEG.DQT);
70 for (int i = 0; i < qtables.length; i++) {
71 tables.add(new Qtable(qtables[i], i));
72 }
73 }
74
75 DQTMarkerSegment(Node node) throws IIOInvalidTreeException {
76 super(JPEG.DQT);
77 NodeList children = node.getChildNodes();
78 int size = children.getLength();
79 if ((size < 1) || (size > 4)) {
80 throw new IIOInvalidTreeException("Invalid DQT node", node);
81 }
82 for (int i = 0; i < size; i++) {
83 tables.add(new Qtable(children.item(i)));
84 }
85 }
86
87 protected Object clone() {
88 DQTMarkerSegment newGuy = (DQTMarkerSegment) super.clone();
89 newGuy.tables = new ArrayList(tables.size());
90 Iterator iter = tables.iterator();
91 while (iter.hasNext()) {
92 Qtable table = (Qtable) iter.next();
93 newGuy.tables.add(table.clone());
94 }
95 return newGuy;
96 }
97
98 IIOMetadataNode getNativeNode() {
99 IIOMetadataNode node = new IIOMetadataNode("dqt");
100 for (int i= 0; i<tables.size(); i++) {
101 Qtable table = (Qtable) tables.get(i);
102 node.appendChild(table.getNativeNode());
103 }
104 return node;
105 }
106
107 /**
108 * Writes the data for this segment to the stream in
109 * valid JPEG format.
110 */
111 void write(ImageOutputStream ios) throws IOException {
112 // We don't write DQT segments; the IJG library does.
113 }
114
115 void print() {
116 printTag("DQT");
117 System.out.println("Num tables: "
118 + Integer.toString(tables.size()));
119 for (int i= 0; i<tables.size(); i++) {
120 Qtable table = (Qtable) tables.get(i);
121 table.print();
122 }
123 System.out.println();
124 }
125
126 /**
127 * Assuming the given table was generated by scaling the "standard"
128 * visually lossless luminance table, extract the scale factor that
129 * was used.
130 */
131 Qtable getChromaForLuma(Qtable luma) {
132 Qtable newGuy = null;
133 // Determine if the table is all the same values
134 // if so, use the same table
135 boolean allSame = true;
136 for (int i = 1; i < luma.QTABLE_SIZE; i++) {
137 if (luma.data[i] != luma.data[i-1]) {
138 allSame = false;
139 break;
140 }
141 }
142 if (allSame) {
143 newGuy = (Qtable) luma.clone();
144 newGuy.tableID = 1;
145 } else {
146 // Otherwise, find the largest coefficient less than 255. This is
147 // the largest value that we know did not clamp on scaling.
148 int largestPos = 0;
149 for (int i = 1; i < luma.QTABLE_SIZE; i++) {
150 if (luma.data[i] > luma.data[largestPos]) {
151 largestPos = i;
152 }
153 }
154 // Compute the scale factor by dividing it by the value in the
155 // same position from the "standard" table.
156 // If the given table was not generated by scaling the standard,
157 // the resulting table will still be reasonable, as it will reflect
158 // a comparable scaling of chrominance frequency response of the
159 // eye.
160 float scaleFactor = ((float)(luma.data[largestPos]))
161 / ((float)(JPEGQTable.K1Div2Luminance.getTable()[largestPos]));
162 // generate a new table
163 JPEGQTable jpegTable =
251 elementPrecision = 0;
252 tableID = getAttributeValue(node, attrs, "qtableId", 0, 3, true);
253 if (node instanceof IIOMetadataNode) {
254 IIOMetadataNode ourNode = (IIOMetadataNode) node;
255 JPEGQTable table = (JPEGQTable) ourNode.getUserObject();
256 if (table == null) {
257 throw new IIOInvalidTreeException
258 ("dqtable node must have user object", node);
259 }
260 data = table.getTable();
261 } else {
262 throw new IIOInvalidTreeException
263 ("dqtable node must have user object", node);
264 }
265 } else {
266 throw new IIOInvalidTreeException
267 ("Invalid node, expected dqtable", node);
268 }
269 }
270
271 protected Object clone() {
272 Qtable newGuy = null;
273 try {
274 newGuy = (Qtable) super.clone();
275 } catch (CloneNotSupportedException e) {} // won't happen
276 if (data != null) {
277 newGuy.data = data.clone();
278 }
279 return newGuy;
280 }
281
282 IIOMetadataNode getNativeNode() {
283 IIOMetadataNode node = new IIOMetadataNode("dqtable");
284 node.setAttribute("elementPrecision",
285 Integer.toString(elementPrecision));
286 node.setAttribute("qtableId",
287 Integer.toString(tableID));
288 node.setUserObject(new JPEGQTable(data));
289 return node;
290 }
291
|
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 import javax.imageio.plugins.jpeg.JPEGQTable;
33
34 import java.io.IOException;
35 import java.util.List;
36 import java.util.ArrayList;
37 import java.util.Iterator;
38
39 import org.w3c.dom.Node;
40 import org.w3c.dom.NodeList;
41 import org.w3c.dom.NamedNodeMap;
42
43 /**
44 * A DQT (Define Quantization Table) marker segment.
45 */
46 class DQTMarkerSegment extends MarkerSegment {
47 List<Qtable> tables = new ArrayList<>(); // Could be 1 to 4
48
49 DQTMarkerSegment(float quality, boolean needTwo) {
50 super(JPEG.DQT);
51 tables.add(new Qtable(true, quality));
52 if (needTwo) {
53 tables.add(new Qtable(false, quality));
54 }
55 }
56
57 DQTMarkerSegment(JPEGBuffer buffer) throws IOException {
58 super(buffer);
59 int count = length;
60 while (count > 0) {
61 Qtable newGuy = new Qtable(buffer);
62 tables.add(newGuy);
63 count -= newGuy.data.length+1;
64 }
65 buffer.bufAvail -= length;
66 }
67
68 DQTMarkerSegment(JPEGQTable[] qtables) {
69 super(JPEG.DQT);
70 for (int i = 0; i < qtables.length; i++) {
71 tables.add(new Qtable(qtables[i], i));
72 }
73 }
74
75 DQTMarkerSegment(Node node) throws IIOInvalidTreeException {
76 super(JPEG.DQT);
77 NodeList children = node.getChildNodes();
78 int size = children.getLength();
79 if ((size < 1) || (size > 4)) {
80 throw new IIOInvalidTreeException("Invalid DQT node", node);
81 }
82 for (int i = 0; i < size; i++) {
83 tables.add(new Qtable(children.item(i)));
84 }
85 }
86
87 protected DQTMarkerSegment clone() {
88 DQTMarkerSegment newGuy = (DQTMarkerSegment) super.clone();
89 newGuy.tables = new ArrayList<>(tables.size());
90 Iterator<Qtable> iter = tables.iterator();
91 while (iter.hasNext()) {
92 Qtable table = iter.next();
93 newGuy.tables.add(table.clone());
94 }
95 return newGuy;
96 }
97
98 IIOMetadataNode getNativeNode() {
99 IIOMetadataNode node = new IIOMetadataNode("dqt");
100 for (int i= 0; i<tables.size(); i++) {
101 Qtable table = tables.get(i);
102 node.appendChild(table.getNativeNode());
103 }
104 return node;
105 }
106
107 /**
108 * Writes the data for this segment to the stream in
109 * valid JPEG format.
110 */
111 void write(ImageOutputStream ios) throws IOException {
112 // We don't write DQT segments; the IJG library does.
113 }
114
115 void print() {
116 printTag("DQT");
117 System.out.println("Num tables: "
118 + Integer.toString(tables.size()));
119 for (int i= 0; i<tables.size(); i++) {
120 Qtable table = tables.get(i);
121 table.print();
122 }
123 System.out.println();
124 }
125
126 /**
127 * Assuming the given table was generated by scaling the "standard"
128 * visually lossless luminance table, extract the scale factor that
129 * was used.
130 */
131 Qtable getChromaForLuma(Qtable luma) {
132 Qtable newGuy = null;
133 // Determine if the table is all the same values
134 // if so, use the same table
135 boolean allSame = true;
136 for (int i = 1; i < luma.QTABLE_SIZE; i++) {
137 if (luma.data[i] != luma.data[i-1]) {
138 allSame = false;
139 break;
140 }
141 }
142 if (allSame) {
143 newGuy = luma.clone();
144 newGuy.tableID = 1;
145 } else {
146 // Otherwise, find the largest coefficient less than 255. This is
147 // the largest value that we know did not clamp on scaling.
148 int largestPos = 0;
149 for (int i = 1; i < luma.QTABLE_SIZE; i++) {
150 if (luma.data[i] > luma.data[largestPos]) {
151 largestPos = i;
152 }
153 }
154 // Compute the scale factor by dividing it by the value in the
155 // same position from the "standard" table.
156 // If the given table was not generated by scaling the standard,
157 // the resulting table will still be reasonable, as it will reflect
158 // a comparable scaling of chrominance frequency response of the
159 // eye.
160 float scaleFactor = ((float)(luma.data[largestPos]))
161 / ((float)(JPEGQTable.K1Div2Luminance.getTable()[largestPos]));
162 // generate a new table
163 JPEGQTable jpegTable =
251 elementPrecision = 0;
252 tableID = getAttributeValue(node, attrs, "qtableId", 0, 3, true);
253 if (node instanceof IIOMetadataNode) {
254 IIOMetadataNode ourNode = (IIOMetadataNode) node;
255 JPEGQTable table = (JPEGQTable) ourNode.getUserObject();
256 if (table == null) {
257 throw new IIOInvalidTreeException
258 ("dqtable node must have user object", node);
259 }
260 data = table.getTable();
261 } else {
262 throw new IIOInvalidTreeException
263 ("dqtable node must have user object", node);
264 }
265 } else {
266 throw new IIOInvalidTreeException
267 ("Invalid node, expected dqtable", node);
268 }
269 }
270
271 protected Qtable clone() {
272 Qtable newGuy = null;
273 try {
274 newGuy = (Qtable) super.clone();
275 } catch (CloneNotSupportedException e) {} // won't happen
276 if (data != null) {
277 newGuy.data = data.clone();
278 }
279 return newGuy;
280 }
281
282 IIOMetadataNode getNativeNode() {
283 IIOMetadataNode node = new IIOMetadataNode("dqtable");
284 node.setAttribute("elementPrecision",
285 Integer.toString(elementPrecision));
286 node.setAttribute("qtableId",
287 Integer.toString(tableID));
288 node.setUserObject(new JPEGQTable(data));
289 return node;
290 }
291
|