Android程序中以编程方式存储的图像在计算机上具有无效格式。

huangapple go评论71阅读模式
英文:

Android programatically stored image has invalid format on PC

问题

我正在尝试拍照并按照Android文档保存照片。

主要区别在于我的代码扩展了Fragment,而不是Activity。而且,我将照片存储在私有的应用程序文件夹中,而不是公共的外部存储。

我的代码:

private void dispatchTakePictureIntent() {
    PackageManager packageManager = getActivity().getPackageManager();
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    // 确保有相机应用可以处理该意图
    if (takePictureIntent.resolveActivity(packageManager) != null) {
        // 创建照片应该存储的文件
        File photoFile = null;
        try {
            photoFile = createImageFile();
        } catch (IOException ex) {
            Log.d(TAG, "创建文件时出现错误:" + ex.toString());
        }
        // 只有在成功创建文件时才继续
        if (photoFile != null) {
            Uri photoURI = FileProvider.getUriForFile(getActivity(),
                    "com.eric.nativetoolkit.fileprovider",
                    photoFile);
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
            startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
        }
    }
}

private File createImageFile() throws IOException {
    // 创建图像文件名
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";
    File storageDir = getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES);

    File image = File.createTempFile(
            imageFileName,  /* 前缀 */
            ".jpeg",         /* 后缀 */
            storageDir      /* 目录 */
    );

    // 为使用ACTION_VIEW意图保存文件路径
    currentPhotoPath = image.getAbsolutePath();
    return image;
}

由于权限问题,每次尝试将图片保存在外部存储上时,Android Studio的Logcat都会显示“创建文件时出现错误”。我在AndroidManifest.xml中具有以下权限,并且还有一个请求权限的方法,但是都不起作用。

AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.eric.nativetoolkit">
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="18" />
    <application
        android:allowBackup="true"
        android:supportsRtl="true">
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.eric.nativetoolkit.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
    </application>
</manifest>

file_paths.xml:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="my_images" path="." />
</paths>

但是主要问题是,即使将图片正确存储在包名/files/Pictures目录下,当我尝试通过将设备连接到计算机并浏览文件夹来查看图像时,会显示“无法打开文件”的消息:

Android程序中以编程方式存储的图像在计算机上具有无效格式。

我无法理解的是,为什么我可以在设备上正确查看图像。我尝试过更改格式(JPG、JPEG、PNG...),但没有任何区别。

英文:

I'm trying to take a picture and save it following Android Documentation.

The main difference is that my code is extending Fragment, not Activity. And the fact that I'm storing pictures on the private app folder instead of the public external storage.

My Code:

private void dispatchTakePictureIntent() {
    PackageManager packageManager = getActivity().getPackageManager();
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    // Ensure that there&#39;s a camera activity to handle the intent
    if (takePictureIntent.resolveActivity(packageManager) != null) {
        // Create the File where the photo should go
        File photoFile = null;
        try {
            photoFile = createImageFile();
        } catch (IOException ex) {
            Log.d(TAG, &quot;Error occurred while creating the File:&quot;+ex.toString());
        }
        // Continue only if the File was successfully created
        if (photoFile != null) {
            Uri photoURI = FileProvider.getUriForFile(getActivity(),
                    &quot;com.eric.nativetoolkit.fileprovider&quot;,
                    photoFile);
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
            startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
        }
    }
}

private File createImageFile() throws IOException
{
    // Create an image file name
    String timeStamp = new SimpleDateFormat(&quot;yyyyMMdd_HHmmss&quot;).format(new Date());
    String imageFileName = &quot;JPEG_&quot; + timeStamp + &quot;_&quot;;
    File storageDir = getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES);

    File image = File.createTempFile(
            imageFileName,  /* prefix */
            &quot;.jpeg&quot;,         /* suffix */
            storageDir      /* directory */
    );

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

This is basically cause every time I try to save pictures on the external Storage, AndroidStudio logcat shows the error "Error occurred while creating the File" due to permisions, I've the following permisions in my AndroidManifest.xml, and I also have a method to request it, but nothing works.

AndroidManifest.xml:

&lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    package=&quot;com.eric.nativetoolkit&quot;&gt;
    &lt;uses-permission android:name=&quot;android.permission.WRITE_EXTERNAL_STORAGE&quot;
        android:maxSdkVersion=&quot;18&quot; /&gt;
    &lt;application
        android:allowBackup=&quot;true&quot;
        android:supportsRtl=&quot;true&quot;&gt;
        &lt;provider
            android:name=&quot;androidx.core.content.FileProvider&quot;
            android:authorities=&quot;com.eric.nativetoolkit.fileprovider&quot;
            android:exported=&quot;false&quot;
            android:grantUriPermissions=&quot;true&quot;&gt;
            &lt;meta-data
                android:name=&quot;android.support.FILE_PROVIDER_PATHS&quot;
                android:resource=&quot;@xml/file_paths&quot; /&gt;
        &lt;/provider&gt;
    &lt;/application&gt;
&lt;/manifest&gt;

file_paths.xml:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;paths xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
    &lt;external-files-path name=&quot;my_images&quot; path=&quot;.&quot; /&gt;
&lt;/paths&gt;

But the main problem is that even correctly storing pictures inside my package/files/Pictures directory, when I try to see the image plugging my device onto the computer and navigating to the folder, it shows the message (in spanish) "Can't open file":

Android程序中以编程方式存储的图像在计算机上具有无效格式。

What I can not understand is why in my device I can correctly visualize the image. I've tried changing format (JPG, JPEG, PNG...) but no diference.

答案1

得分: 2

> 检查 FLAG_GRANT 是否起作用。但为什么我只需要在外部使用那个标志?这与我无法在桌面上看到图片的事实有什么关系?

您正在通过 ACTION_IMAGE_CAPTURE 启动第三方相机应用。它没有权利写入由您的 FileProvider 提供的 Uri 指定的位置。添加 FLAG_GRANT_WRITE_URI_PERMISSION 告诉 Android 您的应用希望将写访问权限授予相机应用。

如果没有该权限,相机应用将以某种错误失败。您仍将拥有一个文件,因为您在尝试 ACTION_IMAGE_CAPTURE 之前使用 File.createTempFile() 创建了一个不必要的空文件。如果您通过桌面文件管理器查看文件大小,您应该会看到它是 0 字节。0 字节的文件不是有效的图像,这就是为什么桌面无法显示它。

英文:

> Checking if that FLAG_GRANT works. But why I need that flag only for external? And where is the relation with the fact that I can not visualize my pictures on Desktop?

You are launching a third-party camera app via ACTION_IMAGE_CAPTURE. It has no rights to write to the location specified by your FileProvider-supplied Uri. Adding FLAG_GRANT_WRITE_URI_PERMISSION tells Android that your app wishes to give write access to that location to the camera app.

Without that permission, the camera app will fail with some sort of error. You will still have a file, since you are using File.createTempFile() to create an unnecessary empty file before you try ACTION_IMAGE_CAPTURE. If you look at the file size via your desktop file manager, you should see that it is 0 bytes. A 0-byte file is not a valid image, which is why the desktop cannot display it.

huangapple
  • 本文由 发表于 2020年8月18日 20:18:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/63468426.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定