001/* 002 * $RCSfile: RenderedImageSrc.java,v $ 003 * 004 * 005 * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without 008 * modification, are permitted provided that the following conditions 009 * are met: 010 * 011 * - Redistribution of source code must retain the above copyright 012 * notice, this list of conditions and the following disclaimer. 013 * 014 * - Redistribution in binary form must reproduce the above copyright 015 * notice, this list of conditions and the following disclaimer in 016 * the documentation and/or other materials provided with the 017 * distribution. 018 * 019 * Neither the name of Sun Microsystems, Inc. or the names of 020 * contributors may be used to endorse or promote products derived 021 * from this software without specific prior written permission. 022 * 023 * This software is provided "AS IS," without a warranty of any 024 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 025 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 026 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY 027 * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL 028 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 029 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS 030 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR 031 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, 032 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND 033 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR 034 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE 035 * POSSIBILITY OF SUCH DAMAGES. 036 * 037 * You acknowledge that this software is not designed or intended for 038 * use in the design, construction, operation or maintenance of any 039 * nuclear facility. 040 * 041 * $Revision: 1.2 $ 042 * $Date: 2006/09/22 23:07:25 $ 043 * $State: Exp $ 044 */ 045package com.github.jaiimageio.jpeg2000.impl; 046 047import java.awt.Point; 048import java.awt.Rectangle; 049import java.awt.image.ColorModel; 050import java.awt.image.DataBuffer; 051import java.awt.image.Raster; 052import java.awt.image.RenderedImage; 053import java.awt.image.SampleModel; 054import java.awt.image.WritableRaster; 055 056import jj2000.j2k.JJ2KExceptionHandler; 057import jj2000.j2k.image.BlkImgDataSrc; 058import jj2000.j2k.image.DataBlk; 059import jj2000.j2k.image.DataBlkInt; 060import jj2000.j2k.image.ImgData; 061 062import com.github.jaiimageio.impl.common.ImageUtil; 063 064public class RenderedImageSrc implements BlkImgDataSrc { 065 /** The width of the image */ 066 private int w; 067 068 /** The height of the image */ 069 private int h; 070 071 /** The tile width for encoding */ 072 int tileWidth; 073 074 /** The tile height for encoding */ 075 int tileHeight; 076 077 /** The tile grid offset for encoding */ 078 int tileXOffset, tileYOffset; 079 080 /** The source -> destination transformation */ 081 int scaleX, scaleY, xOffset, yOffset; 082 083 /** The source bands to be encoded. */ 084 int[] sourceBands = null; 085 086 /** The destination upper-left corner */ 087 int minX, minY; 088 089 /** The number of components in the image */ 090 private int nc; 091 092 /** The number of bits that determine the nominal dynamic range */ 093 // XXX: Should be an int[] of length 'nc'. 094 private int rb; 095 096 /** Buffer for the 3 components of each pixel(in the current block) */ 097 private int[][] barr = null; 098 099 /** Data block used only to store coordinates of the buffered blocks */ 100 private DataBlkInt dbi = new DataBlkInt(); 101 102 /** The line buffer. */ 103 private byte buf[]; 104 105 /** Temporary DataBlkInt object (needed when encoder uses floating-point 106 filters). This avoid allocating new DataBlk at each time */ 107 private DataBlkInt intBlk; 108 109 private RenderedImage src; 110 private J2KImageWriteParamJava param; 111 112 /** The input source raster. */ 113 private Raster raster; 114 115 /** The raster for a destination tile */ 116 private Raster aTile; 117 118 private Point co = new Point(); 119 120 private int dcOffset = 0; 121 122 private boolean isBinary = false; 123 124 private Rectangle destinationRegion; 125 private Rectangle sourceRegion; 126 127 private ColorModel cm; 128 private SampleModel sm; 129 130 private boolean noTransform = true; 131 private boolean noSubband = true; 132 133 /** Used to process abortion. */ 134 private J2KImageWriter writer; 135 136 /** Indicates a <code>raster</code> rather than a <code>RenderedImage</code> 137 * to be encoded. 138 */ 139 private boolean inputIsRaster = false; 140 141 /** 142 * Creates <code>RenderedImageSrc</code> for encoding a <code>Raster</code>. 143 * 144 * @param raster The <code>Raster</code> to be encoded. 145 * @param param The <code>J2KImageWriteParamJava</code> used in encoding. 146 * @param writer The <code>J2KImageWriter</code> performs the encoding. 147 * 148 * @param IOException If an error occurs while opening the file. 149 */ 150 public RenderedImageSrc(Raster raster, 151 J2KImageWriteParamJava param, 152 J2KImageWriter writer) { 153 this.raster = raster; 154 this.param = param; 155 this.writer = writer; 156 this.inputIsRaster = true; 157 158 sourceRegion = param.getSourceRegion(); 159 160 if (sourceRegion == null) 161 sourceRegion = new Rectangle(raster.getMinX(), raster.getMinY(), 162 raster.getWidth(), raster.getHeight()); 163 else 164 sourceRegion = sourceRegion.intersection(raster.getBounds()); 165 166 if (sourceRegion.isEmpty()) 167 throw new RuntimeException(I18N.getString("J2KImageWriterCodecLib0")); 168 169 sm = raster.getSampleModel(); 170 getFromParam(); 171 setSampleModelAndMore(); 172 setTile(0, 0); 173 } 174 175 /** 176 * Creates <code>RenderedImageSrc</code> for encoding a 177 * <code>RenderedImage</code>. 178 * 179 * @param src The <code>RenderedImage</code> to be encoded. 180 * @param param The <code>J2KImageWriteParamJava</code> used in encoding. 181 * @param writer The <code>J2KImageWriter</code> performs the encoding. 182 * 183 * @param IOException If an error occurs while opening the file. 184 * */ 185 public RenderedImageSrc(RenderedImage src, 186 J2KImageWriteParamJava param, 187 J2KImageWriter writer) { 188 this.src = src; 189 this.param = param; 190 this.writer = writer; 191 192 sourceRegion = param.getSourceRegion(); 193 194 if (sourceRegion == null) 195 sourceRegion = new Rectangle(src.getMinX(), src.getMinY(), 196 src.getWidth(), src.getHeight()); 197 else 198 sourceRegion = sourceRegion.intersection(new Rectangle(src.getMinX(), 199 src.getMinY(), 200 src.getWidth(), 201 src.getHeight())); 202 if (sourceRegion.isEmpty()) 203 throw new RuntimeException(I18N.getString("J2KImageWriterCodecLib0")); 204 205 sm = src.getSampleModel(); 206 cm = src.getColorModel(); 207 getFromParam(); 208 setSampleModelAndMore(); 209 } 210 211 private void getFromParam() { 212 try { 213 tileWidth = param.getTileWidth(); 214 tileHeight = param.getTileHeight(); 215 tileXOffset = param.getTileGridXOffset(); 216 tileYOffset = param.getTileGridYOffset(); 217 } catch(IllegalStateException e) { 218 param.setTilingMode(param.MODE_EXPLICIT); 219 if (inputIsRaster) { 220 param.setTiling(raster.getWidth(), raster.getHeight(), 221 raster.getMinX(), raster.getMinY()); 222 } else { 223 param.setTiling(src.getWidth(), src.getHeight(), 224 src.getMinX(), src.getMinY()); 225 } 226 tileWidth = param.getTileWidth(); 227 tileHeight = param.getTileHeight(); 228 tileXOffset = param.getTileGridXOffset(); 229 tileYOffset = param.getTileGridYOffset(); 230 } 231 232 scaleX = param.getSourceXSubsampling(); 233 scaleY = param.getSourceYSubsampling(); 234 xOffset = param.getSubsamplingXOffset(); 235 yOffset = param.getSubsamplingYOffset(); 236 237 sourceRegion.translate(xOffset, yOffset); 238 sourceRegion.width -= xOffset; 239 sourceRegion.height -= yOffset; 240 241 xOffset = sourceRegion.x % scaleX; 242 yOffset = sourceRegion.y % scaleY; 243 244 minX = sourceRegion.x / scaleX; 245 minY = sourceRegion.y / scaleY; 246 247 w = (sourceRegion.width + scaleX - 1) / scaleX; 248 h = (sourceRegion.height + scaleY - 1) / scaleY; 249 250 tileXOffset += (minX - tileXOffset)/tileWidth * tileWidth; 251 tileYOffset += (minY - tileYOffset)/tileHeight * tileHeight; 252 253 destinationRegion = new Rectangle(minX, minY, w, h); 254 255 if (!destinationRegion.equals(sourceRegion) || 256 tileWidth != sm.getWidth() || 257 tileHeight != sm.getHeight() || 258 (!inputIsRaster && 259 (tileXOffset != src.getTileGridXOffset() || 260 tileYOffset != src.getTileGridYOffset())) || 261 (inputIsRaster && 262 (tileXOffset != raster.getMinX() || 263 tileYOffset != raster.getMinY()))) 264 noTransform = false; 265 266 } 267 268 private void setSampleModelAndMore() { 269 nc = sm.getNumBands(); 270 sourceBands = param.getSourceBands(); 271 if (sourceBands != null) { 272 sm = sm.createSubsetSampleModel(sourceBands); 273 noSubband = false; 274 } else { 275 sourceBands = new int[nc]; 276 for (int i = 0; i < nc; i++) 277 sourceBands[i] = i; 278 } 279 280 sm = sm.createCompatibleSampleModel(tileWidth, tileHeight); 281 nc = sm.getNumBands(); 282 isBinary = ImageUtil.isBinary(sm); 283 284 if(cm != null) { 285 // XXX: rb should be set to getComponentSize(); 286 rb = cm.getComponentSize(0); 287 for (int i = 1; i < cm.getNumComponents(); i++) 288 if (rb < cm.getComponentSize(i)) 289 rb = cm.getComponentSize(i); 290 } else { 291 // XXX: rb should be set to getSampleSize(); 292 rb = sm.getSampleSize(0); 293 for (int i = 1; i < sm.getNumBands(); i++) 294 if (rb < sm.getSampleSize(i)) 295 rb = sm.getSampleSize(i); 296 } 297 298 if (!isOrigSigned(0) && rb > 1) 299 // XXX: if rb is an int[] this will have to change. 300 dcOffset = 1 << rb - 1; 301 } 302 303 304 public int getTilePartULX() { 305 return tileXOffset; 306 } 307 308 public int getTilePartULY() { 309 return tileYOffset; 310 } 311 312 /** 313 * Returns the width of the current tile in pixels. 314 * 315 * @return The total image width in pixels. 316 * */ 317 public int getTileWidth() { 318 int width = tileWidth; 319 int maxX = getImgULX() + getImgWidth(); 320 int x = co.x * tileWidth + tileXOffset; 321 if (x + tileWidth >= maxX) 322 width = maxX - x; 323 return width; 324 } 325 326 /** 327 * Returns the overall height of the current tile in pixels. 328 * 329 * @return The total image height in pixels. */ 330 public int getTileHeight() { 331 int height = tileHeight; 332 int maxY = getImgULY() + getImgHeight(); 333 int y = co.y * tileHeight + tileYOffset; 334 if (y + tileHeight >= maxY) 335 height = maxY - y; 336 337 return height; 338 } 339 340 public int getNomTileWidth() { 341 return tileWidth; 342 } 343 344 public int getNomTileHeight() { 345 return tileHeight; 346 } 347 348 /** 349 * Returns the overall width of the image in pixels. This is the image's 350 * width without accounting for any component subsampling or tiling. The 351 * value of <tt>w</tt> is returned. 352 * 353 * @return The total image's width in pixels. 354 * */ 355 public int getImgWidth() { 356 return w; 357 } 358 359 /** 360 * Returns the overall height of the image in pixels. This is the image's 361 * height without accounting for any component subsampling or tiling. The 362 * value of <tt>h</tt> is returned. 363 * 364 * @return The total image's height in pixels. 365 * */ 366 public int getImgHeight() { 367 return h; 368 } 369 370 /** 371 * Returns the number of components in the image. The value of <tt>nc</tt> 372 * is returned. 373 * 374 * @return The number of components in the image. 375 * */ 376 public int getNumComps() { 377 return nc; 378 } 379 380 public int getTileGridXOffset() { 381 return param.getTileGridXOffset(); 382 } 383 384 public int getTileGridYOffset() { 385 return param.getTileGridYOffset(); 386 } 387 388 public int getTileCompHeight(int t, int c) { 389 return tileHeight; 390 } 391 392 public int getTileCompWidth(int t, int c) { 393 return tileWidth; 394 } 395 396 /** 397 * Returns the component subsampling factor in the horizontal direction, 398 * for the specified component. This is, approximately, the ratio of 399 * dimensions between the reference grid and the component itself, see the 400 * 'ImgData' interface desription for details. 401 * 402 * @param c The index of the component (between 0 and C-1) 403 * 404 * @return The horizontal subsampling factor of component 'c' 405 * 406 * @see ImgData 407 * */ 408 public int getCompSubsX(int c) { 409 return 1; 410 } 411 412 /** 413 * Returns the component subsampling factor in the vertical direction, for 414 * the specified component. This is, approximately, the ratio of 415 * dimensions between the reference grid and the component itself, see the 416 * 'ImgData' interface desription for details. 417 * 418 * @param c The index of the component (between 0 and C-1) 419 * 420 * @return The vertical subsampling factor of component 'c' 421 * 422 * @see ImgData 423 * */ 424 public int getCompSubsY(int c) { 425 return 1; 426 } 427 428 /** 429 * Returns the width in pixels of the specified component in the current 430 * tile. This default implementation assumes no tiling and no component 431 * subsampling (i.e., all components, or components, have the same 432 * dimensions in pixels). 433 * 434 * @param c The index of the component, from 0 to C-1. 435 * 436 * @return The width in pixels of component <tt>n</tt> in the current 437 * tile. 438 * */ 439 public int getCompWidth(int n) { 440 return w; 441 } 442 443 /** 444 * Returns the height in pixels of the specified component in the current 445 * tile. This default implementation assumes no tiling and no component 446 * subsampling (i.e., all components, or components, have the same 447 * dimensions in pixels). 448 * 449 * @param c The index of the component, from 0 to C-1. 450 * 451 * @return The height in pixels of component <tt>c</tt> in the current 452 * tile. 453 * */ 454 public int getCompHeight(int c) { 455 return h; 456 } 457 458 /** 459 * Returns the width in pixels of the specified component in the overall 460 * image. This default implementation assumes no component, or component, 461 * subsampling (i.e. all components have the same dimensions in pixels). 462 * 463 * @param c The index of the component, from 0 to C-1. 464 * 465 * @return The width in pixels of component <tt>c</tt> in the overall 466 * image. 467 * */ 468 public int getCompImgWidth(int c) { 469 return w; 470 } 471 472 /** 473 * Returns the height in pixels of the specified component in the overall 474 * image. This default implementation assumes no component, or component, 475 * subsampling (i.e. all components have the same dimensions in pixels). 476 * 477 * @param c The index of the component, from 0 to C-1. 478 * 479 * @return The height in pixels of component <tt>c</tt> in the overall 480 * image. 481 * */ 482 public int getCompImgHeight(int c) { 483 return h; 484 } 485 486 /** 487 * Changes the current tile, given the new coordinates. 488 * 489 * @param x The horizontal coordinate of the tile. 490 * 491 * @param y The vertical coordinate of the new tile. 492 * */ 493 public void setTile(int x, int y) { 494 if (x >= getNumXTiles()) { 495 y += x/ getNumXTiles(); 496 x = x % getNumXTiles(); 497 } 498 co.x = x; 499 co.y = y; 500 aTile = null; 501 } 502 503 /** 504 * Advances to the next tile, in standard scan-line order (by rows then 505 * columns). 506 * */ 507 public void nextTile() { 508 co.x++; 509 if (co.x >= getNumXTiles()) { 510 co.x = 0; 511 co.y++; 512 } 513 setTile(co.x, co.y); 514 } 515 516 /** 517 * Returns the coordinates of the current tile. This default 518 * implementation assumes no-tiling, so (0,0) is returned. 519 * 520 * @param co If not null this object is used to return the information. If 521 * null a new one is created and returned. 522 * 523 * @return The current tile's coordinates. 524 * */ 525 public Point getTile(Point co) { 526 if (co != null) 527 return co; 528 else 529 return new Point(0, 0); 530 } 531 532 /** 533 * Returns the index of the current tile, relative to a standard scan-line 534 * order. 535 * 536 * @return The current tile's index (starts at 0). 537 * */ 538 public int getTileIdx() { 539 return getNumXTiles() * co.y + co.x; 540 } 541 542 /** 543 * Returns the horizontal and vertical offset of the upper-left corner of 544 * the current tile, in the specified component, relative to the canvas 545 * origin, in the component coordinates (not in the reference grid 546 * coordinates). These are the coordinates of the current tile's (not 547 * active tile) upper-left corner relative to the canvas. 548 * 549 * @param co If not null the object is used to return the values, if null 550 * a new one is created and returned. 551 * 552 * @param c The index of the component (between 0 and C-1) 553 * 554 * @return The horizontal and vertical offsets of the upper-left corner of 555 * the current tile, for the specified component, relative to the canvas 556 * origin, in the component coordinates. 557 * */ 558 public Point getTileOff(Point p, int c) { 559 if (p != null) { 560 p.x = co.x * tileWidth + tileXOffset; 561 p.y = co.y * tileHeight + tileYOffset; 562 return co; 563 } else 564 return new Point(co.x * tileWidth + tileXOffset, 565 co.y * tileHeight + tileYOffset); 566 } 567 568 /** 569 * Returns the horizontal coordinate of the upper-left corner of the 570 * active tile, with respect to the canvas origin, in the component 571 * coordinates, for the specified component. 572 * 573 * @param c The index of the component (between 0 and C-1) 574 * 575 * @return The horizontal coordinate of the upper-left corner of the 576 * active tile, with respect to the canvas origin, for component 'c', in 577 * the component coordinates. 578 * */ 579 public int getCompULX(int c) { 580 return raster.getMinX(); 581 } 582 583 /** 584 * Returns the vertical coordinate of the upper-left corner of the active 585 * tile, with respect to the canvas origin, in the component coordinates, 586 * for the specified component. 587 * 588 * @param c The index of the component (between 0 and C-1) 589 * 590 * @return The vertical coordinate of the upper-left corner of the active 591 * tile, with respect to the canvas origin, for component 'c', in the 592 * component coordinates. 593 * */ 594 public int getCompULY(int c) { 595 return raster.getMinY(); 596 } 597 598 /** 599 * Returns the horizontal coordinate of the image origin, the top-left 600 * corner, in the canvas system, on the reference grid. 601 * 602 * @return The horizontal coordinate of the image origin in the canvas 603 * system, on the reference grid. 604 * */ 605 public int getImgULX() { 606 return destinationRegion.x; 607 } 608 609 /** 610 * Returns the vertical coordinate of the image origin, the top-left 611 * corner, in the canvas system, on the reference grid. 612 * 613 * @return The vertical coordinate of the image origin in the canvas 614 * system, on the reference grid. 615 * */ 616 public int getImgULY() { 617 return destinationRegion.y; 618 } 619 620 /** 621 * Returns the number of tiles in the horizontal and vertical 622 * directions. 623 * 624 * @param co If not null this object is used to return the information. If 625 * null a new one is created and returned. 626 * 627 * @return The number of tiles in the horizontal (Point.x) and vertical 628 * (Point.y) directions. 629 * */ 630 public Point getNumTiles(Point co) { 631 if (co != null) { 632 co.x = getNumXTiles(); 633 co.y = getNumYTiles(); 634 return co; 635 } 636 else { 637 return new Point(getNumXTiles(), getNumYTiles()); 638 } 639 } 640 641 /** 642 * Returns the total number of tiles in the image. This default 643 * implementation assumes no tiling, so 1 is always returned. 644 * 645 * @return The total number of tiles in the image. 646 * */ 647 public int getNumTiles() { 648 return getNumXTiles() * getNumYTiles(); 649 } 650 651 /** 652 * Returns the number of bits corresponding to the nominal range of the 653 * data in the specified component. This is the value rb (range bits) that 654 * was specified in the constructor, which normally is 8 for non bilevel 655 * data, and 1 for bilevel data. 656 * 657 * <P>If this number is <i>b</b> then the nominal range is between 658 * -2^(b-1) and 2^(b-1)-1, since unsigned data is level shifted to have a 659 * nominal avergae of 0. 660 * 661 * @param c The index of the component. 662 * 663 * @return The number of bits corresponding to the nominal range of the 664 * data. For floating-point data this value is not applicable and the 665 * return value is undefined. 666 * */ 667 public int getNomRangeBits(int c) { 668 // Check component index 669 // XXX: Should be component-dependent. 670 return rb; 671 } 672 673 /** 674 * Returns the position of the fixed point in the specified component 675 * (i.e. the number of fractional bits), which is always 0 for this 676 * ImgReader. 677 * 678 * @param c The index of the component. 679 * 680 * @return The position of the fixed-point (i.e. the number of fractional 681 * bits). Always 0 for this ImgReader. 682 * */ 683 public int getFixedPoint(int c) { 684 // Check component index 685 return 0; 686 } 687 688 689 /** 690 * Returns, in the blk argument, the block of image data containing the 691 * specifed rectangular area, in the specified component. The data is 692 * returned, as a reference to the internal data, if any, instead of as a 693 * copy, therefore the returned data should not be modified. 694 * 695 * <P> After being read the coefficients are level shifted by subtracting 696 * 2^(nominal bit range - 1) 697 * 698 * <P>The rectangular area to return is specified by the 'ulx', 'uly', 'w' 699 * and 'h' members of the 'blk' argument, relative to the current 700 * tile. These members are not modified by this method. The 'offset' and 701 * 'scanw' of the returned data can be arbitrary. See the 'DataBlk' class. 702 * 703 * <P>If the data array in <tt>blk</tt> is <tt>null</tt>, then a new one 704 * is created if necessary. The implementation of this interface may 705 * choose to return the same array or a new one, depending on what is more 706 * efficient. Therefore, the data array in <tt>blk</tt> prior to the 707 * method call should not be considered to contain the returned data, a 708 * new array may have been created. Instead, get the array from 709 * <tt>blk</tt> after the method has returned. 710 * 711 * <P>The returned data always has its 'progressive' attribute unset 712 * (i.e. false). 713 * 714 * <P>When an I/O exception is encountered the JJ2KExceptionHandler is 715 * used. The exception is passed to its handleException method. The action 716 * that is taken depends on the action that has been registered in 717 * JJ2KExceptionHandler. See JJ2KExceptionHandler for details. 718 * 719 * <P>This method implements buffering for the 3 components: When the 720 * first one is asked, all the 3 components are read and stored until they 721 * are needed. 722 * 723 * @param blk Its coordinates and dimensions specify the area to 724 * return. Some fields in this object are modified to return the data. 725 * 726 * @param c The index of the component from which to get the data. Only 0, 727 * 1 and 3 are valid. 728 * 729 * @return The requested DataBlk 730 * 731 * @see #getCompData 732 * 733 * @see JJ2KExceptionHandler 734 */ 735 public final DataBlk getInternCompData(DataBlk blk, int c) { 736 if (writer != null && writer.getAbortRequest()) 737 throw new RuntimeException(J2KImageWriter.WRITE_ABORTED); 738 739 if (barr == null) 740 barr = new int[nc][]; 741 742 // Check type of block provided as an argument 743 if(blk.getDataType()!=DataBlk.TYPE_INT){ 744 if(intBlk==null) 745 intBlk = new DataBlkInt(blk.ulx,blk.uly,blk.w,blk.h); 746 else{ 747 intBlk.ulx = blk.ulx; 748 intBlk.uly = blk.uly; 749 intBlk.w = blk.w; 750 intBlk.h = blk.h; 751 } 752 blk = intBlk; 753 } 754 755 float percentage = 756 (getTileIdx() + (blk.uly + 1.0F) / blk.h) / getNumTiles(); 757 writer.processImageProgressWrapper(percentage * 100.0F); 758 759 // If asking a component for the first time for this block, read the 3 760 // components 761 if ((barr[c] == null) || 762 (dbi.ulx > blk.ulx) || (dbi.uly > blk.uly) || 763 (dbi.ulx+dbi.w < blk.ulx+blk.w) || 764 (dbi.uly+dbi.h < blk.uly+blk.h)) { 765 int k,j,i,mi; 766 767 // Reset data arrays if needed 768 if (barr[c] == null || barr[c].length < blk.w*blk.h) { 769 barr[c] = new int[blk.w*blk.h]; 770 } 771 blk.setData(barr[c]); 772 773 for (i = (c + 1) % nc; i != c; i = (i + 1) % nc) 774 if (barr[i] == null || barr[i].length < blk.w*blk.h) { 775 barr[i] = new int[blk.w*blk.h]; 776 } 777 778 // set attributes of the DataBlk used for buffering 779 dbi.ulx = blk.ulx; 780 dbi.uly = blk.uly; 781 dbi.w = blk.w; 782 dbi.h = blk.h; 783 784 // get data from the image 785 if (aTile == null) { 786 aTile = getTile(co.x, co.y); 787 Rectangle temp = aTile.getBounds(); 788 aTile = aTile.createTranslatedChild(temp.x-minX, 789 temp.y-minY); 790 } 791 792 for (i = 0; i < nc ; i++) { 793 aTile.getSamples(blk.ulx, blk.uly, blk.w, blk.h, i, barr[i]); 794 for (k = 0; k < barr[i].length; k++) 795 barr[i][k] -= dcOffset; 796 } 797 //getByteData(raster, new Rectangle(blk.ulx, blk.uly, blk.w, blk.h), barr); 798 799 // Set buffer attributes 800 blk.setData(barr[c]); 801 blk.offset = 0; 802 blk.scanw = blk.w; 803 } else { //Asking for the 2nd or 3rd block component 804 blk.setData(barr[c]); 805 blk.offset = (blk.ulx-dbi.ulx)*dbi.w+blk.ulx-dbi.ulx; 806 blk.scanw = dbi.scanw; 807 } 808 809 // Turn off the progressive attribute 810 blk.progressive = false; 811 return blk; 812 } 813 814 /** 815 * Returns, in the blk argument, a block of image data containing the 816 * specifed rectangular area, in the specified component. The data is 817 * returned, as a copy of the internal data, therefore the returned data 818 * can be modified "in place". 819 * 820 * <P> After being read the coefficients are level shifted by subtracting 821 * 2^(nominal bit range - 1) 822 * 823 * <P>The rectangular area to return is specified by the 'ulx', 'uly', 'w' 824 * and 'h' members of the 'blk' argument, relative to the current 825 * tile. These members are not modified by this method. The 'offset' of 826 * the returned data is 0, and the 'scanw' is the same as the block's 827 * width. See the 'DataBlk' class. 828 * 829 * <P>If the data array in 'blk' is 'null', then a new one is created. If 830 * the data array is not 'null' then it is reused, and it must be large 831 * enough to contain the block's data. Otherwise an 'ArrayStoreException' 832 * or an 'IndexOutOfBoundsException' is thrown by the Java system. 833 * 834 * <P>The returned data has its 'progressive' attribute unset 835 * (i.e. false). 836 * 837 * <P>When an I/O exception is encountered the JJ2KExceptionHandler is 838 * used. The exception is passed to its handleException method. The action 839 * that is taken depends on the action that has been registered in 840 * JJ2KExceptionHandler. See JJ2KExceptionHandler for details. 841 * 842 * @param blk Its coordinates and dimensions specify the area to 843 * return. If it contains a non-null data array, then it must have the 844 * correct dimensions. If it contains a null data array a new one is 845 * created. The fields in this object are modified to return the data. 846 * 847 * @param c The index of the component from which to get the data. Only 848 * 0,1 and 2 are valid. 849 * 850 * @return The requested DataBlk 851 * 852 * @see #getInternCompData 853 * 854 * @see JJ2KExceptionHandler 855 * */ 856 public final DataBlk getCompData(DataBlk blk, int c) { 857 // NOTE: can not directly call getInterCompData since that returns 858 // internally buffered data. 859 int ulx,uly,w,h; 860 861 // Check type of block provided as an argument 862 if(blk.getDataType()!=DataBlk.TYPE_INT){ 863 DataBlkInt tmp = new DataBlkInt(blk.ulx,blk.uly,blk.w,blk.h); 864 blk = tmp; 865 } 866 867 int bakarr[] = (int[])blk.getData(); 868 // Save requested block size 869 ulx = blk.ulx; 870 uly = blk.uly; 871 w = blk.w; 872 h = blk.h; 873 // Force internal data buffer to be different from external 874 blk.setData(null); 875 getInternCompData(blk,c); 876 // Copy the data 877 if (bakarr == null) { 878 bakarr = new int[w*h]; 879 } 880 if (blk.offset == 0 && blk.scanw == w) { 881 // Requested and returned block buffer are the same size 882 System.arraycopy(blk.getData(),0,bakarr,0,w*h); 883 } 884 else { // Requested and returned block are different 885 for (int i=h-1; i>=0; i--) { // copy line by line 886 System.arraycopy(blk.getData(),blk.offset+i*blk.scanw, 887 bakarr,i*w,w); 888 } 889 } 890 blk.setData(bakarr); 891 blk.offset = 0; 892 blk.scanw = blk.w; 893 return blk; 894 } 895 896 /** 897 * Returns true if the data read was originally signed in the specified 898 * component, false if not. This method always returns false since PPM 899 * data is always unsigned. 900 * 901 * @param c The index of the component, from 0 to N-1. 902 * 903 * @return always false, since PPM data is always unsigned. 904 * */ 905 public boolean isOrigSigned(int c) { 906 if (isBinary) return true; 907 908 // Check component index 909 SampleModel sm = null; 910 if (inputIsRaster) 911 sm = raster.getSampleModel(); 912 else 913 sm = src.getSampleModel(); 914 915 if (sm.getDataType() == DataBuffer.TYPE_USHORT || 916 sm.getDataType() == DataBuffer.TYPE_BYTE) 917 return false; 918 return true; 919 } 920 921 private int getNumXTiles() { 922 int x = destinationRegion.x; 923 int tx = tileXOffset; 924 int tw = tileWidth; 925 return ToTile(x + destinationRegion.width - 1, tx, tw) - ToTile(x, tx, tw) + 1; 926 } 927 928 private int getNumYTiles() { 929 int y = destinationRegion.y; 930 int ty = tileYOffset; 931 int th = tileHeight; 932 return ToTile(y + destinationRegion.height - 1, ty, th) - ToTile(y, ty, th) + 1; 933 } 934 935 private static int ToTile(int pos, int tileOffset, int tileSize) { 936 pos -= tileOffset; 937 if (pos < 0) { 938 pos += 1 - tileSize; // force round to -infinity (ceiling) 939 } 940 return pos/tileSize; 941 } 942 943 private Raster getTile(int tileX, int tileY) { 944 int sx = tileXOffset + tileX * tileWidth; 945 int sy = tileYOffset + tileY * tileHeight; 946 tileX += tileXOffset / tileWidth; 947 tileY += tileYOffset / tileHeight; 948 949 if (inputIsRaster) { 950 if (noTransform) { 951 return raster.createChild(sx, sy, getTileWidth(), getTileHeight(), 952 sx, sy, sourceBands); 953 } 954 955 WritableRaster ras = 956 Raster.createWritableRaster(sm, new Point(sx, sy)); 957 958 int x = mapToSourceX(sx); 959 int y = mapToSourceY(sy); 960 961 int minY = raster.getMinY(); 962 int maxY = raster.getMinY() + raster.getHeight(); 963 964 int cTileWidth = getTileWidth(); 965 for (int j = 0; j < getTileHeight(); j++, sy++, y += scaleY) { 966 if (y < minY || y >= maxY) 967 continue; 968 Raster source = raster.createChild(x, y, (cTileWidth - 1) * scaleX + 1, 1, 969 x, y, null); 970 int tempX = sx; 971 for (int i = 0, offset = x; i < cTileWidth; i++, tempX++, offset += scaleX) { 972 for (int k = 0; k < nc; k++) { 973 int p = source.getSample(offset, y, sourceBands[k]); 974 ras.setSample(tempX, sy, k, p); 975 } 976 } 977 } 978 979 return ras; 980 981 } else { 982 if (noTransform) { 983 Raster ras = src.getTile(tileX, tileY); 984 if (noSubband) 985 return ras; 986 else { 987 return ras.createChild(sx, sy, tileWidth, tileHeight, 988 sx, sy, sourceBands); 989 } 990 } 991 992 WritableRaster ras = Raster.createWritableRaster(sm, new Point(sx, sy)); 993 994 int x = mapToSourceX(sx); 995 int y = mapToSourceY(sy); 996 997 int minY = src.getMinY(); 998 int maxY = src.getMinY() + src.getHeight(); 999 int length = tileWidth * scaleX; 1000 1001 if (x + length >= src.getWidth()) 1002 length = src.getWidth() - x; 1003 int dLength = (length + scaleX -1 ) / scaleX; 1004 1005 for (int j = 0; j < tileHeight; j++, sy++, y += scaleY) { 1006 if (y < minY || y >= maxY) 1007 continue; 1008 1009 Raster source = src.getData(new Rectangle(x, y, length, 1)); 1010 1011 int tempX = sx; 1012 for (int i = 0, offset = x; i < dLength; i++, tempX++, offset += scaleX) { 1013 1014 for (int k = 0; k < nc; k++) { 1015 int p = source.getSample(offset, y, sourceBands[k]); 1016 1017 ras.setSample(tempX, sy, k, p); 1018 } 1019 } 1020 } 1021 return ras; 1022 } 1023 } 1024 1025 private int mapToSourceX(int x) { 1026 return x * scaleX + xOffset; 1027 } 1028 1029 private int mapToSourceY(int y) { 1030 return y * scaleY + yOffset; 1031 } 1032}