3

I am trying to convert and compress an image taken from a filepath on android to be converted with base64's gzip (i am using this because my desktop version, written in java, is doing the same). Here is what I have currently for compression:

Bitmap bm = BitmapFactory.decodeFile(imagePath);              
ByteArrayOutputStream baos = new ByteArrayOutputStream();     
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);           
byte[] data = baos.toByteArray();                                                               
String base64Str = null;                                      

ByteArrayOutputStream out_bytes = new ByteArrayOutputStream();
OutputStream out = new Base64.OutputStream(out_bytes);

try {
    out.write(data);
    out.close();                                                         
    byte[] encoded = out_bytes.toByteArray();                 

    base64Str = Base64.encodeBytes(encoded, Base64.GZIP);     
    baos.close();                                             
} catch (Exception e) {}
Vnge
  • 1,295
  • 25
  • 49

1 Answers1

4

This is what your code currently does:

//1. Decode data from image file
Bitmap bm = BitmapFactory.decodeFile(imagePath);
...
//2. Compress decoded image data to JPEG format with max quality
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
...
//3. Encode compressed image data to base64
out.write(data);
...
//4. Compress to gzip format, before encoding gzipped data to base64
base64Str = Base64.encodeBytes(encoded, Base64.GZIP);

I don't know how your desktop version does it, but step 3 is unnecessary since you are doing the same thing as part of step 4.

(Removed part of answer)

EDIT: The following code will read the bytes from the file, gzip the bytes and encode them to base64. It works on all readable files smaller than 2 GB. The bytes passed in to Base64.encodeBytes will be the same bytes as in the file, so no information is lost (as opposed to the code above, where you convert the data to JPEG format first).

/*
 * imagePath has changed name to path, as the file doesn't have to be an image.
 */
File file = new File(path);
long length = file.length();
BufferedInputStream bis = null;
try {
    bis = new BufferedInputStream(new FileInputStream(file));
    if(length > Integer.MAX_VALUE) {
        throw new IOException("File must be smaller than 2 GB.");
    }
    byte[] data = new byte[(int)length];
    //Read bytes from file
    bis.read(data);
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if(bis != null)
        try { bis.close(); }
        catch(IOException e) {}
}
//Gzip and encode to base64
String base64Str = Base64.encodeBytes(data, Base64.GZIP);

EDIT2: This should decode the base64 String and write the decoded data to a file:

    //outputPath is the path to the destination file.

    //Decode base64 String (automatically detects and decompresses gzip)
    byte[] data = Base64.decode(base64str);
    FileOutputStream fos = null;
    try {
        fos = new FileOutputStream(outputPath);
        //Write data to file
        fos.write(data);
    } catch(IOException e) {
        e.printStackTrace();
    } finally {
        if(fos != null)
            try { fos.close(); }
            catch(IOException e) {}
    }
Lone nebula
  • 4,768
  • 2
  • 16
  • 16
  • My desktop version does about the same, using a buffered image and using ImageIO. This is exactly what I am looking for. I guess I was looking at a range of possible solutions, not knowing what to use and what not to use. Thanks a bunch! This works for what I need. – Vnge May 06 '13 at 03:39
  • also what do you mean by: By the way, the original image data could often be more compressed than the max quality JPEG version. In such cases, you'll get a shorter base64 String if you use Base64.encodeBytes(data, Base64.GZIP) directly on the original image data. – Vnge May 06 '13 at 03:41
  • @Vnge Let's say you pick a PNG image. If this image has few colors in it, the file size will be small. When you convert it to JPEG format, you'll end up with more bytes than what is stored in the image file. In such cases, you would get a shorter base64 `String` if you were to do step 4 directly on the PNG-formatted data instead of decoding it and compressing to JPEG first. Also, no information is lost if you do it that way. – Lone nebula May 06 '13 at 11:34
  • would it be possible to provide an example of the base64 before step 4? and would i be able to do it with other images as well for that step? – Vnge May 06 '13 at 14:26
  • @Vnge The encoding and decoding should work on both android and a regular computer. – Lone nebula May 07 '13 at 23:26
  • thats what i thought. I tested out the encoding and it works very well. I just didnt know if there was a different way to decode. thanks for your help! – Vnge May 07 '13 at 23:34