将点击的图像保存到自定义文件夹(最好是应用程序内部)而不是图库

Posted

技术标签:

【中文标题】将点击的图像保存到自定义文件夹(最好是应用程序内部)而不是图库【英文标题】:Save clicked images into custom folder(Preferably internal to the app ) instead of gallery 【发布时间】:2013-06-21 01:36:37 【问题描述】:

我正在尝试将相机功能整合到应用程序中。我可以将图片保存到自定义文件夹中,但问题是图像也保存到了相机文件夹(保存相机图片的地方)。因此,我拍摄的每张图像都有重复的图像。我不想那样。以下是代码:

public class PhotoIntentActivity extends Activity 

    private static final int ACTION_TAKE_PHOTO_B = 1;

    private static final String BITMAP_STORAGE_KEY = "viewbitmap";
    private static final String IMAGEVIEW_VISIBILITY_STORAGE_KEY = "imageviewvisibility";
    private ImageView mImageView;
    private Bitmap mImageBitmap;

    private String mCurrentPhotoPath;

    private static final String JPEG_FILE_PREFIX = "IMG_";
    private static final String JPEG_FILE_SUFFIX = ".jpg";

    private AlbumStorageDirFactory mAlbumStorageDirFactory = null;

    /* Photo album for this application */
    private String getAlbumName() 
        return getString(R.string.album_name);
    

    private File getAlbumDir() 
        File storageDir = null;

        if (Environment.MEDIA_MOUNTED.equals(Environment
                .getExternalStorageState())) 

            storageDir = mAlbumStorageDirFactory
                    .getAlbumStorageDir(getAlbumName(), getApplicationContext());

            if (storageDir != null) 
                if (!storageDir.mkdirs()) 
                    if (!storageDir.exists()) 
                        Log.d("CameraSample", "failed to create directory");
                        return null;
                    
                
            

         else 
            Log.v(getString(R.string.app_name),
                    "External storage is not mounted READ/WRITE.");
        

        return storageDir;
    

    private File createImageFile() throws IOException 
        // Create an image file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
                .format(new Date());
        String imageFileName = JPEG_FILE_PREFIX + timeStamp + "_";
        File albumF = getAlbumDir();
        File imageF = File.createTempFile(imageFileName, JPEG_FILE_SUFFIX,
                albumF);
        return imageF;
    

    private File setUpPhotoFile() throws IOException 

        File f = createImageFile();
        mCurrentPhotoPath = f.getAbsolutePath();

        return f;
    

    private void setPic() 

        /* There isn't enough memory to open up more than a couple camera photos */
        /* So pre-scale the target bitmap into which the file is decoded */

        /* Get the size of the ImageView */
        int targetW = mImageView.getWidth();
        int targetH = mImageView.getHeight();

        /* Get the size of the image */
        BitmapFactory.Options bmOptions = new BitmapFactory.Options();
        bmOptions.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
        int photoW = bmOptions.outWidth;
        int photoH = bmOptions.outHeight;

        /* Figure out which way needs to be reduced less */
        int scaleFactor = 1;
        if ((targetW > 0) || (targetH > 0)) 
            scaleFactor = Math.min(photoW / targetW, photoH / targetH);
        

        /* Set bitmap options to scale the image decode target */
        bmOptions.inJustDecodeBounds = false;
        bmOptions.inSampleSize = scaleFactor;
        bmOptions.inPurgeable = true;

        /* Decode the JPEG file into a Bitmap */
        Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);

        /* Associate the Bitmap to the ImageView */
        mImageView.setImageBitmap(bitmap);
        mImageView.setVisibility(View.VISIBLE);

    

    private void galleryAddPic() 
        Intent mediaScanIntent = new Intent(
                "android.intent.action.MEDIA_SCANNER_SCAN_FILE");
        File f = new File(mCurrentPhotoPath);
        System.out.println(mCurrentPhotoPath);
        Uri contentUri = Uri.fromFile(f);
        mediaScanIntent.setData(contentUri);
        this.sendBroadcast(mediaScanIntent);
    

    private void dispatchTakePictureIntent(int actionCode) 

        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

        switch (actionCode) 
        case ACTION_TAKE_PHOTO_B:
            File f = null;

            try 
                f = setUpPhotoFile();
                mCurrentPhotoPath = f.getAbsolutePath();
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                        Uri.fromFile(f));
             catch (IOException e) 
                e.printStackTrace();
                f = null;
                mCurrentPhotoPath = null;
            
            break;

        default:
            break;
         // switch

        startActivityForResult(takePictureIntent, actionCode);
    

    private void handleBigCameraPhoto() 

        if (mCurrentPhotoPath != null) 
            setPic();
            galleryAddPic();
            mCurrentPhotoPath = null;
        

    

    Button.OnClickListener mTakePicOnClickListener = new Button.OnClickListener() 
        @Override
        public void onClick(View v) 
            dispatchTakePictureIntent(ACTION_TAKE_PHOTO_B);
        
    ;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mImageView = (ImageView) findViewById(R.id.imageView1);

        mImageBitmap = null;

        Button picBtn = (Button) findViewById(R.id.btnIntend);
        setBtnListenerOrDisable(picBtn, mTakePicOnClickListener,
                MediaStore.ACTION_IMAGE_CAPTURE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) 
            mAlbumStorageDirFactory = new FroyoAlbumDirFactory();
         else 
            mAlbumStorageDirFactory = new BaseAlbumDirFactory();
        
    

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) 
        switch (requestCode) 
        case ACTION_TAKE_PHOTO_B: 
            if (resultCode == RESULT_OK) 
                handleBigCameraPhoto();
            
            break;
        
        
    

    // Some lifecycle callbacks so that the image can survive orientation change
    @Override
    protected void onSaveInstanceState(Bundle outState) 
        outState.putParcelable(BITMAP_STORAGE_KEY, mImageBitmap);

        outState.putBoolean(IMAGEVIEW_VISIBILITY_STORAGE_KEY,
                (mImageBitmap != null));

        super.onSaveInstanceState(outState);
    

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) 
        super.onRestoreInstanceState(savedInstanceState);
        mImageBitmap = savedInstanceState.getParcelable(BITMAP_STORAGE_KEY);
        mImageView.setImageBitmap(mImageBitmap);
        mImageView
                .setVisibility(savedInstanceState
                        .getBoolean(IMAGEVIEW_VISIBILITY_STORAGE_KEY) ? ImageView.VISIBLE
                        : ImageView.INVISIBLE);
    

    /**
     * Indicates whether the specified action can be used as an intent. This
     * method queries the package manager for installed packages that can
     * respond to an intent with the specified action. If no suitable package is
     * found, this method returns false.
     * http://android-developers.blogspot.com/2009/01/can-i-use-this-intent.html
     * 
     * @param context
     *            The application's environment.
     * @param action
     *            The Intent action to check for availability.
     * 
     * @return True if an Intent with the specified action can be sent and
     *         responded to, false otherwise.
     */
    public static boolean isIntentAvailable(Context context, String action) 
        final PackageManager packageManager = context.getPackageManager();
        final Intent intent = new Intent(action);
        List<ResolveInfo> list = packageManager.queryIntentActivities(intent,
                PackageManager.MATCH_DEFAULT_ONLY);
        return list.size() > 0;
    

    private void setBtnListenerOrDisable(Button btn,
            Button.OnClickListener onClickListener, String intentName) 
        if (isIntentAvailable(this, intentName)) 
            btn.setOnClickListener(onClickListener);
         else 
            btn.setText(getText(R.string.cannot).toString() + " "
                    + btn.getText());
            btn.setClickable(false);
        
    


public final class FroyoAlbumDirFactory extends AlbumStorageDirFactory 

    @Override
    public File getAlbumStorageDir(String albumName, Context context) 
        // TODO Auto-generated method stub
        return new File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES),albumName);
    

提前致谢。

【问题讨论】:

【参考方案1】:

您可以在将文件保存到您的自定义文件后将其删除。如果您不确定相机拍摄的文件名称,您可以查看时间戳,或者如果您愿意发疯,您可以使用FileObserver 等待文件完成写入之前删除它(如果并发是一个问题并且发生了不好的事情。)

在做了一些研究之后,我发现这个答案贴在这里: Double save image

【讨论】:

【参考方案2】:

最佳解决方案保存在应用程序缓存目录下,该目录只能从您的应用程序上下文中访问context.getCacheDir()

或者使用这个类 并致电ExternalStorage.getSDCacheDir(context,"dirname");

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.content.Context;


public class ExternalStorage 
// Convention for external storage path used by Android 2.2.
private static final String EXT_STORAGE_ROOT_PREFIX = "/Android/data/";
private static final String EXT_STORAGE_ROOT_SUFFIX = "/files/";

private static StringBuilder sStoragePath = new StringBuilder();

private static final String ALTERNATE_SDCARD_MOUNTS[] =  "/emmc", 
        "/sdcard/ext_sd", // Newer (2011) HTC devices (Flyer, Rezound)
        "/sdcard-ext", // Some Motorola devices (RAZR)
        "/sdcard/sd", // Older Samsung Galaxy S (Captivate)
        "/sdcard/sdcard" // Archos tablets
;

/**
 * Create given directory on sd card application cache Directory.
 * 
 * @param context
 * @param dirName
 * @return created cache directory file, if not created return null.
 */
public static File getSDCacheDir(Context context, String dirName) 
    File cacheDir = null;

    // Check to see if SD Card is mounted and read/write accessible
    if (android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment
            .getExternalStorageState())) 
        // Get the directory on the SD card to store content
        // Attempt to use getExternalFilesDir() if we are on Android 2.2 or newer
        // Data stored in this location will auto-delete with app uninstall
        Method getExternalFilesDirMethod = null;
        try 
            getExternalFilesDirMethod = Context.class.getMethod(
                    "getExternalFilesDir", String.class);
            cacheDir = (File) getExternalFilesDirMethod.invoke(context,
                    dirName);
         catch (NoSuchMethodException e) 
            // Android 2.1 and earlier - use old APIs
            cacheDir = buildCacheDirPath(context,
                    android.os.Environment.getExternalStorageDirectory(),
                    dirName);
         catch (IllegalArgumentException e) 
            cacheDir = buildCacheDirPath(context,
                    android.os.Environment.getExternalStorageDirectory(),
                    dirName);
         catch (IllegalAccessException e) 
            cacheDir = buildCacheDirPath(context,
                    android.os.Environment.getExternalStorageDirectory(),
                    dirName);
         catch (InvocationTargetException e) 
            cacheDir = buildCacheDirPath(context,
                    android.os.Environment.getExternalStorageDirectory(),
                    dirName);
        
    

    if (cacheDir == null) 
        // Attempting to find the default external storage was a failure.
        // Look for another suitable external filesystem where we can store
        // our crap
        for (int i = 0; i < ALTERNATE_SDCARD_MOUNTS.length; i++) 
            File alternateDir = new File(ALTERNATE_SDCARD_MOUNTS[i]);
            if (alternateDir.exists() && alternateDir.isDirectory()
                    && alternateDir.canRead() && alternateDir.canWrite()) 
                cacheDir = buildCacheDirPath(context, alternateDir, dirName);
                break;
            
        
    

    // Attempt to create folder on external storage if it does not exist
    if (cacheDir != null && !cacheDir.exists()) 
        if (!cacheDir.mkdirs()) 
            cacheDir = null; // Failed to create folder
        
    

    // Fall back on internal cache as a last resort
    if (cacheDir == null) 
        cacheDir = new File(context.getCacheDir() + File.separator
                + dirName);
        cacheDir.mkdirs();
    

    return cacheDir;

【讨论】:

【参考方案3】:

有两种方法

    相机意图自定义相机

您正在使用相机意图。

新意图(MediaStore.ACTION_IMAGE_CAPTURE);

MediaStore.ACTION_IMAGE_CAPTURE- 从现有相机应用程序请求图像的 Intent 操作类型。

MediaStore.EXTRA_OUTPUT - 此设置需要一个 Uri 对象,指定您要保存图片的路径和文件名

如何保存media file?

private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;
  private Uri fileUri;

   @Override
    public void onCreate(Bundle savedInstanceState) 
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

// create Intent to take a picture and return control to the calling application
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name

// start the image capture Intent
startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
  

请正确按照上述说明操作,避免重复。

第二个选项是你需要使用Custom Camera。

请阅读全文article以了解相机功能。

提示:

在您的 startActivityForResult() 中将代码写入 move the picture 从 camera 文件夹 到您的 Custom 文件夹,而不是将图像保存在您的自定义文件夹。

希望这能给你一些有用的信息。

【讨论】:

【参考方案4】:

将此图像保存到自定义文件夹后,从相机文件夹中删除图像

【讨论】:

以上是关于将点击的图像保存到自定义文件夹(最好是应用程序内部)而不是图库的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 react-native-camera 将捕获的图像保存到自定义应用程序特定文件夹

如何将图像保存到自定义相册?

如何将图像保存到自定义相册?

iOS5将图像保存到自定义文件夹,ALAssetsLibrary 失败

Swift 3 或 4 保存到自定义相册会创建重复的图像

Phonegap(cordova)将图像保存到自定义相册