Фотосъемка через намерение внутренних (приложение) возвращает NULL для хранения растрового изображения


Область действия: я хочу сделать снимок с помощью intent и сохранить снимок во внутренней памяти моего приложения. Затем я хочу, чтобы загрузить масштабируемую версию в байтовый массив (от InputStream), сохранить изображение как массив байтов в SQLight. После сохранения его в базе данных я хочу удалить картинку.

(этот вопрос касается только сохранения изображения во внутреннюю память, область действия только здесь, потому что всегда есть кто-то, кто спрашивает об этом)

Проблема: я застрял в экономии изображение на внутреннюю память.

Я добавлю примеры из моего сеанса отладки в качестве комментариев за переменными, чтобы показать значения, которые я получил во время тестирования.

У меня есть ImageView, который имеет onClickListener, который запускает takePictureIntent:

Со следующими глобальными атрибутами:

Uri mCurrentPhotoUri; //URI to file
File mCurrentPicture; //the current picture don't know if I need it somewhere but for complete understanding of code

imageView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        //Intent for the on-board camera
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        //device has camera
        if(takePictureIntent.resolveActivity(getPackageManager()) != null) {
            File photoFile = null;
            try {
                //create a file with path the code below
                photoFile = createImageFile(); //sets photoFile to: /data/data/my.app.project/app_photo/JPEG_20151105_092219_-1434131481.jpg
            } catch (IOException e) {
                e.printStackTrace();
            }
            //file has been created, set members and add Extra to intent, then start intent.
            if(photoFile != null) {
                mCurrentPicture = photoFile; // well, same as above
                mCurrentPhotoUri = Uri.fromFile(photoFile); // this looks somehow wrong, but I don't know much about URIs: file:///data/data/my.app.project/app_photo/JPEG_20151105_092219_-1434131481.jpg
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile)); //same URI as above that extra should be needed to tell the cam that I don't want to save to the default path but my app path
                startActivityForResult(takePictureIntent, 10); //start the intent and use requestcode 10 for onActivityResult ...
            }
        }
    }
});

Создание пути к файлу:

//code from google developers with some changes. 
private File createImageFile() throws IOException {
        String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); //from today value: 20151105_092219
        String imageFilename = "JPEG_" + timestamp + "_"; // concat is this: JPEG_20151105_092219_
        File storageDir = this.getDir("photo", MODE_PRIVATE); //String path is: /data/data/my.app.project/app_photo
        storageDir.mkdirs();
        File image = File.createTempFile(imageFilename, ".jpg", storageDir); //String path is: /data/data/my.app.project/app_photo/JPEG_20151105_092219_-1434131481.jpg
        mCurrentPhotoPath = "file:" + image.getAbsolutePath(); //here I put the absolute path into static mCurrentPhotoPath, concate with the "file:" from googledeveloper guide: file:/data/data/my.app.project/app_photo/JPEG_20151105_092219_-1434131481.jpg
        return image;
}

Итак, камера открывается, и я могу сделать снимок, и я спрашиваю, хочу ли я сохранить эту фотографию (все из встроенного приложения камеры, устройство представляет собой samsung galaxy note).

Тогда вызывается мой onActivityResult-метод: Я использовал данные в качестве параметра, потому что я использовал мини-массив байтов для чего-то, но с пользовательским хранилищем это возвращает null , и он больше не используется.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK) {
        switch(requestcode) {
            ...
            case 10:
                setImageView(ivPreview1, data, 0);
                ivPreview.setVisibility(View.VISIBLE);
                break;
            ...
        }
    ...
    }
}

Метод setImageView:

private void setImageView(ImageView iv, Intent data, int index) {
        try {
            Uri u = mCurrentPhotoUri; //sets u to: file:///data/data/my.app.project/app_photo/JPEG_20151105_092219_-1434131481.jpg

            File file = new File(u.getPath()); //sets file to: /data/data/my.app.project/app_photo/JPEG_20151105_092219_-1434131481.jpg
            Bitmap bm = null;
            ByteArrayOutputStream baos = null;
            int orientation = 0;
            if (file.exists()) { //this is true

                //found that somewhere in the developer training:
                ExifInterface exif = null;
                try {
                    exif = new ExifInterface(photoUri.getPath());
                } catch (IOException e) {
                    e.printStackTrace();
                }

                if(exif != null)
                    orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0); //is 0 (i didn't rotate the tablet)

                //resulution I want to resize the image to:
                int reqWidth = 960, reqHeight = 1280;

                //exchange values if orientation doesn't match landscape
                if (orientation == 0 || orientation == 270) {
                    int temp = reqWidth;
                    reqWidth = reqHeight;
                    reqHeight = temp;

                }
                //this I used before I changed to internal storage to change the size of the image code below
                bm = ImageManager.decodeSampledBitmapFromFile(u.getPath(), reqWidth, reqHeight); // returns null because of this everything following is null too.

                if (orientation == 90 || orientation == 180 || orientation == 270) {
                    Matrix matrix = new Matrix();
                    // rotate the Bitmap

                    if (orientation == 90)
                        matrix.postRotate(90F);
                    else if (orientation == 270)
                        matrix.postRotate(-90F);
                    else
                        matrix.postRotate(180F);

                    // recreate the new Bitmap
                    bm = Bitmap.createBitmap(bm, 0, 0,
                            bm.getWidth(), bm.getHeight(), matrix, true);
                }
                baos = new ByteArrayOutputStream();
                bm.compress(Bitmap.CompressFormat.JPEG, 50, baos);
            }

            iv.setImageBitmap(bm);

        } catch (Exception e) {
            e.printStackTrace();
                Log.e(TAG, "Could not take Photo: ", e);
        }
    }

Следующие методы, которые я использовал для декодирования файла (настройка: http://developer.android.com/downloads/samples/DisplayingBitmaps.zip ):

Линия с BitmapFactory.decodeFile (filename, options); также создает запись журнала: D / skia: - - - SkImageDecoder:: Factory returned null

public static Bitmap decodeSampledBitmapFromFile(String filename,
    int reqWidth, int reqHeight) {
    //this gets parameters:
    // reqHeight: 960, reqWidth: 1280 and filename: /data/data/my.app.project/app_photo/JPEG_20151105_092219_-1434131481.jpg

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;

    BitmapFactory.decodeFile(filename, options); // this adds outHeight and outWidth to -1 (variables from options) 
    //this also creates a log entry: D/skia: --- SkImageDecoder::Factory returned null

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;



    Bitmap bmp = BitmapFactory.decodeFile(filename, options);
    return bmp;
}

public static int calculateInSampleSize(BitmapFactory.Options options,
            int reqWidth, int reqHeight) {
        // BEGIN_INCLUDE (calculate_sample_size)
        // Raw height and width of image
        final int height = options.outHeight; //is -1
        final int width = options.outWidth; //is -1
        int inSampleSize = 1;

        //because its obviously smaller in both statements code will not be executed so it returns 1
        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }

            // This offers some additional logic in case the image has a strange
            // aspect ratio. For example, a panorama may have a much larger
            // width than height. In these cases the total pixels might still
            // end up being too large to fit comfortably in memory, so we should
            // be more aggressive with sample down the image (=larger inSampleSize).

            long totalPixels = width * height / inSampleSize;

            // Anything more than 2x the requested pixels we'll sample down further
            final long totalReqPixelsCap = reqWidth * reqHeight * 2;

            while (totalPixels > totalReqPixelsCap) {
                inSampleSize *= 2;
                totalPixels /= 2;
            }
        }
        return inSampleSize;
        // END_INCLUDE (calculate_sample_size)
    }
Я застрял на этом уже несколько дней, и у меня нет никаких идей, которые могли бы решить мою проблему. Это также связано с отсутствием знаний android и тем фактом, что я не могу использовать эмуляторы на своем компьютере, поэтому я даже не могу посмотреть в папке приложения, чтобы увидеть, была ли сделана фотография.
1 2

1 ответ:

Попробуйте получить путь для хранения временного изображения, как показано ниже.который вернет расположение папки приложения.и добавьте разрешение, а также.

 File dir = context.getExternalFilesDir(null)+"/"+"photo";

Добавить uses-feature для доступа к камере тоже.

<manifest ... >
    <uses-feature android:name="android.hardware.camera"
                  android:required="true" />

Официальнаядокументация .