[原创]纯Java代码批量去除图片文字水印

问题

做习题的小伙伴在做试题的时候需要把Word文档中的习题切图制作成试题,由于没注意到Word转出的图片上有很多水印导致制作的资源很不美观。由于涉及的图片数量庞大几千上万张,如果用PS去处理也够我们UI喝一壶的。于是发扬技术解决一切问题的精神写了个图片批量处理水印程序。

效果预览

先看一下原图,是这样的

img2

img15

img36

img37

 

用程序处理后的结果是介个样子滴:

img1 img15

img36

img37

 

可以看到,水印基本已经无影无踪了。

分析

要实现这样的一个程序首先要了解关于图像的基本知识。我们平常所看到的JPG,PNG等图像在显示的时候是以像素为单位的。长300宽400像素的图片所有像素为300×400=120000个像素点。在ARGB的图像表示方法中,每个像素点有ARGB四个通道,

A代表透明度,取值范围0~255,

R代表三原色中的红,取值范围0~255,

G代表三原色中的绿,取值范围0~255,

B代表三原色中的蓝,取值范围0~255。

所以存储这些数据只需要4个8位二进制在Java中也就是一个int类型就行啦。所以这张图片显示在屏幕上所占用的内存至少是120000×32个字节。每种颜色都有特定的ARGB取值,所以我们要去除水印就是要把图片中特定范围的ARGB取值改为四个通道取值都是255的白色就行了。有了以上理论知识,再结合Java图像处理相关API,根据目标图像的特征提取出适当ARGB取值范围。可以使用qq或者纳克小工,PS等工具查看水印像素所对应的范围。

20170228090910

然后就可以写出一个去水印程序啦。

上代码

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();
    }
}

 

2 条思考于 “[原创]纯Java代码批量去除图片文字水印

    1. 钟家兴 文章作者

      白色水印如果在内容上能和其它地方区分出来就能去除,注意代码 141-148行是处理像素点的,根据实际情况判断一下。

发表评论

电子邮件地址不会被公开。 必填项已用*标注