0

我正在编写一个必须根据接收到的事件绘制已加载位图图像的确定部分的 Android 应用程序。

我需要绘制(或更改当前颜色)位图图像的单个部分,而不更改图像的其余部分。

假设我有一辆汽车,它由许多部分划分:门、窗、轮子等。每次事件(从网络接收)到达时,我需要用指定的颜色更改该特定部分的颜色事件数据。实现这一目标的最佳技术是什么?

我首先想到了 FloodFill,正如 SO 中的许多线程所建议的那样,但考虑到消息的接收速度非常快(每秒几个),我担心它会降低性能,因为它似乎是 CPU 密集型算法。

我还考虑过有多个相同图像的片段,每个片段用不同的颜色着色并在正确的时间显示正确的片段,但汽车至少有 10 个不同的部分,每个部分可以涂上 4-6 种颜色,所以我最终会得到几十张图像,这将是不切实际的处理,更不用说浪费内存了。

那么,还有其他方法吗?

4

1 回答 1

0

最快的方法是使用着色器。为此,您需要使用 OpenGL ES 2(某些 Android 仅支持 ES 1)。您需要一个与要更改的图像大小相同的临时位图。将其设置为目标。在着色器中,从采样器中检索一个像素,该像素绑定到要更改的图像。如果它在您要更改的颜色的小公差范围内,请将 gl_FragColor 设置为新颜色,否则只需将 gl_FragColor 设置为您从采样器中检索到的颜色。您需要将所需颜色和新颜色作为 vec4s 和al_set_shader_float_vector. 最快的方法是保留 2 个位图并在它们之间交换作为您每次颜色变化时使用的“主要”位图。

如果不能使用着色器,则必须锁定位图并替换颜色。使用al_lock_bitmap锁定它,然后您可以使用al_get_pixelal_put_pixel更改颜色。然后al_unlock_bitmap当你完成。您还可以避免使用 al_get_pixel/al_put_pixel 并手动访问内存,这样会更快。如果您使用格式锁定位图,ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE则内存布局如下:

int w = al_get_bitmap_width(bitmap); int h = al_get_bitmap_height(bitmap); for (int y = 0; y < h; y++) { unsigned char *p = locked_region->data + locked_region->pitch * y; for (int x = 0; x < w; x++) { unsigned char r = p[0]; unsigned char g = p[1]; unsigned char b = p[2]; unsigned char a = p[3]; /* change r, g, b, a here if they match */ p[0] = r; p[1] = g; p[2] = b; p[3] = a; p += 4; } }

建议您以创建图像的格式锁定图像。这意味着选择一个像我提到的那样简单的图像,否则循环的内部会变得更加复杂。像素格式的 ABGR_8888 部分描述了数据的布局。ABGR 告诉组件的顺序。如果您要将像素读入单个存储单元(在这种情况下为 int,但与 short 相同),则位模式将为AAAAAAAABBBBBBBBGGGGGGGGRRRRRRRR. 但是,当您一次读取一个字节时,大多数机器都是小端的,这意味着小端首先出现。这就是为什么在我的示例代码中 p[0] 是红色的。8888 部分说明每个组件有多少位。

于 2016-06-18T07:15:59.737 回答