PNMImageDecoder.java
上传用户:btjssb159
上传日期:2018-01-04
资源大小:241k
文件大小:14k
源码类别:

DNA

开发平台:

Java

  1. /*
  2.  * Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without 
  5.  * modification, are permitted provided that the following conditions are met:
  6.  * 
  7.  * -Redistributions of source code must retain the above copyright notice, this 
  8.  * list of conditions and the following disclaimer.
  9.  *
  10.  * -Redistribution in binary form must reproduct the above copyright notice,
  11.  * this list of conditions and the following disclaimer in the documentation
  12.  * and/or other materials provided with the distribution.
  13.  * 
  14.  * Neither the name of Sun Microsystems, Inc. or the names of contributors may
  15.  * be used to endorse or promote products derived from this software without
  16.  * specific prior written permission.
  17.  * 
  18.  * This software is provided "AS IS," without a warranty of any kind. ALL
  19.  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
  20.  * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
  21.  * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
  22.  * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
  23.  * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
  24.  * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
  25.  * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
  26.  * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
  27.  * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
  28.  * POSSIBILITY OF SUCH DAMAGES.
  29.  * 
  30.  * You acknowledge that Software is not designed,licensed or intended for use in 
  31.  * the design, construction, operation or maintenance of any nuclear facility.
  32.  */
  33. import java.awt.Point;
  34. import java.awt.Rectangle;
  35. import java.awt.Transparency;
  36. import java.awt.color.ColorSpace;
  37. import java.awt.image.ComponentColorModel;
  38. import java.awt.image.DataBuffer;
  39. import java.awt.image.DataBufferByte;
  40. import java.awt.image.DataBufferInt;
  41. import java.awt.image.DataBufferUShort;
  42. import java.awt.image.IndexColorModel;
  43. import java.awt.image.MultiPixelPackedSampleModel;
  44. import java.awt.image.Raster;
  45. import java.awt.image.RenderedImage;
  46. import java.awt.image.SampleModel;
  47. import java.awt.image.WritableRaster;
  48. import java.io.IOException;
  49. /**
  50.  */
  51. public class PNMImageDecoder extends ImageDecoderImpl {
  52.     public PNMImageDecoder(SeekableStream input,
  53.                            ImageDecodeParam param) {
  54.         super(input, param);
  55.     }
  56.     public RenderedImage decodeAsRenderedImage(int page) throws IOException {
  57.         if (page != 0) {
  58.             throw new IOException(JaiI18N.getString("PNMImageDecoder5"));
  59.         }
  60.         return new PNMImage(input);
  61.     }
  62. }
  63. class PNMImage extends SimpleRenderedImage {
  64.     private static final int PBM_ASCII = '1';
  65.     private static final int PGM_ASCII = '2';
  66.     private static final int PPM_ASCII = '3';
  67.     private static final int PBM_RAW = '4';
  68.     private static final int PGM_RAW = '5';
  69.     private static final int PPM_RAW = '6';
  70.     private static final int LINE_FEED = 0x0A;
  71.     private SeekableStream input;
  72.     private byte[] lineSeparator;
  73.     /** File variant: PBM/PGM/PPM, ASCII/RAW. */
  74.     private int variant;
  75.     /** Maximum pixel value. */
  76.     private int maxValue;
  77.     /** Raster that is the entire image. */
  78.     private WritableRaster theTile;
  79.     private int numBands;
  80.     private int dataType;
  81.     /**
  82.      * Construct a PNMImage.
  83.      *
  84.      * @param input The SeekableStream for the PNM file.
  85.      */
  86.     public PNMImage(SeekableStream input) {
  87.         theTile = null;
  88.         this.input = input;
  89.         String ls = (String)java.security.AccessController.doPrivileged(
  90.                new sun.security.action.GetPropertyAction("line.separator"));
  91.         lineSeparator = ls.getBytes();
  92.         // Read file header.
  93.         try {
  94.             if (this.input.read() != 'P') { // magic number
  95.                 throw new RuntimeException(JaiI18N.getString("PNMImageDecoder0"));
  96.             }
  97.             variant = this.input.read(); // file variant
  98.             if ((variant < PBM_ASCII) || (variant > PPM_RAW)) {
  99.                 throw new RuntimeException(JaiI18N.getString("PNMImageDecoder1"));
  100.             }
  101.             width = readInteger(this.input); // width
  102.             height = readInteger(this.input); // height
  103.             if (variant == PBM_ASCII || variant == PBM_RAW) {
  104.                 maxValue = 1;
  105.             } else {
  106.                 maxValue = readInteger(this.input); // maximum value
  107.             }
  108.         } catch (IOException e) {
  109.             e.printStackTrace();
  110.             throw new RuntimeException(JaiI18N.getString("PNMImageDecoder2"));
  111.         }
  112.         // The RAWBITS format can only support byte image data, which means
  113.         // maxValue should be less than 0x100. In case there's a conflict,
  114.         // base the maxValue on variant.
  115.         if (isRaw(variant) && maxValue >= 0x100) {
  116.             maxValue = 0xFF;
  117.         }
  118.         // Reset image layout so there's only one tile.
  119.         tileWidth = width;
  120.         tileHeight = height;
  121.         // Determine number of bands: pixmap (PPM) is 3 bands,
  122.         // bitmap (PBM) and greymap (PGM) are 1 band.
  123.         if (variant == PPM_ASCII || variant == PPM_RAW) {
  124.             this.numBands = 3;
  125.         } else {
  126.             this.numBands = 1;
  127.         }
  128.         // Determine data type based on maxValue.
  129.         if (maxValue < 0x100) {
  130.             this.dataType = DataBuffer.TYPE_BYTE;
  131.         } else if (maxValue < 0x10000) {
  132.             this.dataType = DataBuffer.TYPE_USHORT;
  133.         } else {
  134.             this.dataType = DataBuffer.TYPE_INT;
  135.         }
  136.         // Choose an appropriate SampleModel.
  137.         if ((variant == PBM_ASCII) || (variant == PBM_RAW)) {
  138.             // Each pixel takes 1 bit, pack 8 pixels into a byte.
  139.             sampleModel = new MultiPixelPackedSampleModel(
  140.                               DataBuffer.TYPE_BYTE, width, height, 1);
  141.             colorModel =
  142.                 ImageCodec.createGrayIndexColorModel(sampleModel, true);
  143.         } else {
  144.             sampleModel = RasterFactory.createPixelInterleavedSampleModel(
  145.                                         dataType, width, height, numBands);
  146.             
  147.             colorModel =
  148.                 ImageCodec.createComponentColorModel(sampleModel);
  149.         }
  150.     }
  151.     /** Returns true if file variant is raw format, false if ASCII. */
  152.     private boolean isRaw(int v) {
  153.         return (v >= PBM_RAW);
  154.     }
  155.     /** Reads the next integer. */
  156.     private int readInteger(SeekableStream in) throws IOException {
  157.         int ret = 0;
  158.         boolean foundDigit = false;
  159.         int b;
  160.         while ((b = in.read()) != -1) {
  161.             char c = (char)b;
  162.             if (Character.isDigit(c)) {
  163.                 ret = ret * 10 + Character.digit(c, 10);
  164.                 foundDigit = true;
  165.             } else {
  166.                 if (c == '#') { // skip to the end of comment line
  167.                     int length = lineSeparator.length;
  168.                     while ((b = in.read()) != -1) {
  169.                         boolean eol = false;
  170.                         for (int i = 0; i < length; i++) {
  171.                             if (b == lineSeparator[i]) {
  172.                                 eol = true;
  173.                                 break;
  174.                             }
  175.                         }
  176.                         if (eol) {
  177.                             break;
  178.                         }
  179.                     }
  180.                     if (b == -1) {
  181.                         break;
  182.                     }
  183.                 }
  184.                 if (foundDigit) {
  185.                     break;
  186.                 }
  187.             }
  188.         }
  189.         return ret;
  190.     }
  191.     private Raster computeTile(int tileX, int tileY) {
  192.         if (theTile != null) {
  193.             return theTile;
  194.         }
  195.         // Create a new tile.
  196.         Point org = new Point(tileXToX(tileX), tileYToY(tileY));
  197.         theTile = Raster.createWritableRaster(sampleModel, org);
  198.         Rectangle tileRect = theTile.getBounds();
  199.         // There should only be one tile.
  200.         try {
  201.             switch (variant) {
  202.             case PBM_ASCII:
  203.             case PBM_RAW:
  204.                 // SampleModel for these cases should be MultiPixelPacked.
  205.                 DataBuffer dataBuffer = theTile.getDataBuffer();
  206.                 byte[] pixels = new byte[8*width];
  207.                 byte[] buf = null;
  208.                 if (isRaw(variant)) {
  209.                     buf = new byte[width];
  210.                 }
  211.                 
  212.                 // Read 8 rows at a time
  213.                 for (int row = 0; row < height; row += 8) {
  214.                     int rows = Math.min(8, height - row);
  215.                     int len = (rows*width + 7)/8;
  216.                     
  217.                     if (isRaw(variant)) {
  218.                         int nread = 0;
  219.                         while (nread < len) {
  220.                             nread += input.read(buf, nread, len - nread);
  221.                         }
  222.                         
  223.                         for (int i = 0; i < len; i++) {
  224.                             int b = buf[i];
  225.                             pixels[8*i]     = (byte)((b >> 7) & 0x1);
  226.                             pixels[8*i + 1] = (byte)((b >> 6) & 0x1);
  227.                             pixels[8*i + 2] = (byte)((b >> 5) & 0x1);
  228.                             pixels[8*i + 3] = (byte)((b >> 4) & 0x1);
  229.                             pixels[8*i + 4] = (byte)((b >> 3) & 0x1);
  230.                             pixels[8*i + 5] = (byte)((b >> 2) & 0x1);
  231.                             pixels[8*i + 6] = (byte)((b >> 1) & 0x1);
  232.                             pixels[8*i + 7] = (byte)(b & 0x1);
  233.                         }
  234.                     } else {
  235.                         for (int i = 0; i < rows*width; i++) {
  236.                             pixels[i] = (byte)readInteger(input);
  237.                         }
  238.                     }
  239.                     
  240.                     sampleModel.setDataElements(tileRect.x,
  241.                                                 row,
  242.                                                 tileRect.width,
  243.                                                 rows,
  244.                                                 pixels,
  245.                                                 dataBuffer);
  246.                     
  247.                 }
  248.                 break;
  249.             case PGM_ASCII:
  250.             case PGM_RAW:
  251.             case PPM_ASCII:
  252.             case PPM_RAW:
  253.                 // SampleModel for these cases should be PixelInterleaved.
  254.                 int size = width*height*numBands;
  255.                 switch (dataType) {
  256.                 case DataBuffer.TYPE_BYTE:
  257.                     DataBufferByte bbuf =
  258.                         (DataBufferByte)theTile.getDataBuffer();
  259.                     byte[] byteArray = bbuf.getData();
  260.                     if (isRaw(variant)) {
  261.                         input.readFully(byteArray);
  262.                         if (numBands == 3) {
  263.                             for (int i = 0; i < size; i += 3) {
  264.                                 byte tmp = byteArray[i];
  265.                                 byteArray[i] = byteArray[i + 2];
  266.                                 byteArray[i+2] = tmp;
  267.                             }
  268.                         }
  269.                     } else {
  270.                         if (numBands == 1) {
  271.                             for (int i = 0; i < size; i++) {
  272.                                 byteArray[i] = (byte)readInteger(input);
  273.                             }
  274.                         } else {
  275.                             for (int i = 0; i < size; i += 3) {
  276.                                 byteArray[i + 2] = (byte)readInteger(input);
  277.                                 byteArray[i + 1] = (byte)readInteger(input);
  278.                                 byteArray[i]     = (byte)readInteger(input);
  279.                             }
  280.                         }
  281.                     }
  282.                     break;
  283.                 case DataBuffer.TYPE_USHORT:
  284.                     DataBufferUShort sbuf =
  285.                         (DataBufferUShort)theTile.getDataBuffer();
  286.                     short[] shortArray = sbuf.getData();
  287.                     if (numBands == 1) {
  288.                         for (int i = 0; i < size; i++) {
  289.                             shortArray[i] = (short)readInteger(input);
  290.                         }
  291.                     } else {
  292.                         for (int i = 0; i < size; i += 3) {
  293.                             shortArray[i + 2] = (short)readInteger(input);
  294.                             shortArray[i + 1] = (short)readInteger(input);
  295.                             shortArray[i]     = (short)readInteger(input);
  296.                         }
  297.                     }
  298.                     break;
  299.                 case DataBuffer.TYPE_INT:
  300.                     DataBufferInt ibuf =
  301.                         (DataBufferInt)theTile.getDataBuffer();
  302.                     int[] intArray = ibuf.getData();
  303.                     if (numBands == 1) {
  304.                         for (int i = 0; i < size; i++) {
  305.                             intArray[i] = readInteger(input);
  306.                         }
  307.                     } else {
  308.                         for (int i = 0; i < size; i += 3) {
  309.                             intArray[i + 2] = readInteger(input);
  310.                             intArray[i + 1] = readInteger(input);
  311.                             intArray[i]     = readInteger(input);
  312.                         }
  313.                     }
  314.                     break;
  315.                 }
  316.                 break;
  317.             }
  318.             // Close the PNM stream and release system resources.
  319.             input.close();
  320.         } catch (IOException e) {
  321.             e.printStackTrace();
  322.             throw new RuntimeException(JaiI18N.getString("PNMImageDecoder3"));
  323.         }
  324.         return theTile;
  325.     }
  326.     public synchronized Raster getTile(int tileX, int tileY) {
  327.         if ((tileX != 0) || (tileY != 0)) {
  328.             throw new IllegalArgumentException(JaiI18N.getString("PNMImageDecoder4"));
  329.         }
  330.         return computeTile(tileX, tileY);
  331.     }
  332. }