Рисование растровых изображений с альфа-каналом: пожалуйста, сообщите ... (некоторые решения и проблемы со скоростью) - PullRequest
2 голосов
/ 12 января 2012

У меня довольно большое количество маленьких растровых изображений (100+, размер около 40x40), каждое из которых имеет непрозрачные и прозрачные части, и мне нужно нарисовать их с учетом этих областей.

Растровые изображения в формате ARGB, 888 (rgb) плюс 256-битный альфа-канал, стандартный, как в формате PNG.

Единственный (рабочий) способ, которым я нашел их рисование, это следующий подход:

  1. создатьрастровое изображение (ARGB_8888)
  2. заполнить растровое изображение необработанными данными
  3. извлечь альфа-слой из растрового изображения
  4. создать BitmapShader (RGB_565) на основе исходного растрового изображения
  5. Создание краски для растрового изображения, в которой используется созданный шейдер

  6. Затем нарисуйте альфа-маску с помощью краски с помощью специального BitmapShader.

Код инициализации запускается только один раз, конечно:

void initializeTile( int t ){
// Allocate the bitmap:
Bitmap original_data = Bitmap.createBitmap( tile_w, tile_h, Bitmap.Config.ARGB_8888);
// Fill with raw data (this is actually native C++ code):
populateBitmap( original_data );
// Get the alpha mask:
tile_mask[ t ] = original_data.extractAlpha();
// Create the bitmap shader:
tile_data = original_data.copy( Bitmap.Config.RGB_565, false);
// Create the shader:
BitmapShader shader = new BitmapShader(tile_data, CLAMP, CLAMP);

// Create the paint:
tile_paint[ t ] = new Paint();
tile_paint[ t ].setDither(true);
tile_paint[ t ].setAntiAlias(true);
tile_paint[ t ].setFilterBitmap(true);
tile_paint[ t ].setShader( shader );
}

И код рисования является наиболее простым, и он находится в главном цикле рисования:

void paintTile(t){
canvas.drawBitmap( tile_mask[ t ],  tile_x[ t], tile_y[ t], tile_paint[ t] );
}

Теперь на таких телефонах, как Ideos (Android 2.2)он работает плавно и нормально, но на других телефонах, таких как топовый Samsung Galaxy SII (Android 2.3), он дрянной и медленный.Это не имеет большого смысла для меня ...

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

И почему, по вашему мнению, это слишком медленно на современном быстром оборудовании?Есть ли способы улучшить его?

1 Ответ

4 голосов
/ 13 января 2012

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

Но, если это понадобится большему количеству людей, я публикую свое новое решение, которое намного быстрее, хотя и немного сложнее. Основная идея заключается в том, чтобы использовать шейдерный подход ТОЛЬКО во время инициализации, а не для рисования.

Чтобы сделать это, я создаю новое растровое изображение, которое будет содержать «обрезанное» растровое изображение (со всеми очищенными прозрачными областями), используя подход шейдера, затем нарисуйте это обрезанное растровое изображение без какого-либо шейдера в коде рисования.

void initializeTile( int t ){
// Allocate the bitmap:
Bitmap original_data = Bitmap.createBitmap( tile_w, tile_h, Bitmap.Config.ARGB_8888);
// Fill with raw data (this is actually native C++ code):
populateBitmap( original_data );

// Now make a new bitmap to be clipped:
Bitmap clipped_data = Bitmap.createBitmap( tile_w, tile_h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(clipped_data);
Paint clip_paint = new Paint();
clip_paint.setDither(true);
clip_paint.setAntiAlias(true);
clip_paint.setFilterBitmap(true);
clip_paint.setShader( new BitmapShader(original_data, CLAMP, CLAMP));
// Paint the clipped bitmap:
canvas.drawBitmap( tile_mask[ t ], 0, 0, clip_paint );
//Use the clipped bitmap as original bitmap:
tile_data[ t ] = clipped_data;
}

А также чертежный код:

void paintTile(t){
canvas.drawBitmap( tile_data[ t ],  tile_x[ t], tile_y[ t], null );
}

В целом, это намного быстрее. Тем не менее, мне неясно, ПОЧЕМУ Android не будет правильно рисовать мои альфа-каналы без всех этих беспорядков!

...