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