-
Notifications
You must be signed in to change notification settings - Fork 5
Opening An Image
This guide will assume that you've already linked the library and will only cover the code needed to perform these operations.
Let's just drop the code here, then we'll break down the code and what it does.
#include <iostream>
#include "xTGA/xTGA.h"
int main()
{
xtga::ERRORCODE err;
xtga::TGAFile* MyFile = xtga::TGAFile::Alloc("MyImage.tga", &err);
if (err != xtga::ERRORCODE::NONE)
{
std::cout << "Error Occured: " << (uint32)err << std::endl;
return -1;
}
xtga::flags::ALPHATYPE AlphaType;
xtga::ManagedArray<xtga::pixelformats::RGBA8888>* Image = MyFile->GetImageRGBA(&AlphaType, &err);
if (err != xtga::ERRORCODE::NONE)
{
std::cout << "Error Occured: " << (uint32)err << std::endl;
return -1;
}
uint16 width = MyFile->GetWidth();
xtga::TGAFile::Free(MyFile);
for (addressable i = 0; i < Image->size(); ++i)
{
xtga::pixelformats::RGBA8888 pix = Image->at(i);
std::cout << '[' << i % width << ", " << i / width << "] RGBA: " << (uint16)pix.R << ' ' << (uint16)pix.G << ' ' << (uint16)pix.B << ' ' << (uint16)pix.A << '\n';
}
xtga::ManagedArray<xtga::pixelformats::RGBA8888>::Free(Image);
return 0;
}
-
#include "xTGA/xTGA.h"
-- This simply includes the main header for the library, it is also possible to include only some of the headers to save on compilation time if desired. -
xtga::TGAFile* MyFile = xtga::TGAFile::Alloc("MyImage.tga", &err);
-- This creates a new TGAFile object that loads an image at the relative filepathMyImage.tga
. It also takes in ourERRORCODE
argumenterr
, the value oferr
will be changed depending on the result of the loading operation, this pattern is found throughout the library and is a good way to determine what exactly caused an operation to fail. -
if (err != xtga::ERORCODE::NONE)
-- This simply checks that our operation didn't signal an error, if it does it prints out the error code and returns -1. -
xtga::ManagedArray<xtga::pixelformats::RGBA8888>* Image = MyFile->GetImageRGBA(&AlphaType, &err);
-- This returns aManagedArray
ofRGBA8888
values that we can use to view pixel values. The returned array will place the first pixel in the top left position. We are passing through our error/status code holdererr
again to check for errors, we're also passing through the variableAlphaType
which will be modified to indicate the type of alpha the image contains. -
uint16 width = MyFile->GetWidth();
-- Simply returns the width of the image in pixels as the library typeuint16
, an unsigned 16-bit integer. -
xtga::TGAFile::Free(MyFile);
-- We don't need the TGAFile object anymore so we can free it from memory with this call. -
for (addressable i = 0; i < Image->size(); ++i)
-- iterates through each pixel of the image buffer,addressable
is eitheruint32
oruint64
depending on the architecture used. -
xtga::pixelformats::RGBA8888 pix = Image->at(i);
-- returns the pixel at the given index and places it into the library structxtga::pixelformats::RGBA8888
. We can also pass anERRORCODE
object here to check for errors, but it has been omitted here. -
xtga::ManagedArray<xtga::pixelformats::RGBA8888>::Free(Image);
-- frees the ManagedArray from memory as it's no longer needed.
It may also be desirable to return a ManagedArray
of pixels in the format that the TGA file actually holds them. This can be great for memory since a TGA file that contains only one channel -- I8
format -- being converted to RGBA8888
format will end up using 4x the memory! To instead get just the I8
array we can use the GetImage()
function which will return ManagedArray<IPixel>*
. IPixel
is a generic type that all the pixel formats inherit from, meaning it can simply and easily be cast into the appropriate format. The code for this is a little more verbose but still pretty simple to follow:
#include <iostream>
#include "xTGA/xTGA.h"
int main()
{
xtga::ERRORCODE err;
xtga::TGAFile* MyFile = xtga::TGAFile::Alloc("MyImage.tga", &err);
if (err != xtga::ERRORCODE::NONE)
{
std::cout << "Error Occured: " << (uint32)err << std::endl;
return -1;
}
xtga::flags::ALPHATYPE AlphaType;
xtga::pixelformats::PIXELFORMATS PixelType;
xtga::ManagedArray<xtga::pixelformats::IPixel>* Image = MyFile->GetImage(&PixelType, &AlphaType, &err);
if (err != xtga::ERRORCODE::NONE)
{
std::cout << "Error Occured: " << (uint32)err << std::endl;
return -1;
}
uint16 width = MyFile->GetWidth();
xtga::TGAFile::Free(MyFile);
if (PixelType == xtga::pixelformats::PIXELFORMATS::BGRA5551)
{
// do stuff
}
else if (PixelType == xtga::pixelformats::PIXELFORMATS::BGR888)
{
// do stuff
}
else if (PixelType == xtga::pixelformats::PIXELFORMATS::BGRA8888)
{
// do stuff
}
else if (PixelType == xtga::pixelformats::PIXELFORMATS::I8)
{
// do stuff
}
else if (PixelType == xtga::pixelformats::PIXELFORMATS::IA88)
{
// do stuff
}
else
{
std::cout << "Non Standard Pixel Type: " << (uint16)PixelType << '\n';
xtga::ManagedArray<xtga::pixelformats::IPixel>::Free(Image);
return -1;
}
xtga::ManagedArray<xtga::pixelformats::IPixel>::Free(Image);
return 0;
}
-
xtga::pixelformats:PIXELFORMATS PixelType;
-- this will hold the type of pixel the image contains after being passed to ourGetImage()
function. -
xtga::ManagedArray<xtga::pixelformats::IPixel>* Image = MyFile->GetImage(&PixelType, &AlphaType, &err);
-- this is identical to our previous example, however instead we'll be using theGetImage()
function to return the image in the format that the file holds it in (color maps / run-length encoding is first decoded and the buffer is rearranged such that the first pixel is the top left pixel). -
if (PixelType == xtga::pixelformats::PIXELFORMATS::BGRA5551)
-- here we do a simple test to see what type of pixel data is actually contained in the buffer. The listed formats in this code are the only standard pixel formats for the TGA specification:- BGRA5551
- BGR888
- BGRA8888
- I8
- IA88 (could be AI88 in some software, photoshop doesn't support these at all, gimp uses IA88).
Let's just jump right into some code:
#include <stdio.h>
#include "xTGA/xTGA_C.h"
typedef struct
{
uchar R;
uchar G;
uchar B;
uchar A;
} RGBA8888_t;
int main()
{
xtga_ERRORCODE_e err;
xtga_TGAFile* MyFile = xtga_TGAFile_Alloc_FromFile("MyImage.tga", &err);
if (err != xtga_ERRORCODE_NONE)
{
printf("Error Occured: %u\n", (uint32)err);
return -1;
}
xtga_ALPHATYPE_e AlphaType;
xtga_ManagedArray* Image = xtga_TGAFile_GetImageRGBA(MyFile, &AlphaType, &err);
if (err != xtga_ERRORCODE_NONE)
{
printf("Error Occured: %u\n", (uint32)err);
return -1;
}
uint16 width = xtga_TGAFile_GetWidth(MyFile);
xtga_TGAFile_Free(&MyFile);
for (addressable i = 0; i < xtga_ManagedArray_size(Image); ++i)
{
RGBA8888_t pix = *(RGBA8888_t*)xtga_ManagedArray_at(Image, i, NULL);
printf("[%u, %u] RGBA: %u %u %u %u\n", (uint32)i % width, (uint32)i / width, (uint32)pix.R, (uint32)pix.G, (uint32)pix.B, (uint32)pix.A);
}
xtga_ManagedArray_Free(&Image);
return 0;
}
The first thing to notice is that we're including xTGA_C.h
instead of xTGA.h
, the former is the C-interface header and should be the only header included from the library when writing C code.
Another thing to notice is that we've had to define our own RGBA8888_t
struct, the xTGA library doesn't define any pixel structs for the C-interface, you'll need to define those yourself as you need them.
Otherwise the code is pretty similar, you'll notice that our calling convention is essentially the same throughout, we just replace the scope operator ::
with underscores throughout. Another thing is any functions that pass by reference in C++ (i.e. the Free()
functions) now require an address operator to work properly. Forgetting this isn't the end of the world, but your passed pointers will not have their value set to nullptr
as expected without it.