Merge pull request #24622 from alexlyulkov:al/fixed-android-sample-img-save

Fixed problem with saving images in Android sample #24622

Fixes https://github.com/opencv/opencv/issues/24590

Current code for saving images in Android sample worked only on very old phones.
Added support for modern Android versions.

Required:
- https://github.com/opencv/ci-gha-workflow/pull/127
- https://github.com/opencv-infrastructure/opencv-gha-dockerfile/pull/27
This commit is contained in:
alexlyulkov 2023-12-04 15:00:40 +08:00 committed by GitHub
parent 408730b7ab
commit 81656597e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 56 additions and 15 deletions

View File

@ -16,7 +16,7 @@ endif()
set(GRADLE_VERSION "7.6.3" CACHE STRING "Gradle version") set(GRADLE_VERSION "7.6.3" CACHE STRING "Gradle version")
message(STATUS "Gradle version: ${GRADLE_VERSION}") message(STATUS "Gradle version: ${GRADLE_VERSION}")
set(ANDROID_COMPILE_SDK_VERSION "26" CACHE STRING "Android compileSdkVersion") set(ANDROID_COMPILE_SDK_VERSION "31" CACHE STRING "Android compileSdkVersion")
if(ANDROID_NATIVE_API_LEVEL GREATER 21) if(ANDROID_NATIVE_API_LEVEL GREATER 21)
set(ANDROID_MIN_SDK_VERSION "${ANDROID_NATIVE_API_LEVEL}" CACHE STRING "Android minSdkVersion") set(ANDROID_MIN_SDK_VERSION "${ANDROID_NATIVE_API_LEVEL}" CACHE STRING "Android minSdkVersion")
else() else()

View File

@ -157,7 +157,7 @@ def main(args):
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Builds AAR with Java and shared C++ libs from OpenCV SDK") parser = argparse.ArgumentParser(description="Builds AAR with Java and shared C++ libs from OpenCV SDK")
parser.add_argument('opencv_sdk_path') parser.add_argument('opencv_sdk_path')
parser.add_argument('--android_compile_sdk', default="26") parser.add_argument('--android_compile_sdk', default="31")
parser.add_argument('--android_min_sdk', default="21") parser.add_argument('--android_min_sdk', default="21")
parser.add_argument('--android_target_sdk', default="31") parser.add_argument('--android_target_sdk', default="31")
parser.add_argument('--java_version', default="1_8") parser.add_argument('--java_version', default="1_8")

View File

@ -230,9 +230,9 @@ def main(args):
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Builds AAR with static C++ libs from OpenCV SDK") parser = argparse.ArgumentParser(description="Builds AAR with static C++ libs from OpenCV SDK")
parser.add_argument('opencv_sdk_path') parser.add_argument('opencv_sdk_path')
parser.add_argument('--android_compile_sdk', default="26") parser.add_argument('--android_compile_sdk', default="31")
parser.add_argument('--android_min_sdk', default="21") parser.add_argument('--android_min_sdk', default="21")
parser.add_argument('--android_target_sdk', default="26") parser.add_argument('--android_target_sdk', default="31")
parser.add_argument('--java_version', default="1_8") parser.add_argument('--java_version', default="1_8")
parser.add_argument('--ndk_location', default="") parser.add_argument('--ndk_location', default="")
parser.add_argument('--cmake_location', default="") parser.add_argument('--cmake_location', default="")

View File

@ -13,8 +13,11 @@ import org.opencv.android.OpenCVLoader;
import org.opencv.core.Mat; import org.opencv.core.Mat;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2; import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import android.Manifest;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.hardware.Camera.Size; import android.hardware.Camera.Size;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import android.util.Log; import android.util.Log;
@ -177,10 +180,17 @@ public class Tutorial3Activity extends CameraActivity implements CvCameraViewLis
@Override @Override
public boolean onTouch(View v, MotionEvent event) { public boolean onTouch(View v, MotionEvent event) {
Log.i(TAG,"onTouch event"); Log.i(TAG,"onTouch event");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
requestPermissions(permissions, 1);
return false;
}
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
String currentDateandTime = sdf.format(new Date()); String currentDateandTime = sdf.format(new Date());
String fileName = Environment.getExternalStorageDirectory().getPath() + String fileName = "sample_picture_" + currentDateandTime + ".jpg";
"/sample_picture_" + currentDateandTime + ".jpg";
mOpenCvCameraView.takePicture(fileName); mOpenCvCameraView.takePicture(fileName);
Toast.makeText(this, fileName + " saved", Toast.LENGTH_SHORT).show(); Toast.makeText(this, fileName + " saved", Toast.LENGTH_SHORT).show();
return false; return false;

View File

@ -1,14 +1,24 @@
package org.opencv.samples.tutorial3; package org.opencv.samples.tutorial3;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.List; import java.util.List;
import java.util.Objects;
import org.opencv.android.JavaCameraView; import org.opencv.android.JavaCameraView;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera; import android.hardware.Camera;
import android.hardware.Camera.PictureCallback; import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size; import android.hardware.Camera.Size;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log; import android.util.Log;
@ -73,15 +83,36 @@ public class Tutorial3View extends JavaCameraView implements PictureCallback {
mCamera.setPreviewCallback(this); mCamera.setPreviewCallback(this);
// Write the image in a file (in jpeg format) // Write the image in a file (in jpeg format)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
new Thread(new Runnable() {
@Override
public void run() {
ContentResolver resolver = getContext().getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, mPictureFileName);
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
try { try {
FileOutputStream fos = new FileOutputStream(mPictureFileName); OutputStream fos = resolver.openOutputStream(Objects.requireNonNull(imageUri));
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.write(data); Objects.requireNonNull(fos).close();
fos.close();
} catch (java.io.IOException e) { } catch (java.io.IOException e) {
Log.e("PictureDemo", "Exception in photoCallback", e); Log.e("PictureDemo", "Exception in photoCallback", e);
} }
}
}).start();
} else {
mPictureFileName = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getPath()
+ "/" + mPictureFileName;
try {
FileOutputStream fos = new FileOutputStream(mPictureFileName);
fos.write(data);
fos.close();
} catch (java.io.IOException e) {
Log.e("PictureDemo", "Exception in photoCallback", e);
}
}
} }
} }