我正在尝试制作一个简单的程序来“像素化”图像。 (使它们看起来像8位图)。基本上,它是如何工作的:循环遍历给定目录中的图像,为新的“像素”尺寸要求宽度的百分比,然后“像素化”图像。它通过遍历每个新的“像素”并找到该正方形区域的平均颜色并将其保存为2D颜色数组来做到这一点。然后,它遍历2D数组,并在新图像上绘制正确的“像素”大小的矩形。
我在某些像素中存在透明度问题,这很重要,因为我希望能够处理具有透明背景的PNG文件。这是前后图片的样子: Before和After。显然,居中图像之后的像素仍然应该是透明的。我观察到了每个“像素”的颜色,它表明某些像素是透明的,即使它们在图片的右下角以黑色填充。这是我的整个班级:
package pixelator;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import javax.imageio.ImageIO;
public class Pixelator {
public static void main(String[] args) throws IOException{
Scanner scan = new Scanner(System.in);
File folder = new File(args[0]);
File[] files = folder.listFiles();
if(files.length == 0) {
System.out.println("No files in given directory.");
}
for(int i = 0; i < files.length; i ++) {
if(filterFile(files[i])) {
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
img = ImageIO.read(files[i]);
System.out.println("File: " + files[i].getName());
System.out.print("Enter pixelated size percentage(out of 100): ");
double percent = scan.nextDouble();
img = pixelate(img, percent);
File toWrite = new File(args[1] + "\\pixelated_" + files[i].getName());
ImageIO.write(img, files[i].getName().substring(files[i].getName().indexOf(".") + 1, files[i].getName().length()), toWrite);
System.out.println("New image saved");
}
}
}
/**
* returns a pixelated version of the original image with the pixels being the given percent
* if the image's size. Compensates for size of image.
* @param img
* @param percent
* @return BufferedImage
*/
public static BufferedImage pixelate(BufferedImage img, double percent) {
//find the number of pixels in the new "pixel"
int newPixelSize = (int)((percent/100.0) * img.getWidth());
int width = newPixelSize * (img.getWidth() / newPixelSize);
int height = newPixelSize * (img.getHeight() / newPixelSize);
System.out.println("Old Width: " + img.getWidth() + "\nOld Height: " + img.getHeight());
System.out.println("New pixel size: " + newPixelSize + "\nNew Width: " + width + "\nnew Height: " + height);
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Color[][] pixelArray = new Color[height / newPixelSize][width / newPixelSize];
for(int i = 0; i < pixelArray.length; i ++) {
for(int j = 0; j < pixelArray[0].length; j ++) {
pixelArray[i][j] = findColorAtPixelCoordinates(i, j, newPixelSize, img);
}
}
for(int i = 0; i < pixelArray.length; i ++) {
for(int j = 0; j < pixelArray[0].length; j ++) {
newImage = setNewImagePixel(i, j, newPixelSize, newImage, pixelArray[i][j]);
}
}
return newImage;
}
/**
* gets the average color over a certain rectangle on the original image
* @param y
* @param x
* @param pixelSize
* @param img
* @return
*/
public static Color findColorAtPixelCoordinates(int y, int x, int pixelSize, BufferedImage img) {
int[] averageARGB = {0, 0, 0, 0};
x = x * pixelSize;
y = y * pixelSize;
//loop through a certain "pixel" contained in the img, adding all of the values to the array
for(int i = y; i < y + pixelSize; i ++) {
for(int j = x; j < x + pixelSize; j++) {
Color colorAtPixel = new Color(img.getRGB(j, i), true);
averageARGB[0] += colorAtPixel.getRed();
averageARGB[1] += colorAtPixel.getGreen();
averageARGB[2] += colorAtPixel.getBlue();
averageARGB[3] += colorAtPixel.getAlpha();
}
}
//calculate the averages
averageARGB[0] = averageARGB[0] / (pixelSize * pixelSize);
averageARGB[1] = averageARGB[1] / (pixelSize * pixelSize);
averageARGB[2] = averageARGB[2] / (pixelSize * pixelSize);
averageARGB[3] = averageARGB[3] / (pixelSize * pixelSize);
return new Color(averageARGB[0], averageARGB[1], averageARGB[2], averageARGB[3]);
}
/**
* sets a new "pixel" rectangle for the new image. Also prints out each new "pixels: coordinates and color
* for testing
* @param y
* @param x
* @param pixelSize
* @param newImage
* @param color
* @return
*/
public static BufferedImage setNewImagePixel(int y, int x, int pixelSize, BufferedImage newImage, Color color) {
System.out.println("Row: "+ y + ", Column: " + x + ", Color: [" + color.getRed() + ", " + color.getGreen() + ", " + color.getBlue() + ", " + color.getAlpha()+"]");
x = x * pixelSize;
y = y * pixelSize;
// get the graphics then fill the rect with the right color
Graphics2D g = (Graphics2D) newImage.getGraphics();
g.setColor(color);
g.fillRect(x, y, x + pixelSize, y + pixelSize);
return newImage;
}
/**
* return true if the image is a png or jpg file
* @param fileName
* @return boolean
*/
public static boolean filterFile(File fileName) {
//System.out.println(fileName.substring(fileName.indexOf("."), fileName.length()));
if(!fileName.isFile()) {
return false;
}
return fileName.getName().substring(fileName.getName().indexOf("."), fileName.getName().length()).equals(".jpg") ||
fileName.getName().substring(fileName.getName().indexOf("."), fileName.getName().length()).equals(".jpeg") ||
fileName.getName().substring(fileName.getName().indexOf("."), fileName.getName().length()).equals(".png");
}
}
感谢您提供的任何帮助!
答案 0 :(得分:0)
您做错的第一件事是在函数setNewImagePixel
中:
g.fillRect(x, y, x+pixelSize, y+pixelSize);
您提供的是右下角,而不是提供宽度和高度,因此请使用
进行更正g.fillRect(x, y, pixelSize, pixelSize);
另一件事是,您不应该平均函数findColorAtPixelCoordinates
中的alpha分量。您应该将其写为
Color color = new Color(img.getRGB(x, y), true);
averageARGB[3] = color.getAlpha();