Android calls the Camera class and adds watermarks to pictures and saves them to the SD card

Hello everyone, I am learning Android recently and would like to share some of the results I have learned~~~

Go directly to the code:

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;


public class PhotoTakeActivity extends AppCompatActivity {
    private boolean isPreview = false;//Whether it is in preview state, false means not in preview state
    private Camera camera; //Define a camera object
    private Button bt1; //Photo button
    private Button bt2;//Preview button
    //------------------------------------------------Add watermark
    Bitmap realBitmap;//The real photo after synthesis
    TextView textView;//used to display location information
    String str0;//Save the location information, the text to be added to the photo, that is, the watermark
    String str1;//Save the location information, the text to be added to the photo, that is, the watermark
    String str2;//Save the location information, the text to be added to the photo, that is, the watermark
    String str3;//Save the location information, the text to be added to the photo, that is, the watermark
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_takephotos);
        bt1 = findViewById(R.id.bt1); //Photo button
        bt2 = findViewById(R.id.bt2);//Preview button
        textView = findViewById(R.id.textView);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//Set full screen display
        if (!android.os.Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            Toast.makeText(this, "Please install SD card", Toast.LENGTH_LONG).show();
        }//Determine whether the mobile phone has an SD card installed
        //Location
        LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
        //Code for permission checking
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED & amp; & amp; ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            // ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            // public void onRequestPermissionsResult(int requestCode, String[] permissions,
            // int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        locationManager.requestLocationUpdates(
                LocationManager.GPS_PROVIDER,//Specify the provider of GPS positioning
                1000,//Interval time
                1,//position interval is 1 meter
                new LocationListener() {//Listen to whether the GPS positioning information changes
                    @Override
                    public void onLocationChanged(Location location) {//Method called when GPS positioning information changes

                    }

                    public void onStatusChanged(String provider, int status, Bundle extras) {//Method called when the GPS positioning status changes

                    }

                    public void onProviderEnabled(String provider) {//Called when the positioning provider starts

                    }

                    public void onProviderDisabled(String provider) {//Triggered when the positioning provider is closed
                        throw new RuntimeException("Stub!");
                    }
                }
        );
        //Get the latest positioning information
        Location location = locationManager.getLastKnownLocation((LocationManager.GPS_PROVIDER));
        locationUpdates(location);//Pass the latest location information to this method

        //Open the camera and preview
        SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surfaceview); //Used to display camera preview
        SurfaceHolder surfaceHolder = surfaceView.getHolder();//Get SurfaceHolder
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//Set SurfaceView to maintain its own buffer
        bt2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (!isPreview)//It is now a non-preview state
                {
                    camera = Camera.open();//Open the camera
                    isPreview = true; //Set to preview state
                }
                try {
                    camera.setPreviewDisplay(surfaceHolder);//Set the SurfaceView used to display the preview
                    Camera.Parameters parameters = camera.getParameters();//Get camera parameters
                    parameters.setPictureFormat(PixelFormat.JPEG);//Set the picture to a JPG picture
                    parameters.set("jpeg-quality", 80);//Set the quality of the picture
                    camera.setParameters(parameters);//Reset camera parameters
                    camera.startPreview();//Start preview
                    camera.autoFocus(null);//Set auto focus
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        //Get the photo button to implement the photo function
        bt1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (camera != null) {
                    camera.takePicture(null, null, jpeg); // Take pictures
                }
            }
        });
    }

    //Get the latitude and longitude
    public void locationUpdates(Location location) {
        if (location != null)//location is used to obtain location information
        {
            StringBuilder stringBuilder = new StringBuilder();//Create a string builder to record positioning information
            stringBuilder.append("Your location is:\\
");
            stringBuilder.append("Longitude:");
            stringBuilder.append(location.getLongitude());
            stringBuilder.append("\\
Dimension:");
            stringBuilder.append(location.getLatitude());
            stringBuilder.append("\\
Altitude:");
            stringBuilder.append(location.getAltitude());
            str0 = "Your location is:";
            str1 = "Longitude:" + location.getLongitude();
            str2 = "Latitude:" + location.getLatitude();
            str3 = "Altitude:" + location.getAltitude();
            textView.setText(stringBuilder.toString());//Display on the page
        } else {
            textView.setText("No GPS information obtained");
        }
    }

    //Camera
    final Camera.PictureCallback jpeg = new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] bytes, Camera camera) {
            Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);//Create a bitmap based on the data obtained from the photo
            camera.stopPreview();//Stop preview
            isPreview = false; //Set to non-preview state
            realBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(realBitmap);
            Paint paint = new Paint();
            paint.setColor(Color.YELLOW);
            paint.setTextSize(90);
            paint.setAntiAlias(true);
            canvas.drawBitmap(bitmap, 0, 0, null);
            canvas.save();
            Canvas canvas1 = new Canvas(realBitmap);
            canvas1.drawText(str0, realBitmap.getWidth() / 2, realBitmap.getHeight() / 2, paint);
            canvas1.drawText(str1, realBitmap.getWidth() / 2, realBitmap.getHeight() / 2 + 100, paint);
            canvas1.drawText(str2, realBitmap.getWidth() / 2, realBitmap.getHeight() / 2 + 200, paint);
            canvas1.drawText(str3, realBitmap.getWidth() / 2, realBitmap.getHeight() / 2 + 300, paint);
            canvas1.save();
       
            //Get the location where photos are saved in the SD card
            File appDir = new File(Environment.getExternalStorageDirectory(), "/DCIM/Camera/");
            if (!appDir.exists()) {
                appDir.mkdir(); //Create the directory if it does not exist
            }
            String fileName = System.currentTimeMillis() + ".jpg";//Set the current system time to the photo name
            File file = new File(appDir, fileName);//Create file object
            try {//Save the captured picture
                FileOutputStream fos = new FileOutputStream(file);//Create a file output stream object
                realBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);//Compress the image content into JPEG format and output it to the output stream
                //bitmap.compress(Bitmap.CompressFormat.JPEG,100,fos);//Compress the image content into JPEG format and output it to the output stream
                fos.flush();//Write all the data in the buffer to the output stream
                fos.close();//Close the file output stream object

            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

            //Insert the photo into the system gallery
            try {
                MediaStore.Images.Media.insertImage(PhotoTakeActivity.this.getContentResolver(), file.getAbsolutePath(), fileName, null);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }

            //Final notification gallery update
            PhotoTakeActivity.this.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + "")));
            Toast.makeText(PhotoTakeActivity.this, "Save photos to:" + file, Toast.LENGTH_LONG).show();
            resetCamera();//Reset camera preview
        }
    };

    private void resetCamera() {
        if (!isPreview) {
            camera.startPreview();//Start preview
            isPreview = true;
        }
    }

    protected void onPause() {
        super.onPause();
        //Stop preview and release camera resources
        if (camera != null) {
            camera.stopPreview();//Stop preview
            camera.release();//Release resources
        }
    }
}

Finally, let’s summarize the pitfalls I encountered: (1) If the drawing coordinates passed in by Bitmap’s drawText method are (0,0), the watermark will definitely not be displayed because it is drawn elsewhere, so to be conservative, If you set the coordinates to half the width and height of the Bitmap and draw it, you will definitely be able to see it. (2) Bitmap must be created through the Bitmap.createBitmap() method in order for the pixels to be changeable. Only Bitmaps with changeable pixels can be passed into the Canvas object.