Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
5600e7d
[padpainter] provide text drawing methods with TTF usage
linev Aug 21, 2026
85dd38e
[padpainter] move pad and wincontext to base class
linev Aug 21, 2026
cb94395
[virtualx] introduce DrawTTFglyphsW method
linev Aug 21, 2026
c804812
[tgx11] fix boundary check for text drawing
linev Aug 21, 2026
0bd93c3
[tgx11] implement DrawTTFglyphsW method
linev Aug 21, 2026
4cf2473
[win32] implement DrawTTFglyphsW
linev Aug 21, 2026
b38a629
[padpainter] Implement text drawing in TPadPainterBase
linev Aug 21, 2026
04d0716
[ttf] provide method to calculate align and rotation shifts
linev Aug 24, 2026
e6e8018
[padpainter] use TTFhandle::ApplyAlignRotate
linev Aug 24, 2026
b13c5b3
[tgx11] use TTFHandle::ApplyAlignRotate
linev Aug 24, 2026
aca3466
[tgx11] remove protected align enum from TGX11.h
linev Aug 24, 2026
4d0421e
[ttf] provide TTFhandle::GetGlyphData
linev Aug 24, 2026
cfa7327
[tgx11] use new TTFhandle::GetGlyphData method
linev Aug 24, 2026
e712621
[tgx11] avoid dierct use of Freetype includes
linev Aug 24, 2026
3e27844
[asimage] use new TTFhandle ApplyAlignRotate and GetGlyphData methods
linev Aug 24, 2026
f103eaa
[quartz] use new TTFhandle::GetGlyphData methods
linev Aug 25, 2026
67048f6
[win32] use new TTFhandle::GetGlyphData() method
linev Aug 25, 2026
0978acb
[ttf] split TTF and TTFhandle classes
linev Aug 25, 2026
5dab417
[ttf] make Smoothing none-static
linev Aug 25, 2026
c0e57e5
[ttf] better organize members and methods in TTFhandle class
linev Aug 25, 2026
b88e743
Use TTFhandle.h include in ROOT sources
linev Aug 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/base/inc/TVirtualX.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ R__EXTERN Atom_t gROOT_MESSAGE;
class TPoint;
class TString;
class TGWin32Command;
class TTFhandle;

class TVirtualX : public TNamed, public TAttLine, public TAttFill, public TAttText, public TAttMarker {

Expand Down Expand Up @@ -133,6 +134,7 @@ class TVirtualX : public TNamed, public TAttLine, public TAttFill, public TAttTe
virtual void DrawPolyMarkerW(WinContext_t wctxt, Int_t n, TPoint *xy);
virtual void DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Float_t mgn, const char *text, ETextMode mode);
virtual void DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Float_t mgn, const wchar_t *text, ETextMode mode);
virtual void DrawTTFglyphsW(WinContext_t wctxt, Int_t x, Int_t y, TTFhandle &handle, ETextMode mode);
virtual Int_t WriteGIFW(WinContext_t wctxt, const char *name);

virtual Bool_t GetTextExtentA(Font_t font, Double_t size, UInt_t &w, UInt_t &h, const char *mess);
Expand Down
9 changes: 9 additions & 0 deletions core/base/src/TVirtualX.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,15 @@ void TVirtualX::DrawTextW(WinContext_t /* wctxt */, Int_t x, Int_t y, Float_t an
DrawText(x, y, angle, mgn, text, mode);
}

////////////////////////////////////////////////////////////////////////////////
/// Draw TTFglyphs on specified window
/// Will be invoked only if HasTTFonts method returns true

void TVirtualX::DrawTTFglyphsW(WinContext_t /* wctxt */, Int_t /* x */, Int_t /* y */, TTFhandle &/* handle */, ETextMode /* mode */)
{
}


////////////////////////////////////////////////////////////////////////////////
/// Save specified window as GIF image

Expand Down
1 change: 0 additions & 1 deletion graf2d/asimage/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ ROOT_STANDARD_LIBRARY_PACKAGE(ASImage
-writeEmptyRootPCM
LIBRARIES
libAfterImage
Freetype::Freetype
DEPENDENCIES
Core
Graf
Expand Down
3 changes: 2 additions & 1 deletion graf2d/asimage/inc/TASImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ struct ASImage;
struct ASVisual;
class TBrowser;
class THashTable;
class TTFhandle;

class TASImage : public TImage {

Expand All @@ -47,7 +48,7 @@ class TASImage : public TImage {
inline Int_t Idx(Int_t idx);
void FillRectangleInternal(UInt_t col, Int_t x, Int_t y, UInt_t width, UInt_t height);
void DrawTextTTF(Int_t x, Int_t y, const char *text, Int_t size, UInt_t color, const char *font_name, Float_t angle);
void DrawFTGlyph(void *bitmap, UInt_t color, Int_t x, Int_t y, TVirtualPad *clippad = nullptr, Int_t offx = 0, Int_t offy = 0);
void DrawFTGlyphs(TTFhandle &ttf, UInt_t color, Int_t x, Int_t y, TVirtualPad *clippad = nullptr, Int_t offx = 0, Int_t offy = 0);
void SetDefaults();
void CreateThumbnail();
void DestroyImage();
Expand Down
263 changes: 90 additions & 173 deletions graf2d/asimage/src/TASImage.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,6 @@ Several examples showing how to use this class are available in the
ROOT tutorials: `$ROOTSYS/tutorials/visualisation/image/`
*/

#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H

#include "RConfigure.h"
#include "TArrayD.h"
#include "TArrayL.h"
Expand All @@ -82,7 +78,7 @@ ROOT tutorials: `$ROOTSYS/tutorials/visualisation/image/`
#include "TStyle.h"
#include "TSystem.h"
#include "TText.h"
#include "TTF.h"
#include "TTFhandle.h"
#include "TVectorD.h"
#include "TVirtualPad.h"
#include "TVirtualPadPainter.h"
Expand Down Expand Up @@ -5604,56 +5600,10 @@ void TASImage::DrawWideLine(UInt_t x1, UInt_t y1, UInt_t x2, UInt_t y2,
}

////////////////////////////////////////////////////////////////////////////////
/// Draw glyph bitmap.
/// Draw TTF glyphs .

void TASImage::DrawFTGlyph(void *bitmap, UInt_t color, Int_t bx, Int_t by, TVirtualPad *clippad, Int_t offx, Int_t offy)
void TASImage::DrawFTGlyphs(TTFhandle &ttf, UInt_t color, Int_t px, Int_t py, TVirtualPad *clippad, Int_t offx, Int_t offy)
{
UInt_t col[5];
Bool_t has_alpha = (color & 0xff000000) != 0xff000000;

FT_Bitmap *source = (FT_Bitmap *) bitmap;

auto ndots = source->width * source->rows;
ULong_t r = 0, g = 0, b = 0;

const Int_t y0 = by > 0 ? by * fImage->width : 0;
Int_t yy = y0;
for (UInt_t y = 0; y < source->rows; y++) {
Int_t byy = by + y;
if ((byy >= (Int_t) fImage->height) || (byy < 0)) continue;

for (UInt_t x = 0; x < source->width; x++) {
Int_t bxx = bx + x;
if ((bxx >= (Int_t) fImage->width) || (bxx < 0)) continue;

auto idx = Idx(bxx + yy);
r += ((fImage->alt.argb32[idx] & 0xff0000) >> 16);
g += ((fImage->alt.argb32[idx] & 0x00ff00) >> 8);
b += (fImage->alt.argb32[idx] & 0x0000ff);
}
yy += fImage->width;
}
if (ndots > 0) {
r /= ndots;
g /= ndots;
b /= ndots;
}

col[0] = (r << 16) + (g << 8) + b;
col[4] = color;
Int_t col4r = (col[4] & 0xff0000) >> 16;
Int_t col4g = (col[4] & 0x00ff00) >> 8;
Int_t col4b = (col[4] & 0x0000ff);

// interpolate between fore and background colors
for (Int_t x = 3; x > 0; x--) {
Int_t xx = 4 - x;
Int_t colxr = (col4r*x + r*xx) >> 2;
Int_t colxg = (col4g*x + g*xx) >> 2;
Int_t colxb = (col4b*x + b*xx) >> 2;
col[x] = (colxr << 16) + (colxg << 8) + colxb;
}

Int_t clipx1 = 0, clipx2 = 0, clipy1 = 0, clipy2 = 0;
Bool_t noClip = kTRUE;

Expand All @@ -5666,33 +5616,95 @@ void TASImage::DrawFTGlyph(void *bitmap, UInt_t color, Int_t bx, Int_t by, TVirt
noClip = kFALSE;
}

yy = y0;
UChar_t *s = source->buffer;
UInt_t col[5];
Bool_t has_alpha = (color & 0xff000000) != 0xff000000;

ttf.SetSmoothing(kTRUE);

for (UInt_t y = 0; y < source->rows; y++) {
Int_t byy = by + y;
for (UInt_t nglyph = 0; nglyph < ttf.GetNumGlyphs(); nglyph++) {
Int_t bx = 0, by = 0;
UChar_t *buffer = nullptr;
UInt_t width = 0, rows = 0, pitch = 0;
if (!ttf.GetGlyphData(nglyph, bx, by, buffer, width, rows, pitch))
continue;

for (UInt_t x = 0; x < source->width; x++) {
Int_t bxx = bx + x;
bx += px;
by += py;

UChar_t d = *s++ & 0xff;
d = ((d + 10) * 5) >> 8;
if (d > 4) d = 4;
auto ndots = width * rows;
ULong_t r = 0, g = 0, b = 0;

if (d > 0) {
if (noClip || ((bxx < clipx2) && (bxx >= clipx1) &&
(byy >= clipy2) && (byy < clipy1))) {
auto idx = Idx(bxx + yy);
auto acolor = (ARGB32) col[d];
if (has_alpha) {
_alphaBlend(&fImage->alt.argb32[idx], &acolor);
} else {
fImage->alt.argb32[idx] = acolor;
const Int_t y0 = by > 0 ? by * fImage->width : 0;
Int_t yy = y0;
for (UInt_t y = 0; y < rows; y++) {
Int_t byy = by + y;
if ((byy >= (Int_t) fImage->height) || (byy < 0)) continue;

for (UInt_t x = 0; x < width; x++) {
Int_t bxx = bx + x;
if ((bxx >= (Int_t) fImage->width) || (bxx < 0)) continue;

auto idx = Idx(bxx + yy);
r += ((fImage->alt.argb32[idx] & 0xff0000) >> 16);
g += ((fImage->alt.argb32[idx] & 0x00ff00) >> 8);
b += (fImage->alt.argb32[idx] & 0x0000ff);
}
yy += fImage->width;
}
if (ndots > 0) {
r /= ndots;
g /= ndots;
b /= ndots;
}

col[0] = (r << 16) + (g << 8) + b;
col[4] = color;
Int_t col4r = (col[4] & 0xff0000) >> 16;
Int_t col4g = (col[4] & 0x00ff00) >> 8;
Int_t col4b = (col[4] & 0x0000ff);

// interpolate between fore and background colors
for (Int_t x = 3; x > 0; x--) {
Int_t xx = 4 - x;
Int_t colxr = (col4r*x + r*xx) >> 2;
Int_t colxg = (col4g*x + g*xx) >> 2;
Int_t colxb = (col4b*x + b*xx) >> 2;
col[x] = (colxr << 16) + (colxg << 8) + colxb;
}

yy = y0;

for (UInt_t y = 0; y < rows; y++) {
Int_t byy = by + y;

UChar_t *s = buffer;

for (UInt_t x = 0; x < width; x++) {
Int_t bxx = bx + x;

UChar_t d = *s++ & 0xff;
d = ((d + 10) * 5) >> 8;
if (d > 4) d = 4;

if (d > 0) {
if (noClip || ((bxx < clipx2) && (bxx >= clipx1) &&
(byy >= clipy2) && (byy < clipy1))) {
auto idx = Idx(bxx + yy);
auto acolor = (ARGB32) col[d];
if (has_alpha) {
_alphaBlend(&fImage->alt.argb32[idx], &acolor);
} else {
fImage->alt.argb32[idx] = acolor;
}
}
}
}

// ttf has own alignment for rows
buffer += pitch;

yy += fImage->width;
}
yy += fImage->width;
}
}

Expand All @@ -5705,27 +5717,20 @@ void TASImage::DrawText(TText *text, Int_t x, Int_t y)
DrawTextOnPad(text, x, y, gPad, 0, 0);
}


////////////////////////////////////////////////////////////////////////////////
/// Draw text at the pixel position (x,y) checking clip on pad.

void TASImage::DrawTextOnPad(TText *text, Int_t x, Int_t y, TVirtualPad *pad, Int_t offx, Int_t offy)
{
if (!text || !InitImage("DrawTextOnPad"))
if (!text || !pad || !InitImage("DrawTextOnPad"))
return;

TTFhandle ttf;

// set text font
ttf.SetTextFont(text->GetTextFont());

UInt_t padw = pad ? pad->GetPadWidth() : 100;
UInt_t padh = pad ? pad->GetPadHeight() : 100;

// set text size
Float_t ttfsize = text->GetTextSize() * TMath::Min(padw, padh);
ttf.SetTextSize(ttfsize*kScale);

ttf.SetTextSize(text->GetTextSizePixels(*pad)*kScale);
// set text angle
ttf.SetRotationMatrix(text->GetTextAngle());

Expand All @@ -5747,86 +5752,8 @@ void TASImage::DrawTextOnPad(TText *text, Int_t x, Int_t y, TVirtualPad *pad, In
ARGB32 color = ARGB32_White;
parse_argb_color(col->AsHexString(), &color);

// Align()
Int_t align = 0;
Int_t txalh = text->GetTextAlign()/10;
Int_t txalv = text->GetTextAlign()%10;

switch (txalh) {
case 0 :
case 1 :
switch (txalv) { //left
case 1 :
align = 7; //bottom
break;
case 2 :
align = 4; //center
break;
case 3 :
align = 1; //top
break;
}
break;
case 2 :
switch (txalv) { //center
case 1 :
align = 8; //bottom
break;
case 2 :
align = 5; //center
break;
case 3 :
align = 2; //top
break;
}
break;
case 3 :
switch (txalv) { //right
case 1 :
align = 9; //bottom
break;
case 2 :
align = 6; //center
break;
case 3 :
align = 3; //top
break;
}
break;
}

FT_Vector ftal;

// vertical alignment
if (align == 1 || align == 2 || align == 3) {
ftal.y = ttf.GetAscent();
} else if (align == 4 || align == 5 || align == 6) {
ftal.y = ttf.GetAscent() / 2;
} else {
ftal.y = 0;
}

// horizontal alignment
if (align == 3 || align == 6 || align == 9) {
ftal.x = ttf.GetWidth();
} else if (align == 2 || align == 5 || align == 8) {
ftal.x = ttf.GetWidth() / 2;
} else {
ftal.x = 0;
}

FT_Vector_Transform(&ftal, ttf.GetRotMatrix());
ftal.x = (ftal.x >> 6);
ftal.y = (ftal.y >> 6);

for (UInt_t n = 0; n < ttf.GetNumGlyphs(); n++) {
if (auto bitmap = ttf.GetGlyphBitmap(n, kTRUE)) {
Int_t bx = x - ftal.x + bitmap->left;
Int_t by = y + ftal.y - bitmap->top;

DrawFTGlyph(&bitmap->bitmap, color, bx, by, pad, offx, offy);
}
}
if (ttf.ApplyAlignRotate(x, y, text->GetTextAlign(), GetWidth(), GetHeight()))
DrawFTGlyphs(ttf, color, x, y, pad, offx, offy);
}

////////////////////////////////////////////////////////////////////////////////
Expand All @@ -5846,18 +5773,8 @@ void TASImage::DrawTextTTF(Int_t x, Int_t y, const char *text, Int_t size,
ttf.PrepareString(text);
ttf.LayoutGlyphs();

// compute the size and position that will contain the text
// Int_t Xoff = TMath::Max(0, (Int_t) -ttf.GetBox().xMin);
Int_t Yoff = TMath::Max(0, (Int_t) -ttf.GetBox().yMin);
Int_t h = ttf.GetBox().yMax + Yoff;

for (UInt_t n = 0; n < ttf.GetNumGlyphs(); n++) {
if (auto bitmap = ttf.GetGlyphBitmap(n, kTRUE)) {
Int_t bx = x + bitmap->left;
Int_t by = y + h - bitmap->top;
DrawFTGlyph(&bitmap->bitmap, color, bx, by);
}
}
if (ttf.ApplyAlignRotate(x, y, 11, GetWidth(), GetHeight()))
DrawFTGlyphs(ttf, color, x, y);
}

////////////////////////////////////////////////////////////////////////////////
Expand Down
Loading
Loading