web-dev-qa-db-ja.com

Java BufferedImage to PNG format 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をディスク上のファイルに書き込む必要はありません。

19
user72003

私は xehpuk's の回答に従いましたが、特定のブラウザーでデータ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);
  }
}

これにより、ブラウザーでレンダリングしたときに欠落しているピクセルの行に関する問題が解決されました。

9
Robert Hunt

次のステートメントは間違った方向で機能します。

out.writeTo(b64);

Base 64データをoutの空のバイト配列で上書きします。

とにかくoutの目的は何ですか?あなたはそれが必要だとは思わない。

更新:

また、Base 64エンコーダー経由で書き込む代わりに、osに直接イメージを書き込みます。

次のコードが機能するはずです。

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

Java 8を使用した画像のBase64エンコードおよびデコード:

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");
11
xehpuk

これは私にとってはうまくいきます:

画像をBase64文字列にエンコード

public static String encodeToString(BufferedImage image, String type) {
    String imageString = null;
    ByteArrayOutputStream bos = new ByteArrayOutputStream();

    try {
        ImageIO.write(image, type, bos);
        byte[] imageBytes = bos.toByteArray();

        Base64.Encoder encoder = Base64.getEncoder();
        imageString = encoder.encodeToString(imageBytes);

        bos.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return imageString;
}

Base64文字列をイメージにデコード

public static BufferedImage decodeToImage(String imageString) {
    BufferedImage image = null;
    byte[] imageByte;
    try {
        Base64.Decoder decoder = Base64.getDecoder();
        imageByte = decoder.decode(imageString);
        ByteArrayInputStream bis = new ByteArrayInputStream(imageByte);
        image = ImageIO.read(bis);
        bis.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return image;
}