001: /*
002: * $RCSfile: AnWTFilterSpec.java,v $
003: * $Revision: 1.1 $
004: * $Date: 2005/02/11 05:02:29 $
005: * $State: Exp $
006: *
007: * Class: AnWTFilterSpec
008: *
009: * Description: Analysis filters specification
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.wavelet.analysis;
045:
046: import jj2000.j2k.quantization.*;
047: import jj2000.j2k.util.*;
048: import jj2000.j2k.*;
049:
050: import java.util.*;
051:
052: import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageWriteParamJava;
053:
054: /**
055: * This class extends ModuleSpec class for analysis filters specification
056: * holding purpose.
057: *
058: * @see ModuleSpec
059: * */
060: public class AnWTFilterSpec extends ModuleSpec {
061:
062: /** The reversible default filter */
063: private final static String REV_FILTER_STR = "w5x3";
064:
065: /** The non-reversible default filter */
066: private final static String NON_REV_FILTER_STR = "w9x7";
067:
068: /**
069: * Constructs a new 'AnWTFilterSpec' for the specified number of
070: * components and tiles.
071: *
072: * @param nt The number of tiles
073: *
074: * @param nc The number of components
075: *
076: * @param type the type of the specification module i.e. tile specific,
077: * component specific or both.
078: *
079: * @param qts Quantization specifications
080: * */
081: public AnWTFilterSpec(int nt, int nc, byte type, QuantTypeSpec qts,
082: J2KImageWriteParamJava wp, String values) {
083: super (nt, nc, type);
084: /*
085: // Check parameters
086: pl.checkList(AnWTFilter.OPT_PREFIX,
087: pl.toNameArray(AnWTFilter.getParameterInfo()));
088: */
089: specified = values;
090: String param = specified;
091: boolean isFilterSpecified = true;
092:
093: // No parameter specified
094: if (values == null) {
095: isFilterSpecified = false;
096:
097: if (wp.getLossless()) {
098: setDefault(parseFilters(REV_FILTER_STR));
099: return;
100: }
101:
102: // If no filter is specified through the command-line, use
103: // REV_FILTER_STR or NON_REV_FILTER_STR according to the
104: // quantization type
105: for (int t = nt - 1; t >= 0; t--) {
106: for (int c = nc - 1; c >= 0; c--) {
107: switch (qts.getSpecValType(t, c)) {
108: case SPEC_DEF:
109: if (getDefault() == null) {
110: if (wp.getLossless())
111: setDefault(parseFilters(REV_FILTER_STR));
112: if (((String) qts.getDefault())
113: .equals("reversible")) {
114: setDefault(parseFilters(REV_FILTER_STR));
115: } else {
116: setDefault(parseFilters(NON_REV_FILTER_STR));
117: }
118: }
119: specValType[t][c] = SPEC_DEF;
120: break;
121: case SPEC_COMP_DEF:
122: if (!isCompSpecified(c)) {
123: if (((String) qts.getCompDef(c))
124: .equals("reversible")) {
125: setCompDef(c,
126: parseFilters(REV_FILTER_STR));
127: } else {
128: setCompDef(
129: c,
130: parseFilters(NON_REV_FILTER_STR));
131: }
132: }
133: specValType[t][c] = SPEC_COMP_DEF;
134: break;
135: case SPEC_TILE_DEF:
136: if (!isTileSpecified(t)) {
137: if (((String) qts.getTileDef(t))
138: .equals("reversible")) {
139: setTileDef(t,
140: parseFilters(REV_FILTER_STR));
141: } else {
142: setTileDef(
143: t,
144: parseFilters(NON_REV_FILTER_STR));
145: }
146: }
147: specValType[t][c] = SPEC_TILE_DEF;
148: break;
149: case SPEC_TILE_COMP:
150: if (!isTileCompSpecified(t, c)) {
151: if (((String) qts.getTileCompVal(t, c))
152: .equals("reversible")) {
153: setTileCompVal(t, c,
154: parseFilters(REV_FILTER_STR));
155: } else {
156: setTileCompVal(
157: t,
158: c,
159: parseFilters(NON_REV_FILTER_STR));
160: }
161: }
162: specValType[t][c] = SPEC_TILE_COMP;
163: break;
164: default:
165: throw new IllegalArgumentException(
166: "Unsupported " + "specification type");
167: }
168: }
169: }
170:
171: return;
172: }
173:
174: // Parse argument
175: StringTokenizer stk = new StringTokenizer(param);
176: String word; // current word
177: byte curSpecType = SPEC_DEF; // Specification type of the
178: // current parameter
179: boolean[] tileSpec = null; // Tiles concerned by the specification
180: boolean[] compSpec = null; // Components concerned by the specification
181: AnWTFilter[][] filter;
182:
183: while (stk.hasMoreTokens()) {
184: word = stk.nextToken();
185:
186: switch (word.charAt(0)) {
187: case 't': // Tiles specification
188: case 'T': // Tiles specification
189: tileSpec = parseIdx(word, nTiles);
190: if (curSpecType == SPEC_COMP_DEF)
191: curSpecType = SPEC_TILE_COMP;
192: else
193: curSpecType = SPEC_TILE_DEF;
194: break;
195: case 'c': // Components specification
196: case 'C': // Components specification
197: compSpec = parseIdx(word, nComp);
198: if (curSpecType == SPEC_TILE_DEF)
199: curSpecType = SPEC_TILE_COMP;
200: else
201: curSpecType = SPEC_COMP_DEF;
202: break;
203: case 'w': // WT filters specification
204: case 'W': // WT filters specification
205: if (wp.getLossless() && word.equalsIgnoreCase("w9x7")) {
206: throw new IllegalArgumentException(
207: "Cannot use non " + "reversible "
208: + "wavelet transform with"
209: + " '-lossless' option");
210:
211: }
212:
213: filter = parseFilters(word);
214: if (curSpecType == SPEC_DEF) {
215: setDefault(filter);
216: } else if (curSpecType == SPEC_TILE_DEF) {
217: for (int i = tileSpec.length - 1; i >= 0; i--)
218: if (tileSpec[i]) {
219: setTileDef(i, filter);
220: }
221: } else if (curSpecType == SPEC_COMP_DEF) {
222: for (int i = compSpec.length - 1; i >= 0; i--)
223: if (compSpec[i]) {
224: setCompDef(i, filter);
225: }
226: } else {
227: for (int i = tileSpec.length - 1; i >= 0; i--) {
228: for (int j = compSpec.length - 1; j >= 0; j--) {
229: if (tileSpec[i] && compSpec[j]) {
230: setTileCompVal(i, j, filter);
231: }
232: }
233: }
234: }
235:
236: // Re-initialize
237: curSpecType = SPEC_DEF;
238: tileSpec = null;
239: compSpec = null;
240: break;
241:
242: default:
243: throw new IllegalArgumentException(
244: "Bad construction for " + "parameter: " + word);
245: }
246: }
247:
248: // Check that default value has been specified
249: if (getDefault() == null) {
250: int ndefspec = 0;
251: for (int t = nt - 1; t >= 0; t--) {
252: for (int c = nc - 1; c >= 0; c--) {
253: if (specValType[t][c] == SPEC_DEF) {
254: ndefspec++;
255: }
256: }
257: }
258:
259: // If some tile-component have received no specification, it takes
260: // the default value
261: if (ndefspec != 0) {
262: if (((String) qts.getDefault()).equals("reversible"))
263: setDefault(parseFilters(REV_FILTER_STR));
264: else
265: setDefault(parseFilters(NON_REV_FILTER_STR));
266: } else {
267: // All tile-component have been specified, takes the first
268: // tile-component value as default.
269: setDefault(getTileCompVal(0, 0));
270: switch (specValType[0][0]) {
271: case SPEC_TILE_DEF:
272: for (int c = nc - 1; c >= 0; c--) {
273: if (specValType[0][c] == SPEC_TILE_DEF)
274: specValType[0][c] = SPEC_DEF;
275: }
276: tileDef[0] = null;
277: break;
278: case SPEC_COMP_DEF:
279: for (int t = nt - 1; t >= 0; t--) {
280: if (specValType[t][0] == SPEC_COMP_DEF)
281: specValType[t][0] = SPEC_DEF;
282: }
283: compDef[0] = null;
284: break;
285: case SPEC_TILE_COMP:
286: specValType[0][0] = SPEC_DEF;
287: tileCompVal.put("t0c0", null);
288: break;
289: }
290: }
291: }
292:
293: // Check consistency between filter and quantization type
294: // specification
295: for (int t = nt - 1; t >= 0; t--) {
296: for (int c = nc - 1; c >= 0; c--) {
297: // Reversible quantization
298: if (((String) qts.getTileCompVal(t, c))
299: .equals("reversible")) {
300: // If filter is reversible, it is OK
301: if (isReversible(t, c))
302: continue;
303:
304: // If no filter has been defined, use reversible filter
305: if (!isFilterSpecified) {
306: setTileCompVal(t, c,
307: parseFilters(REV_FILTER_STR));
308: } else {
309: // Non reversible filter specified -> Error
310: throw new IllegalArgumentException("Filter of "
311: + "tile-component" + " (" + t + "," + c
312: + ") does" + " not allow "
313: + "reversible " + "quantization. "
314: + "Specify '-Qtype " + "expounded' or "
315: + "'-Qtype derived'" + "in "
316: + "the command line.");
317: }
318: } else { // No reversible quantization
319: // No reversible filter -> OK
320: if (!isReversible(t, c))
321: continue;
322:
323: // If no filter has been specified, use non-reversible
324: // filter
325: if (!isFilterSpecified) {
326: setTileCompVal(t, c,
327: parseFilters(NON_REV_FILTER_STR));
328: } else {
329: // Reversible filter specified -> Error
330: throw new IllegalArgumentException("Filter of "
331: + "tile-component" + " (" + t + "," + c
332: + ") does" + " not allow "
333: + "non-reversible " + "quantization. "
334: + "Specify '-Qtype "
335: + "reversible' in "
336: + "the command line");
337: }
338: }
339: }
340: }
341: }
342:
343: /**
344: * Parse filters from the given word
345: *
346: * @param word String to parse
347: *
348: * @return Analysis wavelet filter (first dimension: by direction,
349: * second dimension: by decomposition levels)
350: */
351: private AnWTFilter[][] parseFilters(String word) {
352: AnWTFilter[][] filt = new AnWTFilter[2][1];
353: if (word.equalsIgnoreCase("w5x3")) {
354: filt[0][0] = new AnWTFilterIntLift5x3();
355: filt[1][0] = new AnWTFilterIntLift5x3();
356: return filt;
357: } else if (word.equalsIgnoreCase("w9x7")) {
358: filt[0][0] = new AnWTFilterFloatLift9x7();
359: filt[1][0] = new AnWTFilterFloatLift9x7();
360: return filt;
361: } else {
362: throw new IllegalArgumentException(
363: "Non JPEG 2000 part I filter: " + word);
364: }
365: }
366:
367: /**
368: * Returns the data type used by the filters in this object, as defined in
369: * the 'DataBlk' interface for specified tile-component.
370: *
371: * @param t Tile index
372: *
373: * @param c Component index
374: *
375: * @return The data type of the filters in this object
376: *
377: * @see jj2000.j2k.image.DataBlk
378: * */
379: public int getWTDataType(int t, int c) {
380: AnWTFilter[][] an = (AnWTFilter[][]) getSpec(t, c);
381: return an[0][0].getDataType();
382: }
383:
384: /**
385: * Returns the horizontal analysis filters to be used in component 'n' and
386: * tile 't'.
387: *
388: * <P>The horizontal analysis filters are returned in an array of
389: * AnWTFilter. Each element contains the horizontal filter for each
390: * resolution level starting with resolution level 1 (i.e. the analysis
391: * filter to go from resolution level 1 to resolution level 0). If there
392: * are less elements than the maximum resolution level, then the last
393: * element is assumed to be repeated.
394: *
395: * @param t The tile index, in raster scan order
396: *
397: * @param c The component index.
398: *
399: * @return The array of horizontal analysis filters for component 'n' and
400: * tile 't'.
401: * */
402: public AnWTFilter[] getHFilters(int t, int c) {
403: AnWTFilter[][] an = (AnWTFilter[][]) getSpec(t, c);
404: return an[0];
405: }
406:
407: /**
408: * Returns the vertical analysis filters to be used in component 'n' and
409: * tile 't'.
410: *
411: * <P>The vertical analysis filters are returned in an array of
412: * AnWTFilter. Each element contains the vertical filter for each
413: * resolution level starting with resolution level 1 (i.e. the analysis
414: * filter to go from resolution level 1 to resolution level 0). If there
415: * are less elements than the maximum resolution level, then the last
416: * element is assumed to be repeated.
417: *
418: * @param t The tile index, in raster scan order
419: *
420: * @param c The component index.
421: *
422: * @return The array of horizontal analysis filters for component 'n' and
423: * tile 't'.
424: * */
425: public AnWTFilter[] getVFilters(int t, int c) {
426: AnWTFilter[][] an = (AnWTFilter[][]) getSpec(t, c);
427: return an[1];
428: }
429:
430: /** Debugging method */
431: public String toString() {
432: String str = "";
433: AnWTFilter[][] an;
434:
435: str += "nTiles=" + nTiles + "\nnComp=" + nComp + "\n\n";
436:
437: for (int t = 0; t < nTiles; t++) {
438: for (int c = 0; c < nComp; c++) {
439: an = (AnWTFilter[][]) getSpec(t, c);
440:
441: str += "(t:" + t + ",c:" + c + ")\n";
442:
443: // Horizontal filters
444: str += "\tH:";
445: for (int i = 0; i < an[0].length; i++)
446: str += " " + an[0][i];
447: // Horizontal filters
448: str += "\n\tV:";
449: for (int i = 0; i < an[1].length; i++)
450: str += " " + an[1][i];
451: str += "\n";
452: }
453: }
454:
455: return str;
456: }
457:
458: /**
459: * Check the reversibility of filters contained is the given
460: * tile-component.
461: *
462: * @param t The index of the tile
463: *
464: * @param c The index of the component
465: * */
466: public boolean isReversible(int t, int c) {
467: // Note: no need to buffer the result since this method is
468: // normally called once per tile-component.
469: AnWTFilter[] hfilter = getHFilters(t, c), vfilter = getVFilters(
470: t, c);
471:
472: // As soon as a filter is not reversible, false can be returned
473: for (int i = hfilter.length - 1; i >= 0; i--)
474: if (!hfilter[i].isReversible()
475: || !vfilter[i].isReversible())
476: return false;
477: return true;
478: }
479: }
|