当前位置: 首页 > 知识库问答 >
问题:

将EXIF数据写入用DocumentFile类保存的图像

钱跃
2023-03-14
  1. 用户选择保存图像的路径,该路径返回包含内容的Uri://com.Android.externalstorage.documentsonActivityResult()。我将此路径与treeuri.tostring()一起保存到SharedPreferences,以便以后使用。
  2. 用户拍摄一张图片,图像用documentfile.fromtreeuri(mainactivity.this,uri.parse(uriString))保存;
  3. 我失败了,获取一个正确指向image的文件,内容为://的Uri不会返回现有的image。正确的Uri应该File://storage/emulated/,我可以使用filePath=new File(Uri.create(savedir.geturi().tostring()));
  4. 将此Uri转换为文件

如何使用从SAF UI获得的Uri获取consturcting文件或文件所需的Uri?

Edit:ExifInterface支持库是为Android7.1+引入的,它可以使用InputStream或FileDescriptor。

Uri uri; // the URI you've received from the other app
InputStream in;
try {
  in = getContentResolver().openInputStream(uri);
  ExifInterface exifInterface = new ExifInterface(in);
  // Now you can extract any Exif tag you want
  // Assuming the image is a JPEG or supported raw format
} catch (IOException e) {
  // Handle any errors
} finally {
  if (in != null) {
    try {
      in.close();
    } catch (IOException ignored) {}
  }
}

注意:ExifInterface不能使用远程InputStream,例如从HTTPurlConnection返回的InputStream。强烈建议只将它们与content://或file://URI一起使用。

上面的代码片段显然是在读取数据,因为它打开了一个InputStream来读取数据。我需要能够写EXIF数据到JPEG文件。

共有1个答案

金泉
2023-03-14

如果Api为24或更高,则使用FileDescriptor将Exif数据写入以前保存的已知内容Uri的图像

private void writeEXIFWithFileDescriptor(Uri uri) {

    if (Build.VERSION.SDK_INT < 24) {
        showToast("writeEXIFWithInputStream() API LOWER 24", Toast.LENGTH_SHORT);
        return;
    }

    ParcelFileDescriptor parcelFileDescriptor = null;
    try {

        parcelFileDescriptor = mContext.getContentResolver().openFileDescriptor(uri, "rw");
        FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
        showToast("writeEXIFWithFileDescriptor(): " + fileDescriptor.toString(), Toast.LENGTH_LONG);
        ExifInterface exifInterface = new ExifInterface(fileDescriptor);
        // TODO Create  Exif Tags class to save Exif data
        exifInterface.saveAttributes();

    } catch (FileNotFoundException e) {
        showToast("File Not Found " + e.getMessage(), Toast.LENGTH_LONG);

    } catch (IOException e) {
        // Handle any errors
        e.printStackTrace();
        showToast("IOEXception " + e.getMessage(), Toast.LENGTH_LONG);
    } finally {
        if (parcelFileDescriptor != null) {
            try {
                parcelFileDescriptor.close();
            } catch (IOException ignored) {
                ignored.printStackTrace();
            }
        }
    }
}

如果Api低于24,则需要使用一个缓冲区文件,并在写完Exif数据后用documentfile将该缓冲区文件保存到实际位置。

private boolean exportImageWithEXIF(Bitmap bitmap, DocumentFile documentFile) {
        OutputStream outputStream = null;
        File bufFile = new File(Environment.getExternalStorageDirectory(), "buffer.jpg");
        long freeSpace = Environment.getExternalStorageDirectory().getFreeSpace() / 1048576;
        double bitmapSize = bitmap.getAllocationByteCount() / 1048576d;

        showToast("exportImageWithEXIF() freeSpace " + freeSpace, Toast.LENGTH_LONG);
        showToast("exportImageWithEXIF() bitmap size " + bitmapSize, Toast.LENGTH_LONG);
        try {
            outputStream = new FileOutputStream(bufFile);
            // Compress image from bitmap with JPEG extension
            if (mCameraSettings.getImageFormat().equals(Constants.IMAGE_FORMAT_JPEG)) {
                isImageSaved = bitmap.compress(CompressFormat.JPEG, mCameraSettings.getImageQuality(), outputStream);
                showToast("isImageSaved: " + isImageSaved, Toast.LENGTH_SHORT);
            }

            if (isImageSaved) {
                writeEXIFWithFile(bufFile);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        OutputStream os = null;
        InputStream is = null;
        try {
            int len;
            byte[] buf = new byte[4096];

            os = mContext.getContentResolver().openOutputStream(documentFile.getUri());
            is = new FileInputStream(bufFile);

            while ((len = is.read(buf)) > 0) {
                os.write(buf, 0, len);
            }

            os.close();
            is.close();

            if (bufFile != null) {
                bufFile.delete();
                bufFile = null;
            }

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

        return isImageSaved;
    }

这两种方法都可以用于将Exif数据写入保存到设备内存或SD卡的图像。您也可以保存图像到SD卡使用有效的Uri从存储访问框架。

 类似资料:
  • 问题内容: 我搜索了从图片文件中获取EXIF数据,然后将其写回Swift中。但是我只能找到针对不同语言的预定义库。 我还找到了对“ CFDictionaryGetValue”的引用,但是我需要哪些键来获取数据?我该怎么写呢? 问题答案: 我正在用它来从图像文件中 获取 EXIF信息: 它为您提供了一个字典,其中包含各种信息,例如颜色配置文件-EXIF信息专门位于中。

  • 在使用相机意图拍摄照片后,我压缩位图以降低文件大小。问题是压缩后,它会丢失所有EXIF数据。检索原始EXIF数据没有问题,但是,如何将压缩后的EXIF数据添加到字节数组中? (我的猜测是获取字节数组并创建一个位图,然后添加旧的EXIF数据,然后再次添加到字节数组,但这是一个移动应用程序,我正在拍摄大量图像,所以我不想浪费内存) 以下是我压缩位图并保存到字节数组输出流的代码:

  • 问题内容: 给定一些源文件(或更通用的输入流),我需要找出 它是图像吗 如果它是图像,则检索其类型(png / jpeg / gif / etc) 检索exif数据(如果有) 我看了看API,但尚不清楚如何获取图像或Exif数据的类型。 问题答案: 几年前,我上一次不得不这样做时,标准API无法读取EXIF数据。该库可以这样做: http://www.drewnoakes.com/code/exi

  • 问题内容: 在我们的网站上,我们从各种来源上传了大量照片。 为了减小文件大小,我们使用mogrify从源中剥离所有exif数据: 我们想要做的是将一些基本的exif数据(如版权Initrode等)插回到这个新的“干净”图像上,但是我似乎在文档中找不到能实现此目的的任何东西。 有任何这样做的经验吗? 如果不能通过imagemagick完成,则基于PHP的解决方案将是下一件好事! 谢谢。 问题答案:

  • 这可能会导致问题,特别是如果有问题的设备依赖于“方向”标签来正确地垂直显示图像。 不同的Android设备以不同的方式处理相机/图像旋转--我信任的旧Nexus One似乎总是在捕获后立即旋转图像,因此文件的原生内容在查看时总是“直立”。 然而,其他设备(尤其是我测试的三星手机)不会旋转图像文件的内容--相反,它们设置了Exif“方向”标签。每当稍后显示图像时,相关的图像代码应该检测到方向“标签”

  • 问题内容: Python新手对csv模块感到有点沮丧。以这种速度,如果我自己编写文件解析器会更容易,但是我想用Pythonic的方式做事情。 我写了一个小python脚本,应该将我的数据保存到CSV文件中。 这是我的代码片段: 文件myfile.csv已成功创建,但为空-但已锁定,因为Python进程仍在使用它。似乎数据已写入内存中的文件,但尚未刷新到磁盘。 由于Python进程在文件上持有锁,因