本文目录导读:

我来为您提供一个完整的Java图片马赛克实现方案。
基础马赛克实现
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class ImageMosaicTool {
/**
* 给图片添加马赛克效果
* @param sourcePath 源图片路径
* @param outputPath 输出图片路径
* @param startX 马赛克区域起始X坐标
* @param startY 马赛克区域起始Y坐标
* @param width 马赛克区域宽度
* @param height 马赛克区域高度
* @param blockSize 马赛克块大小
*/
public static void addMosaic(String sourcePath, String outputPath,
int startX, int startY,
int width, int height,
int blockSize) throws IOException {
// 读取原始图片
File inputFile = new File(sourcePath);
BufferedImage originalImage = ImageIO.read(inputFile);
// 获取图片尺寸
int imageWidth = originalImage.getWidth();
int imageHeight = originalImage.getHeight();
// 创建新图片
BufferedImage resultImage = new BufferedImage(
imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = resultImage.createGraphics();
g2d.drawImage(originalImage, 0, 0, null);
// 计算马赛克区域
int endX = Math.min(startX + width, imageWidth);
int endY = Math.min(startY + height, imageHeight);
// 应用马赛克效果
for (int y = startY; y < endY; y += blockSize) {
for (int x = startX; x < endX; x += blockSize) {
// 计算当前块的边界
int blockEndX = Math.min(x + blockSize, endX);
int blockEndY = Math.min(y + blockSize, endY);
// 获取块中心点的颜色
int centerX = x + blockSize / 2;
int centerY = y + blockSize / 2;
// 边界检查
centerX = Math.min(centerX, imageWidth - 1);
centerY = Math.min(centerY, imageHeight - 1);
int pixelColor = originalImage.getRGB(centerX, centerY);
// 将该块所有像素设为相同颜色
for (int by = y; by < blockEndY; by++) {
for (int bx = x; bx < blockEndX; bx++) {
resultImage.setRGB(bx, by, pixelColor);
}
}
}
}
g2d.dispose();
// 保存结果
String format = outputPath.substring(outputPath.lastIndexOf(".") + 1);
ImageIO.write(resultImage, format, new File(outputPath));
System.out.println("马赛克处理完成!");
}
}
改进版马赛克(使用像素平均值)
/**
* 改进版马赛克 - 使用块内像素平均值
*/
public static void addMosaicAdvanced(String sourcePath, String outputPath,
int startX, int startY,
int width, int height,
int blockSize) throws IOException {
File inputFile = new File(sourcePath);
BufferedImage originalImage = ImageIO.read(inputFile);
int imageWidth = originalImage.getWidth();
int imageHeight = originalImage.getHeight();
BufferedImage resultImage = new BufferedImage(
imageWidth, imageHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = resultImage.createGraphics();
g2d.drawImage(originalImage, 0, 0, null);
int endX = Math.min(startX + width, imageWidth);
int endY = Math.min(startY + height, imageHeight);
for (int y = startY; y < endY; y += blockSize) {
for (int x = startX; x < endX; x += blockSize) {
int blockEndX = Math.min(x + blockSize, endX);
int blockEndY = Math.min(y + blockSize, endY);
// 计算块内像素平均值
long sumRed = 0, sumGreen = 0, sumBlue = 0;
int pixelCount = 0;
for (int by = y; by < blockEndY; by++) {
for (int bx = x; bx < blockEndX; bx++) {
Color pixelColor = new Color(originalImage.getRGB(bx, by));
sumRed += pixelColor.getRed();
sumGreen += pixelColor.getGreen();
sumBlue += pixelColor.getBlue();
pixelCount++;
}
}
// 计算平均色
int avgRed = (int)(sumRed / pixelCount);
int avgGreen = (int)(sumGreen / pixelCount);
int avgBlue = (int)(sumBlue / pixelCount);
Color avgColor = new Color(avgRed, avgGreen, avgBlue);
// 应用平均色
for (int by = y; by < blockEndY; by++) {
for (int bx = x; bx < blockEndX; bx++) {
resultImage.setRGB(bx, by, avgColor.getRGB());
}
}
}
}
g2d.dispose();
String format = outputPath.substring(outputPath.lastIndexOf(".") + 1);
ImageIO.write(resultImage, format, new File(outputPath));
}
完整的测试类
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
public class MosaicDemo extends JFrame {
private JTextField sourcePathField;
private JTextField outputPathField;
private JSpinner blockSizeSpinner;
private JSpinner startXSpinner;
private JSpinner startYSpinner;
private JSpinner widthSpinner;
private JSpinner heightSpinner;
public MosaicDemo() {
setTitle("图片马赛克工具");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
// 源文件选择
gbc.gridx = 0; gbc.gridy = 0;
add(new JLabel("源图片路径:"), gbc);
gbc.gridx = 1;
sourcePathField = new JTextField(30);
add(sourcePathField, gbc);
gbc.gridx = 2;
JButton browseButton = new JButton("浏览");
browseButton.addActionListener(e -> chooseFile(sourcePathField));
add(browseButton, gbc);
// 输出文件路径
gbc.gridx = 0; gbc.gridy = 1;
add(new JLabel("输出图片路径:"), gbc);
gbc.gridx = 1;
outputPathField = new JTextField(30);
add(outputPathField, gbc);
// 马赛克参数
gbc.gridx = 0; gbc.gridy = 2;
add(new JLabel("马赛克块大小:"), gbc);
gbc.gridx = 1;
blockSizeSpinner = new JSpinner(new SpinnerNumberModel(10, 2, 50, 1));
add(blockSizeSpinner, gbc);
gbc.gridx = 0; gbc.gridy = 3;
add(new JLabel("起始X坐标:"), gbc);
gbc.gridx = 1;
startXSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 2000, 10));
add(startXSpinner, gbc);
gbc.gridx = 0; gbc.gridy = 4;
add(new JLabel("起始Y坐标:"), gbc);
gbc.gridx = 1;
startYSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 2000, 10));
add(startYSpinner, gbc);
gbc.gridx = 0; gbc.gridy = 5;
add(new JLabel("马赛克宽度:"), gbc);
gbc.gridx = 1;
widthSpinner = new JSpinner(new SpinnerNumberModel(200, 10, 2000, 10));
add(widthSpinner, gbc);
gbc.gridx = 0; gbc.gridy = 6;
add(new JLabel("马赛克高度:"), gbc);
gbc.gridx = 1;
heightSpinner = new JSpinner(new SpinnerNumberModel(200, 10, 2000, 10));
add(heightSpinner, gbc);
// 处理按钮
gbc.gridx = 0; gbc.gridy = 7; gbc.gridwidth = 3;
JButton processButton = new JButton("处理图片");
processButton.addActionListener(e -> processImage());
processButton.setPreferredSize(new Dimension(200, 40));
add(processButton, gbc);
pack();
setLocationRelativeTo(null);
}
private void chooseFile(JTextField textField) {
JFileChooser fileChooser = new JFileChooser();
if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
textField.setText(fileChooser.getSelectedFile().getAbsolutePath());
}
}
private void processImage() {
try {
String sourcePath = sourcePathField.getText();
String outputPath = outputPathField.getText();
if (sourcePath.isEmpty() || outputPath.isEmpty()) {
JOptionPane.showMessageDialog(this, "请选择源文件和输出路径!");
return;
}
int blockSize = (int) blockSizeSpinner.getValue();
int startX = (int) startXSpinner.getValue();
int startY = (int) startYSpinner.getValue();
int width = (int) widthSpinner.getValue();
int height = (int) heightSpinner.getValue();
// 使用改进版马赛克
ImageMosaicTool.addMosaicAdvanced(
sourcePath, outputPath, startX, startY, width, height, blockSize
);
JOptionPane.showMessageDialog(this, "图片处理完成!");
} catch (Exception ex) {
JOptionPane.showMessageDialog(this,
"处理失败:" + ex.getMessage(),
"错误",
JOptionPane.ERROR_MESSAGE);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new MosaicDemo().setVisible(true);
});
}
}
使用方法
// 命令行使用方式
public class Main {
public static void main(String[] args) {
try {
// 基本用法
ImageMosaicTool.addMosaic(
"input.jpg", // 源图片
"output.jpg", // 输出图片
100, 100, // 起始位置 (x, y)
300, 200, // 马赛克区域大小 (宽, 高)
15 // 马赛克块大小
);
// 高级用法(使用像素平均)
ImageMosaicTool.addMosaicAdvanced(
"input.jpg",
"output.jpg",
100, 100,
300, 200,
15
);
} catch (IOException e) {
e.printStackTrace();
}
// 启动GUI界面
// MosaicDemo.main(args);
}
}
功能特点
- 基础马赛克:获取块中心像素颜色并填充整个块
- 高级马赛克:计算块内所有像素的平均颜色,效果更平滑
- 可配置参数:起始位置、大小、块大小均可调整
- GUI界面:提供友好的图形界面操作
- 错误处理:完善的边界检查和异常处理
这个实现涵盖了马赛克的核心功能,可以根据实际需求调整块大小和位置,实现不同程度的马赛克效果。