/* 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 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(line, (uchar *)dstline, aFormatData, width); break; case 2: CopyARGBLine(line, (ushort *)dstline, aFormatData, width); break; case 3: CopyARGBLine(line, (UlBits24 *)dstline, aFormatData, width); break; case 4: CopyARGBLine(line, (ulong *)dstline, aFormatData, width); break; default: throw "Incorrect destination image format"; } } }