C++ OpenGL TGA Loading Failing - c++

I've been working through a basic OpenGl tutorial on loading a TGA file, to be used as a texture on a 3d object. I've been able to load data from the TGA header, but when I attempt to load the actual image data, it fails. I'm not sure where it is going wrong. Here is my texture loading class:
Header file:
struct TGA_Header
{
GLbyte ID_Length;
GLbyte ColorMapType;
GLbyte ImageType;
// Color map specifications
GLbyte firstEntryIndex[2];
GLbyte colorMapLength[2];
GLbyte colorMapEntrySize;
//image specification
GLshort xOrigin;
GLshort yOrigin;
GLshort ImageWidth;
GLshort ImageHeight;
GLbyte PixelDepth;
GLbyte ImageDescriptor;
};
class Texture
{
public:
Texture(string in_filename, string in_name = "");
~Texture();
public:
unsigned short width;
unsigned short height;
unsigned int length;
unsigned char type;
unsigned char *imageData;
unsigned int bpp;
unsigned int texID;
string name;
static vector<Texture *> textures;
private:
bool loadTGA(string filename);
bool createTexture(unsigned char *imageData, int width, int height, int type);
void swap(unsigned char * ori, unsigned char * dest, GLint size);
void flipImage(unsigned char * image, bool flipHorizontal, bool flipVertical, GLushort width, GLushort height, GLbyte bpp);
};
Here is the load TGA function in the cpp:
bool Texture::loadTGA(string filename)
{
TGA_Header TGAheader;
ifstream file( filename.data(), std::ios::in, std::ios::binary );
//make sure the file was opened properly
if (!file.is_open() )
return false;
if( !file.read( (char *)&TGAheader, sizeof(TGAheader) ) )
return false;
//make sure the image is of a type we can handle
if( TGAheader.ImageType != 2 )
return false;
width = TGAheader.ImageWidth;
height = TGAheader.ImageHeight;
bpp = TGAheader.PixelDepth;
if( width < 0 || // if the width or height is less than 0, than
height <= 0 || // the image is corrupt
(bpp != 24 && bpp != 32) ) // make sure we are of the correct bit depth
{
return false;
}
//check for an alpha channel
GLuint type = GL_RGBA;
if ( bpp == 24 )
type = GL_RGB;
GLuint bytesPerPixel = bpp / 8;
//allocate memory for the TGA so we can read it
GLuint imageSize = width * height * bytesPerPixel;
imageData = new GLubyte[imageSize];
if ( imageData == NULL )
return false;
//make sure we are in the correct position to load the image data
file.seekg(-imageSize, std::ios::end);
// if something when wrong, make sure we free up the memory
//NOTE: It never gets past this point. The conditional always fails.
if ( !file.read( (char *)imageData, imageSize ) )
{
delete imageData;
return false;
}
//more code is down here, but it doesnt matter because it does not pass the above function
}
It seems to load some data, but it keeps returning that it failed. Any help on why would be greatly appreciated. Appologies if it gets a bit wordy, but I'm not sure what is or is not significant.
UPDATE:
So, I just rewrote the function. The ifsteam I was using, seemed to be the cause of the problem. Specifically, it would try and load far more bytes of data than I had entered. I don't know the cause of the behavior, but I've listed my functioning code below. Thank you every one for your help.

The problem could be depending on the TGA algorithm which do not support compressed TGA.
Make sure you do not compress the TGA and that the TGA order (less important) is in a Bottom Left origin.
I usually work with GIMP and at the moment of the same, uncheck the RLE compression and put the Bottom Left alignment.

I'm not familiar with C++, sorry.
Are you sure this line file.seekg(-imageSize, std::ios::end); is not supposed to be file.seekg(headerSize, std::ios::start); ?
Makes more sense to seek from start than from end.
You should also check for ColorMapType != 0.
P.S. Here if( width < 0 || height <=0 width check should be <= as well.

So, I changed from using an ifstream to a FILE. The ifstream, was trying to load far more bytes than I had listed in the arguments. Here is the new code. (NOTE: It still needs optomized. I believe there are some unused variables floating around, but it works perfectly.). Thanks again everyone for your help.
The header file:
//struct to hold tga data
struct TGA_Header
{
GLbyte ID_Length;
GLbyte ColorMapType;
GLbyte ImageType;
// Color map specifications
GLbyte firstEntryIndex[2];
GLbyte colorMapLength[2];
GLbyte colorMapEntrySize;
//image specification
GLshort xOrigin;
GLshort yOrigin;
GLshort ImageWidth;
GLshort ImageHeight;
GLbyte PixelDepth;
GLbyte ImageDescriptor;
};
class Texture
{
public:
//functions
Texture(string in_filename, string in_name = "");
~Texture();
public:
//vars
unsigned char *imageData;
unsigned int texID;
string name;
//temp global access point for accessing all loaded textures
static vector<Texture *> textures;
private:
//can add additional load functions for other image types
bool loadTGA(string filename);
bool createTexture(unsigned char *imageData, int width, int height, int type);
void swap(unsigned char * ori, unsigned char * dest, GLint size);
void flipImage(unsigned char * image, bool flipHorizontal, bool flipVertical, GLushort width, GLushort height, GLbyte bpp);
};
#endif
Here is the load TGA function:
bool Texture::loadTGA(string filename)
{
//var for swapping colors
unsigned char colorSwap = 0;
GLuint type;
TGA_Header TGAheader;
FILE* file = fopen(filename.c_str(), "rb");
unsigned char Temp_TGAheader[18];
//check to make sure the file loaded
if( file == NULL )
return false;
fread(Temp_TGAheader, 1, sizeof(Temp_TGAheader), file);
//pull out the relavent data. 2 byte data (short) must be converted
TGAheader.ID_Length = Temp_TGAheader[0];
TGAheader.ImageType = Temp_TGAheader[2];
TGAheader.ImageWidth = *static_cast<unsigned short*>(static_cast<void*>(&Temp_TGAheader[12]));
TGAheader.ImageHeight = *static_cast<unsigned short*>(static_cast<void*>(&Temp_TGAheader[14]));
TGAheader.PixelDepth = Temp_TGAheader[16];
//make sure the image is of a type we can handle
if( TGAheader.ImageType != 2 || TGAheader.ImageWidth <= 0 || TGAheader.ImageHeight <= 0 )
{
fclose(file);
return false;
}
//set the type
if ( TGAheader.PixelDepth == 32 )
{
type = GL_RGBA;
}
else if ( TGAheader.PixelDepth == 24 )
{
type = GL_RGB;
}
else
{
//incompatable image type
return false;
}
//remember bits != bytes. To convert we need to divide by 8
GLuint bytesPerPixel = TGAheader.PixelDepth / 8;
//The Memory Required For The TGA Data
unsigned int imageSize = TGAheader.ImageWidth * TGAheader.ImageHeight * bytesPerPixel;// Calculate
//request the needed memory
imageData = new GLubyte[imageSize];
if ( imageData == NULL ) // just in case
return false;
if( fread(imageData, 1, imageSize, file) != imageSize )
{
//Kill it
delete [] imageData;
fclose(file);
return false;
}
fclose(file);
for (unsigned int x = 0; x < imageSize; x +=bytesPerPixel)
{
colorSwap = imageData[x];
imageData[x] = imageData[x + 2];
imageData[x + 2] = colorSwap;
}
createTexture( imageData, TGAheader.ImageWidth, TGAheader.ImageHeight, type );
return true;
}

Related

Not able to create multilayered tiff image using FreeImage

Been trying for 2 days now without any luck. My goal is to take 2 arrays of data that we normally create 2 exr files from, and create a multilayered/multipage TIFF file (FreeImage only support multipage for tif, gif and ico, and we need this to work well in python too).
static unsigned DLL_CALLCONV
myReadProc(void *buffer, unsigned size, unsigned count, freeimage::fi_handle handle) {
return (unsigned)fread(buffer, size, count, (FILE *)handle);
}
static unsigned DLL_CALLCONV
myWriteProc(void *buffer, unsigned size, unsigned count, freeimage::fi_handle handle) {
return (unsigned)fwrite(buffer, size, count, (FILE *)handle);
}
static int DLL_CALLCONV
mySeekProc(freeimage::fi_handle handle, long offset, int origin) {
return fseek((FILE *)handle, offset, origin);
}
static long DLL_CALLCONV
myTellProc(freeimage::fi_handle handle) {
return ftell((FILE *)handle);
}
void MyClass::TestMultilayeredFile(math::float4 *data1, math::float4 *data2, Hash128 &hash, const int width, const int height)
{
freeimage::FreeImageIO io;
io.read_proc = myReadProc;
io.write_proc = myWriteProc;
io.seek_proc = mySeekProc;
io.tell_proc = myTellProc;
core::string cachePathAsset = GetAbsoluteHashFilePath(GetRelativeHashFilePath(hash, "_combined.tiff"));
const int pixelCount = width * height;
enum Layers
{
kData1 = 0,
kData2 = 1,
kLayerCount = 2
};
FILE *file = fopen(cachePathAsset.c_str(), "w+b");
if (file != NULL) {
freeimage::FIMULTIBITMAP *out = freeimage::FreeImage_OpenMultiBitmapFromHandle(freeimage::FREE_IMAGE_FORMAT::FIF_TIFF, &io, (freeimage::fi_handle)file, 0x0800);
if (out)
{
const math::float4* kLayers[2] = { data1, data2 };
for (int layer = 0; layer < kLayerCount; ++layer)
{
freeimage::FIBITMAP* bitmap = freeimage::FreeImage_AllocateT(freeimage::FIT_RGBAF, width, height);
const int pitch = freeimage::FreeImage_GetPitch(bitmap);
void* bytes = (freeimage::BYTE*)freeimage::FreeImage_GetBits(bitmap);
const int bytesPerPixel = freeimage::FreeImage_GetBPP(bitmap) / 8;
DebugAssert(pitch == width * bytesPerPixel);
DebugAssert(bytes);
DebugAssert(bytesPerPixel == 16);
memcpy(bytes, kLayers[layer], pixelCount * bytesPerPixel);
freeimage::FreeImage_AppendPage(out, bitmap);
freeimage::FreeImage_Unload(bitmap);
}
// Save the multi-page file to the stream
BOOL bSuccess = freeimage::FreeImage_SaveMultiBitmapToHandle(freeimage::FREE_IMAGE_FORMAT::FIF_TIFF, out, &io, (freeimage::fi_handle)file, 0x0800);
freeimage::FreeImage_CloseMultiBitmap(out, 0);
}
}
}
The tiff file is created, but only contains 1kb. Also, bSuccess returns false. The code to generate the individual images have worked in the past, but haven't done mulipage before.

DDS texture transparency rendered black Opengl

I am currently trying to render textured objects in Opengl. Everything worked fine until I wanted to render a texture with transparency. Instead of showing the the object transparent it just rendered in total black.
The method fo loading the texture file is this:
// structures for reading and information variables
char magic[4];
unsigned char header[124];
unsigned int width, height, linearSize, mipMapCount, fourCC;
unsigned char* dataBuffer;
unsigned int bufferSize;
fstream file(path, ios::in|ios::binary);
// read magic and header
if (!file.read((char*)magic, sizeof(magic))){
cerr<< "File " << path << " not found!"<<endl;
return false;
}
if (magic[0]!='D' || magic[1]!='D' || magic[2]!='S' || magic[3]!=' '){
cerr<< "File does not comply with dds file format!"<<endl;
return false;
}
if (!file.read((char*)header, sizeof(header))){
cerr<< "Not able to read file information!"<<endl;
return false;
}
// derive information from header
height = *(int*)&(header[8]);
width = *(int*)&(header[12]);
linearSize = *(int*)&(header[16]);
mipMapCount = *(int*)&(header[24]);
fourCC = *(int*)&(header[80]);
// determine dataBuffer size
bufferSize = mipMapCount > 1 ? linearSize * 2 : linearSize;
dataBuffer = new unsigned char [bufferSize*2];
// read data and close file
if (file.read((char*)dataBuffer, bufferSize/1.5))
cout<<"Loading texture "<<path<<" successful"<<endl;
else{
cerr<<"Data of file "<<path<<" corrupted"<<endl;
return false;
}
file.close();
// check pixel format
unsigned int format;
switch(fourCC){
case FOURCC_DXT1:
format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
break;
case FOURCC_DXT3:
format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
break;
case FOURCC_DXT5:
format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
break;
default:
cerr << "Compression type not supported or corrupted!" << endl;
return false;
}
glGenTextures(1, &ID);
glBindTexture(GL_TEXTURE_2D, ID);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
unsigned int blockSize = (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16;
unsigned int offset = 0;
/* load the mipmaps */
for (unsigned int level = 0; level < mipMapCount && (width || height); ++level) {
unsigned int size = ((width+3)/4)*((height+3)/4)*blockSize;
glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height,
0, size, dataBuffer + offset);
offset += size;
width /= 2;
height /= 2;
}
textureType = DDS_TEXTURE;
return true;
In the fragment shader I just set the gl_FragColor = texture2D( myTextureSampler, UVcoords )
I hope that there is an easy explanation such as some code missing.
In the openGL initialization i glEnabled GL_Blend and set a blend function.
Does anyone have an idea of what I did wrong?
Make sure the blend function is the correct function for what you are trying to accomplish. For what you've described that should be glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
You probably shouldn't set the blend function in your openGL initialization function but should wrap it around your draw calls like:
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
//gl draw functions (glDrawArrays,glDrawElements,etc..)
glDisable(GL_BLEND)
Are you clearing the 2D texture binding before you swap buffers? i.e ...
glBindTexture(GL_TEXTURE_2D, 0);

reading TGA files in OpenGl to create a 3d ouse

I have a TGA file and a library that allready has everything that I need to read TGA and use them.
This class has a method called pixels(), that returns a pointer that is pointed to the memory area where pixel are stored as RGBRGBRGB...
My question is, how can I take the pixel value?
Cause if I make something like this:
img.load("foo.tga");
printf ("%i", img.pixels());
It gives back to me what is proprably the address.
I've found this code on this site:
struct Pixel2d
{
static const int SIZE = 50;
unsigned char& operator()( int nCol, int nRow, int RGB)
{
return pixels[ ( nCol* SIZE + nRow) * 3 + RGB];
}
unsigned char pixels[SIZE * SIZE * 3 ];
};
int main()
{
Pixel2d p2darray;
glReadPixels(50,50, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &p.pixels);
for( int i = 0; i < Pixel2d::SIZE ; ++i )
{
for( int j = 0; j < Pixel2d::SIZE ; ++j )
{
unsigned char rpixel = p2darray(i , j , 0);
unsigned char gpixel = p2darray(i , j , 1);
unsigned char bpixel = p2darray(i , j , 2);
}
}
}
I think that It can work great for me, but how can I tell the program to read from my img?
Tga supports different pixel depths. And we don't know what library you're using. But generally speaking pixels() should return a pointer to a buffer containing pixels. Say for sake of argument it unpacks the pixels into 8-bit per channel subpixels, then each pixel is represented by 3 bytes.
So to access a pixel at a given offset in the buffer:
const u8* pixelBuffer = img.pixels():
u8 red = pixelBuffer[(offset*3)+0];
u8 green = pixelBuffer[(offset*3)+1];
u8 blue = pixelBuffer[(offset*3)+2];
If you know the width of the image buffer then you can get a pixel by its x and y coordinates:
u8 red = pixelBuffer[((x+(y*width))*3)+0];

Getting incorrect width when decoding bitmap

I have an error with my source code which basically causes bitmap images to appear too wide. for example it will print the width and the height and the height is perfect (256) and the width should also be 256 but the programs says it is billions of pixels wide and it is different everytime. here is the source code.
#include "glob.h"
/* Image type - contains height, width, and data */
struct Image {
unsigned long sizeX;
unsigned long sizeY;
char *data;
};
typedef struct Image Image;
int ImageLoad(char *filename, Image *image) {
FILE *file;
unsigned long size; // size of the image in bytes.
unsigned long i; // standard counter.
unsigned short int planes; // number of planes in image (must be 1)
unsigned short int bpp; // number of bits per pixel (must be 24)
char temp; // temporary color storage for bgr-rgb conversion.
// make sure the file is there.
if ((file = fopen(filename, "rb"))==NULL){
printf("bitmap Not Found : %s\n",filename);
return 0;
}
// seek through the bmp header, up to the width/height:
fseek(file, 18, SEEK_CUR);
// read the width
if ((i = fread(&image->sizeX, 4, 1, file)) != 1) {
printf("Error reading width from %s.\n", filename);
return 0;
}
printf("Width of %s: %lu\n", filename, image->sizeX);
// read the height
if ((i = fread(&image->sizeY, 4, 1, file)) != 1) {
printf("Error reading height from %s.\n", filename);
return 0;
}
printf("Height of %s: %lu\n", filename, image->sizeY);
// calculate the size (assuming 24 bits or 3 bytes per pixel).
size = image->sizeX * image->sizeY * 3;
// read the planes
if ((fread(&planes, 2, 1, file)) != 1) {
printf("Error reading planes from %s.\n", filename);
return 0;
}
if (planes != 1) {
printf("Planes from %s is not 1: %u\n", filename, planes);
return 0;
}
// read the bpp
if ((i = fread(&bpp, 2, 1, file)) != 1) {
printf("Error reading bpp from %s.\n", filename);
return 0;
}
if (bpp != 24) {
printf("Bpp from %s is not 24: %u\n", filename, bpp);
return 0;
}
// seek past the rest of the bitmap header.
fseek(file, 24, SEEK_CUR);
// read the data.
image->data = (char *) malloc(size);
if (image->data == NULL) {
printf("Error allocating memory for color-corrected image data\n");
return 0;
}
if ((i = fread(image->data, size, 1, file)) != 1) {
printf("Error reading image data from %s.\n", filename);
return 0;
}
for (i=0; i<size; i+=3) { // reverse all of the colors. (bgr -> rgb)
temp = image->data[i];
image->data[i] = image->data[i+2];
image->data[i+2] = temp;
}
// we're done.
return 0;
}
// Load Bitmaps And Convert To Textures
void glob::LoadGLTextures() {
// Load Texture
Image *image1;
// allocate space for texture
image1 = (Image *) malloc(sizeof(Image));
if (image1 == NULL) {
printf("(image1 == NULL)\n");
exit(0);
}
ImageLoad("data/textures/NeHe.bmp", image1);
// Create Texture
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture); // 2d texture (x and y size)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // scale linearly when image bigger than texture
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // scale linearly when image smalled than texture
// 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image,
// border 0 (normal), rgb color data, unsigned byte data, and finally the data itself.
glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->data);
};
glob.h is this:
#ifndef GLOB_H_INCLUDED
#define GLOB_H_INCLUDED
#include <iostream>
#include <stdlib.h>
#include <stdio.h> // Header file for standard file i/o.
#include <GL/glx.h> /* this includes the necessary X headers */
#include <GL/gl.h>
//#include <GL/glut.h> // Header File For The GLUT Library
//#include <GL/glu.h> // Header File For The GLu32 Library
#include <X11/X.h> /* X11 constant (e.g. TrueColor) */
#include <X11/keysym.h>
class glob {
bool Running;
GLuint texture; //make an array when we start using more then 1
Display *dpy;
Window win;
XEvent event;
GLboolean doubleBuffer;
GLboolean needRedraw;
GLfloat xAngle, yAngle, zAngle;
float camera_x, camera_y, camera_z;
public:
glob();
int OnExecute();
public:
int init(int argc, char **argv);
void LoadGLTextures();
void OnEvent();
void redraw(void);
};
#endif // GLOB_H_INCLUDED
can any body help me fix this problem?
Lots of things could be going wrong.
If it's a very old file, it could have a BITMAPCOREHEADER which has size fields that are only 2 bytes each.
Is your machine little endian? BMP files are stored little endian.
Note that height may be negative, (which implies it's a top-down bitmap instead of a bottom up one). If you interpret a small negative number as an unsigned 32-bit int, you'll see values in the billions.
Also, your seek to the actual pixel data assumes that it starts right after the bitmap header. This is common, but not required. The file header contains the offset of the actual pixel data. (Microsoft documentation calls this the "bitmap bits" or the "color data".)
I recommend doing a hex dump of the beginning of your file and step through it by hand to make sure all your offsets and assumptions are correct. Feel free to paste the beginning of a hex dump into your question.
Are you on Windows? Can you just call LoadImage?

Convert Leptonica Pix Object to QPixmap ( or other image object )

I'm using the Leptonica Library to process some pictures. After that I want to show them in my QT GUI. Leptonica is using their own format Pix for the images, while QT is using their own format QPixmap. At the moment the only way for me is to save the pictures after processing as a file ( like bmp ) and then load them again with a QT function call. Now I want to convert them in my code, so I dont need to take the detour with saving them on the filesystem. Any ideas how to do this?
Best Regards
// edit:
Okay as already suggested I tried to convert the PIX* to a QImage.
The PIX* is defined like this:
http://tpgit.github.com/Leptonica/pix_8h_source.html
struct Pix
{
l_uint32 w; /* width in pixels */
l_uint32 h; /* height in pixels */
l_uint32 d; /* depth in bits */
l_uint32 wpl; /* 32-bit words/line */
l_uint32 refcount; /* reference count (1 if no clones) */
l_int32 xres; /* image res (ppi) in x direction */
/* (use 0 if unknown) */
l_int32 yres; /* image res (ppi) in y direction */
/* (use 0 if unknown) */
l_int32 informat; /* input file format, IFF_* */
char *text; /* text string associated with pix */
struct PixColormap *colormap; /* colormap (may be null) */
l_uint32 *data; /* the image data */
};
while QImage offers me a method like this:
http://developer.qt.nokia.com/doc/qt-4.8/qimage.html#QImage-7
QImage ( const uchar * data,
int width,
int height,
int bytesPerLine,
Format format )
I assume I cant just copy the data from the PIX to the QImage when calling the constructor. I guess I need to fill the QImage Pixel by Pixel, but actually I dont know how? Do I need to loop through all the coordinates? How do I regard the bit depth? Any ideas here?
I use this for conversion QImage to PIX:
PIX* TessTools::qImage2PIX(QImage& qImage) {
PIX * pixs;
l_uint32 *lines;
qImage = qImage.rgbSwapped();
int width = qImage.width();
int height = qImage.height();
int depth = qImage.depth();
int wpl = qImage.bytesPerLine() / 4;
pixs = pixCreate(width, height, depth);
pixSetWpl(pixs, wpl);
pixSetColormap(pixs, NULL);
l_uint32 *datas = pixs->data;
for (int y = 0; y < height; y++) {
lines = datas + y * wpl;
QByteArray a((const char*)qImage.scanLine(y), qImage.bytesPerLine());
for (int j = 0; j < a.size(); j++) {
*((l_uint8 *)lines + j) = a[j];
}
}
return pixEndianByteSwapNew(pixs);
}
And this for conversion PIX to QImage:
QImage TessTools::PIX2QImage(PIX *pixImage) {
int width = pixGetWidth(pixImage);
int height = pixGetHeight(pixImage);
int depth = pixGetDepth(pixImage);
int bytesPerLine = pixGetWpl(pixImage) * 4;
l_uint32 * s_data = pixGetData(pixEndianByteSwapNew(pixImage));
QImage::Format format;
if (depth == 1)
format = QImage::Format_Mono;
else if (depth == 8)
format = QImage::Format_Indexed8;
else
format = QImage::Format_RGB32;
QImage result((uchar*)s_data, width, height, bytesPerLine, format);
// Handle pallete
QVector<QRgb> _bwCT;
_bwCT.append(qRgb(255,255,255));
_bwCT.append(qRgb(0,0,0));
QVector<QRgb> _grayscaleCT(256);
for (int i = 0; i < 256; i++) {
_grayscaleCT.append(qRgb(i, i, i));
}
if (depth == 1) {
result.setColorTable(_bwCT);
} else if (depth == 8) {
result.setColorTable(_grayscaleCT);
} else {
result.setColorTable(_grayscaleCT);
}
if (result.isNull()) {
static QImage none(0,0,QImage::Format_Invalid);
qDebug() << "***Invalid format!!!";
return none;
}
return result.rgbSwapped();
}
This code accepts a const QImage& parameter.
static PIX* makePIXFromQImage(const QImage &image)
{
QByteArray ba;
QBuffer buf(&ba);
buf.open(QIODevice::WriteOnly);
image.save(&buf, "BMP");
return pixReadMemBmp(ba.constData(), ba.size());
}
I do not know the Leptonica Library, but I had a short look at the documentation and found the documentation about the PIX structure. You can create a QImage from the raw data and convert this to a QPixmap with convertFromImage.
Well I could solve the problem this way:
Leptonica offers a function
l_int32 pixWriteMemBmp (l_uint8 **pdata, size_t *psize, PIX *pix)
With this function you can write into the memory instead of a filestream. Still ( in this example ) the Bmp Header and format persists ( there are the same functions for other image formats too ).
The corresponding function from QT is this one:
bool QImage::loadFromData ( const uchar * data, int len, const char * format = 0 )
Since the the Header persits I just need to pass the data ptr and the size to the loadFromData function and QT does the rest.
So all together it would be like this:
PIX *m_pix;
FILE * pFile;
pFile = fopen( "PathToFile", "r" );
m_pix = pixReadStreamBmp(pFile); // If other file format use the according function
fclose(pFile);
// Now we have a Pix object from leptonica
l_uint8* ptr_memory;
size_t len;
pixWriteMemBmp(&ptr_memory, &size, m_pix);
// Now we have the picture somewhere in the memory
QImage testimage;
QPixmap pixmap;
testimage.loadFromData((uchar *)ptr_memory,len);
pixmap.convertFromImage(testimage);
// Now we have the image as a pixmap in Qt
This actually works for me, tho I don't know if there is a way to do this backwards so easy. ( If there is, please let me know )
Best Regards
You can save your pixmap to RAM instead of file (use QByteArray to store the data, and QBuffer as your I/O device).