PNMImageEncoder.java
上传用户:btjssb159
上传日期:2018-01-04
资源大小:241k
文件大小:12k
- /*
- * Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * -Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * -Redistribution in binary form must reproduct the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any kind. ALL
- * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
- * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
- * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
- * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
- * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
- * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
- * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
- * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
- * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that Software is not designed,licensed or intended for use in
- * the design, construction, operation or maintenance of any nuclear facility.
- */
- import java.awt.Rectangle;
- import java.awt.image.ColorModel;
- import java.awt.image.DataBuffer;
- import java.awt.image.IndexColorModel;
- import java.awt.image.Raster;
- import java.awt.image.RenderedImage;
- import java.awt.image.SampleModel;
- import java.io.IOException;
- import java.io.OutputStream;
- /**
- * An ImageEncoder for the PNM family of file formats.
- *
- * <p> The PNM file format includes PBM for monochrome images, PGM for
- * grey scale images, and PPM for color images. When writing the
- * source data out, the encoder chooses the appropriate file variant
- * based on the actual SampleModel of the source image. In case the
- * source image data is unsuitable for the PNM file format, for
- * example when source has 4 bands or float data type, the encoder
- * throws an Error.
- *
- * <p> The raw file format is used wherever possible, unless the
- * PNMEncodeParam object supplied to the constructor returns
- * <code>true</code> from its <code>getRaw()</code> method.
- *
- *
- */
- public class PNMImageEncoder extends ImageEncoderImpl {
- private static final int PBM_ASCII = '1';
- private static final int PGM_ASCII = '2';
- private static final int PPM_ASCII = '3';
- private static final int PBM_RAW = '4';
- private static final int PGM_RAW = '5';
- private static final int PPM_RAW = '6';
- private static final int SPACE = ' ';
- private static final String COMMENT =
- "# written by com.sun.media.jai.codecimpl.PNMImageEncoder";
- private byte[] lineSeparator;
- private int variant;
- private int maxValue;
- public PNMImageEncoder(OutputStream output,
- ImageEncodeParam param) {
- super(output, param);
- if (this.param == null) {
- this.param = new PNMEncodeParam();
- }
- }
- /**
- * Encodes a RenderedImage and writes the output to the
- * OutputStream associated with this ImageEncoder.
- */
- public void encode(RenderedImage im) throws IOException {
- int minX = im.getMinX();
- int minY = im.getMinY();
- int width = im.getWidth();
- int height = im.getHeight();
- SampleModel sampleModel = im.getSampleModel();
- ColorModel colorModel = im.getColorModel();
- String ls = (String)java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction("line.separator"));
- lineSeparator = ls.getBytes();
- int dataType = sampleModel.getTransferType();
- if ((dataType == DataBuffer.TYPE_FLOAT) ||
- (dataType == DataBuffer.TYPE_DOUBLE)) {
- throw new RuntimeException(JaiI18N.getString("PNMImageEncoder0"));
- }
- // Raw data can only handle bytes, everything greater must be ASCII.
- int[] sampleSize = sampleModel.getSampleSize();
- int numBands = sampleModel.getNumBands();
- byte[] reds = null;
- byte[] greens = null;
- byte[] blues = null;
- if (numBands == 1) {
- if (colorModel instanceof IndexColorModel) {
- variant = PPM_RAW;
- IndexColorModel icm = (IndexColorModel)colorModel;
- int mapSize = icm.getMapSize();
- if (mapSize < (1 << sampleSize[0])) {
- throw new RuntimeException(
- JaiI18N.getString("PNMImageEncoder1"));
- }
- reds = new byte[mapSize];
- greens = new byte[mapSize];
- blues = new byte[mapSize];
- icm.getReds(reds);
- icm.getGreens(greens);
- icm.getBlues(blues);
- } else if (sampleSize[0] == 1) {
- variant = PBM_RAW;
- } else if (sampleSize[0] <= 8) {
- variant = PGM_RAW;
- } else {
- variant = PGM_ASCII;
- }
- } else if (numBands == 3) {
- if (sampleSize[0] <= 8 && sampleSize[1] <= 8 &&
- sampleSize[2] <= 8) { // all 3 bands must be <= 8
- variant = PPM_RAW;
- } else {
- variant = PPM_ASCII;
- }
- } else {
- throw new RuntimeException(JaiI18N.getString("PNMImageEncoder2"));
- }
- // Read parameters
- if (((PNMEncodeParam)param).getRaw()) {
- if (!isRaw(variant)) {
- boolean canUseRaw = true;
- // Make sure sampleSize for all bands no greater than 8.
- for (int i = 0; i < sampleSize.length; i++) {
- if (sampleSize[i] > 8) {
- canUseRaw = false;
- break;
- }
- }
- if (canUseRaw) {
- variant += 0x3;
- }
- }
- } else {
- if (isRaw(variant)) {
- variant -= 0x3;
- }
- }
- maxValue = (1 << sampleSize[0]) - 1;
- // Write PNM file.
- output.write('P'); // magic value
- output.write(variant);
-
- output.write(lineSeparator);
- output.write(COMMENT.getBytes()); // comment line
-
- output.write(lineSeparator);
- writeInteger(output, width); // width
- output.write(SPACE);
- writeInteger(output, height); // height
-
- // Writ esample max value for non-binary images
- if ((variant != PBM_RAW) && (variant != PBM_ASCII)) {
- output.write(lineSeparator);
- writeInteger(output, maxValue);
- }
-
- // The spec allows a single character between the
- // last header value and the start of the raw data.
- if (variant == PBM_RAW ||
- variant == PGM_RAW ||
- variant == PPM_RAW) {
- output.write('n');
- }
- // Buffer for up to 8 rows of pixels
- int[] pixels = new int[8*width*numBands];
- // Also allocate a buffer to hold the data to be written to the file,
- // so we can use array writes.
- byte[] bpixels = reds == null ?
- new byte[8*width*numBands] : new byte[8*width*3];
- // The index of the sample being written, used to
- // place a line separator after every 16th sample in
- // ASCII mode. Not used in raw mode.
- int count = 0;
- // Process 8 rows at a time so all but the last will have
- // a multiple of 8 pixels. This simplifies PBM_RAW encoding.
- int lastRow = minY + height;
- for (int row = minY; row < lastRow; row += 8) {
- int rows = Math.min(8, lastRow - row);
- int size = rows*width*numBands;
-
- // Grab the pixels
- Raster src = im.getData(new Rectangle(minX, row, width, rows));
- src.getPixels(minX, row, width, rows, pixels);
-
- switch (variant) {
- case PBM_ASCII:
- case PGM_ASCII:
- for (int i = 0; i < size; i++) {
- if ((count++ % 16) == 0) {
- output.write(lineSeparator);
- } else {
- output.write(SPACE);
- }
- writeInteger(output, pixels[i]);
- }
- output.write(lineSeparator);
- break;
- case PPM_ASCII:
- if (reds == null) { // no need to expand
- for (int i = 0; i < size; i++) {
- if ((count++ % 16) == 0) {
- output.write(lineSeparator);
- } else {
- output.write(SPACE);
- }
- writeInteger(output, pixels[i]);
- }
- } else {
- for (int i = 0; i < size; i++) {
- if ((count++ % 16) == 0) {
- output.write(lineSeparator);
- } else {
- output.write(SPACE);
- }
- writeInteger(output, (reds[pixels[i]] & 0xFF));
- output.write(SPACE);
- writeInteger(output, (greens[pixels[i]] & 0xFF));
- output.write(SPACE);
- writeInteger(output, (blues[pixels[i]] & 0xFF));
- }
- }
- output.write(lineSeparator);
- break;
-
- case PBM_RAW:
- // 8 pixels packed into 1 byte, the leftovers are padded.
- int kdst = 0;
- int ksrc = 0;
- for (int i = 0; i < size/8; i++) {
- int b = (pixels[ksrc++] << 7) |
- (pixels[ksrc++] << 6) |
- (pixels[ksrc++] << 5) |
- (pixels[ksrc++] << 4) |
- (pixels[ksrc++] << 3) |
- (pixels[ksrc++] << 2) |
- (pixels[ksrc++] << 1) |
- pixels[ksrc++];
- bpixels[kdst++] = (byte)b;
- }
-
- // Leftover pixels, only possible at the end of the file.
- if (size%8 > 0) {
- int b = 0;
- for (int i=0; i<size%8; i++) {
- b |= pixels[size + i] << (7 - i);
- }
- bpixels[kdst++] = (byte)b;
- }
- output.write(bpixels, 0, (size+7)/8);
- break;
-
- case PGM_RAW:
- for(int i=0; i<size; i++) {
- bpixels[i] = (byte)(pixels[i]);
- }
- output.write(bpixels, 0, size);
- break;
- case PPM_RAW:
- if (reds == null) { // no need to expand
- for (int i=0; i<size; i++) {
- bpixels[i] = (byte)(pixels[i] & 0xFF);
- }
- } else {
- for (int i=0, j=0; i<size; i++) {
- bpixels[j++] = reds[pixels[i]];
- bpixels[j++] = greens[pixels[i]];
- bpixels[j++] = blues[pixels[i]];
- }
- }
- output.write(bpixels, 0, bpixels.length);
- break;
- }
- }
-
- // Force all buffered bytes to be written out.
- output.flush();
- }
- /** Writes an integer to the output in ASCII format. */
- private void writeInteger(OutputStream output, int i) throws IOException {
- output.write(Integer.toString(i).getBytes());
- }
- /** Writes a byte to the output in ASCII format. */
- private void writeByte(OutputStream output, byte b) throws IOException {
- output.write(Byte.toString(b).getBytes());
- }
- /** Returns true if file variant is raw format, false if ASCII. */
- private boolean isRaw(int v) {
- return (v >= PBM_RAW);
- }
- }