All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.luciad.imageio.webp.WebPWriter Maven / Gradle / Ivy

There is a newer version: 2.5.8
Show newest version
package com.luciad.imageio.webp;

import javax.imageio.IIOImage;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.ComponentSampleModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.DirectColorModel;
import java.awt.image.RenderedImage;
import java.awt.image.SinglePixelPackedSampleModel;
import java.io.IOException;

class WebPWriter extends ImageWriter {

    WebPWriter(ImageWriterSpi originatingProvider) {
        super(originatingProvider);
    }

    @Override
    public ImageWriteParam getDefaultWriteParam() {
        return new WebPWriteParam(getLocale());
    }

    @Override
    public IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param) {
        return null;
    }

    @Override
    public IIOMetadata convertStreamMetadata(IIOMetadata inData, ImageWriteParam param) {
        return null;
    }

    @Override
    public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, ImageWriteParam param) {
        return null;
    }

    @Override
    public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) {
        return null;
    }

    @Override
    public void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) throws IOException {
        if (param == null) {
            param = getDefaultWriteParam();
        }

        WebPWriteParam writeParam = (WebPWriteParam) param;

        ImageOutputStream output = (ImageOutputStream) getOutput();
        RenderedImage ri = image.getRenderedImage();

        byte[] encodedData = encode(writeParam.getEncoderOptions(), ri);
        output.write(encodedData);
    }

    private static byte[] encode(WebPEncoderOptions aOptions, RenderedImage aImage) throws IOException {
        if (aOptions == null) {
            throw new NullPointerException("Encoder options may not be null");
        }

        if (aImage == null) {
            throw new NullPointerException("Image may not be null");
        }

        boolean encodeAlpha = hasTranslucency(aImage);
        if (encodeAlpha) {
            byte[] rgbaData = getRGBA(aImage);
            return WebP.encodeRGBA(aOptions, rgbaData, aImage.getWidth(), aImage.getHeight(), aImage.getWidth() * 4);
        } else {
            byte[] rgbData = getRGB(aImage);
            return WebP.encodeRGB(aOptions, rgbData, aImage.getWidth(), aImage.getHeight(), aImage.getWidth() * 3);
        }
    }

    private static boolean hasTranslucency(RenderedImage aRi) {
        return aRi.getColorModel().hasAlpha();
    }

    private static int getShift(int aMask) {
        int shift = 0;
        while (((aMask >> shift) & 0x1) == 0) {
            shift++;
        }
        return shift;
    }

    private static byte[] getRGB(RenderedImage aRi) throws IOException {
        int width = aRi.getWidth();
        int height = aRi.getHeight();

        ColorModel colorModel = aRi.getColorModel();
        if (colorModel instanceof ComponentColorModel) {
            ComponentSampleModel sampleModel = (ComponentSampleModel) aRi.getSampleModel();
            int type = sampleModel.getTransferType();
            if (type == DataBuffer.TYPE_BYTE) {
                return extractComponentRGBByte(width, height, sampleModel, ((DataBufferByte) aRi.getData().getDataBuffer()));
            } else if (type == DataBuffer.TYPE_INT) {
                return extractComponentRGBInt(width, height, sampleModel, ((DataBufferInt) aRi.getData().getDataBuffer()));
            } else {
                throw new IOException("Incompatible image: " + aRi);
            }
        } else if (colorModel instanceof DirectColorModel) {
            SinglePixelPackedSampleModel sampleModel = (SinglePixelPackedSampleModel) aRi.getSampleModel();
            int type = sampleModel.getTransferType();
            if (type == DataBuffer.TYPE_INT) {
                return extractDirectRGBInt(width, height, (DirectColorModel) colorModel, sampleModel, ((DataBufferInt) aRi.getData().getDataBuffer()));
            } else {
                throw new IOException("Incompatible image: " + aRi);
            }
        } else {
            BufferedImage i = new BufferedImage(aRi.getWidth(), aRi.getHeight(), BufferedImage.TYPE_INT_RGB);
            Graphics2D g = i.createGraphics();
            g.drawRenderedImage(aRi, new AffineTransform());
            g.dispose();
            return getRGB(i);
        }
    }

    private static byte[] extractDirectRGBInt(int aWidth, int aHeight, DirectColorModel aColorModel, SinglePixelPackedSampleModel aSampleModel, DataBufferInt aDataBuffer) {
        byte[] out = new byte[aWidth * aHeight * 3];

        int rMask = aColorModel.getRedMask();
        int gMask = aColorModel.getGreenMask();
        int bMask = aColorModel.getBlueMask();
        int rShift = getShift(rMask);
        int gShift = getShift(gMask);
        int bShift = getShift(bMask);
        int[] bank = aDataBuffer.getBankData()[0];
        int scanlineStride = aSampleModel.getScanlineStride();
        int scanIx = 0;
        for (int b = 0, y = 0; y < aHeight; y++) {
            int pixIx = scanIx;
            for (int x = 0; x < aWidth; x++, b += 3) {
                int pixel = bank[pixIx++];
                out[b] = (byte) ((pixel & rMask) >>> rShift);
                out[b + 1] = (byte) ((pixel & gMask) >>> gShift);
                out[b + 2] = (byte) ((pixel & bMask) >>> bShift);
            }
            scanIx += scanlineStride;
        }
        return out;
    }

    private static byte[] extractComponentRGBInt(int aWidth, int aHeight, ComponentSampleModel aSampleModel, DataBufferInt aDataBuffer) {
        byte[] out = new byte[aWidth * aHeight * 3];

        int[] bankIndices = aSampleModel.getBankIndices();
        int[] rBank = aDataBuffer.getBankData()[bankIndices[0]];
        int[] gBank = aDataBuffer.getBankData()[bankIndices[1]];
        int[] bBank = aDataBuffer.getBankData()[bankIndices[2]];

        int[] bankOffsets = aSampleModel.getBandOffsets();
        int rScanIx = bankOffsets[0];
        int gScanIx = bankOffsets[1];
        int bScanIx = bankOffsets[2];

        int pixelStride = aSampleModel.getPixelStride();
        int scanlineStride = aSampleModel.getScanlineStride();
        for (int b = 0, y = 0; y < aHeight; y++) {
            int rPixIx = rScanIx;
            int gPixIx = gScanIx;
            int bPixIx = bScanIx;
            for (int x = 0; x < aWidth; x++, b += 3) {
                out[b] = (byte) rBank[rPixIx];
                rPixIx += pixelStride;
                out[b + 1] = (byte) gBank[gPixIx];
                gPixIx += pixelStride;
                out[b + 2] = (byte) bBank[bPixIx];
                bPixIx += pixelStride;
            }
            rScanIx += scanlineStride;
            gScanIx += scanlineStride;
            bScanIx += scanlineStride;
        }
        return out;
    }

    private static byte[] extractComponentRGBByte(int aWidth, int aHeight, ComponentSampleModel aSampleModel, DataBufferByte aDataBuffer) {
        byte[] out = new byte[aWidth * aHeight * 3];

        int[] bankIndices = aSampleModel.getBankIndices();
        byte[] rBank = aDataBuffer.getBankData()[bankIndices[0]];
        byte[] gBank = aDataBuffer.getBankData()[bankIndices[1]];
        byte[] bBank = aDataBuffer.getBankData()[bankIndices[2]];

        int[] bankOffsets = aSampleModel.getBandOffsets();
        int rScanIx = bankOffsets[0];
        int gScanIx = bankOffsets[1];
        int bScanIx = bankOffsets[2];

        int pixelStride = aSampleModel.getPixelStride();
        int scanlineStride = aSampleModel.getScanlineStride();
        for (int b = 0, y = 0; y < aHeight; y++) {
            int rPixIx = rScanIx;
            int gPixIx = gScanIx;
            int bPixIx = bScanIx;
            for (int x = 0; x < aWidth; x++, b += 3) {
                out[b] = rBank[rPixIx];
                rPixIx += pixelStride;
                out[b + 1] = gBank[gPixIx];
                gPixIx += pixelStride;
                out[b + 2] = bBank[bPixIx];
                bPixIx += pixelStride;
            }
            rScanIx += scanlineStride;
            gScanIx += scanlineStride;
            bScanIx += scanlineStride;
        }
        return out;
    }

    private static byte[] getRGBA(RenderedImage aRi) throws IOException {
        int width = aRi.getWidth();
        int height = aRi.getHeight();

        ColorModel colorModel = aRi.getColorModel();
        if (colorModel instanceof ComponentColorModel) {
            ComponentSampleModel sampleModel = (ComponentSampleModel) aRi.getSampleModel();
            int type = sampleModel.getTransferType();
            if (type == DataBuffer.TYPE_BYTE) {
                return extractComponentRGBAByte(width, height, sampleModel, ((DataBufferByte) aRi.getData().getDataBuffer()));
            } else if (type == DataBuffer.TYPE_INT) {
                return extractComponentRGBAInt(width, height, sampleModel, ((DataBufferInt) aRi.getData().getDataBuffer()));
            } else {
                throw new IOException("Incompatible image: " + aRi);
            }
        } else if (colorModel instanceof DirectColorModel) {
            SinglePixelPackedSampleModel sampleModel = (SinglePixelPackedSampleModel) aRi.getSampleModel();
            int type = sampleModel.getTransferType();
            if (type == DataBuffer.TYPE_INT) {
                return extractDirectRGBAInt(width, height, (DirectColorModel) colorModel, sampleModel, ((DataBufferInt) aRi.getData().getDataBuffer()));
            } else {
                throw new IOException("Incompatible image: " + aRi);
            }
        } else {
            BufferedImage i = new BufferedImage(aRi.getWidth(), aRi.getHeight(), BufferedImage.TYPE_INT_ARGB);
            Graphics2D g = i.createGraphics();
            g.drawRenderedImage(aRi, new AffineTransform());
            g.dispose();
            return getRGBA(i);
        }
    }

    private static byte[] extractDirectRGBAInt(int aWidth, int aHeight, DirectColorModel aColorModel, SinglePixelPackedSampleModel aSampleModel, DataBufferInt aDataBuffer) {
        byte[] out = new byte[aWidth * aHeight * 4];

        int rMask = aColorModel.getRedMask();
        int gMask = aColorModel.getGreenMask();
        int bMask = aColorModel.getBlueMask();
        int aMask = aColorModel.getAlphaMask();
        int rShift = getShift(rMask);
        int gShift = getShift(gMask);
        int bShift = getShift(bMask);
        int aShift = getShift(aMask);
        int[] bank = aDataBuffer.getBankData()[0];
        int scanlineStride = aSampleModel.getScanlineStride();
        int scanIx = 0;
        for (int b = 0, y = 0; y < aHeight; y++) {
            int pixIx = scanIx;
            for (int x = 0; x < aWidth; x++, b += 4) {
                int pixel = bank[pixIx++];
                out[b] = (byte) ((pixel & rMask) >>> rShift);
                out[b + 1] = (byte) ((pixel & gMask) >>> gShift);
                out[b + 2] = (byte) ((pixel & bMask) >>> bShift);
                out[b + 3] = (byte) ((pixel & aMask) >>> aShift);
            }
            scanIx += scanlineStride;
        }
        return out;
    }

    private static byte[] extractComponentRGBAInt(int aWidth, int aHeight, ComponentSampleModel aSampleModel, DataBufferInt aDataBuffer) {
        byte[] out = new byte[aWidth * aHeight * 4];

        int[] bankIndices = aSampleModel.getBankIndices();
        int[] rBank = aDataBuffer.getBankData()[bankIndices[0]];
        int[] gBank = aDataBuffer.getBankData()[bankIndices[1]];
        int[] bBank = aDataBuffer.getBankData()[bankIndices[2]];
        int[] aBank = aDataBuffer.getBankData()[bankIndices[3]];

        int[] bankOffsets = aSampleModel.getBandOffsets();
        int rScanIx = bankOffsets[0];
        int gScanIx = bankOffsets[1];
        int bScanIx = bankOffsets[2];
        int aScanIx = bankOffsets[3];

        int pixelStride = aSampleModel.getPixelStride();
        int scanlineStride = aSampleModel.getScanlineStride();
        for (int b = 0, y = 0; y < aHeight; y++) {
            int rPixIx = rScanIx;
            int gPixIx = gScanIx;
            int bPixIx = bScanIx;
            int aPixIx = aScanIx;
            for (int x = 0; x < aWidth; x++, b += 4) {
                out[b] = (byte) rBank[rPixIx];
                rPixIx += pixelStride;
                out[b + 1] = (byte) gBank[gPixIx];
                gPixIx += pixelStride;
                out[b + 2] = (byte) bBank[bPixIx];
                bPixIx += pixelStride;
                out[b + 3] = (byte) aBank[aPixIx];
                aPixIx += pixelStride;
            }
            rScanIx += scanlineStride;
            gScanIx += scanlineStride;
            bScanIx += scanlineStride;
            aScanIx += scanlineStride;
        }
        return out;
    }

    private static byte[] extractComponentRGBAByte(int aWidth, int aHeight, ComponentSampleModel aSampleModel, DataBufferByte aDataBuffer) {
        byte[] out = new byte[aWidth * aHeight * 4];

        int[] bankIndices = aSampleModel.getBankIndices();
        byte[] rBank = aDataBuffer.getBankData()[bankIndices[0]];
        byte[] gBank = aDataBuffer.getBankData()[bankIndices[1]];
        byte[] bBank = aDataBuffer.getBankData()[bankIndices[2]];
        byte[] aBank = aDataBuffer.getBankData()[bankIndices[3]];

        int[] bankOffsets = aSampleModel.getBandOffsets();
        int rScanIx = bankOffsets[0];
        int gScanIx = bankOffsets[1];
        int bScanIx = bankOffsets[2];
        int aScanIx = bankOffsets[3];

        int pixelStride = aSampleModel.getPixelStride();
        int scanlineStride = aSampleModel.getScanlineStride();
        for (int b = 0, y = 0; y < aHeight; y++) {
            int rPixIx = rScanIx;
            int gPixIx = gScanIx;
            int bPixIx = bScanIx;
            int aPixIx = aScanIx;
            for (int x = 0; x < aWidth; x++, b += 4) {
                out[b] = rBank[rPixIx];
                rPixIx += pixelStride;
                out[b + 1] = gBank[gPixIx];
                gPixIx += pixelStride;
                out[b + 2] = bBank[bPixIx];
                bPixIx += pixelStride;
                out[b + 3] = aBank[aPixIx];
                aPixIx += pixelStride;
            }
            rScanIx += scanlineStride;
            gScanIx += scanlineStride;
            bScanIx += scanlineStride;
            aScanIx += scanlineStride;
        }
        return out;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy