Search code examples
winapibitmapgdivclrichedit

How to render RichEdit Text to a canvas by keeping font smoothness


i am trying to render RichEdit to a bitmap. I want to make backgrond tranparent. I could achieve that by the code above. The problem is that when i set bitmap as tranparent only the transparent color becomes transparent. Is there any way to handle the pixels on the edge which are diffrent from background color and also different from font color. i mean making the pixels semi-tranparent on the edge which makes a smooth view.

    Graphics::TBitmap *bitmap = new Graphics::TBitmap();
    bitmap->Width = RichEdit1->Width ;
    bitmap->Height = RichEdit1->Height ;


    TRect BoundingBox(0,0,RichEdit1->Width, RichEdit1->Height) ;

    // Render RichEdit to bitmap
    TFormatRange formatRange;
    int twipsPerPixel = 1440 / Screen->PixelsPerInch;

    formatRange.hdc = bitmap->Canvas->Handle;
    formatRange.hdcTarget = bitmap->Canvas->Handle;
    formatRange.chrg.cpMin = 0;
    formatRange.chrg.cpMax = -1;

    formatRange.rc.top = 2 * twipsPerPixel;
    formatRange.rc.bottom = (BoundingBox.Height() - 4) * twipsPerPixel + formatRange.rc.top;
    formatRange.rc.left = 2 * twipsPerPixel;
    formatRange.rc.right = (BoundingBox.Width() - 4) * twipsPerPixel;

    // Measure text's height.
    RichEdit1->Perform(EM_FORMATRANGE, 0, 0);
    RichEdit1->Perform(EM_FORMATRANGE, 0, (LPARAM) &formatRange);

    formatRange.rc.bottom = (BoundingBox.Height() - 4) * twipsPerPixel + formatRange.rc.top;
    formatRange.rc.left = 2 * twipsPerPixel;
    formatRange.rc.right = (BoundingBox.Width() - 4) * twipsPerPixel;

    formatRange.rcPage = formatRange.rc;


    /**
    * Draw..
    **************************************************************************/
    RichEdit1->Perform(EM_FORMATRANGE, 1, (LPARAM) &formatRange);
    RichEdit1->Perform(EM_FORMATRANGE, 0, 0);


   // Draw background
   // Use different background color to see the trasparency problem
   this->Canvas->Brush->Color = clRed ;
   this->Canvas->Rectangle(0,0,RichEdit1->Width , RichEdit1->Height );

   // Draw the transparent bitmap
   bitmap->Transparent = true ;
   bitmap->TransparentColor = RichEdit1->Color ;
   this->Canvas->Draw(0,0,bitmap);

Thanx.


Solution

  • Font smoothing works with partial transparency using an alpha channel. The Transparent and TransparentColor properties of TBitmap are therefore not applicable.

    You haven't said which version of the C++ Builder/VCL you are using, but more modern versions have better support for partial transparency than some of the older ones.

    To get this to work you will need to set the PixelFormat of your bitmap to be pf32bit. You may also need to set AlphaFormat to afDefined.

    If you can't get TBitmap to do what you need then you'll have to revert to GDI commands to create a suitable HBITMAP. You can at least assign that to the Handle property of a TBitmap and usually from there everything behaves.

    Note that I am not a user of C++ Builder but do know the VCL from Delphi.

    UPDATE

    I tried this out in Delphi and the following worked fine for me:

    procedure TForm4.Button1ClickBMP(Sender: TObject);
    var
      BMP: TBitmap;
      fmtRange: TFormatRange;
      intPPI, Flags: Integer;
    begin
      BMP := TBitmap.Create;
      Try
        BMP.PixelFormat := pf32bit;
        BMP.SetSize(RichEdit1.Width, RichEdit1.Height);
    
        FillChar(fmtRange, SizeOf(fmtRange), 0);
        with fmtRange do begin
          hDC := BMP.Canvas.Handle;
          hdcTarget := hDC;
          intPPI := Screen.PixelsPerInch;
          rc := Rect(
            0,
            0,
            RichEdit1.Width*1440 div intPPI,
            RichEdit1.Height*1440 div intPPI
          );
          rcPage := rc;
          chrg.cpMin := 0;
          chrg.cpMax := -1;
        end;
        Flags := 1;
        RichEdit1.Perform(EM_FORMATRANGE, Flags, Longint(@fmtRange));
        RichEdit1.Perform(EM_FORMATRANGE, 0, 0);
        BMP.SaveToFile('c:\desktop\test.bmp');
      Finally
        FreeAndNil(BMP);
      End;
    end;
    

    The output looks like this, blown up somewhat to see the anti-aliasing:

    enter image description here

    I hope this helps, because it looks like you are very nearly there!