triumphost 120 Posting Whiz

This may be a long post but I really need to know how to Convert between the two image formats and amonst themselves as well.

Here goes:

I have a struct like the one below that holds all pixel information:

typedef union RGB
{
    uint32_t Color;
    struct
    {
        unsigned char B, G, R, A;
    } RGBA;
} *PRGB;

std::vector<RGB> Pixels;   //Holds all pixels.

I am able to do:

Bmp24 -> Bmp24.
Bmp32 -> Bmp32.
Png24 -> Png24.
Png32 -> Png32.
Png32 -> Bmp32.

However I am unable to do:

Bmp24 -> Png24.
Bmp24 -> Png32.
Bmp32 -> Png24.
Png24 -> Bmp32.
Png32 -> Bmp32.
Bmp32 -> Png32. (Works partially. Shows the icon but the image is invisible.)

All of the bitmap writing works except when going from 24 to 32 or vice-versa. I don't know what I'm doing wrong or why 24-32 conversions don't work. My bitmap reading and writing code is as follows:

Bitmap(const void* Pointer, int Width, int Height, uint32_t BitsPerPixel) //Constructor initialization here...
{
    Pixels.clear();
    if (Pointer == nullptr) {throw std::logic_error("Null Pointer Exception. Pointer is NULL.");}
    if (Width < 1 || Height < 1) {throw std::invalid_argument("Invalid Arguments. Width and Height cannot equal 0.");}
    std::memset(&Info, 0, sizeof(BITMAPINFO));
    size = ((width * BitsPerPixel + 31) / 32) * 4 * height;

    Info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    Info.bmiHeader.biWidth = width;
    Info.bmiHeader.biHeight = height;
    Info.bmiHeader.biPlanes = 1;
    Info.bmiHeader.biBitCount = BitsPerPixel;
    Info.bmiHeader.biCompression = BI_RGB;
    Info.bmiHeader.biSizeImage = size;
    bFileHeader.bfType = 0x4D42;
    bFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(Info.bmiHeader);
    bFileHeader.bfSize = bFileHeader.bfOffBits + size;

    const unsigned char* BuffPos = static_cast<const unsigned char*>(Pointer);
    height = (height < 0 ? -height : height);
    Pixels.resize(width * height);
    for (int I = 0; I < height; I++)
    {
        for (int J = 0; J < width; J++)
        {
            Pixels[(height - 1 - I) * width + J].RGBA.B = *(BuffPos++);
            Pixels[(height - 1 - I) * width + J].RGBA.G = *(BuffPos++);
            Pixels[(height - 1 - I) * width + J].RGBA.R = *(BuffPos++);
            Pixels[(height - 1 - I) * width + J].RGBA.A = (Info.bmiHeader.biBitCount > 24 ? *(BuffPos++) : 0);
        }
        if(Info.bmiHeader.biBitCount == 24)
            BuffPos += width % 4;
    }
}

bool SaveBitmap(const char* FilePath)
{
    std::vector<unsigned char> ImageData(size);
    unsigned char* BuffPos = ImageData.data();

    for (int I = 0; I < height; ++I)
    {
        for (int J = 0; J < width; ++J)
        {
            *(BuffPos++) = Pixels[(height - 1 - I) * width + J].RGBA.B;
            *(BuffPos++) = Pixels[(height - 1 - I) * width + J].RGBA.G;
            *(BuffPos++) = Pixels[(height - 1 - I) * width + J].RGBA.R;

            if (Info.bmiHeader.biBitCount > 24)
                *(BuffPos++) = Pixels[(height - 1 - I) * width + J].RGBA.A;
        }
        if(Info.bmiHeader.biBitCount == 24)
            BuffPos += width % 4;
    }

    std::fstream hFile(FilePath, std::fstream::out | std::ofstream::binary);
    if (!hFile.is_open()) return false;

    hFile.write(reinterpret_cast<char*>(&bFileHeader), sizeof(BITMAPFILEHEADER));
    hFile.write(reinterpret_cast<char*>(&Info.bmiHeader), sizeof (BITMAPINFOHEADER));
    hFile.write(reinterpret_cast<char*>(&ImageData[0]), Size());
    hFile.close();

    return true;
}

My PNG Code using LibPNG is as follows (It does 32->24 but not 24->32):

void PNGPack(int width, int height, int BPP, unsigned char* Input, std::vector<RGB> &Pixels)
{
    unsigned char* BuffPos = Input;
    height = (height < 0 ? -height : height);
    Pixels.resize(width * height);

    for (int I = 0; I < height; I++)
    {
        for (int J = 0; J < width; J++)
        {
            Pixels[(height - 1 - I) * width + J].RGBA.B = *(BuffPos++);
            Pixels[(height - 1 - I) * width + J].RGBA.G = *(BuffPos++);
            Pixels[(height - 1 - I) * width + J].RGBA.R = *(BuffPos++);
            Pixels[(height - 1 - I) * width + J].RGBA.A = (BPP > 24 ? *(BuffPos++) : 0);
        }
        if(BPP == 24)
            BuffPos += width % 4;
    }
}

Png::Png(const void* Pointer, int Width, int Height, uint32_t BitsPerPixel) : Pixels(0), BitsPerPixel(BitsPerPixel), width(Width), height(Height), bitdepth(8), colortype(PNG_COLOR_TYPE_RGBA), interlacetype(0), channels(4)
{
    if (Width < 1 || Height < 1) {throw std::invalid_argument("Invalid Argument. Width and Height cannot equal 0.");}

    channels = (BitsPerPixel > 24 ? 4 : 3);
    colortype = (BitsPerPixel > 24 ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB);

    PNGPack(width, height, BitsPerPixel, static_cast<unsigned char*>(const_cast<void*>(Pointer)), Pixels);
}

void Png::Save(const char* FilePath)
{
    std::fstream hFile(FilePath, std::ios::out | std::ios::binary);
    if (!hFile.is_open()) {throw std::invalid_argument("Cannot open file for writing.");}

    png_structp PngPointer = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
    if (!PngPointer)
    {
        hFile.close();
        throw std::runtime_error("Error: Cannot Create Write Structure.");
    }

    png_infop InfoPointer = png_create_info_struct(PngPointer);
    if (!InfoPointer)
    {
        hFile.close();
        png_destroy_write_struct(&PngPointer, nullptr);
        throw std::runtime_error("Error: Cannot Create InfoPointer Structure.");
    }

    if (setjmp(png_jmpbuf(PngPointer)))
    {
        hFile.close();
        png_destroy_write_struct(&PngPointer, &InfoPointer);
        throw std::runtime_error("Error: Cannot Set Jump Pointer.");
    }

    png_set_IHDR (PngPointer, InfoPointer, width, height, bitdepth, BitsPerPixel == 24 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

    std::vector<unsigned char*> RowPointers(height);
    unsigned char* BuffPos = reinterpret_cast<unsigned char*>(Pixels.data());

    for (size_t I = 0; I < height; ++I)
    {
        RowPointers[I] = BuffPos + (I * width * ((BitsPerPixel > 24) ? 4 : 3));
    }

    png_set_bgr(PngPointer);
    //png_init_io(PngPointer, hFile);
    png_set_write_fn(PngPointer, reinterpret_cast<void*>(&hFile), WriteToStream, nullptr);
    png_set_rows(PngPointer, InfoPointer, RowPointers.data());
    png_write_png(PngPointer, InfoPointer, PNG_TRANSFORM_IDENTITY, NULL);
    png_destroy_write_struct(&PngPointer, &InfoPointer);
    hFile.close();
}

Any idea what the two problems could be?

I also tried making helper functions:

void T24To32(std::vector<RGB> &Input, std::vector<RGB> &Output, int Width, int Height)
{
    Output.resize(Input.size());
    for (int I = 0; I < Height; ++I)
    {
        for (int J = 0; J < Width; ++J)
        {
            Output[J].RGBA.B = Input[J].RGBA.B;
            Output[J].RGBA.G = Input[J].RGBA.G;
            Output[J].RGBA.R = Input[J].RGBA.R;
            Output[J].RGBA.A = 0;
        }
    }
}

void Pack(int width, int height, int BPP, unsigned char* Input, std::vector<RGB> &Pixels)
{
    unsigned char* BuffPos = Input;
    height = (height < 0 ? -height : height);
    Pixels.resize(width * height);

    for (int I = 0; I < height; I++)
    {
        for (int J = 0; J < width; J++)
        {
            Pixels[(height - 1 - I) * width + J].RGBA.B = *(BuffPos++);
            Pixels[(height - 1 - I) * width + J].RGBA.G = *(BuffPos++);
            Pixels[(height - 1 - I) * width + J].RGBA.R = *(BuffPos++);
            Pixels[(height - 1 - I) * width + J].RGBA.A = (BPP > 24 ? *(BuffPos++) : 0);
        }
        if(BPP == 24)
            BuffPos += width % 4;
    }
}

void Unpack(int width, int height, int BPP, std::vector<RGB> Pixels, unsigned char* &Output)
{
    unsigned char* BuffPos = Output;

    for (int I = 0; I < height; ++I)
    {
        for (int J = 0; J < width; ++J)
        {
            *(BuffPos++) = Pixels[(height - 1 - I) * width + J].RGBA.B;
            *(BuffPos++) = Pixels[(height - 1 - I) * width + J].RGBA.G;
            *(BuffPos++) = Pixels[(height - 1 - I) * width + J].RGBA.R;

            if (BPP > 24)
                *(BuffPos++) = Pixels[(height - 1 - I) * width + J].RGBA.A;
        }
        if(BPP == 24)
            BuffPos += width % 4;
    }
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts learning and sharing knowledge.