1.需求
- 给图片的指定区域打码
- 给整张图片打码
- 马赛克方格取色支持中心点取色和随机取色
- 马赛克支持灰度处理
2.源码
package com.visy.utils;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.Random;
/**
* @author visy.wang
* @date 2024/9/19 9:56
*/
public class ImageUtil {
/**
* 给图片指定区域打马赛克
* @param x 打码区域左上角的横坐标
* @param y 打码区域左上角的纵坐标
* @param width 打码区域的宽度
* @param height 打码区域的高度
* @param size 马赛克格子尺寸,即每个正方形小方格的边长
*/
public static void mosaic(
InputStream source, OutputStream target, int x, int y, int width, int height, int size
) throws IOException {
//读取该图片
BufferedImage image = ImageIO.read(source);
int imgWidth = image.getWidth(), imgHeight = image.getHeight();
System.out.println("原图片尺寸:"+imgWidth+"*"+imgHeight);
if(size<=0 || width==0 || height==0){
//不打马赛克,直接返回原图
ImageIO.write(image, "jpg", target);
return;
}
//马赛克区域边界值处理
width = width<0||width>imgWidth ? imgWidth : width;
height = height<0||height>imgHeight ? imgHeight : height;
//起点坐标<0处理
x = Math.max(x, 0);
y = Math.max(y, 0);
//马赛克块大小 不能大于图片宽度和高度,超过时取宽高中小的那一个
if (size > imgWidth || size > imgHeight) {
size = Math.min(imgWidth, imgHeight);
}
//创建一张画布(和原图同尺寸,颜色类型选择RGB)
BufferedImage canvas = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
//获得画布的画笔
Graphics gs = canvas.getGraphics();
//先将原图片画到画布上
gs.drawImage(image, 0, 0, null);
//计算横向和纵向绘制马赛克方格的个数
int xCount = width/size + (width%size==0 ? 0 : 1); //横绘绘制个数
int yCount = height/size + (height%size==0 ? 0 : 1); //纵向绘制个数
//遍历指定区域的所有方格并填充
int $x = x;//方格左上角x坐标
for (int i = 0; i < xCount; i++) {
int $y = y;//方格左上角y坐标
//方格的宽度,横向最后一个方格的宽需单独处理
int $width = i==xCount-1 ? (x+width-$x) : size;
for (int j = 0; j < yCount; j++) {
//方格的高度,纵向最后一个方格的高需单独处理
int $height = j==yCount-1 ? (y+height-$y) : size;
//颜色取方格中心像素点RGB值
//int rgb = getCenterRgb($x, $y, $width, $height, image);
//颜色取方格内随机像素点RGB值
int rgb = getRandomRgb($x, $y, $width, $height, image);
//设置颜色(灰度处理)
//Color color = new Color(toGray(rgb));
Color color = new Color(rgb);
//设置颜色
gs.setColor(color);
//填充方格
gs.fillRect($x, $y, $width, $height);
//方格加边框(用于测试)
//gs.setColor(Color.RED);
//gs.drawRect($x, $y, $width, $height);
$y += size;//计算下一个方格的左上角y坐标
}
$x += size;//计算下一行方格的左上角x坐标
}
gs.dispose(); //释放资源
ImageIO.write(canvas, "jpg", target); // 保存图片
}
/**
* 给整张图片打马赛克
* @param source 原图输入流
* @param target 打码后的图片输出流
* @param size 马赛克格子尺寸,即每个正方形小方格的边长
*/
public static void mosaicAll(
InputStream source, OutputStream target, int size
) throws IOException {
mosaic(source, target, 0, 0, -1, -1, size);
}
/**
* 获取马赛克小方格中心点的颜色
* @param x 小方格左上角横坐标
* @param y 小方格左上角纵坐标
* @param width 小方格的宽度
* @param height 小方格的高度
* @param image 原图
* @return 颜色RGB值
*/
private static int getCenterRgb(int x, int y, int width, int height, BufferedImage image){
//计算当前方格中心点位置
int xCenterIndex = x + (width%2==0 ? width : width-1) / 2;
int yCenterIndex = y + (height%2==0 ? height : height-1) / 2;
//颜色取中心像素点RGB值
return image.getRGB(xCenterIndex, yCenterIndex);
}
/**
* 在马赛克小方格区域内随机取一个像素点的颜色
* @param x 小方格左上角横坐标
* @param y 小方格左上角纵坐标
* @param width 小方格的宽度
* @param height 小方格的高度
* @param image 原图
* @return 颜色RGB值
*/
private static int getRandomRgb(int x, int y, int width, int height, BufferedImage image){
//在方格区域内随机取一个点的颜色
Random random = new Random();
int xIndex = x + random.nextInt(width);
int yIndex = y + random.nextInt(height);
return image.getRGB(xIndex, yIndex);
}
/**
* 彩色转换成黑白
* @param rgb 彩色RGB值
* @return 黑白RGB值
*/
private static int toGray(int rgb){
int r = (rgb >> 16) & 0xFF;
int g = (rgb >> 8) & 0xFF;
int b = rgb & 0xFF;
// 计算灰度值
int gray = (r + g + b) / 3;
return (gray << 16) + (gray << 8) + gray;
}
/**
* 创建目标(输出)文件
* @param file 源文件
* @return 目标文件
*/
private static File createTargetFile(File file){
String name = file.getName();
String newName = name.substring(0, name.lastIndexOf("."))+"_mosaic.jpg";
return new File(file.getParent(), newName);
}
public static void mosaic(File file, int x, int y, int width, int height, int size) throws IOException {
InputStream in = Files.newInputStream(file.toPath());
OutputStream out = Files.newOutputStream(createTargetFile(file).toPath());
mosaic(in, out, x, y, width, height, size);
}
public static void mosaicAll(File file, int size) throws IOException {
InputStream in = Files.newInputStream(file.toPath());
OutputStream out = Files.newOutputStream(createTargetFile(file).toPath());
mosaicAll(in, out, size);
}
public static void main(String[] args) throws IOException {
File f = new File("E:\\test\\imgs\\2d6aa7e497a059df30d635667b1ec998.jpeg");
//mosaic(f, 20 , 560, 500, 150, 10);
mosaic(f,370, 241, 370, 245, 15);
System.out.println("处理完成");
}
}
3.输入输出
- 处理前
- 处理后(中心点取色)
- 处理后(灰度处理)
- 处理后(随机取色)