Pregunta

Estoy intentando crear un convertidor de herramienta / activo que rasterises una fuente a una página de textura para un juego XNA usando el FreeType2 motor.

A continuación, la primera imagen es la salida directa desde la] 1 motor FreeType2 . La segunda imagen es el resultado después de intentar convertirlo a un System::Drawing::Bitmap.

dirigen a http://www.freeimagehosting.net/uploads/fb102ee6da.jpg currentresult http://www.freeimagehosting.net/uploads/9ea77fa307.jpg

¿Alguna pista / consejos / ideas sobre lo que está pasando aquí sería muy apreciada. Enlaces a artículos que explican formatos de diseño de píxeles de bytes y también serían útiles.

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

Actualizar . PixelFormat cambiado a 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);
¿Fue útil?

Solución

ha

Ah. Trabajado a cabo.

FT_Bitmap es una imagen de 8 bits, por lo que el PixelFormat correcta era 8bppIndexed, lo que resultó esta salida. No alineados a 32byte límite http://www.freeimagehosting.net/uploads/dd90fa2252.jpg

necesidades System::Drawing::Bitmap a estar alineados en un límite de 32 bits.

Me estaba calculando la zancada, pero no estaba acolchado de que al escribir el mapa de bits. Copiado el buffer FT_Bitmap a un byte[] y luego escribió que a un MemoryStream, añadir el relleno necesario.

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

cubrió de la memoria para que el GC dejaría solo.

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

Como no hay Format8bppIndexed gris la imagen todavía no era correcta.

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

A continuación cambiado la paleta de mapa de bits de escala de grises 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


solución final.

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

Otros consejos

Su valor "profundidad" no coincide con el PixelFormat del mapa de bits. Tiene que ser 24 para que coincida con Format24bppRgb. El PF para las necesidades de mapa de bits para que coincida con el PF y el paso de la FT_Bitmap así, no veo que cuidar de eso.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top