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