【问题标题】:Android camera2 api and exifAndroid camera2 api 和 exif
【发布时间】:2018-12-21 17:13:53
【问题描述】:

我正在尝试使用camera2 api,并且我制作了一个可以从相机拍照的应用程序。现在我想将exif 数据添加到捕获的图像中。我有一个关于将exif information 放在哪里或如何放置的问题。

我应该在 onCaptureCompleted() 函数中创建一个 Exif 接口还是最好的方法是什么?

final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {

    @Override
    public void onCaptureCompleted(CameraCaptureSession session,
                                   CaptureRequest request, TotalCaptureResult result) {

        super.onCaptureCompleted(session, request, result);
        Toast.makeText(MainActivity.this, "Saved:"+file, Toast.LENGTH_SHORT).show();


        ExifInterface exifTags = null;
        try {
            exifTags = new ExifInterface(file.getCanonicalPath());

            exifTags.setAttribute(ExifInterface.TAG_GPS_LATITUDE, Double.toString(cur_lat));
            exifTags.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, Double.toString(cur_long));

            exifTags.saveAttributes();

        } catch (IOException e) {
            e.printStackTrace();
        }
        //System.out.println(file.getCanonicalPath());
        System.out.println("Exif Test: " + Double.toString(cur_lat) + " " + Double.toString(cur_lat));

    }

};

当我这样做时,我得到一个错误:

"ImageReader_JNI:无法获取lockedBuffer,很可能是客户端 尝试锁定超过 maxImages 个缓冲区”

最好的方法是什么?任何建议都会非常有帮助。

【问题讨论】:

    标签: android android-camera


    【解决方案1】:

    您尝试捕捉什么图像格式?如果是 JPEG,那么所有的 Exif 标签都应该已经写在图像中。 结果图像在 OnImageAvailableListener.onImageAvailable() 中传递,而不是在 CameraCaptureSession 中。 onCaptureCompleted()。 尝试在 onImageAvailable 方法中添加您的自定义标签。

    编辑:

    @Override
        public void onImageAvailable(ImageReader reader) {
            Log.e("TAG", System.currentTimeMillis() + "");
            Image mImage = reader.acquireNextImage();
            ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
            byte[] bytes = new byte[buffer.remaining()];
            buffer.get(bytes);
            FileOutputStream output = null;
            try {
                output = new FileOutputStream(mFile);
                output.write(bytes);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                mImage.close();
                if (null != output) {
                    try {
                        output.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            try {
                ExifInterface exif = new ExifInterface(mFile.getAbsolutePath());
                exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, "10");
                exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, "10");
                exif.saveAttributes();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    

    【讨论】:

    • 是的,我正在尝试以 JPEG 格式捕获。您的意思是,如果移动设备中的位置“打开”,exif 标签与 GPS 纬度、经度、方向、高度相关,那么所有这些都已经存在于图像中了吗?我用 exif 查看器查看了图像,但我看不到它。您能否指导我使用 camera2 api 已将哪些标签保存在图像中?我现在需要纬度,经度,方向。我还将按照您的建议探索 OnImageAvailableListener.onImageAvailable() 方法。谢谢
    • 我不确定 GPS 坐标。但是它有关于相机参数的信息,例如焦距,闪光灯等。所以,您只需将图像保存为文件,然后使用ExifInterface添加Exif属性。我添加了代码示例。
    • 顺便说一句,错误“无法获取lockedBuffer,很可能客户端尝试锁定超过maxImages缓冲区”意味着您没有释放图像。
    • @moleculeone,你的问题解决了吗?
    • 是的,解决方案有效,我必须做一些挖掘才能真正改变纬度和经度以适应 exif 可以读取的格式。谢谢!!!
    【解决方案2】:

    嗨,您可以像这样将 Exif 保存到 Imageavaliable 上的图像

    此图片可用:

     @Override
        public void onImageAvailable(ImageReader reader) {
            try {
                if (latitude == null || longitude == null){
                    imageview.setVisibility(View.GONE);
                    /*deleteImage(file.getPath());*/
    
    
    
    
    
                    Toast.makeText(ShotActivity_camera2API.this,"Waiting.. try to get location result.",Toast.LENGTH_LONG).show();
                    //get location
                    myLocation.getLocation(ShotActivity_camera2API.this,locationResult);
                    return;
                }else {
    
                    File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "Image Project");
                    if (!dir.exists())
                        dir.mkdir();
    
                    file = new File(dir, currentDate + ".jpg");
                    Image image = reader.acquireNextImage();
                    ByteBuffer buffer = image.getPlanes()[0].getBuffer();
                    byte[] bytes = new byte[buffer.remaining()];
                    buffer.get(bytes);
    
    
                    try {
                        saveMetaData(file);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
    
    
                    saveImageFile(bytes);
                    /*mBackgroundHandler.post(new ImageSaver(reader.acquireLatestImage(),file));*/
    
    
                    //close image to fix crash second time capture
                    image.close();
    
                }
            } catch (Exception e) {
                e.printStackTrace();
            } /*catch (IOException e) {
                e.printStackTrace();
            }*/
        }
    

    这种保存Exiv的方法:

    private void saveMetaData(File file) throws IOException {
        ExifInterface exif = new ExifInterface(file.getCanonicalPath());
        Log.e(TAG,""+file.getAbsolutePath());
        //add Latitude to metadata
        exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, gpsParse.convert(latitude));
        exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, gpsParse.latitudeRef(latitude));
        exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, gpsParse.convert(longitude));
        exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, gpsParse.longitudeRef(longitude));
        exif.saveAttributes();
        Log.i(TAG, "" + latitude + "," + longitude);
        Log.i(TAG, "" + gpsParse.convert(latitude) + "," + gpsParse.longitudeRef(longitude));
        Log.i(TAG, "" + gpsParse.latitudeRef(latitude) + "," + gpsParse.longitudeRef(longitude));
    }
    

    这是我的 GPS 将纬度经度解析为 Exif :

    package com.example.PT107.task107_imagesqilte.Helper;
    

    公共类 gpsParse { 私有静态 StringBuilder sb = new StringBuilder(20);

    /**
     * returns ref for latitude which is S or N.
     * @param latitude
     * @return S or N
     */
    public static String latitudeRef(double latitude) {
        return latitude<0.0d?"S":"N";
    }
    
    
    public static String longitudeRef(double longitude) {
        return longitude<0.0d?"W":"E";
    }
    
    /**
     * convert latitude into DMS (degree minute second) format. For instance<br/>
     * -79.948862 becomes<br/>
     *  79/1,56/1,55903/1000<br/>
     * It works for latitude and longitude<br/>
     * @param latitude could be longitude.
     * @return
     */
    synchronized public static final String convert(double latitude) {
        latitude=Math.abs(latitude);
        int degree = (int) latitude;
        latitude *= 60;
        latitude -= (degree * 60.0d);
        int minute = (int) latitude;
        latitude *= 60;
        latitude -= (minute * 60.0d);
        int second = (int) (latitude*1000.0d);
    
        sb.setLength(0);
        sb.append(degree);
        sb.append("/1,");
        sb.append(minute);
        sb.append("/1,");
        sb.append(second);
        sb.append("/1000,");
        return sb.toString();
    }
    

    }

    我希望这对某人有帮助:)

    【讨论】:

      猜你喜欢
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 2016-02-14
      • 2017-08-02
      • 2017-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多