![](images/chestnut/misc/left.gif) |
Android Разработка игр на платформе Android |
24.12.2013, 13:35
|
#1
|
ПроЭктировщик
Регистрация: 09.05.2010
Адрес: рф ро шахты
Сообщений: 177
Написано 66 полезных сообщений (для 271 пользователей)
|
Работа с пикселами битовой карты
попробовал применять фильтры и матрицы родными средствами андроид. показалось, что медленно. и тут я сделал глупость. накидал свой обработчик битмапов. теперь отрисовка приведенного в оффтопе примера (поворот картинки на произвольный угол с соответствующим увеличением размеров) на эмуляторе проходит за 9 с лишним секунд! вот это ускорил! понимаю, что дурак, но сам никак не соображу, где я не прав. не подскажете?
// кусочек кода активити для теста ImageView ivMain;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ivMain = (ImageView) findViewById(R.id.ivMain); Bitmap bmp = BitmapFactory.decodeResource(getApplicationContext().getResources(), getApplicationContext().getResources().getIdentifier("cvetochek", "drawable", getPackageName())); long ms = System.currentTimeMillis(); Trans t = Trans(bmp); t.add_act(Trans.T_ROTATE, 45); ivMain.setImageBitmap(t.doit()); ms = System.currentTimeMillis() - ms; Log.d("Trans", "time=" + ms); }
![](images/chestnut/misc/code_php.gif)
package ik.puk.tralyalya;
import java.util.ArrayList; import java.util.Arrays;
import android.graphics.Bitmap; import android.util.Log;
// класс для БЫСТРОГО (ага, молния, бля!) выполнения нескольких примитивных трансформаций битмапа // основные функции: // конструктор Trans(Bitmap bitmap) - создать оъект класса Trans, добавив битмап, который будет преобразовываться // void add_act(int action, int[] params) - добавить действие с параметрами // Bitmap doit() - выполнить все действия с битмапом и получить результирующий битмап public class Trans { // битмапы: исходный и результирующий private static int[] bmp = null; private static int[] new_bmp = null; // размеры битовых карт private static int bmp_w = 0; private static int bmp_h = 0; private static int new_bmp_w = 0; private static int new_bmp_h = 0; public static final int default_color = 0; // типы действий, совершаемых над битмапом public static final int T_NONE = 0; // ничего не делать public static final int T_RESIZE = 1; // изменить размер public static final int T_CROP = 2; // размер полотна (вырезать кусок или добавить края) public static final int T_FREE = 3; // свободная трансформация по четырем угловым точкам public static final int T_ROTATE = 4; // повернуть на угол public static final int T_FLIPV = 5; // отобразить по вертикали public static final int T_FLIPH = 6; // отобразить по горизонтали public static final int T_OPACITY = 7; // прозрачность, изменяется только альфа-канал public static final int T_GREY = 8; // оттенки серого public static final int T_ANDMASK = 9; // маска. argb &= mask public static final int T_ORMASK = 10; // маска. argb |= mask public static final int T_XORMASK = 11; // маска. argb ^= mask public static final int T_INVERT = 12; //обратить цвета. a = a; r = !r; g = !g; b = !b // вспомогательный класс для хранения типа действия и параметров в одной кучке private class Act { int act; int[] params; public Act(int act, int[] params) { this.act = act; this.params = params; } } // список последовательности действий, которые будут производиться над битмапом private static ArrayList<Act> actions; // конструктор класса. на входе - битмап в виде массива public Trans(Bitmap bitmap) { actions = new ArrayList<Act>(); bmp_w = bitmap.getWidth(); bmp_h = bitmap.getHeight(); bmp = new int[bmp_w*bmp_h]; bitmap.getPixels(bmp, 0, bmp_w, 0, 0, bmp_w, bmp_h); bitmap.recycle(); }
// добавить действие без параметров в список public void add_act(int action) { actions.add(new Act(action, null)); } // добавить действие в список public void add_act(int action, int[] params) { actions.add(new Act(action, params)); } // добавить действие с одним параметром public void add_act(int action, int angle) { actions.add(new Act(action, new int[]{angle})); }
// добавить действие с двумя параметрами public void add_act(int action, int w, int h) { actions.add(new Act(action, new int[]{w, h})); }
// добавить действие с четырьмя параметрами public void add_act(int action, int x, int y, int w, int h) { actions.add(new Act(action, new int[]{x, y, w, h})); }
// добавить действие с восемью параметрами public void add_act(int action, int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { actions.add(new Act(action, new int[]{x0, y0, x1, y1, x2, y2, x3, y3})); } // перенос нового битмапа в старый private static void exchange() { bmp_w = new_bmp_w; bmp_h = new_bmp_h; bmp = new_bmp; new_bmp = null; } // находится ли пиксель в пределах битовой карты? private static boolean in_bmp(int x, int y) { return ((x >= 0)&&(y >= 0)&&(x < bmp_w)&&(y < bmp_h)); }
// находится ли пиксель в пределах битовой карты? private static boolean in_new_bmp(int x, int y) { return ((x >= 0)&&(y >= 0)&&(x < new_bmp_w)&&(y < new_bmp_h)); } // свободная трансформация // на входе координаты четырех углов, по которым нужно растянуть битмап private static void t_free(int n[]) { if (n.length == 8) { double x0 = n[0]; double y0 = n[1]; double x1 = n[2]; double y1 = n[3]; double x2 = n[4]; double y2 = n[5]; double x3 = n[6]; double y3 = n[7]; // new_x = A1*x + B1*x*y + C1*y + x0; // new_y = A2*x + B2*x*y + C2*y + y0; new_bmp = new int[bmp_w*bmp_h]; Arrays.fill(new_bmp, default_color); double w = bmp_w; double h = bmp_h; double A1 = (x1 - x0)/w; double A2 = (y1 - y0)/w; double C1 = (x3 - x0)/h; double C2 = (y3 - y0)/h; double B1 = (x2 - x3 - x1 + x0)/w/h; double B2 = (y2 - y3 - y1 + y0)/w/h; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { int new_x = (int)(A1*x + B1*x*y + C1*y + x0); int new_y = (int)(A2*x + B2*x*y + C2*y + y0); if (in_bmp(new_x, new_y)) { new_bmp[new_x + new_y*new_bmp_w] = bmp[x + y*bmp_w]; } } } exchange(); } }
// растягивание битмапа private static void t_resize(int[] n) { if (n.length == 2) { new_bmp_w = n[0]; new_bmp_h = n[1]; new_bmp = new int[new_bmp_w*new_bmp_h]; Arrays.fill(new_bmp, default_color); for (int y = 0; y < new_bmp_h; y++) { for (int x = 0; x < new_bmp_w; x++) { int xx = (int)(Math.round(x*bmp_w/new_bmp_w)); int yy = (int)(Math.round(y*bmp_h/new_bmp_h)); if (in_bmp(xx, yy)) { new_bmp[x + y*new_bmp_w] = bmp[xx + yy*bmp_w]; } } } exchange(); } }
// вырезание куска битмапа (или изменение размера полотна) // на входе - новые ширина/высота или координаты нового верхнего левого угла и новые ширина/высота private static void t_crop(int[] n) { int dx = 0; int dy = 0; int new_w = 0; int new_h = 0; if ((n.length == 2)||(n.length == 4)) { if (n.length == 2) { new_w = n[0]; new_h = n[1]; dx = Math.round((new_w - bmp_w)/2); dy = Math.round((new_h - bmp_h)/2); } else { dx = n[0]; dy = n[1]; new_w = n[2]; new_h = n[3]; } new_bmp_w = new_w; new_bmp_h = new_h; new_bmp = new int[new_w*new_h]; Arrays.fill(new_bmp, default_color); for (int y = 0; y < new_bmp_h; y++) { for (int x = 0; x < new_bmp_w; x++) { int xx = x - dx; int yy = y - dy; if (in_bmp(xx, yy)) { new_bmp[x + y*new_bmp_w] = bmp[xx + yy*bmp_w]; } } } exchange(); } } // поворот битмапа на угол private static void t_rotate(int n[]) { if (n.length > 0) { int a = n[0]; double sn = Math.sin(Math.toRadians(a)); double cs = Math.cos(Math.toRadians(a)); new_bmp_w = bmp_w; new_bmp_h = bmp_h; int xc = bmp_w/2; int yc = bmp_h/2; int x0 = (int) (Math.cos(Math.toRadians(a))*(bmp_w - xc) + Math.sin(Math.toRadians(a))*(bmp_h - yc) + xc); int x1 = (int) (Math.cos(Math.toRadians(a))*(-xc) + Math.sin(Math.toRadians(a))*(-yc) + xc); int y0 = (int) (Math.cos(Math.toRadians(a))*(bmp_h - yc) - Math.sin(Math.toRadians(a))*(bmp_w - xc) + yc); int y1 = (int) (Math.cos(Math.toRadians(a))*(-yc) - Math.sin(Math.toRadians(a))*(-xc) + yc); new_bmp_w = (int) (Math.abs(x1 - x0)); new_bmp_h = (int) (Math.abs(y1 - y0)); Log.d("Trans", "w=" + new_bmp_w); Log.d("Trans", "h=" + new_bmp_h);
t_crop(new int[] {new_bmp_w, new_bmp_h}); xc = bmp_w/2; yc = bmp_h/2; new_bmp = new int[new_bmp_w*new_bmp_h]; for (int new_y = 0; new_y < bmp_h; new_y++){ for (int new_x = 0; new_x < bmp_w; new_x++) { int x = (int) ((cs*(new_x - xc) + sn*(new_y - yc)) + xc); int y = (int) ((cs*(new_y - yc) - sn*(new_x - xc)) + yc); if (in_bmp(x, y)&&(in_new_bmp(new_x, new_y))) { new_bmp[new_x + new_y*new_bmp_w] = bmp[x + y*bmp_w]; } } } exchange(); } } // отобразить битмап по горизонтали private static void t_fliph() { new_bmp_w = bmp_w; new_bmp_h = bmp_h; new_bmp = new int[bmp_w*bmp_h]; for (int y = 0; y < bmp_h; y++) { for (int x = 0; x < bmp_w; x++) { new_bmp[x + y*bmp_w] = bmp[bmp_w - x - 1 + y*bmp_w]; } } exchange(); }
// отобразить битмап по вертикали private static void t_flipv() { new_bmp_w = bmp_w; new_bmp_h = bmp_h; new_bmp = new int[bmp_w*bmp_h]; for (int y = 0; y < bmp_h; y++) { for (int x = 0; x < bmp_w; x++) { new_bmp[x + y*bmp_w] = bmp[x + (bmp_h - y - 1)*bmp_w]; } } exchange(); } // выполнить все преобразования из списка и вернуть результат в виде битмапа public Bitmap doit() { new_bmp_w = bmp_w; new_bmp_h = bmp_h; new_bmp = new int[new_bmp_w*new_bmp_h]; while (actions.size() > 0) { Act act = actions.get(0); switch (act.act) { case T_RESIZE: t_resize(act.params); break; case T_CROP: t_crop(act.params); break; case T_FREE: t_free(act.params); break; case T_ROTATE: t_rotate(act.params); break; case T_FLIPH: t_fliph(); break; case T_FLIPV: t_flipv(); break; } actions.remove(0); } new_bmp = null; return Bitmap.createBitmap(bmp, bmp_w, bmp_h, Bitmap.Config.ARGB_8888); } }
__________________
to be or not to be - it's not a question!
2b or not 2b = ff
|
(Offline)
|
|
24.12.2013, 14:16
|
#2
|
Разработчик
Регистрация: 06.04.2008
Сообщений: 541
Написано 196 полезных сообщений (для 637 пользователей)
|
Ответ: Работа с пикселами битовой карты
Я думаю, если у тебя идет такая интенсивная работа с изображениями - масштабирование, повороты, стоит попробовать OpenGL, причем не напрямую, а какой-нибудь бесплатный открытый движок, рекомендую LibGDX. Гонять туда-сюда битмапы - не вариант.
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
24.12.2013, 15:24
|
#3
|
ПроЭктировщик
Регистрация: 09.05.2010
Адрес: рф ро шахты
Сообщений: 177
Написано 66 полезных сообщений (для 271 пользователей)
|
Ответ: Работа с пикселами битовой карты
работа не очень интенсивная, как я считал. раз в 100 миллисекунд крутнуть, растянуть 2-4 картинки. и то не всё время, а на время анимации объектов...
додумался проверить только что время работы функций извлечения битмапов. взять/положить один битмап - 800мс. прогнать фильтр по каждой точке - еще секунды полторы-две. пипец. а хотел использовать для работы именно с imageView, чтобы она сама мне результат уже масштабированный как надо на экран выводила (
ок, буду пользоваться движками. тогда и контролы самому придется изобретать, как я понял, да?
---
з.ы.: еще немного тут с Romanzes-ом пообщаюсь - и сам программистом стану)))
__________________
to be or not to be - it's not a question!
2b or not 2b = ff
Последний раз редактировалось barsunduk, 25.12.2013 в 12:10.
|
(Offline)
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 14:41.
|