0

I am trying to make a simple program to "pixelate" images. (make them look like 8 bit drawings). Basically how it works is that it loops through images in a given directory, asks for a percent of the width for a new "pixel" size, and then "pixelates" the image. It does this by looping through each new "pixel" and finding an average color for that square region and saving it to a 2D array of colors. Then it loops through the 2D array and draws rectangles on a new image that are the correct "pixel" size.

I'm having an issue with transparency in some of the pixels, and this is important because I want to be able to work with PNG files with transparent backgrounds. Here is what the before and after pictures look like: Before and After. Obviously, the pixels that come after the centered image should still be transparent. I observed every "pixel"'s color and it shows that some are transparent even though they are being filled in black towards the bottom right of the picture. Here is my whole class:

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


}

Thanks for any help you can provide!

  • One way to get image(s) for an example is to hot link to images seen in [this Q&A](http://stackoverflow.com/q/19209650/418556). E.G. [This answer](https://stackoverflow.com/a/10862262/418556) hot links to an image embedded in [this question](https://stackoverflow.com/q/10861852/418556). – Andrew Thompson Nov 14 '18 at 00:28
  • In `findColorAtPixelCoordinates` you loop over `i,j` but don’t use those variables in the loop body. That’s one obvious bug. But it probably doesn’t cause your main error. – Cris Luengo Nov 14 '18 at 01:04
  • Just fixed that error, didn't change a whole lot besides make it more blurry (which was expected). Didn't fix the main error unfortunately. I also can't post images because my reputation is 1 lol. – Griffin Stout Nov 14 '18 at 01:19
  • *"Just fixed that error.."* Tip: Add @CrisLuengo (or whoever, the `@` is important) to *notify* the person of a new comment. – Andrew Thompson Nov 14 '18 at 12:24

1 Answers1

0

First thing you are doing wrong is in function setNewImagePixel:

g.fillRect(x, y, x+pixelSize, y+pixelSize);

Instead of providing width and height, you are providing bottom right corner, So correct it using

g.fillRect(x, y, pixelSize, pixelSize);

Another thing is you should not average the alpha component in function findColorAtPixelCoordinates. You should write it as

Color color = new Color(img.getRGB(x, y), true);
averageARGB[3] = color.getAlpha();
user8190410
  • 1,264
  • 2
  • 8
  • 15