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