I am trying to create a textTool for my image editing app, so I have a button on the main form saying "Text tool". When I click it, a new form (modal) shows allowing me to select a font and enter a text in a RichEdit.
My idea is to have the user format his text in the RichEdit, and when he is satisfied, he should click on the modal button and the text (formatted) will be inserted in a new layer in my image. Also my idea is to treat the text as lines of text and render them separatelly in the new Bitmap32 and then assign the obtained bitmap to the new Layer.
For that I use this function
function GetTextWidth(const Text: string; const Font: TFont): Integer;
var
Canvas: TCanvas;
begin
Canvas := TCanvas.Create;
try
Canvas.Handle := GetDC(0);
try
Canvas.Font.Assign(Font);
Result := Canvas.TextWidth(Text);
finally
ReleaseDC(0, Canvas.Handle);
end;
finally
Canvas.Free;
end;
end;
and parse the lines of richedit and get the textWidth for each one like this:
for q := 0 to TextEditor.RichEdit1.Lines.Count-1 do
begin
latime:=GetTextWidth(TextEditor.RichEdit1.Lines[q], TextEditor.RichEdit1.Font);
Memo1.Lines.Add('Text row '+IntToStr(q)+' width='+IntToStr(latime));
end;
So I will easily obtain the largest width line (maxwidth), that I intend to use for generating my Bitmap32.
So for my Bitmap32 I use the following code (which does not show anything unfortunatelly)
// generating the Bitmap32 to place text on it
tmp := TBitmap32.Create;
tmp.SetSize(maxwidth, textLineHeight*TextLineCount);
for q := 0 to textLineCount-1 do
begin
tmp.RenderText(maxwidth,textLineHeight,TextEditor.RichEdit1.Lines[q],1,myFont.Color);
Memo1.Lines.Add('rendering line of text:'+TextEditor.RichEdit1.Lines[q]);
end;
// Generating the text layer
B := TBitmapLayer.Create(ImgView.Layers);
// Assigning the 'written' bitmap to the new layer
B.Bitmap.Assign(tmp);
B.Bitmap.DrawMode:=dmBlend;
// Positioning
with ImgView.GetViewportRect do
P := ImgView.ControlToBitmap(GR32.Point((Right + Left) div 2, (Top + Bottom) div 2));
// Sizing the layer
B.Location:=GR32.FloatRect(P.X - maxwidth, P.Y - textLineHeight, P.X + maxwidth, P.Y + textLineHeight);
// displaying the new text layer
imgView.Invalidate;
So I get no errors, but the new layer does not show... It's like nothing happens.
I tryied using fixed values for width and height (I used 200 bor both) but still nothing showed up on my ImageView, so I assume it must be something wrong with the Location maybe?
Please assist me in solving this problem.
Thank you very much
First of all, any advanced formats (in form of the extended features the RichEdit offers) are not supported by the RenderText function. It just outputs a string (as it is) with the properties of the bitmap's font property to a certain position (in your case to position maxwidth / textLineHeight).
In order to circle the problem I would start with a simpler code. Something like:
B := TBitmapLayer.Create(ImgView.Layers);
B.Location := FloatRect(0, 0, 100, 100);
B.Bitmap.SetSize(100, 100);
B.Bitmap.RenderText(0, 0, 'Test', 1, clBlack32);
B.Bitmap.DrawMode := dmBlend;
Note here that clBlack32 is used as color and not clBlack as the latter does not contain information about transparency. It might be that the color you are using (in myFont.Color) is of type TColor (and not of type TColor32). In case it is a TColor such as clBlack, it will have an alpha value of 0 which equals to fully transparent.
This code should draw the text 'Test' to the upper left position. If you don't see text you can add something like
B.Bitmap.Clear(clRed32);
after the SetSize call. With this the layer's bitmap background color will be set to red. Thus you should be able to spot the bounds of the layer more easily.
Once the text shows up on the screen you can move further by showing more than one line of text, by adjusting the x / y position etc. until your code looks like the code you posted above.
Some remarks:
By sizing the layer to something different than the bitmap dimensions the text will be stretched. This might look odd and the text might render unreadable. Eventually you might rather want to refresh the text on the bitmap after resizing the layer.
The function RenderText(...) produces a smoother output if the AALevel (oversampling factor) is higher. However, the function call will also be slower the higher the value is. The scale is more or quadratic, which means if you double the value the call will be at least 4 times slower. In practice it's even slower once your processor's cache is exceeded. You will face a major performance drop in that case.
In addition, the text width will get in accurate. It can be off by (2^AALevel * Length(string)) pixels in a worst case scenario!
Eventually it might be better to use the text rendering capabilities of the new vector engine in v2.0. While the steps are not as straight forward as with the rather simple RenderText(...) call, the output looks more pleasant to the eye and it's much faster compared to a high AALevel output. Also the TextWidth can be determined in a perfectly accurate way.