首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从Android应用内摄像头拍照并上传到服务器的更高效的方法

从Android应用内摄像头拍照并上传到服务器的更高效的方法
EN

Stack Overflow用户
提问于 2021-05-07 11:56:43
回答 3查看 110关注 0票数 3

我正在建立一个应用程序,需要从应用程序内相机拍照的方法,但对于一些安卓设备(旧设备或低内存),它是相当冻结时,拍照触发。有没有什么代码可以修改或优化,让用户体验更好?

代码语言:javascript
复制
//this function trigger to take picture (or screenshot) from user screen
    private void captureImage() {
        mPreview.setDrawingCacheEnabled(true);
        final Bitmap[] drawingCache = {Bitmap.createBitmap(mPreview.getDrawingCache())};
        mPreview.setDrawingCacheEnabled(false);

     mCameraSource.takePicture(null, bytes -> {
            int orientation = Exif.getOrientation(bytes);
            Bitmap temp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
            Bitmap picture = rotateImage(temp, orientation);
            assert picture != null;
            Bitmap overlay = Bitmap.createBitmap(mGraphicOverlay.getWidth(), mGraphicOverlay.getHeight(), picture.getConfig());
            Canvas canvas = new Canvas(overlay);

            Matrix matrix = new Matrix();
            matrix.setScale((float) overlay.getWidth() / (float) picture.getWidth(), (float) overlay.getHeight() / (float) picture.getHeight());

            // mirror by inverting scale and translating
            matrix.preScale(-1, 1);
            matrix.postTranslate(canvas.getWidth(), 0);

            Paint paint = new Paint();
            canvas.drawBitmap(picture, matrix, paint);
            canvas.drawBitmap(drawingCache[0], 0, 0, paint);

//this function to save picture taken and put it on app storage cache
            try {
                String mainpath = getApplicationContext().getFilesDir().getPath() + separator + "e-Presensi" + separator;
                File basePath = new File(mainpath);
                if (!basePath.exists())
                    Log.d("CAPTURE_BASE_PATH", basePath.mkdirs() ? "Success" : "Failed");

//this function to get directory path of saved photo
                String path = mainpath + "photo_" + getPhotoTime() + ".jpg";
                String namafotoo = "photo_" + getPhotoTime() + ".jpg";
                filePath = path;

                namafoto = namafotoo;
                SessionManager.createNamaFoto(namafoto);

                File captureFile = new File(path);
                boolean sucess = captureFile.createNewFile();
                if (!captureFile.exists())
                    Log.d("CAPTURE_FILE_PATH", sucess ? "Success" : "Failed");
                FileOutputStream stream = new FileOutputStream(captureFile);
                overlay.compress(Bitmap.CompressFormat.WEBP, 60, stream);
                stream.flush();
                stream.close();
                if (!picture.isRecycled()) {
                    picture.recycle();
                }

                if (drawingCache[0] != null && !drawingCache[0].isRecycled()) {
                    drawingCache[0].recycle();
                    drawingCache[0] = null;
                }
                mPreview.setDrawingCacheEnabled(false);
                uploadPicture();
                finish();

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

谢谢你的帮助。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-05-20 02:55:11

通常,我建议您单步执行代码并查看在每一行上生成的大量内存资源,如果完成,请考虑在遍历整个方法时积极地将这些资源设置为null。

例如,您有一个名为temp的变量,它的大小为"Y“个字节,您似乎要旋转它,然后再也不使用temp。如果picturetemp的旋转副本,那么您现在已经使用了2Y字节的内存来保存temppicture。我怀疑,如果你在创建picture后简单地将temp设置为null,你可能会释放一半的内存,而这些内存是你的旧/慢手机非常需要的。

采用相同的概念,并遵循您的方法的其余部分,看看是否可以找到其他优化。基本上,在创建不会使用的图像数据副本的任何地方,都应该立即将其设置为null,以便垃圾收集器可以积极地将其丢弃。

票数 1
EN

Stack Overflow用户

发布于 2021-05-20 21:02:38

首先,你需要一些变量:

代码语言:javascript
复制
byte[] byteArray_IMG;
String currentPhotoPath;
static final int REQUEST_TAKE_PHOTO = 1;
ImageView imageView; // maybe you need show the photo before send it

然后定义拍摄照片的方法:

代码语言:javascript
复制
  private void dispatchTakePictureIntent() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    // Ensure that there's a camera activity to handle the intent
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
        // Create the File where the photo should go
        File photoFile = null;

        try {
            photoFile = createImageFile();
        } catch (IOException ex) {
            Toast.makeText(getApplicationContext(),Error takin the photo",Toast.LENGTH_LONG).show();
        }

        // Continue only if the File was successfully created
        if (photoFile != null) {
            path_img = photoFile.toString();
            Uri photoURI = FileProvider.getUriForFile(this,"com.app.yournmamepackage.fileprovider" , photoFile);
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
            startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
        }
    }
}

创建创建文件镜像的方法

代码语言:javascript
复制
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 = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    File image = File.createTempFile(
            imageFileName,  /* prefix */
            ".jpg",         /* suffix */
            storageDir      /* directory */
    );

    // Save a file: path for use with ACTION_VIEW intents
    currentPhotoPath = image.getAbsolutePath();
    return image;
}

覆盖活动结果以:

代码语言:javascript
复制
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode,resultCode,data);

    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {

 /*            Bundle extras =  data.getExtras();
        Bitmap imageBitmap = (Bitmap)  extras.get("data");

        imageView.setImageBitmap(imageBitmap);

        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);

        byteArray_IMG = stream.toByteArray();*/

        MediaScannerConnection.scanFile(this, new String[]{path_img}, null,
                new MediaScannerConnection.OnScanCompletedListener() {
                    @Override
                    public void onScanCompleted(String path, Uri uri) {
                        Log.i("path",""+path);
                    }
                });

        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        Bitmap imageBitmap = BitmapFactory.decodeFile(path_img);
        imageBitmap.compress(Bitmap.CompressFormat.JPEG, 14, stream);
        imageView.setImageBitmap(imageBitmap);
        byteArray_IMG = stream.toByteArray();
    }
}

记住这一点非常重要

代码语言:javascript
复制
imageBitmap.compress(Bitmap.CompressFormat.JPEG, 25, stream)

 // 25 is photo quality  0-100

然后,您可以在异步过程中上传图片

票数 0
EN

Stack Overflow用户

发布于 2021-05-22 16:28:06

首先,在您的活动/片段中的onCreate()方法上初始化这些变量

代码语言:javascript
复制
val FILE_NAME:String="photo.jpg"     //give any name with.jpg extension
private var imageuri: Uri?=null
val REQUEST_IMAGE=111

现在打开摄像头

代码语言:javascript
复制
val intent: Intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)

        photofile = getphotofile(FILE_NAME)
        imageuri = activity?.let { it1 -> FileProvider.getUriForFile(it1, "//your package name here//.fileprovider", photofile) }     //put your package name
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageuri)
        startActivityForResult(int, REQUEST_IMAGE)

onActivityResult()方法

代码语言:javascript
复制
if(requestCode==REQUEST_IMAGE && resultCode == Activity.RESULT_OK){
        val progressdialog: ProgressDialog = ProgressDialog(activity)
        progressdialog.setTitle("Sending Image....")         
        progressdialog.show()                   //start your progressdialog

        val ref= FirebaseDatabase.getInstance().reference
        val messagekey=ref.push().key          //create a key to store image in firebase

        var bmp: Bitmap?=null
        try {
            bmp=MediaStore.Images.Media.getBitmap(activity?.contentResolver,imageuri)   //get image in bitmap
        } catch (e: IOException) {
            e.printStackTrace();
        }
        val baos= ByteArrayOutputStream()
        bmp!!.compress(Bitmap.CompressFormat.JPEG,50,baos)   //compress the quality of image to 50 from 100
        val fileinBytes: ByteArray =baos.toByteArray()

        val store: StorageReference = FirebaseStorage.getInstance().reference.child("Chat Images/")    //create a child reference in firebase
        val path=store.child("$messagekey.jpg")    //store a message in above reference with the unique key created above with .jpg extension
        val uploadTask: StorageTask<*>
        uploadTask=path.putBytes(fileinBytes)    //it will upload the image to firebase at given path

        uploadTask.continueWithTask(Continuation<UploadTask.TaskSnapshot, Task<Uri>> { task ->
            if (!task.isSuccessful) {
                task.exception?.let {
                    throw it
                }
                Toast.makeText(activity, "Upload Failed", Toast.LENGTH_SHORT).show()
            }
            return@Continuation path.downloadUrl
        }).addOnCompleteListener { task->
            if(task.isSuccessful){

                url=task.result.toString()   //get the url of uploaded image
                
                //Do what you want with the url of your image                     

                progressdialog.dismiss()
                Toast.makeText(activity, "Image Uploaded", Toast.LENGTH_SHORT).show()
            }
        }.addOnFailureListener { e->
            progressdialog.dismiss()
            Toast.makeText(activity, "Failed " + e.message, Toast.LENGTH_SHORT)
                    .show();
        }
        uploadTask.addOnProgressListener { task->
            var progress:Double=(100.0*task.bytesTransferred)/task.totalByteCount
            progressdialog.setMessage("Sending ${progress.toInt()}%")   //this will show the progress in progress bar 0-100%
        }

    }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67428809

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档