быстрый доступ к пикселям и управление ими на Android

#android #image #android-canvas #draw #pixel

#Android #изображение #android-холст #рисовать #пиксель

Вопрос:

Я пытаюсь перенести эмулятор, который я написал на Java, на Android. Все шло хорошо, я смог перенести большую часть своих кодов с незначительными изменениями, однако из-за того, как работает эмуляция, мне нужно отображать изображение на уровне пикселей.

Что касается настольной Java, я использую

 int[] pixelsA = ((DataBufferInt) src.getRaster().getDataBuffer()).getData(); 
  

что позволяет мне получать ссылку на пиксельный буфер и обновлять его на лету (минимизировать создание объектов)

В настоящее время это то, что мой эмулятор для Android делает для каждого кадра

 @Override
public void onDraw(Canvas canvas)
{
    buffer = Bitmap.createBitmap(pixelsA, 256, 192, Bitmap.Config.RGB_565);
    canvas.drawBitmap(buffer, 0, 0, null);

}   
  

pixelsA — это массив int[], pixelsA содержит всю информацию о цвете, поэтому для каждого кадра он должен будет создавать растровый объект, выполняя

 buffer = Bitmap.createBitmap(pixelsA, 256, 192, Bitmap.Config.RGB_565);
  

я считаю, что это довольно дорого и медленно.

Есть ли какой-нибудь способ эффективно рисовать пиксели с помощью canvas?

Комментарии:

1. Правда, CreateBitmap работает медленно, это копирование в память и даже преобразование формата пикселей в вашем случае!

Ответ №1:

Один довольно низкоуровневый метод, но для меня он работает нормально (с собственным кодом):

Создайте Bitmap объект размером с ваш видимый экран. Также создайте View объект и реализуйте onDraw метод.

Затем в машинном коде вы загружаете libjnigraphics.итак, встроенная библиотека, функции поиска AndroidBitmap_lockPixels и. AndroidBitmap_unlockPixels Эти функции определены в исходном коде Android в bitmap.h.

Затем вы вызываете блокировку / разблокировку растрового изображения, получая адрес в необработанных пикселях. Вы должны интерпретировать формат пикселей RGB в соответствии с тем, что он есть на самом деле (16-разрядный 565 или 32-разрядный 8888).

После изменения содержимого растрового изображения вы хотите отобразить это на экране. Вызовите View.invalidate() свой View . В its onDraw превратите ваше растровое изображение в заданное Canvas .

Этот метод очень низкоуровневый и зависит от фактической реализации Android, однако он очень быстрый, вы можете получить 60 кадров в секунду без проблем.

bitmap.h является частью Android NDK с версии платформы 8, так что это официальный способ сделать это с Android 2.2.

Ответ №2:

Вы можете использовать метод drawBitmap, который позволяет избежать создания растрового изображения каждый раз или даже в крайнем случае рисовать пиксели один за другим с помощью drawPoint.

Комментарии:

1. Я попробовал метод drawBitmap, который принимает int[] в качестве своего параметра, это дает хороший прирост производительности по сравнению с созданием растровых объектов. Кажется, это единственный способ (я думаю) достичь приемлемой производительности, не прибегая к машинному коду.

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

Ответ №3:

Не воссоздавайте растровое изображение каждый раз. Попробуйте что-то вроде этого:

 Bitmap buffer = null;
@Override
public void onDraw(Canvas canvas)
{
    if(buffer == null) buffer = Bitmap.createBitmap(256, 192, Bitmap.Config.RGB_565);
    buffer.copyPixelsFromBuffer(pixelsA);
    canvas.drawBitmap(buffer, 0, 0, null);
}
  

РЕДАКТИРОВАТЬ: как указывалось, вам необходимо обновить буфер пикселей. И растровое изображение должно быть изменяемым, чтобы это произошло.

Комментарии:

1. Это не сработает. Bitmap инициализирует свой собственный пиксельный буфер в CreateBitmap, его вызов не приведет к обновлению пикселей Bitmap.

Ответ №4:

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

 canvas.drawBitmap(pixelsA, 0, 256, 0, 0, 256, 192, false, null);