Попытка нарисовать изображение с помощью букв ASCII, но мое изображение получается повернутым

Я пытаюсь сделать ASCII Art из изображения, но по какой-то причине вывод всегда поворачивается, и я несколько раз просматривал свой код, и я просто не могу найти ошибку. Я предполагаю, что это как-то связано с imageWidth и imageHeight, но все это выглядит хорошо для меня..

Код можно найти на GitHub

4 ответа

Нарисуйте ASCII Art из изображения

Предположим, что один персонаж занимает площадь 21×8пикселей. Итак, сначала вам нужно получить средний цвет этой области, затем получить среднюю яркость этого цвета, а затем преобразовать ее в символ.

Исходное изображение:

Изображение ASCII:


      public static void main(String[] args) throws IOException {
    // assume that one character occupies an area of 21×8 pixels
    char[][] chars = readImage("/tmp/image.jpg", 21, 8);
    writeToFile("/tmp/image.txt", chars);
}

static char[][] readImage(String path, int scaleH, int scaleW) throws IOException {
    BufferedImage image = ImageIO.read(new File("/tmp/image.jpg"));
    int height = image.getHeight() / scaleH;
    int width = image.getWidth() / scaleW;
    char[][] chars = new char[height][width];
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            // scaling image and accumulating colors
            int colorRGB = 0;
            for (int k = 0; k < scaleH; k++)
                for (int p = 0; p < scaleW; p++)
                    colorRGB += image.getRGB(j * scaleW + p, i * scaleH + k);
            // get the average color
            Color color = new Color(colorRGB / (scaleH * scaleW));
            // read the R, G, B values of the color and get the average brightness
            int brightness = (color.getRed() + color.getGreen() + color.getBlue()) / 3;
            // get a character depending on the brightness value
            chars[i][j] = getDensity(brightness);
        }
    }
    return chars;
}

static final String DENSITY =
        "\"`^\\\",:;Il!i~+_-?][}{1)(|\\\\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$\"";

static char getDensity(int value) {
    // Since we don't have 255 characters, we have to get the char using percentages
    int charValue = (int) Math.round(DENSITY.length() / 255.0 * value);
    charValue = Math.max(charValue, 0);
    charValue = Math.min(charValue, DENSITY.length() - 1);
    return DENSITY.charAt(charValue);
}

static void writeToFile(String path, char[][] chars) throws IOException {
    FileWriter writer = new FileWriter(path);
    for (char[] row : chars) {
        String str = String.valueOf(row);
        writer.append(str).write("\n");
        System.out.println(str);
    }
    writer.flush();
    writer.close();
}

Выход:

      hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
hhhhhhhhhhhhhfpCmQbU%pCZJJhhhhhhhhhhhhh
hhhhhhhhhhhh00qh"""""""hWLUuhhhhhhhhhhh
hhhhhhhhhhbw"""""""""""""""cthhhhhhhhhh
hhhhhhhhhhZ"""""""""""""""""Ohhhhhhhhhh
hhhhhhhhhhJ"""""""""""""""""whhhhhhhhhh
hhhhhhhhhh\bw"""""""""""""wQChhhhhhhhhh
hhhhhhhhhhhhzJ"""""""""""pCUhhhhhhhhhhh
hhhhhhhhkL|XZa"""""""""""wtYXYohhhhhhhh
hhhhhhnjz8"""""""""""""""""""*J0hhhhhhh
hhhhhZL%"""""""""""""""""""""""hruhhhhh
hhhh0U"""""""""""""""""""""""""""0Ohhhh
hhhuq"""""""""""""""""""""""""""""Jzhhh

Создание карт плотности и яркости символов

Вы можете создать собственную карту плотности символов из любого диапазона символов, а затем, поскольку плотности распределены неравномерно, преобразовать ее в карту яркости и далее вызыватьceilingEntryа такжеfloorEntryметоды.

Сначала нарисуйте каждый символ как черно-белую картинку, используяjava.awtупаковать и подсчитать количество пикселей — получится карта плотности . Затем для каждой записи с этой карты рассчитайте процент яркости на шкале 0-255- вы получаете карту яркости .

Картинки:

Код:

      public static void main(String[] args) {
  Font font = new Font(Font.MONOSPACED, Font.PLAIN, 22);
  // ASCII characters: 0 - 255
  // Runic: 0x16A0 - 0x16FF
  // Box Drawing: 0x2500 - 0x257F
  // Block Elements: 0x2580 - 0x259F
  // Geometric Shapes: 0x25A0 - 0x25FF
  // Hiragana: 0x3040 - 0x309F
  TreeMap<Integer, List<String>> density = getDensityMap(font,0x25A0,0x25FF,0);
  // the map of brightness of pixels [0, 255]
  TreeMap<Integer, List<String>> brightness = getBrightnessMap(density);
  // output, geometric shapes
  for (List<String> value : brightness.values()) System.out.print(value.get(0));
  // ◙◘■▩●▦▣◚◛◕▨▧◉▤◐◒▮◍◑▼▪◤▬◗◭◖◈◎◮◊◫▰◄◯□▯▷▫▽◹△◁▸▭◅▵◌▱▹▿◠◃◦◟◞◜
}

/**
 * @param density character density map
 * @return the pixel brightness map [0, 255],
 * based on percentages of character density
 */
static TreeMap<Integer, List<String>> getBrightnessMap(
        TreeMap<Integer, List<String>> density) {
  int max = density.lastKey(); // maximum density
  TreeMap<Integer, List<String>> brightness = new TreeMap<>();
  for (Map.Entry<Integer, List<String>> entry : density.entrySet()) {
    // pixel brightness, based on the percentage of character density
    int key = (int) Math.round(255.0 - entry.getKey() * 255.0 / max);
    List<String> value = entry.getValue();
    List<String> val = brightness.remove(key);
    if (val == null) val = new ArrayList<>();
    val.addAll(value);
    brightness.put(key, val);
  }
  return brightness;
}

/**
 * @param f   font to render text
 * @param min character codepoint range, lower bound
 * @param max character codepoint range, upper bound
 * @param pd  padding as a precaution, in most cases 0
 * @return the character density map:
 * key - density, value - list of characters
 */
static TreeMap<Integer, List<String>> getDensityMap(
        Font f, int min, int max, int pd) {
  // key - density, value - list of characters
  TreeMap<Integer, List<String>> density = new TreeMap<>();
  for (int i = min; i <= max; i++) {
    // printable characters
    if (f.canDisplay(i) && Character.isDefined(i)
          && !Character.isISOControl(i)
          && !Character.isIdentifierIgnorable(i)) {
      String str = String.valueOf(Character.toChars(i));
      int key = getDensity(str, f, pd);
      List<String> list = density.remove(key);
      if (list == null) list = new ArrayList<>();
      list.add(str);
      density.put(key, list);
    }
  }
  return density;
}

/**
 * @param text source text to draw
 * @param f    font to render text
 * @param pd   padding as a precaution, in most cases 0
 * @return the density of the characters in this text
 */
static int getDensity(String text, Font f, int pd) {
  FontRenderContext ctx = new FontRenderContext(f.getTransform(), false, false);
  Rectangle bounds = f.getStringBounds(text, ctx).getBounds();
  int width = bounds.width + pd * 2;
  int height = bounds.height + pd * 2;
  BufferedImage image =
          new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);
  Graphics2D graphics = (Graphics2D) image.getGraphics();
  graphics.setFont(f);
  graphics.drawString(text, pd + bounds.x, pd - bounds.y);
  //ImageIO.write(image, "png", new File("text.png"));
  int density = 0;
  for (int i = 0; i < height; i++)
    for (int j = 0; j < width; j++)
      if (image.getRGB(j, i) == 0xFFFFFFFF)
        density++;
  return density;
}

В ImageWriting.java, строка 34:

this.writer.append(Density.DENSITY.getDensityFor(this.brightnessValues[j][i]));

Я сильно подозреваю, что вы проходите через одну координату в каком-то цикле, а другой цикл вложен внутрь. (Не буду гнаться за кодом на другом сайте.)

Попробуйте поменять местами вложение циклы или порядок доступа к элементу по индексам массива (заменяя фрагмент кода с или что-то подобное в зависимости от того, какой у вас есть на другом сайте, за которым я не буду гнаться).

Другие вопросы по тегам