[android] 카메라에서 이미지 캡처 및 활동 표시
버튼을 클릭하면 카메라가 열리는 모듈을 작성하고 이미지를 클릭하여 캡처 할 수 있습니다. 이미지가 마음에 들지 않으면 이미지를 삭제하고 하나 이상의 이미지를 클릭 한 다음 이미지를 선택하면 해당 이미지가 다시 표시되어 활동에 해당 이미지가 표시됩니다.
답변
다음은 카메라 앱을 시작한 다음 이미지를 검색하여 표시하는 활동의 예입니다.
package edu.gvsu.cis.masl.camerademo;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
public class MyCameraActivity extends Activity
{
private static final int CAMERA_REQUEST = 1888;
private ImageView imageView;
private static final int MY_CAMERA_PERMISSION_CODE = 100;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
this.imageView = (ImageView)this.findViewById(R.id.imageView1);
Button photoButton = (Button) this.findViewById(R.id.button1);
photoButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
{
requestPermissions(new String[]{Manifest.permission.CAMERA}, MY_CAMERA_PERMISSION_CODE);
}
else
{
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_REQUEST);
}
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
{
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == MY_CAMERA_PERMISSION_CODE)
{
if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
Toast.makeText(this, "camera permission granted", Toast.LENGTH_LONG).show();
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_REQUEST);
}
else
{
Toast.makeText(this, "camera permission denied", Toast.LENGTH_LONG).show();
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (requestCode == CAMERA_REQUEST && resultCode == Activity.RESULT_OK)
{
Bitmap photo = (Bitmap) data.getExtras().get("data");
imageView.setImageBitmap(photo);
}
}
}
카메라 앱 자체는 이미지를 검토 / 복구 할 수있는 기능을 제공하며 이미지가 승인되면 활동에 이미지가 표시됩니다.
위 활동에서 사용하는 레이아웃은 다음과 같습니다. id button1이있는 Button과 id imageview1이있는 ImageView를 포함하는 LinearLayout입니다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/photo"></Button>
<ImageView android:id="@+id/imageView1" android:layout_height="wrap_content" android:src="@drawable/icon" android:layout_width="wrap_content"></ImageView>
</LinearLayout>
마지막 세부 사항은 다음을 추가하십시오.
<uses-feature android:name="android.hardware.camera"></uses-feature>
카메라가 앱 기능에 선택적인 경우. 권한에서 require를 false로 설정하십시오. 이처럼
<uses-feature android:name="android.hardware.camera" android:required="false"></uses-feature>
manifest.xml에.
답변
업데이트 (2020)
구글은 새로운 추가 한 ActivityResultRegistry
것으로 API를 “당신이 처리 할 수 있습니다 startActivityForResult()
+를 onActivityResult()
뿐만 아니라 requestPermissions()
+는 onRequestPermissionsResult()
사용자의 활동이나 조각의 메소드를 오버라이드 (override)하지 않고 흐름, 증가 형 안전을 통해 제공 ActivityResultContract
하고, 흐름이 테스트를위한 훅을 제공” – 소스 .
API는 androidx.activity 1.2.0-alpha02 및 androidx.fragment 1.3.0-alpha02 에 추가되었습니다 .
이제 다음과 같은 작업을 수행 할 수 있습니다.
val takePicture = registerForActivityResult(ActivityResultContracts.TakePicture()) { success: Boolean ->
if (success) {
// The image was saved into the given Uri -> do something with it
}
}
val imageUri: Uri = ...
button.setOnClickListener {
takePicture.launch(imageUri)
}
새로운 Activity result API를 사용하는 방법을 배우려면 설명서를 살펴보십시오. 참조하십시오 https://developer.android.com/training/basics/intents/result#kotlin
연락처 선택, 권한 요청, 사진 촬영 또는 비디오 촬영과 같은 다양한 작업을 수행 할 수 있는 내장 ActivityResultContracts 가 많이 있습니다. ActivityResultContracts에 관심이있을 것입니다.위에 표시된 .
참고 1.3.0-alpha04을 androidx.fragment는 deprecates startActivityForResult()
+ onActivityResult()
과 requestPermissions()
+ onRequestPermissionsResult()
조각에 대한 API를. 따라서 ActivityResultContracts
지금부터 일을하는 새로운 방법 인 것 같습니다 .
원래 답변 (2015)
이 작업을 수행하는 데 몇 시간이 걸렸습니다. 코드는 거의 developer.android.com 에서 복사하여 붙여 넣습니다. 이며 약간의 차이가 있습니다.
다음에 대해이 권한을 요청하십시오 AndroidManifest.xml
.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
에서 다음 Activity
을 정의 하여 시작하십시오.
static final int REQUEST_IMAGE_CAPTURE = 1;
private Bitmap mImageBitmap;
private String mCurrentPhotoPath;
private ImageView mImageView;
그런 다음이 화재 Intent
에 onClick
:
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (cameraIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
Log.i(TAG, "IOException");
}
// Continue only if the File was successfully created
if (photoFile != null) {
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
startActivityForResult(cameraIntent, REQUEST_IMAGE_CAPTURE);
}
}
다음 지원 방법을 추가하십시오.
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, // prefix
".jpg", // suffix
storageDir // directory
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = "file:" + image.getAbsolutePath();
return image;
}
그런 다음 결과를 받으십시오.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
try {
mImageBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), Uri.parse(mCurrentPhotoPath));
mImageView.setImageBitmap(mImageBitmap);
} catch (IOException e) {
e.printStackTrace();
}
}
}
그것이 작동하게 한 것은 developer.android.comMediaStore.Images.Media.getBitmap(this.getContentResolver(), Uri.parse(mCurrentPhotoPath))
의 코드와 다른 입니다 . 원래 코드는 나에게 FileNotFoundException
.
답변
사진 캡처 + 갤러리에서 선택 :
a = (ImageButton)findViewById(R.id.imageButton1);
a.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
selectImage();
}
});
}
private File savebitmap(Bitmap bmp) {
String extStorageDirectory = Environment.getExternalStorageDirectory().toString();
OutputStream outStream = null;
// String temp = null;
File file = new File(extStorageDirectory, "temp.png");
if (file.exists()) {
file.delete();
file = new File(extStorageDirectory, "temp.png");
}
try {
outStream = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.PNG, 100, outStream);
outStream.flush();
outStream.close();
} catch (Exception e) {
e.printStackTrace();
return null;
}
return file;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private void selectImage() {
final CharSequence[] options = { "Take Photo", "Choose from Gallery","Cancel" };
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("Add Photo!");
builder.setItems(options, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int item) {
if (options[item].equals("Take Photo"))
{
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File f = new File(android.os.Environment.getExternalStorageDirectory(), "temp.jpg");
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
//pic = f;
startActivityForResult(intent, 1);
}
else if (options[item].equals("Choose from Gallery"))
{
Intent intent = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 2);
}
else if (options[item].equals("Cancel")) {
dialog.dismiss();
}
}
});
builder.show();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == 1) {
//h=0;
File f = new File(Environment.getExternalStorageDirectory().toString());
for (File temp : f.listFiles()) {
if (temp.getName().equals("temp.jpg")) {
f = temp;
File photo = new File(Environment.getExternalStorageDirectory(), "temp.jpg");
//pic = photo;
break;
}
}
try {
Bitmap bitmap;
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmap = BitmapFactory.decodeFile(f.getAbsolutePath(),
bitmapOptions);
a.setImageBitmap(bitmap);
String path = android.os.Environment
.getExternalStorageDirectory()
+ File.separator
+ "Phoenix" + File.separator + "default";
//p = path;
f.delete();
OutputStream outFile = null;
File file = new File(path, String.valueOf(System.currentTimeMillis()) + ".jpg");
try {
outFile = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 85, outFile);
//pic=file;
outFile.flush();
outFile.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
} else if (requestCode == 2) {
Uri selectedImage = data.getData();
// h=1;
//imgui = selectedImage;
String[] filePath = { MediaStore.Images.Media.DATA };
Cursor c = getContentResolver().query(selectedImage,filePath, null, null, null);
c.moveToFirst();
int columnIndex = c.getColumnIndex(filePath[0]);
String picturePath = c.getString(columnIndex);
c.close();
Bitmap thumbnail = (BitmapFactory.decodeFile(picturePath));
Log.w("path of image from gallery......******************.........", picturePath+"");
a.setImageBitmap(thumbnail);
}
}
답변
나는 그것이 아주 오래된 스레드라는 것을 알고 있지만 onActivityResult의 데이터가 null이기 때문에 사용자가 카메라를 회전 할 때 이러한 모든 솔루션이 완료되지 않고 일부 장치에서 작동하지 않습니다. 그래서 여기에 많은 장치에서 테스트했지만 지금까지 아무런 문제가 발생하지 않은 솔루션이 있습니다.
먼저 활동에서 Uri 변수를 선언하십시오.
private Uri uriFilePath;
그런 다음 캡처 된 이미지를 저장할 임시 폴더를 만들고 카메라로 이미지를 캡처 할 의도를 만드십시오.
PackageManager packageManager = getActivity().getPackageManager();
if (packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
File mainDirectory = new File(Environment.getExternalStorageDirectory(), "MyFolder/tmp");
if (!mainDirectory.exists())
mainDirectory.mkdirs();
Calendar calendar = Calendar.getInstance();
uriFilePath = Uri.fromFile(new File(mainDirectory, "IMG_" + calendar.getTimeInMillis()));
intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uriFilePath);
startActivityForResult(intent, 1);
}
그리고 여기 가장 중요한 것들 중 하나가 있습니다. uriFilePath를 onSaveInstanceState에 저장해야합니다. 카메라를 사용하지 않고 장치를 회전하면 uri가 null이기 때문에 uriFilePath를 onSaveInstanceState에 저장해야합니다.
@Override
protected void onSaveInstanceState(Bundle outState) {
if (uriFilePath != null)
outState.putString("uri_file_path", uriFilePath.toString());
super.onSaveInstanceState(outState);
}
그 후에는 항상 onCreate 메소드에서 URI를 복구해야합니다.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
if (uriFilePath == null && savedInstanceState.getString("uri_file_path") != null) {
uriFilePath = Uri.parse(savedInstanceState.getString("uri_file_path"));
}
}
}
그리고 여기 onActivityResult에서 Uri를 얻는 마지막 부분이 있습니다.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == 1) {
String filePath = uriFilePath.getPath(); // Here is path of your captured image, so you can create bitmap from it, etc.
}
}
}
PS 카메라 및 Ext에 대한 권한을 추가하는 것을 잊지 마십시오. 매니페스트에 스토리지 쓰기.
답변
여기에서 카메라 또는 갤러리를 열고 선택한 이미지를 이미지보기로 설정할 수 있습니다
private static final String IMAGE_DIRECTORY = "/YourDirectName";
private Context mContext;
private CircleImageView circleImageView; // imageview
private int GALLERY = 1, CAMERA = 2;
매니페스트에 권한 추가
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="ANDROID.PERMISSION.READ_EXTERNAL_STORAGE" />
onCreate ()에서
requestMultiplePermissions(); // check permission
circleImageView = findViewById(R.id.profile_image);
circleImageView.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
showPictureDialog();
}
});
옵션 대화 상자 표시 (카메라 또는 갤러리에서 이미지를 선택)
private void showPictureDialog() {
AlertDialog.Builder pictureDialog = new AlertDialog.Builder(this);
pictureDialog.setTitle("Select Action");
String[] pictureDialogItems = {"Select photo from gallery", "Capture photo from camera"};
pictureDialog.setItems(pictureDialogItems,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0:
choosePhotoFromGallary();
break;
case 1:
takePhotoFromCamera();
break;
}
}
});
pictureDialog.show();
}
갤러리에서 사진 가져 오기
public void choosePhotoFromGallary() {
Intent galleryIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(galleryIntent, GALLERY);
}
카메라에서 사진 가져 오기
private void takePhotoFromCamera() {
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, CAMERA);
}
이미지가 선택되거나 캡처되면,
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == this.RESULT_CANCELED) {
return;
}
if (requestCode == GALLERY) {
if (data != null) {
Uri contentURI = data.getData();
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), contentURI);
String path = saveImage(bitmap);
Toast.makeText(getApplicationContext(), "Image Saved!", Toast.LENGTH_SHORT).show();
circleImageView.setImageBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), "Failed!", Toast.LENGTH_SHORT).show();
}
}
} else if (requestCode == CAMERA) {
Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
circleImageView.setImageBitmap(thumbnail);
saveImage(thumbnail);
Toast.makeText(getApplicationContext(), "Image Saved!", Toast.LENGTH_SHORT).show();
}
}
이제 사진을 저장하는 시간
public String saveImage(Bitmap myBitmap) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
myBitmap.compress(Bitmap.CompressFormat.JPEG, 90, bytes);
File wallpaperDirectory = new File(Environment.getExternalStorageDirectory() + IMAGE_DIRECTORY);
if (!wallpaperDirectory.exists()) { // have the object build the directory structure, if needed.
wallpaperDirectory.mkdirs();
}
try {
File f = new File(wallpaperDirectory, Calendar.getInstance().getTimeInMillis() + ".jpg");
f.createNewFile();
FileOutputStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
MediaScannerConnection.scanFile(this,
new String[]{f.getPath()},
new String[]{"image/jpeg"}, null);
fo.close();
Log.d("TAG", "File Saved::--->" + f.getAbsolutePath());
return f.getAbsolutePath();
} catch (IOException e1) {
e1.printStackTrace();
}
return "";
}
권한 요청
private void requestMultiplePermissions() {
Dexter.withActivity(this)
.withPermissions(
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE)
.withListener(new MultiplePermissionsListener() {
@Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
if (report.areAllPermissionsGranted()) { // check if all permissions are granted
Toast.makeText(getApplicationContext(), "All permissions are granted by user!", Toast.LENGTH_SHORT).show();
}
if (report.isAnyPermissionPermanentlyDenied()) { // check for permanent denial of any permission
// show alert dialog navigating to Settings
//openSettingsDialog();
}
}
@Override
public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
token.continuePermissionRequest();
}
}).
withErrorListener(new PermissionRequestErrorListener() {
@Override
public void onError(DexterError error) {
Toast.makeText(getApplicationContext(), "Some Error! ", Toast.LENGTH_SHORT).show();
}
})
.onSameThread()
.check();
}
답변
카메라 에 대해 읽어야합니다 . (원하는 것을하기 위해 현재 이미지를 앱에 저장하고 거기에서 선택 / 삭제 한 다음 카메라를 다시 호출하여 카메라 내부에서 직접 다시 시도하는 대신 카메라를 다시 시도해야한다고 생각합니다.)
답변
카메라 이미지 캡처 및 저장에 사용한 코드는 다음과 같습니다. 필요에 따라 사용할 수 있습니다.
카메라 이미지를 특정 위치에 저장 한 다음 해당 위치에서 가져 와서 바이트 배열로 변환해야합니다.
카메라 이미지 활동 캡처를 여는 방법은 다음과 같습니다.
private static final int CAMERA_PHOTO = 111;
private Uri imageToUploadUri;
private void captureCameraImage() {
Intent chooserIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File f = new File(Environment.getExternalStorageDirectory(), "POST_IMAGE.jpg");
chooserIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
imageToUploadUri = Uri.fromFile(f);
startActivityForResult(chooserIntent, CAMERA_PHOTO);
}
onActivityResult () 메소드는 다음과 같아야합니다.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_PHOTO && resultCode == Activity.RESULT_OK) {
if(imageToUploadUri != null){
Uri selectedImage = imageToUploadUri;
getContentResolver().notifyChange(selectedImage, null);
Bitmap reducedSizeBitmap = getBitmap(imageToUploadUri.getPath());
if(reducedSizeBitmap != null){
ImgPhoto.setImageBitmap(reducedSizeBitmap);
Button uploadImageButton = (Button) findViewById(R.id.uploadUserImageButton);
uploadImageButton.setVisibility(View.VISIBLE);
}else{
Toast.makeText(this,"Error while capturing Image",Toast.LENGTH_LONG).show();
}
}else{
Toast.makeText(this,"Error while capturing Image",Toast.LENGTH_LONG).show();
}
}
}
다음은 onActivityResult ()에서 사용되는 getBitmap () 메소드입니다. 카메라 캡처 이미지 비트 맵을 가져 오는 동안 가능한 모든 성능 향상을 수행했습니다.
private Bitmap getBitmap(String path) {
Uri uri = Uri.fromFile(new File(path));
InputStream in = null;
try {
final int IMAGE_MAX_SIZE = 1200000; // 1.2MP
in = getContentResolver().openInputStream(uri);
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, o);
in.close();
int scale = 1;
while ((o.outWidth * o.outHeight) * (1 / Math.pow(scale, 2)) >
IMAGE_MAX_SIZE) {
scale++;
}
Log.d("", "scale = " + scale + ", orig-width: " + o.outWidth + ", orig-height: " + o.outHeight);
Bitmap b = null;
in = getContentResolver().openInputStream(uri);
if (scale > 1) {
scale--;
// scale to max possible inSampleSize that still yields an image
// larger than target
o = new BitmapFactory.Options();
o.inSampleSize = scale;
b = BitmapFactory.decodeStream(in, null, o);
// resize to desired dimensions
int height = b.getHeight();
int width = b.getWidth();
Log.d("", "1th scale operation dimenions - width: " + width + ", height: " + height);
double y = Math.sqrt(IMAGE_MAX_SIZE
/ (((double) width) / height));
double x = (y / height) * width;
Bitmap scaledBitmap = Bitmap.createScaledBitmap(b, (int) x,
(int) y, true);
b.recycle();
b = scaledBitmap;
System.gc();
} else {
b = BitmapFactory.decodeStream(in);
}
in.close();
Log.d("", "bitmap size - width: " + b.getWidth() + ", height: " +
b.getHeight());
return b;
} catch (IOException e) {
Log.e("", e.getMessage(), e);
return null;
}
}
그것이 도움이되기를 바랍니다!