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.