Search in sources :

Example 46 with AffineTransformOp

use of java.awt.image.AffineTransformOp in project Overloaded by CJ-MC-Mods.

the class ImageUtil method scaleDownToWidth.

public static BufferedImage scaleDownToWidth(@Nonnull BufferedImage original, int width) {
    double scale = original.getWidth() / (double) width;
    if (scale <= 1) {
        return original;
    }
    AffineTransform at = new AffineTransform();
    at.scale(1 / scale, 1 / scale);
    AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
    return scaleOp.filter(original, null);
}
Also used : AffineTransform(java.awt.geom.AffineTransform) AffineTransformOp(java.awt.image.AffineTransformOp)

Example 47 with AffineTransformOp

use of java.awt.image.AffineTransformOp in project BKCommonLib by bergerhealer.

the class MapColorPalette method resizeCopy.

/**
 * Copies the input byte array of map color pixel data to the output array,
 * performing an image resize operation with bilinear interpolation. For performance
 * it is recommended to scale down an integer resolution amount. For example:
 * 128x64 -> 64x32.<br>
 * <br>
 * If no faster method is possible, will use a slow method involving Graphics2D.
 *
 * @param input Input byte array of map pixel colors
 * @param inputWidth Input image resolution width
 * @param inputHeight Input image resolution height
 * @param output Output buffer to write the updated colors to
 * @param outputWidth Output image resolution width
 * @param outputHeight Output image resolution height
 */
public static void resizeCopy(byte[] input, int inputWidth, int inputHeight, byte[] output, int outputWidth, int outputHeight) {
    // Unique case
    if (inputWidth == outputWidth && inputHeight == outputHeight) {
        System.arraycopy(input, 0, output, 0, inputWidth * inputHeight);
        return;
    }
    // Optimized code when down-sizing an integer amount
    int outputLength = outputWidth * outputHeight;
    int pixelStepX = inputWidth / outputWidth;
    int pixelStepY = inputHeight / outputHeight;
    if ((outputWidth * pixelStepX) == inputWidth && (outputHeight * pixelStepY) == inputHeight) {
        int pixelStepBlock = pixelStepX * pixelStepY;
        int pixelStepBlockHalf = pixelStepBlock / 2;
        int inputLineOffset = inputWidth - pixelStepX;
        int inputLineStep = (pixelStepY - 1) * inputWidth;
        int inputStartIndex = 0;
        int inputLineEndIndex = inputWidth;
        for (int i = 0; i < outputLength; i++) {
            // Collect average RGB pixel value
            // Also count how many pixels are transparent
            // If over 50% is transparent, make it a transparent pixel
            int numTransparent = 0;
            int r = 0;
            int g = 0;
            int b = 0;
            int inputIndex = inputStartIndex;
            for (int dy = 0; dy < pixelStepY; dy++) {
                for (int dx = 0; dx < pixelStepX; dx++) {
                    byte pixel = input[inputIndex++];
                    if (isTransparent(pixel)) {
                        numTransparent++;
                    } else {
                        Color c = MapColorPalette.getRealColor(pixel);
                        r += c.getRed();
                        g += c.getGreen();
                        b += c.getBlue();
                    }
                }
                inputIndex += inputLineOffset;
            }
            if (numTransparent >= pixelStepBlockHalf) {
                output[i] = COLOR_TRANSPARENT;
            } else {
                int fact = pixelStepBlock - numTransparent;
                r /= fact;
                g /= fact;
                b /= fact;
                output[i] = COLOR_MAP_DATA.get(r, g, b);
            }
            // Next pixel of the input, and then next line
            inputStartIndex += pixelStepX;
            if (inputStartIndex >= inputLineEndIndex) {
                inputStartIndex += inputLineStep;
                inputLineEndIndex = inputStartIndex + inputWidth;
            }
        }
        return;
    }
    // Default fallback code just uses Graphics2D
    // Create an indexed BufferedImage for the input
    BufferedImage inputImage;
    {
        java.awt.image.DataBufferByte data = new java.awt.image.DataBufferByte(input, input.length);
        WritableRaster raster = Raster.createInterleavedRaster(data, inputWidth, inputHeight, inputWidth, 1, new int[] { 0 }, null);
        inputImage = new BufferedImage(MapColorPalette.getIndexColorModel(), raster, false, null);
    }
    // When scaling down, we must use getScaledInstance because bilinear interpolation looks awful
    // When scaling up, we must use the bilinear interpolation affine operation for best results
    // Sadly there is no solution that covers best of both worlds :(
    BufferedImage outputImage = new BufferedImage(outputWidth, outputHeight, BufferedImage.TYPE_INT_ARGB);
    if (outputLength > (inputWidth * inputHeight)) {
        // Scaling up
        AffineTransform at = new AffineTransform();
        at.scale((double) outputWidth / (double) inputWidth, (double) outputHeight / (double) inputHeight);
        AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
        outputImage = scaleOp.filter(inputImage, outputImage);
    } else {
        // Scaling down. Note that performance is very poor, but quality is good.
        Image tmp = inputImage.getScaledInstance(outputWidth, outputHeight, Image.SCALE_AREA_AVERAGING);
        // Convert to BufferedImage
        java.awt.Graphics2D graphics2D = outputImage.createGraphics();
        graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
        graphics2D.drawImage(tmp, 0, 0, outputWidth, outputHeight, null);
        graphics2D.dispose();
    }
    // Convert back to map colors
    int[] intPixels = ((java.awt.image.DataBufferInt) outputImage.getRaster().getDataBuffer()).getData();
    ColorConverterType converterType = ColorConverterType.ARGB;
    for (int i = 0; i < outputLength; i++) {
        output[i] = converterType.convert(intPixels[i]);
    }
}
Also used : Color(java.awt.Color) Image(java.awt.Image) BufferedImage(java.awt.image.BufferedImage) BufferedImage(java.awt.image.BufferedImage) AffineTransformOp(java.awt.image.AffineTransformOp) WritableRaster(java.awt.image.WritableRaster) AffineTransform(java.awt.geom.AffineTransform)

Aggregations

AffineTransformOp (java.awt.image.AffineTransformOp)47 AffineTransform (java.awt.geom.AffineTransform)30 BufferedImage (java.awt.image.BufferedImage)29 Graphics2D (java.awt.Graphics2D)20 IOException (java.io.IOException)4 Rectangle2D (java.awt.geom.Rectangle2D)3 WritableRaster (java.awt.image.WritableRaster)3 ByteArrayOutputStream (java.io.ByteArrayOutputStream)3 Color (java.awt.Color)2 Image (java.awt.Image)2 RenderingHints (java.awt.RenderingHints)2 ByteLookupTable (java.awt.image.ByteLookupTable)2 ConvolveOp (java.awt.image.ConvolveOp)2 LookupOp (java.awt.image.LookupOp)2 LookupTable (java.awt.image.LookupTable)2 ByteArrayInputStream (java.io.ByteArrayInputStream)2 File (java.io.File)2 ImageException (cbit.image.ImageException)1 GeometryException (cbit.vcell.geometry.GeometryException)1 ChecksumException (com.google.zxing.ChecksumException)1