Resampler.java 19.7 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.internal.io.ByteArrayByteWriter
 *  com.adobe.internal.io.ByteWriter
 *  com.adobe.internal.io.DataBufferByteWriter
 */
package com.adobe.internal.pdftoolkit.image;

import com.adobe.internal.io.ByteArrayByteWriter;
import com.adobe.internal.io.ByteWriter;
import com.adobe.internal.io.DataBufferByteWriter;
import com.adobe.internal.pdftoolkit.image.ARGBImage;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.security.InvalidParameterException;
import java.util.Hashtable;

public class Resampler {
    public static final int kResampleNearestNeighbor = 1;
    public static final int kResampleBicubic = 2;
    public static final int kResampleLinear = 3;
    private static final short[] LinearWeights = new short[]{16384, 0, 15872, 512, 15360, 1024, 14848, 1536, 14336, 2048, 13824, 2560, 13312, 3072, 12800, 3584, 12288, 4096, 11776, 4608, 11264, 5120, 10752, 5632, 10240, 6144, 9728, 6656, 9216, 7168, 8704, 7680, 8192, 8192, 7680, 8704, 7168, 9216, 6656, 9728, 6144, 10240, 5632, 10752, 5120, 11264, 4608, 11776, 4096, 12288, 3584, 12800, 3072, 13312, 2560, 13824, 2048, 14336, 1536, 14848, 1024, 15360, 512, 15872};
    private static final short[] Cubic1Weights = new short[]{0, 16384, 0, 0, -360, 16349, 407, -12, -675, 16245, 859, -45, -946, 16077, 1351, -98, -1176, 15848, 1880, -168, -1367, 15562, 2442, -253, -1521, 15223, 3033, -351, -1641, 14834, 3650, -459, -1728, 14400, 4288, -576, -1785, 13924, 4944, -699, -1815, 13409, 5615, -825, -1819, 12860, 6296, -953, -1800, 12280, 6984, -1080, -1760, 11673, 7675, -1204, -1701, 11043, 8365, -1323, -1626, 10393, 9051, -1434, -1536, 9728, 9728, -1536, -1434, 9051, 10393, -1626, -1323, 8365, 11043, -1701, -1204, 7675, 11673, -1760, -1080, 6984, 12280, -1800, -953, 6296, 12860, -1819, -825, 5615, 13409, -1815, -699, 4944, 13924, -1785, -576, 4288, 14400, -1728, -459, 3650, 14834, -1641, -351, 3033, 15223, -1521, -253, 2442, 15562, -1367, -168, 1880, 15848, -1176, -98, 1351, 16077, -946, -45, 859, 16245, -675, -12, 407, 16349, -360};
    private static final short[] Cubic2Weights = new short[]{-706, 2077, 13642, 2077, -706, 0, -618, 1681, 13625, 2492, -796, 0, -531, 1303, 13574, 2924, -886, 0, -447, 946, 13489, 3371, -975, 0, -367, 612, 13369, 3831, -1061, 0, -292, 300, 13217, 4303, -1144, 0, -223, 15, 13030, 4784, -1222, 0, -161, -244, 12812, 5272, -1295, 0, -107, -475, 12561, 5765, -1360, 0, -63, -681, 12283, 6262, -1417, 0, -30, -863, 11980, 6762, -1465, 0, -9, -1021, 11654, 7263, -1503, 0, 0, -1157, 11307, 7764, -1530, 0, 0, -1271, 10937, 8261, -1543, 0, 0, -1364, 10541, 8749, -1542, 0, 0, -1436, 10121, 9223, -1524, 0, 0, -1489, 9681, 9681, -1489, 0, 0, -1524, 9223, 10121, -1436, 0, 0, -1542, 8749, 10541, -1364, 0, 0, -1543, 8261, 10937, -1271, 0, 0, -1530, 7764, 11307, -1157, 0, 0, -1503, 7263, 11654, -1021, -9, 0, -1465, 6762, 11980, -863, -30, 0, -1417, 6262, 12283, -681, -63, 0, -1360, 5765, 12561, -475, -107, 0, -1295, 5272, 12812, -244, -161, 0, -1222, 4784, 13030, 15, -223, 0, -1144, 4303, 13217, 300, -292, 0, -1061, 3831, 13369, 612, -367, 0, -975, 3371, 13489, 946, -447, 0, -886, 2924, 13574, 1303, -531, 0, -796, 2492, 13625, 1681, -618};
    private static final short[] Cubic3Weights = new short[]{-1229, 3655, 11532, 3655, -1229, 0, -1199, 3325, 11520, 3991, -1253, 0, -1163, 3000, 11487, 4331, -1271, 0, -1122, 2682, 11430, 4674, -1280, 0, -1077, 2372, 11352, 5019, -1282, 0, -1027, 2069, 11251, 5366, -1275, 0, -973, 1775, 11130, 5712, -1259, -1, -917, 1492, 10993, 6059, -1234, -9, -858, 1219, 10839, 6407, -1198, -25, -798, 959, 10669, 6754, -1152, -48, -736, 710, 10484, 7098, -1094, -78, -673, 476, 10279, 7439, -1024, -113, -609, 255, 10060, 7774, -941, -155, -546, 50, 9825, 8101, -845, -201, -483, -139, 9572, 8419, -734, -251, -422, -312, 9306, 8726, -609, -305, -362, -468, 9022, 9022, -468, -362, -305, -609, 8726, 9306, -312, -422, -251, -734, 8419, 9572, -139, -483, -201, -845, 8101, 9825, 50, -546, -155, -941, 7774, 10060, 255, -609, -113, -1024, 7439, 10279, 476, -673, -78, -1094, 7098, 10484, 710, -736, -48, -1152, 6754, 10669, 959, -798, -25, -1198, 6407, 10839, 1219, -858, -9, -1234, 6059, 10993, 1492, -917, -1, -1259, 5712, 11130, 1775, -973, 0, -1275, 5366, 11251, 2069, -1027, 0, -1282, 5019, 11352, 2372, -1077, 0, -1280, 4674, 11430, 2682, -1122, 0, -1271, 4331, 11487, 3000, -1163, 0, -1253, 3991, 11520, 3325, -1199};
    private static final short[] Cubic4Weights = new short[]{-266, -903, 4522, 9678, 4522, -903, -266, 0, -227, -947, 4280, 9671, 4765, -852, -306, 0, -191, -984, 4039, 9653, 5009, -794, -348, 0, -157, -1015, 3799, 9623, 5253, -728, -391, 0, -126, -1039, 3562, 9579, 5497, -654, -435, 0, -97, -1058, 3326, 9525, 5740, -572, -480, 0, -72, -1071, 3092, 9461, 5982, -482, -526, 0, -49, -1079, 2861, 9382, 6223, -382, -572, 0, -31, -1082, 2632, 9295, 6461, -273, -618, 0, -17, -1080, 2407, 9196, 6695, -154, -663, 0, -7, -1073, 2185, 9085, 6927, -25, -708, 0, -1, -1061, 1967, 8962, 7154, 115, -752, 0, 0, -1046, 1754, 8830, 7376, 264, -794, 0, 0, -1026, 1545, 8686, 7591, 423, -835, 0, 0, -1002, 1341, 8530, 7798, 591, -874, 0, 0, -975, 1143, 8362, 7996, 768, -910, 0, 0, -944, 952, 8184, 8184, 952, -944, 0, 0, -910, 768, 7996, 8362, 1143, -975, 0, 0, -874, 591, 7798, 8530, 1341, -1002, 0, 0, -835, 423, 7591, 8686, 1545, -1026, 0, 0, -794, 264, 7376, 8830, 1754, -1046, 0, 0, -752, 115, 7154, 8962, 1967, -1061, -1, 0, -708, -25, 6927, 9085, 2185, -1073, -7, 0, -663, -154, 6695, 9196, 2407, -1080, -17, 0, -618, -273, 6461, 9295, 2632, -1082, -31, 0, -572, -382, 6223, 9382, 2861, -1079, -49, 0, -526, -482, 5982, 9461, 3092, -1071, -72, 0, -480, -572, 5740, 9525, 3326, -1058, -97, 0, -435, -654, 5497, 9579, 3562, -1039, -126, 0, -391, -728, 5253, 9623, 3799, -1015, -157, 0, -348, -794, 5009, 9653, 4039, -984, -191, 0, -306, -852, 4765, 9671, 4280, -947, -227};
    private static final short[] Cubic5Weights = new short[]{-768, 0, 4864, 8192, 4864, 0, -768, 0, -743, -93, 4695, 8187, 5031, 99, -791, -1, -717, -180, 4525, 8174, 5197, 204, -813, -6, -690, -262, 4354, 8154, 5360, 314, -833, -13, -662, -338, 4183, 8123, 5522, 430, -851, -23, -632, -408, 4010, 8085, 5680, 550, -866, -35, -602, -473, 3837, 8038, 5837, 676, -880, -49, -571, -533, 3665, 7983, 5990, 806, -891, -65, -540, -588, 3492, 7924, 6140, 940, -900, -84, -508, -638, 3320, 7854, 6287, 1079, -906, -104, -476, -683, 3148, 7781, 6430, 1221, -910, -127, -444, -724, 2977, 7699, 6569, 1367, -910, -150, -413, -761, 2808, 7612, 6705, 1517, -908, -176, -381, -792, 2639, 7518, 6835, 1669, -902, -202, -349, -820, 2472, 7417, 6962, 1825, -893, -230, -318, -844, 2307, 7311, 7083, 1983, -880, -258, -288, -864, 2144, 7200, 7200, 2144, -864, -288, -258, -880, 1983, 7083, 7311, 2307, -844, -318, -230, -893, 1825, 6962, 7417, 2472, -820, -349, -202, -902, 1669, 6835, 7518, 2639, -792, -381, -176, -908, 1517, 6705, 7612, 2808, -761, -413, -150, -910, 1367, 6569, 7699, 2977, -724, -444, -127, -910, 1221, 6430, 7781, 3148, -683, -476, -104, -906, 1079, 6287, 7854, 3320, -638, -508, -84, -900, 940, 6140, 7924, 3492, -588, -540, -65, -891, 806, 5990, 7983, 3665, -533, -571, -49, -880, 676, 5837, 8038, 3837, -473, -602, -35, -866, 550, 5680, 8085, 4010, -408, -632, -23, -851, 430, 5522, 8123, 4183, -338, -662, -13, -833, 314, 5360, 8154, 4354, -262, -690, -6, -813, 204, 5197, 8174, 4525, -180, -717, -1, -791, 99, 5031, 8187, 4695, -93, -743};

    private static final double __proj(double value, double x0, double x1) {
        return (value - x0) / (x1 - x0);
    }

    private static final double __invproj(double value, double x0, double x1) {
        return value * (x1 - x0) + x0;
    }

    private static final long __Round32(double x) {
        return (long)(x >= 0.0 ? Math.floor(x + 0.5) : - Math.floor(- x + 0.5));
    }

    private static final long __Pin32(long bottom, long target, long top) {
        return Math.max(bottom, Math.min(target, top));
    }

    private static final long __PinU8(long target) {
        if ((target & -256) != 0) {
            target = (target ^ -1) >> 31;
        }
        return target & 255;
    }

    private static int[] resizeHorizontal(int[] srcPixels, int dstWidth, int dstHeight, int srcWidth, int srcHeight, short[] kernelWeights, short kernelWidth, int numComponents) {
        if (srcHeight != dstHeight) {
            throw new InvalidParameterException("resizeHorizontal(): srcHeight != dstHeight");
        }
        short[] hIndexTable = new short[dstWidth];
        byte[] hBinMapTable = new byte[dstWidth];
        for (long j = 0; j < (long)dstWidth; ++j) {
            double u = Resampler.__proj((double)j + 0.5, 0.0, dstWidth);
            long y = Resampler.__Round32((Resampler.__invproj(u, 0.0, srcWidth) - 0.5) * 32.0);
            y = Resampler.__Pin32(0, y, srcWidth * 32);
            hIndexTable[(int)j] = (short)(y >> 5);
            hBinMapTable[(int)j] = (byte)(y & 31);
        }
        if (kernelWidth > 8) {
            throw new InvalidParameterException("resizeHorizontal(): kernelWidth > 8");
        }
        long kernelOffset = 1 - kernelWidth / 2;
        long[] sum = new long[numComponents];
        int[] destPixels = new int[dstWidth * dstHeight];
        for (int row = 0; row < dstHeight; ++row) {
            for (int col = 0; col < dstWidth; ++col) {
                int comp;
                int comp2;
                long hWeightBin = (long)hBinMapTable[col] * (long)kernelWidth;
                long colOffset = (long)hIndexTable[col] + kernelOffset;
                for (comp = 0; comp < numComponents; ++comp) {
                    sum[comp] = 0;
                }
                for (long sample = 0; sample < (long)kernelWidth; ++sample) {
                    short weight = kernelWeights[(int)(hWeightBin + sample)];
                    int pSample = (int)Resampler.__Pin32(0, colOffset + sample, srcWidth - 1);
                    int pixel = srcPixels[row * srcWidth + pSample];
                    for (int comp3 = 0; comp3 < numComponents; ++comp3) {
                        long[] arrl = sum;
                        int n = comp3;
                        arrl[n] = arrl[n] + (long)((pixel >> comp3 * 8 & 255) * weight);
                    }
                }
                for (comp = 0; comp < numComponents; ++comp) {
                    sum[comp] = sum[comp] + 8192 >> 14;
                }
                int outPixel = 0;
                if (numComponents > 1) {
                    for (comp2 = 0; comp2 < numComponents; ++comp2) {
                        outPixel = (int)((long)outPixel | Resampler.__PinU8(sum[comp2]) << comp2 * 8);
                    }
                } else {
                    for (comp2 = 0; comp2 < 3; ++comp2) {
                        outPixel = (int)((long)outPixel | Resampler.__PinU8(sum[0]) << comp2 * 8);
                    }
                }
                destPixels[row * dstWidth + col] = outPixel;
            }
        }
        return destPixels;
    }

    private static int[] resizeVertical(int[] srcPixels, int dstWidth, int dstHeight, int srcWidth, int srcHeight, short[] kernelWeights, short kernelWidth, int numComponents) {
        if (srcWidth != dstWidth) {
            throw new InvalidParameterException("resizeVertical(): srcWidth != dstWidth");
        }
        short[] vIndexTable = new short[dstHeight];
        byte[] vBinMapTable = new byte[dstHeight];
        for (long j = 0; j < (long)dstHeight; ++j) {
            double u = Resampler.__proj((double)j + 0.5, 0.0, dstHeight);
            long y = Resampler.__Round32((Resampler.__invproj(u, 0.0, srcHeight) - 0.5) * 32.0);
            y = Resampler.__Pin32(0, y, srcHeight * 32);
            vIndexTable[(int)j] = (short)(y >> 5);
            vBinMapTable[(int)j] = (byte)(y & 31);
        }
        if (kernelWidth > 8) {
            throw new InvalidParameterException("resizeVertical(): kernelWidth > 8");
        }
        long kernelOffset = 1 - kernelWidth / 2;
        long[] sum = new long[numComponents];
        int[] destPixels = new int[dstWidth * dstHeight];
        for (int col = 0; col < dstWidth; ++col) {
            for (int row = 0; row < dstHeight; ++row) {
                int comp;
                int comp2;
                long vWeightBin = (long)vBinMapTable[row] * (long)kernelWidth;
                long rowOffset = (long)vIndexTable[row] + kernelOffset;
                for (comp = 0; comp < numComponents; ++comp) {
                    sum[comp] = 0;
                }
                for (long sample = 0; sample < (long)kernelWidth; ++sample) {
                    short weight = kernelWeights[(int)(vWeightBin + sample)];
                    int pSample = (int)Resampler.__Pin32(0, rowOffset, srcHeight - 1);
                    int pixel = srcPixels[pSample * srcWidth + col];
                    for (int comp3 = 0; comp3 < numComponents; ++comp3) {
                        long[] arrl = sum;
                        int n = comp3;
                        arrl[n] = arrl[n] + (long)((pixel >> comp3 * 8 & 255) * weight);
                    }
                }
                for (comp = 0; comp < numComponents; ++comp) {
                    sum[comp] = sum[comp] + 8192 >> 14;
                }
                int outPixel = 0;
                if (numComponents > 1) {
                    for (comp2 = 0; comp2 < numComponents; ++comp2) {
                        outPixel = (int)((long)outPixel | Resampler.__PinU8(sum[comp2]) << comp2 * 8);
                    }
                } else {
                    for (comp2 = 0; comp2 < 3; ++comp2) {
                        outPixel = (int)((long)outPixel | Resampler.__PinU8(sum[0]) << comp2 * 8);
                    }
                }
                destPixels[row * dstWidth + col] = outPixel;
            }
        }
        return destPixels;
    }

    private static BufferedImage createDestBufferedImage(BufferedImage sourceBufferedImage, int dx, int dy) {
        ByteArrayByteWriter babw = new ByteArrayByteWriter();
        ColorModel cm = sourceBufferedImage.getColorModel();
        WritableRaster raster = cm.createCompatibleWritableRaster(dx, dy);
        DataBufferByteWriter buffer = new DataBufferByteWriter((ByteWriter)babw, raster.getDataBuffer().getDataType(), raster.getDataBuffer().getSize());
        ARGBImage.DataBufferWritableRaster newRaster = new ARGBImage.DataBufferWritableRaster(raster.getSampleModel(), (DataBuffer)buffer, new Point(0, 0));
        return new BufferedImage(cm, newRaster, false, null);
    }

    public static BufferedImage resampleImage(BufferedImage sourceBufferedImage, int dx, int dy, int method) {
        int width = sourceBufferedImage.getWidth();
        int height = sourceBufferedImage.getHeight();
        int[] originalPixels = sourceBufferedImage.getRGB(0, 0, width, height, new int[width * height], 0, width);
        int[] downSampledPixels = null;
        switch (method) {
            case 1: {
                downSampledPixels = Resampler.downSampleWithNearestNeighbourMethod(dx, dy, width, height, originalPixels);
            }
            case 2: {
                downSampledPixels = Resampler.downSampleWithBicubicMethod(dx, dy, width, height, originalPixels, sourceBufferedImage.getColorModel().getNumComponents());
            }
            case 3: {
                downSampledPixels = Resampler.downSampleWithBicubicMethod(dx, dy, width, height, originalPixels, sourceBufferedImage.getColorModel().getNumComponents());
            }
        }
        BufferedImage destBufferedImage = Resampler.createDestBufferedImage(sourceBufferedImage, dx, dy);
        destBufferedImage.setRGB(0, 0, dx, dy, downSampledPixels, 0, dx);
        return destBufferedImage;
    }

    static int[] downSampleWithNearestNeighbourMethod(int destWidth, int destHeight, int width, int height, int[] pixels) {
        int i;
        int[] hTable = new int[destWidth];
        int[] vTable = new int[destHeight];
        double hZoomFactor = (double)destWidth / (double)width;
        double vZoomFactor = (double)destHeight / (double)height;
        for (i = 0; i < destWidth; ++i) {
            hTable[i] = (int)Math.floor((double)i / hZoomFactor);
        }
        for (i = 0; i < destHeight; ++i) {
            vTable[i] = (int)Math.floor((double)i / vZoomFactor);
        }
        int[] downSampledPixels = new int[destHeight * destWidth];
        for (int row = 0; row < destHeight; ++row) {
            for (int col = 0; col < destWidth; ++col) {
                downSampledPixels[row * destWidth + col] = pixels[vTable[row] * width + hTable[col]];
            }
        }
        return downSampledPixels;
    }

    static int[] downSampleWithLinearMethod(int destWidth, int destHeight, int width, int height, int[] pixels, int numComponents) {
        short[] hKernelWeights = LinearWeights;
        short hKernelWidth = 2;
        short[] vKernelWeights = LinearWeights;
        short vKernelWidth = 2;
        int[] destPixels = null;
        if (destWidth * height <= width * destHeight) {
            int[] tempPixels = Resampler.resizeHorizontal(pixels, destWidth, height, width, height, hKernelWeights, hKernelWidth, numComponents);
            destPixels = Resampler.resizeVertical(tempPixels, destWidth, destHeight, destWidth, height, vKernelWeights, vKernelWidth, numComponents);
        } else {
            int[] tempPixels = Resampler.resizeVertical(pixels, width, destHeight, width, height, vKernelWeights, vKernelWidth, numComponents);
            destPixels = Resampler.resizeHorizontal(tempPixels, destWidth, destHeight, width, destHeight, hKernelWeights, hKernelWidth, numComponents);
        }
        return destPixels;
    }

    public static int[] downSampleWithBicubicMethod(int destWidth, int destHeight, int width, int height, int[] pixels, int numComponents) {
        short[] hKernelWeights = null;
        short hKernelWidth = 0;
        short[] vKernelWeights = null;
        short vKernelWidth = 0;
        double hScale = (double)destWidth / (double)width;
        if (hScale >= 0.917) {
            hKernelWeights = Cubic1Weights;
            hKernelWidth = 4;
        } else if (hScale >= 0.771) {
            hKernelWeights = Cubic2Weights;
            hKernelWidth = 6;
        } else if (hScale >= 0.648) {
            hKernelWeights = Cubic3Weights;
            hKernelWidth = 6;
        } else if (hScale >= 0.545) {
            hKernelWeights = Cubic4Weights;
            hKernelWidth = 8;
        } else {
            hKernelWeights = Cubic5Weights;
            hKernelWidth = 8;
        }
        double vScale = (double)destHeight / (double)height;
        if (vScale >= 0.917) {
            vKernelWeights = Cubic1Weights;
            vKernelWidth = 4;
        } else if (vScale >= 0.771) {
            vKernelWeights = Cubic2Weights;
            vKernelWidth = 6;
        } else if (vScale >= 0.648) {
            vKernelWeights = Cubic3Weights;
            vKernelWidth = 6;
        } else if (vScale >= 0.545) {
            vKernelWeights = Cubic4Weights;
            vKernelWidth = 8;
        } else {
            vKernelWeights = Cubic5Weights;
            vKernelWidth = 8;
        }
        int[] destPixels = null;
        if (destWidth * height <= width * destHeight) {
            int[] tempPixels = Resampler.resizeHorizontal(pixels, destWidth, height, width, height, hKernelWeights, hKernelWidth, numComponents);
            destPixels = Resampler.resizeVertical(tempPixels, destWidth, destHeight, destWidth, height, vKernelWeights, vKernelWidth, numComponents);
        } else {
            int[] tempPixels = Resampler.resizeVertical(pixels, width, destHeight, width, height, vKernelWeights, vKernelWidth, numComponents);
            destPixels = Resampler.resizeHorizontal(tempPixels, destWidth, destHeight, width, destHeight, hKernelWeights, hKernelWidth, numComponents);
        }
        return destPixels;
    }
}