How to upload an image using ByteArrayOutputStream in Vaadin? - java

I want to receive an uploaded image as a byte array (so that it can be inserted into a sql database).
I also want to show the uploaded image as a preview.
I have tried the following code but im not receiving the bytes of the full image. (if i print the byte array it prints only a few characters)
final Embedded preview = new Embedded("Uploaded Image");
preview.setVisible(false);
final Upload upload = new Upload();
upload.setCaption("Image");
// Create upload stream
final ByteArrayOutputStream baos = new ByteArrayOutputStream(); // Stream to write to
upload.setReceiver(new Upload.Receiver() {
#Override
public OutputStream receiveUpload(String filename, String mimeType) {
return baos; // Return the output stream to write to
}
});
upload.addSucceededListener(new Upload.SucceededListener() {
#Override
public void uploadSucceeded(Upload.SucceededEvent succeededEvent) {
final byte[] bytes = baos.toByteArray();
preview.setVisible(true);
preview.setSource(new StreamResource(new StreamResource.StreamSource() {
#Override
public InputStream getStream() {
return new ByteArrayInputStream(bytes);
}
}, ""));
}
});

image.setSource(new StreamResource(new StreamResource.StreamSource() {
#Override
public InputStream getStream() {
return new ByteArrayInputStream(baos.toByteArray());
}
}, ""));

You could try adding a ProgressListener with some logs to the Upload to see what is happening; you will get the amount of read bytes and total content length as a parameter to the updateProgress method so you can see if everything is being sent.

Related

Base 64 Encoded QRGen QR code can't be decoded

Im trying to generate a QR code using QRGen, encode it in Base64 and insert it as an image in an HTML string. Later, the HTML string is decoded to be displayed in a JEditorPane (and then sent to a printer). To this end, the ImageView class is extended and a custom View factory is used. This all works fine... sometimes. It completely depends on the input string. Some strings work without issue, others fail cause the decode process to fail with the error java.lang.IllegalArgumentException: Input byte array has wrong 4-byte ending unit.
Here is the encode process:
public BufferedImage generateQRCodeImage(String barcodeText) throws Exception {
ByteArrayOutputStream stream = QRCode.from(barcodeText).to(ImageType.PNG).stream();
ByteArrayInputStream bis = new ByteArrayInputStream(stream.toByteArray());
return ImageIO.read(bis);
}
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;
}
and the decode process:
private Image loadImage() {
String b64 = getBASE64Image();
BufferedImage newImage = null;
ByteArrayInputStream bais = null;
try {
bais = new ByteArrayInputStream(Base64.getDecoder().decode(b64.getBytes())); //fails here
newImage = ImageIO.read(bais);
} catch (Throwable ex) {
ex.printStackTrace();
}
return newImage;
}
#Override
public URL getImageURL() {
String src = (String) getElement().getAttributes().getAttribute(HTML.Attribute.SRC);
if (isBase64Encoded(src)) {
this.url = BASE64ImageView.class.getProtectionDomain()
.getCodeSource().getLocation();
return this.url;
}
return super.getImageURL();
}
private boolean isBase64Encoded(String src) {
return src != null && src.contains("base64,");
}
private String getBASE64Image() {
String src = (String) getElement().getAttributes().getAttribute(HTML.Attribute.SRC);
if (!isBase64Encoded(src)) {
return null;
}
return src.substring(src.indexOf("base64,") + 7, src.length() - 1);
}
And here is the QR code in question that fails to decode.
<img width='30' height='30' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAH0AAAB9AQAAAACn+1GIAAAApklEQVR4Xu2UMQ4EMQgD/QP+/0vK6zjsvayUMmavWxQpMAUBkwS12wcveAAkgNSCD3rR5Lkgoai3GUCMgWqbAEYR3HxAkZlzU/0MyBisYRsgI1ERFfcpBpA+ze6k56Cj7KTdXNigFWZvSOpsgqLfd18i2aAukXh9TXBNmdWt5gzA/oqzWkkN8HtA7G8CNOwYAiZt3wZixUfkA32OHNQq7Bxs9oI/gC/9fV8AVCkPjQAAAABJRU5ErkJggg=='/>
I did open the above QR in a browser (Chrome) and it does work, which definitely points to something being wrong in the decode process and not the encode process.
Found the issue. In getBASE64Image(), I have
private String getBASE64Image() {
String src = (String) getElement().getAttributes().getAttribute(HTML.Attribute.SRC);
if (!isBase64Encoded(src)) {
return null;
}
return src.substring(src.indexOf("base64,") + 7, src.length() - 1);
}
The "-1" in the substring call was the cause of my problems. Not sure why this would work only sometimes, but removing seems to have fixed the problem.

How to attach custom/existing screenshot in allure report?

Generally, I am using below code to take a screenshot and attach in allure report :
#Attachment(value = "Page Screenshot", type = "image/png")
public static byte[] saveScreenshotPNG(WebDriver driver) {
return ((TakesScreenshot)driver).getScreenshotAs(OutputType.BYTES);
}
But now my need is I have already some screenshot on my desktop and want to attach it with an allure report. is that possible?
You can take the existing image and convert it to byte[]. getScreenshotAs() decodes the screenshot string so you might need to do it as well
Java
#Attachment(value = "Page Screenshot", type = "image/png")
public static byte[] saveScreenshotPNG(String path) {
File file = new File(path);
BufferedImage bufferedImage = ImageIO.read(file);
byte[] image = null;
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
ImageIO.write(bufferedImage, "png", bos);
image = bos.toByteArray();
} catch (Exception e) { }
// if decoding is not necessary just return image
return image != null ? Base64.getMimeDecoder().decode(image) : null;
}
Python
with open(path, 'rb') as image:
file = image.read()
byte_array = bytearray(file)
allure.attach(byte_array, name="Screenshot", attachment_type=AttachmentType.PNG)

Skia error when trying to retrieve a bitmap downloaded from Google Sign-in

So, I am downloading the profile picture from the Google SIgn-in api and I save it to a hidden file. The problem is that when I try to retrieve it, it throws me: D/skia: --- Failed to create image decoder with message 'unimplemented'. However when I retrieve an image from FireBaseStorage and save that one to the hidden file I can retrieve it whithout any problems.
I tried BitmapFactory.decodeByteArray(), but then I had a message telling me skia wasn't able to decode the file and it returned null.
The method I use to retrieve the profile picture and call the method that will save the file
private void getUsersPic() {
Bitmap profilePic;
try {
InputStream in = new URL(AppData.getUser().getPicture()).openConnection().getInputStream();
profilePic = BitmapFactory.decodeStream(in);
int size = profilePic.getRowBytes()*profilePic.getHeight();
ByteBuffer b = ByteBuffer.allocate(size);
byte[] bytes = new byte[size];
profilePic.copyPixelsToBuffer(b);
b.position(0);
b.get(bytes, 0, bytes.length);
SaveBitmapToFile.saveBitmap(bytes , AppData.getUser().getName()+AppData.getUser().getLastName());
} catch(Exception e) {
System.out.println("Get profile pic: "+e.toString());
}
}
Save the file
public static void saveBitmap(byte[] bitmap, String key) {
String path = AppData.getAppContext().getFilesDir()+"/.image"+"/";
File fileDir = new File(path);
if(!fileDir.isDirectory())
fileDir.mkdirs();
try {
File bitmapDir = new File(fileDir+"/"+key);
bitmapDir.createNewFile();
FileOutputStream stream = new FileOutputStream(bitmapDir);
stream.write(bitmap);
stream.close();
} catch (IOException e) {
System.out.println("Problem creating file "+e.toString()+ " Directory: "+fileDir);
}
}
Retrieve and return a bitmap
public static Bitmap getBitmap(String key) {
File file = new File(AppData.getAppContext().getFilesDir()+"/.image/"+key);
try {
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
return BitmapFactory.decodeStream(buf);//BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
} catch(Exception e) {
System.out.println("Exception getting bitmap: "+e.toString());
return null;
}
}
The last method should return a Bitmap and it is doing it. It is just not working when the image comes from the Google Sign-in api.
As pskink said in the comment of the post, I had to use compress() instead of copyPixelToBuffer(). Here is my updated method:
private void getUsersPic() {
Bitmap profilePic;
try {
InputStream in = new URL(AppData.getUser().getPicture()).openConnection().getInputStream();
profilePic = BitmapFactory.decodeStream(in);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
profilePic.compress(Bitmap.CompressFormat.PNG, 100, stream);
SaveBitmapToFile.saveBitmap(stream.toByteArray() , AppData.getUser().getName()+AppData.getUser().getLastName());
} catch(Exception e) {
System.out.println("Get profile pic: "+e.toString());
}
}

How to get a byte [ ] from an OutputStream to retrieve uploaded file

After receiving the uploaded file i want to return a byte[ ] representing the uploaded file i overrode the receiveUpload methode:
/**
* Invoked when a new upload arrives.
*
* #param filename
* the desired filename of the upload, usually as specified
* by the client.
* #param mimeType
* the MIME type of the uploaded file.
* #return Stream to which the uploaded file should be written.
*/
public OutputStream receiveUpload(String filename, String mimeType);
But it returns an OutputStream
Here's the full implementation :
class FileUploaderReceiver implements Receiver{
public File file;
#Override
public OutputStream receiveUpload(String filename,
String mimeType) {
// Create upload stream
OutputStream fos = null; // Stream to write to
try {
// Open the file for writing.
file = new File("/tmp/uploads/" + filename);
fos = new FileOutputStream(file);
} catch (final java.io.FileNotFoundException e) {
new Notification("Could not open file<br/>",
e.getMessage(),
Notification.Type.ERROR_MESSAGE)
.show(Page.getCurrent());
return null;
}
return fos; // Return the output stream to write to
}
So how to get the byte[ ], i know that i can retrieve it using the ByteArrayOutputStream class, but i'am blocked.
Any idea will be appreciated,
Thank you
Wrap the OutputStream with a ByteArrayOutputStream, then use toByteArray().
As kostyan mentioned, you need to use an InputStream (with respect to your method intention). From the InputStream, you can get the bytes, using something like this: http://lasanthals.blogspot.de/2012/09/get-byte-array-from-inputstream.html.
Do note, I provide this as a quick answer, from a quick search, have not tried this one myself.
The problem is how to be notified when the data is fully written to the returned stream.
You can return a ByteArrayOutputStream with overriden close() method. When the stream gets closed, you'll know that the upload was fully written to that stream.
public OutputStream receiveUpload(String filename, String mimeType) {
return new ByteArrayOutputStream() {
#Override
public void close() throws IOException {
byte[] uploadData = toByteArray();
//....
}
};
}

How to decompress a gzipped data in a byte array?

I have a class which has a method that is receiving an object as a parameter.
This method is invoked via RMI.
public RMIClass extends Serializable {
public RMIMethod(MyFile file){
// do stuff
}
}
MyFile has a property called "body", which is a byte array.
public final class MyFile implements Serializable {
private byte[] body = new byte[0];
//....
public byte[] getBody() {
return body;
}
//....
}
This property holds the gzipped data of a file that was parsed by another application.
I need to decompress this byte array before performing further actions with it.
All the examples I see of decompressing gzipped data assume that I want to write it to the disk and create a physical file, which I do not.
How do I do this?
Thanks in advance.
Wrap your byte array with a ByteArrayInputStream and feed it into a GZipInputStream
Look at those samples, and wherever they're using FileOutputStream, use ByteArrayOutputStream instead. Wherever they're using FileInputStream, use ByteArrayInputStream instead. The rest should be simple.
JDK 9+
private byte[] gzipUncompress(byte[] compressedBytes) throws IOException {
try (InputStream inputStream = new GZIPInputStream(new ByteArrayInputStream(compressedBytes))) {
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
inputStream.transferTo(outputStream);
return outputStream.toByteArray();
}
}
}
Why don't you create your own class that extends OutputStream or , whatever is the archive writing to ?
If you want to write to a ByteBuffer you can do this.
private static void uncompress(final byte[] input, final ByteBuffer output) throws IOException
{
final GZIPInputStream inputGzipStream = new GZIPInputStream(new ByteArrayInputStream(input));
Channels.newChannel(inputGzipStream).read(output);
}

Categories