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

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.Rectangle;
  34. import java.awt.image.ColorModel;
  35. import java.awt.image.DataBuffer;
  36. import java.awt.image.IndexColorModel;
  37. import java.awt.image.Raster;
  38. import java.awt.image.RenderedImage;
  39. import java.awt.image.SampleModel;
  40. import java.io.IOException;
  41. import java.io.OutputStream;
  42. /**
  43.  * An ImageEncoder for the PNM family of file formats.
  44.  *
  45.  * <p> The PNM file format includes PBM for monochrome images, PGM for
  46.  * grey scale images, and PPM for color images. When writing the
  47.  * source data out, the encoder chooses the appropriate file variant
  48.  * based on the actual SampleModel of the source image. In case the
  49.  * source image data is unsuitable for the PNM file format, for
  50.  * example when source has 4 bands or float data type, the encoder
  51.  * throws an Error.
  52.  *
  53.  * <p> The raw file format is used wherever possible, unless the
  54.  * PNMEncodeParam object supplied to the constructor returns
  55.  * <code>true</code> from its <code>getRaw()</code> method.
  56.  *
  57.  *
  58.  */
  59. public class PNMImageEncoder extends ImageEncoderImpl {
  60.     private static final int PBM_ASCII  = '1';
  61.     private static final int PGM_ASCII  = '2';
  62.     private static final int PPM_ASCII  = '3';
  63.     private static final int PBM_RAW    = '4';
  64.     private static final int PGM_RAW    = '5';
  65.     private static final int PPM_RAW    = '6';
  66.     private static final int SPACE      = ' ';
  67.     private static final String COMMENT = 
  68.         "# written by com.sun.media.jai.codecimpl.PNMImageEncoder";
  69.     private byte[] lineSeparator;
  70.     private int variant;
  71.     private int maxValue;
  72.     public PNMImageEncoder(OutputStream output,
  73.                            ImageEncodeParam param) {
  74.         super(output, param);
  75.         if (this.param == null) {
  76.             this.param = new PNMEncodeParam();
  77.         }
  78.     }
  79.     /**
  80.      * Encodes a RenderedImage and writes the output to the
  81.      * OutputStream associated with this ImageEncoder.
  82.      */
  83.     public void encode(RenderedImage im) throws IOException {
  84.         int minX = im.getMinX();
  85.         int minY = im.getMinY();
  86.         int width = im.getWidth();
  87.         int height = im.getHeight();
  88.         SampleModel sampleModel = im.getSampleModel();
  89.         ColorModel colorModel = im.getColorModel();
  90.         String ls = (String)java.security.AccessController.doPrivileged(
  91.                new sun.security.action.GetPropertyAction("line.separator"));
  92.         lineSeparator = ls.getBytes();
  93.         int dataType = sampleModel.getTransferType();
  94.         if ((dataType == DataBuffer.TYPE_FLOAT) ||
  95.             (dataType == DataBuffer.TYPE_DOUBLE)) {
  96.             throw new RuntimeException(JaiI18N.getString("PNMImageEncoder0"));
  97.         }
  98.         // Raw data can only handle bytes, everything greater must be ASCII.
  99.         int[] sampleSize = sampleModel.getSampleSize();
  100.         int numBands = sampleModel.getNumBands();
  101.         byte[] reds = null;
  102.         byte[] greens = null;
  103.         byte[] blues = null;
  104.         if (numBands == 1) {
  105.             if (colorModel instanceof IndexColorModel) {
  106.                 variant = PPM_RAW;
  107.                 IndexColorModel icm = (IndexColorModel)colorModel;
  108.                 int mapSize = icm.getMapSize();
  109.                 if (mapSize < (1 << sampleSize[0])) {
  110.                     throw new RuntimeException(
  111.                         JaiI18N.getString("PNMImageEncoder1"));
  112.                 }
  113.                 reds = new byte[mapSize];
  114.                 greens = new byte[mapSize];
  115.                 blues = new byte[mapSize];
  116.                 icm.getReds(reds);
  117.                 icm.getGreens(greens);
  118.                 icm.getBlues(blues);
  119.             } else if (sampleSize[0] == 1) {
  120.                 variant = PBM_RAW;
  121.             } else if (sampleSize[0] <= 8) {
  122.                 variant = PGM_RAW;
  123.             } else {
  124.                 variant = PGM_ASCII;
  125.             }
  126.         } else if (numBands == 3) {
  127.             if (sampleSize[0] <= 8 && sampleSize[1] <= 8 &&
  128.                 sampleSize[2] <= 8) { // all 3 bands must be <= 8
  129.                 variant = PPM_RAW;
  130.             } else {
  131.                 variant = PPM_ASCII;
  132.             }
  133.         } else {
  134.             throw new RuntimeException(JaiI18N.getString("PNMImageEncoder2"));
  135.         }
  136.         // Read parameters
  137.         if (((PNMEncodeParam)param).getRaw()) {
  138.             if (!isRaw(variant)) {
  139.                 boolean canUseRaw = true;
  140.                 // Make sure sampleSize for all bands no greater than 8.
  141.                 for (int i = 0; i < sampleSize.length; i++) {
  142.                     if (sampleSize[i] > 8) {
  143.                         canUseRaw = false;
  144.                         break;
  145.                     }
  146.                 }
  147.                 if (canUseRaw) {
  148.                     variant += 0x3;
  149.                 }
  150.             }
  151.         } else {
  152.             if (isRaw(variant)) {
  153.                 variant -= 0x3;
  154.             }
  155.         }
  156.         maxValue = (1 << sampleSize[0]) - 1;
  157.         // Write PNM file.
  158.         output.write('P'); // magic value
  159.         output.write(variant);
  160.         
  161.         output.write(lineSeparator);
  162.         output.write(COMMENT.getBytes()); // comment line
  163.         
  164.         output.write(lineSeparator);
  165.         writeInteger(output, width); // width
  166.         output.write(SPACE);
  167.         writeInteger(output, height); // height
  168.         
  169.         // Writ esample max value for non-binary images
  170.         if ((variant != PBM_RAW) && (variant != PBM_ASCII)) {
  171.             output.write(lineSeparator);
  172.             writeInteger(output, maxValue);
  173.         }
  174.         
  175.         // The spec allows a single character between the
  176.         // last header value and the start of the raw data.
  177.         if (variant == PBM_RAW ||
  178.             variant == PGM_RAW ||
  179.             variant == PPM_RAW) {
  180.             output.write('n');
  181.         }
  182.         // Buffer for up to 8 rows of pixels
  183.         int[] pixels = new int[8*width*numBands];
  184.         // Also allocate a buffer to hold the data to be written to the file,
  185.         // so we can use array writes.
  186.         byte[] bpixels = reds == null ?
  187.                          new byte[8*width*numBands] : new byte[8*width*3];
  188.         // The index of the sample being written, used to
  189.         // place a line separator after every 16th sample in
  190.         // ASCII mode.  Not used in raw mode.
  191.         int count = 0;
  192.         // Process 8 rows at a time so all but the last will have
  193.         // a multiple of 8 pixels.  This simplifies PBM_RAW encoding.
  194.         int lastRow = minY + height;
  195.         for (int row = minY; row < lastRow; row += 8) {
  196.             int rows = Math.min(8, lastRow - row);
  197.             int size = rows*width*numBands;
  198.             
  199.             // Grab the pixels
  200.             Raster src = im.getData(new Rectangle(minX, row, width, rows));
  201.             src.getPixels(minX, row, width, rows, pixels);
  202.         
  203.             switch (variant) {
  204.             case PBM_ASCII:
  205.             case PGM_ASCII:
  206.                 for (int i = 0; i < size; i++) {
  207.                     if ((count++ % 16) == 0) {
  208.                         output.write(lineSeparator);
  209.                     } else {
  210.                         output.write(SPACE);
  211.                     }
  212.                     writeInteger(output, pixels[i]);
  213.                 }
  214.                 output.write(lineSeparator);
  215.                 break;
  216.             case PPM_ASCII:
  217.                 if (reds == null) { // no need to expand
  218.                     for (int i = 0; i < size; i++) {
  219.                         if ((count++ % 16) == 0) {
  220.                             output.write(lineSeparator);
  221.                         } else {
  222.                             output.write(SPACE);
  223.                         }
  224.                         writeInteger(output, pixels[i]);
  225.                     }
  226.                 } else {
  227.                     for (int i = 0; i < size; i++) {
  228.                         if ((count++ % 16) == 0) {
  229.                             output.write(lineSeparator);
  230.                         } else {
  231.                             output.write(SPACE);
  232.                         }
  233.                         writeInteger(output, (reds[pixels[i]] & 0xFF));
  234.                         output.write(SPACE);
  235.                         writeInteger(output, (greens[pixels[i]] & 0xFF));
  236.                         output.write(SPACE);
  237.                         writeInteger(output, (blues[pixels[i]] & 0xFF));
  238.                     }
  239.                 }
  240.                 output.write(lineSeparator);
  241.                 break;
  242.             
  243.             case PBM_RAW:
  244.                 // 8 pixels packed into 1 byte, the leftovers are padded.
  245.                 int kdst = 0;
  246.                 int ksrc = 0;
  247.                 for (int i = 0; i < size/8; i++) {
  248.                     int b = (pixels[ksrc++] << 7) |
  249.                             (pixels[ksrc++] << 6) |
  250.                             (pixels[ksrc++] << 5) |
  251.                             (pixels[ksrc++] << 4) |
  252.                             (pixels[ksrc++] << 3) |
  253.                             (pixels[ksrc++] << 2) |
  254.                             (pixels[ksrc++] << 1) |
  255.                              pixels[ksrc++];
  256.                     bpixels[kdst++] = (byte)b;
  257.                 }
  258.             
  259.                 // Leftover pixels, only possible at the end of the file.
  260.                 if (size%8 > 0) {
  261.                     int b = 0;
  262.                     for (int i=0; i<size%8; i++) {
  263.                         b |= pixels[size + i] << (7 - i);
  264.                     }
  265.                     bpixels[kdst++] = (byte)b;
  266.                 }
  267.                 output.write(bpixels, 0, (size+7)/8);
  268.                 break;
  269.                 
  270.             case PGM_RAW:
  271.                 for(int i=0; i<size; i++) {
  272.                     bpixels[i] = (byte)(pixels[i]);
  273.                 }
  274.                 output.write(bpixels, 0, size);
  275.                 break;
  276.             case PPM_RAW:
  277.                 if (reds == null) { // no need to expand
  278.                     for (int i=0; i<size; i++) {
  279.                         bpixels[i] = (byte)(pixels[i] & 0xFF);
  280.                     }
  281.                 } else {
  282.                     for (int i=0, j=0; i<size; i++) {
  283.                         bpixels[j++] = reds[pixels[i]];
  284.                         bpixels[j++] = greens[pixels[i]];
  285.                         bpixels[j++] = blues[pixels[i]];
  286.                     }
  287.                 }
  288.                 output.write(bpixels, 0, bpixels.length);
  289.                 break;
  290.             }
  291.         }
  292.         
  293.         // Force all buffered bytes to be written out.
  294.         output.flush();
  295.     }
  296.     /** Writes an integer to the output in ASCII format. */
  297.     private void writeInteger(OutputStream output, int i) throws IOException {
  298.         output.write(Integer.toString(i).getBytes());
  299.     }
  300.     /** Writes a byte to the output in ASCII format. */
  301.     private void writeByte(OutputStream output, byte b) throws IOException {
  302.         output.write(Byte.toString(b).getBytes());
  303.     }
  304.     /** Returns true if file variant is raw format, false if ASCII. */
  305.     private boolean isRaw(int v) {
  306.         return (v >= PBM_RAW);
  307.     }
  308. }