diff --git a/core/base/inc/TVirtualPadPainter.h b/core/base/inc/TVirtualPadPainter.h index a3cebc2efdd73..5d01110bb0e8c 100644 --- a/core/base/inc/TVirtualPadPainter.h +++ b/core/base/inc/TVirtualPadPainter.h @@ -109,8 +109,8 @@ class TVirtualPadPainter { //TASImage support. - virtual void DrawPixels(const unsigned char *pixelData, UInt_t width, UInt_t height, - Int_t dstX, Int_t dstY, Bool_t enableAlphaBlending) = 0; + virtual void R__DEPRECATED(7,00, "Use DrawImage instead") DrawPixels(const unsigned char * /* pixelData */, UInt_t /* width */, UInt_t /* height */, + Int_t /* dstX */, Int_t /* dstY */, Bool_t /* enableAlphaBlending */) {} // //These functions are not required by X11/GDI. virtual void InitPainter(); diff --git a/etc/plugins/TVirtualPadPainter/P020_TPadPainter.C b/etc/plugins/TVirtualPadPainter/P020_TPadPainter.C new file mode 100644 index 0000000000000..9e8e2ba4ee369 --- /dev/null +++ b/etc/plugins/TVirtualPadPainter/P020_TPadPainter.C @@ -0,0 +1,5 @@ +void P020_TPadPainter() +{ + gPluginMgr->AddHandler("TVirtualPadPainter", "native", "TPadPainter", + "ROOTPadPainter", "TPadPainter()"); +} diff --git a/graf2d/CMakeLists.txt b/graf2d/CMakeLists.txt index 3fcb56483a917..8d993e59f9682 100644 --- a/graf2d/CMakeLists.txt +++ b/graf2d/CMakeLists.txt @@ -20,6 +20,7 @@ endif() if(asimage) add_subdirectory(asimage) # special CMakeLists.txt endif() +add_subdirectory(padpainter) if(gviz) add_subdirectory(gviz) endif() diff --git a/graf2d/asimage/CMakeLists.txt b/graf2d/asimage/CMakeLists.txt index 48a3143979bee..6ef9aa0e6007e 100644 --- a/graf2d/asimage/CMakeLists.txt +++ b/graf2d/asimage/CMakeLists.txt @@ -34,6 +34,23 @@ if (x11) target_link_libraries(ASImage PRIVATE X11::X11) endif() +ROOT_STANDARD_LIBRARY_PACKAGE(ASImageUtils + NO_INSTALL_HEADERS + HEADERS + TASUtils.h + SOURCES + TASUtils.cxx + LINKDEF + LinkDefUtils.h + DICTIONARY_OPTIONS + -writeEmptyRootPCM + LIBRARIES + libAfterImage + DEPENDENCIES + ASImage + Gpad +) + ROOT_STANDARD_LIBRARY_PACKAGE(ASImageGui NO_INSTALL_HEADERS HEADERS diff --git a/graf2d/asimage/inc/LinkDefUtils.h b/graf2d/asimage/inc/LinkDefUtils.h new file mode 100644 index 0000000000000..0abd290f2d1e3 --- /dev/null +++ b/graf2d/asimage/inc/LinkDefUtils.h @@ -0,0 +1,19 @@ +/* @(#)root/asimage:$Id$ */ + +/************************************************************************* + * Copyright (C) 1995-2026, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms seeg $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class TASUtils; + +#endif diff --git a/graf2d/asimage/inc/TASImage.h b/graf2d/asimage/inc/TASImage.h index 3fad702ba1f0f..405d1f8f8ffd0 100644 --- a/graf2d/asimage/inc/TASImage.h +++ b/graf2d/asimage/inc/TASImage.h @@ -28,9 +28,14 @@ struct ASVisual; class TBrowser; class THashTable; class TTFhandle; +class TASPaletteEditor; +class TASUtils; class TASImage : public TImage { +friend class TASPaletteEditor; // to access FromGradient method +friend class TASUtils; // to implement gVirtualX-specific methods + private: enum { kNoZoom = 0, kZoom = 1, kZoomOps = -1 }; enum { kReadWritePNG, kReadWriteVector }; @@ -72,6 +77,7 @@ class TASImage : public TImage { static THashTable *fgPlugList; ///dpy was set to nullptr @@ -79,9 +85,11 @@ class TASImage : public TImage { void MapFileTypes(EImageFileTypes &type, UInt_t &astype, Bool_t toas = kTRUE); void MapQuality(EImageQuality &quality, UInt_t &asquality, Bool_t toas = kTRUE); - static Bool_t InitVisual(); + static ASVisual *InitVisual(Bool_t plain = kFALSE); Bool_t InitImage(const char *caller); + void FromGradient(struct ASGradient *as_gradient, UInt_t width, UInt_t height); + public: TASImage(); TASImage(UInt_t w, UInt_t h); @@ -104,7 +112,6 @@ class TASImage : public TImage { void FromBitmap(const UChar_t *buf, UInt_t width, UInt_t height) override; void FromPad(TVirtualPad *pad, Int_t x = 0, Int_t y = 0, UInt_t w = 0, UInt_t h = 0) override; - void FromX11Window(Window_t win , Int_t x, Int_t y, Int_t width, Int_t height) override; void FromWindow(Drawable_t wid, Int_t x = 0, Int_t y = 0, UInt_t w = 0, UInt_t h = 0) override; void FromGLBuffer(UChar_t *buf, UInt_t width, UInt_t height) override; @@ -193,7 +200,6 @@ class TASImage : public TImage { ASImage *GetImage() const { return fImage; } void SetImage(ASImage *image) { DestroyImage(); fImage = image; } TImage *GetScaledImage() const override { return fScaledImage; } - Pixmap_t GetX11Pixmap(Window_t root_window) override; Pixmap_t GetPixmap() override; Bool_t GetMaskBits(UInt_t &width, UInt_t &height, std::vector &bits) override; Pixmap_t GetMask() override; diff --git a/graf2d/asimage/inc/TASUtils.h b/graf2d/asimage/inc/TASUtils.h new file mode 100644 index 0000000000000..90dbf6fb2bc57 --- /dev/null +++ b/graf2d/asimage/inc/TASUtils.h @@ -0,0 +1,41 @@ +// @(#)root/asimage:$Id$ +// Author: Sergey Linev 16/10/2026 + +/************************************************************************* + * Copyright (C) 1995-2026, Rene Brun and Fons Rademakers * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT_TASUtils +#define ROOT_TASUtils + +////////////////////////////////////////////////////////////////////////// +// // +// TASUtils // +// // +// Extra functions for TASImage requiring gVirtualX and X11 usage // +// // +////////////////////////////////////////////////////////////////////////// + +#include "Rtypes.h" +#include "GuiTypes.h" +#include + +class TImage; + +class TASUtils { +public: + static Pixmap_t GetPixmap(TImage *timg); + static Pixmap_t GetMask(TImage *timg); + + static Bool_t PaintImage(TImage *timg, Drawable_t wid, Int_t x, Int_t y, Bool_t opaque = kFALSE); + static Bool_t FillImageFromWindow(TImage *img, Window_t wid, Int_t width, Int_t height); + + static std::unique_ptr FromWindow(Window_t wid); + static std::unique_ptr FromPixmap(Pixmap_t pxm, Pixmap_t mask); +}; + +#endif diff --git a/graf2d/asimage/src/TASImage.cxx b/graf2d/asimage/src/TASImage.cxx index fd12225042217..25f6eae466271 100644 --- a/graf2d/asimage/src/TASImage.cxx +++ b/graf2d/asimage/src/TASImage.cxx @@ -117,6 +117,7 @@ extern "C" { ASVisual *TASImage::fgVisual = nullptr; +ASVisual *TASImage::fgBatchVisual = nullptr; Bool_t TASImage::fgInit = kFALSE; Bool_t TASImage::fgBatch = kFALSE; @@ -1075,23 +1076,6 @@ void TASImage::SetImage(const TVectorD &imageData, UInt_t width, TImagePalette * imageData.GetNoElements() / width, palette); } -//////////////////////////////////////////////////////////////////////////////// -/// Create an image from the given X11 window -/// Can only be used on platforms where X11 is supported - -void TASImage::FromX11Window(Window_t win, Int_t x, Int_t y, Int_t width, Int_t height) -{ - DestroyImage(); - DestroyScaledImage(); - - if (!InitVisual()) { - Warning("FromX11Window", "Visual not initiated"); - return; - } - - fImage = pixmap2asimage(fgVisual, win, x, y, width, height, kAllPlanes, 0, 0); -} - //////////////////////////////////////////////////////////////////////////////// /// Create an image from the given pad, afterwards this image can be /// saved in any of the supported image formats. @@ -2001,7 +1985,8 @@ void TASImage::Mirror(Bool_t vert) return; } - if (!InitVisual()) { + auto vis = InitVisual(true); + if (!vis) { Warning("Mirror", "Visual not initiated"); return; } @@ -2011,7 +1996,7 @@ void TASImage::Mirror(Bool_t vert) return; } - ASImage *img = mirror_asimage(fgVisual, fImage, 0, 0, + ASImage *img = mirror_asimage(vis, fImage, 0, 0, fImage->width, fImage->height, vert, ASA_ASImage, GetImageCompression(), GetImageQuality()); @@ -2069,14 +2054,19 @@ void TASImage::GetZoomPosition(UInt_t &x, UInt_t &y, UInt_t &w, UInt_t &h) const } //////////////////////////////////////////////////////////////////////////////// -/// Static function to initialize the ASVisual. +/// Static internal method to initialize the ASVisual +/// Many operations do not require X11 display so plain "batch" visual can be used -Bool_t TASImage::InitVisual() +ASVisual *TASImage::InitVisual(Bool_t plain) { - Bool_t noX = gROOT->IsBatch() || !gVirtualX->InheritsFrom("TGX11"); + // this is new API, means return value must be used + if (fgBatchVisual && plain) + return fgBatchVisual; - if (fgVisual && (noX == fgBatch)) - return kTRUE; + Bool_t noX = plain || gROOT->IsBatch() || !gVirtualX->InheritsFrom("TGX11"); + + if (fgVisual && !noX && !fgBatch) + return fgVisual; fgVisual = nullptr; fgBatch = false; @@ -2100,20 +2090,17 @@ Bool_t TASImage::InitVisual() #endif #endif - static ASVisual *vis_batch = nullptr; - if (!fgVisual) { - if (!vis_batch) { + if (!fgBatchVisual) { // create dummy visual for batch mode - vis_batch = create_asvisual(nullptr, 0, 0, nullptr); - vis_batch->dpy = nullptr; // fake (not used) + fgBatchVisual = create_asvisual(nullptr, 0, 0, nullptr); + fgBatchVisual->dpy = nullptr; // fake (not used) } - - fgVisual = vis_batch; + fgVisual = fgBatchVisual; fgBatch = true; } - return kTRUE; + return fgVisual; } //////////////////////////////////////////////////////////////////////////////// @@ -2161,33 +2148,24 @@ void TASImage::StartPaletteEditor() //////////////////////////////////////////////////////////////////////////////// -/// Returns image X11 pixmap. -/// Workrs only on the platforms with support of X11 +/// DEPRECATED. Method left for backward compatibility and will be removed in ROOT7! +/// Returns image pixmap. /// The pixmap must deleted by user. -Pixmap_t TASImage::GetX11Pixmap(Window_t root_window) +Pixmap_t TASImage::GetPixmap() { if (!InitVisual()) { - Warning("GetX11Pixmap", "Visual not initiated"); + Warning("GetPixmap", "Visual not initiated"); return 0; } - ASImage *img = fScaledImage ? fScaledImage->fImage : fImage; - - return (Pixmap_t)asimage2pixmap(fgVisual, root_window, img, nullptr, kTRUE); -} - -//////////////////////////////////////////////////////////////////////////////// -/// DEPRECATED. Method left for backward compatibility and will be removed in ROOT7! -/// Returns image pixmap. -/// The pixmap must deleted by user. - -Pixmap_t TASImage::GetPixmap() -{ static Bool_t x11 = gVirtualX->InheritsFrom("TGX11"); - if (x11) - return GetX11Pixmap(gVirtualX->GetDefaultRootWindow()); + if (x11) { + ASImage *img = fScaledImage ? fScaledImage->fImage : fImage; + + return (Pixmap_t)asimage2pixmap(fgVisual, gVirtualX->GetDefaultRootWindow(), img, nullptr, kTRUE); + } auto argb = GetArgbArray(); if (!argb) { @@ -2269,6 +2247,7 @@ Pixmap_t TASImage::GetMask() } //////////////////////////////////////////////////////////////////////////////// +/// DEPRECATED. Method left for backward compatibility and will be removed in ROOT7! /// Create image from pixmap. void TASImage::SetImage(Pixmap_t pxm, Pixmap_t mask) @@ -2285,10 +2264,10 @@ void TASImage::SetImage(Pixmap_t pxm, Pixmap_t mask) UInt_t w, h; gVirtualX->GetWindowSize(pxm, xy, xy, w, h); - if (fName.IsNull()) fName.Form("img_%dx%d",w, h); + if (fName.IsNull()) + fName.Form("img_%dx%d",w, h); - static int x11 = -1; - if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11"); + static Bool_t x11 = gVirtualX->InheritsFrom("TGX11"); if (x11) { //use built-in optimized version fImage = picture2asimage(fgVisual, pxm, mask, 0, 0, w, h, kAllPlanes, 1, 0); @@ -3333,13 +3312,19 @@ void TASImage::Crop(Int_t x, Int_t y, UInt_t width, UInt_t height) x = x < 0 ? 0 : x; y = y < 0 ? 0 : y; + if ((x >= (Int_t) fImage->width) || (y >= (Int_t) fImage->height)) { + Warning("Crop", "specified x/y position larger than image"); + return; + } + width = x + width > fImage->width ? fImage->width - x : width; height = y + height > fImage->height ? fImage->height - y : height; if ((width == fImage->width) && (height == fImage->height)) { - Warning("Crop", "input size larger than image"); + Warning("Crop", "specified size larger than image"); return; } + ASImageDecoder *imdec = start_image_decoding(fgVisual, fImage, SCL_DO_ALL, x, y, width, height, nullptr); @@ -3351,7 +3336,7 @@ void TASImage::Crop(Int_t x, Int_t y, UInt_t width, UInt_t height) ASImage *img = create_asimage(width, height, 0); if (!img) { - delete [] imdec; + stop_image_decoding(&imdec); Warning("Crop", "Failed to create image"); return; } @@ -3362,7 +3347,7 @@ void TASImage::Crop(Int_t x, Int_t y, UInt_t width, UInt_t height) if (!imout) { Warning("Crop", "Failed to start image output"); destroy_asimage(&img); - if (imdec) delete [] imdec; + stop_image_decoding(&imdec); return; } @@ -3570,23 +3555,23 @@ UInt_t *TASImage::GetRgbaArray() UInt_t *TASImage::GetScanline(UInt_t y) { - if (!fImage) { + ASImage *img = fScaledImage ? fScaledImage->fImage : fImage; + + if (!img) { Warning("GetScanline", "no image"); return nullptr; } - ASImage *img = fScaledImage ? fScaledImage->fImage : fImage; - CARD32 *ret = new CARD32[img->width]; - ASImageDecoder *imdec = start_image_decoding(fgVisual, img, SCL_DO_ALL, 0, y, img->width, 1, nullptr); if (!imdec) { - delete [] ret; Warning("GetScanline", "Failed to start image decoding"); return nullptr; } + CARD32 *ret = new CARD32[img->width]; + #ifdef HAVE_MMX mmx_init(); #endif @@ -6319,6 +6304,7 @@ void TASImage::Gray(Bool_t on) } //////////////////////////////////////////////////////////////////////////////// +/// DEPRECATED. Method left for backward compatibility and will be removed in ROOT7! /// Create an image (screenshot) from specified window. void TASImage::FromWindow(Drawable_t wid, Int_t x, Int_t y, UInt_t w, UInt_t h) @@ -6370,6 +6356,7 @@ void TASImage::FromWindow(Drawable_t wid, Int_t x, Int_t y, UInt_t w, UInt_t h) } //////////////////////////////////////////////////////////////////////////////// +/// DEPRECATED. Method left for backward compatibility and will be removed in ROOT7! /// Creates an image (screenshot) from a RGBA buffer provided by GL. void TASImage::FromGLBuffer(UChar_t* buf, UInt_t w, UInt_t h) @@ -6396,6 +6383,22 @@ void TASImage::FromBitmap(const UChar_t *buf, UInt_t width, UInt_t height) fImage = bitmap2asimage(const_cast(buf), width, height, 0, nullptr); } + +//////////////////////////////////////////////////////////////////////////////// +/// Creates an image from ASGradient + +void TASImage::FromGradient(ASGradient *as_gradient, UInt_t width, UInt_t height) +{ + DestroyImage(); + DestroyScaledImage(); + + if (!InitVisual()) + Warning("FromGradient", "Visual not initiated"); + else + fImage = make_gradient(fgVisual, as_gradient, width, height, SCL_DO_COLOR, ASA_ARGB32, 0, GetImageQuality()); +} + + //////////////////////////////////////////////////////////////////////////////// /// Switch on/off the image palette. /// That also invokes calling vectorization of image. diff --git a/graf2d/asimage/src/TASPaletteEditor.cxx b/graf2d/asimage/src/TASPaletteEditor.cxx index eaf2c23c7de89..97fd87f77f2d8 100644 --- a/graf2d/asimage/src/TASPaletteEditor.cxx +++ b/graf2d/asimage/src/TASPaletteEditor.cxx @@ -891,36 +891,30 @@ void TASPaletteEditor::UpdateRange() void TASPaletteEditor::PaintPalette::Paint(Option_t *) { - // get geometry of pad - Int_t to_w = TMath::Abs(gPad->XtoPixel(gPad->GetX2()) - - gPad->XtoPixel(gPad->GetX1())); - Int_t to_h = TMath::Abs(gPad->YtoPixel(gPad->GetY2()) - - gPad->YtoPixel(gPad->GetY1())); + auto &pal = **fPalette; ASGradient grad; + grad.npoints = pal.fNumPoints - 2; + std::vector color(grad.npoints); + std::vector offset(grad.npoints); - grad.npoints = (*fPalette)->fNumPoints - 2; - grad.type = GRADIENT_Left2Right; - grad.color = new ARGB32[grad.npoints]; - grad.offset = new double[grad.npoints]; for (Int_t pt = 0; pt < grad.npoints; pt++) { - grad.offset[pt] = ((*fPalette)->fPoints[pt + 1] - (*fPalette)->fPoints[1]) / - ((*fPalette)->fPoints[(*fPalette)->fNumPoints - 2] - (*fPalette)->fPoints[1]); - grad.color[pt] = (((ARGB32)((*fPalette)->fColorBlue[pt + 1] & 0xff00)) >> 8) | - (((ARGB32)((*fPalette)->fColorGreen[pt + 1] & 0xff00)) ) | - (((ARGB32)((*fPalette)->fColorRed[pt + 1] & 0xff00)) << 8) | - (((ARGB32)((*fPalette)->fColorAlpha[pt + 1] & 0xff00)) << 16); + offset[pt] = (pal.fPoints[pt + 1] - pal.fPoints[1]) / + (pal.fPoints[pal.fNumPoints - 2] - pal.fPoints[1]); + color[pt] = (((ARGB32)(pal.fColorBlue[pt + 1] & 0xff00)) >> 8) | + (((ARGB32)(pal.fColorGreen[pt + 1] & 0xff00)) ) | + (((ARGB32)(pal.fColorRed[pt + 1] & 0xff00)) << 8) | + (((ARGB32)(pal.fColorAlpha[pt + 1] & 0xff00)) << 16); } - ASImage * grad_im = make_gradient((ASVisual*)TASImage::GetVisual(), &grad , to_w, to_h, - SCL_DO_COLOR, ASA_ARGB32, 0, - fAttImage->GetImageQuality()); - delete [] grad.color; - delete [] grad.offset; + grad.color = color.data(); + grad.offset = offset.data(); + grad.type = GRADIENT_Left2Right; - Window_t wid = (Window_t)gVirtualX->GetWindowID(gPad->GetPixmapID()); - TASImage::Image2Drawable(grad_im, wid, 0, 0); - destroy_asimage(&grad_im); + TASImage img; + img.SetImageQuality(fAttImage->GetImageQuality()); + img.FromGradient(&grad, gPad->GetPadWidth(), gPad->GetPadHeight()); + img.Paint("x"); // x mean expand to full pad } //////////////////////////////////////////////////////////////////////////////// diff --git a/graf2d/asimage/src/TASUtils.cxx b/graf2d/asimage/src/TASUtils.cxx new file mode 100644 index 0000000000000..dd01c8d3a9e76 --- /dev/null +++ b/graf2d/asimage/src/TASUtils.cxx @@ -0,0 +1,343 @@ +// @(#)root/asimage:$Id$ +// Author: Sergey Linev 16/10/2026 + +/************************************************************************* + * Copyright (C) 1995-2026, Rene Brun and Fons Rademakers * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#include "TASUtils.h" +#include "RConfigure.h" +#include "TASImage.h" +#include "TVirtualX.h" +#include "TSystem.h" +#include "TVirtualPad.h" +#include "TError.h" + +#ifdef WIN32 +#define X_DISPLAY_MISSING 1 +#include "Windows4root.h" +#else +#ifdef R__HAS_COCOA +#define X_DISPLAY_MISSING 1 +#endif +#endif + +#include "afterbase.h" +#include "afterimage.h" +#include "bmp.h" + +#ifndef X_DISPLAY_MISSING +const unsigned long kAllPlanes = ~0; +#endif + +// Holder of ASVisual instance, destroyed when application closed +class ASVisualHolder { + ASVisual *fVisual = nullptr; + +public: + + GContext_t fGC = 0; // context used in PaintImage + + ASVisual *operator()() + { +#ifndef X_DISPLAY_MISSING + if (!fVisual) { + Display *disp = (Display*) gVirtualX->GetDisplay(); + Int_t screen = gVirtualX->GetScreen(); + Int_t depth = gVirtualX->GetDepth(); + Visual *vis = (Visual*) gVirtualX->GetVisual(); + Colormap cmap = (Colormap) gVirtualX->GetColormap(); + + if (vis && cmap) + fVisual = create_asvisual_for_id(disp, screen, depth, XVisualIDFromVisual(vis), cmap, nullptr); + } +#endif + if (!fVisual) { + fVisual = create_asvisual(nullptr, 0, 0, nullptr); + fVisual->dpy = nullptr; // fake (not used) + } + + return fVisual; + } + + ~ASVisualHolder() + { + if (fVisual) { + destroy_asvisual(fVisual, 0); + fVisual = nullptr; + } + if (fGC && gVirtualX) + gVirtualX->DeleteGC(fGC); + } +}; + +thread_local ASVisualHolder holder; + + +//////////////////////////////////////////////////////////////////////////////// +/// Returns image pixmap. +/// The pixmap must deleted by user. +/// Replacement for deprecated TImage::GetPixmap method +/// Special handling for X11-based displays where ASImage has optimized implementation + +Pixmap_t TASUtils::GetPixmap(TImage *timg) +{ + if (!timg) { + ::Error("TASUtils::GetPixmap", "Image not provided"); + return 0; + } + static Bool_t x11 = gVirtualX->InheritsFrom("TGX11"); + + if (x11) { +#ifndef X_DISPLAY_MISSING + auto asimg = dynamic_cast(timg); + if (!asimg) { + ::Warning("TASUtils::GetPixmap", "ASImage not provided"); + return 0; + } + + auto vis = holder(); + + if (!vis) { + ::Warning("TASUtils::GetPixmap", "Visual not initiated"); + return 0; + } + + ASImage *img = asimg->fScaledImage ? asimg->fScaledImage->fImage : asimg->fImage; + + return (Pixmap_t)asimage2pixmap(vis, gVirtualX->GetDefaultRootWindow(), img, nullptr, kTRUE); +#else + ::Error("TASUtils::GetPixmap", "Invoke X11-specific methods on unsupported platform"); + return 0; +#endif + } + + auto argb = timg->GetArgbArray(); + if (!argb) { + ::Error("TASUtils::GetPixmap", "ARGB array is not exists"); + return 0; + } + + return gVirtualX->CreatePixmapFromData((unsigned char*) argb, timg->GetScaledWidth(), timg->GetScaledHeight()); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Returns image mask pixmap (alpha channel). +/// The pixmap must deleted by user. +/// Replacement for deprecated TImage::GetMask() method + +Pixmap_t TASUtils::GetMask(TImage *img) +{ + Pixmap_t pixmap = 0; + + UInt_t width = 0, height = 0; + std::vector bits; + + if (!img) + ::Error("TGWindow::GetImageMask", "Image not provided"); + else if (img->GetMaskBits(width, height, bits)) + pixmap = gVirtualX->CreateBitmap(gVirtualX->GetDefaultRootWindow(), bits.data(), width, height); + + return pixmap; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Create an image from the given window + +Bool_t TASUtils::FillImageFromWindow(TImage *img, Window_t wid, Int_t width, Int_t height) +{ + auto asimg = dynamic_cast (img); + if (!asimg) + return kFALSE; + + asimg->DestroyImage(); + asimg->DestroyScaledImage(); + + gVirtualX->Update(1); + if (!gThreadXAR) { + gSystem->Sleep(10); + gSystem->ProcessEvents(); + gSystem->Sleep(10); + gSystem->ProcessEvents(); + } + + static Bool_t x11 = gVirtualX->InheritsFrom("TGX11"); + + if (x11) { + auto vis = holder(); + + if (!vis) { + ::Error("TASUtils::FillImageFromWindow", "Visual not initiated"); + return kFALSE; + } + +#ifndef X_DISPLAY_MISSING + asimg->fImage = pixmap2asimage(vis, wid, 0, 0, width, height, kAllPlanes, 0, 0); +#else + ::Error("TASUtils::FillImageFromWindow", "Invoke X11-specific methods on unsupported platform"); +#endif + } else { + unsigned char *bits = gVirtualX->GetColorBits(wid, 0, 0, width, height); + if (!bits) { + ::Error("TASUtils::FillImageFromWindow", "Fail to extract color bits for specified window"); + return kFALSE; + } + asimg->FromBitmap(bits, width, height); + delete [] bits; + } + + if (!asimg->IsValid()) + return kFALSE; + + return kTRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Create an image from the given window + +std::unique_ptr TASUtils::FromWindow(Window_t wid) +{ + Int_t x = 0, y = 0; + UInt_t w = 0, h = 0; + + gVirtualX->GetWindowSize(wid, x, y, w, h); + + (void) x; // position of window is not used + (void) y; + + auto asimg = std::make_unique(); + + if (!FillImageFromWindow(asimg.get(), wid, w, h)) + return nullptr; + + return asimg; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Create image from pixmap. + +std::unique_ptr TASUtils::FromPixmap(Pixmap_t pxm, Pixmap_t mask) +{ + auto asimg = std::make_unique(); + + Int_t xy; + UInt_t w, h; + gVirtualX->GetWindowSize(pxm, xy, xy, w, h); + + asimg->SetName(TString::Format("img_%dx%d",w, h)); + + if (gVirtualX->InheritsFrom("TGX11")) { //use built-in optimized version + auto vis = holder(); + + if (!vis) { + ::Warning("TASUtils::FromPixmap", "Visual not initiated"); + return nullptr; + } + +#ifndef X_DISPLAY_MISSING + asimg->fImage = picture2asimage(vis, pxm, mask, 0, 0, w, h, kAllPlanes, 1, 0); +#else + ::Error("TASUtils::FromPixmap", "Invoke X11-specific methods on unsupported platform"); +#endif + } else { + unsigned char *bits = gVirtualX->GetColorBits(pxm, 0, 0, w, h); + if (!bits) // error + return nullptr; + + unsigned char *mask_bits = mask ? gVirtualX->GetColorBits(mask, 0, 0, w, h) : nullptr; + + asimg->fImage = bitmap2asimage(bits, w, h, 0, mask_bits); + + if (mask_bits) + delete [] mask_bits; + delete [] bits; + } + + if (!asimg->IsValid()) + return nullptr; + + return asimg; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Paint image on specified window + +Bool_t TASUtils::PaintImage(TImage *timg, Drawable_t wid, Int_t x, Int_t y, Bool_t opaque) +{ + auto asimg = dynamic_cast(timg); + if (!asimg) { + ::Warning("TASUtils::PaintImage", "Image not provided"); + return kFALSE; + } + + Pixmap_t mask = kNone; + + Bool_t isX11 = gVirtualX->InheritsFrom("TGX11"); + + if (isX11) { + UInt_t mwidth = 0, mheight = 0; + std::vector bits; + if (asimg->GetMaskBits(mwidth, mheight, bits)) + mask = gVirtualX->CreateBitmap(gVirtualX->GetDefaultRootWindow(), bits.data(), mwidth, mheight); + } + + GCValues_t gv; + gv.fMask = kGCClipMask | kGCClipXOrigin | kGCClipYOrigin; + gv.fClipMask = mask; + gv.fClipXOrigin = x; + gv.fClipYOrigin = y; + + if (!holder.fGC) { + holder.fGC = gVirtualX->CreateGC(gVirtualX->GetDefaultRootWindow(), &gv); + } else { + gVirtualX->ChangeGC(holder.fGC, &gv); + } + + UInt_t width = asimg->GetScaledWidth(); + UInt_t height = asimg->GetScaledHeight(); + + Bool_t res = kTRUE; + + if (isX11) { //use built-in optimized version + #ifndef X_DISPLAY_MISSING + ASImage *im = asimg->fScaledImage ? asimg->fScaledImage->fImage : asimg->fImage; + auto vis = holder(); + if (vis && im) + asimage2drawable(vis, wid, im, (GC)holder.fGC, 0, 0, x, y, width, height, 1); + else + res = kFALSE; + #else + ::Error("TASUtils::PaintImage", "Invoke X11-specific methods on unsupported platform"); + res = kFALSE; + #endif + } else { + auto argb = asimg->GetArgbArray(); + + Pixmap_t pic = argb ? gVirtualX->CreatePixmapFromData((unsigned char *) argb, width, height) : 0; + + if (pic) { + if (!opaque) { + SETBIT(width, 31); + SETBIT(height, 31); + } + gVirtualX->CopyArea(pic, wid, holder.fGC, 0, 0, width, height, x, y); + gVirtualX->DeletePixmap(pic); + } else + res = kFALSE; + } + + // free mask pixmap + if (mask != kNone) + gVirtualX->DeletePixmap(mask); + + gv.fMask = kGCClipMask; + gv.fClipMask = kNone; + if (holder.fGC) + gVirtualX->ChangeGC(holder.fGC, &gv); + + return res; +} diff --git a/graf2d/gpad/CMakeLists.txt b/graf2d/gpad/CMakeLists.txt index 1a2e979e53138..96e3d868fe8da 100644 --- a/graf2d/gpad/CMakeLists.txt +++ b/graf2d/gpad/CMakeLists.txt @@ -25,7 +25,6 @@ ROOT_STANDARD_LIBRARY_PACKAGE(Gpad TInspectCanvas.h TPad.h TPadPainterBase.h - TPadPainter.h TPadPainterPS.h TPaveClass.h TRatioPlot.h @@ -48,7 +47,6 @@ ROOT_STANDARD_LIBRARY_PACKAGE(Gpad src/TInspectCanvas.cxx src/TPad.cxx src/TPadPainterBase.cxx - src/TPadPainter.cxx src/TPadPainterPS.cxx src/TPaveClass.cxx src/TRatioPlot.cxx diff --git a/graf2d/gpad/inc/LinkDef.h b/graf2d/gpad/inc/LinkDef.h index eeb1d68c513ff..956f3aed9f08e 100644 --- a/graf2d/gpad/inc/LinkDef.h +++ b/graf2d/gpad/inc/LinkDef.h @@ -32,7 +32,6 @@ #pragma link C++ class TView+; #pragma link C++ class TViewer3DPad; #pragma link C++ class TPadPainterBase; -#pragma link C++ class TPadPainter; #pragma link C++ class TPadPainterPS; #pragma link C++ class TRatioPlot+; diff --git a/graf2d/gpad/src/TCanvas.cxx b/graf2d/gpad/src/TCanvas.cxx index d046ecba0a8ff..f5ecc92314ec2 100644 --- a/graf2d/gpad/src/TCanvas.cxx +++ b/graf2d/gpad/src/TCanvas.cxx @@ -36,7 +36,6 @@ #include "TObjArray.h" #include "TVirtualPadEditor.h" #include "TVirtualViewer3D.h" -#include "TPadPainter.h" #include "TPadPainterPS.h" #include "TVirtualGL.h" #include "TVirtualPS.h" @@ -2659,18 +2658,21 @@ void TCanvas::CreatePainter() { //Even for batch mode painter is still required, just to delegate //some calls to batch "virtual X". - if (!UseGL() || fBatch || IsWeb()) { - fPainter = nullptr; - if (fCanvasImp) fPainter = fCanvasImp->CreatePadPainter(); - if (!fPainter) fPainter = new TPadPainter; // Do not need plugin manager for this! - } else { + + fPainter = nullptr; + if (UseGL() && !IsBatch() && !IsWeb()) { fPainter = TVirtualPadPainter::PadPainter("gl"); if (!fPainter) { Error("CreatePainter", "GL Painter creation failed! Will use default!"); - fPainter = new TPadPainter; fUseGL = kFALSE; } } + if (!fPainter && fCanvasImp) + fPainter = fCanvasImp->CreatePadPainter(); + if (!fPainter) + fPainter = TVirtualPadPainter::PadPainter("native"); + if (!fPainter) + Error("CreatePainter", "Fail to create any pad painter"); } //////////////////////////////////////////////////////////////////////////////// diff --git a/graf2d/graf/inc/TImage.h b/graf2d/graf/inc/TImage.h index 59b2af21a8553..4bab2fd8fa545 100644 --- a/graf2d/graf/inc/TImage.h +++ b/graf2d/graf/inc/TImage.h @@ -120,7 +120,7 @@ friend TImage operator/(const TImage &i1, const TImage &s2); virtual void SetImage(const Double_t * /*imageData*/, UInt_t /*width*/, UInt_t /*height*/, TImagePalette * /*palette*/ = nullptr) {} virtual void SetImage(const TArrayD & /*imageData*/, UInt_t /*width*/, TImagePalette * /*palette*/ = nullptr) {} virtual void SetImage(const TVectorD & /*imageData*/, UInt_t /*width*/, TImagePalette * /*palette*/ = nullptr) {} - virtual void SetImage(Pixmap_t /*pxm*/, Pixmap_t /*mask*/ = 0) {} + virtual void R__DEPRECATED(7,00, "Use TASUtils::FromPixmap instead") SetImage(Pixmap_t /*pxm*/, Pixmap_t /*mask*/ = 0) {} // Create an image from bitmap. (See TASImage::FromBitmap) @@ -129,11 +129,8 @@ friend TImage operator/(const TImage &i1, const TImage &s2); // Create an image from the given pad. (See TASImage::FromPad) virtual void FromPad(TVirtualPad * /*pad*/, Int_t /*x*/ = 0, Int_t /*y*/ = 0, UInt_t /*w*/ = 0, UInt_t /*h*/ = 0) {} - // Create an image from X11 window handle. (See TASImage::FromX11Window) - virtual void FromX11Window(Window_t /* win */ , Int_t /* x */, Int_t /* y */, Int_t /* width */, Int_t /* height */) {} - // Create an image from gVirtualX window. (See TASImage::FromWindow) - virtual void R__DEPRECATED(7,00, "Use TGWindow::CreateImageFromWindow instead") FromWindow(Drawable_t /*wid*/, Int_t /*x*/ = 0, Int_t /*y*/ = 0, UInt_t /*w*/ = 0, UInt_t /*h*/ = 0) {} + virtual void R__DEPRECATED(7,00, "Use TASUtils::FromWindow instead") FromWindow(Drawable_t /*wid*/, Int_t /*x*/ = 0, Int_t /*y*/ = 0, UInt_t /*w*/ = 0, UInt_t /*h*/ = 0) {} // Create an image from GL buffer. (See TASImage::FromGLBuffer) virtual void R__DEPRECATED(7,00, "Use FromBitmap instead") FromGLBuffer(UChar_t * /*buf*/, UInt_t /*w*/, UInt_t /*h*/) {} @@ -252,17 +249,16 @@ friend TImage operator/(const TImage &i1, const TImage &s2); virtual TArrayL *GetPixels(Int_t /*x*/= 0, Int_t /*y*/= 0, UInt_t /*w*/ = 0, UInt_t /*h*/ = 0) { return nullptr; } virtual TArrayD *GetArray(UInt_t /*w*/ = 0, UInt_t /*h*/ = 0, TImagePalette * = gWebImagePalette) { return nullptr; } - virtual Pixmap_t GetX11Pixmap(Window_t /* root_window */) { return 0; } - virtual Pixmap_t R__DEPRECATED(7,00, "Use TGWindow::GetImagePixmap instead") GetPixmap() { return 0; } + virtual Pixmap_t R__DEPRECATED(7,00, "Use TASUtils::GetPixmap instead") GetPixmap() { return 0; } virtual Bool_t GetMaskBits(UInt_t & /* width */, UInt_t & /* height */, std::vector & /* bits */) { return kFALSE; } - virtual Pixmap_t R__DEPRECATED(7,00, "Use TGWindow::GetImageMask instead") GetMask() { return 0; } + virtual Pixmap_t R__DEPRECATED(7,00, "Use TASUtils::GetMask instead") GetMask() { return 0; } virtual UInt_t *GetArgbArray() { return nullptr; } virtual UInt_t *GetRgbaArray() { return nullptr; } virtual Double_t *GetVecArray() { return nullptr; } virtual UInt_t *GetScanline(UInt_t /*y*/) { return nullptr; } virtual void GetImageBuffer(char ** /*buffer*/, int* /*size*/, EImageFileTypes /*type*/ = TImage::kPng) {} virtual Bool_t SetImageBuffer(char ** /*buffer*/, EImageFileTypes /*type*/ = TImage::kPng) { return kFALSE; } - virtual void PaintImage(Drawable_t /*wid*/, Int_t /*x*/, Int_t /*y*/, Int_t /*xsrc*/ = 0, Int_t /*ysrc*/ = 0, UInt_t /*wsrc*/ = 0, UInt_t /*hsrc*/ = 0, Option_t * /*opt*/ = "") { } + virtual void R__DEPRECATED(7,00, "Use TASUtils::PaintImage instead") PaintImage(Drawable_t /*wid*/, Int_t /*x*/, Int_t /*y*/, Int_t /*xsrc*/ = 0, Int_t /*ysrc*/ = 0, UInt_t /*wsrc*/ = 0, UInt_t /*hsrc*/ = 0, Option_t * /*opt*/ = "") { } static EImageFileTypes GetImageFileTypeFromFilename(const char* opt); static TImage *Create(); diff --git a/graf2d/padpainter/CMakeLists.txt b/graf2d/padpainter/CMakeLists.txt new file mode 100644 index 0000000000000..2553f0411cda1 --- /dev/null +++ b/graf2d/padpainter/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (C) 1995-2026, Rene Brun and Fons Rademakers. +# All rights reserved. +# +# For the licensing terms see $ROOTSYS/LICENSE. +# For the list of contributors see $ROOTSYS/README/CREDITS. + +############################################################################ +# CMakeLists.txt file for building ROOT graf2d/padpainter package +# @author Sergey Linev, GSI +############################################################################ + +ROOT_STANDARD_LIBRARY_PACKAGE(ROOTPadPainter + NO_INSTALL_HEADERS + HEADERS + TPadPainter.h + SOURCES + TPadPainter.cxx + DICTIONARY_OPTIONS + -writeEmptyRootPCM + DEPENDENCIES + Gpad +) + + +if(asimage) + target_link_libraries(ROOTPadPainter PUBLIC ASImageUtils) + target_compile_definitions(ROOTPadPainter PRIVATE USE_ASIMAGEUTILS) +endif() + + +ROOT_INSTALL_HEADERS() diff --git a/graf2d/padpainter/inc/LinkDef.h b/graf2d/padpainter/inc/LinkDef.h new file mode 100644 index 0000000000000..5649423ad6fe5 --- /dev/null +++ b/graf2d/padpainter/inc/LinkDef.h @@ -0,0 +1,19 @@ +/* @(#)root/padpainter:$Id$ */ + +/************************************************************************* + * Copyright (C) 1995-2026, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms seeg $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class TPadPainter; + +#endif diff --git a/graf2d/gpad/inc/TPadPainter.h b/graf2d/padpainter/inc/TPadPainter.h similarity index 100% rename from graf2d/gpad/inc/TPadPainter.h rename to graf2d/padpainter/inc/TPadPainter.h diff --git a/graf2d/gpad/src/TPadPainter.cxx b/graf2d/padpainter/src/TPadPainter.cxx similarity index 96% rename from graf2d/gpad/src/TPadPainter.cxx rename to graf2d/padpainter/src/TPadPainter.cxx index aa0d87d6db32e..071a0866e7440 100644 --- a/graf2d/gpad/src/TPadPainter.cxx +++ b/graf2d/padpainter/src/TPadPainter.cxx @@ -25,6 +25,10 @@ #include "TMath.h" #include "TPad.h" +#ifdef USE_ASIMAGEUTILS +#include "TASUtils.h" +#endif + namespace { //Typedef is fine, but let's pretend we look cool and modern: @@ -226,9 +230,21 @@ Bool_t TPadPainter::HasTTFonts() const void TPadPainter::DrawImage(TImage *img, Int_t x, Int_t y, Int_t flags) { - Window_t wid = (Window_t)gVirtualX->GetWindowID(fPad->GetPixmapID()); + Window_t wid = gVirtualX->GetWindowID(fPad->GetPixmapID()); + // use old API to draw image on gVirtualX window - img->PaintImage(wid, x, y, 0, 0, 0, 0, flags ? "" : "opaque"); + // img->PaintImage(wid, x, y, 0, 0, 0, 0, flags ? "" : "opaque"); +#ifdef USE_ASIMAGEUTILS + // new API invokes + TASUtils::PaintImage(img, wid, x, y, !flags); +#else + ::Error("TPadPainter::DrawImage", "TASImage not compiled, image painting is not possible"); + (void) wid; + (void) img; + (void) x; + (void) y; + (void) flags; +#endif } //////////////////////////////////////////////////////////////////////////////// @@ -573,44 +589,31 @@ TVirtualPadPainter::ESaveImageResult TPadPainter::SaveAsImage(TVirtualPad *pad, //////////////////////////////////////////////////////////////////////////////// /// Fill image object with the pixel data from the pad -/// Implements special handling for X11 where ASImage has native implementation +/// Use TASUtils::FillImageFromWindow method which provides native X11 handling Bool_t TPadPainter::FillImageFromPad(TImage *image, TVirtualPad *pad) const { if (!image || !pad) return kFALSE; - gVirtualX->Update(1); - if (!gThreadXAR) { - gSystem->Sleep(10); - gSystem->ProcessEvents(); - gSystem->Sleep(10); - gSystem->ProcessEvents(); - } - +#ifdef USE_ASIMAGEUTILS auto width = pad->GetPadWidth(); auto height = pad->GetPadHeight(); Int_t wid = (pad == pad->GetCanvas()) ? pad->GetCanvasID() : pad->GetPixmapID(); gVirtualX->SelectWindow(wid); - Window_t wd = (Window_t)gVirtualX->GetCurrentWindow(); + Window_t wd = gVirtualX->GetCurrentWindow(); - if (IsX11()) { //use built-in optimized version - image->FromX11Window(wd, 0, 0, width, height); - } else { - unsigned char *bits = gVirtualX->GetColorBits(wd, 0, 0, width, height); - if (!bits) - return kFALSE; - - image->FromBitmap(bits, width, height); - delete [] bits; - } - - return image->IsValid(); + return TASUtils::FillImageFromWindow(image, wd, width, height); +#else + ::Error("TPadPainter::FillImageFromPad", "Cannot work without TASImage class"); + (void) image; + (void) pad; + return kFALSE; +#endif } - //Aux. private functions. namespace { diff --git a/graf3d/gl/src/TGLPadPainter.cxx b/graf3d/gl/src/TGLPadPainter.cxx index 605bbf803f48c..8fdc67371554f 100644 --- a/graf3d/gl/src/TGLPadPainter.cxx +++ b/graf3d/gl/src/TGLPadPainter.cxx @@ -872,13 +872,60 @@ void TGLPadPainter::RestoreViewport() //////////////////////////////////////////////////////////////////////////////// /// Draw image on the GL window -void TGLPadPainter::DrawImage(TImage *img, Int_t x, Int_t y, Int_t flags) +void TGLPadPainter::DrawImage(TImage *img, Int_t dstX, Int_t dstY, Int_t flags) { - Int_t width = img->GetWidth(); - Int_t height = img->GetHeight(); - auto bits = img->GetArgbArray(); - if (bits) - DrawPixels((unsigned char *)bits, width, height, x, y, flags); + if (fLocked) + return; + + auto width = img->GetWidth(); + auto height = img->GetHeight(); + auto pixelData = (unsigned char *) img->GetArgbArray(); + + if (!pixelData) { + ::Error("TGLPadPainter::DrawImage", "pixel data is null"); + return; + } + + if (!width || !height) { + //Assert is better. + ::Error("TGLPadPainter::DrawImage", "invalid image dimentsion"); + return; + } + + if (!gPad) { + ::Error("TGLPadPainter::DrawImage", "pad is not provided"); + return; + } + + const Double_t rasterX = Double_t(dstX) / gPad->GetPadWidth() * (gPad->GetX2() - gPad->GetX1()) + gPad->GetX1(); + + const Double_t yRange = gPad->GetY2() - gPad->GetY1(); + const Double_t rasterY = yRange - Double_t(dstY + height) / gPad->GetPadHeight() * yRange + gPad->GetY1(); + + GLdouble oldPos[4] = {}; + // Save the previous raster pos. + glGetDoublev(GL_CURRENT_RASTER_POSITION, oldPos); + + glRasterPos2d(rasterX, rasterY); + // Stupid asimage provides us upside-down image. + std::vector upsideDownImage(4 * width * height); + const unsigned char *srcLine = pixelData + 4 * width * (height - 1); + unsigned char *dstLine = &upsideDownImage[0]; + for (UInt_t i = 0; i < height; ++i, srcLine -= 4 * width, dstLine += 4 * width) + std::copy(srcLine, srcLine + 4 * width, dstLine); + + if (flags) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + glDrawPixels(width, height, GL_BGRA, GL_UNSIGNED_BYTE, &upsideDownImage[0]); + + if (flags) + glDisable(GL_BLEND); + + //Restore raster pos. + glRasterPos2d(oldPos[0], oldPos[1]); } //////////////////////////////////////////////////////////////////////////////// @@ -957,75 +1004,9 @@ Bool_t TGLPadPainter::FillImageFromPad(TImage *image, TVirtualPad *pad) const //////////////////////////////////////////////////////////////////////////////// -void TGLPadPainter::DrawPixels(const unsigned char *pixelData, UInt_t width, UInt_t height, - Int_t dstX, Int_t dstY, Bool_t enableBlending) +void TGLPadPainter::DrawPixels(const unsigned char *, UInt_t, UInt_t, + Int_t, Int_t, Bool_t) { - if (fLocked) - return; - - if (!pixelData) { - //I'd prefer an assert. - ::Error("TGLPadPainter::DrawPixels", "pixel data is null"); - return; - } - - if (std::numeric_limits::digits >= 32) { - //TASImage uses bit 31 as ... - //alpha channel flag! FUUUUUUUUUUUUU ..... !!! - CLRBIT(width, 31); - CLRBIT(height, 31); - } - - if (!width) { - //Assert is better. - ::Error("TGLPadPainter::DrawPixels", "invalid width"); - return; - } - - if (!height) { - //Assert is better. - ::Error("TGLPadPainter::DrawPixels", "invalid height"); - return; - } - - if (TPad *pad = dynamic_cast(gPad)) { - //TASImage passes pixel coordinates in pad's pixmap coordinate space. - //While glRasterPosX said to work with 'window' coordinates, - //that's a lie :) it does not :) - - const Double_t rasterX = Double_t(dstX) / (pad->GetAbsWNDC() * pad->GetWw()) * - (pad->GetX2() - pad->GetX1()) + pad->GetX1(); - - const Double_t yRange = pad->GetY2() - pad->GetY1(); - const Double_t rasterY = yRange - Double_t(dstY + height) / (pad->GetAbsHNDC() * pad->GetWh()) * yRange + - pad->GetY1(); - - GLdouble oldPos[4] = {}; - //Save the previous raster pos. - glGetDoublev(GL_CURRENT_RASTER_POSITION, oldPos); - - glRasterPos2d(rasterX, rasterY); - //Stupid asimage provides us upside-down image. - std::vector upsideDownImage(4 * width * height); - const unsigned char *srcLine = pixelData + 4 * width * (height - 1); - unsigned char *dstLine = &upsideDownImage[0]; - for (UInt_t i = 0; i < height; ++i, srcLine -= 4 * width, dstLine += 4 * width) - std::copy(srcLine, srcLine + 4 * width, dstLine); - - if (enableBlending) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - - glDrawPixels(width, height, GL_BGRA, GL_UNSIGNED_BYTE, &upsideDownImage[0]); - - if (enableBlending) - glDisable(GL_BLEND); - - //Restore raster pos. - glRasterPos2d(oldPos[0], oldPos[1]); - } else - ::Error("TGLPadPainter::DrawPixels", "no pad found to draw"); } //Aux. functions - gradient and solid fill of arbitrary area. diff --git a/gui/gui/CMakeLists.txt b/gui/gui/CMakeLists.txt index b25f7c0ddbf8a..1bf64a8f34e2f 100644 --- a/gui/gui/CMakeLists.txt +++ b/gui/gui/CMakeLists.txt @@ -204,6 +204,8 @@ ROOT_STANDARD_LIBRARY_PACKAGE(Gui Gpad Graf MathCore + ASImageUtils + ROOTPadPainter ROOTNTupleBrowse ) diff --git a/gui/gui/inc/TGWindow.h b/gui/gui/inc/TGWindow.h index ce65b8a825300..96e2e0fcba6f9 100644 --- a/gui/gui/inc/TGWindow.h +++ b/gui/gui/inc/TGWindow.h @@ -19,7 +19,6 @@ class TGClient; class TGIdleHandler; -class TImage; class TGWindow : public TGObject { @@ -126,10 +125,6 @@ friend class TGClient; static Int_t GetCounter(); - static std::unique_ptr CreateImageFromWindow(Drawable_t wid); - static Pixmap_t GetImagePixmap(TImage *img); - static Pixmap_t GetImageMask(TImage *img); - ClassDefOverride(TGWindow, 0); // GUI Window base class }; diff --git a/gui/gui/inc/TRootCanvas.h b/gui/gui/inc/TRootCanvas.h index c151bc456d0a8..d01b18ff1d7ca 100644 --- a/gui/gui/inc/TRootCanvas.h +++ b/gui/gui/inc/TRootCanvas.h @@ -99,6 +99,8 @@ friend class TRootContainer; Atom_t HandleDNDEnter(Atom_t * typelist) override; Bool_t HandleDNDLeave() override; + TVirtualPadPainter *CreatePadPainter() override; + public: TRootCanvas(TCanvas *c = nullptr, const char *name = "ROOT Canvas", UInt_t width = 500, UInt_t height = 300); TRootCanvas(TCanvas *c, const char *name, Int_t x, Int_t y, UInt_t width, UInt_t height); diff --git a/gui/gui/src/TGButton.cxx b/gui/gui/src/TGButton.cxx index ede2fe0b66382..3661c47d10cf1 100644 --- a/gui/gui/src/TGButton.cxx +++ b/gui/gui/src/TGButton.cxx @@ -143,6 +143,7 @@ by calling the SetSplit(Bool_t) method. #include "TGResourcePool.h" #include "TSystem.h" #include "TImage.h" +#include "TASUtils.h" #include "TEnv.h" #include "TClass.h" #include "TGMenu.h" @@ -1101,26 +1102,22 @@ void TGPictureButton::DoRedraw() void TGPictureButton::CreateDisabledPicture() { - TImage *img = TImage::Create(); - if (!img) return; - TImage *img2 = TImage::Create(); - if (!img2) { - if (img) delete img; + std::unique_ptr img2(TImage::Create()); + if (!img2) return; - } TString back = gEnv->GetValue("Gui.BackgroundColor", "#c0c0c0"); img2->FillRectangle(back.Data(), 0, 0, fPic->GetWidth(), fPic->GetHeight()); - img->SetImage(fPic->GetPicture(), fPic->GetMask()); - Pixmap_t mask = GetImageMask(img); - img2->Merge(img, "overlay"); - - TString name = "disbl_"; - name += fPic->GetName(); - fPicD = fClient->GetPicturePool()->GetPicture(name.Data(), GetImagePixmap(img2), - mask); - fOwnDisabledPic = kTRUE; - delete img; - delete img2; + auto img = TASUtils::FromPixmap(fPic->GetPicture(), fPic->GetMask()); + if (img) { + Pixmap_t mask = TASUtils::GetMask(img.get()); + img2->Merge(img.get(), "overlay"); + + TString name = "disbl_"; + name += fPic->GetName(); + fPicD = fClient->GetPicturePool()->GetPicture(name.Data(), TASUtils::GetPixmap(img2.get()), + mask); + fOwnDisabledPic = kTRUE; + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/gui/gui/src/TGFSContainer.cxx b/gui/gui/src/TGFSContainer.cxx index 3d2e23578fd3c..fb1b9e3e4a5a7 100644 --- a/gui/gui/src/TGFSContainer.cxx +++ b/gui/gui/src/TGFSContainer.cxx @@ -54,6 +54,7 @@ Utility class used by the file selection dialog (TGFSDialog). #include "TRemoteObject.h" #include "TBufferFile.h" #include "TImage.h" +#include "TASUtils.h" #include #include @@ -692,36 +693,28 @@ void TGFileContainer::GetFilePictures(const TGPicture **pic, } } if (is_link) { - TImage *img1, *img2; if (*pic && *lpic) { - TString lnk_name; - img1 = TImage::Create(); + auto img1 = TASUtils::FromPixmap((*pic)->GetPicture(), (*pic)->GetMask()); if (img1) { - img1->SetImage(((const TGPicture *)*pic)->GetPicture(), - ((const TGPicture *)*pic)->GetMask()); - img2 = TImage::Open("slink_t.xpm"); - if (img2) img1->Merge(img2); - lnk_name = ((const TGPicture *)*pic)->GetName(); + std::unique_ptr img2(TImage::Open("slink_t.xpm")); + if (img2) + img1->Merge(img2.get()); + TString lnk_name = (*pic)->GetName(); lnk_name.Prepend("lnk_"); *pic = fClient->GetPicturePool()->GetPicture(lnk_name.Data(), - GetImagePixmap(img1), GetImageMask(img1)); + TASUtils::GetPixmap(img1.get()), TASUtils::GetMask(img1.get())); fCleanups->Add(((TObject *)*pic)); - if (img2) delete img2; - delete img1; } - img1 = TImage::Create(); + img1 = TASUtils::FromPixmap((*lpic)->GetPicture(), (*lpic)->GetMask()); if (img1) { - img1->SetImage(((const TGPicture *)*lpic)->GetPicture(), - ((const TGPicture *)*lpic)->GetMask()); - img2 = TImage::Open("slink_s.xpm"); - if (img2) img1->Merge(img2); - lnk_name = ((const TGPicture *)*lpic)->GetName(); + std::unique_ptr img2(TImage::Open("slink_s.xpm")); + if (img2) + img1->Merge(img2.get()); + TString lnk_name = (*lpic)->GetName(); lnk_name.Prepend("lnk_"); *lpic = fClient->GetPicturePool()->GetPicture(lnk_name.Data(), - GetImagePixmap(img1), GetImageMask(img1)); + TASUtils::GetPixmap(img1.get()), TASUtils::GetMask(img1.get())); fCleanups->Add(((TObject *)*lpic)); - if (img2) delete img2; - delete img1; } } else { diff --git a/gui/gui/src/TGFileBrowser.cxx b/gui/gui/src/TGFileBrowser.cxx index b2aa57e018d42..660423f87e558 100644 --- a/gui/gui/src/TGFileBrowser.cxx +++ b/gui/gui/src/TGFileBrowser.cxx @@ -30,6 +30,7 @@ #include "TRegexp.h" #include "TEnv.h" #include "TImage.h" +#include "TASUtils.h" #include "TBrowser.h" #include "TRemoteObject.h" #include "TKey.h" @@ -1161,18 +1162,16 @@ static Bool_t IsTextFile(const char *candidate) static const TGPicture *MakeLinkPic(const TGPicture *pic) { if (pic) { - auto img1 = TImage::Create(); - if (!img1) return pic; - img1->SetImage(((const TGPicture *)pic)->GetPicture(), - ((const TGPicture *)pic)->GetMask()); - auto img2 = TImage::Open("slink_t.xpm"); - if (img2) img1->Merge(img2); - TString lnk_name = ((const TGPicture *)pic)->GetName(); + auto img1 = TASUtils::FromPixmap(pic->GetPicture(), pic->GetMask()); + if (!img1) + return pic; + std::unique_ptr img2(TImage::Open("slink_t.xpm")); + if (img2) + img1->Merge(img2.get()); + TString lnk_name = pic->GetName(); lnk_name.Prepend("lnk_"); - auto merged = gClient->GetPicturePool()->GetPicture(lnk_name.Data(), - TGWindow::GetImagePixmap(img1), TGWindow::GetImageMask(img1)); - if (img2) delete img2; - delete img1; + auto merged = gClient->GetPicturePool()->GetPicture(lnk_name.Data(), TASUtils::GetPixmap(img1.get()), + TASUtils::GetMask(img1.get())); return merged; } return pic; @@ -1614,7 +1613,7 @@ void TGFileBrowser::GetObjPicture(const TGPicture **pic, TObject *obj) if (!(*pic) && xpm) { if (im && im->SetImageBuffer((char**)&name, TImage::kXpm)) { im->Scale(im->GetWidth()/4, im->GetHeight()/4); - *pic = gClient->GetPicturePool()->GetPicture(iconname, TGWindow::GetImagePixmap(im), TGWindow::GetImageMask(im)); + *pic = gClient->GetPicturePool()->GetPicture(iconname, TASUtils::GetPixmap(im), TASUtils::GetMask(im)); } gClient->GetMimeTypeList()->AddType("[thumbnail]", iconname, iconname, iconname, "->Browse()"); return; diff --git a/gui/gui/src/TGFrame.cxx b/gui/gui/src/TGFrame.cxx index 625101cbb7d44..04fdb1a84bd8a 100644 --- a/gui/gui/src/TGFrame.cxx +++ b/gui/gui/src/TGFrame.cxx @@ -102,6 +102,7 @@ in a list view. Used to have resizable column headers. #include "TGSplitter.h" #include "TGDNDManager.h" #include "TImage.h" +#include "TASUtils.h" #include "TObjectSpy.h" #include "TVirtualX.h" @@ -1579,7 +1580,7 @@ Bool_t TGMainFrame::SaveFrameAsCodeOrImage(const TString &fileName) Int_t saver = gErrorIgnoreLevel; gErrorIgnoreLevel = kFatal; RaiseWindow(); - auto img = TGWindow::CreateImageFromWindow(GetId()); + auto img = TASUtils::FromWindow(GetId()); if (img) img->WriteImage(fname, gtype); gErrorIgnoreLevel = saver; @@ -1833,7 +1834,7 @@ void TGMainFrame::SetIconPixmap(char **xpm_array) TImage *img = TImage::Create(); if (!img) return; img->SetImageBuffer(xpm_array, TImage::kXpm); - Pixmap_t pic = GetImagePixmap(img); + Pixmap_t pic = TASUtils::GetPixmap(img); if (pic) { gVirtualX->SetIconPixmap(fId, pic); } else { diff --git a/gui/gui/src/TGIcon.cxx b/gui/gui/src/TGIcon.cxx index 9547eda7f6654..6f02d124042f3 100644 --- a/gui/gui/src/TGIcon.cxx +++ b/gui/gui/src/TGIcon.cxx @@ -33,6 +33,7 @@ This class handles GUI icons. #include "TGPicture.h" #include "TSystem.h" #include "TImage.h" +#include "TASUtils.h" #include "TVirtualDragManager.h" #include "TVirtualX.h" @@ -57,7 +58,7 @@ TGIcon::TGIcon(const TGWindow *p, const char *image) : TGFrame(p, 1, 1) fImage = TImage::Open(path); if (fImage) { fPic = fClient->GetPicturePool()->GetPicture(gSystem->BaseName(path), - GetImagePixmap(fImage), GetImageMask(fImage)); + TASUtils::GetPixmap(fImage), TASUtils::GetMask(fImage)); TGFrame::Resize(fImage->GetWidth(), fImage->GetHeight()); } SetWindowName(); @@ -154,8 +155,8 @@ void TGIcon::Resize(UInt_t w, UInt_t h) (GetOptions() & kDoubleBorder); fImage->Scale(w - 2*border, h - 2*border); - fPic = fClient->GetPicturePool()->GetPicture(fImage->GetName(), - GetImagePixmap(fImage), GetImageMask(fImage)); + fPic = + fClient->GetPicturePool()->GetPicture(fImage->GetName(), TASUtils::GetPixmap(fImage), TASUtils::GetMask(fImage)); DoRedraw(); } diff --git a/gui/gui/src/TGObject.cxx b/gui/gui/src/TGObject.cxx index a62534698b0ea..1ef7b329483e2 100644 --- a/gui/gui/src/TGObject.cxx +++ b/gui/gui/src/TGObject.cxx @@ -34,6 +34,7 @@ is based on the XClass'95 code (see Copyleft in source). #include "TGObject.h" #include "TGWindow.h" #include "TImage.h" +#include "TASUtils.h" #include "TROOT.h" @@ -55,7 +56,7 @@ void TGObject::SaveAs(const char* filename /*= ""*/, Option_t* option /*= ""*/) { TImage::EImageFileTypes type = TImage::GetImageFileTypeFromFilename(filename); if (type != TImage::kUnknown) { - auto img = TGWindow::CreateImageFromWindow(GetId()); + auto img = TASUtils::FromWindow(GetId()); if (img) img->WriteImage(filename, type); return; diff --git a/gui/gui/src/TGPicture.cxx b/gui/gui/src/TGPicture.cxx index 2dced4a815938..ffddb91aa160d 100644 --- a/gui/gui/src/TGPicture.cxx +++ b/gui/gui/src/TGPicture.cxx @@ -40,6 +40,7 @@ destroyed by the TGPicturePool. #include "TGWindow.h" #include "TVirtualX.h" #include "TImage.h" +#include "TASUtils.h" #include "TROOT.h" #include @@ -116,7 +117,7 @@ const TGPicture *TGPicturePool::GetPicture(const char *name) return nullptr; } - pic = new TGPicture(pname, TGWindow::GetImagePixmap(img), TGWindow::GetImageMask(img)); + pic = new TGPicture(pname, TASUtils::GetPixmap(img), TASUtils::GetMask(img)); delete img; fPicList->Add(pic); return pic; @@ -192,7 +193,7 @@ const TGPicture *TGPicturePool::GetPicture(const char *name, img->Scale(new_width, new_height); - pic = new TGPicture(hname, TGWindow::GetImagePixmap(img), TGWindow::GetImageMask(img)); + pic = new TGPicture(hname, TASUtils::GetPixmap(img), TASUtils::GetMask(img)); delete [] picnam; delete img; fPicList->Add(pic); @@ -271,7 +272,7 @@ const TGPicture *TGPicturePool::GetPicture(const char *name, char **xpm) return 0; } - pic = new TGPicture(hname, TGWindow::GetImagePixmap(img), TGWindow::GetImageMask(img)); + pic = new TGPicture(hname, TASUtils::GetPixmap(img), TASUtils::GetMask(img)); delete img; return pic; } diff --git a/gui/gui/src/TGScrollBar.cxx b/gui/gui/src/TGScrollBar.cxx index 707e145e7ea3a..f8558a07749c9 100644 --- a/gui/gui/src/TGScrollBar.cxx +++ b/gui/gui/src/TGScrollBar.cxx @@ -51,6 +51,7 @@ kC_VSCROLL, kSB_SLIDERTRACK, position, 0 #include "TGResourcePool.h" #include "TGPicture.h" #include "TImage.h" +#include "TASUtils.h" #include "TSystem.h" #include "TTimer.h" #include "TEnv.h" @@ -157,25 +158,21 @@ void TGScrollBarElement::SetEnabled(Bool_t on) SetState(kButtonDisabled); if (!fPicD) { - TImage *img = TImage::Create(); - if (!img) return; - TImage *img2 = TImage::Create(); - if (!img2) { - if (img) delete img; + std::unique_ptr img2(TImage::Create()); + if (!img2) return; - } TString back = gEnv->GetValue("Gui.BackgroundColor", "#c0c0c0"); img2->FillRectangle(back.Data(), 0, 0, fPic->GetWidth(), fPic->GetHeight()); - img->SetImage(fPicN->GetPicture(), fPicN->GetMask()); - Pixmap_t mask = GetImageMask(img); - img2->Merge(img, "overlay"); + auto img = TASUtils::FromPixmap(fPicN->GetPicture(), fPicN->GetMask()); + if (!img) + return; + Pixmap_t mask = TASUtils::GetMask(img.get()); + img2->Merge(img.get(), "overlay"); TString name = "disbl_"; name += fPic->GetName(); - fPicD = fClient->GetPicturePool()->GetPicture(name.Data(), GetImagePixmap(img2), + fPicD = fClient->GetPicturePool()->GetPicture(name.Data(), TASUtils::GetPixmap(img2.get()), mask); - delete img; - delete img2; } fPic = fPicD; } diff --git a/gui/gui/src/TGShapedFrame.cxx b/gui/gui/src/TGShapedFrame.cxx index 3a425258353dd..c6439f5ccf90e 100644 --- a/gui/gui/src/TGShapedFrame.cxx +++ b/gui/gui/src/TGShapedFrame.cxx @@ -12,6 +12,7 @@ #include "TGLayout.h" #include "TString.h" #include "TImage.h" +#include "TASUtils.h" #include "TGShapedFrame.h" #include "TVirtualX.h" @@ -50,7 +51,7 @@ TGShapedFrame::TGShapedFrame(const char *pname, const TGWindow *p, UInt_t w, Error("TGShapedFrame", "%s not found", picName.Data()); return; } - fBgnd = fClient->GetPicturePool()->GetPicture(picName.Data(), GetImagePixmap(fImage), GetImageMask(fImage)); + fBgnd = fClient->GetPicturePool()->GetPicture(picName.Data(), TASUtils::GetPixmap(fImage), TASUtils::GetMask(fImage)); // shape the window with the picture mask gVirtualX->ShapeCombineMask(fId, 0, 0, fBgnd->GetMask()); // and finally set the background picture diff --git a/gui/gui/src/TGSlider.cxx b/gui/gui/src/TGSlider.cxx index 5ed270c90188e..3432597a5ba43 100644 --- a/gui/gui/src/TGSlider.cxx +++ b/gui/gui/src/TGSlider.cxx @@ -64,6 +64,7 @@ Releasing the mouse will generate the event: #include "TGSlider.h" #include "TGPicture.h" #include "TImage.h" +#include "TASUtils.h" #include "TEnv.h" #include "TVirtualX.h" @@ -129,25 +130,21 @@ void TGSlider::CreateDisabledPicture() { if (!fSliderPic) return; - TImage *img = TImage::Create(); - if (!img) return; - TImage *img2 = TImage::Create(); - if (!img2) { - if (img) delete img; + std::unique_ptr img2(TImage::Create()); + if (!img2) return; - } TString back = gEnv->GetValue("Gui.BackgroundColor", "#c0c0c0"); img2->FillRectangle(back.Data(), 0, 0, fSliderPic->GetWidth(), fSliderPic->GetHeight()); - img->SetImage(fSliderPic->GetPicture(), fSliderPic->GetMask()); - Pixmap_t mask = GetImageMask(img); - img2->Merge(img, "overlay"); + auto img = TASUtils::FromPixmap(fSliderPic->GetPicture(), fSliderPic->GetMask()); + if (!img) + return; + Pixmap_t mask = TASUtils::GetMask(img.get()); + img2->Merge(img.get(), "overlay"); TString name = "disbl_"; - name += fSliderPic->GetName(); - fDisabledPic = fClient->GetPicturePool()->GetPicture(name.Data(), GetImagePixmap(img2), mask); - delete img; - delete img2; + name.Append(fSliderPic->GetName()); + fDisabledPic = fClient->GetPicturePool()->GetPicture(name.Data(), TASUtils::GetPixmap(img2.get()), mask); } //////////////////////////////////////////////////////////////////////////////// diff --git a/gui/gui/src/TGSpeedo.cxx b/gui/gui/src/TGSpeedo.cxx index b0373e4169d05..06da3dba25a4d 100644 --- a/gui/gui/src/TGSpeedo.cxx +++ b/gui/gui/src/TGSpeedo.cxx @@ -31,6 +31,7 @@ Two signals are available: #include "TSystem.h" #include "TGResourcePool.h" #include "TImage.h" +#include "TASUtils.h" #include "TMath.h" #include "TVirtualX.h" #include "TGSpeedo.h" @@ -136,7 +137,7 @@ void TGSpeedo::Build() if (fImage && fImage->IsValid()) { fBase = fClient->GetPicturePool()->GetPicture(gSystem->BaseName(fPicName.Data()), - GetImagePixmap(fImage), GetImageMask(fImage)); + TASUtils::GetPixmap(fImage), TASUtils::GetMask(fImage)); // center of the image Float_t xc = (Float_t)(fBase ? (fBase->GetWidth() + 1) / 2 : 96.0); Float_t yc = (Float_t)(fBase ? (fBase->GetHeight() + 1) / 2 : 96.0); @@ -527,8 +528,9 @@ void TGSpeedo::DrawNeedle() if (fImage2 && fImage2->IsValid()) { // First clone original image. - TImage *img = (TImage*)fImage2->Clone("img"); - if (!img || !img->IsValid()) return; + std::unique_ptr img((TImage*)fImage2->Clone("img")); + if (!img || !img->IsValid()) + return; if (fPeakMark) { img->DrawLine(xpk0, ypk0, xpk1, ypk1, "#00ff00", 3); img->DrawLine(xpk0, ypk0, xpk1, ypk1, "#ffffff", 1); @@ -539,10 +541,9 @@ void TGSpeedo::DrawNeedle() } // draw line (used to render the needle) directly on the image img->DrawLine(xch0, ych0, xch1, ych1, "#ff0000", 2); + // finally paint image to the widget - img->PaintImage(fId, 0, 0, 0, 0, 0, 0, "opaque"); - // and finally, to avoid memory leaks - delete img; + TASUtils::PaintImage(img.get(), fId, 0, 0, kTRUE); } gVirtualX->Update(); } @@ -645,7 +646,8 @@ void TGSpeedo::DoRedraw() if (fImage2 && fImage2->IsValid()) delete fImage2; fImage2 = (TImage*)fImage->Clone("fImage2"); - if (!fImage2 || !fImage2->IsValid()) return; + if (!fImage2 || !fImage2->IsValid()) + return; TString ar = "arialbd.ttf"; // format counter value Int_t nexe = 0; @@ -678,8 +680,9 @@ void TGSpeedo::DoRedraw() // second line strSize = gVirtualX->TextWidth(fTextFS, fDisplay2.Data(), fDisplay2.Length()) - 6; fImage2->DrawText((Int_t)xc - (strSize / 2), (Int_t)yc + 38, fDisplay2.Data(), 8, "#ffffff", ar); - TImage *img = (TImage*)fImage2->Clone("img"); - if (!img || !img->IsValid()) return; + std::unique_ptr img((TImage*)fImage2->Clone("img")); + if (!img || !img->IsValid()) + return; if (fPeakMark) { img->DrawLine(xpk0, ypk0, xpk1, ypk1, "#00ff00", 3); img->DrawLine(xpk0, ypk0, xpk1, ypk1, "#ffffff", 1); @@ -690,9 +693,8 @@ void TGSpeedo::DoRedraw() } // draw line (used to render the needle) directly on the image img->DrawLine(xch0, ych0, xch1, ych1, "#ff0000", 2); + // finally paint image to the widget - img->PaintImage(fId, 0, 0, 0, 0, 0, 0, "opaque"); - // and finally, to avoid memory leaks - delete img; + TASUtils::PaintImage(img.get(), fId, 0, 0, kTRUE); } } diff --git a/gui/gui/src/TGWindow.cxx b/gui/gui/src/TGWindow.cxx index 4306e9031c835..cd977d1842dd9 100644 --- a/gui/gui/src/TGWindow.cxx +++ b/gui/gui/src/TGWindow.cxx @@ -37,6 +37,7 @@ ROOT GUI Window base class. #include "TError.h" #include "TSystem.h" #include "TImage.h" +#include "TASUtils.h" Int_t TGWindow::fgCounter = 0; @@ -356,92 +357,3 @@ const char *TGWindow::GetName()const return fName.Data(); } - - -//////////////////////////////////////////////////////////////////////////////// -/// Create TImage object with content of displayed window - -std::unique_ptr TGWindow::CreateImageFromWindow(Drawable_t wid) -{ - std::unique_ptr img(TImage::Create()); - if (!img) { - ::Error("TGWindow::CreateImageFromWindow", "Fail to create TImage object"); - return nullptr; - } - gVirtualX->Update(1); - if (!gThreadXAR) { - gSystem->Sleep(10); - gSystem->ProcessEvents(); - gSystem->Sleep(10); - gSystem->ProcessEvents(); - } - - Int_t x = 0, y = 0; - UInt_t w = 0, h = 0; - - gVirtualX->GetWindowSize(wid, x, y, w, h); - - (void) x; // position of window is not used - (void) y; - - static Bool_t x11 = gVirtualX->InheritsFrom("TGX11"); - - if (x11) { - img->FromX11Window(wid, 0, 0, w, h); - } else { - unsigned char *bits = gVirtualX->GetColorBits(wid, 0, 0, w, h); - if (!bits) { - ::Error("TGWindow::CreateImageFromWindow", "Fail to extract color bits for specified window"); - return nullptr; - } - img->FromBitmap(bits, w, h); - delete [] bits; - } - - return img; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Returns image pixmap. -/// The pixmap must deleted by user. -/// Replacement for deprecated TImage::GetPixmap method - -Pixmap_t TGWindow::GetImagePixmap(TImage *img) -{ - if (!img) { - ::Error("TGWindow::GetImagePixmap", "Image not provided"); - return 0; - } - static Bool_t x11 = gVirtualX->InheritsFrom("TGX11"); - - if (x11) - return img->GetX11Pixmap(gVirtualX->GetDefaultRootWindow()); - - auto argb = img->GetArgbArray(); - if (!argb) { - ::Error("TGWindow::GetImagePixmap", "ARGB array is not exists"); - return 0; - } - - return gVirtualX->CreatePixmapFromData((unsigned char*) argb, img->GetScaledWidth(), img->GetScaledHeight()); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Returns image mask pixmap (alpha channel). -/// The pixmap must deleted by user. -/// Replacement for deprecated TImage::GetMask() method - -Pixmap_t TGWindow::GetImageMask(TImage *img) -{ - Pixmap_t pixmap = 0; - - UInt_t width = 0, height = 0; - std::vector bits; - - if (!img) - ::Error("TGWindow::GetImageMask", "Image not provided"); - else if (img->GetMaskBits(width, height, bits)) - pixmap = gVirtualX->CreateBitmap(gVirtualX->GetDefaultRootWindow(), bits.data(), width, height); - - return pixmap; -} diff --git a/gui/gui/src/TRootBrowserLite.cxx b/gui/gui/src/TRootBrowserLite.cxx index 41d8190a9c31d..bdd460ab79838 100644 --- a/gui/gui/src/TRootBrowserLite.cxx +++ b/gui/gui/src/TRootBrowserLite.cxx @@ -58,6 +58,7 @@ Explorer). The widgets used are the new native ROOT GUI widgets. #include "TInterpreter.h" #include "TGuiBuilder.h" #include "TImage.h" +#include "TASUtils.h" #include "TVirtualPad.h" #include "KeySymbols.h" #include "THashTable.h" @@ -503,11 +504,11 @@ void TRootIconBox::GetObjPictures(const TGPicture **pic, const TGPicture **spic, if (!(*pic) && xpm) { if (im && im->SetImageBuffer((char**)&name, TImage::kXpm)) { - *pic = fClient->GetPicturePool()->GetPicture(iconname, GetImagePixmap(im), - GetImageMask(im)); + *pic = fClient->GetPicturePool()->GetPicture(iconname, TASUtils::GetPixmap(im), + TASUtils::GetMask(im)); im->Scale(im->GetWidth()/2, im->GetHeight()/2); - *spic = fClient->GetPicturePool()->GetPicture(iconname, GetImagePixmap(im), - GetImageMask(im)); + *spic = fClient->GetPicturePool()->GetPicture(iconname, TASUtils::GetPixmap(im), + TASUtils::GetMask(im)); } fClient->GetMimeTypeList()->AddType("[thumbnail]", iconname, iconname, iconname, "->Browse()"); @@ -1746,9 +1747,9 @@ void TRootBrowserLite::ExecuteDefaultAction(TObject *obj) img->Merge(img, "tint"); // contrasting img->DrawBox(0, 0, w, h, "#ffff00", 1); // yellow frame - pic = fClient->GetPicturePool()->GetPicture(path.Data(), GetImagePixmap(img), 0); + pic = fClient->GetPicturePool()->GetPicture(path.Data(), TASUtils::GetPixmap(img), 0); img->Scale(w/3, h/3); - spic = fClient->GetPicturePool()->GetPicture(path.Data(), GetImagePixmap(img), 0); + spic = fClient->GetPicturePool()->GetPicture(path.Data(), TASUtils::GetPixmap(img), 0); thumb = new TIconBoxThumb(path.Data(), spic, pic); fIconBox->fThumbnails->Add(thumb); diff --git a/gui/gui/src/TRootCanvas.cxx b/gui/gui/src/TRootCanvas.cxx index 6eda74b953c29..82485e25e0f5b 100644 --- a/gui/gui/src/TRootCanvas.cxx +++ b/gui/gui/src/TRootCanvas.cxx @@ -49,6 +49,7 @@ drawing area. The widgets used are the new native ROOT GUI widgets. #include "TMath.h" #include #include "TGDockableFrame.h" +#include "TPadPainter.h" #include "TG3DLine.h" #include "TGToolBar.h" @@ -57,6 +58,7 @@ drawing area. The widgets used are the new native ROOT GUI widgets. #include "TRootControlBar.h" #include "TGuiBuilder.h" #include "TImage.h" +#include "TASUtils.h" #include "TError.h" #include "TGDNDManager.h" #include "TBufferFile.h" @@ -2216,7 +2218,6 @@ void TRootCanvas::UpdateDisplay(Int_t mode, Bool_t sleep) gSystem->Sleep(30); } - //////////////////////////////////////////////////////////////////////////////// /// Save a canvas container as a C++ statement(s) on output stream out. @@ -2231,3 +2232,11 @@ void TRootContainer::SavePrimitive(std::ostream &out, Option_t * /*= ""*/) } +//////////////////////////////////////////////////////////////////////////////// +/// Create pad painter instance + +TVirtualPadPainter *TRootCanvas::CreatePadPainter() +{ + return new TPadPainter(); +} + diff --git a/gui/guibuilder/CMakeLists.txt b/gui/guibuilder/CMakeLists.txt index d468d540881bc..063dca47863b6 100644 --- a/gui/guibuilder/CMakeLists.txt +++ b/gui/guibuilder/CMakeLists.txt @@ -29,4 +29,5 @@ ROOT_STANDARD_LIBRARY_PACKAGE(GuiBld Gui Graf MathCore + ASImageUtils ) diff --git a/gui/guibuilder/src/TGuiBldDragManager.cxx b/gui/guibuilder/src/TGuiBldDragManager.cxx index 86272f37864ce..ca03f64174751 100644 --- a/gui/guibuilder/src/TGuiBldDragManager.cxx +++ b/gui/guibuilder/src/TGuiBldDragManager.cxx @@ -21,6 +21,7 @@ #include "TROOT.h" #include "TColor.h" #include "TImage.h" +#include "TASUtils.h" #include "TError.h" #include "TClassMenuItem.h" @@ -3296,7 +3297,7 @@ Bool_t TGuiBldDragManager::Save(const char *file) static std::unique_ptr img; - img = TGWindow::CreateImageFromWindow(main->GetId()); + img = TASUtils::FromWindow(main->GetId()); if (!file || !file[0]) { static TString dir("."); @@ -3362,7 +3363,7 @@ Bool_t TGuiBldDragManager::SaveFrame(const char *file) static std::unique_ptr img; - img = TGWindow::CreateImageFromWindow(frame->GetId()); + img = TASUtils::FromWindow(frame->GetId()); static TString dir("."); static Bool_t overwr = kFALSE; diff --git a/gui/guibuilder/src/TRootGuiBuilder.cxx b/gui/guibuilder/src/TRootGuiBuilder.cxx index af371cf6c0505..cef94f8af2d71 100644 --- a/gui/guibuilder/src/TRootGuiBuilder.cxx +++ b/gui/guibuilder/src/TRootGuiBuilder.cxx @@ -35,6 +35,7 @@ #include "TRootHelpDialog.h" #include "TGListTree.h" #include "TImage.h" +#include "TASUtils.h" #include "TGTextEdit.h" #include "TGTab.h" #include "TGListBox.h" @@ -1601,7 +1602,7 @@ Bool_t TRootGuiBuilder::SaveProject(Event_t *event) static std::unique_ptr img; - img = TGWindow::CreateImageFromWindow(savfr->GetParent()->GetId()); + img = TASUtils::FromWindow(savfr->GetParent()->GetId()); TGWindow *root = (TGWindow*)fClient->GetRoot(); TGFileInfo fi; @@ -1690,7 +1691,7 @@ void TRootGuiBuilder::AddMacro(const char *macro, TImage *img) static int i = 0; const TGPicture *pic = fClient->GetPicturePool()->GetPicture( TString::Format("%s;%d", macro, i++), - GetImagePixmap(img), GetImageMask(img)); + TASUtils::GetPixmap(img), TASUtils::GetMask(img)); const char *name = gSystem->BaseName(macro); TGButton *btn = FindActionButton(name, "User's Macros"); diff --git a/gui/guihtml/CMakeLists.txt b/gui/guihtml/CMakeLists.txt index b010bb6d8f668..ce5669b9b5ce2 100644 --- a/gui/guihtml/CMakeLists.txt +++ b/gui/guihtml/CMakeLists.txt @@ -29,4 +29,5 @@ ROOT_STANDARD_LIBRARY_PACKAGE(GuiHtml DEPENDENCIES Gui Graf + ASImageUtils ) diff --git a/gui/guihtml/src/TGHtmlDraw.cxx b/gui/guihtml/src/TGHtmlDraw.cxx index e275c017d75e9..c506c54f333e5 100644 --- a/gui/guihtml/src/TGHtmlDraw.cxx +++ b/gui/guihtml/src/TGHtmlDraw.cxx @@ -38,6 +38,7 @@ #include "TGHtml.h" #include "TImage.h" +#include "TASUtils.h" #include "TVirtualX.h" #include "strlcpy.h" @@ -572,12 +573,23 @@ void TGHtml::DrawImage(TGHtmlImageMarkup *image, Drawable_t drawable, imageX = 0; } + // no need to paint if any visisble dimension is not-positive + // this happens when image is not shown on currently painted region + if ((imageH <= 0) || (imageW <= 0)) + return; + TImage *img = image->fPImage->fImage; + if (!img) + return; - imageH = imageH < 0 ? -imageH : imageH; - imageW = imageW < 0 ? -imageW : imageW; + if ((imageX == 0) && (imageY == 0) && (imageW == image->fW) && (imageH == image->fH)) { + TASUtils::PaintImage(img, drawable, x, y); + } else { + std::unique_ptr cloned((TImage *) img->Clone("crop_img")); + cloned->Crop(imageX, imageY, imageW, imageH); + TASUtils::PaintImage(cloned.get(), drawable, x, y); + } - img->PaintImage(drawable, x, y, imageX, imageY, imageW, imageH); //gVirtualX->Update(kFALSE); image->fRedrawNeeded = 0; @@ -891,7 +903,7 @@ void TGHtml::DrawTableBgnd(int l, int t, int w, int h, w -= sw; } #else - auto img_pixmap = TGWindow::GetImagePixmap(image); + auto img_pixmap = TASUtils::GetPixmap(image); if (!img_pixmap) return; GContext_t gc = GetAnyGC(); GCValues_t gcv; diff --git a/gui/guihtml/src/TGHtmlSizer.cxx b/gui/guihtml/src/TGHtmlSizer.cxx index 46dff10b952fb..433c2c2db4a9e 100644 --- a/gui/guihtml/src/TGHtmlSizer.cxx +++ b/gui/guihtml/src/TGHtmlSizer.cxx @@ -27,6 +27,7 @@ #include "TGHtml.h" #include "TImage.h" +#include "TASUtils.h" #include "TVirtualX.h" #include @@ -353,10 +354,10 @@ void TGHtml::AddStyle(TGHtmlElement *p) // unsigned int mask; // mask = kGCTile | kGCFillStyle | kGCGraphicsExposures; - gcv.fTile = TGWindow::GetImagePixmap(img); + gcv.fTile = TASUtils::GetPixmap(img); gcv.fFillStyle = kFillTiled; gcv.fGraphicsExposures = kTRUE; - fCanvas->SetBackgroundPixmap(TGWindow::GetImagePixmap(img)); + fCanvas->SetBackgroundPixmap(TASUtils::GetPixmap(img)); gVirtualX->ChangeGC(fWhiteGC.GetGC(), &gcv); diff --git a/roottest/root/treeformula/string/execAliasString.ref b/roottest/root/treeformula/string/execAliasString.ref index ddc2ca9f31a38..bd4733bc5aed1 100644 --- a/roottest/root/treeformula/string/execAliasString.ref +++ b/roottest/root/treeformula/string/execAliasString.ref @@ -1,11 +1,11 @@ Processing execAliasString.C... -Info in : created default TCanvas with name c1 ************************************** * Row * name.name * count.count * ************************************** * 0 * 16A * 3 * * 1 * 17B * 2 * ************************************** +Info in : created default TCanvas with name c1 *********************************** * Row * first?name:"not f... * *********************************** diff --git a/roottest/root/treeproxy/execsearch.ref b/roottest/root/treeproxy/execsearch.ref index 16aaf476e1419..25dd2554f9997 100644 --- a/roottest/root/treeproxy/execsearch.ref +++ b/roottest/root/treeproxy/execsearch.ref @@ -2,7 +2,7 @@ Processing execsearch.C... Warning in : no dictionary for class ND::P0D::NueEvtInfo is available Warning in : no dictionary for class ND::P0D::TVertex is available Warning in : no dictionary for class ND::P0D::TPID is available -Info in : created default TCanvas with name c1 trajPos.fP.fX[1]=635.86 trajPos.fP[1].fX=635.86 trajPos[1].fP.fX=635.86 +Info in : created default TCanvas with name c1 diff --git a/roottest/root/treeproxy/valdim3.ref b/roottest/root/treeproxy/valdim3.ref index f49e2513144c9..0f585d9a53fe3 100644 --- a/roottest/root/treeproxy/valdim3.ref +++ b/roottest/root/treeproxy/valdim3.ref @@ -1,5 +1,4 @@ Processing runvaldim3.C... -Info in : created default TCanvas with name c1 ntracks = 2 trs[0].a = 0 trs[0].bb[0] = 0.000000 @@ -60,3 +59,4 @@ a[1][2][0] = 120 a[1][2][1] = 121 a[1][2][2] = 122 a[1][2][3] = 123 +Info in : created default TCanvas with name c1 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2eebde410858f..c4d75e93b327a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -207,7 +207,7 @@ ROOT_ADD_TEST(test-stresshistogram-interpreted COMMAND ${root_exe} -b -q ${CMAKE #--stressGUI--------------------------------------------------------------------------------------- if(asimage) - ROOT_EXECUTABLE(stressGUI stressGUI.cxx LIBRARIES Gui Recorder GuiHtml ASImageGui) + ROOT_EXECUTABLE(stressGUI stressGUI.cxx LIBRARIES Gui Recorder GuiHtml ASImageUtils ASImageGui) find_program(XVFB_RUN_EXECUTABLE NAMES xvfb-run) diff --git a/test/stressGUI.cxx b/test/stressGUI.cxx index 52f9b4b407b72..3556d867a7e8f 100644 --- a/test/stressGUI.cxx +++ b/test/stressGUI.cxx @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -175,7 +176,7 @@ void ProcessFrame(TGFrame *f, const char *title) outfile.Form("sgui_%02d.png", gTestNum); f->RaiseWindow(); - auto img = TGWindow::CreateImageFromWindow(f->GetId()); + auto img = TASUtils::FromWindow(f->GetId()); if (img) img->WriteImage(outfile); diff --git a/tutorials/visualisation/eve/SplitGLView.C b/tutorials/visualisation/eve/SplitGLView.C index 71beecc3e41ad..24fb03c97e666 100644 --- a/tutorials/visualisation/eve/SplitGLView.C +++ b/tutorials/visualisation/eve/SplitGLView.C @@ -299,7 +299,8 @@ void TGShapedToolTip::Refresh() nlines++; img->DrawText(fTextX, fTextY + (nlines * size), s, size, fTextCol, ar); } - img->PaintImage(fId, 0, 0, 0, 0, 0, 0, "opaque"); + // use instead deprecated img->PaintImage() + TASUtils::PaintImage(img, fId, 0, 0, kTRUE); free(string); delete img; gVirtualX->Update(); diff --git a/tutorials/visualisation/gui/drag_and_drop.C b/tutorials/visualisation/gui/drag_and_drop.C index 63bdaded3acdb..ce35f6eb84352 100644 --- a/tutorials/visualisation/gui/drag_and_drop.C +++ b/tutorials/visualisation/gui/drag_and_drop.C @@ -195,7 +195,7 @@ DNDMainFrame::DNDMainFrame(const TGWindow *p, int w, int h) : TGMainFrame(p, w, if (img) { // create a 16x16 icon from the original picture img->Scale(16, 16); - pic = gClient->GetPicturePool()->GetPicture("rose512", TGWindow::GetImagePixmap(img), TGWindow::GetImageMask(img)); + pic = gClient->GetPicturePool()->GetPicture("rose512", TASUtils::GetPixmap(img), TASUtils::GetMask(img)); delete img; } else pic = gClient->GetPicture("psp_t.xpm"); @@ -284,7 +284,7 @@ void DNDMainFrame::DataDropped(TGListTreeItem *, TDNDData *data) TImage *img2 = TImage::Open("slink_t.xpm"); if (img1 && img2) { img1->Merge(img2); - pic = gClient->GetPicturePool()->GetPicture("doc_lnk", TGWindow::GetImagePixmap(img1), TGWindow::GetImageMask(img1)); + pic = gClient->GetPicturePool()->GetPicture("doc_lnk", TASUtils::GetPixmap(img1), TASUtils::GetMask(img1)); delete img2; delete img1; } else diff --git a/tutorials/visualisation/gui/exec_macro.C b/tutorials/visualisation/gui/exec_macro.C index da6ad424c73db..67bf8f0214463 100644 --- a/tutorials/visualisation/gui/exec_macro.C +++ b/tutorials/visualisation/gui/exec_macro.C @@ -61,7 +61,7 @@ Int_t exec_macro(const char *macro, Bool_t comp = kFALSE, Bool_t save = kTRUE) outfile.ReplaceAll(".C", TString::Format("_%d.png", ++nMainFrames)); win->RaiseWindow(); - auto img = TGWindow::CreateImageFromWindow(win->GetId()); + auto img = TASUtils::FromWindow(win->GetId()); if (img) img->WriteImage(outfile.Data()); }