30

I am developing an application for Android, and part of the application has to takes pictures and save them to the SDcard. The onPictureTaken method returned a byte array with the data of the captured image.

All I need to do is save the byte array into a .jpeg image file. I have attempted to do this with the help of BitmapFactory.decodeByteArray (to get a Bitmap) and then bImage.compress (to an OutputStream), a plain OutputStream, and a BufferedOutputStream. All three of these methods seem to give me the same weird bug. My Android phone (8MP camera and a decent processor), seems to save the photo (size looks correct), but in a corrupted way (the image is sliced and each slice is shifted; or I just get almost horizontal lines of various colors); and The weird thing is, that an Android tablet with a 5MP camera and a fast processor, seems to save the image correctly.

So I thought maybe the processor can't keep up with saving large images, because I got OutOfMemory Exceptions after about 3 pictures (even at compression quality of 40). But then how does the built in Camera app do it, and much faster too? I'm pretty sure (from debug) that the OutputStream writes all the data (bytes) and it should be fine, but it's still corrupted.

***In short, what is the best/fastest way (that works) to save a byte array to a jpeg file?

Thanks in advance, Mark

code I've tried (and some other slight variations):

    try {
        Bitmap image = BitmapFactory.decodeByteArray(args, 0, args.length);
        OutputStream fOut = new FileOutputStream(externalStorageFile);
        long time = System.currentTimeMillis();
        image.compress(Bitmap.CompressFormat.JPEG,
                jpegQuality, fOut);
        System.out.println(System.currentTimeMillis() - time);
        fOut.flush();
        fOut.close();
    } catch (Exception e) {
    }

and

    try {
        externalStorageFile.createNewFile();
        FileOutputStream fos = new FileOutputStream(externalStorageFile);
        fos.write(args);
        fos.flush();
        fos.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
Mark
  • 700
  • 2
  • 7
  • 17
  • have you tried doing this : http://stackoverflow.com/questions/4263375/android-saving-created-bitmap-to-directory-on-sd-card/4264989#4264989 – Quentin DOMMERC Nov 02 '11 at 10:43
  • I think this might be my exact problem: http://stackoverflow.com/questions/5859876/android-jpeg-saved-from-camera-looks-corrupted It's not on the desire, but also on an HTC phone – Mark Nov 02 '11 at 11:05
  • 1
    Yeah, I tried what they did and it seems to be the problem. Now how to fix it... Anyone know how to fix it? Because apps like Paper Camera and Camera ZOOM FX have working preview (they don't distort) and take pictures fine. If not, I guess I either have to have the camera preview distorted, but pictures work; or have the preview look nice, and have it not work on some HTC devices... – Mark Nov 02 '11 at 11:22

4 Answers4

58

All I need to do is save the byte array into a .jpeg image file.

Just write it out to a file. It already is in JPEG format. Here is a sample application demonstrating this. Here is the key piece of code:

class SavePhotoTask extends AsyncTask<byte[], String, String> {
    @Override
    protected String doInBackground(byte[]... jpeg) {
      File photo=new File(Environment.getExternalStorageDirectory(), "photo.jpg");

      if (photo.exists()) {
            photo.delete();
      }

      try {
        FileOutputStream fos=new FileOutputStream(photo.getPath());

        fos.write(jpeg[0]);
        fos.close();
      }
      catch (java.io.IOException e) {
        Log.e("PictureDemo", "Exception in photoCallback", e);
      }

      return(null);
    }
}
CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • This does answer my question, so I will pick it. But if you looked in the comments, I discovered that the problem was not in saving, but that some HTC devices seem to corrupt images when you use "parameters.setPreviewSize" Do you know how to work around or with that bug? Because if I don't set an optimal preview size, then the preview becomes squished and looks a bit weird. – Mark Nov 03 '11 at 08:18
  • @Mark: No clue. You might consider posting a fresh question on that topic. – CommonsWare Nov 03 '11 at 10:27
  • 8
    @CommonsWare i have used your code but i am getting corrupt image file.That means i cann't open file. – Ricky Khatri Dec 29 '12 at 08:29
  • 4
    I almost got fooled by `fos.write(jpeg[0]);` which writes only one byte in the `File`. In this code, you should write `fos.write( jpeg );` to have the whole byte array written. – Sunshinator Aug 22 '16 at 20:05
  • 4
    @TheSunshinator: No. `jpeg` is `byte[]...`, so `jpeg[0]` is a `byte[]`. – CommonsWare Aug 22 '16 at 20:07
  • Really? That's new to me. Then my problem must have been that my function was using a `byte[]` (without ...). Be careful with that. – Sunshinator Aug 22 '16 at 20:16
  • Save my time. Thanks @CommonsWare – Rabindra Acharya Sep 21 '19 at 09:30
  • Lol. Good answer. I was going to answer similarly. Whatn is all the bitmap KungFu for. Just save the data to a file! Probably he got curruption by all of those compression and converting. –  Sep 25 '19 at 22:23
1

Hey this codes for kotlin

camera.addCameraListener(object : CameraListener(){

        override fun onPictureTaken(result: PictureResult) {
            val jpeg = result.data //result.data is a ByteArray!
            val photo = File(Environment.getExternalStorageDirectory(), "/DCIM/androidify.jpg");
            if (photo.exists()) {
                photo.delete();
            }
            try {
                val fos = FileOutputStream(photo.getPath() );
                fos.write(jpeg);
                fos.close();
            }
            catch (e: IOException) {
                Log.e("PictureDemo", "Exception in photoCallback", e)
            }
        }
})
Yasin Aktimur
  • 459
  • 6
  • 9
0

This Code is perfect for saving image in storage, from byte[]... note that "image" here is byte[]....taken as "byte[] image" as a parameter into a function.

    File photo=new File(Environment.getExternalStorageDirectory(), "photo.jpg");

    if (photo.exists()) {
        photo.delete();
    }

    try {
        FileOutputStream fos=new FileOutputStream(photo.getPath());
        Toast.makeText(this, photo.getPath(), Toast.LENGTH_SHORT).show();
        fos.write(image);
        fos.close();
    }
    catch (java.io.IOException e) {
        Log.e("PictureDemo", "Exception in photoCallback", e);
    }
}
Ali Raza
  • 11
  • 1
0

Here's the function to convert byte[] into image.jpg

public void SavePhotoTask(byte [] jpeg){
 File imagesFolder = new File(Environment.getExternalStorageDirectory(), "Life Lapse");
 imagesFolder.mkdirs();

 final File photo= new File(imagesFolder, "name.jpg");
 try
 {
    FileOutputStream fos=new FileOutputStream(photo.getPath());
    fos.write(jpeg);
    fos.close();
 }
 catch(Exception e)
 {

 }
}