We have a servlet that accepts image uploads. Sometimes when the uploads originate in our iPhone client (flaky connection) the saved image can end up being partly or completely gray. I suspect this is due to the connection being prematurely terminated and the servlet ending up processing an incomplete image.
Whats the best remedy for this? Is there a way to see if the whole image was uploaded before processing? Should I use HTTP Content-Length header and compare whats uploaded with this number?
Thanks!
Some code for context:
#Path("images/")
#POST
#Consumes("image/*")
#Produces({"application/xml", "application/json"})
public AbstractConverter postImage(byte[] imageData) {
BufferedImage bufferedImage = null;
try {
bufferedImage = ImageIO.read(new ByteArrayInputStream(imageData));
} catch (Exception e) {
}
if (bufferedImage == null) {
throw new PlacesException("Image data not provided or could not be parsed", Response.Status.BAD_REQUEST);
}
...
BufferedImage scaledImage = ImageTool.scale(bufferedImage, imageSize);
BufferedImage thumbnail = ImageTool.scale(bufferedImage, thumbnailSize);
//Save image and thumbnail
File outputfile = new File(path);
ImageTool.imageToJpegFile(scaledImage, outputfile, 0.9f);
File tnOutputfile = new File(thumbnailPath);
ImageTool.imageToJpegFile(thumbnail, tnOutputfile, 0.9f);
...
public static void imageToJpegFile(RenderedImage image, File outFile, float compressionQuality) throws IOException {
//Find a jpeg writer
ImageWriter writer = null;
Iterator<ImageWriter> iterator = ImageIO.getImageWritersByFormatName("jpeg");
if (iterator.hasNext()) {
writer = iterator.next();
} else {
throw new RuntimeException("No jpeg writer found");
}
//Set the compression quality
ImageWriteParam params = writer.getDefaultWriteParam();
params.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
params.setCompressionQuality(compressionQuality);
//Write to the out file
ImageOutputStream ios = null;
try {
ios = ImageIO.createImageOutputStream(outFile);
writer.setOutput(ios);
writer.write(null, new IIOImage(image, null, null), params);
} finally {
writer.dispose();
if (ios != null) {
try {
ios.flush();
} catch (Exception e) {
}
try {
ios.close();
} catch (Exception e) {
}
}
}
}
Seems that the upload did not complete properly.
As you point out yourself, your best bet is to use the HTTP Content-Length header to check that all data has been received. If not, discard the image.
Related
When I am using webp files for animated sticker packs it get rejected but if use same files for static stickers it get excepted. After looking all the codes I came to know that this is the last point where those files becomes problematic. But don not know how to identify if webp files stays as animated webp after saving. Please share your thought.
ps: I am using these webp files for whatsapp sticker packs. there is flag "animated_sticker_pack". we have to tell whatsapp that this pack contains only animated webp with proper fomrat. If I set it false then sticker pack get added (let it be static or animated webp). But if I set that flag true then those animated webp get rejected for pack showing error that There's problem with this pack.... So it might be that frames are lesser then it required. It get accepted as static means it might have single frame only.
To avoid issues regarding file type,format,size and all I am using the sample files from WhatsApp sample app
Code:
public static void SaveImage(Bitmap finalBitmap, String name, String identifier) {
String root = path + "/" + identifier;
File myDir = new File(root);
myDir.mkdirs();
String fname = name;
File file = new File(myDir, fname);
if (file.exists()){
file.delete();
}
try {
// FileOutputStream
FileOutputStream out = new FileOutputStream(file);
// Bitmap.compress
finalBitmap.compress(Bitmap.CompressFormat.WEBP, 100, out);
// close
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
////////////////////Other methods before saving images
private Bitmap downloadImageBitmap(String sUrl, String sIdentifier, String sName) {
imageFileName = getLastBitFromUrl(sUrl).replace(".png", ".webp");
identifier = sIdentifier;
name = sName;
Bitmap bitmap = null;
try {
InputStream inputStream = new URL(sUrl).openStream(); // Download Image from URL
bitmap = BitmapFactory.decodeStream(inputStream); // Decode Bitmap
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
#Override
protected Bitmap doInBackground(String... params) {
return downloadImageBitmap(params[0], params[1], params[2]);
}
protected void onPostExecute(Bitmap result) {
SaveImage(result, imageFileName, identifier);
}
You can download and save in doInBackground()
InputStream inputStream = new URL(sUrl).openStream(); // Download Image from URL
FileOutputStream out = new FileOutputStream(file);
Then make a loop where you read bytes in a buffer from input stream and write to output stream.
Don't forget to close all streams when done.
I'm making an Android application that captures images and stores them in the internal memory, but to save the images are compressed and I want to be saved in its original size without any compression.
This is the code I am using to store images, as I do so not me compress ??
ContextWrapper cw = new ContextWrapper(context);
File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
File mypath = new File(directory, "TheChat" + (System.currentTimeMillis()/1000) + "Avatar.jpg");
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(mypath);
bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if (fileOutputStream != null) {
fileOutputStream.flush();
fileOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Save it as a BLOB (bytearray), then reconvert it to a bitmap upon loading it. If it's for internal use only it should work fine. If you're not compressing it at all you might as well save it in a straight-forward format.
I have a Parse Android app for which I am implementing Facebook sign up. Currently I am stuck on grabbing images to set as profile pictures of new ParseUser's. I have successfully used the Facebook Graph API to retrieve the correct URL (I have checked this by plugging it into a browser, where I am shown the right profile picture), but I now need a way to turn that URL into a byte array (byte[]) so that I can save the ParseFile field of our ParseUser's profile picture. I have already looked at all these SO questions:
• java.net.URL read stream to byte[]
• Efficiently read file from URL into byte[] in Java
• Get image with given url and convert it to byte array
None of these have worked. I am currently trying to use the Apache IOutils, like in the solution from the second link. Here is my current code for the AsyncTask:
private class SetProfPicWithURL extends AsyncTask<URL, Integer, byte[]> {
#Override
protected byte[] doInBackground(URL... imageURL) {
Log.i("SetProfPicWithURL", "invocation, URL: " + imageURL[0]);
InputStream is = null;
byte[] bytes = null;
try {
is = imageURL[0].openStream();
bytes = IOUtils.toByteArray(is);
} catch (IOException e) {
e.printStackTrace();
}
finally {
if (is != null) try {
is.close();
if(bytes == null){Log.e("LoginActivity", "bytes is null int SetProfPicWithURL");}
final ParseFile imageFile = new ParseFile("image.jpg", bytes);
imageFile.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
Log.i("LoginActivity", "getCurrentUser.put");
ParseUser.getCurrentUser().put(ParseUtils.PARSE_PROFILE_IMAGE, imageFile);
ParseUser.getCurrentUser().saveInBackground();
} else {
e.printStackTrace();
}
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
return bytes;
}
}
Now when this code executes, I get no error logs, and a ParseFile is created. However, no profile pictures load within the app, and when I click to examine the file in the dashboard, I get this error message:
The file “tfss-0280f98d-7180-4528-9d24-3ec47d3b25d4-image.jpg” could
not be opened because it is empty.
Honestly, I'm at a loss. I've spent significantly more time on this one photo issue than any other part of implementing the Facebook login. And the way our database is set up, it is really not ideal to create another field to save the URL and load with Picasso. Any help with this issue is truly appreciated!
Directly save your imagefile as profile picture like this :
final ParseFile imageFile = new ParseFile("image.jpg", bytes);
ParseUser.getCurrentUser().put(ParseUtils.PARSE_PROFILE_IMAGE, imageFile);
ParseUser.getCurrentUser().saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
Log.i("LoginActivity", "Profile saved succesfully");
} else {
e.printStackTrace();
}
}
});
EDIT :
Use this to get image byte array from url.
try {
java.net.URL img_value = new java.net.URL(imageURL);
Bitmap mIcon = BitmapFactory
.decodeStream(img_value.openConnection()
.getInputStream());
if (mIcon != null)
imgByteArray = encodeToByteArray(mIcon);
} catch (Exception e) {
e.printStackTrace();
}
public byte[] encodeToByteArray(Bitmap image) {
Log.d(TAG, "encodeToByteArray");
Bitmap b= image;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
b.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] imgByteArray = baos.toByteArray();
return imgByteArray ;
}
I already found this nearly similar question on Stackoverflow:
How can I remove metadata from a JPEG image in Java?
But when I use the Method described above, the saved image is being compressed. Is there any way to remove the metadata without compressing the image? Is there any library that I could use in my Java-Program?
Ok, I finaly found a solution by using Apache "commons-imaging":
https://svn.apache.org/repos/asf/commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/examples/WriteExifMetadataExample.java
public void removeExifMetadata(final File jpegImageFile, final File dst)
throws IOException, ImageReadException, ImageWriteException {
OutputStream os = null;
try {
os = new FileOutputStream(dst);
os = new BufferedOutputStream(os);
new ExifRewriter().removeExifMetadata(jpegImageFile, os);
} finally {
if (os != null) {
try {
os.close();
} catch (final IOException e) {
}
}
}
}
I have created an applet jar. That jar contains an images in the following folder
com\common\images\red.bmp
Now, I want to display this image on the Swing Applet.
private static final ImageIcon redIndicator = new ImageIcon("com\\common\\images\\red.bmp");
After that, I have attached the redIndicator to a JPanel but I am not able to see this image.
Any suggestions?
==================================EDITED=========================================
private static final ImageIcon marker = loadImage("com/common/images/scale.jpg");
#SuppressWarnings("unused")
private static ImageIcon loadImage(String imagePath) {
BufferedInputStream imgStream = new BufferedInputStream(TpcHandler.class.getResourceAsStream(imagePath));
int count = 0;
if (imgStream != null) {
byte buf[] = new byte[2400];
try {
count = imgStream.read(buf);
} catch (java.io.IOException ioe) {
return null;
} finally {
if (imgStream != null)
try {
imgStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (count <= 0) {
LOGGER.warning("Empty image file: " + imagePath);
return null;
}
return new ImageIcon(Toolkit.getDefaultToolkit().createImage(buf));
} else {
LOGGER.warning("Couldn't find image file: " + imagePath);
return null;
}
}
I am getting the following exception
java.io.IOException: Stream closed
at line count = imgStream.read(buf);
This should do the trick (if called from a class loaded from that same jar):
new ImageIcon(getClass().getResource("/com/common/images/red.bmp"))
Use YourPanel.class.getResourceAsStream("/com/common/images/red.bmp"), read the stream to a byte[] and construct the ImageIcon based on that. (and don't use bmps - prefer png or jpeg)
Applets and Images that is a frequently asked questions so, as for Java applets and images, I recommend you read one of my previous answers hope it helps a bit :)
Good luck