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