001: /*
002: * $RCSfile: Tiler.java,v $
003: * $Revision: 1.1 $
004: * $Date: 2005/02/11 05:02:13 $
005: * $State: Exp $
006: *
007: * Class: Tiler
008: *
009: * Description: An object to create TiledImgData from
010: * ImgData
011: *
012: *
013: *
014: * COPYRIGHT:
015: *
016: * This software module was originally developed by Raphaël Grosbois and
017: * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
018: * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
019: * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
020: * Centre France S.A) in the course of development of the JPEG2000
021: * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
022: * software module is an implementation of a part of the JPEG 2000
023: * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
024: * Systems AB and Canon Research Centre France S.A (collectively JJ2000
025: * Partners) agree not to assert against ISO/IEC and users of the JPEG
026: * 2000 Standard (Users) any of their rights under the copyright, not
027: * including other intellectual property rights, for this software module
028: * with respect to the usage by ISO/IEC and Users of this software module
029: * or modifications thereof for use in hardware or software products
030: * claiming conformance to the JPEG 2000 Standard. Those intending to use
031: * this software module in hardware or software products are advised that
032: * their use may infringe existing patents. The original developers of
033: * this software module, JJ2000 Partners and ISO/IEC assume no liability
034: * for use of this software module or modifications thereof. No license
035: * or right to this software module is granted for non JPEG 2000 Standard
036: * conforming products. JJ2000 Partners have full right to use this
037: * software module for his/her own purpose, assign or donate this
038: * software module to any third party and to inhibit third parties from
039: * using this software module for non JPEG 2000 Standard conforming
040: * products. This copyright notice must be included in all copies or
041: * derivative works of this software module.
042: *
043: * Copyright (c) 1999/2000 JJ2000 Partners.
044: * */
045: package jj2000.j2k.image;
046:
047: import java.awt.Point;
048:
049: import jj2000.j2k.util.*;
050: import jj2000.j2k.*;
051:
052: /**
053: * This class places an image in the canvas coordinate system, tiles it, if so
054: * specified, and performs the coordinate conversions transparently. The
055: * source must be a 'BlkImgDataSrc' which is not tiled and has a the image
056: * origin at the canvas origin (i.e. it is not "canvased"), or an exception is
057: * thrown by the constructor. A tiled and "canvased" output is given through
058: * the 'BlkImgDataSrc' interface. See the 'ImgData' interface for a
059: * description of the canvas and tiling.
060: *
061: * <p>All tiles produced are rectangular, non-overlapping and their union
062: * covers all the image. However, the tiling may not be uniform, depending on
063: * the nominal tile size, tiling origin, component subsampling and other
064: * factors. Therefore it might not be assumed that all tiles are of the same
065: * width and height.</p>
066: *
067: * <p>The nominal dimension of the tiles is the maximal one, in the reference
068: * grid. All the components of the image have the same number of tiles.</p>
069: *
070: * @see ImgData
071: * @see BlkImgDataSrc
072: * */
073: public class Tiler extends ImgDataAdapter implements BlkImgDataSrc {
074:
075: /** The source of image data */
076: private BlkImgDataSrc src = null;
077:
078: /** Horizontal coordinate of the upper left hand reference grid point.*/
079: private int x0siz;
080:
081: /** Vertical coordinate of the upper left hand reference grid point.*/
082: private int y0siz;
083:
084: /** The horizontal coordinate of the tiling origin in the canvas system,
085: * on the reference grid. */
086: private int xt0siz;
087:
088: /** The vertical coordinate of the tiling origin in the canvas system, on
089: * the reference grid. */
090: private int yt0siz;
091:
092: /** The nominal width of the tiles, on the reference grid. If 0 then there
093: * is no tiling in that direction. */
094: private int xtsiz;
095:
096: /** The nominal height of the tiles, on the reference grid. If 0 then
097: * there is no tiling in that direction. */
098: private int ytsiz;
099:
100: /** The number of tiles in the horizontal direction. */
101: private int ntX;
102:
103: /** The number of tiles in the vertical direction. */
104: private int ntY;
105:
106: /** The component width in the current active tile, for each component */
107: private int compW[] = null;
108:
109: /** The component height in the current active tile, for each component */
110: private int compH[] = null;
111:
112: /** The horizontal coordinates of the upper-left corner of the components
113: * in the current tile */
114: private int tcx0[] = null;
115:
116: /** The vertical coordinates of the upper-left corner of the components in
117: * the current tile. */
118: private int tcy0[] = null;
119:
120: /** The horizontal index of the current tile */
121: private int tx;
122:
123: /** The vertical index of the current tile */
124: private int ty;
125:
126: /** The width of the current tile, on the reference grid. */
127: private int tileW;
128:
129: /** The height of the current tile, on the reference grid. */
130: private int tileH;
131:
132: /**
133: * Constructs a new tiler with the specified 'BlkImgDataSrc' source,
134: * image origin, tiling origin and nominal tile size.
135: *
136: * @param src The 'BlkImgDataSrc' source from where to get the image
137: * data. It must not be tiled and the image origin must be at '(0,0)' on
138: * its canvas.
139: *
140: * @param ax The horizontal coordinate of the image origin in the canvas
141: * system, on the reference grid (i.e. the image's top-left corner in the
142: * reference grid).
143: *
144: * @param ay The vertical coordinate of the image origin in the canvas
145: * system, on the reference grid (i.e. the image's top-left corner in the
146: * reference grid).
147: *
148: * @param px The horizontal tiling origin, in the canvas system, on the
149: * reference grid. It must satisfy 'px<=ax'.
150: *
151: * @param py The vertical tiling origin, in the canvas system, on the
152: * reference grid. It must satisfy 'py<=ay'.
153: *
154: * @param nw The nominal tile width, on the reference grid. If 0 then
155: * there is no tiling in that direction.
156: *
157: * @param nh The nominal tile height, on the reference grid. If 0 then
158: * there is no tiling in that direction.
159: *
160: * @exception IllegalArgumentException If src is tiled or "canvased", or
161: * if the arguments do not satisfy the specified constraints.
162: * */
163: public Tiler(BlkImgDataSrc src, int ax, int ay, int px, int py,
164: int nw, int nh) {
165: super (src);
166:
167: // Initialize
168: this .src = src;
169: this .x0siz = ax;
170: this .y0siz = ay;
171: this .xt0siz = px;
172: this .yt0siz = py;
173: this .xtsiz = nw;
174: this .ytsiz = nh;
175:
176: // Verify that input is not tiled
177: /*
178: if (src.getNumTiles()!=1) {
179: throw new IllegalArgumentException("Source is tiled");
180: }
181: */
182: // Verify that source is not "canvased"
183: /*
184: if (src.getImgULX()!=0 || src.getImgULY()!=0) {
185: throw new IllegalArgumentException("Source is \"canvased\"");
186: }
187: */
188: // Verify that arguments satisfy trivial requirements
189: if (x0siz < 0 || y0siz < 0 || xt0siz < 0 || yt0siz < 0
190: || xtsiz < 0 || ytsiz < 0 || xt0siz > x0siz
191: || yt0siz > y0siz) {
192: throw new IllegalArgumentException("Invalid image origin, "
193: + "tiling origin or nominal " + "tile size");
194: }
195:
196: // If no tiling has been specified, creates a unique tile with maximum
197: // dimension.
198: if (xtsiz == 0)
199: xtsiz = x0siz + src.getImgWidth() - xt0siz;
200: if (ytsiz == 0)
201: ytsiz = y0siz + src.getImgHeight() - yt0siz;
202:
203: // Automatically adjusts xt0siz,yt0siz so that tile (0,0) always
204: // overlaps with the image.
205: if (x0siz - xt0siz >= xtsiz) {
206: xt0siz += ((x0siz - xt0siz) / xtsiz) * xtsiz;
207: }
208: if (y0siz - yt0siz >= ytsiz) {
209: yt0siz += ((y0siz - yt0siz) / ytsiz) * ytsiz;
210: }
211: if (x0siz - xt0siz >= xtsiz || y0siz - yt0siz >= ytsiz) {
212: FacilityManager.getMsgLogger().printmsg(
213: MsgLogger.INFO,
214: "Automatically adjusted tiling "
215: + "origin to equivalent one (" + xt0siz
216: + "," + yt0siz + ") so that "
217: + "first tile overlaps the image");
218: }
219:
220: // Calculate the number of tiles
221: ntX = (int) Math.ceil((x0siz + src.getImgWidth() - xt0siz)
222: / (double) xtsiz);
223: ntY = (int) Math.ceil((y0siz + src.getImgHeight() - yt0siz)
224: / (double) ytsiz);
225: }
226:
227: /**
228: * Returns the overall width of the current tile in pixels. This is the
229: * tile's width without accounting for any component subsampling.
230: *
231: * @return The total current tile width in pixels.
232: * */
233: public final int getTileWidth() {
234: return tileW;
235: }
236:
237: /**
238: * Returns the overall height of the current tile in pixels. This is the
239: * tile's width without accounting for any component subsampling.
240: *
241: * @return The total current tile height in pixels.
242: * */
243: public final int getTileHeight() {
244: return tileH;
245: }
246:
247: /**
248: * Returns the width in pixels of the specified tile-component.
249: *
250: * @param t Tile index
251: *
252: * @param c The index of the component, from 0 to N-1.
253: *
254: * @return The width of specified tile-component.
255: * */
256: public final int getTileCompWidth(int t, int c) {
257: if (t != getTileIdx()) {
258: throw new Error(
259: "Asking the width of a tile-component which is "
260: + "not in the current tile (call setTile() or "
261: + "nextTile() methods before).");
262: }
263: return compW[c];
264: }
265:
266: /**
267: * Returns the height in pixels of the specified tile-component.
268: *
269: * @param t The tile index.
270: *
271: * @param c The index of the component, from 0 to N-1.
272: *
273: * @return The height of specified tile-component.
274: * */
275: public final int getTileCompHeight(int t, int c) {
276: if (t != getTileIdx()) {
277: throw new Error(
278: "Asking the width of a tile-component which is "
279: + "not in the current tile (call setTile() or "
280: + "nextTile() methods before).");
281: }
282: return compH[c];
283: }
284:
285: /**
286: * Returns the position of the fixed point in the specified
287: * component. This is the position of the least significant integral
288: * (i.e. non-fractional) bit, which is equivalent to the number of
289: * fractional bits. For instance, for fixed-point values with 2 fractional
290: * bits, 2 is returned. For floating-point data this value does not apply
291: * and 0 should be returned. Position 0 is the position of the least
292: * significant bit in the data.
293: *
294: * @param c The index of the component.
295: *
296: * @return The position of the fixed-point, which is the same as the
297: * number of fractional bits. For floating-point data 0 is returned.
298: * */
299: public int getFixedPoint(int c) {
300: return src.getFixedPoint(c);
301: }
302:
303: /**
304: * Returns, in the blk argument, a block of image data containing the
305: * specifed rectangular area, in the specified component. The data is
306: * returned, as a reference to the internal data, if any, instead of as a
307: * copy, therefore the returned data should not be modified.
308: *
309: * <p>The rectangular area to return is specified by the 'ulx', 'uly', 'w'
310: * and 'h' members of the 'blk' argument, relative to the current
311: * tile. These members are not modified by this method. The 'offset' and
312: * 'scanw' of the returned data can be arbitrary. See the 'DataBlk'
313: * class.</p>
314: *
315: * <p>This method, in general, is more efficient than the 'getCompData()'
316: * method since it may not copy the data. However if the array of returned
317: * data is to be modified by the caller then the other method is probably
318: * preferable.</p>
319: *
320: * <p>If the data array in <tt>blk</tt> is <tt>null</tt>, then a new one
321: * is created if necessary. The implementation of this interface may
322: * choose to return the same array or a new one, depending on what is more
323: * efficient. Therefore, the data array in <tt>blk</tt> prior to the
324: * method call should not be considered to contain the returned data, a
325: * new array may have been created. Instead, get the array from
326: * <tt>blk</tt> after the method has returned.</p>
327: *
328: * <p>The returned data may have its 'progressive' attribute set. In this
329: * case the returned data is only an approximation of the "final"
330: * data.</p>
331: *
332: * @param blk Its coordinates and dimensions specify the area to return,
333: * relative to the current tile. Some fields in this object are modified
334: * to return the data.
335: *
336: * @param c The index of the component from which to get the data.
337: *
338: * @return The requested DataBlk
339: *
340: * @see #getCompData
341: * */
342: public final DataBlk getInternCompData(DataBlk blk, int c) {
343: // Check that block is inside tile
344: if (blk.ulx < 0 || blk.uly < 0 || blk.w > compW[c]
345: || blk.h > compH[c]) {
346: throw new IllegalArgumentException(
347: "Block is outside the tile");
348: }
349: // Translate to the sources coordinates
350: int incx = (int) Math
351: .ceil(x0siz / (double) src.getCompSubsX(c));
352: int incy = (int) Math
353: .ceil(y0siz / (double) src.getCompSubsY(c));
354: blk.ulx -= incx;
355: blk.uly -= incy;
356: blk = src.getInternCompData(blk, c);
357: // Translate back to the tiled coordinates
358: blk.ulx += incx;
359: blk.uly += incy;
360: return blk;
361: }
362:
363: /**
364: * Returns, in the blk argument, a block of image data containing the
365: * specifed rectangular area, in the specified component. The data is
366: * returned, as a copy of the internal data, therefore the returned data
367: * can be modified "in place".
368: *
369: * <p>The rectangular area to return is specified by the 'ulx', 'uly', 'w'
370: * and 'h' members of the 'blk' argument, relative to the current
371: * tile. These members are not modified by this method. The 'offset' of
372: * the returned data is 0, and the 'scanw' is the same as the block's
373: * width. See the 'DataBlk' class.</p>
374: *
375: * <p>This method, in general, is less efficient than the
376: * 'getInternCompData()' method since, in general, it copies the
377: * data. However if the array of returned data is to be modified by the
378: * caller then this method is preferable.</p>
379: *
380: * <p>If the data array in 'blk' is 'null', then a new one is created. If
381: * the data array is not 'null' then it is reused, and it must be large
382: * enough to contain the block's data. Otherwise an 'ArrayStoreException'
383: * or an 'IndexOutOfBoundsException' is thrown by the Java system.</p>
384: *
385: * <p>The returned data may have its 'progressive' attribute set. In this
386: * case the returned data is only an approximation of the "final"
387: * data.</p>
388: *
389: * @param blk Its coordinates and dimensions specify the area to return,
390: * relative to the current tile. If it contains a non-null data array,
391: * then it must be large enough. If it contains a null data array a new
392: * one is created. Some fields in this object are modified to return the
393: * data.
394: *
395: * @param c The index of the component from which to get the data.
396: *
397: * @return The requested DataBlk
398: *
399: * @see #getInternCompData
400: * */
401: public final DataBlk getCompData(DataBlk blk, int c) {
402: // Check that block is inside tile
403: if (blk.ulx < 0 || blk.uly < 0 || blk.w > compW[c]
404: || blk.h > compH[c]) {
405: throw new IllegalArgumentException(
406: "Block is outside the tile");
407: }
408: // Translate to the source's coordinates
409: int incx = (int) Math
410: .ceil(x0siz / (double) src.getCompSubsX(c));
411: int incy = (int) Math
412: .ceil(y0siz / (double) src.getCompSubsY(c));
413: blk.ulx -= incx;
414: blk.uly -= incy;
415: blk = src.getCompData(blk, c);
416: // Translate back to the tiled coordinates
417: blk.ulx += incx;
418: blk.uly += incy;
419: return blk;
420: }
421:
422: /**
423: * Changes the current tile, given the new tile indexes. An
424: * IllegalArgumentException is thrown if the coordinates do not correspond
425: * to a valid tile.
426: *
427: * @param x The horizontal index of the tile.
428: *
429: * @param y The vertical index of the new tile.
430: * */
431: public final void setTile(int x, int y) {
432: src.setTile(x, y);
433:
434: // Check tile indexes
435: if (x < 0 || y < 0 || x >= ntX || y >= ntY) {
436: throw new IllegalArgumentException(
437: "Tile's indexes out of bounds");
438: }
439:
440: // Set new current tile
441: tx = x;
442: ty = y;
443: // Calculate tile origins
444: int tx0 = (x != 0) ? xt0siz + x * xtsiz : x0siz;
445: int ty0 = (y != 0) ? yt0siz + y * ytsiz : y0siz;
446: int tx1 = (x != ntX - 1) ? (xt0siz + (x + 1) * xtsiz)
447: : (x0siz + src.getImgWidth());
448: int ty1 = (y != ntY - 1) ? (yt0siz + (y + 1) * ytsiz)
449: : (y0siz + src.getImgHeight());
450: // Set general variables
451: tileW = tx1 - tx0;
452: tileH = ty1 - ty0;
453: // Set component specific variables
454: int nc = src.getNumComps();
455: if (compW == null)
456: compW = new int[nc];
457: if (compH == null)
458: compH = new int[nc];
459: if (tcx0 == null)
460: tcx0 = new int[nc];
461: if (tcy0 == null)
462: tcy0 = new int[nc];
463: for (int i = 0; i < nc; i++) {
464: tcx0[i] = (int) Math.ceil(tx0
465: / (double) src.getCompSubsX(i));
466: tcy0[i] = (int) Math.ceil(ty0
467: / (double) src.getCompSubsY(i));
468: compW[i] = (int) Math.ceil(tx1
469: / (double) src.getCompSubsX(i))
470: - tcx0[i];
471: compH[i] = (int) Math.ceil(ty1
472: / (double) src.getCompSubsY(i))
473: - tcy0[i];
474: }
475: }
476:
477: /**
478: * Advances to the next tile, in standard scan-line order (by rows then
479: * columns). An NoNextElementException is thrown if the current tile is
480: * the last one (i.e. there is no next tile).
481: * */
482: public final void nextTile() {
483: if (tx == ntX - 1 && ty == ntY - 1) { // Already at last tile
484: throw new NoNextElementException();
485: } else if (tx < ntX - 1) { // If not at end of current tile line
486: setTile(tx + 1, ty);
487: } else { // First tile at next line
488: setTile(0, ty + 1);
489: }
490: }
491:
492: /**
493: * Returns the horizontal and vertical indexes of the current tile.
494: *
495: * @param co If not null this object is used to return the
496: * information. If null a new one is created and returned.
497: *
498: * @return The current tile's horizontal and vertical indexes..
499: * */
500: public final Point getTile(Point co) {
501: if (co != null) {
502: co.x = tx;
503: co.y = ty;
504: return co;
505: } else {
506: return new Point(tx, ty);
507: }
508: }
509:
510: /**
511: * Returns the index of the current tile, relative to a standard scan-line
512: * order.
513: *
514: * @return The current tile's index (starts at 0).
515: * */
516: public final int getTileIdx() {
517: return ty * ntX + tx;
518: }
519:
520: /**
521: * Returns the horizontal coordinate of the upper-left corner of the
522: * specified component in the current tile.
523: *
524: * @param c The component index.
525: * */
526: public final int getCompULX(int c) {
527: return tcx0[c];
528: }
529:
530: /**
531: * Returns the vertical coordinate of the upper-left corner of the
532: * specified component in the current tile.
533: *
534: * @param c The component index.
535: * */
536: public final int getCompULY(int c) {
537: return tcy0[c];
538: }
539:
540: /** Returns the horizontal tile partition offset in the reference grid */
541: public int getTilePartULX() {
542: return xt0siz;
543: }
544:
545: /** Returns the vertical tile partition offset in the reference grid */
546: public int getTilePartULY() {
547: return yt0siz;
548: }
549:
550: /**
551: * Returns the horizontal coordinate of the image origin, the top-left
552: * corner, in the canvas system, on the reference grid.
553: *
554: * @return The horizontal coordinate of the image origin in the canvas
555: * system, on the reference grid.
556: * */
557: public final int getImgULX() {
558: return x0siz;
559: }
560:
561: /**
562: * Returns the vertical coordinate of the image origin, the top-left
563: * corner, in the canvas system, on the reference grid.
564: *
565: * @return The vertical coordinate of the image origin in the canvas
566: * system, on the reference grid.
567: * */
568: public final int getImgULY() {
569: return y0siz;
570: }
571:
572: /**
573: * Returns the number of tiles in the horizontal and vertical directions.
574: *
575: * @param co If not null this object is used to return the information. If
576: * null a new one is created and returned.
577: *
578: * @return The number of tiles in the horizontal (Point.x) and vertical
579: * (Point.y) directions.
580: * */
581: public final Point getNumTiles(Point co) {
582: if (co != null) {
583: co.x = ntX;
584: co.y = ntY;
585: return co;
586: } else {
587: return new Point(ntX, ntY);
588: }
589: }
590:
591: /**
592: * Returns the total number of tiles in the image.
593: *
594: * @return The total number of tiles in the image.
595: * */
596: public final int getNumTiles() {
597: return ntX * ntY;
598: }
599:
600: /**
601: * Returns the nominal width of the tiles in the reference grid.
602: *
603: * @return The nominal tile width, in the reference grid.
604: * */
605: public final int getNomTileWidth() {
606: return xtsiz;
607: }
608:
609: /**
610: * Returns the nominal width of the tiles in the reference grid.
611: *
612: * @return The nominal tile width, in the reference grid.
613: * */
614: public final int getNomTileHeight() {
615: return ytsiz;
616: }
617:
618: /**
619: * Returns the tiling origin, referred to as '(xt0siz,yt0siz)' in the
620: * codestream header (SIZ marker segment).
621: *
622: * @param co If not null this object is used to return the information. If
623: * null a new one is created and returned.
624: *
625: * @return The coordinate of the tiling origin, in the canvas system, on
626: * the reference grid.
627: *
628: * @see ImgData
629: * */
630: public final Point getTilingOrigin(Point co) {
631: if (co != null) {
632: co.x = xt0siz;
633: co.y = yt0siz;
634: return co;
635: } else {
636: return new Point(xt0siz, yt0siz);
637: }
638: }
639:
640: /**
641: * Returns a String object representing Tiler's informations
642: *
643: * @return Tiler's infos in a string
644: * */
645: public String toString() {
646: return "Tiler: source= " + src + "\n" + getNumTiles()
647: + " tile(s), nominal width=" + xtsiz
648: + ", nominal height=" + ytsiz;
649: }
650: }
|