android的rgb转bitmap,Android: 格式为RGB_565的bitmap问题

一般我们写代码的时候,创建的bitmap格式都为ARGB_8888, 包含alpha通道,并且可以获得最好的图片质量。但是有些时候,我们还是会需要使用到格式为RGB_565的bitmap, 以减少需要处理的数据量。

那么创建格式为RGB_565的bitmap有什么问题呢,先看下面一段代码:

#include

#include

#include

#include

struct BitmapFileHeader {

uint16_t bfType;

uint32_t bfSize;

uint16_t bfReserved1;

uint16_t bfReserved2;

uint32_t bfOffBits;

}__attribute__((__packed__));

struct BitmapInfoHeader {

uint32_t biSize;

uint32_t biWidth;

uint32_t biHeight;

uint16_t biPlanes;

uint16_t biBitCount;

uint32_t biCompression;

uint32_t biSizeImage;

uint32_t biXPelsPerMeter;

uint32_t biYPelsPerMeter;

uint32_t biClrUsed;

uint32_t biClrImportant;

};

void saveBitmap(const char *name, int width, int height, int bitCount, const unsigned char *pixels)

{

struct BitmapFileHeader bfh;

struct BitmapInfoHeader bih;

FILE *fp;

char buf[256];

memset(&bfh, 0x00, sizeof(struct BitmapFileHeader));

memset(&bih, 0x00, sizeof(struct BitmapInfoHeader));

bfh.bfType = 0x4d42;

bfh.bfSize = sizeof(bfh) + sizeof(bih) + ((width + 3) & ~3) * height * bitCount / 8;

bfh.bfOffBits = sizeof(bfh) + sizeof(bih);

bih.biSize = sizeof(bih);

bih.biWidth = width;

bih.biHeight = -height; // top-down image

bih.biPlanes = 1;

bih.biBitCount = 16;

bih.biCompression = 0; //BI_RGB;

fp = fopen(name, "w+");

fwrite(&bfh, sizeof(bfh), 1, fp);

fwrite(&bih, sizeof(bih), 1, fp);

fwrite(pixels, ((width + 3) & ~3) * height * bitCount / 8, 1, fp);

fclose(fp);

}

int main(int argc, const char *argv[])

{

unsigned short color_table[] = {

0x0000, 0x0020, 0x0041, 0x0441, 0x0462, 0x0482, 0x04a2, 0x08a3,

0x08c3, 0x08e3, 0x0904, 0x0924, 0x0d25, 0x0d45, 0x0d65, 0x0d86,

0x11a6, 0x11a6, 0x11c7, 0x11e7, 0x1208, 0x1608, 0x1628, 0x1649,

0x1669, 0x1689, 0x1a8a, 0x1aaa, 0x1acb, 0x1aeb, 0x1eeb, 0x1f0c,

0x1f2c, 0x1f4c, 0x1f6d, 0x236d, 0x238e, 0x23ae, 0x23ce, 0x27cf,

0x27ef, 0x240f, 0x2430, 0x2450, 0x2851, 0x2871, 0x2891, 0x28b2,

0x2cd2, 0x2cd2, 0x2cf3, 0x2d13, 0x2d34, 0x3134, 0x3154, 0x3175,

0x3195, 0x31b5, 0x35b6, 0x35d6, 0x35f7, 0x3617, 0x3a17, 0x3a38,

0x3a58, 0x3a78, 0x3a99, 0x3e99, 0x3eba, 0x3eda, 0x3efa, 0x42fb,

0x431b, 0x433b, 0x435c, 0x437c, 0x477d, 0x479d, 0x47bd, 0x47de,

0x4bfe, 0x4bfe, 0x481f, 0x483f, 0x4840, 0x4c40, 0x4c60, 0x4c81,

0x4ca1, 0x50c1, 0x50c2, 0x50e2, 0x5103, 0x5123, 0x5523, 0x5544,

0x5564, 0x5584, 0x55a5, 0x59a5, 0x59c6, 0x59e6, 0x5a06, 0x5e07,

0x5e27, 0x5e47, 0x5e68, 0x5e88, 0x6289, 0x62a9, 0x62c9, 0x62ea,

0x670a, 0x670a, 0x672b, 0x674b, 0x676c, 0x6b6c, 0x6b8c, 0x6bad,

0x6bcd, 0x6fed, 0x6fee, 0x6c0e, 0x6c2f, 0x6c4f, 0x704f, 0x7070,

0x7090, 0x70b0, 0x70d1, 0x74d1, 0x74f2, 0x7512, 0x7532, 0x7933,

0x7953, 0x7973, 0x7994, 0x79b4, 0x7db5, 0x7dd5, 0x7df5, 0x7e16,

0x0236, 0x0236, 0x0257, 0x0277, 0x0298, 0x0698, 0x06b8, 0x06d9,

0x06f9, 0x0b19, 0x0b1a, 0x0b3a, 0x0b5b, 0x0b7b, 0x0f7b, 0x0f9c,

0x0fbc, 0x0fdc, 0x0ffd, 0x13fd, 0x101e, 0x103e, 0x105e, 0x145f,

0x147f, 0x149f, 0x14a0, 0x14c0, 0x18c1, 0x18e1, 0x1901, 0x1922,

0x1d42, 0x1d42, 0x1d63, 0x1d83, 0x1da4, 0x21a4, 0x21c4, 0x21e5,

0x2205, 0x2625, 0x2626, 0x2646, 0x2667, 0x2687, 0x2a87, 0x2aa8,

0x2ac8, 0x2ae8, 0x2f09, 0x2f09, 0x2f2a, 0x2f4a, 0x2f6a, 0x336b,

0x338b, 0x33ab, 0x33cc, 0x33ec, 0x37ed, 0x340d, 0x342d, 0x344e,

0x386e, 0x386e, 0x388f, 0x38af, 0x38d0, 0x3cd0, 0x3cf0, 0x3d11,

0x3d31, 0x4151, 0x4152, 0x4172, 0x4193, 0x41b3, 0x45b3, 0x45d4,

0x45f4, 0x4614, 0x4a35, 0x4a35, 0x4a56, 0x4a76, 0x4a96, 0x4e97,

0x4eb7, 0x4ed7, 0x4ef8, 0x4f18, 0x5319, 0x5339, 0x5359, 0x537a,

0x579a, 0x579a, 0x57bb, 0x57db, 0x57fc, 0x5bfc, 0x581c, 0x583d,

0x585d, 0x5c7d, 0x5c7e, 0x5c9e, 0x5cbf, 0x5cdf, 0x60df, 0x60e0,

};

unsigned short *pixels;

int i, j;

int W = 256*3, H = 256*2;

// create a (256*3)x(256*2)x2 bitmap

pixels = (unsigned short *)malloc(W * H * 2);

for (i = 0; i < H; i++) {

for (j = 0; j < 256; j++) {

*(pixels + W * (H - 1 - i) + j * 3 + 0) = color_table[j];

*(pixels + W * (H - 1 - i) + j * 3 + 1) = color_table[j];

*(pixels + W * (H - 1 - i) + j * 3 + 2) = color_table[j];

}

}

saveBitmap("bitmap_rgb565.bmp", W, H, 16, (unsigned char *)pixels);

free(pixels);

return 0;

}

这段代码是用来创建一个名为bitmap_rgb565.bmp的图片,图片的宽度为256*3个pixel,高度为256*2个pixel。编译、运行上面的代码可以得到如下图片:

$ gcc -o bitmap_rgb565 bitmap_rgb565.c

$ ./bitmap_rgb565

37a99645cf387782a9186be628e2b412.png

图片本身没什么特别。

由于有了libgraphics这个库,我们可以很方便地在native代码(JNI)中得到bitmap pixel所对应的内存地址。我们可以接对bitmap中的pixel进行修改。这在java代码中基本上不太可能,虽然Bitmap也提供了如copyPixelsFromBuffer()、copyPixelsToBuffer()、getPixel()、setPixel()等这些方法,但是性能跟不上。下面,我们看一下如何在native层对bitmap的像素点进行操作:

首先在java代码中创建一个格式为RGB_565的Bitmap对象, 再将这个对象通过JNI接口(update())传递给native层:

public class CubicActivity extends Activity {

private static final String TAG = "Cubic";

private static class CubicView extends View {

private Bitmap mBitmap;

private int W = 256 * 3;

private int H = 256 * 2;

public CubicView(Context context) {

super(context);

mBitmap = Bitmap.createBitmap(W, H, Bitmap.Config.RGB_565);

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

post(new Runnable() {

@Override

public void run() {

update(mBitmap);

invalidate();

}

});

}

@Override

public void onDraw(Canvas canvas) {

super.onDraw(canvas);

canvas.drawBitmap(mBitmap, 0, 0, null);

}

}

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(new CubicView(this));

}

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

static {

System.loadLibrary("cubic-jni");

}

private static native void update(Bitmap bitmap);

在native层,我们可以通过AndroidBitmap_getInfo()得到bitmap的相关信息,如宽度,高度等。再调用AndroidBitmap_lockPixels()得到bitmap像素点所在的内存地址,操用完成之后再调用AndroidBitmap_unlockPixels()进行提交:

extern "C" void Java_com_brobwind_cubic_CubicActivity_update(JNIEnv *env, jobject, jobject jbitmap)

{

// Get the info.

AndroidBitmapInfo info;

int result = AndroidBitmap_getInfo(env, jbitmap, &info);

if (result < 0) {

throwIllegalStateException(env, (char*)"Cannot get bitmap info");

return;

}

// Lock the pixels.

void* ptr;

result = AndroidBitmap_lockPixels(env, jbitmap, &ptr);

if (result < 0) {

throwIllegalStateException(env, (char*)"Cannot lock bitmap pixels");

return;

}

unsigned short *pixels = (unsigned short *)ptr;

unsigned short color_table[] = {

0x0000, 0x0020, 0x0041, 0x0441, 0x0462, 0x0482, 0x04a2, 0x08a3,

...

};

for (int i = 0; i < (int)info.height; i++) {

for (int j = 0; j < (int)info.width / 3; j++) {

*(pixels + info.width * (info.height - 1 - i) + j * 3 + 0) = color_table[j];

*(pixels + info.width * (info.height - 1 - i) + j * 3 + 1) = color_table[j];

*(pixels + info.width * (info.height - 1 - i) + j * 3 + 2) = color_table[j];

}

}

// Unlock the pixels.

result = AndroidBitmap_unlockPixels(env, jbitmap);

if (result < 0) {

throwIllegalStateException(env, (char*)"Cannot unlock bitmap pixels");

}

}

仔细查看的话,可以发现这些代码实际上是要在应用程序的窗口中直接绘制之前的那张位图。实际的显示效果又是怎么样呢:

535f5488d6860b9483dc57b1f8d1f19a.png

为什么会这样呢?

在bitmap文件或者是windows中的CreateDIBSection(BI_RGB, 16)创建的位图,pixel中r, g, b排列为:

f e d c b a 9 8 7 6 5 4 3 2 1 0

--------- --------- ---------

r g b

而Android中的RGB_565, pixel中的r, g, b排列为:

f e d c b a 9 8 7 6 5 4 3 2 1 0

--------- ----------- ---------

r g b

都是16位色,但是不能直接copy。如果想直接保存这个位图,可以指定compression为BI_BITFIELDS,指明alpha, red, green, blue的mask。

unsigned short B = color_table[j];

unsigned short B_r = (B >> 10) & 0x1f;

unsigned short B_g = (B >> 5) & 0x1f;

unsigned short B_b = (B >> 0) & 0x1f;

B = B_r << 11 | B_g << 6 | B_b;

*(pixels + info.width * (info.height - 1 - i) + j * 3 + 0) = B;

*(pixels + info.width * (info.height - 1 - i) + j * 3 + 1) = B;

*(pixels + info.width * (info.height - 1 - i) + j * 3 + 2) = B;

相关文档:

https://en.wikipedia.org/wiki/BMP_file_format

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值