Как установить выходное изображение используйте com.android.camera.action.CROP

У меня есть код для обрезки изображения, например:

public void doCrop(){
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setType("image/");
List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent,0);
int size = list.size();
if (size == 0 ){
   Toast.makeText(this, "Cant find crop app").show();
   return;
} else{
   intent.setData(selectImageUri);
   intent.putExtra("outputX", 300);
   intent.putExtra("outputY", 300);
   intent.putExtra("aspectX", 1);
   intent.putExtra("aspectY", 1);
   intent.putExtra("scale", true);
   intent.putExtra("return-data", true);
   if (size == 1) {
       Intent i = new Intent(intent);
       ResolveInfo res = list.get(0);
       i.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
       startActivityForResult(i, CROP_RESULT);
   }
}
}

public void onActivityResult (int requestCode, int resultCode, Intent dara){
   if (resultCode == RESULT_OK){
      if (requestCode == CROP_RESULT){
          Bundle extras = data.getExtras();
          if (extras != null){
              bmp = extras.getParcelable("data");
          }
          File f = new File(selectImageUri.getPath());
          if (f.exists()) f.delete();
          Intent inten3 = new Intent(this, tabActivity.class);
          startActivity(inten3);
      }
   }
}

из того, что я прочитал, код intent.putExtra("outputX", 300); intent.putExtra("outputY", 300); используется для установки разрешения результата обрезки, но почему я не могу получить разрешение изображения выше, чем 300x300? когда я установил intent.putExtra("outputX", 800); intent.putExtra("outputY", 800); функция обрезки не дает результата или вылетает, есть идеи для этой ситуации?

бревенчатый кот скажет "!!! СБОЙ БИНДЕРА!"

2 ответа

Решение

Это намерение не является частью общедоступного API Android и не гарантируется, что оно будет работать на всех устройствах. Он использовался в более ранних версиях Android 1.x и 2.x, но больше не используется и не рекомендуется. Вероятно, поэтому он рушится или работает неправильно.

Используйте такие методы, как Bitmap.createBitmap(..) или же Bitmap.createScaledBitmap(..) создать измененную или обрезанную версию вашего исходного изображения. Они являются частью Android API и гарантированно работают.

Смотрите официальные документы здесь и здесь

Чтобы обрезать растровое изображение, вы можете использовать Bitmap.createBitmap(Bitmap, int x, int y, int width, int height), Например, если вам нужно обрезать 10 пикселей с каждой стороны растрового изображения, используйте это:

Bitmap croppedBitmap = Bitmap.createBitmap(originalBitmap, 10, 10, originalBitmap.getWidth() - 20, originalBitmap.getHeight() - 20);

Если вам нужно показать селектор пользователю. Тогда вы можете сделать что-то вроде этого:

private static final String TEMP_PHOTO_FILE = "temporary_holder.jpg";  

Intent photoPickerIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
photoPickerIntent.setType("image/*");
photoPickerIntent.putExtra("crop", "true");
photoPickerIntent.putExtra(MediaStore.EXTRA_OUTPUT, getTempUri());
photoPickerIntent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
startActivityForResult(photoPickerIntent, REQ_CODE_PICK_IMAGE);


    private Uri getTempUri() {
    return Uri.fromFile(getTempFile());
    }

    private File getTempFile() {
    if (isSDCARDMounted()) {

    File f = new File(Environment.getExternalStorageDirectory(),TEMP_PHOTO_FILE);
    try {
    f.createNewFile();
    } catch (IOException e) {

    }
    return f;
    } else {
    return null;
    }
    }

    private boolean isSDCARDMounted(){
    String status = Environment.getExternalStorageState();
    if (status.equals(Environment.MEDIA_MOUNTED))
    return true;
    return false;
    }




protected void onActivityResult(int requestCode, int resultCode,
        Intent imageReturnedIntent) {
    super.onActivityResult(requestCode, resultCode, imageReturnedIntent);

    switch (requestCode) {
    case REQ_CODE_PICK_IMAGE:
        if (resultCode == RESULT_OK) {  
          if (imageReturnedIntent!=null){



               File tempFile = getTempFile();

              String filePath= Environment.getExternalStorageDirectory()
            + "/temporary_holder.jpg";
              System.out.println("path "+filePath);


    Bitmap selectedImage =  BitmapFactory.decodeFile(filePath);
    _image = (ImageView) findViewById(R.id.image);
    _image.setImageBitmap(selectedImage );

}
}
}

код отсюда

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

Короткий ответ

Краткий ответ - не использовать опцию возврата данных. Подробнее об этом и о том, как получить изображение, читайте здесь: http://www.androidworks.com/crop_large_photos_with_android. Статья отлично справляется со списком (известных) параметров конфигурации для Intent и того, как их использовать.

Вариант № 2. Если вы установите для "return-data" значение "false", вы не получите растровое изображение обратно из встроенного намерения onActivityResult, вместо этого вам нужно будет установить MediaStore.EXTRA_OUTPUT на Uri (только для файловой схемы), где вы хотите сохранить растровое изображение. Это имеет некоторые ограничения, во-первых, вам нужно иметь временное местоположение файловой системы, чтобы дать URI схемы файла, а это не большая проблема (за исключением некоторых устройств, у которых нет sdcards).

    /** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    thiz = this;
    setContentView(R.layout.main);
    mBtn = (Button) findViewById(R.id.btnLaunch);
    photo = (ImageView) findViewById(R.id.imgPhoto);
    mBtn.setOnClickListener(new OnClickListener(){

        public void onClick(View v) {
            try {
                // Launch picker to choose photo for selected contact
                Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
                intent.setType("image/*");
                intent.putExtra("crop", "true");
                intent.putExtra("aspectX", aspectX);
                intent.putExtra("aspectY", aspectY);
                intent.putExtra("outputX", outputX);
                intent.putExtra("outputY", outputY);
                intent.putExtra("scale", scale);
                intent.putExtra("return-data", return_data);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, getTempUri());
                intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
                intent.putExtra("noFaceDetection",!faceDetection); // lol, negative boolean noFaceDetection
                if (circleCrop) {
                    intent.putExtra("circleCrop", true);
                }

                startActivityForResult(intent, PHOTO_PICKED);
            } catch (ActivityNotFoundException e) {
                Toast.makeText(thiz, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show();
            }
        }
    });
}

private Uri getTempUri() {
    return Uri.fromFile(getTempFile());
}

private File getTempFile() {
    if (isSDCARDMounted()) {
        File f = new File(Environment.getExternalStorageDirectory(),TEMP_PHOTO_FILE);
        try {
            f.createNewFile();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            Toast.makeText(thiz, R.string.fileIOIssue, Toast.LENGTH_LONG).show();
        }
        return f;
    } else {
        return null;
    }
}

private boolean isSDCARDMounted(){
    String status = Environment.getExternalStorageState();    
    if (status.equals(Environment.MEDIA_MOUNTED))
        return true;
    return false;
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    switch (requestCode) {
        case PHOTO_PICKED:
            if (resultCode == RESULT_OK) {
                if (data == null) {
                    Log.w(TAG, "Null data, but RESULT_OK, from image picker!");
                    Toast.makeText(this, R.string.no_photo_picked,
Toast.LENGTH_SHORT).show();
                    return;
                }

            final Bundle extras = data.getExtras();
            if (extras != null) {
                File tempFile = getTempFile();
                // new logic to get the photo from a URI
                if (data.getAction() != null) {
                    processPhotoUpdate(tempFile);
                }
            }
        }
        break;
    }
}

Пример кода с: http://www.androidworks.com/crop_large_photos_with_android

Дополнительная информация

Длинный ответ не использовать это намерение вообще. Продолжайте читать, чтобы узнать почему.

Неофициальный API

Суть проблемы заключается в неофициальном намерении. Неофициальный, так как не является частью публичного API. В настоящее время это работает для большинства устройств, но большинство просто не достаточно. Также Google может изменить это намерение в любое время, не сообщая об этом. Разбивая все приложения, использующие его. Очень похоже на то, как когда-то API календаря был неофициальным. На самом деле эта цель уже однажды изменилась. Поэтому избегайте использования этого намерения. Есть альтернативы. Не стесняйтесь игнорировать этот совет.

Просто чтобы проверить "работает для некоторых устройств" перейдите по этой ссылке и наслаждайтесь разочарованными разработчиками Android, обсуждающими то, что следует считать частью основных функций Android (и не является): https://code.google.com/p/android/issues/detail?id=1480

Время для примера кода? Проверьте этот проект GitHub: https://github.com/lorensiuswlt/AndroidImageCrop

О пределе размера

Еще одна проблема, с которой я столкнулся при исследовании этого намерения, - это ограничение размера кадрирования изображения. Это может быть легко воспроизведено с использованием приведенного выше примера кода и размером изображения более 300 пикселей. В основном, о чем этот оригинальный вопрос. В лучшем случае ваше приложение будет зависать. Но я видел еще хуже до зависания устройств, которые можно было сбросить только при извлечении батареи.

Теперь, если вы удалите эту опцию 'return-data', вы сможете запустить ее снова. Более подробную информацию о том, как получить результат, можно найти в кратком ответе, где я уже ссылался на эту ссылку: http://www.androidworks.com/crop_large_photos_with_android

Решение

Так много проблем. Проблемы требуют решения. Единственное достойное решение до тех пор, пока Google не предложит открытый API для этого, - это обеспечить ваше собственное намерение. Просто возьмите в руки подходящую библиотеку, такую ​​как эта, на github: https://github.com/lvillani/android-cropimage

В проекте отсутствует некоторая документация, но, поскольку это выдержка из неофициального намерения обрезки андроида, вы можете использовать приведенные выше примеры, чтобы начать. Просто убедитесь, что вы не используете опцию return-data. Ах, и проверьте класс CropImageIntentBuilder. Это должно позволить вам легко создать цель для обрезки. Не забудьте добавить эту активность в манифест и разрешения на запись во внешнее хранилище данных.

private void doCrop(File croppedResult){
        CropImageIntentBuilder builder = new CropImageIntentBuilder(600,600, croppedResult);
        // don't forget this, the error handling within the library is just ignoring if you do
        builder.setSourceImage(mImageCaptureUri);
        Intent  intent = builder.getIntent(getApplicationContext());
        // do not use return data for big images
        intent.putExtra("return-data", false);
        // start an activity and then get the result back in onActivtyResult
        startActivityForResult(intent, CROP_FROM_CAMERA);
    }

Использование этой библиотеки также открывает двери для дополнительной настройки. Полезно знать, является ли базовое растровое изображение функционально используемым для изменения размера: Как обрезать проанализированное изображение в Android?

И это все. Наслаждайтесь!

Другие вопросы по тегам