ascii_art
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
ascii_art [2023/03/24 10:53] – frchris | ascii_art [2023/03/26 11:36] – [Step 0. Choose an image] frchris | ||
---|---|---|---|
Line 33: | Line 33: | ||
"""" | """" | ||
</ | </ | ||
+ | |||
+ | This Lab is based on one of [[https:// | ||
+ | |||
==== Step 0. Choose an image ==== | ==== Step 0. Choose an image ==== | ||
+ | |||
+ | Choose the first image that you want to convert into ASCII art. It’s good to start with an image around 640x480 or smaller (Of course, you can shrink and crop an image of any size down to this). | ||
+ | |||
+ | Light pixels will be represented by small characters like a dot (.), which leave lots of the background exposed. On the other extreme, dense characters like $ are used to cover up the background. You can easily invert this later. | ||
+ | |||
+ | <code PickPicture.java> | ||
+ | import java.awt.Color; | ||
+ | import java.awt.Font; | ||
+ | import java.awt.Graphics; | ||
+ | import javax.swing.JFrame; | ||
+ | import javax.swing.JPanel; | ||
+ | import java.awt.image.BufferedImage; | ||
+ | import java.io.File; | ||
+ | import java.io.IOException; | ||
+ | import javax.imageio.ImageIO; | ||
+ | import java.awt.*; | ||
+ | /** | ||
+ | | ||
+ | | ||
+ | | ||
+ | */ | ||
+ | public class PickPicture extends JPanel | ||
+ | { | ||
+ | | ||
+ | private String fileName; | ||
+ | private BufferedImage source; | ||
+ | private Font titleFont, regularFont; | ||
+ | |||
+ | public PickPicture(String fileName) | ||
+ | { | ||
+ | titleFont = new Font(" | ||
+ | regularFont = new Font(" | ||
+ | try | ||
+ | { | ||
+ | // the line that reads the image file | ||
+ | this.fileName = fileName; | ||
+ | this.source = ImageIO.read(new File(fileName)); | ||
+ | System.out.println(fileName + " read "); | ||
+ | System.out.println(source.getWidth() + " by " + source.getHeight()); | ||
+ | |||
+ | } | ||
+ | catch (IOException e) | ||
+ | { | ||
+ | System.out.println(" | ||
+ | "Make sure the file is \n 1. In the project folder,\n " + | ||
+ | "2. The file name is perfect-including capital letters\n " + | ||
+ | "3. The extension is right-like .png or .jpg\n " + e); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | public int getWidth() {return source.getWidth(); | ||
+ | public int getHeight() {return source.getHeight(); | ||
+ | | ||
+ | public void paintComponent(Graphics g){ | ||
+ | super.paintComponent(g); | ||
+ | g.setColor(Color.WHITE); | ||
+ | g.fillRect(0, | ||
+ | g.drawImage(source, | ||
+ | g.setColor(Color.BLACK);// | ||
+ | g.setFont(titleFont); | ||
+ | g.drawString(fileName, | ||
+ | g.setFont(regularFont); | ||
+ | g.drawString ( getWidth() + " by " + getHeight(), | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | public static void main(String[] args) { | ||
+ | PickPicture pic= new PickPicture(" | ||
+ | JFrame window = new JFrame(" | ||
+ | window.setSize(pic.getWidth(), | ||
+ | window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | ||
+ | window.getContentPane().add(pic); | ||
+ | window.setVisible(true); | ||
+ | |||
+ | } | ||
+ | |||
+ | } | ||
+ | </ | ||
==== Step 1. Read your image and print its height and width in pixels ==== | ==== Step 1. Read your image and print its height and width in pixels ==== | ||
- | ==== Step 2. Read your image and print its height and width in pixels ==== | ||
- | ==== Step 3. Read your image and print its height and width in pixels ==== | ||
- | ==== Step 4. Read your image and print its height and width in pixels ==== | ||
+ | <code Step1.java> | ||
+ | import java.awt.image.BufferedImage; | ||
+ | import java.io.File; | ||
+ | import java.io.IOException; | ||
+ | import javax.imageio.ImageIO; | ||
+ | |||
+ | public class Step1 | ||
+ | { | ||
+ | private BufferedImage image; | ||
+ | private String fileName; | ||
+ | public Step1(String fileName) | ||
+ | { | ||
+ | try | ||
+ | { | ||
+ | this.fileName = fileName; | ||
+ | image = ImageIO.read(new File(fileName)); | ||
+ | System.out.println(fileName + " read "); | ||
+ | | ||
+ | System.out.println(" | ||
+ | // Print the width and height of the image using a BufferedImage method. | ||
+ | |||
+ | } | ||
+ | catch (IOException e) | ||
+ | { | ||
+ | System.out.println(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | public static void main(String[] args) | ||
+ | { | ||
+ | new Step1(" | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </ | ||
+ | ==== Step 2. Load your image’s pixel data into a 2-dimensional array ==== | ||
+ | <code Step2.java> | ||
+ | |||
+ | import java.awt.image.BufferedImage; | ||
+ | import java.io.File; | ||
+ | import java.io.IOException; | ||
+ | import javax.imageio.ImageIO; | ||
+ | /** | ||
+ | * Start Step2 with this code. | ||
+ | * The image will return a single line of ints that represent color | ||
+ | * and you need to make a 2D Array of Color from it. | ||
+ | * | ||
+ | * @author Chris Thiel, OFMCap | ||
+ | * @version 25 Mar 2023 | ||
+ | */ | ||
+ | public class Step2 | ||
+ | { | ||
+ | private BufferedImage image; | ||
+ | private String fileName; | ||
+ | private int width, | ||
+ | private int[] rgb; // for 8bit RGB packed in an int array | ||
+ | private Color[][] px; | ||
+ | public Step2(String fileName) | ||
+ | { | ||
+ | try | ||
+ | { | ||
+ | // the line that reads the image file | ||
+ | this.fileName = fileName; | ||
+ | image = ImageIO.read(new File(fileName)); | ||
+ | System.out.println(fileName + " read "); | ||
+ | width = image.getWidth(); | ||
+ | height = image.getHeight(); | ||
+ | System.out.println(" | ||
+ | rgb = image.getRGB(0, | ||
+ | System.out.println(rgb.length); | ||
+ | // rgb is a 1D array, with the rows listed one after the other. | ||
+ | ///to convert to a 2D array use something like this: | ||
+ | // grid (x,y) = rgb[ y*width + x]; | ||
+ | // Make a new 2D array of color name px, and fill it from the 1D rgb array | ||
+ | // for example, px[0][0] = new Color ( rgb[0] ); | ||
+ | | ||
+ | |||
+ | } | ||
+ | catch (IOException e) | ||
+ | { | ||
+ | System.out.println(" | ||
+ | } | ||
+ | } | ||
+ | public Color[][] getPx() { return px;} | ||
+ | public static void main(String[] args) | ||
+ | { | ||
+ | new Step2(" | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </ | ||
+ | You can see what your new 2D Array of Color looks like with {{ :: | ||
+ | |||
+ | ==== Step 3. Convert the RGB tuples of your pixels into single brightness numbers | ||
+ | |||
+ | Now that you have a 2D Array of '' | ||
+ | - Average: average the R, G and B values - '' | ||
+ | - Lightness: average the maximum and minimum values out of R, G and B - '' | ||
+ | - Luminance: take a weighted average of the R, G and B values to account for human perception - '' | ||
+ | - Luminosity: Take the sqrt root of the weighted squares - '' | ||
+ | - See [[https:// | ||
+ | <code Step3.java> | ||
+ | import java.awt.Color; | ||
+ | import java.awt.Font; | ||
+ | import java.awt.Graphics; | ||
+ | import javax.swing.JFrame; | ||
+ | import javax.swing.JPanel; | ||
+ | import java.awt.*; | ||
+ | /** | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | */ | ||
+ | public class Step3 extends JPanel | ||
+ | { | ||
+ | |||
+ | private String fileName; | ||
+ | private Font titleFont, regularFont; | ||
+ | private Color[][] clr; | ||
+ | private int[][] brightness; | ||
+ | |||
+ | public Step3(String fileName) | ||
+ | { | ||
+ | this.fileName = fileName; | ||
+ | this.clr = new Step2(fileName).getPx(); | ||
+ | titleFont = new Font(" | ||
+ | regularFont = new Font(" | ||
+ | | ||
+ | // Make a 2D int array that same number of rows and columns | ||
+ | // as the Color array | ||
+ | | ||
+ | |||
+ | | ||
+ | | ||
+ | //Fill the brightness array with yout choice of conversion method | ||
+ | // (like Average, Lightness, Luminocity, or your own) | ||
+ | | ||
+ | |||
+ | |||
+ | } | ||
+ | public int average(Color c) | ||
+ | { | ||
+ | // your code here | ||
+ | } | ||
+ | public int luminance(Color c) | ||
+ | { | ||
+ | // your code here | ||
+ | } | ||
+ | public int lightness(Color c) | ||
+ | { | ||
+ | //your code here | ||
+ | } | ||
+ | public int luminosity(Color c){ | ||
+ | // your code here | ||
+ | } | ||
+ | public int getWidth() { | ||
+ | return brightness.length;// | ||
+ | } | ||
+ | |||
+ | public int getHeight() { | ||
+ | return brightness[0].length; | ||
+ | } | ||
+ | |||
+ | public void paintComponent(Graphics g){ | ||
+ | super.paintComponent(g); | ||
+ | g.setColor(Color.WHITE); | ||
+ | g.fillRect(0, | ||
+ | // | ||
+ | for (int y=0; y < getHeight(); | ||
+ | for(int x=0; x < getWidth(); x++) | ||
+ | { | ||
+ | int b = brightness[x][y]; | ||
+ | g.setColor( new Color(b, | ||
+ | g.fillRect( x, y, 1, 1); | ||
+ | } | ||
+ | |||
+ | g.setColor(Color.BLACK);// | ||
+ | g.setFont(titleFont); | ||
+ | g.drawString(fileName, | ||
+ | g.setFont(regularFont); | ||
+ | g.drawString ( getWidth() + " by " + getHeight() + "- Drawn from 2DColor Array", | ||
+ | |||
+ | } | ||
+ | public int[][] getBrightness() | ||
+ | { | ||
+ | return brightness; | ||
+ | } | ||
+ | public static void main(String[] args) { | ||
+ | Step3 pic= new Step3(" | ||
+ | JFrame window = new JFrame(" | ||
+ | window.setSize(pic.getWidth(), | ||
+ | window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | ||
+ | window.getContentPane().add(pic); | ||
+ | window.setVisible(true); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </ | ||
+ | ==== Step 4. Convert brightness numbers to ASCII characters | ||
+ | You can experiment with different ways to map brightnesses to characters, but a good place to start is the string in the starter code. The characters in it are ordered from thinnest to boldest, which means lightest to darkest. To get started you may wish to use {{ :: | ||
+ | |||
+ | <code Step4.java> | ||
+ | import java.awt.Color; | ||
+ | import java.awt.Font; | ||
+ | import java.awt.Graphics; | ||
+ | import javax.swing.JFrame; | ||
+ | import javax.swing.JPanel; | ||
+ | import java.awt.*; | ||
+ | import java.nio.file.Files; | ||
+ | import java.io.IOException; | ||
+ | import java.nio.file.Paths; | ||
+ | |||
+ | /** | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | */ | ||
+ | public class Step4 | ||
+ | { | ||
+ | |||
+ | private String fileName; | ||
+ | private Font titleFont, regularFont; | ||
+ | |||
+ | private int[][] brightness; | ||
+ | private char[][] ascii; | ||
+ | | ||
+ | |||
+ | public Step4(String fileName) | ||
+ | { | ||
+ | | ||
+ | this.fileName = fileName; | ||
+ | this.brightness = new Step3(fileName).getBrightness(); | ||
+ | titleFont = new Font(" | ||
+ | regularFont = new Font(" | ||
+ | //Make a 2D int array that matched the dimentions of the Brightness array | ||
+ | | ||
+ | ascii = new char[brightness.length][brightness[0].length]; | ||
+ | | ||
+ | //Fill the asciii array with your choice of conversion method | ||
+ | | ||
+ | // your code here | ||
+ | |||
+ | } | ||
+ | /** | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | */ | ||
+ | public char asciiChar( int lightValue) | ||
+ | { | ||
+ | String chars = ""; | ||
+ | int max = chars.length(); | ||
+ | // your code here | ||
+ | } | ||
+ | public int getWidth() { | ||
+ | return brightness.length;// | ||
+ | } | ||
+ | |||
+ | public int getHeight() { | ||
+ | return brightness[0].length; | ||
+ | } | ||
+ | /** | ||
+ | * The ascii array is constructed with a newline " | ||
+ | */ | ||
+ | public String toString(){ | ||
+ | // your code here | ||
+ | } | ||
+ | public void writeToFile() | ||
+ | { | ||
+ | String name = fileName.substring(0, | ||
+ | try { | ||
+ | | ||
+ | } catch (IOException e){ | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | public static void main(String[] args) { | ||
+ | System.out.println(" | ||
+ | Step4 pic= new Step4(" | ||
+ | System.out.println(pic); | ||
+ | pic.writeToFile(); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </ | ||
+ | ==== Step 5. What if it looks your image looks stretched or too big ==== | ||
+ | |||
+ | |||
+ | Characters tend to be three times taller than wide, so you could replace each character with three. If that is too large, you could make one character represent the average of three columns. | ||
- | [[https:// | + | [[https:// |
ascii_art.txt · Last modified: 2023/03/27 10:46 by frchris