001/* 002 * $RCSfile: PNMImageReader.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.1 $ 042 * $Date: 2005/02/11 05:01:40 $ 043 * $State: Exp $ 044 */ 045package com.github.jaiimageio.impl.plugins.pnm; 046 047import java.awt.Point; 048import java.awt.Rectangle; 049import java.awt.image.BufferedImage; 050import java.awt.image.ColorModel; 051import java.awt.image.DataBuffer; 052import java.awt.image.DataBufferByte; 053import java.awt.image.DataBufferInt; 054import java.awt.image.DataBufferUShort; 055import java.awt.image.IndexColorModel; 056import java.awt.image.MultiPixelPackedSampleModel; 057import java.awt.image.PixelInterleavedSampleModel; 058import java.awt.image.Raster; 059import java.awt.image.SampleModel; 060import java.awt.image.WritableRaster; 061import java.io.IOException; 062import java.util.ArrayList; 063import java.util.Iterator; 064import java.util.StringTokenizer; 065 066import javax.imageio.ImageReadParam; 067import javax.imageio.ImageReader; 068import javax.imageio.ImageTypeSpecifier; 069import javax.imageio.metadata.IIOMetadata; 070import javax.imageio.spi.ImageReaderSpi; 071import javax.imageio.stream.ImageInputStream; 072 073import com.github.jaiimageio.impl.common.ImageUtil; 074 075/** This class is the Java Image IO plugin reader for PNM images. 076 * It may subsample the image, clip the image, select sub-bands, 077 * and shift the decoded image origin if the proper decoding parameter 078 * are set in the provided <code>PNMImageReadParam</code>. 079 */ 080public class PNMImageReader extends ImageReader { 081 private static final int PBM_ASCII = '1'; 082 private static final int PGM_ASCII = '2'; 083 private static final int PPM_ASCII = '3'; 084 private static final int PBM_RAW = '4'; 085 private static final int PGM_RAW = '5'; 086 private static final int PPM_RAW = '6'; 087 088 private static final int LINE_FEED = 0x0A; 089 private static byte[] lineSeparator; 090 091 static { 092 if (lineSeparator == null) { 093 lineSeparator = System.getProperty("line.separator").getBytes(); 094 } 095 } 096 097 /** File variant: PBM/PGM/PPM, ASCII/RAW. */ 098 private int variant; 099 100 /** Maximum pixel value. */ 101 private int maxValue; 102 103 /** The input stream where reads from */ 104 private ImageInputStream iis = null; 105 106 /** Indicates whether the header is read. */ 107 private boolean gotHeader = false; 108 109 /** The stream position where the image data starts. */ 110 private long imageDataOffset; 111 112 /** The original image width. */ 113 private int width; 114 115 /** The original image height. */ 116 private int height; 117 118 private String aLine; 119 private StringTokenizer token; 120 121 private PNMMetadata metadata; 122 123 /** Constructs <code>PNMImageReader</code> from the provided 124 * <code>ImageReaderSpi</code>. 125 */ 126 public PNMImageReader(ImageReaderSpi originator) { 127 super(originator); 128 } 129 130 /** Overrides the method defined in the superclass. */ 131 public void setInput(Object input, 132 boolean seekForwardOnly, 133 boolean ignoreMetadata) { 134 super.setInput(input, seekForwardOnly, ignoreMetadata); 135 iis = (ImageInputStream) input; // Always works 136 } 137 138 /** Overrides the method defined in the superclass. */ 139 public int getNumImages(boolean allowSearch) throws IOException { 140 return 1; 141 } 142 143 public int getWidth(int imageIndex) throws IOException { 144 checkIndex(imageIndex); 145 readHeader(); 146 return width; 147 } 148 149 public int getHeight(int imageIndex) throws IOException { 150 checkIndex(imageIndex); 151 readHeader(); 152 return height; 153 } 154 155 public int getVariant() { 156 return variant; 157 } 158 159 public int getMaxValue() { 160 return maxValue; 161 } 162 163 private void checkIndex(int imageIndex) { 164 if (imageIndex != 0) { 165 throw new IndexOutOfBoundsException(I18N.getString("PNMImageReader1")); 166 } 167 } 168 169 public synchronized void readHeader() throws IOException { 170 if (gotHeader) { 171 // Seek to where the image data starts, since that is where 172 // the stream pointer should be after header is read 173 iis.seek(imageDataOffset); 174 return; 175 } 176 177 if (iis != null) { 178 if (iis.readByte() != 'P') { // magic number 179 throw new RuntimeException(I18N.getString("PNMImageReader0")); 180 } 181 182 variant = iis.readByte(); // file variant 183 if ((variant < PBM_ASCII) || (variant > PPM_RAW)) { 184 throw new RuntimeException(I18N.getString("PNMImageReader0")); 185 } 186 187 // Create the metadata object. 188 metadata = new PNMMetadata(); 189 190 // Set the variant. 191 metadata.setVariant(variant); 192 193 // Read the line separator. 194 iis.readLine(); 195 196 readComments(iis, metadata); 197 198 width = readInteger(iis); // width 199 height = readInteger(iis); // height 200 201 if (variant == PBM_ASCII || variant == PBM_RAW) { 202 maxValue = 1; 203 } else { 204 maxValue = readInteger(iis); // maximum value 205 } 206 207 metadata.setWidth(width); 208 metadata.setHeight(height); 209 metadata.setMaxBitDepth(maxValue); 210 211 gotHeader = true; 212 213 // Store the stream position where the image data starts 214 imageDataOffset = iis.getStreamPosition(); 215 } 216 } 217 218 public Iterator getImageTypes(int imageIndex) 219 throws IOException { 220 checkIndex(imageIndex); 221 222 readHeader(); 223 int tmp = (variant - '1') % 3 ; 224 225 ArrayList list = new ArrayList(1); 226 int dataType = DataBuffer.TYPE_INT; 227 // Determine data type based on maxValue. 228 if (maxValue < 0x100) { 229 dataType = DataBuffer.TYPE_BYTE; 230 } else if (maxValue < 0x10000) { 231 dataType = DataBuffer.TYPE_USHORT; 232 } 233 234 // Choose an appropriate SampleModel. 235 SampleModel sampleModel = null; 236 ColorModel colorModel = null; 237 if ((variant == PBM_ASCII) || (variant == PBM_RAW)) { 238 // Each pixel takes 1 bit, pack 8 pixels into a byte. 239 sampleModel = new MultiPixelPackedSampleModel( 240 DataBuffer.TYPE_BYTE, 241 width, 242 height, 243 1); 244 byte[] color = {(byte)0xFF, (byte)0}; 245 colorModel = new IndexColorModel(1, 2, color, color, color); 246 } else { 247 sampleModel = 248 new PixelInterleavedSampleModel(dataType, 249 width, 250 height, 251 tmp == 1 ? 1 : 3, 252 width * (tmp == 1 ? 1 : 3), 253 tmp == 1 ? new int[]{0} : new int[]{0, 1, 2}); 254 255 colorModel = ImageUtil.createColorModel(null, sampleModel); 256 } 257 258 list.add(new ImageTypeSpecifier(colorModel, sampleModel)); 259 260 return list.iterator(); 261 } 262 263 public ImageReadParam getDefaultReadParam() { 264 return new ImageReadParam(); 265 } 266 267 public IIOMetadata getImageMetadata(int imageIndex) 268 throws IOException { 269 checkIndex(imageIndex); 270 readHeader(); 271 return metadata; 272 } 273 274 public IIOMetadata getStreamMetadata() throws IOException { 275 return null; 276 } 277 278 public boolean isRandomAccessEasy(int imageIndex) throws IOException { 279 checkIndex(imageIndex); 280 return true; 281 } 282 283 public BufferedImage read(int imageIndex, ImageReadParam param) 284 throws IOException { 285 checkIndex(imageIndex); 286 clearAbortRequest(); 287 processImageStarted(imageIndex); 288 289 if (param == null) 290 param = getDefaultReadParam(); 291 292 //read header 293 readHeader(); 294 295 Rectangle sourceRegion = new Rectangle(0, 0, 0, 0); 296 Rectangle destinationRegion = new Rectangle(0, 0, 0, 0); 297 298 computeRegions(param, this.width, this.height, 299 param.getDestination(), 300 sourceRegion, 301 destinationRegion); 302 303 int scaleX = param.getSourceXSubsampling(); 304 int scaleY = param.getSourceYSubsampling(); 305 306 // If the destination band is set used it 307 int[] sourceBands = param.getSourceBands(); 308 int[] destBands = param.getDestinationBands(); 309 310 boolean seleBand = (sourceBands != null) && (destBands != null); 311 boolean noTransform = 312 destinationRegion.equals(new Rectangle(0, 0, width, height)) || 313 seleBand; 314 315 // The RAWBITS format can only support byte image data, which means 316 // maxValue should be less than 0x100. In case there's a conflict, 317 // base the maxValue on variant. 318 if (isRaw(variant) && maxValue >= 0x100) { 319 maxValue = 0xFF; 320 } 321 322 int numBands = 1; 323 // Determine number of bands: pixmap (PPM) is 3 bands, 324 // bitmap (PBM) and greymap (PGM) are 1 band. 325 if (variant == PPM_ASCII || variant == PPM_RAW) { 326 numBands = 3; 327 } 328 329 if (!seleBand) { 330 sourceBands = new int[numBands]; 331 destBands = new int[numBands]; 332 for (int i = 0; i < numBands; i++) 333 destBands[i] = sourceBands[i] = i; 334 } 335 336 int dataType = DataBuffer.TYPE_INT; 337 // Determine data type based on maxValue. 338 if (maxValue < 0x100) { 339 dataType = DataBuffer.TYPE_BYTE; 340 } else if (maxValue < 0x10000) { 341 dataType = DataBuffer.TYPE_USHORT; 342 } 343 344 // Choose an appropriate SampleModel. 345 SampleModel sampleModel = null; 346 ColorModel colorModel = null; 347 if ((variant == PBM_ASCII) || (variant == PBM_RAW)) { 348 // Each pixel takes 1 bit, pack 8 pixels into a byte. 349 sampleModel = new MultiPixelPackedSampleModel( 350 DataBuffer.TYPE_BYTE, 351 destinationRegion.width, 352 destinationRegion.height, 353 1); 354 byte[] color = {(byte)0xFF, (byte)0}; 355 colorModel = new IndexColorModel(1, 2, color, color, color); 356 } else { 357 sampleModel = 358 new PixelInterleavedSampleModel(dataType, 359 destinationRegion.width, 360 destinationRegion.height, 361 sourceBands.length, 362 destinationRegion.width * 363 sourceBands.length, 364 destBands); 365 366 colorModel = ImageUtil.createColorModel(null, sampleModel); 367 } 368 369 // If the destination is provided, then use it. Otherwise, create new 370 // one 371 BufferedImage bi = param.getDestination(); 372 373 // Get the image data. 374 WritableRaster raster = null; 375 376 if (bi == null) { 377 sampleModel = sampleModel.createCompatibleSampleModel( 378 destinationRegion.x + destinationRegion.width, 379 destinationRegion.y + destinationRegion.height); 380 if (seleBand) 381 sampleModel = sampleModel.createSubsetSampleModel(sourceBands); 382 383 raster = Raster.createWritableRaster(sampleModel, new Point()); 384 bi = new BufferedImage(colorModel, raster, false, null); 385 } else { 386 raster = bi.getWritableTile(0, 0); 387 sampleModel = bi.getSampleModel(); 388 colorModel = bi.getColorModel(); 389 noTransform &= destinationRegion.equals(raster.getBounds()); 390 } 391 392 switch (variant) { 393 case PBM_RAW: 394 { 395 396 // SampleModel for these cases should be MultiPixelPacked. 397 DataBuffer dataBuffer = raster.getDataBuffer(); 398 399 // Read the entire image. 400 byte[] buf = ((DataBufferByte)dataBuffer).getData(); 401 if (noTransform) { 402 iis.readFully(buf, 0, buf.length); 403 processImageUpdate(bi, 404 0, 0, 405 width, height, 1, 1, 406 destBands); 407 processImageProgress(100.0F); 408 } else if (scaleX == 1 && sourceRegion.x % 8 == 0) { 409 int skip = sourceRegion.x >> 3; 410 int originalLS = width + 7 >> 3; 411 int destLS = raster.getWidth() + 7 >> 3; 412 413 int readLength = sourceRegion.width + 7 >> 3; 414 int offset = sourceRegion.y * originalLS; 415 iis.skipBytes(offset + skip); 416 offset = originalLS * (scaleY - 1) + originalLS - readLength; 417 byte[] lineData = new byte[readLength]; 418 419 int bitoff = destinationRegion.x & 7; 420 boolean reformat = !(bitoff == 0); 421 422 for (int i = 0, j = 0, 423 k = destinationRegion.y * destLS + (destinationRegion.x >> 3); 424 i < destinationRegion.height; i++, j += scaleY) { 425 if (reformat) { 426 iis.read(lineData, 0, readLength); 427 int mask1 = (255 << bitoff) & 255; 428 int mask2 = ~mask1 & 255; 429 int shift = 8 - bitoff; 430 431 int n = 0; 432 int m = k; 433 for (; n < readLength -1; n++, m++) 434 buf[m] = (byte)(((lineData[n] & mask2) << shift) | 435 (lineData[n + 1] & mask1) >>bitoff); 436 buf[m] = (byte)((lineData[n] & mask2) << shift); 437 } else { 438 iis.read(buf, k, readLength); 439 } 440 441 iis.skipBytes(offset); 442 k += destLS; 443 444 processImageUpdate(bi, 445 0, i, 446 destinationRegion.width, 1, 1, 1, 447 destBands); 448 processImageProgress(100.0F*i/destinationRegion.height); 449 } 450 } else { 451 int originalLS = width + 7 >> 3; 452 byte[] data = new byte[originalLS]; 453 iis.skipBytes(sourceRegion.y * originalLS); 454 int destLS = bi.getWidth() + 7 >> 3; 455 int offset = originalLS * (scaleY - 1); 456 int dsx = destLS * destinationRegion.y + 457 (destinationRegion.x >> 3); 458 for (int i = 0, j = 0, n = dsx; 459 i < destinationRegion.height; i++, j += scaleY) { 460 iis.read(data, 0, originalLS); 461 iis.skipBytes(offset); 462 463 int b = 0; 464 int pos = 7 - (destinationRegion.x & 7); 465 for (int m = sourceRegion.x; 466 m < sourceRegion.x + sourceRegion.width; 467 m += scaleX) { 468 b |= (data[m >> 3] >> (7 - (m & 7)) & 1) << pos; 469 pos--; 470 if (pos == -1) { 471 buf[n++] = (byte)b; 472 b = 0; 473 pos = 7; 474 } 475 } 476 477 if (pos != 7) 478 buf[n++] = (byte)b; 479 480 n += destinationRegion.x >> 3; 481 processImageUpdate(bi, 482 0, i, 483 destinationRegion.width, 1, 1, 1, 484 destBands); 485 processImageProgress(100.0F*i/destinationRegion.height); 486 } 487 } 488 break; 489 } 490 case PBM_ASCII: 491 { 492 DataBuffer dataBuffer = raster.getDataBuffer(); 493 byte[] buf = ((DataBufferByte)dataBuffer).getData(); 494 if (noTransform) 495 for (int i = 0, n = 0; i < height; i++) { 496 int b = 0; 497 int pos = 7; 498 for (int j = 0; j < width; j++) { 499 b |= (readInteger(iis) & 1) << pos; 500 pos--; 501 if (pos == -1 ) { 502 buf[n++] = (byte)b; 503 b = 0; 504 pos = 7; 505 } 506 } 507 if (pos != 7) 508 buf[n++] = (byte)b; 509 processImageUpdate(bi, 510 0, i, 511 width, 1, 1, 1, 512 destBands); 513 processImageProgress(100.0F * i / height); 514 } 515 else { 516 skipInteger(iis, sourceRegion.y * width + sourceRegion.x); 517 int skipX = scaleX - 1; 518 int skipY = (scaleY - 1) * width + 519 width - destinationRegion.width * scaleX; 520 int dsx = (bi.getWidth() + 7 >> 3) * 521 destinationRegion.y + (destinationRegion.x >> 3); 522 for (int i = 0, n = dsx; i < destinationRegion.height; i++) { 523 int b = 0; 524 int pos = 7 - (destinationRegion.x & 7); 525 for (int j = 0; j < destinationRegion.width; j++) { 526 b |= (readInteger(iis) & 1) << pos; 527 pos--; 528 if (pos == -1 ) { 529 buf[n++] = (byte)b; 530 b = 0; 531 pos = 7; 532 } 533 skipInteger(iis, skipX); 534 } 535 if (pos != 7) 536 buf[n++] = (byte)b; 537 538 n += destinationRegion.x >> 3; 539 skipInteger(iis, skipY); 540 processImageUpdate(bi, 541 0, i, 542 destinationRegion.width, 1, 1, 1, 543 destBands); 544 processImageProgress(100.0F*i/destinationRegion.height); 545 } 546 } 547 break; 548 } 549 case PGM_ASCII: 550 case PGM_RAW: 551 case PPM_ASCII: 552 case PPM_RAW: 553 // SampleModel for these cases should be PixelInterleaved. 554 int skipX = (scaleX - 1) * numBands; 555 int skipY = (scaleY * width - 556 destinationRegion.width * scaleX) * numBands; 557 int dsx = (bi.getWidth() * destinationRegion. y + 558 destinationRegion.x) * numBands; 559 switch (dataType) { 560 case DataBuffer.TYPE_BYTE: 561 DataBufferByte bbuf = 562 (DataBufferByte)raster.getDataBuffer(); 563 byte[] byteArray = bbuf.getData(); 564 if (isRaw(variant)) { 565 if (noTransform) { 566 iis.readFully(byteArray); 567 processImageUpdate(bi, 568 0, 0, 569 width, height, 1, 1, 570 destBands); 571 processImageProgress(100.0F); 572 } else { 573 iis.skipBytes(sourceRegion.y * width * numBands); 574 int skip = (scaleY - 1) * width * numBands; 575 byte[] data = new byte[width * numBands]; 576 int pixelStride = scaleX * numBands; 577 int sx = sourceRegion.x * numBands; 578 int ex = width; 579 for (int i = 0, n = dsx ; i < destinationRegion.height; i++) { 580 iis.read(data); 581 for (int j = sourceRegion.x, k = sx; 582 j < sourceRegion.x + sourceRegion.width; 583 j+= scaleX, k += pixelStride) { 584 for (int m = 0; m < sourceBands.length; m++) 585 byteArray[n+ destBands[m]] = data[k + sourceBands[m]]; 586 n += sourceBands.length; 587 } 588 n += destinationRegion.x * numBands; 589 iis.skipBytes(skip); 590 processImageUpdate(bi, 591 0, i, 592 destinationRegion.width, 1, 1, 1, 593 destBands); 594 processImageProgress(100.0F*i/destinationRegion.height); 595 } 596 } 597 } else { 598 skipInteger(iis, 599 (sourceRegion.y * width + sourceRegion.x) * 600 numBands); 601 602 if (seleBand) { 603 byte[] data = new byte[numBands]; 604 for (int i = 0, n = dsx; i < destinationRegion.height; i++) { 605 for (int j = 0; j < destinationRegion.width; j++) { 606 for (int k = 0; k < numBands; k++) 607 data[k] = (byte)readInteger(iis); 608 for (int k = 0; k < sourceBands.length; k++) 609 byteArray[n+destBands[k]] = data[sourceBands[k]]; 610 n += sourceBands.length; 611 skipInteger(iis, skipX); 612 } 613 n += destinationRegion.x * sourceBands.length; 614 skipInteger(iis, skipY); 615 processImageUpdate(bi, 616 0, i, 617 destinationRegion.width, 1, 1, 1, 618 destBands); 619 processImageProgress(100.0F*i/destinationRegion.height); 620 } 621 } else 622 for (int i = 0, n = dsx; i < destinationRegion.height; i++) { 623 for (int j = 0; j < destinationRegion.width; j++) { 624 for (int k = 0; k < numBands; k++) 625 byteArray[n++] = (byte)readInteger(iis); 626 skipInteger(iis, skipX); 627 } 628 n += destinationRegion.x * sourceBands.length; 629 skipInteger(iis, skipY); 630 processImageUpdate(bi, 631 0, i, 632 destinationRegion.width, 1, 1, 1, 633 destBands); 634 processImageProgress(100.0F*i/destinationRegion.height); 635 } 636 } 637 break; 638 639 case DataBuffer.TYPE_USHORT: 640 DataBufferUShort sbuf = 641 (DataBufferUShort)raster.getDataBuffer(); 642 short[] shortArray = sbuf.getData(); 643 skipInteger(iis, sourceRegion.y * width * numBands + sourceRegion.x); 644 645 if (seleBand) { 646 short[] data = new short[numBands]; 647 for (int i = 0, n = dsx; i < destinationRegion.height; i++) { 648 for (int j = 0; j < destinationRegion.width; j++) { 649 for (int k = 0; k < numBands; k++) 650 data[k] = (short)readInteger(iis); 651 for (int k = 0; k < sourceBands.length; k++) 652 shortArray[n+destBands[k]] = data[sourceBands[k]]; 653 n += sourceBands.length; 654 skipInteger(iis, skipX); 655 } 656 n += destinationRegion.x * sourceBands.length; 657 skipInteger(iis, skipY); 658 processImageUpdate(bi, 659 0, i, 660 destinationRegion.width, 1, 1, 1, 661 destBands); 662 processImageProgress(100.0F*i/destinationRegion.height); 663 } 664 } else 665 for (int i = 0, n = dsx; i < destinationRegion.height; i++) { 666 for (int j = 0; j < destinationRegion.width; j++) { 667 for (int k = 0; k < numBands; k++) 668 shortArray[n++] = (short)readInteger(iis); 669 skipInteger(iis, skipX); 670 } 671 n += destinationRegion.x * sourceBands.length; 672 skipInteger(iis, skipY); 673 processImageUpdate(bi, 674 0, i, 675 destinationRegion.width, 1, 1, 1, 676 destBands); 677 processImageProgress(100.0F*i/destinationRegion.height); 678 } 679 break; 680 681 case DataBuffer.TYPE_INT: 682 DataBufferInt ibuf = 683 (DataBufferInt)raster.getDataBuffer(); 684 int[] intArray = ibuf.getData(); 685 skipInteger(iis, sourceRegion.y * width * numBands + sourceRegion.x); 686 if (seleBand) { 687 int[] data = new int[numBands]; 688 for (int i = 0, n = dsx; i < destinationRegion.height; i++) { 689 for (int j = 0; j < destinationRegion.width; j++) { 690 for (int k = 0; k < numBands; k++) 691 data[k] = readInteger(iis); 692 for (int k = 0; k < sourceBands.length; k++) 693 intArray[n+destBands[k]] = data[sourceBands[k]]; 694 n += sourceBands.length; 695 skipInteger(iis, skipX); 696 } 697 n += destinationRegion.x * sourceBands.length; 698 skipInteger(iis, skipY); 699 processImageUpdate(bi, 700 0, i, 701 destinationRegion.width, 1, 1, 1, 702 destBands); 703 processImageProgress(100.0F*i/destinationRegion.height); 704 } 705 } else 706 for (int i = 0, n = dsx; i < destinationRegion.height; i++) { 707 for (int j = 0; j < destinationRegion.width; j++) { 708 for (int k = 0; k < numBands; k++) 709 intArray[n++] = readInteger(iis); 710 skipInteger(iis, skipX); 711 } 712 n += destinationRegion.x * sourceBands.length; 713 skipInteger(iis, skipY); 714 processImageUpdate(bi, 715 0, i, 716 destinationRegion.width, 1, 1, 1, 717 destBands); 718 processImageProgress(100.0F*i/destinationRegion.height); 719 } 720 break; 721 } 722 break; 723 } 724 725 if (abortRequested()) 726 processReadAborted(); 727 else 728 processImageComplete(); 729 return bi; 730 } 731 732 public boolean canReadRaster() { 733 return true; 734 } 735 736 public Raster readRaster(int imageIndex, 737 ImageReadParam param) throws IOException { 738 BufferedImage bi = read(imageIndex, param); 739 return bi.getData(); 740 } 741 742 public void reset() { 743 super.reset(); 744 iis = null; 745 gotHeader = false; 746 System.gc(); 747 } 748 749 /** Returns true if file variant is raw format, false if ASCII. */ 750 private boolean isRaw(int v) { 751 return (v >= PBM_RAW); 752 } 753 754 /** Reads the comments. */ 755 private void readComments(ImageInputStream stream, 756 PNMMetadata metadata) throws IOException { 757 String line = null; 758 int pos = -1; 759 stream.mark(); 760 while ((line = stream.readLine()) != null && 761 (pos = line.indexOf("#")) >= 0) { 762 metadata.addComment(line.substring(pos + 1).trim()); 763 } 764 stream.reset(); 765 } 766 767 /** Reads the next integer. */ 768 private int readInteger(ImageInputStream stream) throws IOException { 769 boolean foundDigit = false; 770 771 while (aLine == null) { 772 aLine = stream.readLine(); 773 if (aLine == null) 774 return 0; 775 int pos = aLine.indexOf("#"); 776 if (pos == 0) 777 aLine = null; 778 else if (pos > 0) 779 aLine = aLine.substring(0, pos - 1); 780 781 if (aLine != null) 782 token = new StringTokenizer(aLine); 783 } 784 785 while (token.hasMoreTokens()) { 786 String s = token.nextToken(); 787 788 try { 789 return new Integer(s).intValue(); 790 } catch (NumberFormatException e) { 791 continue; 792 } 793 } 794 795 if (!foundDigit) { 796 aLine = null; 797 return readInteger(stream); 798 } 799 800 return 0; 801 } 802 803 private void skipInteger(ImageInputStream stream, int num) throws IOException { 804 for (int i = 0; i < num; i++) 805 readInteger(stream); 806 } 807}