Search code examples
androidandroid-storage

Storing Bitmap to jpg in Android using WRITE_EXTERNAL_STORAGE


I am looking forward for an Android application Paint , which displays an preview of image . I want to store that drawn image in JPEG or PNG format into my external or internal storage of my device. please help me with this Following is code for MainActitvity.java file:

package ai.fritz.tflitedemo;

import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.io.*;
import java.util.*;
import java.util.Map;
import android.os.Environment;
import java.io.File;
import android.Manifest;
import android.app.Activity;
import android.support.v4.app.ActivityCompat;

import ai.fritz.tflitedemo.ml.DigitsDetector;
import ai.fritz.tflitedemo.ui.PaintView;
import butterknife.BindView;
import butterknife.ButterKnife;



public class MainActivity extends AppCompatActivity {
private final String TAG = this.getClass().getSimpleName();
private static final int PIXEL_WIDTH = 28;
private DigitsDetector mnistClassifier;

@BindView(R.id.button_detect)
View detectButton;

@BindView(R.id.button_clear)
View clearButton;

@BindView(R.id.text_result)
TextView mResultText;

@BindView(R.id.paintView)
PaintView paintView;

@BindView(R.id.preview_image)
ImageView previewImage;

@BindView(R.id.inference_preview)
LinearLayout inferencePreview;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    setTitle(R.string.app_name);
    ButterKnife.bind(this);

    ActivityCompat.requestPermissions(MainActivity.this,new String[] 
  {Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
    mnistClassifier = new DigitsDetector(this);

    DisplayMetrics metrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(metrics);
    paintView.init(metrics);

    detectButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            onDetectClicked();
        }
    });

    clearButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            onClearClicked();
        }
    });
}


private void onDetectClicked() {
    inferencePreview.setVisibility(View.VISIBLE);
    Bitmap scaledBitmap = Bitmap.createScaledBitmap(paintView.getBitmap(), PIXEL_WIDTH, PIXEL_WIDTH, false);
    int digit = mnistClassifier.classify(scaledBitmap);
    previewImage.setImageBitmap(scaledBitmap);

    SaveImage(scaledBitmap);
    if (digit >= 0) {
        Log.d(TAG, "Found Digit = " + digit);
        mResultText.setText(getString(R.string.found_digits, String.valueOf(digit)));
    } else {
        mResultText.setText(getString(R.string.not_detected));
    }
}
private void SaveImage(Bitmap finalBitmap) {

    File root = Environment.getExternalStorageDirectory();
    //Path path = FileSystems.getDefault().getPath("logs", "access.log");
    File myDir = new File(root+"/saved_images");
    Log.d("root",myDir.toString());
    if (!myDir.exists()) {
        myDir.mkdirs();
    }
    Random generator = new Random();
    int n = 10000;
    n = generator.nextInt(n);
    String fname = "Image-"+ n +".jpg";
    File file = new File (myDir, fname);
    if (file.exists ())
        file.delete ();
    try {
        FileOutputStream out = new FileOutputStream(file);
        finalBitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
        out.flush();
        out.close();

    } catch (Exception e) {
        e.printStackTrace();
    }
}
private void onClearClicked() {
    mResultText.setText("");
    paintView.clear();
}
 }

Here is the code for permission access:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

It throws error stating cannot find the source of the file

java.io.FileNotFoundException: /storage/emulated/0/saved_images/Image- 
6131.jpg: open failed: ENOENT (No such file or directory)

. But the preview works fine.

I want to store the drawn image as jpg file .

Thanks in advance


Solution

  • For Android 8+ you need both READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE

    Ask permissions:

    private static final int REQUEST_STORAGE = 1111;
    
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
      if ((checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) || (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) {
    requestPermissions(new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_STORAGE);
      }
    }
    

    And here you will get the result:

    @TargetApi(23)
        @Override
        public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            switch (requestCode) {
                case REQUEST_STORAGE: {
                    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        //Toast.makeText(getBaseContext(), getResources().getString(R.string.permission_ok), Toast.LENGTH_SHORT).show();
                        recreate();                 
                    } else {
                        AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.AlertDialogCustom));
                        builder.setTitle(getResources().getString(R.string.assign_permissions));
                        builder.setMessage(getResources().getString(R.string.permissions_denied));
                        builder.setPositiveButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
    
                                finish();
                                dialog.dismiss();
    
                            }
                        });
                        builder.show();
                    }
                    break;
                }
            }
    
        }