Decompressing Bitmap from Base64 and GZIP - java

In my application I get a profile picture for user then I save it to a serialized class as string.
I do the GZIP compress and Base64 using the code below, but I can not do the reverse thing as you see in the getProfilePicture() method further down:
private void saveBitmap(){
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
mBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream.toByteArray();
String bitmapContent = "";
try {
bitmapContent = FileHelpers.compressAndBase64(byteArray);
//later save it...
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "Error converting bitmap to gzip and base64");
}
}
public static String compressAndBase64(byte[] byteArray)
throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream zos = new GZIPOutputStream(baos);
zos.write(byteArray);
zos.close();
byte[] bytes = baos.toByteArray();
return Base64.encodeToString(bytes, Base64.DEFAULT);
}
Now I want to convert it back to Bitmap...but so far I didn't succeed to.
The steps are decoding back the string from Base64 to byte array then decompress the byte array and convert to Bitmap.
public Bitmap getProfilePicture(){
if(getProfilePhotoBase64() != null) {
byte[] decoded = Base64.decode(mProfilePhotoBase64.getBytes(), Base64.DEFAULT);
final int BUFFER_SIZE = 32;
ByteArrayInputStream is = new ByteArrayInputStream(decoded);
GZIPInputStream gis = null;
try {
gis = new GZIPInputStream(is, BUFFER_SIZE);
} catch (IOException e) {
e.printStackTrace();
}
StringBuilder string = new StringBuilder();
byte[] data = new byte[BUFFER_SIZE];
int bytesRead;
try {
while ((bytesRead = gis.read(data)) != -1) {
string.append(new String(data, 0, bytesRead));
}
} catch (IOException e) {
e.printStackTrace();
}
try {
gis.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
byte[] byteArray = string.toString().getBytes();
Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0,byteArray.length);
if(bitmap != null) {
return bitmap;
} else {
return null;
}
}
return null;
}
This is the error message I get using the code above:
--- SkImageDecoder::Factory returned null
I can do this quite easy in PHP, but its darn hard to make it work in Java!
if(isset($_POST["photo"])) {
$photoContent = $_POST["photo"];
$photo = imap_base64 ($photoContent);
$photo = gzdecode($photo);
$filename = $_POST["username"].".png";
$dir = SITE_ROOT_PATH."/images/".$user."/".$filename;
file_force_contents($dir, $photo);
} else {
$filename = "NO_PROFILE_PHOTO";
}

Ok I managed to fix the problem in this way:
/**
* IMPORTANT NOTE!!!!!!!!!!!!!!
* String is first converted to byte array, then compressed using GZIP and then
* the resulting byte array is encoded to Base64.DEFAULT
* #return
*/
public String getProfilePhotoBase64() {
return mProfilePhotoBase64;
}
public Bitmap getProfilePicture(){
if(getProfilePhotoBase64() != null) {
byte[] decoded = Base64.decode(mProfilePhotoBase64.getBytes(), Base64.DEFAULT);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ByteArrayInputStream bis = new ByteArrayInputStream(decoded);
GZIPInputStream zis = null;
try {
zis = new GZIPInputStream(bis);
byte[] tmpBuffer = new byte[256];
int n;
while ((n = zis.read(tmpBuffer)) >= 0) {
bos.write(tmpBuffer, 0, n);
}
zis.close();
} catch (IOException e) {
e.printStackTrace();
}
Bitmap bitmap = BitmapFactory.decodeByteArray(bos.toByteArray(), 0
, bos.toByteArray().length);
if(bitmap != null) {
return bitmap;
} else {
return null;
}
}
return null;
}

And what is the problem exactly? compressAndBase64() will return an empty string as boas.toByteArray() will return 0 bytes as boas is just created and hence empty. You don't need to create a boas. Just change
return Base64.encodeToString(bytes, Base64.DEFAULT);
to
return Base64.encodeToString(byteArray, Base64.DEFAULT);

Related

Attempt to get length of null array when encode pdf file

This is my code
public static String convetFiletoString(File f)
{
byte[] bA = null;
try {
InputStream inputStream = new FileInputStream(f);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024 * 11];
int bR;
while ((bR = inputStream.read(b)) != -1) {
bos.write(b, 0, bR);
}
bA = bos.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return Base64.encodeToString(bA, Base64.DEFAULT);
}
I got an exception like this = Attempt to get length of null array
, I checked Uri it working.
The problem is return Base64.encodeToString(bA, Base64.DEFAULT); is outside the try...catch block. This means that if an exception occurs before bA = bos.toByteArray(); then bA will still be null. The most likely solution is to put the return inside the try...catch.

Unable to create checkSum value using SHA-256

As per my requirement I want to create checksum value using SHA-256, from InputStream,
As below:
private InputStream createZipInput(List<ResponsePack> aList, byte[] manifestData)
{
final int bufferSize = 2048;
byte buffer[] = new byte[bufferSize];
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ZipOutputStream zipFileToSend = new ZipOutputStream(byteStream);
LOG.trace("Compressing the file {}");
try
{
for (ResponsePack info : aList)
{
ByteArrayOutputStream byteStreamCheckSum = new ByteArrayOutputStream();
ZipOutputStream zipFileToSendCheckSum = new ZipOutputStream(byteStreamCheckSum);
zipFileToSend.putNextEntry(new ZipEntry(info.getFileName()));
zipFileToSendCheckSum.putNextEntry(new ZipEntry(info.getFileName()));
InputStream in = info.getFileContentStream();
int length;
while ((length = in.read(buffer)) >= 0)
{
zipFileToSend.write(buffer, 0, length);
zipFileToSendCheckSum.write(buffer, 0, length);
}
zipFileToSend.closeEntry();
zipFileToSendCheckSum.closeEntry();
String checksum = validChecksum(byteStreamCheckSum.toByteArray());
LOG.error("Checksum {}", checksum);
zipFileToSendCheckSum.flush();
zipFileToSendCheckSum.close();
}
zipFileToSend.close();
}
catch (IOException e)
{
return e;
}
return new ByteArrayInputStream(byteStream.toByteArray());
}
private static String validChecksum(byte[] dataCopy)
{
printLOG("Byte Array Size {}", dataCopy.length);
try (ZipInputStream zipInputStream = new ZipInputStream(new ByteArrayInputStream(dataCopy)))
{
ZipEntry zipEntry;
MessageDigest digest = DigestUtils.getSha256Digest();
DWriter writer = new DWriter(digest);
while ((zipEntry = zipInputStream.getNextEntry()) != null)
{
org.apache.commons.io.output.ByteArrayOutputStream dest = StreamUtils.extractFileAsByteArrayStream(zipInputStream);
LOG.error("CheckSum Entity creating");
if(zipEntry != null)
{
printLOG("CheckSum Entity file Name {}", zipEntry.getName());
}
LOG.error("Byte array size {}", dest.toByteArray().length);
writer.write(dest.toByteArray());
dest.flush();
dest.close();
}
if (writer.getChecksum() != null)
{
return writer.getChecksum();
}
else
{
return "";
}
}
catch (Exception e)
{
printLOG("Exception encountered while creating checksum: {}", e.getMessage());
return "";
}
}
static class DWriter
{
private final MessageDigest myDigest;
DWriter(MessageDigest digest)
{
myDigest = digest;
}
public void write(byte[] data)
{
myDigest.update(data);
}
public String getChecksum()
{
return new String(Hex.encodeHex(myDigest.digest()));
}
}
But the problem is when I checked the log, found byte array contains value but still checksum always creating for empty string, as below
Byte Array Size 3948
CheckSum Entity creating
CheckSum Entity file Name 20200911104812526.json
Byte array size 20854
Checksum e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Help me where I am doing wrong, due to which I am getting checksum for an empty string
I'm not sure what's wrong with the code but it seems overly complicated: you're writing the input into a zipped stream and the dezip it in memory to read it again.
You don't need to do that: storing the input in a (non-zipped) byte array should be enough.
I think you need to make sure that in.read() works as intended (and that there's actually some data to read).
You get the checksum for a null input and your zip entry is also empty, so it looks like the input was empty. Add some logs or use a debugger to investigate what's happening.
private InputStream createZipInput(List<ResponsePack> aList, byte[] manifestData) {
final int bufferSize = 2048;
byte buffer[] = new byte[bufferSize];
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ZipOutputStream zipFileToSend = new ZipOutputStream(byteStream);
LOG.trace("Compressing the file {}");
try {
for (ResponsePack info : aList) {
ByteArrayOutputStream byteStreamCheckSum = new ByteArrayOutputStream();
zipFileToSend.putNextEntry(new ZipEntry(info.getFileName()));
InputStream in = info.getFileContentStream();
int length;
while ((length = in.read(buffer)) != -1) {
zipFileToSend.write(buffer, 0, length);
byteStreamCheckSum.write(buffer, 0, length);
}
zipFileToSend.closeEntry();
MessageDigest digest = DigestUtils.getSha256Digest();
digest.update(byteStreamCheckSum.toByteArray());
String checksum = new String(Hex.encodeHex(digest.digest()));
LOG.error("Checksum {}", checksum);
}
zipFileToSend.close();
} catch (IOException e) {
throw e;
}
return new ByteArrayInputStream(byteStream.toByteArray());

I have an one ArrayList storing few pdf files location in a directory. How to read the contents of pdf as array of bytes and Zip it

ArrayList is like this - [ Desktop/folder/abc.pdf, Desktop/folder/xyz.pdf ]
I am doing something like this
public byte[] compressByteArray(byte[] bytes){
ByteArrayOutputStream baos = null;
Deflater dfl = new Deflater();
dfl.setLevel(Deflater.BEST_COMPRESSION);
dfl.setInput(bytes);
dfl.finish();
baos = new ByteArrayOutputStream();
byte[] tmp = new byte[4*1024];
try{
while(!dfl.finished()){
int size = dfl.deflate(tmp);
baos.write(tmp, 0, size);
}
} catch (Exception ex){
} finally {
try{
if(baos != null) baos.close();
} catch(Exception ex){}
}
return baos.toByteArray();
}

Convert Byte array to file in chunks

I know that there's a way of converting a file to byte array in chunks, here's a sample code:
InputStream inputStream = new FileInputStream(videoFile);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int bytesRead =0;
while ((bytesRead = inputStream.read(b)) != -1)
{
bos.write(b, 0, bytesRead);
}
I'm looking for the opposite: a way of converting a byte array into a file in chunks. I didn't find any example of doing it in chunks.
You just have to use either the write(byte[]) or write(byte[],int,int) methods from the FileOutputStream class.
byte[] to file:
FileOutputStream fop = null; File file;
try {
file = new File(filePath);
fop = new FileOutputStream(file, true);
fop.write(chunk);
fop.flush();
fop.close();
System.out.println("Done");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fop != null) {
fop.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Try this for file to byte[]:
InputStream is = new FileInputStream(file);
int length = (int) file.length();
int take = 262144;//size of your chunk
byte[] bytes = new byte[take];
int offset=0;
int a = 0;
do {
a = is.read(bytes, 0, take);
offset += a;
//And you can add here each chunk created in to a list, etc, etc.
//encode to base 64 this is extra :)
String str = Base64.encodeToString(bytes, Base64.DEFAULT);
} while (offset < length);=
is.close();
is=null;
Consider generalizing the problem.
This method copies data in chunks:
public static <T extends OutputStream> T copy(InputStream in, T out)
throws IOException {
byte[] buffer = new byte[1024];
for (int r = in.read(buffer); r != -1; r = in.read(buffer)) {
out.write(buffer, 0, r);
}
return out;
}
This can then be used in both reading to and from byte arrays:
try (InputStream in = new FileInputStream("original.txt");
OutputStream out = new FileOutputStream("copy.txt")) {
byte[] contents = copy(in, new ByteArrayOutputStream()).toByteArray();
copy(new ByteArrayInputStream(contents), out);
}

Android : How to read file in bytes?

I am trying to get file content in bytes in Android application. I have get the file in SD card now want to get the selected file in bytes. I googled but no such success. Please help
Below is the code to get files with extension. Through this i get files and show in spinner. On file selection I want to get file in bytes.
private List<String> getListOfFiles(String path) {
File files = new File(path);
FileFilter filter = new FileFilter() {
private final List<String> exts = Arrays.asList("jpeg", "jpg", "png", "bmp", "gif","mp3");
public boolean accept(File pathname) {
String ext;
String path = pathname.getPath();
ext = path.substring(path.lastIndexOf(".") + 1);
return exts.contains(ext);
}
};
final File [] filesFound = files.listFiles(filter);
List<String> list = new ArrayList<String>();
if (filesFound != null && filesFound.length > 0) {
for (File file : filesFound) {
list.add(file.getName());
}
}
return list;
}
here it's a simple:
File file = new File(path);
int size = (int) file.length();
byte[] bytes = new byte[size];
try {
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
buf.read(bytes, 0, bytes.length);
buf.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Add permission in manifest.xml:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
The easiest solution today is to used Apache common io :
http://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/FileUtils.html#readFileToByteArray(java.io.File)
byte bytes[] = FileUtils.readFileToByteArray(photoFile)
The only drawback is to add this dependency in your build.gradle app :
implementation 'commons-io:commons-io:2.5'
+ 1562 Methods count
Since the accepted BufferedInputStream#read isn't guaranteed to read everything, rather than keeping track of the buffer sizes myself, I used this approach:
byte bytes[] = new byte[(int) file.length()];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
DataInputStream dis = new DataInputStream(bis);
dis.readFully(bytes);
Blocks until a full read is complete, and doesn't require extra imports.
Here is a solution that guarantees entire file will be read, that requires no libraries and is efficient:
byte[] fullyReadFileToBytes(File f) throws IOException {
int size = (int) f.length();
byte bytes[] = new byte[size];
byte tmpBuff[] = new byte[size];
FileInputStream fis= new FileInputStream(f);;
try {
int read = fis.read(bytes, 0, size);
if (read < size) {
int remain = size - read;
while (remain > 0) {
read = fis.read(tmpBuff, 0, remain);
System.arraycopy(tmpBuff, 0, bytes, size - remain, read);
remain -= read;
}
}
} catch (IOException e){
throw e;
} finally {
fis.close();
}
return bytes;
}
NOTE: it assumes file size is less than MAX_INT bytes, you can add handling for that if you want.
If you want to use a the openFileInput method from a Context for this, you can use the following code.
This will create a BufferArrayOutputStream and append each byte as it's read from the file to it.
/**
* <p>
* Creates a InputStream for a file using the specified Context
* and returns the Bytes read from the file.
* </p>
*
* #param context The context to use.
* #param file The file to read from.
* #return The array of bytes read from the file, or null if no file was found.
*/
public static byte[] read(Context context, String file) throws IOException {
byte[] ret = null;
if (context != null) {
try {
InputStream inputStream = context.openFileInput(file);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
int nextByte = inputStream.read();
while (nextByte != -1) {
outputStream.write(nextByte);
nextByte = inputStream.read();
}
ret = outputStream.toByteArray();
} catch (FileNotFoundException ignored) { }
}
return ret;
}
In Kotlin you can simply use:
File(path).readBytes()
You can also do it this way:
byte[] getBytes (File file)
{
FileInputStream input = null;
if (file.exists()) try
{
input = new FileInputStream (file);
int len = (int) file.length();
byte[] data = new byte[len];
int count, total = 0;
while ((count = input.read (data, total, len - total)) > 0) total += count;
return data;
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
if (input != null) try
{
input.close();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
return null;
}
A simple InputStream will do
byte[] fileToBytes(File file){
byte[] bytes = new byte[0];
try(FileInputStream inputStream = new FileInputStream(file)) {
bytes = new byte[inputStream.available()];
//noinspection ResultOfMethodCallIgnored
inputStream.read(bytes);
} catch (IOException e) {
e.printStackTrace();
}
return bytes;
}
Following is the working solution to read the entire file in chunks and its efficient solution to read the large files using a scanner class.
try {
FileInputStream fiStream = new FileInputStream(inputFile_name);
Scanner sc = null;
try {
sc = new Scanner(fiStream);
while (sc.hasNextLine()) {
String line = sc.nextLine();
byte[] buf = line.getBytes();
}
} finally {
if (fiStream != null) {
fiStream.close();
}
if (sc != null) {
sc.close();
}
}
}catch (Exception e){
Log.e(TAG, "Exception: " + e.toString());
}
To read a file in bytes, often used to read binary files, such as pictures, sounds, images, etc.
Use the method below.
public static byte[] readFileByBytes(File file) {
byte[] tempBuf = new byte[100];
int byteRead;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
while ((byteRead = bufferedInputStream.read(tempBuf)) != -1) {
byteArrayOutputStream.write(tempBuf, 0, byteRead);
}
bufferedInputStream.close();
return byteArrayOutputStream.toByteArray();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

Categories