Фотосъемка через намерение внутренних (приложение) возвращает 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 ответ:
Попробуйте получить путь для хранения временного изображения, как показано ниже.который вернет расположение папки приложения.и добавьте разрешение, а также.
File dir = context.getExternalFilesDir(null)+"/"+"photo";
Добавить uses-feature для доступа к камере тоже.
<manifest ... > <uses-feature android:name="android.hardware.camera" android:required="true" />
Официальнаядокументация .