问题
做习题的小伙伴在做试题的时候需要把Word文档中的习题切图制作成试题,由于没注意到Word转出的图片上有很多水印导致制作的资源很不美观。由于涉及的图片数量庞大几千上万张,如果用PS去处理也够我们UI喝一壶的。于是发扬技术解决一切问题的精神写了个图片批量处理水印程序。
效果预览
先看一下原图,是这样的
用程序处理后的结果是介个样子滴:
可以看到,水印基本已经无影无踪了。
分析
要实现这样的一个程序首先要了解关于图像的基本知识。我们平常所看到的JPG,PNG等图像在显示的时候是以像素为单位的。长300宽400像素的图片所有像素为300x400=120000个像素点。在ARGB的图像表示方法中,每个像素点有ARGB四个通道,
A代表透明度,取值范围0~255,
R代表三原色中的红,取值范围0~255,
G代表三原色中的绿,取值范围0~255,
B代表三原色中的蓝,取值范围0~255。
所以存储这些数据只需要4个8位二进制在Java中也就是一个int类型就行啦。所以这张图片显示在屏幕上所占用的内存至少是120000x32个字节。每种颜色都有特定的ARGB取值,所以我们要去除水印就是要把图片中特定范围的ARGB取值改为四个通道取值都是255的白色就行了。有了以上理论知识,再结合Java图像处理相关API,根据目标图像的特征提取出适当ARGB取值范围。可以使用qq或者纳克小工,PS等工具查看水印像素所对应的范围。
然后就可以写出一个去水印程序啦。
上代码
package com.jzhung.demo.core.image; import javax.imageio.ImageIO; import javax.imageio.ImageWriter; import javax.imageio.stream.ImageOutputStream; import javax.net.ssl.HttpsURLConnection; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Scanner; /** * Created by Jzhung on 2017/2/27. * 文档图片水印处理 */ public class ImageConverter { private static List<File> fileList = new ArrayList<File>(); public static void main(String[] args) { System.out.println("输入需要去水印的图片所在的根目录回车(支持递归子目录):"); Scanner input = new Scanner(System.in); String dir = input.nextLine().trim(); System.out.println("输入转换后的存储目录:"); String saveDir = input.nextLine().trim(); System.out.println("输入y开始"); String comfrm = input.nextLine().trim(); if (comfrm.equals("y")) { convertAllImages(dir, saveDir); } else { System.out.println("您输入的不是y程序,程序退出"); } /*String dir = "E:\\data\\Desktop"; String saveDir = "E:\\data\\Desktop-convert";*/ //replaceFolderImages(dir); /*String srcFile = "E:\\data\\image\\img38.png"; String dstFile = "E:\\data\\image\\img38.png"; long begin = System.currentTimeMillis(); repleaceColor(srcFile, dstFile); long time = System.currentTimeMillis() - begin; System.out.println(time);*/ } private static void convertAllImages(String dir, String saveDir) { File dirFile = new File(dir); File saveDirFile = new File(saveDir); dir = dirFile.getAbsolutePath(); saveDir = saveDirFile.getAbsolutePath(); loadImages(new File(dir)); for (File file : fileList) { String filePath = file.getAbsolutePath(); String dstPath = saveDir + filePath.substring(filePath.indexOf(dir) + dir.length(), filePath.length()); System.out.println("converting: " + filePath); replaceColor(file.getAbsolutePath(), dstPath); } } public static void loadImages(File f) { if (f != null) { if (f.isDirectory()) { File[] fileArray = f.listFiles(); if (fileArray != null) { for (int i = 0; i < fileArray.length; i++) { //递归调用 loadImages(fileArray[i]); } } } else { String name = f.getName(); if (name.endsWith("png") || name.endsWith("jpg")) { fileList.add(f); } } } } private static void replaceFolderImages(String dir) { File dirFile = new File(dir); File[] files = dirFile.listFiles(new FileFilter() { public boolean accept(File file) { String name = file.getName(); if (name.endsWith("png") || name.endsWith("jpg")) { return true; } return false; } }); for (File img : files) { replaceColor(img.getAbsolutePath(), img.getAbsolutePath()); } } private static void replaceColor(String srcFile, String dstFile) { try { Color color = new Color(255, 195, 195); replaceImageColor(srcFile, dstFile, color, Color.WHITE); } catch (IOException e) { e.printStackTrace(); } } public static void replaceImageColor(String file, String dstFile, Color srcColor, Color targetColor) throws IOException { URL http; if (file.trim().startsWith("https")) { http = new URL(file); HttpsURLConnection conn = (HttpsURLConnection) http.openConnection(); conn.setRequestMethod("GET"); } else if (file.trim().startsWith("http")) { http = new URL(file); HttpURLConnection conn = (HttpURLConnection) http.openConnection(); conn.setRequestMethod("GET"); } else { http = new File(file).toURI().toURL(); } BufferedImage bi = ImageIO.read(http.openStream()); if(bi == null){ return; } Color wColor = new Color(255, 255, 255); for (int i = 0; i < bi.getWidth(); i++) { for (int j = 0; j < bi.getHeight(); j++) { //System.out.println(bi.getRGB(i, j)); int color = bi.getRGB(i, j); Color oriColor = new Color(color); int red = oriColor.getRed(); int greed = oriColor.getGreen(); int blue = oriColor.getBlue(); //粉色 if (greed < 190 || blue < 190) { } else { if (red == 255 && greed > 180 && blue > 180) { bi.setRGB(i, j, wColor.getRGB()); } } } } String type = file.substring(file.lastIndexOf(".") + 1, file.length()); Iterator<ImageWriter> it = ImageIO.getImageWritersByFormatName(type); ImageWriter writer = it.next(); File f = new File(dstFile); f.getParentFile().mkdirs(); ImageOutputStream ios = ImageIO.createImageOutputStream(f); writer.setOutput(ios); writer.write(bi); bi.flush(); ios.flush(); ios.close(); } }
你好,白色的水印好去除么?白色的水印需要改成什么颜色?255,255,255不行呀
白色水印如果在内容上能和其它地方区分出来就能去除,注意代码 141-148行是处理像素点的,根据实际情况判断一下。