One of my personal goals is to celebrate several successes every day – even if these successes are fairly small. Today, I succeeded in using the Direct2D and DirectWrite libraries from .Net! It took several hours, of course, but I managed to my .Net code to lock a bitmap and manipulate it in unmanaged C++ code, actually writing some text to the bitmap.

Here’s how it goes. First, you need a System.Drawing.Bitmap created on the .Net side. You lock its bits, then send it over to the unmanaged (‘native’) function:

private static Size RegenerateFreeformImage(ConversionOptions options, string markup, int index)
{
  const int w = 512, h = 256;
  using (Bitmap bmp = new Bitmap(w, h))
  {
    BitmapData data = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite,
                                   bmp.PixelFormat);
    NativeMethods.RenderMarkup(data.Scan0, markup, data.Width, data.Height, 
      data.Stride, options.FreeformFontFamily, options.FreeformFontSize);
    bmp.UnlockBits(data);
    string filename = Path.Combine(Path.GetTempPath(), options.FreeformPrefix + index + ".jpg");
    using (Bitmap bmp2 = FlowBasedRenderer.Crop(bmp))
      SaveImageAsJpeg(bmp2, filename);
  }
  return new Size(w, h);
}

The C++ code picks up on this with the following (rather basic) signature:

MYAPI void RenderMarkup(BYTE* dst, LPCWSTR markup, int width, int height, 
                        int stride, LPCWSTR fontFamily, float fontSize)
{
  ⋮
}

Inside, all operations happen on a separate bitmap object that we create, together with a render target.

if (SUCCEEDED(hr))
{
  hr = pWICFactory->CreateBitmap(width, height,
       GUID_WICPixelFormat32bppBGR,
       WICBitmapCacheOnLoad, &pWICBitmap);
}
if (SUCCEEDED(hr))
{
  hr = pD2DFactory->CreateWicBitmapRenderTarget(
       pWICBitmap, D2D1::RenderTargetProperties(), &pRT);
}

Before rendering text to the render target, some preparatory steps are needed:

if (SUCCEEDED(hr))
{
  hr = pDWriteFactory->CreateTextFormat(
       fontFamily,
       NULL,
       DWRITE_FONT_WEIGHT_NORMAL,
       DWRITE_FONT_STYLE_NORMAL,
       DWRITE_FONT_STRETCH_NORMAL,
       fontSize,
       L"",
       &pTextFormat);
}
if (SUCCEEDED(hr))
{
  pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
  pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
}
if (SUCCEEDED(hr))
{
  hr = pRT->CreateSolidColorBrush(
      D2D1::ColorF(D2D1::ColorF::Black),
      &pBlackBrush
      );
}

Finally, we render text to the bitmap. What’s show below is the simplest case – it’s worth bearing in mind that DirectWrite can do really amazing OpenType wizardry that’s a bit too complex to show here.

if (SUCCEEDED(hr))
{
  pRT->BeginDraw();
  pRT->Clear(D2D1::ColorF(D2D1::ColorF::White));
  D2D1_SIZE_F rtSize = pRT->GetSize();
  pRT->DrawText(
      markup,
      wcslen(markup),
      pTextFormat,
      D2D1::RectF(0, 0, rtSize.width, rtSize.height),
      pBlackBrush);
  hr = pRT->EndDraw();
}

Finally, here’s something that’s amazingly easy to do: we just copy the pixels from the bitmap we rendered to to the Bitmap we passed from .Net. Does it ever get more simple?

WICRect r;
r.X = r.Y = 0;
r.Width = width;
r.Height = height;
hr = pWICBitmap->CopyPixels(&r, stride, sizeof(Pixel) * width * height, dst);

Of course, this addition was written for my TypograFix pet project. Meanwhile, let me leave you with the fruits of my labour. The image below was generated using Direct2D & DirectWrite.

Beautiful Typography

Ahh, can life possibly get any better?