Растровое изображение не нарисовано сглаживанием

У меня есть пользовательский View, который всегда рисует Bitmap при определенном вращении. Я перезаписываю метод onDraw, поворачиваю Canvas и рисую растровое изображение с помощью сглаживания Paint.

public RotatedImageView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    someBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.placeholder);
}

@Override
protected void onDraw(Canvas canvas) {

    // Save and rotate canvas
    canvas.save();
    canvas.rotate(3F, getWidth() / 2, getHeight());

    // Draw the icon
    Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
    canvas.drawBitmap(someBitmap, 0, 0, p);
    canvas.drawRoundRect(new RectF(75, 50, 225, 200), 10, 10, p);

    // All done; restore canvas
    canvas.restore();
}

Однако, я всегда получаю зубчатые края в растровом изображении. Обратите внимание, что рулонный прямоугольник получает красиво сглаженные края. Кроме того, когда я применяю p.setFilterBitmap(true);, это работает (поверхность растрового изображения фильтруется/сглаживается) правильно. Я что-то пропустил?

No anti-aliasing on the photo

Здесь минимальный проект Android с изолированным примером одного экрана, который показывает представление, которое рисует не сглаженный Bitmap, загруженный из ресурса: https://bitbucket.org/erickok/antialiastest

ОБНОВЛЕНИЕ: Я также пробовал следующее:

    Paint p = new Paint();
    p.setAntiAlias(true);
    p.setFilterBitmap(true);
    p.setDither(true);
    canvas.drawBitmap(someBitmap, 0, 0, p);

Но это не помогает, поскольку setFilterBitmap фильтрует поверхность; он не сглаживает края. Кроме того, setAntiAlias делает то же самое, что непосредственно устанавливает флаг в конструкторе Paint. Если есть сомнения, попробуйте мой минимальный тестовый проект. Большое спасибо за любую помощь!

Ответы

Ответ 1

Я выяснил, почему я не получил никакого сглаживания: аппаратное ускорение. После того, как я (по чистой случайности) протестировал на своем Nexus One, он внезапно сработал, а мой Nexus 7 - нет. Оказывается, что ANTI_ALIAS_FLAG ничего не делает, когда Canvas создается с помощью аппаратного ускорения. С этим пониманием я нашел fooobar.com/questions/350007/..., который отвечает на мой вопрос.

Решения выглядят так: добавление прозрачной границы для каждого растрового изображения (вручную или "на лету" ) или "делать что-то с шейдерами". Мне тоже не очень нравятся. Вместо этого я отключил аппаратное ускорение на моем пользовательском представлении с помощью метода setLayerType. Обратите внимание, что это доступно с уровня API 11, но (не случайно) вам не придется заниматься аппаратным ускорением до любого способа. Поэтому я добавил в конструкторе вида:

    if (android.os.Build.VERSION.SDK_INT >= 11) {
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }

Я обновил вышеупомянутый проект с открытым исходным кодом на BitBucket для заинтересованных.

Ответ 2

Используйте setFilterBitmap (true).

paint_object.setFilterBitmap(true);

он работает для меня тоже.. Я получил это от этого вопроса

Рисование растрового растрового изображения с анти-алиасами

установите флаг AntiAlias ​​ и флаг FilterBitmap в true, они вместе сделают планки растровых изображений плавными, я протестировал их на Samsung Galaxy Ace, android 2.2...

Мой тестовый код

Paint p = new Paint();
p.setAntiAlias(true);
p.setFilterBitmap(true);
canvas.drawBitmap(someBitmap, new Matrix(), p);

Ответ 3

В моем случае я сделал это, но может быть, вам понравилось:

Paint paint = new Paint();
paint.setAntiAlias(true);

Просто попробуйте.

Удачи!

Ответ 4

Я тестировал предыдущие предложения, и они работают для меня. Может быть, проблемы в вашем растровом изображении? Может быть, в вашем устройстве? Вот код, который создает bitmap inline. Проверьте, работает ли этот пример для вас.

public class BitmapRotateActivity extends Activity { 

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(new MyView(this));
  }
  class MyView extends View {

    Bitmap bitmap;
    public MyView(Context context) {
      super(context);

      bitmap = Bitmap.createBitmap(160, 160, Bitmap.Config.RGB_565);
      Paint p = new Paint();
      p.setColor(Color.RED);
      p.setStyle(Paint.Style.FILL);
      Canvas c = new Canvas(bitmap);
      c.drawRect(0, 0, bitmap.getWidth(), bitmap.getHeight(), p);
    }

    @Override
    protected void onDraw(Canvas canvas) {
      Paint pbg = new Paint();
      pbg.setStyle(Paint.Style.FILL);
      pbg.setColor(0xffe0e0ff);
      canvas.drawRect(0, 0, getWidth(), getHeight(), pbg);

      Paint p = new Paint();
      p.setAntiAlias(true);
      p.setFilterBitmap(true);

      canvas.save();
      canvas.rotate(3F, getWidth() / 2, getHeight() / 2);
      canvas.drawBitmap(bitmap, 30, 30, p);
      canvas.restore();
    }
  }
}

Ответ 5

У меня была такая же проблема, и я попробовал все эти исправления. Что в конечном итоге сработало, это глобальное отключение аппаратного ускорения в файле AndroidManifest.xml:

 <application
       android:hardwareAccelerated="false" 
  ...
 >

а затем отключив inSampleSize, когда я загрузил растровое изображение изображения, чтобы (я полагаю) изображение загрузилось с достаточно высоким качеством, чтобы избежать любых зигзагов, а затем для моего фактического ImageView, используя приведенный выше совет: установка уровня введите в View.LAYER_TYPE_SOFTWARE, с объектом рисования с растровым изображением фильтра, установленным в true (как указано выше) и сглаживанием.