web-dev-qa-db-fra.com

Java BufferedImage au format PNG Chaîne Base64

J'essaie d'obtenir une sortie de capture d'écran sous forme de chaîne codée en base64, mais je ne vais pas très loin. Le code que j'ai jusqu'à présent utilise une bibliothèque 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");

Chaque fois que je lance ceci, "résultat" est toujours une chaîne vide mais je ne comprends pas pourquoi. Des idées?

Remarque: je ne veux pas avoir à écrire le png dans un fichier sur le disque.

19
user72003

J'ai suivi réponse de xehpuk mais j'ai eu des problèmes avec certaines images ayant les dernières lignes de pixels manquantes lors du rendu dans certains navigateurs via une URL de données (Chrome et Firefox, Safari semblait les rendre bien). Je soupçonne que c'est parce que le navigateur fait, il est préférable d'interpréter les données, mais les derniers octets de données manquaient donc cela montre ce qu'il peut.

L'encapsulage du flux de sortie semble être la cause de ce problème. La documentation de Base64.wrap(OutputStream os) explique:

Il est recommandé de fermer rapidement le flux de sortie renvoyé après utilisation, pendant lequel il videra tous les octets restants possibles dans le flux de sortie sous-jacent.

Ainsi, selon la longueur des données, il est possible que les derniers octets ne soient pas vidés du flux car close() n'y est pas appelé. Ma solution à cela était de ne pas prendre la peine d'envelopper le flux et de simplement encoder le flux directement:

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);
  }
}

Cela a résolu les problèmes avec les lignes de pixels manquantes lors du rendu dans un navigateur.

9
Robert Hunt

L'instruction suivante fonctionne dans la mauvaise direction:

out.writeTo(b64);

Il écrase les données Base 64 avec le tableau d'octets vide de out.

Quel est le but de out de toute façon? Je ne pense pas que vous en ayez besoin.

Mise à jour:

Et vous écrivez l'image directement dans os au lieu d'écrire via l'encodeur Base 64.

Le code suivant devrait fonctionner:

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

Encodage et décodage Base64 d'images en utilisant 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);
    }
}

Utilisez-le comme ceci pour votre scénario de capture d'écran:

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

Cela fonctionne pour moi:

Encoder l'image en chaîne 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;
}

Décoder la chaîne Base64 en image

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;
}
0