Порівняння двох малюнків у android


Відповіді:


150

Оновлення https://stackoverflow.com/a/36373569/1835650

getConstantState () працює погано

Існує ще один спосіб порівняння:

mRememberPwd.getDrawable().getConstantState().equals
            (getResources().getDrawable(R.drawable.login_checked).getConstantState());

mRemeberPwdє ImageViewв цьому прикладі. Якщо ви використовуєте a TextView, використовуйте getBackground().getConstantStateзамість цього.


3
Це рішення працює та покращується, оскільки дозволяє уникнути перетворення Drawable у Bitmap та порівняння.
Брадж

2
Не завжди: WallpaperManager.getInstance (this) .getFastDrawable (). GetConstantState () має значення null.
paulgavrikov

Вибачте, що пізно прийняв це як відповідь і змінив свою власну відповідь, оскільки це здається кращим варіантом (і ще більше прихильників :)). Тож перевіряючи це як відповідь.
Рошан Джа

Дякую, це найкраща відповідь
сатири

8
Цей код чудово працює на пристроях нижче 5.0, але при отриманні помилок при його використанні на пристрої 5.0, хтось може підтвердити, що цей метод працює чи ні на android 5.0 або вище
Phil3992

41

Покладання на getConstantState()одне лише може призвести до помилкових негативів .

Я підходив до того, щоб спробувати порівняти ConstantState спочатку, але повернутися до порівняння Bitmap, якщо ця перевірка не вдається.

Це має працювати у всіх випадках (включаючи зображення, які не є ресурсами), але зауважте, що це вимагає пам'яті.

public static boolean areDrawablesIdentical(Drawable drawableA, Drawable drawableB) {
    Drawable.ConstantState stateA = drawableA.getConstantState();
    Drawable.ConstantState stateB = drawableB.getConstantState();
    // If the constant state is identical, they are using the same drawable resource.
    // However, the opposite is not necessarily true.
    return (stateA != null && stateB != null && stateA.equals(stateB))
            || getBitmap(drawableA).sameAs(getBitmap(drawableB));
}

public static Bitmap getBitmap(Drawable drawable) {
    Bitmap result;
    if (drawable instanceof BitmapDrawable) {
        result = ((BitmapDrawable) drawable).getBitmap();
    } else {
        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();
        // Some drawables have no intrinsic width - e.g. solid colours.
        if (width <= 0) {
            width = 1;
        }
        if (height <= 0) {
            height = 1;
        }

        result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(result);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);
    }
    return result;
}

Це правда на 100% і потребує більше голосів! Люди, будь ласка, протестуйте свій код за допомогою відомих малюнків, перш ніж негайно покладатися на getConstantState()порівняння
лавина

Гарних знахідок! Але згідно з документацією BitmapDrawable.getBitmap (), getBitmap () може бути нульовим, тож ви можете перевірити і це
PhilLab

Ця відповідь вірна, і я перевірив, що після налагодження декількох годин із кодуванням тільки getConstantState ().
Raghav Satyadev

Щоб бути в безпеці, setBoundsі drawна копії замість оригінального stackoverflow.com/a/25462223/1916449
arekolek

Це не працює з тонованими BitmapDrawables (див. SetTintMode / setTint / setTintList). Бітові карти можуть бути однаковими для байта, але з різними властивостями відтінку. Оскільки Android SDK не надає ніяких геттерів для властивостей відтінку, можливо, не існує способу змусити його працювати з тонованими малюнками.
Тео,

13

Моє питання полягало в тому, щоб просто порівняти два малюнки, я спробував, але не зміг отримати жодного методу, який безпосередньо порівнює два малюнки, однак для свого рішення я змінив drawable на растрове зображення, а потім порівняв два растрові зображення, і це працює.

Bitmap bitmap = ((BitmapDrawable)fDraw).getBitmap();
Bitmap bitmap2 = ((BitmapDrawable)sDraw).getBitmap();

if(bitmap == bitmap2)
    {
        //Code blcok
    }

ось що я вам пропонував, порівняти витягуваний за типом витягуваного.
реактивний літак

1
Ви також можете порівняти растрові зображення , як це: stackoverflow.com/a/7696320/317889
HGPB

2
Це дуже важко, тому подумайте про переробку растрових зображень, інакше ви потрапите в OutOfMemoryError!
paulgavrikov

2
Чому ви можете порівнювати растрові зображення з показником рівності (==)? Я очікував би, що потрібен Bitmap.equals ().
Еллен Спертус

@espertus Ви маєте рацію. Я використовував те саме, про що йдеться, для об’єктів, що малюються, не знаю, чому у відповіді звернувся до == для об’єкта растрових зображень. Будь-які способи дякую, що вказали на це основне.
Рошан Джа

9

для SDK 21+

це працює в SDK -21

mRememberPwd.getDrawable().getConstantState().equals
        (getResources().getDrawable(R.drawable.login_checked).getConstantState())

для SDK +21 для андроїд 5. встановіть ідентифікуваний малюнок для перегляду зображення за допомогою тегу

img.setTag(R.drawable.xxx);

і порівняйте так

if ((Integer) img.getTag() == R.drawable.xxx)
{
....your code
}

це рішення для тих, хто хоче порівняти drawableid imageviewз id of drawable.xxx.


Насправді це працює, але я трохи вражений, чому немає іншої можливості T_T!
error1337

4

Рішення для Android 5:

 if(image.getDrawable().getConstantState().equals(image.getContext().getDrawable(R.drawable.something).getConstantState()))

4

getDrawable (int) зараз застарілий. Використовуйте getDrawable (context, R.drawable.yourimageid)

Для порівняння двох фонів

Boolean Condition1=v.getBackground().getConstantState().equals(
ContextCompat.getDrawable(getApplicationContext(),R.drawable.***).getConstantState());

2
Це спрацювало як заклинання для виправлення дивної помилки на Android 5. У моєму коді фактичний малюнок було повернуто context.getResources().getDrawable(R.drawable.***)на Android 6+, але не на Android 5. За допомогою цієї невеликої зміни я можу бездоганно порівнювати фонові малюнки у всіх версіях Android
Jose_GD

3

можливо, спробувати таким чином:

public void MyClick(View view)
{
 Drawable fDraw = view.getBackground();
 Drawable sDraw = getResources().getDrawable(R.drawable.twt_hover);

  if(fDraw.hashCode() == sDraw.hashCode())
  {
   //Not coming
  }
}

або підготуйте метод, який приймає два аргументи, які можна малювати, і повертає логічне значення. За допомогою цього методу ви можете перетворити що малюється в байти і порівняти,

public boolean compareDrawable(Drawable d1, Drawable d2){
    try{
        Bitmap bitmap1 = ((BitmapDrawable)d1).getBitmap();
        ByteArrayOutputStream stream1 = new ByteArrayOutputStream();
        bitmap1.compress(Bitmap.CompressFormat.JPEG, 100, stream1);
        stream1.flush();
        byte[] bitmapdata1 = stream1.toByteArray();
        stream1.close();

        Bitmap bitmap2 = ((BitmapDrawable)d2).getBitmap();
        ByteArrayOutputStream stream2 = new ByteArrayOutputStream();
        bitmap2.compress(Bitmap.CompressFormat.JPEG, 100, stream2);
        stream2.flush();
        byte[] bitmapdata2 = stream2.toByteArray();
        stream2.close();

        return bitmapdata1.equals(bitmapdata2);
    }
    catch (Exception e) {
        // TODO: handle exception
    }
    return false;
}

перевірте оновлену відповідь. якщо все ще не працює, перевірте свої малюнки. Або спробуйте передати ті самі малюнки, щоб перевірити функціональність коду
waqaslam

так, після того, як я не досяг успіху, я думаю те саме для перетворення малюнків у растрове зображення, а потім у байт, дозвольте мені спробувати це, дякую за ваші зусилля
Рошан Джа

не працює, ти тестував? може бути щось не так, хіба ми не можемо безпосередньо порівняти два малюнки?
Рошан Джа

ви пробували, передаючи той самий малювальний для e.g R.drawable.abcобох параметрів?
waqaslam

привіт waqas, ще раз перевір свій метод, а потім ще раз скажи, працює він чи ні, можливо, я роблю щось не так, але це не спрацювало, але тоді це змінює визначення мого запитання про те, як порівняти два малюнки. drawable to bitmap, а потім байти порівнюватимуть bitmap і bytes thats not my demand. якщо ми перевіряємо drawable method, то існує метод .equals (object), тому я думав, що він повинен працювати безпосередньо, але це не так. Ну, ви можете перевірити мою відповідь внизу я перетворюю графічне зображення у растрове зображення, а потім порівнюю два растрові зображення, і воно працює.
Рошан Джа

2

Добре, я думаю, що знайшов найкраще рішення для цього. Через AppCompat та друзів пропонований малюнок іноді завищується у різних формах, тому цього недостатньо getResources().getBitmap(R.drawable.my_awesome_drawable).

Отже, щоб отримати примірник того самого типу та форми, що передбачений видом, можна зробити це:

public static Drawable drawableFrom(View view, @DrawableRes int drawableId) {
    Context context = view.getContext();
    try {
        View dummyView = view.getClass().getConstructor(Context.class).newInstance(context);
        dummyView.setBackgroundResource(drawableId);
        return dummyView.getBackground();
    } catch (Exception e) {
      return ResourcesCompat.getDrawable(context.getResources(), drawableId, null);
    }
}

Це корисно при проведенні тестів. Однак я б не рекомендував робити це на виробництві. Якщо вам потрібно, додаткове кешування буде бажаним, щоб уникнути занадто великих роздумів.

Для тестів Expresso ви можете дуже добре використовувати це:

onView(withDrawable(R.drawable.awesome_drawable))
  .check(matches(isDisplayed()));

або

onView(withId(R.id.view_id))
  .check(matches(withDrawable(R.drawable.awesome_drawable)));

Перш ніж вам доведеться оголосити цей допоміжний клас:

public class CustomMatchers {

  public static Matcher<View> withDrawable(@DrawableRes final int drawableId) {
     return new DrawableViewMatcher(drawableId);
  }
  private static class DrawableViewMatcher extends TypeSafeMatcher<View> {

     private final int expectedId;
     private String resourceName;

     private enum DrawableExtractionPolicy {
        IMAGE_VIEW {
          @Override
          Drawable findDrawable(View view) {
             return view instanceof ImageView ? ((ImageView) view).getDrawable() : null;
          }
        },
        TEXT_VIEW_COMPOUND {
          @Override
          Drawable findDrawable(View view) {
             return view instanceof TextView ? findFirstCompoundDrawable((TextView) view) : null;
          }
        },
        BACKGROUND {
          @Override
          Drawable findDrawable(View view) {
             return view.getBackground();
          }
        };

        @Nullable
        private static Drawable findFirstCompoundDrawable(TextView view) {
          for (Drawable drawable : view.getCompoundDrawables()) {
             if (drawable != null) {
                return drawable;
             }
          }
          return null;
        }

        abstract Drawable findDrawable(View view);

     }

     private DrawableViewMatcher(@DrawableRes int expectedId) {
        this.expectedId = expectedId;
     }

     @Override
     protected boolean matchesSafely(View view) {
        resourceName = resources(view).getResourceName(expectedId);
        return haveSameState(actualDrawable(view), expectedDrawable(view));
     }

     private boolean haveSameState(Drawable actual, Drawable expected) {
        return actual != null && expected != null && areEqual(expected.getConstantState(), actual.getConstantState());
     }

     private Drawable actualDrawable(View view) {
        for (DrawableExtractionPolicy policy : DrawableExtractionPolicy.values()) {
          Drawable drawable = policy.findDrawable(view);
          if (drawable != null) {
             return drawable;
          }
        }
        return null;
     }

     private boolean areEqual(Object first, Object second) {
        return first == null ? second == null : first.equals(second);
     }

     private Drawable expectedDrawable(View view) {
        return drawableFrom(view, expectedId);
     }

     private static Drawable drawableFrom(View view, @DrawableRes int drawableId) {
        Context context = view.getContext();
        try {
          View dummyView = view.getClass().getConstructor(Context.class).newInstance(context);
          dummyView.setBackgroundResource(drawableId);
          return dummyView.getBackground();
        } catch (Exception e) {
          return ResourcesCompat.getDrawable(context.getResources(), drawableId, null);
        }
     }

     @NonNull
     private Resources resources(View view) {
        return view.getContext().getResources();
     }

     @Override
     public void describeTo(Description description) {
        description.appendText("with drawable from resource id: ");
        description.appendValue(expectedId);
        if (resourceName != null) {
          description.appendValueList("[", "", "]", resourceName);
        }
     }
  }

}


0

Я вже відповів на подібну тему тут: Отримайте ідентифікатор, який можна малювати в ImageView . Підхід заснований на тегуванні подання із зазначеним ідентифікатором ресурсу в користувацькому LayoutInflater. Весь процес автоматизований простою бібліотекою TagView .

Як результат, ви можете порівняти два малюнки за їх ідентифікаторами:

TagViewUtils.getTag(view, ViewTag.VIEW_BACKGROUND.id) == R.drawable.twt_hover

0

Розширюючи відповідь від @vaughandroid, наступний Matcher працює для Vector Drawable, який тонується. Ви повинні надати відтінок, який був використаний для Drawable.

public static Matcher<View> compareVectorDrawables(final int imageId, final int tintId) {
        return new TypeSafeMatcher<View>() {

        @Override
        protected boolean matchesSafely(View target) {
            if (!(target instanceof ImageView)) {
                return false;
            }
            ImageView imageView = (ImageView) target;
            if (imageId < 0) {
                return imageView.getDrawable() == null;
            }
            Resources resources = target.getContext().getResources();
            Drawable expectedDrawable = resources.getDrawable(imageId, null);
            if (expectedDrawable == null) {
                return false;
            }

            Drawable imageDrawable = imageView.getDrawable();
            ColorFilter imageColorFilter = imageDrawable.getColorFilter();

            expectedDrawable.setColorFilter(imageColorFilter);
            expectedDrawable.setTintList(target.getResources()
                    .getColorStateList(tintId, null));

            boolean areSame = areDrawablesIdentical(imageDrawable, expectedDrawable);
            return areSame;
        }

        public boolean areDrawablesIdentical(Drawable drawableA, Drawable drawableB) {
            Drawable.ConstantState stateA = drawableA.getConstantState();
            Drawable.ConstantState stateB = drawableB.getConstantState();
            // If the constant state is identical, they are using the same drawable resource.
            // However, the opposite is not necessarily true.
            return (stateA != null && stateB != null && stateA.equals(stateB))
                    || getBitmap(drawableA).sameAs(getBitmap(drawableB));
        }

        public Bitmap getBitmap(Drawable drawable) {
            Bitmap result;
            if (drawable instanceof BitmapDrawable) {
                result = ((BitmapDrawable) drawable).getBitmap();
            } else {
                int width = drawable.getIntrinsicWidth();
                int height = drawable.getIntrinsicHeight();
                // Some drawables have no intrinsic width - e.g. solid colours.
                if (width <= 0) {
                    width = 1;
                }
                if (height <= 0) {
                    height = 1;
                }

                result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
                Canvas canvas = new Canvas(result);
                drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
                drawable.draw(canvas);
            }
            return result;
        }

        @Override
        public void describeTo(Description description) {

        }
    };
}

0

Порівняйте 2 малювальні:

drawable1.constantState == drawable2.constantState
            || drawable1.toBitmap().sameAs(drawable2.toBitmap())

Якщо ви не можете знайти Drawable.toBitmap(...)тут, це Drawable.kt


-1

якщо ви хочете безпосередньо порівняти два малювальні, використовуйте наступний код

Drawable fDraw = getResources (). GetDrawable (R.drawable.twt_hover);

Drawable sDraw = getResources (). GetDrawable (R.drawable.twt_hover);

if (fDraw.getConstantState().equals(sDraw.getConstantState())) {
    //write your code.
} else {
    //write your code.
}

-2

Коли ви використовуєте equals()метод, він використовується для порівняння вмісту. слід спробувати ==порівняти два об’єкти.

public void MyClick(View view)
{
 Drawable fDraw = view.getBackground();
 Drawable sDraw = getResources().getDrawable(R.drawable.twt_hover);

  if( fDraw == sDraw )
  {
   // Coming
  }
}

тоді може бути можливо, що вони не ==, вони є! =
Люцифер

але вони посилаються на одне і те ж зображення з ресурсів
Рошан Джа

Мені просто потрібно перевірити, однакові вони чи ні? Не будь-який доступний для цього метод?
Рошан Джа

так, я отримав вашу вимогу, будь ласка, заходьте до чату
Люцифер

1
== Порівнює, якщо це той самий об’єкт, який це не n 99,99999999% випадків.
Павлгавриков
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.