Подтвердить что ты не робот

Формат Java BufferedImage для PNG Base64 String

Я пытаюсь получить вывод скриншота в качестве кодированной в base64 строки, но не очень далеко. Код, который я использовал до сих пор, использует библиотеку Base64 (http://iharder.sourceforge.net/current/java/base64/):

    Robot robot = new Robot();
    Rectangle r = new Rectangle( Toolkit.getDefaultToolkit().getScreenSize() );
    BufferedImage bi = robot.createScreenCapture(r);
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    OutputStream b64 = new Base64.OutputStream(os);
    ImageIO.write(bi, "png", os);
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    out.writeTo(b64);
    String result = out.toString("UTF-8");

Каждый раз, когда я запускаю это, "результат" всегда является пустой строкой, но я не понимаю, почему. Любые идеи?

Примечание. Я не хочу писать png в файл на диске.

4b9b3361

Ответ 1

Я последовал за ответом xehpuk, но имел проблемы с определенными изображениями, имеющими последние несколько строк пикселей, отсутствующих при визуализации в некоторых браузерах через URL-адрес данных (Chrome и Firefox, Safari казалось, делали их прекрасными). Я подозреваю, что это связано с тем, что браузер делает все возможное для интерпретации данных, но последние несколько байтов данных отсутствуют, поэтому он показывает, что он может.

Похоже, что причиной этой проблемы является обертка выходного потока. Документация для Base64.wrap(OutputStream os) объясняет:

Рекомендуется немедленно закрыть возвращаемый выходной поток после использования, в течение которого он будет очищать все возможные оставшиеся байты до основного потока вывода.

Таким образом, в зависимости от длины данных возможно, что последние несколько байтов не сбрасываются из потока, потому что close() не вызывается на него. Моим решением было не беспокоиться об обертывании потока и просто закодировать поток напрямую:

public static String imgToBase64String(final RenderedImage img, final String formatName)
{
  final ByteArrayOutputStream os = new ByteArrayOutputStream();

  try
  {
    ImageIO.write(img, formatName, os);
    return Base64.getEncoder().encodeToString(os.toByteArray());
  }
  catch (final IOException ioe)
  {
    throw new UncheckedIOException(ioe);
  }
}

Это разрешило проблемы с отсутствующими рядами пикселей при визуализации в браузере.

Ответ 2

Следующее утверждение работает в неправильном направлении:

out.writeTo(b64);

Он перезаписывает данные Base 64 пустым массивом байтов out.

Какова цель out в любом случае? Я не думаю, что вам это нужно.

Update:

И вы пишете изображение непосредственно на os вместо записи через кодировщик Base 64.

Следующий код должен работать:

...
ByteArrayOutputStream os = new ByteArrayOutputStream();
OutputStream b64 = new Base64.OutputStream(os);
ImageIO.write(bi, "png", b64);
String result = os.toString("UTF-8");

Ответ 3

Base64 кодирование и декодирование изображений с использованием Java 8:

public static String imgToBase64String(final RenderedImage img, final String formatName) {
    final ByteArrayOutputStream os = new ByteArrayOutputStream();
    try {
        ImageIO.write(img, formatName, Base64.getEncoder().wrap(os));
        return os.toString(StandardCharsets.ISO_8859_1.name());
    } catch (final IOException ioe) {
        throw new UncheckedIOException(ioe);
    }
}

public static BufferedImage base64StringToImg(final String base64String) {
    try {
        return ImageIO.read(new ByteArrayInputStream(Base64.getDecoder().decode(base64String)));
    } catch (final IOException ioe) {
        throw new UncheckedIOException(ioe);
    }
}

Используйте его так, как показано на скриншоте:

final Robot robot = new Robot();
final Rectangle r = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
final BufferedImage bi = robot.createScreenCapture(r);
final String base64String = imgToBase64String(bi, "png");