unsigned char * буфер в System :: Drawing :: Bitmap - PullRequest
4 голосов
/ 01 мая 2010

Я пытаюсь создать конвертер инструментов / ресурсов, который растеризует шрифт на странице текстуры для игры XNA, используя FreeType2 .

Ниже первое изображение - прямой вывод из движка FreeType2] 1 . Второе изображение - результат после попытки преобразовать его в System::Drawing::Bitmap.

target http://www.freeimagehosting.net/uploads/fb102ee6da.jpg currentresult 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);

Ответы [ 2 ]

6 голосов
/ 03 мая 2010

Ах, ха.Сработало.

FT_Bitmap - это 8-битное изображение, поэтому правильное значение PixelFormat было 8bppIndexed, в результате чего получился вывод. Не выровнен по 32-байтовой границе 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);    
  }

Закрепил память, чтобы ГК оставил ее в покое.

  // 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 Grey изображение все равно было неправильным.

альтернативный текст 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;

альтернативный текст 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);
1 голос
/ 01 мая 2010

Ваше значение глубины не соответствует пиксельному формату растрового изображения. Это должно быть 24, чтобы соответствовать Format24bppRgb. PF для растрового изображения должен соответствовать PF и шагу FT_Bitmap, я не вижу, чтобы вы позаботились об этом.

...