最近,项目中需要对图片进行处理。实现的方式当然有很多种,这里,我使用了Java的BufferedImage进行了实现。由于对图片的不熟悉,实现的时候费了点儿劲,这里记录一下,以备后用。
场景描述:其实问题很简单,有一类混淆了的图片,我要将其还原。中间需要将图片切开,然后在重新组装。组装成跟原来一样大小的图片。中间不可以缩放比例,不可以裁剪丢失。
也就是说:我们要将图1这样的图片,将其处理成图2和图3这样。



没有很复杂的东西,关键就是一个对图片熟悉的过程,实现代码如下:
package com.lzq.images;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;/*** lzq* 滑块图片处理*/
public class DealImages {private static final List<Integer> drawImageCoor = Arrays.asList(22, 9, 21, 19, 14, 2, 6, 8, 3, 12, 15, 23, 5, 4, 7, 17, 18, 20, 10, 13, 25, 11, 0, 1, 16, 24);/*切割后图片的长度*/private static final int width = 20;/*切割后图片的宽*/private static final int height = 80;public static void main(String[] args) {BufferedImage bi = getImageFromFile("D:\\imageFile\\slide1.png");makeDrawImage(bi,BufferedImage.TYPE_INT_ARGB,"D:\\imageFile\\result1.png");makeDrawImage(bi,BufferedImage.TYPE_INT_RGB,"D:\\imageFile\\result2.png");}/*** 图片来源于本地* @param path* @return*/static BufferedImage getImageFromFile(String path){BufferedImage bi = null;try {bi = ImageIO.read(new FileInputStream(path));} catch (IOException e) {e.printStackTrace();}return bi;}/*** 图片来源于url* @param url* @return*/static BufferedImage getImageFromUrl(String url){BufferedImage bi = null;try {// 读取源图像URL bgPicUrl = new URL(url);bi = ImageIO.read(bgPicUrl);} catch (IOException e) {e.printStackTrace();}return bi;}/*** 图片处理* @param bi* @param bufferedImageType* @param resultPath* @return*/static BufferedImage makeDrawImage(BufferedImage bi, int bufferedImageType,String resultPath){BufferedImage imageNew = null;try {List<List<ImageInfo>> lsResult = cutImage(bi);List<ImageInfo> lsImage = new ArrayList<>();//分别横向合并lsImage.add(new ImageInfo(0,0,mergeImage(lsResult.get(0), TypeEnum.LIE,bufferedImageType)));lsImage.add(new ImageInfo(0,height,mergeImage(lsResult.get(1), TypeEnum.LIE,bufferedImageType)));//纵向合并imageNew = mergeImage(lsImage, TypeEnum.STAND,bufferedImageType);ImageIO.write(imageNew, "png", new File(resultPath));} catch (Exception e) {e.printStackTrace();}return imageNew;}/*** 图像切割(按指定起点坐标和宽高切割)* @param bi 源图像*/private static List<List<ImageInfo>> cutImage(BufferedImage bi) {List<List<ImageInfo>> lsResult = new ArrayList<>();List<ImageInfo> images1 = new ArrayList<>();List<ImageInfo> images2 = new ArrayList<>();try {int srcHeight = bi.getHeight(); // 源图宽度int srcWidth = bi.getWidth(); // 源图高度for (int i = 0; i < drawImageCoor.size(); i++) {int drawImg = drawImageCoor.get(i);int half = drawImageCoor.size() / 2;int x = (drawImg % half) * 20;if (drawImg == 0) {x = 0;}int y = (int) Math.floor(drawImg / half) * 80;int sx = (i % half) * 20;if (i == 0)sx = 0;int sy = (int) Math.floor(i / half) * 80;Image image = bi.getScaledInstance(srcWidth, srcHeight, Image.SCALE_DEFAULT);// 四个参数分别为图像起点坐标和宽高// 即: CropImageFilter(int x,int y,int width,int height)
// System.out.println("sx="+sx+";sy="+sy+";x="+x+";y="+y);ImageFilter cropFilter = new CropImageFilter(sx, sy, width, height);Image img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(),cropFilter));BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);Graphics g = tag.getGraphics();g.drawImage(img, 0, 0, width, height, null); // 绘制切割后的图g.dispose();if (y>0){images2.add(new ImageInfo(x,y,tag));}else {images1.add(new ImageInfo(x,y,tag));}}Collections.sort(images1);Collections.sort(images2);lsResult.add(images1);lsResult.add(images2);} catch (Exception e) {e.printStackTrace();}return lsResult;}/*** 图片拼接 (注意:必须两张图片长宽一致哦)* @param imageInfos 要拼接的文件列表* @param type 横向拼接, 2 纵向拼接*/private static BufferedImage mergeImage(List<ImageInfo> imageInfos, TypeEnum type, int bufferedImageType) {BufferedImage imageNew;int len = imageInfos.size();if (len < 1) {throw new RuntimeException("图片数量小于1");}BufferedImage[] images = new BufferedImage[len];int[][] ImageArrays = new int[len][];for (int i = 0; i < len; i++) {try {images[i] = imageInfos.get(i).getBufferedImage();} catch (Exception e) {throw new RuntimeException(e);}int width = images[i].getWidth();int height = images[i].getHeight();ImageArrays[i] = new int[width * height];ImageArrays[i] = images[i].getRGB(0, 0, width, height, ImageArrays[i], 0, width);}int newHeight = 0;int newWidth = 0;for (int i = 0; i < images.length; i++) {// 横向if (type == TypeEnum.LIE) {newHeight = newHeight > images[i].getHeight() ? newHeight : images[i].getHeight();newWidth += images[i].getWidth();} else if (type == TypeEnum.STAND) {// 纵向newWidth = newWidth > images[i].getWidth() ? newWidth : images[i].getWidth();newHeight += images[i].getHeight();}}if (type == TypeEnum.LIE && newWidth < 1) {return null;}if (type == TypeEnum.STAND && newHeight < 1) {return null;}// 生成新图片try {/** BufferedImage.TYPE_INT_RGB 生成原图* BufferedImage.TYPE_INT_ARGB 严格按照图盘文件生成* */
// imageNew = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);imageNew = new BufferedImage(newWidth, newHeight, bufferedImageType);int height_i = 0;int width_i = 0;for (int i = 0; i < images.length; i++) {if (type == TypeEnum.LIE) {imageNew.setRGB(width_i, 0, images[i].getWidth(), newHeight, ImageArrays[i], 0, images[i].getWidth());width_i += images[i].getWidth();} else if (type == TypeEnum.STAND) {imageNew.setRGB(0, height_i, newWidth, images[i].getHeight(), ImageArrays[i], 0, newWidth);height_i += images[i].getHeight();}}} catch (Exception e) {throw new RuntimeException(e);}return imageNew;}/*** 两张图片,比较滑动点* @param testphoto 滑动图* @param contrasphoto 原图* @return*/public static int slideLength(BufferedImage testphoto, BufferedImage contrasphoto){int contras_rgb[] = new int[3];int test_rgb[] = new int[3];int k = 0;// int contraswidth = contrasphoto.getWidth();
// int contrasheight = contrasphoto.getHeight();int testwidth = testphoto.getWidth();int testheight = testphoto.getHeight();for (int i = 0; i < testwidth; i++) {for (int j = 0; j < testheight; j++) {int pixel1 = contrasphoto.getRGB(i, j);int pixle2= testphoto.getRGB(i, j);contras_rgb[0] = (pixel1 & 0xff0000) >> 16; //将值转化成16进制contras_rgb[1] = (pixel1 & 0xff00) >> 8;contras_rgb[2] = (pixel1 & 0xff);test_rgb[0] = (pixle2 & 0xff0000) >> 16;test_rgb[1] = (pixle2 & 0xff00) >> 8;test_rgb[2] = (pixle2 & 0xff);int Difference_R = Math.abs(contras_rgb[0]-test_rgb[0]); //相减并且求绝对值int Difference_G= Math.abs(contras_rgb[1]-test_rgb[1]);int Difference_B= Math.abs(contras_rgb[2]-test_rgb[2]);//System.out.println("第"+j+"次:"+Math.abs(Difference));final int R = 35; //35final int L = 130;int Q = Difference_R+Difference_G+Difference_B;if (Difference_R>30 || Difference_G>30 ||Difference_B>30){return i;}}}return k;}/*** 滑块滑动距离* @param bi* @return*/public static int slideLength(BufferedImage bi){System.out.println(bi.getWidth());int x=bi.getWidth();for (int i = 0; i < bi.getWidth(); i++) {for (int j = 0; j < bi.getHeight(); j++) {int cl = bi.getRGB(i, j);if(cl>250*250*250) {bi.setRGB(i, j, (new Color(0f,0f,0f)).getRGB());if(x>i&&bi.getRGB(i+5, j+20)>250*250*250 ) {x=i;}}}}return x;}/*** 拼接图片方式类型*/enum TypeEnum{LIE(1,"横着"),STAND(2,"竖着");private int code;private String desc;TypeEnum(int code, String desc){this.code = code;this.desc = desc;}}/*** 图片信息单元存储*/static class ImageInfo implements Comparable<ImageInfo> {private int x; //横坐标private int y; //纵坐标private BufferedImage bufferedImage;public ImageInfo(int x, int y, BufferedImage bufferedImage) {this.x = x;this.y = y;this.bufferedImage = bufferedImage;}@Overridepublic int compareTo(ImageInfo image) {return this.x - image.getX();}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}public BufferedImage getBufferedImage() {return bufferedImage;}}
}
总结:该实现,还包括对图片处理的一系列功能:
对图片的切割、重组;
生成滑块图;
生成真实原图;
滑块图缺失部分的位置比较。