代码之家  ›  专栏  ›  技术社区  ›  Dennis

无符号字符*缓冲区到System::Drawing::Bitmap

  •  4
  • Dennis  · 技术社区  · 15 年前

    我正在尝试创建一个工具/资产转换器,它使用 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 回复  |  直到 13 年前
        1
  •  6
  •   Dennis    13 年前

    啊哈。解决了。

    FT_Bitmap 是8位图像,因此正确 PixelFormat 8bppIndexed ,从而产生此输出。 Not aligned to 32byte boundary http://www.freeimagehosting.net/uploads/dd90fa2252.jpg

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

    我正在计算步幅,但在编写位图时没有填充它。复制了 FTT-位图 缓冲区到 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 灰色图像仍然不正确。

    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
  •  1
  •   Hans Passant    15 年前

    “深度”值与位图的像素格式不匹配。它必须是24才能匹配格式24bpprgb。位图的pf也需要与ft_位图的pf和步幅相匹配,我不认为你会处理好。

    推荐文章