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