Hi,
I'm trying to convert a FreeType2 bitmap to a System::Drawing::Bitmap in C++/CLI.
FT_Bitmap has a unsigned char* buffer that contains the data to write.
I have got somewhat working save it disk as a *.tga, but when saving as *.bmp it renders incorrectly.
I believe that the size of byte[] is incorrect and that my data is truncated.
Any hints/tips/ideas on what is going on here would be greatly appreciated. Links to articles explaining byte layout and pixel formats etc. would be helpful.
Thanks!!
C++/CLI code.
FT_Bitmap *bitmap = &face->glyph->bitmap;
int width = (face->bitmap->metrics.width / 64);
int height = (face->bitmap->metrics.height / 64);
// must be aligned on a 32 bit boundary or 4 bytes
int depth = 8;
int stride = ((width * depth + 31) & ~31) >> 3;
int bytes = (int)(stride * height);
// as *.tga
void *buffer = bytes ? malloc(bytes) : NULL;
if (buffer)
{
memset(buffer, 0, bytes);
for (int i = 0; i < glyph->rows; ++i)
memcpy((char *)buffer + (i * width), glyph->buffer + (i * glyph->pitch), glyph->pitch);
WriteTGA("Test.tga", buffer, width, height);
}
// as *.bmp
array<Byte>^ values = gcnew array<Byte>(bytes);
Marshal::Copy((IntPtr)glyph->buffer, values, 0, bytes);
Bitmap^ systemBitmap = gcnew Bitmap(width, height, PixelFormat::Format24bppRgb);
// create bitmap data, lock pixels to be written.
BitmapData^ bitmapData = systemBitmap->LockBits(Rectangle(0, 0, width, height), ImageLockMode::WriteOnly, bitmap->PixelFormat);
Marshal::Copy(values, 0, bitmapData->Scan0, bytes);
systemBitmap->UnlockBits(bitmapData);
systemBitmap->Save("Test.bmp");
Reference, FT_Bitmap
typedef struct FT_Bitmap_
{
int rows;
int width;
int pitch;
unsigned char* buffer;
short num_grays;
char pixel_mode;
char palette_mode;
void* palette;
} FT_Bitmap;
Reference, WriteTGA
bool WriteTGA(const char *filename, void *pxl, uint16 width, uint16 height)
{
FILE *fp = NULL;
fopen_s(&fp, filename, "wb");
if (fp)
{
TGAHeader header;
memset(&header, 0, sizeof(TGAHeader));
header.imageType = 3;
header.width = width;
header.height = height;
header.depth = 8;
header.descriptor = 0x20;
fwrite(&header, sizeof(header), 1, fp);
fwrite(pxl, sizeof(uint8) * width * height, 1, fp);
fclose(fp);
return true;
}
return false;
}
Update
FT_Bitmap *bitmap = &face->glyph->bitmap;
// stride must be aligned on a 32 bit boundary or 4 bytes
int depth = 8;
int stride = ((width * depth + 31) & ~31) >> 3;
int bytes = (int)(stride * height);
target = gcnew Bitmap(width, height, PixelFormat::Format8bppIndexed);
// create bitmap data, lock pixels to be written.
BitmapData^ bitmapData = target->LockBits(Rectangle(0, 0, width, height), ImageLockMode::WriteOnly, target->PixelFormat);
array<Byte>^ values = gcnew array<Byte>(bytes);
Marshal::Copy((IntPtr)bitmap->buffer, values, 0, bytes);
Marshal::Copy(values, 0, bitmapData->Scan0, bytes);
target->UnlockBits(bitmapData);