java 图像缩放,高质量、无损,非图像抽稀

废话不说,上代码!

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.imageio.ImageIO;

//png图像无损压缩(不改变分辨率),https://repo.maven.apache.org/maven2/com/idrsolutions/OpenViewerFX/7.13.31/
import com.idrsolutions.image.png.PngCompressor;

/**
 * 图像缩放:支持jpg图像、无透明通道的png图像(若有透明通道,将会出现边缘异常)
 * @author RainingTime
 *
 */
public class ImageReSize {

	private static int srcWidth;
    private static int srcHeight;
    private static int scaleWidth;
    static double support = 3.0;
    static double[] contrib;
    static double[] normContrib;
    static double[] tmpContrib;
    static int startContrib, stopContrib;
    static int nDots;
    static int nHalfDots;
	
    public static void main(String[] args) throws IOException {
    	
    	//缩放模式:jpg模式图像质量不好,png模式图像质量高。这里只是一个计算模式,不是图片后缀名
    	String type = "png";
    	//String type = "jpg";
    	
    	String imageName = "C:/Users/RainingTime/Desktop/图像缩放/cat.jpg";
    	String newImageName = imageName.substring(0, imageName.lastIndexOf("."))+"-new."+imageName.substring(imageName.lastIndexOf(".")+1);
    	
        BufferedImage image1 = ImageIO.read(new File(imageName));
        int w = 100;
        int h = 144;
        boolean keepScale = true;//是否保持长宽比
        BufferedImage image2 = ImageReSize.imageReSize(image1, w, h, type, keepScale);
        ImageIO.write(image2, type, new File(newImageName));
        
        if("png".equals(type)){
        	//png图像无损压缩(不改变分辨率)
        	PngCompressor.compress(new File(newImageName), new File(newImageName));
        }
    }
    

    /**
     * @param srcBufferImage	源图像
     * @param w					目标图像宽度
     * @param h					目标图像高度
     * @param lockScale			是否锁定宽高比例(以宽度为基准。false:否,true:是)
     * @return
     */
    public static BufferedImage imageReSize(BufferedImage srcBufferImage, int w, int h, String type, boolean lockScale) {
    	srcWidth = srcBufferImage.getWidth();
    	srcHeight = srcBufferImage.getHeight();
        scaleWidth = w;
        if (lockScale) {
            h = w * srcHeight / srcWidth;
        }
        if(w > srcWidth && h > srcHeight){
        	return srcBufferImage;
        }else if(w > srcWidth){
        	w = srcWidth;
        }else if(h > srcHeight){
        	h = srcHeight;
        }

        CalContrib();
        
        //单线程模式:速度较慢,内存占用小
        /*BufferedImage pbOut = HorizontalFiltering(srcBufferImage, w, type);
        BufferedImage pbFinalOut = VerticalFiltering(pbOut, h, type);*/
        
        //多线程模式:速度快,内存占用高
        BufferedImage pbOut = HorizontalFiltering2(srcBufferImage, w, type);
        BufferedImage pbFinalOut = VerticalFiltering2(pbOut, h, type);
        
        return pbFinalOut;
    }


    private static void CalContrib() {
        nHalfDots = (int) ((double) srcWidth * support / (double) scaleWidth);
        nDots = nHalfDots * 2 + 1;
        try {
            contrib = new double[nDots];
            normContrib = new double[nDots];
            tmpContrib = new double[nDots];
        } catch (Exception e) {
            System.out.println("init contrib,normContrib,tmpContrib" + e);
        }

        int center = nHalfDots;
        contrib[center] = 1.0;

        double weight = 0.0;
        int i = 0;
        for (i = 1; i <= center; i++) {
            contrib[center + i] = Lanczos(i, srcWidth, scaleWidth, support);
            contrib[center - i] = Lanczos(i, srcWidth, scaleWidth, support);
            weight += contrib[center + i];
        }

        weight = weight * 2 + 1.0;
        for (i = 0; i <= center; i++) {
            normContrib[i] = contrib[i] / weight;
            normContrib[center * 2 - i] = contrib[i] / weight;
        }
    }
    
    private static double Lanczos(int i, int inWidth, int outWidth, double Support) {
        double x;
        x = (double) i * (double) outWidth / (double) inWidth;
        return Math.sin(x * Math.PI) / (x * Math.PI) * Math.sin(x * Math.PI / Support) / (x * Math.PI / Support);
    }

    // 处理边缘
    private static void CalTempContrib(int start, int stop) { 
        double weight = 0;
        int i = 0;
        for (i = start; i <= stop; i++) {
            weight += contrib[i];
        }
        for (i = start; i <= stop; i++) {
            tmpContrib[i] = contrib[i] / weight;
        }
    }
    
    // 处理边缘
    private static double[] CalTempContrib2(int start, int stop) { 
    	double[] newContrib = new double[nDots];
    	double weight = 0;
    	int i = 0;
    	for (i = start; i <= stop; i++) {
    		weight += contrib[i];
    	}
    	for (i = start; i <= stop; i++) {
    		newContrib[i] = contrib[i] / weight;
    	}
    	return newContrib;
    }

    private static int GetOpacityValue(int rgbValue) {
        return (rgbValue >> 24) & 0x00ff;
    }
    
    private static int GetRedValue(int rgbValue) {
    	return (rgbValue >> 16) & 0x00ff;
    }

    private static int GetGreenValue(int rgbValue) {
    	return (rgbValue >> 8) & 0x00ff;
    }

    private static int GetBlueValue(int rgbValue) {
    	return rgbValue & 0x00ff;
    }

    private static int ComRGB(int opacityValue, int redValue, int greenValue, int blueValue) {
        return (opacityValue << 24) + (redValue << 16) + (greenValue << 8) + blueValue;
    }

    // 行水平滤波
    private static int HorizontalFilter(BufferedImage bufImg, int startX, int stopX, int start, int stop, int y, double[] pContrib) {
    	double valueRed = 0;
    	double valueGreen = 0;
        double valueBlue = 0;
        double valueOpacity = 0;
        int valueRGB = 0;
        int i, j;
        
        try {
			for (i = startX, j = start; i <= stopX; i++, j++) {
			    valueRGB = bufImg.getRGB(i, y);
			    //valueOpacity += GetOpacityValue(valueRGB) * (1 / Math.pow(2, Math.abs((startX+stopX+1)/2 - i)));
			    valueRed += GetRedValue(valueRGB) * pContrib[j];
			    valueGreen += GetGreenValue(valueRGB) * pContrib[j];
			    valueBlue += GetBlueValue(valueRGB) * pContrib[j];
			}
		} catch (Exception e) {
		}
        //valueRGB = ComRGB(Clip((int)valueOpacity), Clip((int)valueRed), Clip((int)valueGreen), Clip((int)valueBlue));
        valueRGB = ComRGB(255, Clip((int)valueRed), Clip((int)valueGreen), Clip((int)valueBlue));
        return valueRGB;
    }

    // 图片水平滤波
    private static BufferedImage HorizontalFiltering(BufferedImage bufImage, int iOutW, String type) {
        int dwInW = bufImage.getWidth();
        int dwInH = bufImage.getHeight();
        int value = 0;
        
        BufferedImage pbOut;
        if("png".equals(type)){
            pbOut = new BufferedImage(iOutW, dwInH, BufferedImage.TYPE_INT_ARGB);
        }else{
        	pbOut = new BufferedImage(iOutW, dwInH, BufferedImage.TYPE_INT_RGB);
        }

        for (int x = 0; x < iOutW; x++) {
            int startX;
            int start;
            int X = (int) (((double) x) * ((double) dwInW) / ((double) iOutW) + 0.5);
            int y = 0;

            startX = X - nHalfDots;
            if (startX < 0) {
                startX = 0;
                start = nHalfDots - X;
            } else {
                start = 0;
            }

            int stop;
            int stopX = X + nHalfDots;
            if (stopX > (dwInW - 1)) {
                stopX = dwInW - 1;
                stop = nHalfDots + (dwInW - 1 - X);
            } else {
                stop = nHalfDots * 2;
            }

            if (start > 0 || stop < nDots - 1) {
            	CalTempContrib(start, stop);
                for (y = 0; y < dwInH; y++) {
                    value = HorizontalFilter(bufImage, startX, stopX, start, stop, y, tmpContrib);
                    pbOut.setRGB(x, y, value);
                }
            } else {
                for (y = 0; y < dwInH; y++) {
                    value = HorizontalFilter(bufImage, startX, stopX, start, stop, y, normContrib);
                    pbOut.setRGB(x, y, value);
                }
            }
        }
        return pbOut;
    }
    
    // 图片水平滤波-多线程
    private static BufferedImage HorizontalFiltering2(final BufferedImage bufImage, final int iOutW, String type) {
    	final int dwInW = bufImage.getWidth();
    	final int dwInH = bufImage.getHeight();
    	
    	final BufferedImage pbOut;
    	if("png".equals(type)){
    		pbOut = new BufferedImage(iOutW, dwInH, BufferedImage.TYPE_INT_ARGB);
    	}else{
    		pbOut = new BufferedImage(iOutW, dwInH, BufferedImage.TYPE_INT_RGB);
    	}
    	
    	ExecutorService exe = Executors.newFixedThreadPool(4);
    	for (int x = 0; x < iOutW; x++) {
    		final int x1 = x;
    		exe.execute(new Runnable() {
				@Override
				public void run() {
					int startX;
		    		int start;
		    		int X = (int) (((double) x1) * ((double) dwInW) / ((double) iOutW) + 0.5);
		    		int y = 0;
		    		
		    		startX = X - nHalfDots;
		    		if (startX < 0) {
		    			startX = 0;
		    			start = nHalfDots - X;
		    		} else {
		    			start = 0;
		    		}
		    		
		    		int stop;
		    		int stopX = X + nHalfDots;
		    		if (stopX > (dwInW - 1)) {
		    			stopX = dwInW - 1;
		    			stop = nHalfDots + (dwInW - 1 - X);
		    		} else {
		    			stop = nHalfDots * 2;
		    		}
		    		
		    		if (start > 0 || stop < nDots - 1) {
		    			final double[] newContrib = CalTempContrib2(start, stop);
		    			for (y = 0; y < dwInH; y++) {
		    				pbOut.setRGB(x1, y, HorizontalFilter(bufImage, startX, stopX, start, stop, y, newContrib));
		    			}
		    		} else {
		    			for (y = 0; y < dwInH; y++) {
		    	    		pbOut.setRGB(x1, y, HorizontalFilter(bufImage, startX, stopX, start, stop, y, normContrib));
		    			}
		    		}
				}
    		});
    	}
    	exe.shutdown();
		while (true) {
			try {
				Thread.sleep(100L);//主线程休眠0.1秒,等待线程池运行结束,同时避免一直死循环造成CPU浪费
			} catch (InterruptedException e) {
			}
			if (exe.isTerminated()) {//线程池所有线程都结束运行
				break; 
			}
		}
    	return pbOut;
    }

    private static int VerticalFilter(BufferedImage pbInImage, int startY, int stopY, int start, int stop, int x, double[] pContrib) {
    	double valueRed = 0;
        double valueGreen = 0;
        double valueBlue = 0;
        double valueOpacity = 0;
        int valueRGB = 0;
        int i, j;

        try {
			for (i = startY, j = start; i <= stopY; i++, j++) {
			    valueRGB = pbInImage.getRGB(x, i);
			    //valueOpacity += GetOpacityValue(valueRGB) * (1 / Math.pow(2, Math.abs((startY+stopY+1)/2 - i)));
			    valueRed += GetRedValue(valueRGB) * pContrib[j];
			    valueGreen += GetGreenValue(valueRGB) * pContrib[j];
			    valueBlue += GetBlueValue(valueRGB) * pContrib[j];
			}
		} catch (Exception e) {
			for (int k = 0; k < pContrib.length; k++) {
				System.out.print(pContrib[k]+", ");
			}
			System.out.println();
		}
        //valueRGB = ComRGB(Clip((int)valueOpacity), Clip((int)valueRed), Clip((int)valueGreen), Clip((int)valueBlue));
        valueRGB = ComRGB(255, Clip((int)valueRed), Clip((int)valueGreen), Clip((int)valueBlue));
        return valueRGB;
    }

    //纵向滤波
    private static BufferedImage VerticalFiltering(BufferedImage pbImage, int iOutH, String type) {
        int iW = pbImage.getWidth();
        int iH = pbImage.getHeight();
        int value = 0;
        
        BufferedImage pbOut;
        if("png".equals(type)){
            pbOut = new BufferedImage(iW, iOutH, BufferedImage.TYPE_INT_ARGB);
        }else{
        	pbOut = new BufferedImage(iW, iOutH, BufferedImage.TYPE_INT_RGB);
        }
        
        for (int y = 0; y < iOutH; y++) {
            int startY;
            int start;
            int Y = (int) (((double) y) * ((double) iH) / ((double) iOutH) + 0.5);
            
            startY = Y - nHalfDots;
            if (startY < 0) {
                startY = 0;
                start = nHalfDots - Y;
            } else {
                start = 0;
            }
            
            int stop;
            int stopY = Y + nHalfDots;
            if (stopY > (int) (iH - 1)) {
                stopY = iH - 1;
                stop = nHalfDots + (iH - 1 - Y);
            } else {
                stop = nHalfDots * 2;
            }

            if (start > 0 || stop < nDots - 1) {
            	CalTempContrib(start, stop);
                for (int x = 0; x < iW; x++) {
                    value = VerticalFilter(pbImage, startY, stopY, start, stop, x, tmpContrib);
                    pbOut.setRGB(x, y, value);
                }
            } else {
                for (int x = 0; x < iW; x++) {
                    value = VerticalFilter(pbImage, startY, stopY, start, stop, x, normContrib);
                    pbOut.setRGB(x, y, value);
                }
            }
        }
        return pbOut;
    }
    
	//纵向滤波-多线程
    private static BufferedImage VerticalFiltering2(final BufferedImage pbImage, final int iOutH, String type) {
    	final int iW = pbImage.getWidth();
    	final int iH = pbImage.getHeight();
    	
    	final BufferedImage pbOut;
    	if("png".equals(type)){
    		pbOut = new BufferedImage(iW, iOutH, BufferedImage.TYPE_INT_ARGB);
    	}else{
    		pbOut = new BufferedImage(iW, iOutH, BufferedImage.TYPE_INT_RGB);
    	}
    	
    	ExecutorService exe = Executors.newFixedThreadPool(4);
    	for (int y = 0; y < iOutH; y++) {
    		final int y1 = y;
    		exe.execute(new Runnable() {
				@Override
				public void run() {
					int startY;
		    		int start;
		    		int Y = (int) (((double) y1) * ((double) iH) / ((double) iOutH) + 0.5);
		    		
		    		startY = Y - nHalfDots;
		    		if (startY < 0) {
		    			startY = 0;
		    			start = nHalfDots - Y;
		    		} else {
		    			start = 0;
		    		}
		    		
		    		int stop;
		    		int stopY = Y + nHalfDots;
		    		if (stopY > (int) (iH - 1)) {
		    			stopY = iH - 1;
		    			stop = nHalfDots + (iH - 1 - Y);
		    		} else {
		    			stop = nHalfDots * 2;
		    		}
		    		
		    		if (start > 0 || stop < nDots - 1) {
		    			double[] newContrib = CalTempContrib2(start, stop);
		    			for (int x = 0; x < iW; x++) {
				    		pbOut.setRGB(x, y1, VerticalFilter(pbImage, startY, stopY, start, stop, x, newContrib));
		    			}
		    		} else {
		    			for (int x = 0; x < iW; x++) {
				    		pbOut.setRGB(x, y1, VerticalFilter(pbImage, startY, stopY, start, stop, x, normContrib));
		    			}
		    		}
		    	}
			});
    	}
    	exe.shutdown();
		while (true) {
			try {
				Thread.sleep(100L);//主线程休眠0.1秒,等待线程池运行结束,同时避免一直死循环造成CPU浪费
			} catch (InterruptedException e) {
			}
			if (exe.isTerminated()) {//线程池所有线程都结束运行
				break; 
			}
		}
    	return pbOut;
    }

    private static int Clip(int x) {
        if (x < 0)
            return 0;
        if (x > 255)
            return 255;
        return x;
    }

}

效果:

原图:

 缩放后:

 喜欢请点赞。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RainingTime

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值