c++delphigraphicsgdic++builder-10-seattle

BeginPath Textout EndPath draws inverted text


here is the code that I have in OnPaint event of my form:

int elementCount;
String tStr = L"15:00";

::BeginPath(Canvas->Handle);
::TextOut(Canvas->Handle, 5, 5, tStr.c_str(), tStr.Length());
::EndPath(Canvas->Handle);
elementCount = ::GetPath(Canvas->Handle, NULL, NULL, 0);
Canvas->Brush->Color = clBlue;
Canvas->Pen->Color = clYellow;
Canvas->Pen->Width = 4;
if(0 < elementCount)
{
    boost::scoped_array<TPoint> mPoints(new TPoint[elementCount]);
    boost::scoped_array<BYTE> mTypes(new BYTE[elementCount]);

    ::GetPath(Canvas->Handle, mPoints.get(), mTypes.get(), elementCount);
    ::FillPath(Canvas->Handle);
    ::PolyDraw(Canvas->Handle, mPoints.get(), mTypes.get(), elementCount);
}
else
    ::StrokeAndFillPath(Canvas->Handle);

but here is what I get on the form:

enter image description here

as you can see the text comes out inverted (the text has to be blue and background gray but it is the other way around and the yellow line is around the background instead of text). Does anyone know how I can fix this?

I am using C++ Builder 10 Seattle but if anyone knows that Delphi or pure C++ trick, I can work with that as well.

Thank you


Solution

  • This is explained in TextOut's documentation:

    When the TextOut function is placed inside a path bracket, the system generates a path for the TrueType text that includes each character plus its character box. The region generated is the character box minus the text, rather than the text itself. You can obtain the region enclosed by the outline of the TrueType text by setting the background mode to transparent before placing the TextOut function in the path bracket. Following is sample code that demonstrates this procedure.

    The below is a Delphi adaption of the mentioned sample code and your snippet, draws yellow outlined blue text:

    procedure TForm1.FormPaint(Sender: TObject);
    var
      elementCount: Integer;
      mPoints: array of TPoint;
      mTypes: array of Byte;
    const
      tStr = '15:00';
    begin
      BeginPath(Canvas.Handle);
      Canvas.Brush.Style := bsClear;
      TextOut(Canvas.Handle, 5, 5, PChar(tStr), Length(tStr));
      EndPath(Canvas.Handle);
    
      Canvas.Brush.Color := clBlue;
      Canvas.Pen.Color := clYellow;
      Canvas.Pen.Width := 4;
    
      elementCount := GetPath(Canvas.Handle, Pointer(nil)^, Pointer(nil)^, 0);
      if elementCount > 0 then begin
        SetLength(mPoints, elementCount);
        SetLength(mTypes, elementCount);
        GetPath(Canvas.Handle, mPoints[0], mTypes[0], elementCount);
    
        Canvas.Brush.Style := bsSolid;
        SelectClipPath(Canvas.Handle, RGN_AND);
        Canvas.FillRect(ClientRect);
    
        SelectClipRgn(Canvas.Handle, 0);
        PolyDraw(Canvas.Handle, mPoints[0], mTypes[0], elementCount);
      end else
        StrokeAndFillPath(Canvas.Handle);
    end;