4

i'm creating a BufferedImage and i'm trying to include it to a MimeBodyPart as follows:

BufferedImage img=generateQR(otp);
messageBodyPart = new MimeBodyPart();
File test = new File("phill.png");
ImageIO.write(img, "png", test);
DataSource fds = new FileDataSource(test);
messageBodyPart.setDataHandler(new DataHandler(fds));
messageBodyPart.setFileName("./phill.png");
messageBodyPart.setHeader("Content-ID", "<image>");
multipart.addBodyPart(messageBodyPart);
test.delete();

Is there any way to attach a BufferedImage without creating a File?

Please assume that

  • generateQR() exists
  • There is an HTML MimeBodyPart
TT.
  • 15,774
  • 6
  • 47
  • 88
Phill Alexakis
  • 1,449
  • 1
  • 12
  • 31
  • 1
    You can [`write`](https://docs.oracle.com/javase/7/docs/api/javax/imageio/ImageIO.html#write(java.awt.image.RenderedImage,%20java.lang.String,%20java.io.OutputStream)) the image data to any `OutputStream`, e.g. to a [`ByteArrayOutputStream`](https://docs.oracle.com/javase/7/docs/api/java/io/ByteArrayOutputStream.html), and then use the bytes written (to memory) as you like. – JimmyB Aug 08 '19 at 12:25
  • @JimmyB How will the bytes be attached to the `MimeBodyPart` though? :/ – Phill Alexakis Aug 08 '19 at 12:28
  • Check https://stackoverflow.com/questions/34009587/send-email-with-javax-mail-using-an-existing-inputstream-as-attachment-content – JimmyB Aug 08 '19 at 12:35
  • @PhillAlexakis, maybe use [ByteArrayDataSource](https://docs.oracle.com/javaee/5/api/javax/mail/util/ByteArrayDataSource.html) instead of `FileDataSource`? – uaraven Aug 08 '19 at 12:36
  • @uaraven yes, it worked perfectly, thanks! – Phill Alexakis Aug 08 '19 at 13:58
  • 1
    @JimmyB you are correct , thank you also! – Phill Alexakis Aug 08 '19 at 13:59

1 Answers1

5

As suggested, you may get the bytes from your image, and use the according datasource.

This is based on the questions :

Java- Convert bufferedimage to byte[] without writing to disk

and

javamail problem: how to attach file without creating file

You may end up with something like :

byte[] imageBytes = ((DataBufferByte) img.getData().getDataBuffer()).getData();

ByteArrayDataSource bds = new ByteArrayDataSource(imageBytes, "image/png"); 
messageBodyPart.setDataHandler(new DataHandler(bds)); 
messageBodyPart.setFileName("./phill.png");
messageBodyPart.setHeader("Content-ID", "<image>");
multipart.addBodyPart(messageBodyPart);

Edit :

As the databuffer may not always be a DataBufferByte, you may put the image data in a byte array that way :

Replace

byte[] imageBytes = ((DataBufferByte) img.getData().getDataBuffer()).getData();

with the following operations :

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(img, "png", baos);
baos.flush();
byte[] imageBytes= baos.toByteArray();
baos.close();

(example inspired from How I can convert BufferedImage to a byte array without using files)

Arnaud
  • 17,229
  • 3
  • 31
  • 44
  • i think `img.getData().getBuffer()` returns `DataBufferInt`, and i'm getting a `java.awt.image.DataBufferInt cannot be cast to java.awt.image.DataBufferByte at SendEmailSMTP.sendEmail(SendEmailSMTP.java:46)` because of the casting – Phill Alexakis Aug 08 '19 at 13:28
  • `ImageIO.write()` is creating a local png isn't it? – Phill Alexakis Aug 08 '19 at 13:44
  • 1
    Not a local file here, it writes to the outputstream you want, in this case it is an in-memory "stream" . – Arnaud Aug 08 '19 at 13:45
  • right i'm sorry i didn't see you were writing to a `ByteArrayOutputStream` – Phill Alexakis Aug 08 '19 at 13:47
  • 1
    The first proposed solution will only work if&when the image's data buffer already contains PNG encoded data. This cannot be expected because the image may never have been a PNG before. `ImageIO.write()` is the only reliable way to ensure you get a certain format of image data. – JimmyB Aug 09 '19 at 10:00