I have an image being sent to me through a JSON string. I want to convert that string into an image in my android app and then display that image.
The JSON string looks like this:
"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVI..."
Note: I truncated the string with a ...
I've got a function that (I think) converts the string into an image. Am I doing this right?
public Bitmap ConvertToImage(String image){
try{
InputStream stream = new ByteArrayInputStream(image.getBytes());
Bitmap bitmap = BitmapFactory.decodeStream(stream);
return bitmap;
}
catch (Exception e) {
return null;
}
}
Then I try to display it on my android activity like this
String image = jsonObject.getString("barcode_img");
Bitmap myBitmap = this.ConvertToImage(image);
ImageView cimg = (ImageView)findViewById(R.id.imageView1);
//Now try setting dynamic image
cimg.setImageBitmap(myBitmap);
However, when I do this, nothing shows up. I don't get any errors in the logcat. What am I doing wrong?
Thanks
I'm worried about that you need to decode only the base64 string to get the image bytes, so in your
"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVI..."
string, you must get the data after data:image\/png;base64,, so you get only the image bytes and then decode them:
String imageDataBytes = completeImageData.substring(completeImageData.indexOf(",")+1);
InputStream stream = new ByteArrayInputStream(Base64.decode(imageDataBytes.getBytes(), Base64.DEFAULT));
This is a code so you understand how it works, but if you receive a JSON object it should be done the correct way:
Converting the JSON string to a JSON object.
Extract the String under data key.
Make sure that starts with image/png so you know is a png image.
Make sure that contains base64 string, so you know that data must be decoded.
Decode the data after base64 string to get the image.
InputStream stream = new ByteArrayInputStream(image.getBytes());
should be changed to
InputStream stream = new ByteArrayInputStream(Base64.decode(image.getBytes(), Base64.DEFAULT));
Refer http://developer.android.com/reference/android/util/Base64.html for details on how to do Base64 decoding.
Disclaimer: I have not checked for syntax, but this is how you should do it.
Here is the working code that converts the Base64 encoded inputStream and writes it to the disk.
I spent a few time to make it work correctly. So I hope this helps other developers.
public boolean writeImageToDisk(FileItem item, File imageFile) {
// clear error message
errorMessage = null;
FileOutputStream out = null;
boolean ret = false;
try {
// write thumbnail to output folder
out = createOutputStream(imageFile);
// Copy input stream to output stream
byte[] headerBytes = new byte[22];
InputStream imageStream = item.getInputStream();
imageStream.read(headerBytes);
String header = new String(headerBytes);
// System.out.println(header);
byte[] b = new byte[4 * 1024];
byte[] decoded;
int read = 0;
while ((read = imageStream.read(b)) != -1) {
// System.out.println();
if (Base64.isArrayByteBase64(b)) {
decoded = Base64.decodeBase64(b);
out.write(decoded);
}
}
ret = true;
} catch (IOException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
errorMessage = "error: " + sw;
} finally {
if (out != null) {
try {
out.close();
} catch (Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
System.out.println("Cannot close outputStream after writing file to disk!" + sw.toString());
}
}
}
return ret;
}
/**
* Helper method for the creation of a file output stream.
*
* #param imageFolder
* : folder where images are to be saved.
* #param id
* : id of spcefic image file.
* #return FileOutputStream object prepared to store images.
* #throws FileNotFoundException
*/
protected FileOutputStream createOutputStream(File imageFile) throws FileNotFoundException {
imageFile.getParentFile().mkdirs();
return new FileOutputStream(imageFile);
}
Related
I have encountered the problem to write Base64image data on FTP.
When I write it on local drive, The photo is appeared clearly.
But, When I write it on FTP server, it's appeared like spoiled images.
when I write it on local drive, it's shown like this enter image description here
I have attached the picture on FTP . enter image description here
Here is my code.
private static String testFilesDir = "C:\\Storage";
public String getIncidentPhotoByID(int incident_id, int photoId) {
String base64Image = null;
WebSSLClient client = new WebSSLClient();
Response response =client.createRequest(PropertiesUtil.getOracleCloudRestUrL() + "/mobile/platform/storage/collections/incident_photos_collection/objects/incident_462_03").get();
String jsonResponse = response.readEntity(String.class);
base64Image = jsonResponse;
FTPClient ftp = new FTPClient();
FileInputStream fis = null;
String filename = "incident_462_03";
String[] strings = base64Image.split(",");
String extension;
switch (strings[0]) {//check image's extension
case "data:image/jpeg;base64":
extension = "jpeg";
break;
case "data:image/png;base64":
extension = "png";
break;
default://should write cases for more images types
extension = "jpg";
break;
}
//convert base64 string to binary data
byte[] data1 = Base64.decodeBase64(strings[1]);
/*
String path = testFilesDir+"/"+filename+"."+ extension;
File file = new File(path);
try (OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file))) {
outputStream.write(data1);
} catch (IOException e) {
e.printStackTrace();
} */
try {
ftp.connect("link.myjpl.com");
ftp.login("user", "password");
String path = "Images/test/"+filename+"."+ extension;
OutputStream out1 = ftp.storeFileStream(path);
out1.write(data1);
ftp.logout();
} catch (IOException e) {
e.printStackTrace();
}
return base64Image;
}
}
Try setting the fileType to FTP.BINARY_FILE_TYPE. Also as per the javadocs, to finalize the file transfer you must call completePendingCommand and check its return value to verify success.
See https://commons.apache.org/proper/commons-net/apidocs/org/apache/commons/net/ftp/FTPClient.html#storeFileStream(java.lang.String)
I have an encrypted file that was done using reference from this question .I got the file encrypted.Now my issue is when trying to read the contents out, am getting an empty strings from the returned read(). Below is my call method and the method to decrypt the encrypted text to a string variable.
Calling Method:
File encryptedCFG = new File(homeDir + "/" + folder_name + "/twCGF.txt");
dc.ReadEncryptedFile(encryptedCFG);
Method:
public void ReadEncryptedFile(File deInFile) {
try {
FileInputStream fis = new FileInputStream(deInFile);
int length = (int) deInFile.length();
byte[] filebyte = new byte[length]
// Decrypt the byte contents from the file using the cipher setup
byte[] tmpTxT = mDecipher.doFinal(filebyte);
fis.read(tmpTxT);
fis.close();
// Read into a string since we got the contents
String plaintxt = new String(tmpTxt, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
}
Any pointers why am not getting the contents of the encrypted file correctly?
At the line where you're decrypting the byte array, it's still empty. You haven't read the file in, yet. You have to switch the operations.
byte[] filebyte = new byte[length]
fis.read(filebyte);
byte[] tmpTxt = mDecipher.doFinal(filebyte);
fis.close();
String plaintxt = new String(tmpTxt, "UTF-8");
I have an application where I am generating a "target file" based on a Java "source" class. I want to regenerate the target when the source changes. I have decided the best way to do this would be to get a byte[] of the class contents and calculate a checksum on the byte[].
I am looking for the best way to get the byte[] for a class. This byte[] would be equivalent to the contents of the compiled .class file. Using ObjectOutputStream does not work. The code below generates a byte[] that is much smaller than the byte contents of the class file.
// Incorrect function to calculate the byte[] contents of a Java class
public static final byte[] getClassContents(Class<?> myClass) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try( ObjectOutputStream stream = new ObjectOutputStream(buffer) ) {
stream.writeObject(myClass);
}
// This byte array is much smaller than the contents of the *.class file!!!
byte[] contents = buffer.toByteArray();
return contents;
}
Is there a way to get the byte[] with the identical contents of the *.class file? Calculating the checksum is the easy part, the hard part is obtaining the byte[] contents used to calculate an MD5 or CRC32 checksum.
THis is the solution that I ended up using. I don't know if it's the most efficient implementation, but the following code uses the class loader to get the location of the *.class file and reads its contents. For simplicity, I skipped buffering of the read.
// Function to obtain the byte[] contents of a Java class
public static final byte[] getClassContents(Class<?> myClass) throws IOException {
String path = myClass.getName().replace('.', '/');
String fileName = new StringBuffer(path).append(".class").toString();
URL url = myClass.getClassLoader().getResource(fileName);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try (InputStream stream = url.openConnection().getInputStream()) {
int datum = stream.read();
while( datum != -1) {
buffer.write(datum);
datum = stream.read();
}
}
return buffer.toByteArray();
}
I don't get what you means, but i think you are looking for this, MD5.
To check MD5 of a file, you can use this code
public String getMd5(File file)
{
DigestInputStream stream = null;
try
{
stream = new DigestInputStream(new FileInputStream(file), MessageDigest.getInstance("MD5"));
byte[] buffer = new byte[65536];
read = stream.read(buffer);
while (read >= 1) {
read = stream.read(buffer);
}
}
catch (Exception ignored)
{
int read;
return null;
}
return String.format("%1$032x", new Object[] { new BigInteger(1, stream.getMessageDigest().digest()) });
}
Then, you can store the md5 of a file in any way for exmaple XML. An exmaple of MD5 is 49e6d7e2967d1a471341335c49f46c6c so once the file name and size change, md5 will change. You can store md5 of each file in XML format and next time your run a code to check md5 and compare the md5 of each file in the xml file.
If you really want the contents of the .class file, you should read the contents of .class file, not the byte[] representation that is in memory. So something like
import java.io.*;
public class ReadSelf {
public static void main(String args[]) throws Exception {
Class classInstance = ReadSelf.class;
byte[] bytes = readClass(classInstance);
}
public static byte[] readClass(Class classInstance) throws Exception {
String name = classInstance.getName();
name = name.replaceAll("[.]", "/") + ".class";
System.out.println("Reading this: " + name);
File file = new File(name);
System.out.println("exists: " + file.exists());
return read(file);
}
public static byte[] read(File file) throws Exception {
byte[] data = new byte[(int)file.length()]; // can only read a file of size INT_MAX
DataInputStream inputStream =
new DataInputStream(
new BufferedInputStream(
new FileInputStream(file)));
int total = 0;
int nRead = 0;
try {
while((nRead = inputStream.read(data)) != -1) {
total += nRead;
}
}
finally {
inputStream.close();
}
System.out.println("Read " + total
+ " characters, which should match file length of "
+ file.length() + " characters");
return data;
}
}
I have a method to download image from URL. As like below..
public static byte[] downloadImageFromURL(final String strUrl) {
InputStream in;
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
URL url = new URL(strUrl);
in = new BufferedInputStream(url.openStream());
byte[] buf = new byte[2048];
int n = 0;
while (-1 != (n = in.read(buf))) {
out.write(buf, 0, n);
}
out.close();
in.close();
}
catch (IOException e) {
return null;
}
return out.toByteArray();
}
I have an image url and it is valid. for example.
https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTxfYM-hnD-Z80tgWdIgQKchKe-MXVUfTpCw1R5KkfJlbRbgr3Zcg
My problem is I don't want to download if image is really not exists.Like ....
https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTxfYM-hnD-Z80tgWdIgQKchKe-MXVUfTpCw1R5KkfJlbRbgr3Zcgaaaaabbbbdddddddddddddddddddddddddddd
This image shouldn't be download by my method. So , how can I know the giving image URL is not really exists. I don't want to validate my URL (I think that may not my solution ).
So, I googled for that. From this article ...
How to check if a URL exists or returns 404 with Java? and
Check if file exists on remote server using its URL
But this con.getResponseCode() will always return status code "200". This mean my method will also download invalid image urls. So , I output my bufferStream as like...
System.out.println(in.read(buf));
Invalid image URL produces "43". So , I add these lines of codes in my method.
if (in.read(buf) == 43) {
return null;
}
It is ok. But I don't think that will always satisfy. Has another way to get it ? am I right? I would really appreciate any suggestions. This problem may struct my head. Thanks for reading my question.
*UPDATE
I call this download method and save downloaded image in some directory as..
// call method to save image
FileSupport.saveFile(filePath+".JPG", data);
After that I tried to output as...
File file = new File(filePath+".JPG);
System.err.println(file.length());
that may also produces "43" for invalid image urls. I want to know why that return "43" for all of invalid urls. what is "43" ?
Try this,
Open an image in notepad or something and check the first 3-4 characters, it will tell you the format of the image..
When downloading check the first 3 or 4 characters, that should tell you if this image is valid or not.
Note: Here, I'm assuming that your requirement is specific to certain types of images and not all possible images.
some samples:
‰PNG for PNG images
����JFIF for JPG images.
byte[] tenBytes=new byte[10];
// fill this array with the first 10 bytes.
String str = new String(tenBytes);
if(str.contains("JIFF")){
// JPG
}
if(str.contains("PNG"){
// PNG
} ...
if nothing matches, its either an invalid image or an image you don't want.
Note this is untested code.. you might have to make adjustments for it to work properly. you should look at this as an psuedo code to build your implementation...
Update:
Instead of checking for file size 43, you should be looking for the content (as described above).
If
con.setRequestMethod("HEAD");
does not help you, you should do something like this (read from connection's input strean will fail if the image does not exist.
HttpUrlConnection con = (HttpUrlConnection)url.openConnection;
con.setRequestMethod("GET");
con.addRequestProperty("User-Agent", "Mozilla/4.0");
int responseCode = con.getResponseCode(); //if you do not get 200 here, you can stop
if(responseCode != HttpUrlConnection.HTTP_OK) {
return;
}
// Now, read image buffer
byte[] image = null;
try{
InputStream in = new BufferedInputStream(con.getInputStream());
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int n = 0;
while (-1!=(n=in.read(buf)))
{
out.write(buf, 0, n);
}
out.close();
in.close();
image = out.toByteArray();
} catch (IOException ioe){
// do whatever you need
} finally {
con.disconnect();
}
Also, this code
if (in.read(buf) == 43) {
return null;
}
does not look good. Some magic number, not clear what is it.
This is how I would do it:
//By Nishanth Chandradas
import java.awt.Image;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import javax.activation.MimetypesFileTypeMap;
import javax.swing.ImageIcon;
import java.io.File;
public class downloadimagefromurl {
/**
* #param args
* #throws IOException
*/
public static byte[] downloadImageFromURL(final String strUrl) throws IOException {
InputStream in;
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
URL url = new URL(strUrl);
in = new BufferedInputStream(url.openStream());
byte[] buf = new byte[2048];
int n = 0;
while (-1 != (n = in.read(buf))) {
out.write(buf, 0, n);
}
out.close();
in.close();
}
catch (IOException e) {
return null;
}
byte[] response = out.toByteArray();
FileOutputStream fos = new FileOutputStream("/Users/Nish/Desktop/image.jpg");
fos.write(response);
fos.close();
return response;
}
static boolean isImage(String image_path){
Image image = new ImageIcon(image_path).getImage();
if(image.getWidth(null) == -1){
return false;
}
else{
return true;
}
}
public static void main(String[] args) throws IOException {
downloadImageFromURL("https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTxfYM-hnD-Z80tgWdIgQKchKe-MXVUfTpCw1R5KkfJlbRbgr3Zcg");
System.out.println(isImage("/Users/Nish/Desktop/image.jpg"));
}
The output will be true or false depending if the download was an image or not.
You can add a second catch statement to catch java.io.FileNotFoundException
catch (FileNotFoundException e) {
// Failed
}
Hi i'm new to android and Image encryption.
My scenario is like this,
first I'm encrypting the image file.
Then I'm uploading it to the Server
From my app I'm downloading encrypted image and saving it in SD card.
then I'm decrypting it before set it to the imageView
(See bottom for all need methods I have used..)
But I'm getting javax.crypto.BadPaddingException: pad block corrupted when decrypting. I read some articles about this exception but all are about text encryption. Can you help me to avoid this. Thank you in advance
Image Encrption using ...
private byte[] encrypt(byte[] raw, byte[] clear) throws Exception
{
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
Here I'm saving several other images as well, all saved in sd card successfully...
for (int i = 0; i < imageUrls.size(); i++)
{
File file = new File(imageUrls.get(i));
String metapath = CommonUtils.getDataFromPreferences("metaPath", "");
Log.d("metapath", metapath);
String extStorageDirectory = metapath + file.getName();
File wallpaperDirectory = new File(extStorageDirectory);
if (!wallpaperDirectory.exists() || wallpaperDirectory.length() == 0)
{
new DownloadImagesTask()
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, imageUrls.get(i));
}
}
Toast toast = Toast.makeText(ScratchDetailsActivity.this, "Lottery was purchased and saved to sdcard/E-Lottery",
Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
Image decryption...
decrypt the file here first argument is key and second is encrypted file which we get from SD card.
decrpt = simpleCrypto.decrypt(KEY, getImageFileFromSdCard());
bmpimg2 = BitmapFactory.decodeByteArray(decrpt, 0, decrpt.length);
Drawable d = new BitmapDrawable(getResources(), bmpimg2);
hiddenImage.setImageDrawable(d);
DownloadImageTask..
public class DownloadImagesTask extends AsyncTask<String, Void, InputStream>{
private String fileName;
#Override
protected InputStream doInBackground(String... urls)
{
//Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
return download_Image(urls[0]);
}
#Override
protected void onPostExecute(InputStream result)
{
storeImage(result);
}
private InputStream download_Image(String url)
{
InputStream is = null;
File file = new File(url);
fileName = file.getName();
try
{
URL aURL = new URL(url);
URLConnection conn = aURL.openConnection();
conn.connect();
is = conn.getInputStream();
}
catch (OutOfMemoryError e)
{
Log.e("Hub", "Error getting the image from server : " + e.getMessage().toString());
}
catch (IOException e)
{
Log.e("Hub", "Error getting the image from server : " + e.getMessage().toString());
}
return is;
}
public void storeImage(InputStream is)
{
String extStorageDirectory = CommonUtils.getDataFromPreferences("metaPath", "");
Log.d("extStorageDirectory", extStorageDirectory);
OutputStream outStream = null;
File wallpaperDirectory = new File(extStorageDirectory);
if (!wallpaperDirectory.exists())
{
wallpaperDirectory.mkdirs();
}
File outputFile = new File(wallpaperDirectory, fileName);
if (!outputFile.exists() || outputFile.length() == 0)
{
try
{
outStream = new FileOutputStream(outputFile);
}
catch (FileNotFoundException e1)
{
e1.printStackTrace();
}
try
{
int bytesRead = -1;
byte[] buffer = new byte[4096];
while ((bytesRead = is.read(buffer)) != -1)
{
outStream.write(buffer, 0, bytesRead);
}
outStream.close();
is.close();
Log.d("ScratchActivtiy", "Image Saved");
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}}
getImageFileFromSDCard method
/**
* This method fetch encrypted file which is save in sd card and convert it in byte array after that this file will
* be decrept.
*
* #return byte array of encrypted data for decription.
* #throws FileNotFoundException
*/
public byte[] getImageFileFromSdCard() throws FileNotFoundException
{
byte[] inarry = null;
try
{
String metapath = CommonUtils.getDataFromPreferences("metaPath", "");
File imageFolder = new File(metapath);
File urlFile = new File(selectedLottery.getImage());
for (File f : imageFolder.listFiles())
{
if (urlFile.getName().equals(f.getName()))
metapath = metapath + f.getName();
}
File imageFile = new File(metapath);
//Convert file into array of bytes.
FileInputStream fileInputStream = null;
byte[] bFile = new byte[(int) imageFile.length()];
fileInputStream = new FileInputStream(imageFile);
fileInputStream.read(bFile);
fileInputStream.close();
inarry = bFile;
}
catch (IOException e)
{
Log.d("Exception", e.getMessage());
}
return inarry;
}
There are a lot of things that might cause a Bad Padding exception. Obvious things to check are that for both encryption and decryption you are using:
the same key, that is byte-for-byte the same.
the same encryption mode (CBC, CTR or GCM usually).
the same IV/Nonce, again byte-for-byte the same.
the same padding (PKCS5 or PKCS7 are common).
Do not rely on system defaults, especially when encrypting on one system and decrypting on another, as you seem to be doing. If the system defaults are different, then your decryption will fail. Always explicitly set key, mode, IV and padding. There will be documented ways to do so in any reasonable crypto library.
If that doesn't solve it then you will need to do a bit more digging. Set the decryption method temporarily to NoPadding or whatever equivalent your library uses. That will let the decryption method ignore padding errors, and give you some output. Have a look at the output and compare it to the original input; you may have to look at hex dumps here to be sure what is happening.
Among the possibilities are:
the output is complete garbage: your key is wrong, or the IV/Nonce
is wrong for a stream cypher or GCM mode or CTR mode.
the first block is garbage with the rest matching the plaintext: you
have the wrong IV in CBC mode.
the output matches with some extra stuff at the end: the extra stuff
is padding. Set your decryption method to expect that type of
padding.
If none of these happen, then ask again here, describing the symptoms.
When you have got a solution, you must set your decryption method back to expect the correct padding. Leaving it set to NoPadding is not secure since any old garbage can be added to the decrypted plaintext.