『Targa』是常用於3D紋理的『.tga』圖檔,它與『Bitmap』最大的分別是索引、RGB、灰度均支持RLE編碼,當色彩較單調時壓縮效果明顯. 渲染演示程式下載:
它的文檔結構主要由三部份組成:
Targa圖檔結構 | 簡介 |
HEADER header; | 頭部 |
PALETTEENTRY palette[256]; | 調色板常用於256色模式,灰度模式和RGB模式均無調色板 |
PBYTE buffer; | 位圖數據 |
頭部結構 | 簡介 |
BYTE imageIDLength; | 圖像頭部的長度 |
BYTE colorMayType | 調色板類型
0=無 1=使用調色盤 |
BYTE imageTypeCode | 圖像類型
0=無圖像數據 1=索引模式 2= RGB模式 3=灰度模式 9=RLE壓縮索引模式 10=RLE壓縮RGB模式 11=RLE壓縮灰度模式 |
WORD colorMapOrigin | 調色板偏移量 |
WORD colorMapLength | 調色板的長度8bit圖檔這個值為256 |
BYTE colorMapEntrySize | 調色板單個條目的大細
有本書居然寫錯左所占空間大細暈 |
WORD imageXOrigin | 圖像左下角的X軸座標總為0 |
WORD imageYOrigin | 圖像左下角的Y軸座標總為0 |
WORD imageWidth | 圖寬 |
WORD imageHeight | 圖高 |
BYTE bitCount | 像素8BIT,16BIT,24BIT,32BIT |
BYTE imageDescriptor | 圖像原點的位置 |
調色板結構 | 簡介 |
BYTE red; | 紅色 |
BYTE green; | 綠色 |
BYTE blue; | 藍色 |
載入並分釋TARGA圖檔
bool Load_Targa(TARGA_FILE_PTR targa, PBYTE data,int size)
{
int index;
PBYTE image;
int image_size;// 圖像字節的長度
int pixel_size;// 像素大小
int pixel_count;// 像素個數(寬*高)
memcpy(&targa->header, data, sizeof(TARGA_HEADER));// 讀取頭部數據
image_size = targa->header.imageWidth * targa->header.imageHeight * targa->header.bitCount / 8;
pixel_size = targa->header.bitCount / 8;
pixel_count = targa->header.imageWidth * targa->header.imageHeight;
targa->buffer = (PBYTE)malloc(image_size);// 根據位圖影像的大小申請空間
if (targa->buffer == NULL)
return false;//出錯返回
if (targa->header.imageTypeCode == TARGA_TYPE_INDEXED ||
targa->header.imageTypeCode == TARGA_TYPE_INDEXED_RLE )// 壓縮索引
image = data + sizeof(TARGA_HEADER) + targa->header.imageIDLength + targa->header.colorMapOrigin + (targa->header.colorMapEntrySize / 8) * targa->header.colorMapLength;
else
image = data + sizeof(TARGA_HEADER) + targa->header.imageIDLength ;
if( targa->header.imageTypeCode == TARGA_TYPE_INDEXED ||// 索引
targa->header.imageTypeCode == TARGA_TYPE_RGB ||// RGB
targa->header.imageTypeCode == TARGA_TYPE_GRAYSCALE)// 灰度
{ // 讀取位圖的圖像
memcpy(targa->buffer, image, image_size);
}
else
if (targa->header.imageTypeCode == TARGA_TYPE_INDEXED_RLE ||// 壓縮索引
targa->header.imageTypeCode == TARGA_TYPE_RGB_RLE ||// 壓縮RGB
targa->header.imageTypeCode == TARGA_TYPE_GRAYSCALE_RLE )// 壓縮灰度
{ // RLE解碼
Load_RLE_Targa(targa->buffer, image, image_size, pixel_size);
}
if (targa->header.bitCount == 8)
{ // 計算調色板的入口地址
PBYTE palette = data + sizeof(TARGA_HEADER) + targa->header.imageIDLength + targa->header.colorMapOrigin;
// RGBQUAD結構與PALETTEENTRY結構的順序調轉了
for (index = 0; index < targa->header.colorMapLength; index++)
{//掉轉調色板的紅色和綠色
targa->palette[index].red = palette[index *targa->header.colorMapEntrySize/8 + 2];
targa->palette[index].green = palette[index *targa->header.colorMapEntrySize/8 + 1];
targa->palette[index].blue = palette[index *targa->header.colorMapEntrySize/8 + 0];
targa->palette[index].flags = PC_NOCOLLAPSE;
}
PBYTE temp_buffer = targa->buffer;
//根據圖像的寬高計算記憶體空間(24BIT)
targa->buffer = (UCHAR *)malloc(targa->header.imageWidth * targa->header.imageHeight * 3);
if (targa->buffer == NULL)
return false;//出錯返回
for (index = 0; index < image_size; index++)
{ // 現在將索引值轉為24位值
int color = temp_buffer[index];
if (targa->header.imageTypeCode == TARGA_TYPE_GRAYSCALE ||
targa->header.imageTypeCode == TARGA_TYPE_GRAYSCALE_RLE)
{// 處理灰度圖像
targa->buffer[index * 3 + 0] = color;
targa->buffer[index * 3 + 1] = color;
targa->buffer[index * 3 + 2] = color;
}
else
{
targa->buffer[index * 3 + 0] = targa->palette[color].red;
targa->buffer[index * 3 + 1] = targa->palette[color].green;
targa->buffer[index * 3 + 2] = targa->palette[color].blue;
}
}
targa->header.bitCount = 24;//最後將位圖位數變為24位
}
else
if (targa->header.bitCount == 16)//RGB555
{ // 根據位圖影像的大小申請空間
PBYTE temp_buffer = targa->buffer;
// 根據位圖影像的大小生請空間(位圖為16位但要生成24位空間來保存)
targa->buffer = (UCHAR *)malloc(targa->header.imageWidth * targa->header.imageHeight * 3);
if (targa->buffer == NULL)
{//分配內存空間失敗
free(temp_buffer); // 釋放資源
return false;//出錯返回
}
for (index = 0; index < pixel_count; ++index)
{
WORD color = (temp_buffer[index2 + 1] << 8) | temp_buffer[index2 + 0];
UCHAR red = (((color) >> 10) & 0x1f);
UCHAR green = (((color) >> 5) & 0x1f);
UCHAR blue = ((color) & 0x1f);
targa->buffer[index * 3 + 0] = (red << 3);
targa->buffer[index * 3 + 1] = (green << 3);
targa->buffer[index * 3 + 2] = (blue << 3);
}
targa->header.bitCount = 24;//最後將位圖位數變為24位
free(temp_buffer); // 釋放資源
}
else
if (targa->header.bitCount == 24)
{
for (index = 0; index < image_size; index = index + 3)
{
UCHAR blue = targa->buffer[index + 0];
UCHAR green = targa->buffer[index + 1];
UCHAR red = targa->buffer[index + 2];
targa->buffer[index + 0] = red ;
targa->buffer[index + 2] = blue;
}
}
else
if (targa->header.bitCount == 32)
{
for (index = 0; index < image_size; index = index + 4)
{
//DWORD color;//32的顏色
UCHAR blue = targa->buffer[index + 0];
UCHAR green = targa->buffer[index + 1];
UCHAR red = targa->buffer[index + 2];
targa->buffer[index + 0] = red;
targa->buffer[index + 2] = blue;
}
}
// 判斷圖像原點是否左下角,否則翻轉圖像
if ((targa->header.imageDescriptor & TARGA_ORIGIN_TOP_LEFT) == TARGA_ORIGIN_TOP_LEFT)
Flip_Targa(targa->buffer, targa->header.imageWidth * pixel_size, targa->header.imageHeight);
return true;//
}
將顛倒的圖像翻轉過來
image:指向位圖數據
bytes_per_line:圖像每行所占的字節數
height:圖像的高度
bool Flip_Targa(UCHAR *image, int bytes_per_line, int height)
{
UCHAR *buffer; //用於臨時保存位圖數據.
int index; //循環計數
//根據位圖影像的大小生請空間
buffer = (UCHAR )malloc(bytes_per_lineheight);
if (buffer == NULL)
return false;
// 位圖拷貝
memcpy(buffer, image, bytes_per_line*height);
// 垂直顛倒圖片
for (index = 0; index < height; index++)
memcpy(&image[((height – 1) – index)bytes_per_line], &buffer[indexbytes_per_line], bytes_per_line);
//釋放臨時空間
free(buffer);
return true;//返回
}