常見顔色深度的 bitmap 之間的互相轉換 作者: 劉鵬 日期: 2009-08-14 本文介紹了常見色深的格式轉換原理和算法。
簡介
在很多場合中會遇到不同顔色深度的 surface 之間的轉化問題,如筆者在開發 一個虛拟 framebuffer 時就需要将客戶 GUI 系統的顔色深度轉換成虛拟 framebuffer 給定的顔色深度,根據工作中的實際經驗,筆者總結了在幾對典型 的顔色深度之間進行轉換的思路和實作方法,讀者在此基礎可以舉一反三,處理 更多的轉換。
16 位色轉成 24 位色
16位色有兩種格式,一種是565, 另一種是555,本文以 565 格式為例。
對于 16 位色的 surface,一個像素由兩個位元組表示,其中 R 顔色分量占 5 位, G 顔色分量占6 位,B 顔色分量占 5 位。
24 位色的 surface,一個像素由三個位元組表示,R、G、B 分量各占 8 位。
要将 16 位色轉換成 24 位色,需要将565布局的 R、B、G 分量取出來,分别填 充到三個位元組中去,注意要填充時放在高位,末位補 0 ,否則誤差會放大,分 拆情況如下圖所示:
圖1 |
實作轉換的代碼如下所示:
for (row = 0;row < src_buffer_height; row++) {
sp = src_buf + src_buf_pitch * row;
dp = dst_buf + dst_buf_pitch * row;
for (col = 0; col < src_buffer_width; col++) {
word = *((Uint16*)sp);
sp+=2;
*dp++ = ((word & 0xF800) >> 11) << 3; /* red */
*dp++ = ((word & 0x07E0) >> 5) << 2; /* green */
*dp++ = (word & 0x001F) << 3; /* blue */
}
}
4 位色轉為 8 位色
對于 4 位色 surface,每個像素由 4 位表示,每個位元組可表示兩個像素;
對于 8 位色 surface,每個像素由 8 位表示,每個位元組表示一個像素;
要将 4 位色轉換成 8 位色,需要一個位元組的高 4 位和低 4 位分别轉成一個字 節,如下圖所示:
圖2 |
完成轉化的示例代碼如下所示:
for (row = 0;row < src_buffer_height; row++) {
sp = src_buf + src_buf_pitch * row;
dp = dst_buf + dst_buf_pitch * row;
for (col = 0; col < src_buffer_width; col++) {
bit = (col% 2) << 2;
if (bit == 0)
c = *sp++;
*dp++ = (c >> bit) & 0x0f;
}
}
2 位色轉為 8 位色
對于 2 位色 surface,每個像素由 2 位表示,每個位元組可表示四個像素;
對于 8 位色 surface,每個像素由 8 位表示,每個位元組表示一個像素;
要将 2 位色轉換成 8 位色,需要一個位元組按兩位為一個單元分拆,然後将每個 單元填充成一個位元組,如下圖所示:
圖3 |
轉換的實作代碼如下所示:
for (row = 0;row < src_buffer_height; row++) {
sp = src_buf + src_buf_pitch * row;
dp = dst_buf + dst_buf_pitch * row;
for (col = 0; col < src_buffer_width; col++) {
bit = (col% 4) << 1;
if (bit == 0)
c = *sp++;
*dp++ = (c >> bit) & 0x03;
}
}
1 位色轉為 8 位色
對于 1 位色 surface,每個像素由 1 位表示,每個位元組可表示八個像素;
對于 8 位色 surface,每個像素由 8 位表示,每個位元組表示一個像素;
要将 1 位色轉換成 8 位色,需要将一個位元組逐位分拆并将其填充成一個位元組,如下圖所示:
圖4 |
實作代碼如下所示:
for (row = 0;row < src_buffer_height; row++) {
sp = src_buf + src_buf_pitch * row;
dp = dst_buf + dst_buf_pitch * row;
for (col = 0; col < src_buffer_width; col++) {
bit = col %8;
if (bit == 0)
c = *sp++;
*dp++ = (c >> bit) & 0x01;
}
}