001: /*
002: * $RCSfile: ImgDataJoiner.java,v $
003: * $Revision: 1.1 $
004: * $Date: 2005/02/11 05:02:13 $
005: * $State: Exp $
006: *
007: * Class: ImgDataJoiner
008: *
009: * Description: Get ImgData from different sources
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.image;
045:
046: import java.awt.Point;
047:
048: import jj2000.j2k.*;
049:
050: /**
051: * This class implements the ImgData interface and allows to obtain data from
052: * different sources. Here, one source is represented by an ImgData and a
053: * component index. The typical use of this class is when the encoder needs
054: * different components (Red, Green, Blue, alpha, ...) from different input
055: * files (i.e. from different ImgReader objects).
056: *
057: * <p>All input ImgData must not be tiled (i.e. must have only 1 tile) and the
058: * image origin must be the canvas origin. The different inputs can have
059: * different dimensions though (this will lead to different subsampling
060: * factors for each component).</p>
061: *
062: * <p>The input ImgData and component index list must be defined when
063: * constructing this class and can not be modified later.</p>
064: *
065: * @see ImgData
066: * @see jj2000.j2k.image.input.ImgReader
067: * */
068: public class ImgDataJoiner implements BlkImgDataSrc {
069:
070: /** The width of the image */
071: private int w;
072:
073: /** The height of the image */
074: private int h;
075:
076: /** The number of components in the image */
077: private int nc;
078:
079: /** The list of input ImgData */
080: private BlkImgDataSrc[] imageData;
081:
082: /** The component index associated with each ImgData */
083: private int[] compIdx;
084:
085: /** The subsampling factor along the horizontal direction, for every
086: * component */
087: private int[] subsX;
088:
089: /** The subsampling factor along the vertical direction, for every
090: * component */
091: private int[] subsY;
092:
093: /**
094: * Class constructor. Each input BlkImgDataSrc and its component index
095: * must appear in the order wanted for the output components.<br>
096: *
097: * <u>Example:</u> Reading R,G,B components from 3 PGM files.<br>
098: * <tt>
099: * BlkImgDataSrc[] idList = <br>
100: * {<br>
101: * new ImgReaderPGM(new BEBufferedRandomAccessFile("R.pgm", "r")),<br>
102: * new ImgReaderPGM(new BEBufferedRandomAccessFile("G.pgm", "r")),<br>
103: * new ImgReaderPGM(new BEBufferedRandomAccessFile("B.pgm", "r"))<br>
104: * };<br>
105: * int[] compIdx = {0,0,0};<br>
106: * ImgDataJoiner idj = new ImgDataJoiner(idList, compIdx);
107: * </tt>
108: *
109: * <p>Of course, the 2 arrays must have the same length (This length is
110: * the number of output components). The image width and height are
111: * definded to be the maximum values of all the input ImgData.
112: *
113: * @param imD The list of input BlkImgDataSrc in an array.
114: *
115: * @param cIdx The component index associated with each ImgData.
116: * */
117: public ImgDataJoiner(BlkImgDataSrc[] imD, int[] cIdx) {
118: int i;
119: int maxW, maxH;
120:
121: // Initializes
122: imageData = imD;
123: compIdx = cIdx;
124: if (imageData.length != compIdx.length)
125: throw new IllegalArgumentException(
126: "imD and cIdx must have the" + " same length");
127:
128: nc = imD.length;
129:
130: subsX = new int[nc];
131: subsY = new int[nc];
132:
133: // Check that no source is tiled and that the image origin is at the
134: // canvas origin.
135: for (i = 0; i < nc; i++) {
136: if (imD[i].getNumTiles() != 1
137: || imD[i].getCompULX(cIdx[i]) != 0
138: || imD[i].getCompULY(cIdx[i]) != 0) {
139: throw new IllegalArgumentException(
140: "All input components must, "
141: + "not use tiles and must " + "have "
142: + "the origin at the canvas "
143: + "origin");
144: }
145: }
146:
147: // Guess component subsampling factors based on the fact that the
148: // ceil() operation relates the reference grid size to the component's
149: // size, through the subsampling factor.
150:
151: // Mhhh, difficult problem. For now just assume that one of the
152: // subsampling factors is always 1 and that the component width is
153: // always larger than its subsampling factor, which covers most of the
154: // cases. We check the correctness of the solution once found to chek
155: // out hypothesis.
156:
157: // Look for max width and height.
158: maxW = 0;
159: maxH = 0;
160: for (i = 0; i < nc; i++) {
161: if (imD[i].getCompImgWidth(cIdx[i]) > maxW)
162: maxW = imD[i].getCompImgWidth(cIdx[i]);
163: if (imD[i].getCompImgHeight(cIdx[i]) > maxH)
164: maxH = imD[i].getCompImgHeight(cIdx[i]);
165: }
166: // Set the image width and height as the maximum ones
167: w = maxW;
168: h = maxH;
169:
170: // Now get the sumsampling factors and check the subsampling factors,
171: // just to see if above hypothesis were correct.
172: for (i = 0; i < nc; i++) {
173: // This calculation only holds if the subsampling factor is less
174: // than the component width
175: subsX[i] = (maxW + imD[i].getCompImgWidth(cIdx[i]) - 1)
176: / imD[i].getCompImgWidth(cIdx[i]);
177: subsY[i] = (maxH + imD[i].getCompImgHeight(cIdx[i]) - 1)
178: / imD[i].getCompImgHeight(cIdx[i]);
179: if ((maxW + subsX[i] - 1) / subsX[i] != imD[i]
180: .getCompImgWidth(cIdx[i])
181: || (maxH + subsY[i] - 1) / subsY[i] != imD[i]
182: .getCompImgHeight(cIdx[i])) {
183: throw new Error(
184: "Can not compute component subsampling "
185: + "factors: strange subsampling.");
186: }
187: }
188: }
189:
190: /**
191: * Returns the overall width of the current tile in pixels. This is the
192: * tile's width without accounting for any component subsampling.
193: *
194: * @return The total current tile's width in pixels.
195: * */
196: public int getTileWidth() {
197: return w;
198: }
199:
200: /**
201: * Returns the overall height of the current tile in pixels. This is the
202: * tile's height without accounting for any component subsampling.
203: *
204: * @return The total current tile's height in pixels.
205: * */
206: public int getTileHeight() {
207: return h;
208: }
209:
210: /** Returns the nominal tiles width */
211: public int getNomTileWidth() {
212: return w;
213: }
214:
215: /** Returns the nominal tiles height */
216: public int getNomTileHeight() {
217: return h;
218: }
219:
220: /**
221: * Returns the overall width of the image in pixels. This is the image's
222: * width without accounting for any component subsampling or tiling.
223: *
224: * @return The total image's width in pixels.
225: * */
226: public int getImgWidth() {
227: return w;
228: }
229:
230: /**
231: * Returns the overall height of the image in pixels. This is the image's
232: * height without accounting for any component subsampling or tiling.
233: *
234: * @return The total image's height in pixels.
235: * */
236: public int getImgHeight() {
237: return h;
238: }
239:
240: /**
241: * Returns the number of components in the image.
242: *
243: * @return The number of components in the image.
244: * */
245: public int getNumComps() {
246: return nc;
247: }
248:
249: /**
250: * Returns the component subsampling factor in the horizontal direction,
251: * for the specified component. This is, approximately, the ratio of
252: * dimensions between the reference grid and the component itself, see the
253: * 'ImgData' interface desription for details.
254: *
255: * @param c The index of the component (between 0 and N-1)
256: *
257: * @return The horizontal subsampling factor of component 'c'
258: *
259: * @see ImgData
260: * */
261: public int getCompSubsX(int c) {
262: return subsX[c];
263: }
264:
265: /**
266: * Returns the component subsampling factor in the vertical direction, for
267: * the specified component. This is, approximately, the ratio of
268: * dimensions between the reference grid and the component itself, see the
269: * 'ImgData' interface desription for details.
270: *
271: * @param c The index of the component (between 0 and N-1)
272: *
273: * @return The vertical subsampling factor of component 'c'
274: *
275: * @see ImgData
276: * */
277: public int getCompSubsY(int c) {
278: return subsY[c];
279: }
280:
281: /**
282: * Returns the width in pixels of the specified tile-component
283: *
284: * @param t Tile index
285: *
286: * @param c The index of the component, from 0 to N-1.
287: *
288: * @return The width in pixels of component <tt>c</tt> in tile<tt>t</tt>.
289: * */
290: public int getTileCompWidth(int t, int c) {
291: return imageData[c].getTileCompWidth(t, compIdx[c]);
292: }
293:
294: /**
295: * Returns the height in pixels of the specified tile-component.
296: *
297: * @param t The tile index.
298: *
299: * @param c The index of the component, from 0 to N-1.
300: *
301: * @return The height in pixels of component <tt>c</tt> in the current
302: * tile.
303: * */
304: public int getTileCompHeight(int t, int c) {
305: return imageData[c].getTileCompHeight(t, compIdx[c]);
306: }
307:
308: /**
309: * Returns the width in pixels of the specified component in the overall
310: * image.
311: *
312: * @param c The index of the component, from 0 to N-1.
313: *
314: * @return The width in pixels of component <tt>c</tt> in the overall
315: * image.
316: * */
317: public int getCompImgWidth(int c) {
318: return imageData[c].getCompImgWidth(compIdx[c]);
319: }
320:
321: /**
322: * Returns the height in pixels of the specified component in the
323: * overall image.
324: *
325: * @param n The index of the component, from 0 to N-1.
326: *
327: * @return The height in pixels of component <tt>n</tt> in the overall
328: * image.
329: *
330: *
331: * */
332: public int getCompImgHeight(int n) {
333: return imageData[n].getCompImgHeight(compIdx[n]);
334: }
335:
336: /**
337: * Returns the number of bits, referred to as the "range bits",
338: * corresponding to the nominal range of the data in the specified
339: * component. If this number is <i>b</b> then for unsigned data the
340: * nominal range is between 0 and 2^b-1, and for signed data it is between
341: * -2^(b-1) and 2^(b-1)-1. For floating point data this value is not
342: * applicable.
343: *
344: * @param c The index of the component.
345: *
346: * @return The number of bits corresponding to the nominal range of the
347: * data. Fro floating-point data this value is not applicable and the
348: * return value is undefined.
349: * */
350: public int getNomRangeBits(int c) {
351: return imageData[c].getNomRangeBits(compIdx[c]);
352: }
353:
354: /**
355: * Returns the position of the fixed point in the specified
356: * component. This is the position of the least significant integral
357: * (i.e. non-fractional) bit, which is equivalent to the number of
358: * fractional bits. For instance, for fixed-point values with 2 fractional
359: * bits, 2 is returned. For floating-point data this value does not apply
360: * and 0 should be returned. Position 0 is the position of the least
361: * significant bit in the data.
362: *
363: * @param c The index of the component.
364: *
365: * @return The position of the fixed-point, which is the same as the
366: * number of fractional bits. For floating-point data 0 is returned.
367: * */
368: public int getFixedPoint(int c) {
369: return imageData[c].getFixedPoint(compIdx[c]);
370: }
371:
372: /**
373: * Returns, in the blk argument, a block of image data containing the
374: * specifed rectangular area, in the specified component. The data is
375: * returned, as a reference to the internal data, if any, instead of as a
376: * copy, therefore the returned data should not be modified.
377: *
378: * <P>The rectangular area to return is specified by the 'ulx', 'uly', 'w'
379: * and 'h' members of the 'blk' argument, relative to the current
380: * tile. These members are not modified by this method. The 'offset' and
381: * 'scanw' of the returned data can be arbitrary. See the 'DataBlk' class.
382: *
383: * <P>This method, in general, is more efficient than the 'getCompData()'
384: * method since it may not copy the data. However if the array of returned
385: * data is to be modified by the caller then the other method is probably
386: * preferable.
387: *
388: * <P>If the data array in <tt>blk</tt> is <tt>null</tt>, then a new one
389: * is created if necessary. The implementation of this interface may
390: * choose to return the same array or a new one, depending on what is more
391: * efficient. Therefore, the data array in <tt>blk</tt> prior to the
392: * method call should not be considered to contain the returned data, a
393: * new array may have been created. Instead, get the array from
394: * <tt>blk</tt> after the method has returned.
395: *
396: * <P>The returned data may have its 'progressive' attribute set. In this
397: * case the returned data is only an approximation of the "final" data.
398: *
399: * @param blk Its coordinates and dimensions specify the area to return,
400: * relative to the current tile. Some fields in this object are modified
401: * to return the data.
402: *
403: * @param c The index of the component from which to get the data.
404: *
405: * @return The requested DataBlk
406: *
407: * @see #getCompData
408: * */
409: public DataBlk getInternCompData(DataBlk blk, int c) {
410: return imageData[c].getInternCompData(blk, compIdx[c]);
411: }
412:
413: /**
414: * Returns, in the blk argument, a block of image data containing the
415: * specifed rectangular area, in the specified component. The data is
416: * returned, as a copy of the internal data, therefore the returned data
417: * can be modified "in place".
418: *
419: * <P>The rectangular area to return is specified by the 'ulx', 'uly', 'w'
420: * and 'h' members of the 'blk' argument, relative to the current
421: * tile. These members are not modified by this method. The 'offset' of
422: * the returned data is 0, and the 'scanw' is the same as the block's
423: * width. See the 'DataBlk' class.
424: *
425: * <P>This method, in general, is less efficient than the
426: * 'getInternCompData()' method since, in general, it copies the
427: * data. However if the array of returned data is to be modified by the
428: * caller then this method is preferable.
429: *
430: * <P>If the data array in 'blk' is 'null', then a new one is created. If
431: * the data array is not 'null' then it is reused, and it must be large
432: * enough to contain the block's data. Otherwise an 'ArrayStoreException'
433: * or an 'IndexOutOfBoundsException' is thrown by the Java system.
434: *
435: * <P>The returned data may have its 'progressive' attribute set. In this
436: * case the returned data is only an approximation of the "final" data.
437: *
438: * @param blk Its coordinates and dimensions specify the area to return,
439: * relative to the current tile. If it contains a non-null data array,
440: * then it must be large enough. If it contains a null data array a new
441: * one is created. Some fields in this object are modified to return the
442: * data.
443: *
444: * @param c The index of the component from which to get the data.
445: *
446: * @return The requested DataBlk
447: *
448: * @see #getInternCompData
449: * */
450: public DataBlk getCompData(DataBlk blk, int c) {
451: return imageData[c].getCompData(blk, compIdx[c]);
452: }
453:
454: /**
455: * Changes the current tile, given the new coordinates. An
456: * IllegalArgumentException is thrown if the coordinates do not correspond
457: * to a valid tile.
458: *
459: * @param x The horizontal coordinate of the tile.
460: *
461: * @param y The vertical coordinate of the new tile.
462: * */
463: public void setTile(int x, int y) {
464: if (x != 0 || y != 0) {
465: throw new IllegalArgumentException();
466: }
467: }
468:
469: /**
470: * Advances to the next tile, in standard scan-line order (by rows then
471: * columns). A NoNextElementException is thrown if the current tile is the
472: * last one (i.e. there is no next tile). This default implementation
473: * assumes no tiling, so NoNextElementException() is always thrown.
474: * */
475: public void nextTile() {
476: throw new NoNextElementException();
477: }
478:
479: /**
480: * Returns the coordinates of the current tile. This default
481: * implementation assumes no-tiling, so (0,0) is returned.
482: *
483: * @param co If not null this object is used to return the information. If
484: * null a new one is created and returned.
485: *
486: * @return The current tile's coordinates.
487: * */
488: public Point getTile(Point co) {
489: if (co != null) {
490: co.x = 0;
491: co.y = 0;
492: return co;
493: } else {
494: return new Point(0, 0);
495: }
496: }
497:
498: /**
499: * Returns the index of the current tile, relative to a standard scan-line
500: * order. This default implementations assumes no tiling, so 0 is always
501: * returned.
502: *
503: * @return The current tile's index (starts at 0).
504: * */
505: public int getTileIdx() {
506: return 0;
507: }
508:
509: /**
510: * Returns the horizontal coordinate of the upper-left corner of the
511: * specified component in the current tile.
512: *
513: * @param c The component index.
514: * */
515: public int getCompULX(int c) {
516: return 0;
517: }
518:
519: /**
520: * Returns the vertical coordinate of the upper-left corner of the
521: * specified component in the current tile.
522: *
523: * @param c The component index.
524: * */
525: public int getCompULY(int c) {
526: return 0;
527: }
528:
529: /** Returns the horizontal tile partition offset in the reference grid */
530: public int getTilePartULX() {
531: return 0;
532: }
533:
534: /** Returns the vertical tile partition offset in the reference grid */
535: public int getTilePartULY() {
536: return 0;
537: }
538:
539: /**
540: * Returns the horizontal coordinate of the image origin, the top-left
541: * corner, in the canvas system, on the reference grid.
542: *
543: * @return The horizontal coordinate of the image origin in the canvas
544: * system, on the reference grid.
545: * */
546: public int getImgULX() {
547: return 0;
548: }
549:
550: /**
551: * Returns the vertical coordinate of the image origin, the top-left
552: * corner, in the canvas system, on the reference grid.
553: *
554: * @return The vertical coordinate of the image origin in the canvas
555: * system, on the reference grid.
556: * */
557: public int getImgULY() {
558: return 0;
559: }
560:
561: /**
562: * Returns the number of tiles in the horizontal and vertical
563: * directions. This default implementation assumes no tiling, so (1,1) is
564: * always returned.
565: *
566: * @param co If not null this object is used to return the information. If
567: * null a new one is created and returned.
568: *
569: * @return The number of tiles in the horizontal (Point.x) and vertical
570: * (Point.y) directions.
571: * */
572: public Point getNumTiles(Point co) {
573: if (co != null) {
574: co.x = 1;
575: co.y = 1;
576: return co;
577: } else {
578: return new Point(1, 1);
579: }
580: }
581:
582: /**
583: * Returns the total number of tiles in the image. This default
584: * implementation assumes no tiling, so 1 is always returned.
585: *
586: * @return The total number of tiles in the image.
587: * */
588: public int getNumTiles() {
589: return 1;
590: }
591:
592: /**
593: * Returns a string of information about the object, more than 1 line
594: * long. The information string includes information from the several
595: * input ImgData (their toString() method are called one after the other).
596: *
597: * @return A string of information about the object.
598: * */
599: public String toString() {
600: String string = "ImgDataJoiner: WxH = " + w + "x" + h;
601: for (int i = 0; i < nc; i++) {
602: string += "\n- Component " + i + " " + imageData[i];
603: }
604: return string;
605: }
606: }
|