Targa Image
Como será necessário para o desenvolvimento do nosso SPRITE concreto – feito com opengl, derivado de um sprite abstrato. (ambos serão apresentados aqui no blog num post posterior) – vamos aprender um pouco, pelo menos o suficiente para extrair os dados mais interessantes, sobre um formato de imagem fácil de trabalhar e apresentado na maioria dos livros que abordam opengl – Targa (*.tga).
As informações foram obtidas pelos livros sobre OpenGL:
- Beginning OpenGL Game Programming – Dave Astle, Kevin Hawkin.
- OpenGL super bible – Comprehensive Tutorial and Reference -Richard S. Wright, Jr, Benjamin Lipchak, Nicholas Haemel – 4th edition
e do site sobre formatos:
As informações que repassarei à vós será bastante pontual, abordando apenas alguns pontos do TGA. Não nos apronfudaremos em erros, compressão ou tópicos mais avançados. Inclusive, para facilitar, iremos trabalhar apenas com o “Image type code” número 2 – pode-se facilmente modificar para aceitar todos os tipos de imagem targa, mas não será o nosso objetivo aqui.
Aqui tem um código que trata alguns erros, é voltado para OpenGL, mas está incompleto. E aqui tem o código teste estruturado.
Para começar, teremos um cabeçá-lho da imagem targa, que pode será um conjunto de variáveis. Aqui representaremos por uma struct – por ser mais fácil para carregar.
struct TargaHeader
{
unsigned char idLength;
unsigned char colorMapType;
unsigned char imageTypeCode;
unsigned char colorMapSpecification[5];
unsigned short xOrigin;
unsigned short yOrigin;
unsigned short width;
unsigned short height;
unsigned char bpp;
unsigned char imageDesc;
};
Vamos às explicações.
Obviamente cada char da estrutura tem um byte, e cada short tem 2 bytes. Então o “image type code” (código de tipo da imagem) é o terceiro byte – sempre será, para toda imagem targa. No nosso caso esperamos que seja sempre 2.
O primeiro byte (idLenght) será o número de characteres do Identification Field (campo de identificação) – que começa no byte 18. Isso pode ser útil para caso quisermos pular esse campo (idField) posteriormente ou até mesmo lê-lo. É comum ser 0, que indica que não existe o IdField.
O segundo byte é o “Color Map Type“. Pode ser 0 ou 1. Zero significa que nenhum mapa de cor é incluido – o que é bastante comum.
Terceiro byte – Image Type Code = 2 – sempre para o formato de terga image que estamos discutindo agora
Quarto byte – É justamente a especificação do mapa de cor, portanto ignorado se o ColorMapType for 0. Caso contrário deve ser interpretado – olhe uma especificação do targa image para saber como.
Sétimo byte – pulamos os bytes do Color Map Specification. Do sétimo ao décimo sexto byte é a especificação da imagem. Então é reservado 2 bytes para alguns campos ficando separado assim:
7 – 8 = X origin of Image – Coordenada do canto inferior esquerdo da imagem.
9 – 10 = Y origin of Image – Coordenada do canto inferior esquerdo da imagem.
11 – 12 = Width – Largura da Image.
13 – 14 = Height – Altura da Image.
15 = Image Pixel Size – Número de bits em um pixel. Isto é, 16, 24, 32..
16 = Image Descriptor Byte.
Existe bits importantes no Image Descriptor Byte, que tem significados diferentes. Olhe a descrição do formato TGA. (Para abrir com opengl, é importante o bit 5. Se esse bit for 0 quer dizer que a orgem da tela é a partir do canto inferior esquerdo – assim como na openGL.)
Se o byte 1 (idLenght) e o byte 2 forem 0 então a partir daqui fica os dados da nossa imagem.
segue um código exemplo para abrir uma imagem TGA:
#ifndef _TESTE_TARGA_
#define _TESTE_TARGA_
#include <cstdio>
#include <iostream>
struct TargaHeader
{
unsigned char idLength;
unsigned char colorMapType;
unsigned char imageTypeCode;
unsigned char colorMapSpec[5];
unsigned short xOrigin;
unsigned short yOrigin;
unsigned short width;
unsigned short height;
unsigned char bpp;//Image Pixel Size
unsigned char imageDesc;//Image Descriptor Byte
};
int main (int argc, char const* argv[])
{
TargaHeader header;
std::cout << "Iniciando testes com Targa Image" << std::endl;
FILE* targaFile = NULL;
targaFile = fopen("/home/zeroth/GameDev/Developing/Breakout Project/imagens/teste/teste.tga","rb");
if(targaFile==NULL) std::cout << "ERRO" << std::endl;
else std::cout << "Carregado com sucesso." << std::endl;
std::cout << "Tamanho do Targa Header = " << sizeof(header) << std::endl;//espera-se 18 bytes.
fread(&header,sizeof(header),1,targaFile);//carrega o targa file.
std::cout << "Especificacoes do Header:" << std::endl;
std::cout << "Id Lenght = " << (int)(header.idLength) <<std::endl;
std::cout << "Color Map Type = " << (int)(header.colorMapType) <<std::endl;
std::cout << "Image Type Code = " << (int)(header.imageTypeCode) <<std::endl;
std::cout << "Color Map Spec 3+1 = " << (int)(header.colorMapSpec[3]) <<std::endl;
std::cout << "Color Map Spec 4+1= " << (int)(header.colorMapSpec[4]) <<std::endl;
std::cout << "X Origin = " << (int)(header.xOrigin) <<std::endl;
std::cout << "Y Origin = " << (int)(header.yOrigin) <<std::endl;
std::cout << "width = " << (int)(header.width) <<std::endl;
std::cout << "height = " << (int)(header.height) <<std::endl;
std::cout << "bpp = " << (int)(header.bpp) <<std::endl;
std::cout << "imageDesc = " << (int)(header.imageDesc) <<std::endl;
long int imageSize = header.width * header.height * header.bpp/8;
unsigned char* image = new unsigned char[imageSize];
std::cout << "Image Size = " << (imageSize) <<std::endl;
fread(image, imageSize, 1, targaFile);//carrega a imagem MESMO
std::cout << "Image Fragment = " << (image[50]) <<std::endl;//um pedaço de uma cor que compõe um pixel da imagem
delete targaFile;
return 0;
}
#endif
Aqui tem uma especificação mais tetalhada e em ingles do formato Targa – foi retirado do site wosit.org
e a seguir uma versão orientada a objetos: