diff --git a/core/base/inc/TVirtualPS.h b/core/base/inc/TVirtualPS.h index 604caedfa7dea..17fb37b3a6c39 100644 --- a/core/base/inc/TVirtualPS.h +++ b/core/base/inc/TVirtualPS.h @@ -27,6 +27,8 @@ #include "TAttText.h" #include "TAttMarker.h" +class TImage; + class TVirtualPS : public TNamed, public TAttLine, public TAttFill, public TAttMarker, public TAttText { private: @@ -54,6 +56,9 @@ class TVirtualPS : public TNamed, public TAttLine, public TAttFill, public TAttM virtual void CellArrayFill(Int_t r, Int_t g, Int_t b) = 0; virtual void CellArrayPng(char * /* buffer */, int /* size */) {} virtual void CellArrayEnd() = 0; + + virtual void DrawImage(TImage * /* img */, Int_t /* x */, Int_t /* y */ , Int_t /* flags */ = 0) {} + virtual void Close(Option_t *opt="") = 0; virtual void DrawBox(Double_t x1, Double_t y1,Double_t x2, Double_t y2) = 0; virtual void DrawFrame(Double_t xl, Double_t yl, Double_t xt, Double_t yt, diff --git a/core/base/inc/TVirtualPadPainter.h b/core/base/inc/TVirtualPadPainter.h index 79d1b22cb6ee6..9ad912fc32831 100644 --- a/core/base/inc/TVirtualPadPainter.h +++ b/core/base/inc/TVirtualPadPainter.h @@ -17,6 +17,7 @@ class TVirtualPad; class TVirtualPS; +class TImage; class TAttFill; class TAttLine; class TAttMarker; @@ -151,6 +152,8 @@ class TVirtualPadPainter { virtual void DrawTextUrl(Double_t x, Double_t y, const char *text, const char *url); + virtual void DrawImage(TImage *img, Int_t x, Int_t y, Int_t flags = 0); + //gif, jpg, png, bmp output. virtual void SaveImage(TVirtualPad *pad, const char *fileName, Int_t type) const = 0; diff --git a/core/base/src/TVirtualPadPainter.cxx b/core/base/src/TVirtualPadPainter.cxx index e3c6795cdd82e..cec650fa652a5 100644 --- a/core/base/src/TVirtualPadPainter.cxx +++ b/core/base/src/TVirtualPadPainter.cxx @@ -212,3 +212,10 @@ void TVirtualPadPainter::SetCursor(Int_t device, ECursor cursor) gVirtualX->SetCursor(device, cursor); } + +//////////////////////////////////////////////////////////////////////////////// +/// Draw image, need to be implemented in correspondent + +void TVirtualPadPainter::DrawImage(TImage *, Int_t, Int_t, Int_t) +{ +} diff --git a/graf2d/asimage/src/TASImage.cxx b/graf2d/asimage/src/TASImage.cxx index f3589b32740b5..45761ecc22bc8 100644 --- a/graf2d/asimage/src/TASImage.cxx +++ b/graf2d/asimage/src/TASImage.cxx @@ -86,6 +86,7 @@ ROOT tutorials: `$ROOTSYS/tutorials/visualisation/image/` #include "TVirtualX.h" #include +#include #include #include "snprintf.h" @@ -1230,13 +1231,13 @@ void TASImage::Image2Drawable(ASImage *im, Drawable_t wid, Int_t x, Int_t y, Int_t xsrc, Int_t ysrc, UInt_t wsrc, UInt_t hsrc, Option_t *opt) { - if (!im) return; + if (!im) + return; wsrc = wsrc ? wsrc : im->width; hsrc = hsrc ? hsrc : im->height; - static int x11 = -1; - if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11"); + static int x11 = gVirtualX->InheritsFrom("TGX11"); Pixmap_t mask = kNone; @@ -1245,21 +1246,18 @@ void TASImage::Image2Drawable(ASImage *im, Drawable_t wid, Int_t x, Int_t y, UInt_t ow = wsrc%8; UInt_t ww = wsrc - ow + (ow ? 8 : 0); - UInt_t bit = 0; - int i = 0; - UInt_t yy = 0; - UInt_t xx = 0; + UInt_t bit = 0, i = 0; - char *bits = new char[ww*hh]; //an array of bits + std::vector bits(ww*hh); //an array of bits ASImageDecoder *imdec = start_image_decoding(fgVisual, im, SCL_DO_ALPHA, xsrc, ysrc, ww, 0, nullptr); if (imdec) { - for (yy = 0; yy < hh; yy++) { + for (UInt_t yy = 0; yy < hh; yy++) { imdec->decode_image_scanline(imdec); CARD32 *a = imdec->buffer.alpha; - for (xx = 0; xx < ww; xx++) { + for (UInt_t xx = 0; xx < ww; xx++) { if (a[xx]) { SETBIT(bits[i], bit); } else { @@ -1277,8 +1275,7 @@ void TASImage::Image2Drawable(ASImage *im, Drawable_t wid, Int_t x, Int_t y, stop_image_decoding(&imdec); mask = gVirtualX->CreateBitmap(gVirtualX->GetDefaultRootWindow(), - (const char *)bits, ww, hh); - delete [] bits; + bits.data(), ww, hh); } GCValues_t gv; @@ -1295,7 +1292,7 @@ void TASImage::Image2Drawable(ASImage *im, Drawable_t wid, Int_t x, Int_t y, gVirtualX->ChangeGC(gc, &gv); } - if (x11 && (!gPad || gPad->GetGLDevice() == -1)) { //use built-in optimized version + if (x11) { //use built-in optimized version asimage2drawable(fgVisual, wid, im, (GC)gc, xsrc, ysrc, x, y, wsrc, hsrc, 1); } else { ASImage *img = nullptr; @@ -1311,33 +1308,29 @@ void TASImage::Image2Drawable(ASImage *im, Drawable_t wid, Int_t x, Int_t y, TString option(opt); option.ToLower(); - if (gPad && gPad->GetGLDevice() != -1) { - if (TVirtualPadPainter *painter = gPad->GetPainter()) - painter->DrawPixels(bits, wsrc, hsrc, x, y, !option.Contains("opaque")); - } else { - Pixmap_t pic = gVirtualX->CreatePixmapFromData(bits, wsrc, hsrc); - if (pic) { - if (!option.Contains("opaque")) { - SETBIT(wsrc,31); - SETBIT(hsrc,31); - } - gVirtualX->CopyArea(pic, wid, gc, 0, 0, wsrc, hsrc, x, y); - gVirtualX->DeletePixmap(pic); + Pixmap_t pic = gVirtualX->CreatePixmapFromData(bits, wsrc, hsrc); + if (pic) { + if (!option.Contains("opaque")) { + SETBIT(wsrc,31); + SETBIT(hsrc,31); } + gVirtualX->CopyArea(pic, wid, gc, 0, 0, wsrc, hsrc, x, y); + gVirtualX->DeletePixmap(pic); } } - if (img) { + if (img) destroy_asimage(&img); - } } // free mask pixmap - if (gv.fClipMask != kNone) gVirtualX->DeletePixmap(gv.fClipMask); + if (mask != kNone) + gVirtualX->DeletePixmap(mask); gv.fMask = kGCClipMask; gv.fClipMask = kNone; - if (gc) gVirtualX->ChangeGC(gc, &gv); + if (gc) + gVirtualX->ChangeGC(gc, &gv); } @@ -1411,6 +1404,9 @@ void TASImage::Paint(Option_t *option) } } + // opaque flag used in some X11 + Int_t flags = opt.Contains("opaque") ? 0 : 1; + ASImage *image = fImage; // Get geometry of pad @@ -1536,173 +1532,42 @@ void TASImage::Paint(Option_t *option) int tox = expand ? 0 : int(gPad->UtoPixel(1.) * gPad->GetLeftMargin()); int toy = expand ? 0 : int(gPad->VtoPixel(0.) * gPad->GetTopMargin()); - auto ps = gPad->GetPainter()->GetPS(); + auto pp = gPad->GetPainter(); - if (!ps) { - Window_t wid = (Window_t)gVirtualX->GetWindowID(gPad->GetPixmapID()); - Image2Drawable(fScaledImage ? fScaledImage->fImage : fImage, wid, tox, toy); + pp->DrawImage(fScaledImage ? fScaledImage : this, tox, toy, flags); - if (grad_im && fPaletteEnabled) { - // draw color bar - Image2Drawable(grad_im, wid, pal_x, pal_y); + if (grad_im && fPaletteEnabled) { + TASImage pimg; + pimg.fImage = grad_im; + grad_im = nullptr; // will be delete with pimg destructor - // values of palette - TGaxis axis; - Int_t ndiv = 510; - double min = fMinValue; - double max = fMaxValue; + // draw color bar + pp->DrawImage(&pimg, pal_x, pal_y, flags); + + // values of palette + TGaxis axis; + Int_t ndiv = 510; + Double_t min = fMinValue; + Double_t max = fMaxValue; + Double_t pal_Xpos = gPad->AbsPixeltoX(pal_Ax + pal_w); + if (!pp->GetPS()) { + // TODO: check why here special drawing for none-PS axis.SetLineColor(0); // draw white ticks - Double_t pal_Xpos = gPad->AbsPixeltoX(pal_Ax + pal_w); axis.PaintAxis(pal_Xpos, gPad->PixeltoY(pal_Ay + pal_h - 1), pal_Xpos, gPad->PixeltoY(pal_Ay), min, max, ndiv, "+LU"); min = fMinValue; max = fMaxValue; - axis.SetLineColor(1); // draw black ticks - axis.PaintAxis(pal_Xpos, gPad->AbsPixeltoY(pal_Ay + pal_h), - pal_Xpos, gPad->AbsPixeltoY(pal_Ay + 1), - min, max, ndiv, "+L"); - } - } else { - // loop over pixmap and draw image to PostScript - - Bool_t paint_as_png = kFALSE; - - if (ps->InheritsFrom("TImageDump")) { // PostScript is asimage - TImage *dump = (TImage *)ps->GetStream(); - if (!dump) return; - dump->Merge(fScaledImage ? fScaledImage : this, "alphablend", - gPad->XtoAbsPixel(0), gPad->YtoAbsPixel(1)); - - if (grad_im) { - TASImage tgrad; - tgrad.fImage = grad_im; - dump->Merge(&tgrad, "alphablend", pal_Ax, pal_Ay); - - // values of palette - TGaxis axis; - Int_t ndiv = 510; - double min = fMinValue; - double max = fMaxValue; - axis.SetLineColor(1); // draw black ticks - Double_t pal_Xpos = gPad->AbsPixeltoX(pal_Ax + pal_w); - axis.PaintAxis(pal_Xpos, gPad->AbsPixeltoY(pal_Ay + pal_h), - pal_Xpos, gPad->AbsPixeltoY(pal_Ay + 1), - min, max, ndiv, "+L"); - } - return; - } else if (ps->InheritsFrom("TSVG")) { - paint_as_png = kTRUE; - } - - Double_t dx = gPad->GetX2() - gPad->GetX1(); - Double_t dy = gPad->GetY2() - gPad->GetY1(); - Double_t x1, x2, y1, y2; - - if (expand) { - x1 = gPad->GetX1(); - x2 = x1+dx/image->width; - y1 = gPad->GetY2(); - y2 = y1+dy/image->height; - } else { - x1 = gPad->GetX1()+dx*gPad->GetLeftMargin(); - x2 = x1+(dx*(1-gPad->GetRightMargin()-gPad->GetLeftMargin()))/image->width; - y1 = gPad->GetY2()-dy*gPad->GetTopMargin(); - y2 = y1+(dy*(1-gPad->GetTopMargin()-gPad->GetBottomMargin()))/image->height; } - // get special color cell to be reused during image printing - ps->SetFillColor(TColor::GetColor((Float_t) 1., (Float_t) 1., (Float_t) 1.)); - ps->SetFillStyle(1001); - - ps->CellArrayBegin(image->width, image->height, x1, x2, y1, y2); - - if (paint_as_png) { - char *buffer = nullptr; - int size = 0; - ASImageExportParams params; - params.png.type = ASIT_Png; - params.png.flags = EXPORT_ALPHA; - params.png.compression = GetImageCompression(); - if (!params.png.compression) - params.png.compression = -1; - if (ASImage2PNGBuff(image, (CARD8 **)&buffer, &size, ¶ms)) { - ps->CellArrayPng(buffer, size); - free(buffer); - } - } else { - auto imdec = start_image_decoding(fgVisual, image, SCL_DO_ALL, - 0, 0, image->width, image->height, nullptr); - if (imdec) - for (Int_t yt = 0; yt < (Int_t)image->height; yt++) { - imdec->decode_image_scanline(imdec); - for (Int_t xt = 0; xt < (Int_t)image->width; xt++) - ps->CellArrayFill(imdec->buffer.red[xt], - imdec->buffer.green[xt], - imdec->buffer.blue[xt]); - } - stop_image_decoding(&imdec); - } - ps->CellArrayEnd(); - - // print the color bar - if (grad_im) { - Double_t xconv = (gPad->AbsPixeltoX(pal_Ax + pal_w) - gPad->AbsPixeltoX(pal_Ax)) / grad_im->width; - Double_t yconv = (gPad->AbsPixeltoY(pal_Ay - pal_h) - gPad->AbsPixeltoY(pal_Ay)) / grad_im->height; - x1 = gPad->AbsPixeltoX(pal_Ax); - x2 = x1 + xconv; - y2 = gPad->AbsPixeltoY(pal_Ay); - y1 = y2 - yconv; - ps->CellArrayBegin(grad_im->width, grad_im->height, - x1, x2, y1, y2); - - if (paint_as_png) { - char *buffer = nullptr; - int size = 0; - ASImageExportParams params; - params.png.type = ASIT_Png; - params.png.flags = EXPORT_ALPHA; - params.png.compression = GetImageCompression(); - if (!params.png.compression) - params.png.compression = -1; - - if (ASImage2PNGBuff(grad_im, (CARD8 **)&buffer, &size, ¶ms)) { - ps->CellArrayPng(buffer, size); - free(buffer); - } - } else { - auto imdec = start_image_decoding(fgVisual, grad_im, SCL_DO_ALL, - 0, 0, grad_im->width, grad_im->height, nullptr); - if (imdec) - for (Int_t yt = 0; yt < (Int_t)grad_im->height; yt++) { - imdec->decode_image_scanline(imdec); - for (Int_t xt = 0; xt < (Int_t)grad_im->width; xt++) - ps->CellArrayFill(imdec->buffer.red[xt], - imdec->buffer.green[xt], - imdec->buffer.blue[xt]); - } - stop_image_decoding(&imdec); - } - ps->CellArrayEnd(); - - // values of palette - TGaxis axis; - Int_t ndiv = 510; - double min = fMinValue; - double max = fMaxValue; - axis.SetLineColor(1); // draw black ticks - Double_t pal_Xpos = gPad->AbsPixeltoX(pal_Ax + pal_w); - // TODO: provide PaintAxisOn method - axis.PaintAxis(pal_Xpos, gPad->AbsPixeltoY(pal_Ay + pal_h), - pal_Xpos, gPad->AbsPixeltoY(pal_Ay + 1), - min, max, ndiv, "+L"); - - } + axis.SetLineColor(1); // draw black ticks + axis.PaintAxis(pal_Xpos, gPad->AbsPixeltoY(pal_Ay + pal_h), + pal_Xpos, gPad->AbsPixeltoY(pal_Ay + 1), + min, max, ndiv, "+L"); } - if (grad_im) { + if (grad_im) destroy_asimage(&grad_im); - } } //////////////////////////////////////////////////////////////////////////////// @@ -5773,7 +5638,7 @@ void TASImage::DrawTextTTF(Int_t x, Int_t y, const char *text, Int_t size, ttf.PrepareString(text); ttf.LayoutGlyphs(); - if (ttf.ApplyAlignRotate(x, y, 11, GetWidth(), GetHeight())) + if (ttf.ApplyAlignRotate(x, y, 13, GetWidth(), GetHeight())) DrawFTGlyphs(ttf, color, x, y); } diff --git a/graf2d/gpad/inc/TPadPainter.h b/graf2d/gpad/inc/TPadPainter.h index 17275ae1d7c39..08aa50a76f0e3 100644 --- a/graf2d/gpad/inc/TPadPainter.h +++ b/graf2d/gpad/inc/TPadPainter.h @@ -79,6 +79,8 @@ class TPadPainter : public TPadPainterBase { void DrawTTFglyphs(Int_t x, Int_t y, TTFhandle &ttf, ETextMode mode) override; + void DrawImage(TImage *img, Int_t x, Int_t y, Int_t flags = 0) override; + //jpg, png, bmp, gif output. void SaveImage(TVirtualPad *pad, const char *fileName, Int_t type) const override; diff --git a/graf2d/gpad/inc/TPadPainterPS.h b/graf2d/gpad/inc/TPadPainterPS.h index 64b7a33c6f1da..aaa2a83316f7e 100644 --- a/graf2d/gpad/inc/TPadPainterPS.h +++ b/graf2d/gpad/inc/TPadPainterPS.h @@ -85,6 +85,8 @@ class TPadPainterPS : public TPadPainterBase { void DrawTextUrl(Double_t x, Double_t y, const char *text, const char *url) override; + void DrawImage(TImage *img, Int_t x, Int_t y, Int_t flags = 0) override; + //jpg, png, bmp, gif output. void SaveImage(TVirtualPad *pad, const char *fileName, Int_t type) const override; diff --git a/graf2d/gpad/src/TPadPainter.cxx b/graf2d/gpad/src/TPadPainter.cxx index f2ebd73efceb0..2c887fcd735df 100644 --- a/graf2d/gpad/src/TPadPainter.cxx +++ b/graf2d/gpad/src/TPadPainter.cxx @@ -213,6 +213,15 @@ Bool_t TPadPainter::HasTTFonts() const return gVirtualX->HasTTFonts(); } +//////////////////////////////////////////////////////////////////////////////// +/// Draw image on the gVirtualX window + +void TPadPainter::DrawImage(TImage *img, Int_t x, Int_t y, Int_t flags) +{ + Window_t wid = (Window_t)gVirtualX->GetWindowID(fPad->GetPixmapID()); + // use old API to draw image on gVirtualX window + img->PaintImage(wid, x, y, 0, 0, 0, 0, flags ? "" : "opaque"); +} //////////////////////////////////////////////////////////////////////////////// ///Noop, for non-gl pad TASImage calls gVirtualX->CopyArea. diff --git a/graf2d/gpad/src/TPadPainterPS.cxx b/graf2d/gpad/src/TPadPainterPS.cxx index ce9165e07b5ff..c36328a912dc7 100644 --- a/graf2d/gpad/src/TPadPainterPS.cxx +++ b/graf2d/gpad/src/TPadPainterPS.cxx @@ -421,6 +421,19 @@ void TPadPainterPS::DrawTextNDC(Double_t u, Double_t v, const char *text, ETextM } +//////////////////////////////////////////////////////////////////////////////// +/// Draw image on the PS output + +void TPadPainterPS::DrawImage(TImage *img, Int_t x, Int_t y, Int_t flags) +{ + // transfer to absolute pixel coordiantes for PS + x += fPad->UtoAbsPixel(0); + y += fPad->VtoAbsPixel(1); + + fPS->DrawImage(img, x, y, flags); +} + + //////////////////////////////////////////////////////////////////////////////// /// Save the image displayed in the canvas pointed by "pad" into a binary file. diff --git a/graf2d/postscript/inc/TImageDump.h b/graf2d/postscript/inc/TImageDump.h index 49df2d8f0561e..9ae6f6ac7b241 100644 --- a/graf2d/postscript/inc/TImageDump.h +++ b/graf2d/postscript/inc/TImageDump.h @@ -50,6 +50,8 @@ class TImageDump : public TVirtualPS { void CellArrayBegin(Int_t W, Int_t H, Double_t x1, Double_t x2, Double_t y1, Double_t y2) override; void CellArrayFill(Int_t r, Int_t g, Int_t b) override; void CellArrayEnd() override; + void DrawImage(TImage *img, Int_t x, Int_t y , Int_t flags = 0) override; + void Close(Option_t *opt = "") override; void DrawBox(Double_t x1, Double_t y1,Double_t x2, Double_t y2) override; void DrawFrame(Double_t xl, Double_t yl, Double_t xt, Double_t yt, diff --git a/graf2d/postscript/inc/TPDF.h b/graf2d/postscript/inc/TPDF.h index 81a68b2d82edd..c00145a560982 100644 --- a/graf2d/postscript/inc/TPDF.h +++ b/graf2d/postscript/inc/TPDF.h @@ -103,6 +103,9 @@ class TPDF : public TVirtualPS { void CellArrayBegin(Int_t W, Int_t H, Double_t x1, Double_t x2, Double_t y1, Double_t y2) override; void CellArrayFill(Int_t r, Int_t g, Int_t b) override; void CellArrayEnd() override; + + void DrawImage(TImage *img, Int_t x, Int_t y, Int_t flags = 0) override; + void Close(Option_t *opt = "") override; Double_t CMtoPDF(Double_t u) { return Int_t(0.5 + 72 * u / 2.54); } void ComputeRect(const char* chars, Double_t fontsize, Double_t a, Double_t b, Double_t c, Double_t d, Double_t e, Double_t f); diff --git a/graf2d/postscript/inc/TPostScript.h b/graf2d/postscript/inc/TPostScript.h index d84e4d6d1bb9a..d36860dbf9fd0 100644 --- a/graf2d/postscript/inc/TPostScript.h +++ b/graf2d/postscript/inc/TPostScript.h @@ -98,6 +98,7 @@ class TPostScript : public TVirtualPS { Double_t y1, Double_t y2) override; void CellArrayFill(Int_t r, Int_t g, Int_t b) override; void CellArrayEnd() override; + void DrawImage(TImage *img, Int_t x, Int_t y, Int_t flags = 0) override; void Close(Option_t *opt="") override; Int_t CMtoPS(Double_t u) {return Int_t(0.5 + 72*u/2.54);} void DrawBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2) override; diff --git a/graf2d/postscript/inc/TSVG.h b/graf2d/postscript/inc/TSVG.h index cee6b15b1f265..5b6a2999f2143 100644 --- a/graf2d/postscript/inc/TSVG.h +++ b/graf2d/postscript/inc/TSVG.h @@ -46,6 +46,9 @@ class TSVG : public TVirtualPS { void CellArrayFill(Int_t r, Int_t g, Int_t b) override; void CellArrayPng(char *buffer, int size) override; void CellArrayEnd() override; + + void DrawImage(TImage *img, Int_t x, Int_t y , Int_t flags = 0) override; + void Close(Option_t *opt="") override; Double_t CMtoSVG(Double_t u) { return 0.5 + 72*u/2.54; } void DrawBox(Double_t x1, Double_t y1,Double_t x2, Double_t y2) override; diff --git a/graf2d/postscript/src/TImageDump.cxx b/graf2d/postscript/src/TImageDump.cxx index a3ffca6fe8a24..2c3e4011713db 100644 --- a/graf2d/postscript/src/TImageDump.cxx +++ b/graf2d/postscript/src/TImageDump.cxx @@ -624,6 +624,16 @@ void TImageDump::CellArrayEnd() fCellArrayY2 = 0; } +//////////////////////////////////////////////////////////////////////////////// +/// Draw image + +void TImageDump::DrawImage(TImage *img, Int_t x, Int_t y, Int_t) +{ + if (fImage) + fImage->Merge(img, "alphablend", x, y); +} + + //////////////////////////////////////////////////////////////////////////////// /// Set color with its R G B components /// diff --git a/graf2d/postscript/src/TPDF.cxx b/graf2d/postscript/src/TPDF.cxx index e1cd9b10d10ac..3d67b69be8d97 100644 --- a/graf2d/postscript/src/TPDF.cxx +++ b/graf2d/postscript/src/TPDF.cxx @@ -64,6 +64,7 @@ the table of contents. #include "TVirtualPad.h" #include "TPoint.h" #include "TPoints.h" +#include "TImage.h" #include "TPDF.h" #include "TStyle.h" #include "TMath.h" @@ -259,6 +260,51 @@ void TPDF::CellArrayEnd() fCellArrayRGB.shrink_to_fit(); } +//////////////////////////////////////////////////////////////////////////////// +/// Draw image in the PDF + +void TPDF::DrawImage(TImage *img, Int_t x, Int_t y, Int_t) +{ + Int_t width = img->GetWidth(); + Int_t height = img->GetHeight(); + + auto x1 = gPad->AbsPixeltoX(x); + auto x2 = gPad->AbsPixeltoX(x + width); + auto y1 = gPad->AbsPixeltoY(y); + auto y2 = gPad->AbsPixeltoY(y + height); + + fCellArrayW = width; + fCellArrayH = height; + + Double_t xLeft = XtoPDF(x1); + Double_t xRight = XtoPDF(x2); + Double_t yTop = YtoPDF(y1); + Double_t yBot = YtoPDF(y2); + + fCellArrayXpdf = xLeft; + fCellArrayYpdfBot = yBot; + fCellArrayWpdf = xRight - xLeft; + fCellArrayHpdf = yTop - yBot; + + auto argb = img->GetArgbArray(); + if (!argb) { + Error("DrawImage", "Fail to access to ARGB values"); + return; + } + + fCellArrayRGB.resize(3 * width * height); + for (Int_t i = 0; i < width * height; ++i) { + UInt_t p = argb[i]; + fCellArrayRGB[i*3] = static_cast((p >> 16) & 0xFF); + fCellArrayRGB[i*3 + 1] = static_cast((p >> 8) & 0xFF); + fCellArrayRGB[i*3 + 2] = static_cast(p & 0xFF); + } + + // use old method, move here once old API is deprecated + CellArrayEnd(); +} + + //////////////////////////////////////////////////////////////////////////////// /// Close a PDF file diff --git a/graf2d/postscript/src/TPostScript.cxx b/graf2d/postscript/src/TPostScript.cxx index d65ca29240fe3..08ea96937c50b 100644 --- a/graf2d/postscript/src/TPostScript.cxx +++ b/graf2d/postscript/src/TPostScript.cxx @@ -244,6 +244,7 @@ To change the color model use `gStyle->SetColorModelPS(c)`. #include "TVirtualPad.h" #include "TPoints.h" #include "TPoint.h" +#include "TImage.h" #include "TPostScript.h" #include "TStyle.h" #include "TMath.h" @@ -621,6 +622,102 @@ void TPostScript::CellArrayEnd() PrintStr(" def DrawCT "); } +//////////////////////////////////////////////////////////////////////////////// +/// Draw image in postscript + +void TPostScript::DrawImage(TImage *img, Int_t x, Int_t y, Int_t) +{ + auto argb = img->GetArgbArray(); + if (!argb) { + Error("DrawImage", "Fail to access ARGB values"); + return; + } + + Int_t width = img->GetWidth(); + Int_t height = img->GetHeight(); + + auto x1 = gPad->AbsPixeltoX(x); + auto x2 = gPad->AbsPixeltoX(x + width); + auto y1 = gPad->AbsPixeltoY(y); + auto y2 = gPad->AbsPixeltoY(y - height); + + Int_t ix1 = XtoPS(x1); + Int_t iy1 = YtoPS(y1); + Int_t ix2 = XtoPS(x2); + Int_t iy2 = YtoPS(y2); + + Float_t wt = (0. + ix2 - ix1) / width; + Float_t ht = (0. + iy2 - iy1) / height; + + fLastCellRed = 300; + fLastCellGreen = 300; + fLastCellBlue = 300; + fNBSameColorCell = 0; + + fNbinCT = 0; + fNbCellW = width; + fNbCellLine = 0; + fMaxLines = 40000/(3*fNbCellW); + + // Define some parameters + PrintStr("@/WT"); WriteReal(wt) ; PrintStr(" def"); // Cells width + PrintStr(" /HT"); WriteReal(ht) ; PrintStr(" def"); // Cells height + PrintStr(" /XS"); WriteInteger(ix1) ; PrintStr(" def"); // X start + PrintStr(" /YY"); WriteInteger(iy1) ; PrintStr(" def"); // Y start + PrintStr(" /NX"); WriteInteger(width) ; PrintStr(" def"); // Number of columns + PrintStr(" /NY"); WriteInteger(fMaxLines); PrintStr(" def"); // Number of lines + + // This PS procedure draws one cell. + PrintStr(" /DrawCell "); + PrintStr( "{WT HT XX YY bf"); + PrintStr( " /NBBD NBBD 1 add def"); + PrintStr( " NBBD NBB eq {exit} if"); + PrintStr( " /XX WT XX add def"); + PrintStr( " IX NX eq "); + PrintStr( "{/YY YY HT sub def"); + PrintStr( " /XX XS def"); + PrintStr( " /IX 0 def} if"); + PrintStr( " /IX IX 1 add def} def"); + + // This PS procedure draws fMaxLines line. It takes care of duplicated + // colors. Values "n" greater than 300 mean than the previous color + // should be duplicated n-300 times. + PrintStr(" /DrawCT "); + PrintStr( "{/NBB NX NY mul def"); + PrintStr( " /XX XS def"); + PrintStr( " /IX 1 def"); + PrintStr( " /NBBD 0 def"); + PrintStr( " /RC 0 def /GC 1 def /BC 2 def"); + PrintStr( " 1 1 NBB "); + PrintStr( "{/NB CT RC get def"); + PrintStr( " NB 301 ge "); + PrintStr( "{/NBL NB 300 sub def"); + PrintStr( " 1 1 NBL "); + PrintStr( "{DrawCell}"); + PrintStr( " for"); + PrintStr( " /RC RC 1 add def"); + PrintStr( " /GC RC 1 add def"); + PrintStr( " /BC RC 2 add def}"); + PrintStr( "{CT RC get 255 div CT GC get 255 div CT BC get 255 div setrgbcolor"); + PrintStr( " DrawCell"); + PrintStr( " /RC RC 3 add def"); + PrintStr( " /GC GC 3 add def"); + PrintStr( " /BC BC 3 add def} ifelse NBBD NBB eq {exit} if} for"); + PrintStr( " /YY YY HT sub def clear} def"); + + PrintStr(" /CT ["); + + // use old API, move here once old is deprecated + for (Int_t i = 0; i < width * height; ++i) { + UInt_t p = argb[i]; + auto r = static_cast((p >> 16) & 0xFF); + auto g = static_cast((p >> 8) & 0xFF); + auto b = static_cast(p & 0xFF); + CellArrayFill(r, g, b); + } + + CellArrayEnd(); +} //////////////////////////////////////////////////////////////////////////////// /// Draw a Box diff --git a/graf2d/postscript/src/TSVG.cxx b/graf2d/postscript/src/TSVG.cxx index 01759e4cda013..435371d594955 100644 --- a/graf2d/postscript/src/TSVG.cxx +++ b/graf2d/postscript/src/TSVG.cxx @@ -26,6 +26,7 @@ #include "TVirtualPad.h" #include "TPoint.h" #include "TPoints.h" +#include "TImage.h" #include "TSVG.h" #include "TStyle.h" #include "TMath.h" @@ -752,6 +753,53 @@ void TSVG::CellArrayEnd() PrintStr("@"); } +//////////////////////////////////////////////////////////////////////////////// +/// Draw image in the SVG +/// Replaces CellArray methods calling + +void TSVG::DrawImage(TImage *img, Int_t x, Int_t y, Int_t) +{ + Int_t width = img->GetWidth(); + Int_t height = img->GetHeight(); + + auto x1 = gPad->AbsPixeltoX(x); + auto x2 = gPad->AbsPixeltoX(x + width); + auto y1 = gPad->AbsPixeltoY(y); + auto y2 = gPad->AbsPixeltoY(y + height); + + Double_t svgx1 = XtoSVG(x1); + Double_t svgx2 = XtoSVG(x2); + Double_t svgy1 = YtoSVG(y1); + Double_t svgy2 = YtoSVG(y2); + + char *buffer = nullptr; + int size = 0; + + img->GetImageBuffer(&buffer, &size, TImage::kPng); + if (!buffer) { + Error("DrawImage", "Fail to get PNG format of the image"); + return; + } + + TString base64 = TBase64::Encode(reinterpret_cast(buffer), size); + free(buffer); + + PrintStr("@@"); + PrintStr(TString::Format("@"); + PrintStr("@"); +} + //////////////////////////////////////////////////////////////////////////////// /// Initialize the SVG file. The main task of the function is to output the /// SVG header file which consist in ``, `<desc>` and `<defs>`. The diff --git a/graf3d/gl/inc/TGLPadPainter.h b/graf3d/gl/inc/TGLPadPainter.h index a0baf240ee660..1087afe223947 100644 --- a/graf3d/gl/inc/TGLPadPainter.h +++ b/graf3d/gl/inc/TGLPadPainter.h @@ -116,6 +116,8 @@ class TGLPadPainter : public TPadPainterBase { void DrawTextNDC(Double_t x, Double_t y, const char *text, ETextMode mode) override; void DrawTextNDC(Double_t, Double_t, const wchar_t *, ETextMode) override; + void DrawImage(TImage *img, Int_t x, Int_t y, Int_t flags = 0) override; + //jpg, png, gif and bmp output. void SaveImage(TVirtualPad *pad, const char *fileName, Int_t type) const override; diff --git a/graf3d/gl/src/TGLPadPainter.cxx b/graf3d/gl/src/TGLPadPainter.cxx index 85ba074511f23..2b3efe96e3aba 100644 --- a/graf3d/gl/src/TGLPadPainter.cxx +++ b/graf3d/gl/src/TGLPadPainter.cxx @@ -22,6 +22,7 @@ #include "TROOT.h" #include "TPad.h" #include "TCanvas.h" +#include "TImage.h" #include "TColorGradient.h" #include "TGLPadPainter.h" @@ -858,6 +859,19 @@ void TGLPadPainter::RestoreViewport() glViewport(fVp[0], fVp[1], fVp[2], fVp[3]); } + +//////////////////////////////////////////////////////////////////////////////// +/// Draw image on the GL window + +void TGLPadPainter::DrawImage(TImage *img, Int_t x, Int_t y, 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); +} + //////////////////////////////////////////////////////////////////////////////// /// Using TImage save frame-buffer contents as a picture. diff --git a/hist/histpainter/src/THistPainter.cxx b/hist/histpainter/src/THistPainter.cxx index a3758eda1384e..b76ffd7884c7f 100644 --- a/hist/histpainter/src/THistPainter.cxx +++ b/hist/histpainter/src/THistPainter.cxx @@ -58,6 +58,7 @@ #include "TPaletteAxis.h" #include "TCrown.h" #include "TArrow.h" +#include "TVirtualPadPainter.h" #include "TVirtualPadEditor.h" #include "TVirtualX.h" #include "TEnv.h" @@ -5772,11 +5773,14 @@ void THistPainter::PaintColorLevelsFast(Option_t*) pImage->SetImage(buffer.data(), nXPixels, nYPixels, pPalette); delete pPalette; - Window_t wid = static_cast<Window_t>(gVirtualX->GetWindowID(gPad->GetPixmapID())); - pImage->PaintImage(wid, px0, py1, 0, 0, nXPixels, nYPixels); + auto pp = gPad->GetPainter(); + if (pp) + pp->DrawImage(pImage, px0, py1); + delete pImage; - if (Hoption.Zscale) PaintPalette(); + if (Hoption.Zscale) + PaintPalette(); // Reset the maximum and minimum values to their original values // when this function was called. If we don't do this, an initial diff --git a/test/stressGraphics.ref b/test/stressGraphics.ref index a53d01ec1b7b2..501c31bb4d088 100644 --- a/test/stressGraphics.ref +++ b/test/stressGraphics.ref @@ -73,7 +73,7 @@ tgraph2d3 15025 3000 29874 500 42525 11300 33336 3900 14787 4000 ntuple1 293000 5000 383731 7000 55666 30400 46534 6500 298000 7000 quarks 4846 150 14289 200 33239 600 25303 500 4877 150 - timage 1435879 150000 456978 10000 26170 100 365000 15000 1085792 250000 + timage 1435879 150000 456978 10000 26470 100 365000 15000 1085792 250000 zoomtf1 5884 500 16856 200 40706 14000 30026 4000 5884 500 zoomfit 5723 700 15959 200 32236 11000 16916 3200 5670 800 parallelcoord 1027338 160000 532630 50000 29519 3000 71404 7000 1027338 160000 diff --git a/test/stressGraphics_zlibng.ref b/test/stressGraphics_zlibng.ref index 5b43fcffe9490..740a55244e261 100644 --- a/test/stressGraphics_zlibng.ref +++ b/test/stressGraphics_zlibng.ref @@ -73,7 +73,7 @@ tgraph2d3 16675 3000 30066 500 40536 11300 33519 3900 16452 4000 ntuple1 295000 5000 382457 7000 54446 30400 45002 6500 300000 7000 quarks 4759 180 14288 100 32913 600 25421 1000 4790 180 - timage 1442666 150000 463176 10000 26100 100 374206 15000 1102279 250000 + timage 1442666 150000 463176 10000 26400 100 374206 15000 1102279 250000 zoomtf1 6130 500 16747 300 49750 14000 29288 4000 5429 500 zoomfit 6200 700 15885 200 31219 11000 18280 3200 6113 800 parallelcoord 1021126 160000 531255 50000 29893 3000 73438 7000 1027338 160000 diff --git a/test/svg_ref/timage.svg b/test/svg_ref/timage.svg index f28853fec03c6..a34cbeceaa356 100644 --- a/test/svg_ref/timage.svg +++ b/test/svg_ref/timage.svg @@ -11,7 +11,7 @@ timage.svg <path d="M29,247l 2.0, -2.0h 166v -216l 2.0, -2.0v 220h -170z" fill="#a9a9a9"/> <rect x="46" y="49" width="136" height="176" fill="#f2f2f2"/> <rect x="46" y="49" width="136" height="176" fill="none" stroke="#f2f2f2"/> -<g transform="translate(46 49) scale(0.712 0.712)"> +<g transform="translate(45 49) scale(0.712 0.712)"> <image width="191" height="247" href="data:image/png;base64,"></image> </g> <rect x="312" y="82" width="227" height="165" fill="#f2f2f2"/> @@ -19,7 +19,7 @@ timage.svg <path d="M312,247l 2.0, -2.0h 223v -161l 2.0, -2.0v 165h -227z" fill="#a9a9a9"/> <rect x="335" y="99" width="181" height="132" fill="#f2f2f2"/> <rect x="335" y="99" width="181" height="132" fill="none" stroke="#f2f2f2"/> -<g transform="translate(335 99) scale(0.714 0.709)"> +<g transform="translate(335 99) scale(0.712 0.712)"> <image width="254" height="186" href="data:image/png;base64,"></image> </g> <rect x="312" y="302" width="170" height="220" fill="#f2f2f2"/> @@ -35,7 +35,7 @@ timage.svg <path d="M29,522l 2.0, -2.0h 223v -161l 2.0, -2.0v 165h -227z" fill="#a9a9a9"/> <rect x="52" y="374" width="181" height="132" fill="#f2f2f2"/> <rect x="52" y="374" width="181" height="132" fill="none" stroke="#f2f2f2"/> -<g transform="translate(52 374) scale(0.714 0.709)"> +<g transform="translate(51 374) scale(0.712 0.712)"> <image width="254" height="186" href="data:image/png;base64,"></image> </g> </svg>