Skip to content

Opening An Image

Brett Anthony edited this page Jul 6, 2019 · 2 revisions

This guide will assume that you've already linked the library and will only cover the code needed to perform these operations.

Table Of Contents

Opening An Image With C++

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 filepath MyImage.tga. It also takes in our ERRORCODE argument err, the value of err 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 a ManagedArray of RGBA8888 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 holder err again to check for errors, we're also passing through the variable AlphaType 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 type uint16, 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 either uint32 or uint64 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 struct xtga::pixelformats::RGBA8888. We can also pass an ERRORCODE 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 our GetImage() 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 the GetImage() 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).

Opening An Image With C

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.

Clone this wiki locally