Заполнение данных в растровом изображении Android как можно быстрее с помощью C

#java #android #c #bitmap #java-native-interface

#java #Android #c #растровое изображение #java-native-interface

Вопрос:

Мне удалось получить android.graphics.Создано растровое изображение, и я успешно заполняю его с помощью команды SetPixels.

Проблема в том, что я начинаю с данных RGBA. Затем я создаю jintArray. Затем я вызываю SetIntArray (эффективно записываю данные в буфер). Затем, наконец, я вызываю SetPixels, чтобы фактически установить пиксели (что, предположительно, вызывает другую копию).

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

В идеале мне нужен способ заполнения буфера с использованием только одной копии и позволяющий мне делать это без преобразования формата пикселей.

Есть ли какой-либо способ напрямую получить доступ к данным буфера, содержащимся в растровом изображении? Я вижу, что в JNI есть функция GetDirectBufferAddress, но документация, которую я могу найти по ней, предполагает, что она ограничена java.nio.buffer . Могу ли я напрямую получить данные в пикселях, используя эту функцию? Возможно, путем получения внутреннего буфера, используемого классом Bitmap?

Является ли мой единственный способ использовать это для создания глобальной ссылки Java.nio.buffer, затем каждый раз, когда я хочу обновить, скопируйте в него мои пиксельные данные, а затем используйте copyPixelsFromBuffer? Это все еще требует 2 копий, но может, по крайней мере, исключить изменение формата пикселей. Будет ли это более эффективным, чем метод, который я уже использую?

Есть ли еще лучший способ сделать это?

Кстати, я знаю о том, что могу использовать функции в < android/bitmap.h >, но мне бы очень хотелось не потерять поддержку Android 2.1 и Android 2.2 …

Заранее приветствую!

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

1. 2.2 поддерживает <android/bitmap.h>, поэтому вы потеряете только 2.1. На данный момент я не думаю, что это такая большая потеря…

2. Прямой доступ к пикселям растрового изображения возможен также на 2.1 (даже на 1.5), я использую его, проверено на работу, но это своего рода взлом в NDK. Если вы можете, продолжайте использовать official bitmap.h и AndroidBitmap_lockPixels / AndroidBitmap_unlockPixels.

3. @mice I use it, tested to work, but it's kind of hacking in NDK — Не могли бы вы опубликовать подробности?

Ответ №1:

Вот грязное, но рабочее решение, работающее с Android 1.5 до 4.0. Код написан на C .

                               //decls of some partial classes from Skia library
class SkRefCnt{
public:
   virtual ~SkRefCnt(){}
private:
   mutable int fRefCnt;
};

//----------------------------

class SkPixelRef: public SkRefCnt{
public:
   virtual class Factory getFactory() const;
   virtual void flatten(class SkFlattenableWriteBufferamp;) const;
protected:
   virtual void* onLockPixels(class SkColorTable**) = 0;
   virtual void onUnlockPixels() = 0;
public:
   void *GetPixels(){
      SkColorTable *ct;
      return onLockPixels(amp;ct);
   }
};

jobject java_bitmap;  //your Bitmap object
jclass java_bitmap_class = env.GetObjectClass(java_bitmap);
class SkBitmap;
SkBitmap *sk_bitmap = (SkBitmap*)env.CallIntMethod(java_bitmap, env.GetMethodID(java_bitmap_class, "ni", "()I"));
SkPixelRef *sk_pix_ref;
sk_pix_ref = (SkPixelRef*)((int*)sk_bitmap)[1];
// get pointer to Bitmap's pixel memory, and lenght of single line in bytes
int buffer_pitch = env.CallIntMethod(java_bitmap, env.GetMethodID(java_bitmap_class, "getRowBytes", "()I"));
void *buffer = sk_pix_ref->GetPixels();
  

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

1. Что именно представляет собой библиотека skia?

2. Часть Android. Графическая библиотека тесно связана с классами Java (Canvas, Bitmap, Paint). Так что это всегда есть, на каждом устройстве.

3. Прохладный. Это где-нибудь задокументировано?

4. Что именно? Skia находится в исходном коде Android, вы можете скачать его и изучить. Также доступны исходные тексты Java.

5. Спасибо, это работает почти из коробки и сэкономило много часов.

Ответ №2:

AFAIK, статический метод:

 public static Bitmap createBitmap (int[] colors, int offset, int stride, int width, int height, Bitmap.Config config)
  

не требует копирования данных, но создает (неизменяемую) структуру растрового изображения поверх существующего массива пикселей. Таким образом, вы можете подготовить такое растровое изображение заранее, а затем управлять буфером из своего
собственного кода. Это должно поддерживать различные форматы пикселей. Пример использования доступен здесь:

http://javaocr.svn.sourceforge.net/viewvc/javaocr/trunk/demos/recognizer/src/net/sf/javaocr/demos/android/recognizer/Recognizer.java?revision=239amp;view=markup

( Строка 520 )

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

1. Он должен выполнить копирование. В противном случае, как он меняется с массива int на растровое изображение «ALPHA_8»? Однако я не вижу, что показывает ваша ссылка, кроме того, как создать растровое изображение (что я уже могу сделать с C ). Однако мне нужно регулярно обновлять изображение, и каждый раз создавать новое растровое изображение очень расточительно…

2. Почему оно должно измениться на ALPHA_8, если мои пиксели уже RGBA? По моей ссылке показан пример приложения OCR для Android — в Java есть немало возможностей для обработки изображений

3. Но что, если растровое изображение не является RGBA?? Я не использую RGBA, потому что он слишком медленный для заполнения растрового изображения…

4. затем вам нужно скопировать. Вы всегда обмениваете память на скорость — я решил работать с целыми пикселями в линейном массиве, даже если мне нужен 1 бит. Я трачу много памяти, но я могу определить растровое изображение поверх него, не справляясь.

5. Но если вы создаете растровое изображение каждый раз, когда хотите его изменить, вы не только тратите впустую память и скорость заполнения, но и тратите массу времени на создание объектов…