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