This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| Universal Image Format Conversion Submitted by

Did You ever want to convert Your image into any possible format? R8G8B8, A4R4G4B4, X1R5G5B5, R6G7A1B2... ? In a single function call? LOOK!!!

Download Associated File: imgconvert.txt (4,371 bytes)

    /*

    Did You ever want to convert Your image into any possible format?

    R8G8B8, A4R4G4B4, X1R5G5B5, R6G7A1B2... ?

    In a single function call?

    LOOK!!!

    */

    //------------------------------------------------------------------------------
    // Sample of using:
    //
    // ConvertFromA8R8G8B8(sourceInA8R8G8B8, 256, 256,
    //    UlFormatData("X1R5G5B5"), destinationBuffer, destinationPitch);
    //------------------------------------------------------------------------------

    //------------------------------------------------------------------------------
    // There is one basic type of format: A8R8G8B8.
    // UlFormatData is a description how basic format must be
    // converted into desired format.
    //
    // During conversion on each color will be done & operation with its bitmask,
    // and then right shift.
    // After all there will binary 'or' along each color.

    typedef unsigned long ulong;
    typedef unsigned short ushort;
    typedef unsigned char uchar;

    struct UlFormatData
    {
    public:
        int BytesPP;

        ulong BitMask[4]; // A bit mask in source A8R8G8B8 picture.
        int ShiftR[4]; // Can be < 0 for left shift operation.

    public:
        ulong CreateBitMask(int aStartPosition, int aSize)
        {
            ulong result = 0;
            UlFor (int i = 0; i < aSize; i++)
            {
                result = (result >> 1) | 0x80000000;
            }
            result = result >> aStartPosition;
            return result;
        }

        UlFormatData(const char *format_str)
        {
            BytesPP = 0;
            for (int i = 0; i < 4; i++)
            {
                ShiftR[i] = 0;
                BitMask[i] = 0; // Exclude color if not in use.
            }

            // Count destination's bits per pixel.
            int bitsPP = 0;
            UlFor (const char *temp = format_str; *temp; temp++)
            {
                if ('0' <= *temp && *temp <= '9')
                    bitsPP += *temp - '0';
            }

            // Main loop: trace format_str and calculate masks and shifts.
            int bitsPassed = 0;
            int currentIndex = 0; // Index for any 'argb' order.

            while (*format_str)
            {
                char color = *(format_str++);
                char numberOfBits = *(format_str++) - '0';

                int sourceColorStart =
                color == 'A' || color == 'X' ? 0 :
                color == 'R' ? 8 :
                color == 'G' ? 16 :
                color == 'B' ? 24 : 32;

                BitMask[currentIndex] = CreateBitMask(sourceColorStart, numberOfBits);
                ShiftR[currentIndex] = bitsPassed - sourceColorStart + (32 - bitsPP);

                bitsPassed += numberOfBits;
                currentIndex++;
            }

            BytesPP = bitsPP / 8;
        }
    };

    //------------------------------------------------------------------------------
    // There is no 24-bit type in C++, so...

    struct UlBits24
    {
        char b[3];
    };

    //------------------------------------------------------------------------------
    // Template function that will copy a line of image into destination with
    //    adequate conversion.

    template <class dsttype>
    static inline void CopyARGBLine(const ulong *srcline, dsttype *dstline,
        const UlFormatData &aFormatData, int width)
    {
        for (int x = 0; x < width; x++)
        {
            ulong temp = *(srcline++);
            ulong result = 0;
            UlFor (int i = 0; i < 4; i++)
            {
                result |= ((temp & aFormatData.BitMask[i]) >>
                    aFormatData.ShiftR[i]);
            }
            *(dstline++) = *(dsttype *)(&result);
        }
    }

    //------------------------------------------------------------------------------
    void ConvertFromA8R8G8B8(const ulong *aSource, int width, int height,
        const UlFormatData &aFormatData, uchar *aData, int aPitch)
    {
        for (int y = 0; y < height; y++)
        {
            const ulong *line = aSource + (y * width);
            uchar *dstline = aData + (y * aPitch);

            switch (aFormatData.BytesPP)
            {
            case 1:
                CopyARGBLine<uchar>(line, (uchar *)dstline, aFormatData, width);
                break;
            case 2:
                CopyARGBLine<ushort>(line, (ushort *)dstline, aFormatData, width);
                break;
            case 3:
                CopyARGBLine<UlBits24>(line, (UlBits24 *)dstline,
                    aFormatData, width);
                break;
            case 4:
                CopyARGBLine<ulong>(line, (ulong *)dstline, aFormatData, width);
                break;
            default:
                throw "Incorrect destination image format";
            }
        }
    }

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.