6
\$\begingroup\$

I wrote a little fractal noise generator the other day, and to test it I wanted to display the dark values with a darker character and the bright values with bright characters (I use a dark background with light foreground). So I wrote a simple java program to do this, and here it is:

package com.loovjo.brightSort;

import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.stream.Collectors;

public class Main {

    private static final int IMG_SIZE = 128;

    public static void main(String[] args) {
        ArrayList<Character> order = new ArrayList<Character>();

        HashMap<Character, Float> brightness = new HashMap<Character, Float>();

        long timer = System.currentTimeMillis();

        int max = 0xFF;

        for (char c = 0; c < max; c++) {
            Character.UnicodeBlock block = Character.UnicodeBlock.of(c);
            if (!(!Character.isISOControl(c)) && c != KeyEvent.CHAR_UNDEFINED && block != null
                && block != Character.UnicodeBlock.SPECIALS)
                // We don't want any unprintables in out gradient.
                continue;

            brightness.put(c, getBrightness(c));
            if (System.currentTimeMillis() - timer > 100) {
                timer = System.currentTimeMillis();
                System.out.println(((float) c / max) * 100 + "% done.");
            }
        }

        // Sort brightness into order

        while (!brightness.isEmpty()) {
            char min = '\0';
            float val = Float.MAX_VALUE;
            for (Entry<Character, Float> e : brightness.entrySet()) {
                if (e.getValue() < val) {
                    val = e.getValue();
                    min = e.getKey();
                }
            }
            brightness.remove(min);
            order.add(min);
        }
        for (int i = 0; i < 10; i++)
            System.out.println(order.stream().map(c -> "" + c).collect(Collectors.joining()));

     }

    private static float getBrightness(char c) {
        BufferedImage img = new BufferedImage(IMG_SIZE, IMG_SIZE, BufferedImage.TYPE_INT_RGB);
        Graphics g = img.getGraphics();
        g.setFont(new Font("Monaco", Font.PLAIN, (int) (img.getHeight() * 0.5)));
        // img.getHeight() * 0.5 because else some of the characters will be
        // rendered off-screen, giving them wierd values

        g.drawString(c + "", 0, g.getFont().getSize());
        g.dispose();

        int totalBrightness = 0;
        for (int x = 0; x < img.getWidth(); x++) {
            for (int y = 0; y < img.getHeight(); y++) {
                totalBrightness += img.getRGB(x, y) & 0xFF;
            }
        }

        return totalBrightness / (float) (img.getWidth() * img.getHeight());
    }

}

For those of you who can't run this program, here's a screenshot of the output: Output

\$\endgroup\$
4
\$\begingroup\$

You may want to separate the logic to determine if a character is printable into a method and rewrite the brightness calculation using streams:

Map<Character, Float> brightness = IntStream.range(0, max)
        .mapToObj(x -> (char) x)
        .filter(Main::isPrintable)
        .collect(toMap(c -> c, Main::getBrightness));

Your sort algorithm is very inefficient, and there isn't a need to write your own. Streams API makes it nice and clean:

List<Character> order = brightness.entrySet().stream()
        .sorted(comparingByValue())
        .map(Map.Entry::getKey)
        .collect(toList());

Above snippets assume static imports

import static java.util.Map.Entry.comparingByValue;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.