Search in sources :

Example 1 with PNMImageWriteParam

use of com.sun.media.imageio.plugins.pnm.PNMImageWriteParam in project imageio-ext by geosolutions-it.

the class PNMImageWriter method write.

public void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) throws IOException {
    clearAbortRequest();
    processImageStarted(0);
    if (param == null)
        param = getDefaultWriteParam();
    RenderedImage input = null;
    Raster inputRaster = null;
    boolean writeRaster = image.hasRaster();
    Rectangle sourceRegion = param.getSourceRegion();
    SampleModel sampleModel = null;
    ColorModel colorModel = null;
    if (writeRaster) {
        inputRaster = image.getRaster();
        sampleModel = inputRaster.getSampleModel();
        if (sourceRegion == null)
            sourceRegion = inputRaster.getBounds();
        else
            sourceRegion = sourceRegion.intersection(inputRaster.getBounds());
    } else {
        input = image.getRenderedImage();
        sampleModel = input.getSampleModel();
        colorModel = input.getColorModel();
        Rectangle rect = new Rectangle(input.getMinX(), input.getMinY(), input.getWidth(), input.getHeight());
        if (sourceRegion == null)
            sourceRegion = rect;
        else
            sourceRegion = sourceRegion.intersection(rect);
    }
    if (sourceRegion.isEmpty())
        throw new RuntimeException(I18N.getString("PNMImageWrite1"));
    ImageUtil.canEncodeImage(this, colorModel, sampleModel);
    int scaleX = param.getSourceXSubsampling();
    int scaleY = param.getSourceYSubsampling();
    int xOffset = param.getSubsamplingXOffset();
    int yOffset = param.getSubsamplingYOffset();
    sourceRegion.translate(xOffset, yOffset);
    sourceRegion.width -= xOffset;
    sourceRegion.height -= yOffset;
    int w = (sourceRegion.width + scaleX - 1) / scaleX;
    int h = (sourceRegion.height + scaleY - 1) / scaleY;
    int tileWidth = sampleModel.getWidth();
    // Raw data can only handle bytes, everything greater must be ASCII.
    int[] sampleSize = sampleModel.getSampleSize();
    int[] sourceBands = param.getSourceBands();
    int numBands = sampleModel.getNumBands();
    if (sourceBands != null) {
        sampleModel = sampleModel.createSubsetSampleModel(sourceBands);
        colorModel = null;
        numBands = sampleModel.getNumBands();
    } else {
        sourceBands = new int[numBands];
        for (int i = 0; i < numBands; i++) sourceBands[i] = i;
    }
    // Colormap populated for non-bilevel IndexColorModel only.
    byte[] reds = null;
    byte[] greens = null;
    byte[] blues = null;
    // Flag indicating that PB data should be inverted before writing.
    boolean isPBMInverted = false;
    if (numBands == 1) {
        if (colorModel instanceof IndexColorModel) {
            IndexColorModel icm = (IndexColorModel) colorModel;
            int mapSize = icm.getMapSize();
            if (mapSize < (1 << sampleSize[0]))
                throw new RuntimeException(I18N.getString("PNMImageWrite2"));
            if (sampleSize[0] == 1) {
                variant = PBM_RAW;
                // Set PBM inversion flag if 1 maps to a higher color
                // value than 0: PBM expects white-is-zero so if this
                // does not obtain then inversion needs to occur.
                isPBMInverted = icm.getRed(1) > icm.getRed(0);
            } else {
                variant = PPM_RAW;
                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(I18N.getString("PNMImageWrite3"));
    }
    IIOMetadata inputMetadata = image.getMetadata();
    ImageTypeSpecifier imageType;
    if (colorModel != null) {
        imageType = new ImageTypeSpecifier(colorModel, sampleModel);
    } else {
        int dataType = sampleModel.getDataType();
        switch(numBands) {
            case 1:
                imageType = ImageTypeSpecifier.createGrayscale(sampleSize[0], dataType, false);
                break;
            case 3:
                ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
                imageType = ImageTypeSpecifier.createInterleaved(cs, new int[] { 0, 1, 2 }, dataType, false, false);
                break;
            default:
                throw new IIOException("Cannot encode image with " + numBands + " bands!");
        }
    }
    PNMMetadata metadata;
    if (inputMetadata != null) {
        // Convert metadata.
        metadata = (PNMMetadata) convertImageMetadata(inputMetadata, imageType, param);
    } else {
        // Use default.
        metadata = (PNMMetadata) getDefaultImageMetadata(imageType, param);
    }
    // Read parameters
    boolean isRawPNM;
    if (param instanceof PNMImageWriteParam) {
        isRawPNM = ((PNMImageWriteParam) param).getRaw();
    } else {
        isRawPNM = metadata.isRaw();
    }
    maxValue = metadata.getMaxValue();
    for (int i = 0; i < sampleSize.length; i++) {
        int v = (1 << sampleSize[i]) - 1;
        if (v > maxValue) {
            maxValue = v;
        }
    }
    if (isRawPNM) {
        // Raw output is desired.
        int maxBitDepth = metadata.getMaxBitDepth();
        if (!isRaw(variant) && maxBitDepth <= 8) {
            // Current variant is ASCII and the bit depth is acceptable
            // so convert to RAW variant by adding '3' to variant.
            variant += 0x3;
        } else if (isRaw(variant) && maxBitDepth > 8) {
            // Current variant is RAW and the bit depth it too large for
            // RAW so convert to ASCII.
            variant -= 0x3;
        }
    // Omitted cases are (variant == RAW && max <= 8) and
    // (variant == ASCII && max > 8) neither of which requires action.
    } else if (isRaw(variant)) {
        // Raw output is NOT desired so convert to ASCII
        variant -= 0x3;
    }
    // Write PNM file.
    // magic value: 'P'
    stream.writeByte('P');
    stream.writeByte(variant);
    stream.write(lineSeparator);
    // comment line
    stream.write(COMMENT.getBytes());
    // Write the comments provided in the metadata
    Iterator comments = metadata.getComments();
    if (comments != null) {
        while (comments.hasNext()) {
            stream.write(lineSeparator);
            String comment = "# " + (String) comments.next();
            stream.write(comment.getBytes());
        }
    }
    stream.write(lineSeparator);
    // width
    writeInteger(stream, w);
    stream.write(SPACE);
    // height
    writeInteger(stream, h);
    // Write sample max value for non-binary images
    if ((variant != PBM_RAW) && (variant != PBM_ASCII)) {
        stream.write(lineSeparator);
        writeInteger(stream, maxValue);
    }
    // last header value and the start of the raw data.
    if (variant == PBM_RAW || variant == PGM_RAW || variant == PPM_RAW) {
        stream.write('\n');
    }
    // Set flag for optimal image writing case: row-packed data with
    // correct band order if applicable.
    boolean writeOptimal = false;
    if (variant == PBM_RAW && sampleModel.getTransferType() == DataBuffer.TYPE_BYTE && sampleModel instanceof MultiPixelPackedSampleModel) {
        MultiPixelPackedSampleModel mppsm = (MultiPixelPackedSampleModel) sampleModel;
        int originX = 0;
        if (writeRaster)
            originX = inputRaster.getMinX();
        else
            originX = input.getMinX();
        // Must have left-aligned bytes with unity bit stride.
        if (mppsm.getBitOffset((sourceRegion.x - originX) % tileWidth) == 0 && mppsm.getPixelBitStride() == 1 && scaleX == 1)
            writeOptimal = true;
    } else if ((variant == PGM_RAW || variant == PPM_RAW) && sampleModel instanceof ComponentSampleModel && !(colorModel instanceof IndexColorModel)) {
        ComponentSampleModel csm = (ComponentSampleModel) sampleModel;
        // Pixel stride must equal band count.
        if (csm.getPixelStride() == numBands && scaleX == 1) {
            writeOptimal = true;
            // Band offsets must equal band indices.
            if (variant == PPM_RAW) {
                int[] bandOffsets = csm.getBandOffsets();
                for (int b = 0; b < numBands; b++) {
                    if (bandOffsets[b] != b) {
                        writeOptimal = false;
                        break;
                    }
                }
            }
        }
    }
    // Write using an optimal approach if possible.
    if (writeOptimal) {
        int bytesPerRow = variant == PBM_RAW ? (w + 7) / 8 : w * sampleModel.getNumBands();
        byte[] bdata = null;
        byte[] invertedData = new byte[bytesPerRow];
        // Loop over tiles to minimize cobbling.
        for (int j = 0; j < sourceRegion.height; j++) {
            if (abortRequested())
                break;
            Raster lineRaster = null;
            if (writeRaster) {
                lineRaster = inputRaster.createChild(sourceRegion.x, j, sourceRegion.width, 1, 0, 0, null);
            } else {
                lineRaster = input.getData(new Rectangle(sourceRegion.x, sourceRegion.y + j, w, 1));
                lineRaster = lineRaster.createTranslatedChild(0, 0);
            }
            bdata = ((DataBufferByte) lineRaster.getDataBuffer()).getData();
            sampleModel = lineRaster.getSampleModel();
            int offset = 0;
            if (sampleModel instanceof ComponentSampleModel) {
                offset = ((ComponentSampleModel) sampleModel).getOffset(lineRaster.getMinX() - lineRaster.getSampleModelTranslateX(), lineRaster.getMinY() - lineRaster.getSampleModelTranslateY());
            } else if (sampleModel instanceof MultiPixelPackedSampleModel) {
                offset = ((MultiPixelPackedSampleModel) sampleModel).getOffset(lineRaster.getMinX() - lineRaster.getSampleModelTranslateX(), lineRaster.getMinX() - lineRaster.getSampleModelTranslateY());
            }
            if (isPBMInverted) {
                for (int k = offset, m = 0; m < bytesPerRow; k++, m++) invertedData[m] = (byte) ~bdata[k];
                bdata = invertedData;
                offset = 0;
            }
            stream.write(bdata, offset, bytesPerRow);
            processImageProgress(100.0F * j / sourceRegion.height);
        }
        // Write all buffered bytes and return.
        stream.flush();
        if (abortRequested())
            processWriteAborted();
        else
            processImageComplete();
        return;
    }
    // Buffer for 1 rows of original pixels
    int size = sourceRegion.width * numBands;
    int[] pixels = new int[size];
    // 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[w * numBands] : new byte[w * 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 line by line
    int lastRow = sourceRegion.y + sourceRegion.height;
    for (int row = sourceRegion.y; row < lastRow; row += scaleY) {
        if (abortRequested())
            break;
        // Grab the pixels
        Raster src = null;
        if (writeRaster)
            src = inputRaster.createChild(sourceRegion.x, row, sourceRegion.width, 1, sourceRegion.x, row, sourceBands);
        else
            src = input.getData(new Rectangle(sourceRegion.x, row, sourceRegion.width, 1));
        src.getPixels(sourceRegion.x, row, sourceRegion.width, 1, pixels);
        if (isPBMInverted)
            for (int i = 0; i < size; i += scaleX) bpixels[i] ^= 1;
        switch(variant) {
            case PBM_ASCII:
                for (int i = 0; i < size; i += scaleX) {
                    if ((count++ % 16) == 0)
                        stream.write(lineSeparator);
                    else
                        stream.write(SPACE);
                    writeInteger(stream, isPBMInverted ? (byte) ~pixels[i] : pixels[i]);
                }
                stream.write(lineSeparator);
                break;
            case PGM_ASCII:
                for (int i = 0; i < size; i += scaleX) {
                    if ((count++ % 16) == 0)
                        stream.write(lineSeparator);
                    else
                        stream.write(SPACE);
                    writeInteger(stream, pixels[i]);
                }
                stream.write(lineSeparator);
                break;
            case PPM_ASCII:
                if (reds == null) {
                    for (int i = 0; i < size; i += scaleX * numBands) {
                        for (int j = 0; j < numBands; j++) {
                            if ((count++ % 16) == 0)
                                stream.write(lineSeparator);
                            else
                                stream.write(SPACE);
                            writeInteger(stream, pixels[i + j]);
                        }
                    }
                } else {
                    for (int i = 0; i < size; i += scaleX) {
                        if ((count++ % 5) == 0)
                            stream.write(lineSeparator);
                        else
                            stream.write(SPACE);
                        writeInteger(stream, (reds[pixels[i]] & 0xFF));
                        stream.write(SPACE);
                        writeInteger(stream, (greens[pixels[i]] & 0xFF));
                        stream.write(SPACE);
                        writeInteger(stream, (blues[pixels[i]] & 0xFF));
                    }
                }
                stream.write(lineSeparator);
                break;
            case PBM_RAW:
                // 8 pixels packed into 1 byte, the leftovers are padded.
                int kdst = 0;
                int b = 0;
                int pos = 7;
                for (int i = 0; i < size; i += scaleX) {
                    b |= pixels[i] << pos;
                    pos--;
                    if (pos == -1) {
                        bpixels[kdst++] = (byte) b;
                        b = 0;
                        pos = 7;
                    }
                }
                if (pos != 7)
                    bpixels[kdst++] = (byte) b;
                stream.write(bpixels, 0, kdst);
                break;
            case PGM_RAW:
                for (int i = 0, j = 0; i < size; i += scaleX) {
                    bpixels[j++] = (byte) (pixels[i]);
                }
                stream.write(bpixels, 0, w);
                break;
            case PPM_RAW:
                if (reds == null) {
                    // no need to expand
                    for (int i = 0, k = 0; i < size; i += scaleX * numBands) {
                        for (int j = 0; j < numBands; j++) bpixels[k++] = (byte) (pixels[i + j] & 0xFF);
                    }
                } else {
                    for (int i = 0, j = 0; i < size; i += scaleX) {
                        bpixels[j++] = reds[pixels[i]];
                        bpixels[j++] = greens[pixels[i]];
                        bpixels[j++] = blues[pixels[i]];
                    }
                }
                stream.write(bpixels, 0, bpixels.length);
                break;
        }
        processImageProgress(100.0F * (row - sourceRegion.y) / sourceRegion.height);
    }
    // Force all buffered bytes to be written out.
    stream.flush();
    if (abortRequested())
        processWriteAborted();
    else
        processImageComplete();
}
Also used : ColorSpace(java.awt.color.ColorSpace) Raster(java.awt.image.Raster) PNMImageWriteParam(com.sun.media.imageio.plugins.pnm.PNMImageWriteParam) Rectangle(java.awt.Rectangle) MultiPixelPackedSampleModel(java.awt.image.MultiPixelPackedSampleModel) IIOException(javax.imageio.IIOException) ComponentSampleModel(java.awt.image.ComponentSampleModel) ImageTypeSpecifier(javax.imageio.ImageTypeSpecifier) IIOMetadata(javax.imageio.metadata.IIOMetadata) ComponentSampleModel(java.awt.image.ComponentSampleModel) SampleModel(java.awt.image.SampleModel) MultiPixelPackedSampleModel(java.awt.image.MultiPixelPackedSampleModel) ColorModel(java.awt.image.ColorModel) IndexColorModel(java.awt.image.IndexColorModel) Iterator(java.util.Iterator) RenderedImage(java.awt.image.RenderedImage) IndexColorModel(java.awt.image.IndexColorModel)

Example 2 with PNMImageWriteParam

use of com.sun.media.imageio.plugins.pnm.PNMImageWriteParam in project imageio-ext by geosolutions-it.

the class PNMMetadata method initialize.

void initialize(ImageTypeSpecifier imageType, ImageWriteParam param) {
    ImageTypeSpecifier destType = null;
    if (param != null) {
        destType = param.getDestinationType();
        if (destType == null) {
            destType = imageType;
        }
    } else {
        destType = imageType;
    }
    if (destType != null) {
        SampleModel sm = destType.getSampleModel();
        int[] sampleSize = sm.getSampleSize();
        this.width = sm.getWidth();
        this.height = sm.getHeight();
        for (int i = 0; i < sampleSize.length; i++) {
            if (sampleSize[i] > maxSampleSize) {
                maxSampleSize = sampleSize[i];
            }
        }
        this.maxSample = (1 << maxSampleSize) - 1;
        // default value
        boolean isRaw = true;
        if (param instanceof PNMImageWriteParam) {
            isRaw = ((PNMImageWriteParam) param).getRaw();
        }
        if (maxSampleSize == 1)
            variant = '1';
        else if (sm.getNumBands() == 1) {
            variant = '2';
        } else if (sm.getNumBands() == 3) {
            variant = '3';
        }
        // Force to Raw if the sample size is small enough.
        if (variant <= '3' && isRaw && maxSampleSize <= 8) {
            variant += 0x3;
        }
    }
}
Also used : SampleModel(java.awt.image.SampleModel) PNMImageWriteParam(com.sun.media.imageio.plugins.pnm.PNMImageWriteParam) ImageTypeSpecifier(javax.imageio.ImageTypeSpecifier)

Aggregations

PNMImageWriteParam (com.sun.media.imageio.plugins.pnm.PNMImageWriteParam)2 SampleModel (java.awt.image.SampleModel)2 ImageTypeSpecifier (javax.imageio.ImageTypeSpecifier)2 Rectangle (java.awt.Rectangle)1 ColorSpace (java.awt.color.ColorSpace)1 ColorModel (java.awt.image.ColorModel)1 ComponentSampleModel (java.awt.image.ComponentSampleModel)1 IndexColorModel (java.awt.image.IndexColorModel)1 MultiPixelPackedSampleModel (java.awt.image.MultiPixelPackedSampleModel)1 Raster (java.awt.image.Raster)1 RenderedImage (java.awt.image.RenderedImage)1 Iterator (java.util.Iterator)1 IIOException (javax.imageio.IIOException)1 IIOMetadata (javax.imageio.metadata.IIOMetadata)1