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 * */ 044package jj2000.j2k.image; 045import java.awt.Point; 046 047import jj2000.j2k.*; 048 049/** 050 * This class implements the ImgData interface and allows to obtain data from 051 * different sources. Here, one source is represented by an ImgData and a 052 * component index. The typical use of this class is when the encoder needs 053 * different components (Red, Green, Blue, alpha, ...) from different input 054 * files (i.e. from different ImgReader objects). 055 * 056 * <p>All input ImgData must not be tiled (i.e. must have only 1 tile) and the 057 * image origin must be the canvas origin. The different inputs can have 058 * different dimensions though (this will lead to different subsampling 059 * factors for each component).</p> 060 * 061 * <p>The input ImgData and component index list must be defined when 062 * constructing this class and can not be modified later.</p> 063 * 064 * @see ImgData 065 * @see jj2000.j2k.image.input.ImgReader 066 * */ 067public class ImgDataJoiner implements BlkImgDataSrc { 068 069 /** The width of the image */ 070 private int w; 071 072 /** The height of the image */ 073 private int h; 074 075 /** The number of components in the image */ 076 private int nc; 077 078 /** The list of input ImgData */ 079 private BlkImgDataSrc[] imageData; 080 081 /** The component index associated with each ImgData */ 082 private int[] compIdx; 083 084 /** The subsampling factor along the horizontal direction, for every 085 * component */ 086 private int[] subsX; 087 088 /** The subsampling factor along the vertical direction, for every 089 * component */ 090 private int[] subsY; 091 092 /** 093 * Class constructor. Each input BlkImgDataSrc and its component index 094 * must appear in the order wanted for the output components.<br> 095 * 096 * <u>Example:</u> Reading R,G,B components from 3 PGM files.<br> 097 * <tt> 098 * BlkImgDataSrc[] idList = <br> 099 * {<br> 100 * new ImgReaderPGM(new BEBufferedRandomAccessFile("R.pgm", "r")),<br> 101 * new ImgReaderPGM(new BEBufferedRandomAccessFile("G.pgm", "r")),<br> 102 * new ImgReaderPGM(new BEBufferedRandomAccessFile("B.pgm", "r"))<br> 103 * };<br> 104 * int[] compIdx = {0,0,0};<br> 105 * ImgDataJoiner idj = new ImgDataJoiner(idList, compIdx); 106 * </tt> 107 * 108 * <p>Of course, the 2 arrays must have the same length (This length is 109 * the number of output components). The image width and height are 110 * definded to be the maximum values of all the input ImgData. 111 * 112 * @param imD The list of input BlkImgDataSrc in an array. 113 * 114 * @param cIdx The component index associated with each ImgData. 115 * */ 116 public ImgDataJoiner(BlkImgDataSrc[] imD, int[] cIdx){ 117 int i; 118 int maxW, maxH; 119 120 // Initializes 121 imageData = imD; 122 compIdx = cIdx; 123 if(imageData.length != compIdx.length) 124 throw new IllegalArgumentException("imD and cIdx must have the"+ 125 " same length"); 126 127 nc = imD.length; 128 129 subsX = new int[nc]; 130 subsY = new int[nc]; 131 132 // Check that no source is tiled and that the image origin is at the 133 // canvas origin. 134 for(i=0; i<nc; i++) { 135 if (imD[i].getNumTiles() != 1 || 136 imD[i].getCompULX(cIdx[i])!=0 || 137 imD[i].getCompULY(cIdx[i])!=0) { 138 throw 139 new IllegalArgumentException("All input components must, "+ 140 "not use tiles and must "+ 141 "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] != 180 imD[i].getCompImgWidth(cIdx[i]) || 181 (maxH+subsY[i]-1)/subsY[i] != 182 imD[i].getCompImgHeight(cIdx[i])) { 183 throw new Error("Can not compute component subsampling "+ 184 "factors: strange subsampling."); 185 } 186 } 187 } 188 189 /** 190 * Returns the overall width of the current tile in pixels. This is the 191 * tile's width without accounting for any component subsampling. 192 * 193 * @return The total current tile's width in pixels. 194 * */ 195 public int getTileWidth(){ 196 return w; 197 } 198 199 /** 200 * Returns the overall height of the current tile in pixels. This is the 201 * tile's height without accounting for any component subsampling. 202 * 203 * @return The total current tile's height in pixels. 204 * */ 205 public int getTileHeight(){ 206 return h; 207 } 208 209 /** Returns the nominal tiles width */ 210 public int getNomTileWidth() { 211 return w; 212 } 213 214 /** Returns the nominal tiles height */ 215 public int getNomTileHeight() { 216 return h; 217 } 218 219 /** 220 * Returns the overall width of the image in pixels. This is the image's 221 * width without accounting for any component subsampling or tiling. 222 * 223 * @return The total image's width in pixels. 224 * */ 225 public int getImgWidth(){ 226 return w; 227 } 228 229 /** 230 * Returns the overall height of the image in pixels. This is the image's 231 * height without accounting for any component subsampling or tiling. 232 * 233 * @return The total image's height in pixels. 234 * */ 235 public int getImgHeight(){ 236 return h; 237 } 238 239 /** 240 * Returns the number of components in the image. 241 * 242 * @return The number of components in the image. 243 * */ 244 public int getNumComps(){ 245 return nc; 246 } 247 248 /** 249 * Returns the component subsampling factor in the horizontal direction, 250 * for the specified component. This is, approximately, the ratio of 251 * dimensions between the reference grid and the component itself, see the 252 * 'ImgData' interface desription for details. 253 * 254 * @param c The index of the component (between 0 and N-1) 255 * 256 * @return The horizontal subsampling factor of component 'c' 257 * 258 * @see ImgData 259 * */ 260 public int getCompSubsX(int c) { 261 return subsX[c]; 262 } 263 264 /** 265 * Returns the component subsampling factor in the vertical direction, for 266 * the specified component. This is, approximately, the ratio of 267 * dimensions between the reference grid and the component itself, see the 268 * 'ImgData' interface desription for details. 269 * 270 * @param c The index of the component (between 0 and N-1) 271 * 272 * @return The vertical subsampling factor of component 'c' 273 * 274 * @see ImgData 275 * */ 276 public int getCompSubsY(int c) { 277 return subsY[c]; 278 } 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 } 494 else { 495 return new Point(0,0); 496 } 497 } 498 499 /** 500 * Returns the index of the current tile, relative to a standard scan-line 501 * order. This default implementations assumes no tiling, so 0 is always 502 * returned. 503 * 504 * @return The current tile's index (starts at 0). 505 * */ 506 public int getTileIdx() { 507 return 0; 508 } 509 510 /** 511 * Returns the horizontal coordinate of the upper-left corner of the 512 * specified component in the current tile. 513 * 514 * @param c The component index. 515 * */ 516 public int getCompULX(int c) { 517 return 0; 518 } 519 520 /** 521 * Returns the vertical 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 int getCompULY(int c) { 527 return 0; 528 } 529 530 /** Returns the horizontal tile partition offset in the reference grid */ 531 public int getTilePartULX() { 532 return 0; 533 } 534 535 /** Returns the vertical tile partition offset in the reference grid */ 536 public int getTilePartULY() { 537 return 0; 538 } 539 540 /** 541 * Returns the horizontal coordinate of the image origin, the top-left 542 * corner, in the canvas system, on the reference grid. 543 * 544 * @return The horizontal coordinate of the image origin in the canvas 545 * system, on the reference grid. 546 * */ 547 public int getImgULX() { 548 return 0; 549 } 550 551 /** 552 * Returns the vertical coordinate of the image origin, the top-left 553 * corner, in the canvas system, on the reference grid. 554 * 555 * @return The vertical coordinate of the image origin in the canvas 556 * system, on the reference grid. 557 * */ 558 public int getImgULY() { 559 return 0; 560 } 561 562 /** 563 * Returns the number of tiles in the horizontal and vertical 564 * directions. This default implementation assumes no tiling, so (1,1) is 565 * always returned. 566 * 567 * @param co If not null this object is used to return the information. If 568 * null a new one is created and returned. 569 * 570 * @return The number of tiles in the horizontal (Point.x) and vertical 571 * (Point.y) directions. 572 * */ 573 public Point getNumTiles(Point co) { 574 if (co != null) { 575 co.x = 1; 576 co.y = 1; 577 return co; 578 } 579 else { 580 return new Point(1,1); 581 } 582 } 583 584 /** 585 * Returns the total number of tiles in the image. This default 586 * implementation assumes no tiling, so 1 is always returned. 587 * 588 * @return The total number of tiles in the image. 589 * */ 590 public int getNumTiles() { 591 return 1; 592 } 593 594 /** 595 * Returns a string of information about the object, more than 1 line 596 * long. The information string includes information from the several 597 * input ImgData (their toString() method are called one after the other). 598 * 599 * @return A string of information about the object. 600 * */ 601 public String toString() { 602 String string = "ImgDataJoiner: WxH = " + w + "x" + h; 603 for(int i=0; i<nc; i++){ 604 string += "\n- Component "+i+" "+imageData[i]; 605 } 606 return string; 607 } 608}