diff --git a/graf2d/asimage/inc/TASImage.h b/graf2d/asimage/inc/TASImage.h index 3fad702ba1f0f..1cbcebddb8289 100644 --- a/graf2d/asimage/inc/TASImage.h +++ b/graf2d/asimage/inc/TASImage.h @@ -55,6 +55,8 @@ class TASImage : public TImage { void DestroyScaledImage(); const char *TypeFromMagicNumber(const char *file); + void CloneImageData(const TASImage &src); + protected: ASImage *fImage; ///(img.fScaledImage->Clone()) : nullptr; - fGrayImage = img.fGrayImage ? clone_asimage(img.fGrayImage, SCL_DO_ALL) : nullptr; - - if (img.fImage->alt.vector) { - Int_t size = img.fImage->width * img.fImage->height * sizeof(double); - fImage->alt.vector = (double*)malloc(size); - memcpy(fImage->alt.vector, img.fImage->alt.vector, size); - } - - fZoomUpdate = kNoZoom; - fZoomOffX = img.fZoomOffX; - fZoomOffY = img.fZoomOffY; - fZoomWidth = img.fZoomWidth; - fZoomHeight = img.fZoomHeight; - fEditable = img.fEditable; - fIsGray = img.fIsGray; - } + if (img.IsValid()) + CloneImageData(img); } //////////////////////////////////////////////////////////////////////////////// @@ -334,24 +317,7 @@ TASImage &TASImage::operator=(const TASImage &img) DestroyImage(); DestroyScaledImage(); - fImage = clone_asimage(img.fImage, SCL_DO_ALL); - fScaledImage = img.fScaledImage ? static_cast(img.fScaledImage->Clone()) : nullptr; - fGrayImage = img.fGrayImage ? clone_asimage(img.fGrayImage, SCL_DO_ALL) : nullptr; - - if (img.fImage->alt.vector) { - Int_t size = img.fImage->width * img.fImage->height * sizeof(double); - fImage->alt.vector = (double*)malloc(size); - memcpy(fImage->alt.vector, img.fImage->alt.vector, size); - } - - fZoomUpdate = kNoZoom; - fZoomOffX = img.fZoomOffX; - fZoomOffY = img.fZoomOffY; - fZoomWidth = img.fZoomWidth; - fZoomHeight = img.fZoomHeight; - fEditable = img.fEditable; - fIsGray = img.fIsGray; - fPaintMode = 1; + CloneImageData(img); } return *this; @@ -366,6 +332,42 @@ TASImage::~TASImage() DestroyScaledImage(); } + +//////////////////////////////////////////////////////////////////////////////// +/// Clone image data +/// Used for clones and assign operator + +void TASImage::CloneImageData(const TASImage &img) +{ + fImage = img.fImage ? clone_asimage(img.fImage, SCL_DO_ALL) : nullptr; + fScaledImage = img.fScaledImage ? static_cast(img.fScaledImage->Clone()) : nullptr; + fGrayImage = img.fGrayImage ? clone_asimage(img.fGrayImage, SCL_DO_ALL) : nullptr; + + if (img.fImage && img.fImage->alt.vector) { + Int_t size = img.fImage->width * img.fImage->height * sizeof(double); + fImage->alt.vector = (double*)malloc(size); + memcpy(fImage->alt.vector, img.fImage->alt.vector, size); + } + + if (img.fImage && img.fImage->alt.argb32) { + Int_t size = img.fImage->width * img.fImage->height * sizeof(ARGB32); + fImage->alt.argb32 = (ARGB32*)safemalloc(size); + memcpy(fImage->alt.argb32, img.fImage->alt.argb32, size); + } + + fPaintMode = img.fPaintMode; + fZoomOffX = img.fZoomOffX; + fZoomOffY = img.fZoomOffY; + fZoomWidth = img.fZoomWidth; + fZoomHeight = img.fZoomHeight; + fZoomUpdate = img.fZoomUpdate; + fEditable = img.fEditable; + fIsGray = img.fIsGray; + fMaxValue = img.fMaxValue; + fMinValue = img.fMinValue; +} + + //////////////////////////////////////////////////////////////////////////////// /// Set icons paths. @@ -2692,37 +2694,11 @@ void TASImage::Blur(Double_t hr, Double_t vr) TObject *TASImage::Clone(const char *newname) const { - if (!InitVisual() || !fImage) { - Warning("Clone", "Image not initiated"); - return nullptr; - } - - TASImage *im = static_cast(TImage::Create()); - - if (!im) { - Warning("Clone", "Failed to create image"); - return nullptr; - } - - im->SetName(newname); - - im->fImage = clone_asimage(fImage, SCL_DO_ALL); - im->fMaxValue = fMaxValue; - im->fMinValue = fMinValue; - im->fZoomOffX = fZoomOffX; - im->fZoomOffY = fZoomOffY; - im->fZoomWidth = fZoomWidth; - im->fZoomHeight = fZoomHeight; - im->fZoomUpdate = fZoomUpdate; - im->fScaledImage = fScaledImage ? static_cast(fScaledImage->Clone()) : nullptr; - - if (fImage->alt.argb32) { - UInt_t sz = fImage->width * fImage->height; - im->fImage->alt.argb32 = (ARGB32*)safemalloc(sz*sizeof(ARGB32)); - memcpy(im->fImage->alt.argb32, fImage->alt.argb32, sz * sizeof(ARGB32)); - } - - return im; + auto newimg = new TASImage(); + if (newname) + newimg->SetName(newname); + newimg->CloneImageData(*this); + return newimg; } //////////////////////////////////////////////////////////////////////////////// @@ -3405,7 +3381,9 @@ void TASImage::Append(const TImage *im, const char *option, const char *color ) } if (!fImage) { - fImage = ((TASImage*)im)->fImage; + // if image not exists - just clone data from source image + if (auto asimg = dynamic_cast(im)) + CloneImageData(*asimg); return; } diff --git a/net/http/test/test_suite.cxx b/net/http/test/test_suite.cxx index 76e8b39ce3ad2..0f8407afe0978 100644 --- a/net/http/test/test_suite.cxx +++ b/net/http/test/test_suite.cxx @@ -1,3 +1,5 @@ +#include "TH1F.h" + Int_t server_hash = 0; TString server_url; TString unix_socket; @@ -54,9 +56,12 @@ void test_suite(THttpServer &serv) TNamed obj1("obj1", "title1"); TNamed obj2("obj2", "title2"); + TH1F h1("h1", "title", 100, -10, 10); + serv.Register("/", &obj1); serv.Register("/", &obj2); + serv.Register("/", &h1); // check JSON representation for the object std::string res = execute_request("/obj1/root.json"); @@ -142,6 +147,12 @@ void test_suite(THttpServer &serv) EXPECT_EQ(res, "") << "exe.json should be empty in readonly"; + res = execute_request("/h1/root.png?w=500&h=500"); + EXPECT_NE(res.length(), 0) << "root.png should not be empty"; + EXPECT_NEAR(res.length(), 5558, 2000) << "root.png should be around 5K"; + + + // disable readonly to get extra functionality serv.SetReadOnly(kFALSE); diff --git a/net/httpsniff/src/TRootSnifferFull.cxx b/net/httpsniff/src/TRootSnifferFull.cxx index 0323937d4dbd7..d4d451e6159fb 100644 --- a/net/httpsniff/src/TRootSnifferFull.cxx +++ b/net/httpsniff/src/TRootSnifferFull.cxx @@ -403,7 +403,7 @@ Bool_t TRootSnifferFull::ProduceImage(Int_t kind, const std::string &path, const TObject *obj = (TObject *)obj_ptr; - TImage *img = TImage::Create(); + std::unique_ptr img(TImage::Create()); if (!img) return kFALSE; @@ -412,6 +412,7 @@ Bool_t TRootSnifferFull::ProduceImage(Int_t kind, const std::string &path, const if (gDebug > 1) Info("TRootSniffer", "Crate IMAGE directly from pad"); img->FromPad((TPad *)obj); + } else if (CanDrawClass(obj->IsA())) { if (gDebug > 1) @@ -439,26 +440,21 @@ Bool_t TRootSnifferFull::ProduceImage(Int_t kind, const std::string &path, const if (!isbatch) gROOT->SetBatch(kTRUE); - TCanvas *c1 = new TCanvas("__online_draw_canvas__", "title", width, height); - obj->Draw(drawopt.Data()); - img->FromPad(c1); - delete c1; + TCanvas c1("__online_draw_canvas__", "title", width, height); + c1.Add(obj, drawopt.Data()); + img->FromPad(&c1); if (!isbatch) gROOT->SetBatch(kFALSE); } else { - delete img; return kFALSE; } - TImage *im = TImage::Create(); - im->Append(img); - char *png_buffer = nullptr; - int size(0); + int size = 0; - im->GetImageBuffer(&png_buffer, &size, (TImage::EImageFileTypes)kind); + img->GetImageBuffer(&png_buffer, &size, (TImage::EImageFileTypes)kind); if (png_buffer && (size > 0)) { res.resize(size); @@ -466,7 +462,6 @@ Bool_t TRootSnifferFull::ProduceImage(Int_t kind, const std::string &path, const } free(png_buffer); - delete im; return !res.empty(); } diff --git a/net/httpsniff/test/test_sniffer.cxx b/net/httpsniff/test/test_sniffer.cxx index e4782439cd7b3..63205f28b0509 100644 --- a/net/httpsniff/test/test_sniffer.cxx +++ b/net/httpsniff/test/test_sniffer.cxx @@ -353,3 +353,21 @@ TEST(TRootSniffer, multi_json) " \"fTitle\" : \"title2\"\n" "}]") << "return value of multi.json"; } + +// Produce image object +TEST(TRootSniffer, root_png) +{ + TH1F h1("h1", "title", 100, -10, 10); + + TRootSnifferFull sniffer("sniffer"); + // disable readonly to get method executed + sniffer.SetReadOnly(kFALSE); + + sniffer.RegisterObject("/", &h1); + + std::string res; + + sniffer.Produce("/h1", "root.png", "w=500&h=500", res); + EXPECT_NE(res.length(), 0) << "image size should not be 0"; + EXPECT_NEAR(res.length(), 5558, 2000) << "image size should be around 5K"; +}