【问题标题】:unsigned char* buffer to System::Drawing::Bitmapunsigned char* 缓冲区到 System::Drawing::Bitmap
【发布时间】:2010-05-01 14:43:54
【问题描述】:

我正在尝试使用FreeType2 引擎创建一个工具/资产转换器,将字体光栅化为 XNA 游戏的纹理页面。

下面,第一张图片是 FreeType2]1 引擎的直接输出。第二张图片是尝试将其转换为System::Drawing::Bitmap 后的结果。

target http://www.freeimagehosting.net/uploads/fb102ee6da.jpgcurrentresult http://www.freeimagehosting.net/uploads/9ea77fa307.jpg

任何关于这里发生的事情的提示/提示/想法将不胜感激。解释字节布局和像素格式的文章链接也会有所帮助。

  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 *.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");

更新。将 PixelFormat 更改为 8bppIndexed

  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);

【问题讨论】:

  • bitmapData->scan0是位图中第一个像素数据的地址。
  • FT_Bitmap 是 FT_PIXEL_MODE_GRAY(8 位位图)。 bit.ly/9lgh69.

标签: visual-c++ c++-cli freetype freetype2


【解决方案1】:

啊哈。解决了。

FT_Bitmap 是一个 8 位图像,所以正确的 PixelFormat8bppIndexed,这导致了这个输出。 Not aligned to 32byte boundary http://www.freeimagehosting.net/uploads/dd90fa2252.jpg

System::Drawing::Bitmap 需要在 32 位边界上对齐。

我正在计算步幅,但在编写位图时没有填充它。将FT_Bitmap 缓冲区复制到byte[],然后将其写入MemoryStream,添加必要的填充。

  int stride = ((width * pixelDepth + 31) & ~31) >> 3;
  int padding = stride - (((width * pixelDepth) + 7) / 8);

  array<Byte>^ pad = gcnew array<Byte>(padding);
  array<Byte>^ buffer = gcnew array<Byte>(size);  
  Marshal::Copy((IntPtr)source->buffer, buffer, 0, size);

  MemoryStream^ ms = gcnew MemoryStream();

  for (int i = 0; i < height; ++i)
  {
    ms->Write(buffer, i * width, width);
    ms->Write(pad, 0, padding);    
  }

固定内存,以便 GC 不理会它。

  // pin memory and create bitmap
  GCHandle handle = GCHandle::Alloc(ms->ToArray(), GCHandleType::Pinned);
  target = gcnew Bitmap(width, height, stride, PixelFormat::Format8bppIndexed, handle.AddrOfPinnedObject());   
  ms->Close();

由于没有Format8bppIndexed Gray,图像仍然不正确。

alt text http://www.freeimagehosting.net/uploads/8a883b7dce.png

然后将位图调色板更改为 256 灰度。

  // 256-level greyscale palette
  ColorPalette^ palette = target->Palette;
  for (int i = 0; i < palette->Entries->Length; ++i)
    palette->Entries[i] = Color::FromArgb(i,i,i);

  target->Palette = palette;

alt text http://www.freeimagehosting.net/uploads/59a745269e.jpg


最终解决方案。

  error = FT_Load_Char(face, ch, FT_LOAD_RENDER);
  if (error)
    throw gcnew InvalidOperationException("Failed to load and render character");

  FT_Bitmap *source = &face->glyph->bitmap; 

  int width = (face->glyph->metrics.width / 64);
  int height = (face->glyph->metrics.height / 64);
  int pixelDepth = 8;   
  int size = width * height;

  // stride must be aligned on a 32 bit boundary or 4 bytes
  // padding is the number of bytes to add to make each row a 32bit aligned row
  int stride = ((width * pixelDepth + 31) & ~31) >> 3;
  int padding = stride - (((width * pixelDepth) + 7) / 8);

  array<Byte>^ pad = gcnew array<Byte>(padding);
  array<Byte>^ buffer = gcnew array<Byte>(size);  
  Marshal::Copy((IntPtr)source->buffer, buffer, 0, size);

  MemoryStream^ ms = gcnew MemoryStream();

  for (int i = 0; i < height; ++i)
  {
    ms->Write(buffer, i * width, width);
    ms->Write(pad, 0, padding);    
  }

  // pin memory and create bitmap
  GCHandle handle = GCHandle::Alloc(ms->ToArray(), GCHandleType::Pinned);
  target = gcnew Bitmap(width, height, stride, PixelFormat::Format8bppIndexed, handle.AddrOfPinnedObject());   
  ms->Close();

  // 256-level greyscale palette
  ColorPalette^ palette = target->Palette;
  for (int i = 0; i < palette->Entries->Length; ++i)
    palette->Entries[i] = Color::FromArgb(i,i,i);

  target->Palette = palette;

  FT_Done_FreeType(library);

【讨论】:

    【解决方案2】:

    您的“深度”值与位图的 PixelFormat 不匹配。它需要为 24 才能匹配 Format24bppRgb。位图的 PF 也需要与 FT_Bitmap 的 PF 和步幅相匹配,我不认为你会处理这个问题。

    【讨论】:

    • 感谢您的回复。 FT_Bitmap 是 FT_PIXEL_MODE_GRAY(8 位位图)。 bit.ly/9lgh69。我应该使用什么正确的步幅和 PixelFormat?
    • 没有,8bpp 格式需要调色板将字节映射到颜色。 GDI+很好地处理调色板,坚持使用 .tga。或者从顶部修补一下,它是一种非常无用的像素格式,用于很好地抗锯齿的文本,在 LCD 显示器上显示良好。
    • 感谢汉斯的帮助,我设法弄明白了。将其写为 *.tga 只是为了测试输出是否正确。这是一项更大任务的一部分,需要将图像放入位图中以在 C# 中进一步处理。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-12
    • 2014-06-26
    • 2012-05-27
    相关资源
    最近更新 更多