30
votes

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();
    }
4
I think this might be my exact problem: stackoverflow.com/questions/5859876/… It's not on the desire, but also on an HTC phone - Mark
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

4 Answers

58
votes

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);
    }
}
0
votes

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);
    }
}
0
votes

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)
            }
        }
})
0
votes

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)
 {

 }
}