Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TASImage.cxx
Go to the documentation of this file.
1// @(#)root/asimage:$Id: TASImage.cxx,v 1.54 2006/03/13 15:18:56 rdm E
2// Author: Fons Rademakers, Reiner Rohlfs, Valeriy Onuchin 28/11/2001
3
4/*************************************************************************
5 * Copyright (C) 1995-2001, Rene Brun, Fons Rademakers and Reiner Rohlfs *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/**************************************************************************
13 * Some parts of this source are based on libAfterImage 2.00.00
14 * (http://www.afterstep.org/)
15 *
16 * Copyright (c) 2002 Sasha Vasko <sasha@aftercode.net>
17 * Copyright (c) 1998, 1999 Ethan Fischer <allanon@crystaltokyo.com>
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU Library General Public License as
21 * published by the Free Software Foundation; either version 2 of the
22 * License, or (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU Library General Public
30 * License along with this program; if not, write to the Free Software
31 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 *
33 **************************************************************************/
34
35/** \class TASImage
36\ingroup asimage
37
38Image class.
39
40TASImage is the concrete interface to the image processing library
41libAfterImage.
42
43It allows reading and writing of images in different formats, several image
44manipulations (scaling, tiling, merging, etc.) and displaying in pads. The size
45of the image on the screen does not depend on the original size of the image but
46on the size of the pad. Therefore it is very easy to resize the image on the
47screen by resizing the pad.
48
49Besides reading an image from a file an image can be defined by a two
50dimensional array of values. A palette defines the color of each value.
51
52The image can be zoomed by defining a rectangle with the mouse. The color
53palette can be modified with a GUI, just select StartPaletteEditor() from the
54context menu.
55
56Several examples showing how to use this class are available in the
57ROOT tutorials: `$ROOTSYS/tutorials/visualisation/image/`
58*/
59
60#include <ft2build.h>
61#include FT_FREETYPE_H
62#include FT_GLYPH_H
63
64#include "RConfigure.h"
65#include "TArrayD.h"
66#include "TArrayL.h"
67#include "TASImage.h"
68#include "TASImagePlugin.h"
69#include "TBuffer.h"
70#include "TColor.h"
71#include "TEnv.h"
72#include "TFrame.h"
73#include "TGaxis.h"
74#include "THashTable.h"
75#include "TImageDump.h"
76#include "TMath.h"
77#include "TObjArray.h"
78#include "TPluginManager.h"
79#include "TPoint.h"
80#include "TRandom.h"
81#include "TROOT.h"
82#include "TStyle.h"
83#include "TSystem.h"
84#include "TText.h"
85#include "TTF.h"
86#include "TVectorD.h"
87#include "TVirtualPad.h"
88#include "TVirtualPadPainter.h"
89#include "TVirtualPS.h"
90#include "TVirtualX.h"
91
92#include <iostream>
93#include <memory>
94
95#include "snprintf.h"
96
97#ifndef WIN32
98#ifndef R__HAS_COCOA
99# include <X11/Xlib.h>
100#endif
101#else
102# include "Windows4root.h"
103#endif
104#ifndef WIN32
105#ifdef R__HAS_COCOA
106# define X_DISPLAY_MISSING 1
107#endif
108# include <afterbase.h>
109#else
110# define X_DISPLAY_MISSING 1
111# include <afterbase.h>
112#endif
113# include <afterimage.h>
114# include <bmp.h>
115extern "C" {
116# include <draw.h>
117}
118
119// auxiliary functions for general polygon filling
120#include "TASPolyUtils.c"
121
122
126
127static ASFontManager *gFontManager = nullptr;
128static unsigned long kAllPlanes = ~0;
130
131// default icon paths
132static char *gIconPaths[7] = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
133
134// To scale fonts to the same size as the old TT version
135const Float_t kScale = 0.985;
136
137///////////////////////////// alpha-blending macros ///////////////////////////////
138
139#if defined(__GNUC__) && __GNUC__ >= 4 && ((__GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ >= 1) || (__GNUC_MINOR__ >= 3)) && !__INTEL_COMPILER
140#pragma GCC diagnostic ignored "-Wstrict-aliasing"
141#endif
142
143#ifdef R__BYTESWAP
144typedef struct {
145 unsigned char b;
146 unsigned char g;
147 unsigned char r;
148 unsigned char a;
149} __argb32__;
150#else
151typedef struct {
152 unsigned char a;
153 unsigned char r;
154 unsigned char g;
155 unsigned char b;
156} __argb32__;
157#endif
158
159
160//______________________________________________________________________________
161#define _alphaBlend(bot, top) {\
162 __argb32__ *T = (__argb32__*)(top);\
163 __argb32__ *B = (__argb32__*)(bot);\
164 int aa = 255-T->a; /* NOLINT */ \
165 if (!aa) {\
166 *bot = *top;\
167 } else { \
168 B->a = ((B->a*aa)>>8) + T->a;\
169 B->r = (B->r*aa + T->r*T->a)>>8;\
170 B->g = (B->g*aa + T->g*T->a)>>8;\
171 B->b = (B->b*aa + T->b*T->a)>>8;\
172 }\
173}\
174
175
176////////////////////////////////////////////////////////////////////////////////
177/// Destroy image.
178
180{
181 if (fImage) {
183 }
184
185 if (fIsGray && fGrayImage) {
187 }
188
189 fIsGray = kFALSE;
190 fGrayImage = nullptr;
191 fImage = nullptr;
192}
193
194////////////////////////////////////////////////////////////////////////////////
195/// Destroy scaled image.
196
198{
199 if (fScaledImage) {
200 delete fScaledImage;
201 fScaledImage = nullptr;
202 }
203
204}
205
206////////////////////////////////////////////////////////////////////////////////
207/// Set default parameters.
208
210{
211 fImage = nullptr;
212 fScaledImage = nullptr;
213 fMaxValue = 1;
214 fMinValue = 0;
216 fPaintMode = 1;
217 fZoomOffX = 0;
218 fZoomOffY = 0;
219 fZoomWidth = 0;
220 fZoomHeight = 0;
222
223 fGrayImage = nullptr;
224 fIsGray = kFALSE;
226
227 if (!fgInit) {
228 set_application_name((char*)(gProgName ? gProgName : "ROOT"));
229 fgInit = kTRUE;
230 }
231}
232
233////////////////////////////////////////////////////////////////////////////////
234/// Default image constructor.
235
240
241////////////////////////////////////////////////////////////////////////////////
242/// Create an empty image.
243
245{
246 SetDefaults();
247 fImage = create_asimage(w ? w : 20, h ? h : 20, 0);
248 UnZoom();
249}
250
251////////////////////////////////////////////////////////////////////////////////
252/// Create an image object and read from specified file.
253/// For more information see description of function ReadImage()
254/// which is called by this constructor.
255
256TASImage::TASImage(const char *file, EImageFileTypes) : TImage(file)
257{
258 SetDefaults();
259 TString fname = file;
261 ReadImage(fname.Data());
262}
263
264////////////////////////////////////////////////////////////////////////////////
265/// Create an image depending on the values of imageData.
266/// For more information see function SetImage() which is called
267/// by this constructor.
268
275
276////////////////////////////////////////////////////////////////////////////////
277/// Create an image depending on the values of imageData.
278/// The size of the image is width X (imageData.fN / width).
279/// For more information see function SetImage() which is called by
280/// this constructor.
281
288
289////////////////////////////////////////////////////////////////////////////////
290/// Create an image depending on the values of imageData.
291/// The size of the image is width X (imageData.fN / width).
292/// For more information see function SetImage() which is called by
293/// this constructor.
294
301
302////////////////////////////////////////////////////////////////////////////////
303/// Image copy constructor.
304
306{
307 SetDefaults();
308
309 if (img.IsValid()) {
311 fScaledImage = img.fScaledImage ? static_cast<TASImage *>(img.fScaledImage->Clone()) : nullptr;
312 fGrayImage = img.fGrayImage ? clone_asimage(img.fGrayImage, SCL_DO_ALL) : nullptr;
313
314 if (img.fImage->alt.vector) {
315 Int_t size = img.fImage->width * img.fImage->height * sizeof(double);
316 fImage->alt.vector = (double*)malloc(size);
317 memcpy(fImage->alt.vector, img.fImage->alt.vector, size);
318 }
319
321 fZoomOffX = img.fZoomOffX;
322 fZoomOffY = img.fZoomOffY;
323 fZoomWidth = img.fZoomWidth;
324 fZoomHeight = img.fZoomHeight;
325 fEditable = img.fEditable;
326 fIsGray = img.fIsGray;
327 }
328}
329
330////////////////////////////////////////////////////////////////////////////////
331/// Image assignment operator.
332
334{
335 if (this != &img && img.IsValid()) {
337
338 DestroyImage();
340
342 fScaledImage = img.fScaledImage ? static_cast<TASImage *>(img.fScaledImage->Clone()) : nullptr;
343 fGrayImage = img.fGrayImage ? clone_asimage(img.fGrayImage, SCL_DO_ALL) : nullptr;
344
345 if (img.fImage->alt.vector) {
346 Int_t size = img.fImage->width * img.fImage->height * sizeof(double);
347 fImage->alt.vector = (double*)malloc(size);
348 memcpy(fImage->alt.vector, img.fImage->alt.vector, size);
349 }
350
352 fZoomOffX = img.fZoomOffX;
353 fZoomOffY = img.fZoomOffY;
354 fZoomWidth = img.fZoomWidth;
355 fZoomHeight = img.fZoomHeight;
356 fEditable = img.fEditable;
357 fIsGray = img.fIsGray;
358 fPaintMode = 1;
359 }
360
361 return *this;
362}
363
364////////////////////////////////////////////////////////////////////////////////
365/// Image destructor, clean up image and visual.
366
372
373////////////////////////////////////////////////////////////////////////////////
374/// Set icons paths.
375
376static void init_icon_paths()
377{
378 TString icon_path = gEnv->GetValue("Gui.IconPath", "");
379 if (icon_path.IsNull()) {
380 icon_path = "icons";
382#ifndef R__WIN32
383 icon_path = ".:" + icon_path + ":" + TROOT::GetIconPath() + ":" + EXTRAICONPATH;
384#else
385 icon_path = ".;" + icon_path + ";" + TROOT::GetIconPath() + ";" + EXTRAICONPATH;
386#endif
387 }
388
389 Int_t cnt = 0;
390 Ssiz_t from = 0;
391 TString token;
392#ifndef R__WIN32
393 const char *delim = ":";
394#else
395 const char *delim = ";";
396#endif
397 while (icon_path.Tokenize(token, from, delim) && cnt < 6) {
398 char *path = gSystem->ExpandPathName(token.Data());
399 if (path) {
400 gIconPaths[cnt] = path;
401 cnt++;
402 }
403 }
404 gIconPaths[cnt] = nullptr;
405}
406
407////////////////////////////////////////////////////////////////////////////////
408/// Guess the file type from the first byte of file.
409
410const char *TASImage::TypeFromMagicNumber(const char *file)
411{
413 FILE *fp = fopen(file, "rb");
414 const char *ret = "";
415
416 if (!fp) return nullptr;
417
418 if (!fread(&magic, 1, 1, fp)) {
419 fclose(fp);
420 return nullptr;
421 }
422
423 switch (magic) {
424 case 0x00:
425 {
426 if (!fread(&magic, 1, 1, fp)) {
427 fclose(fp);
428 return nullptr;
429 }
430 if (!fread(&magic, 1, 1, fp)) {
431 fclose(fp);
432 return nullptr;
433 }
434
435 ret = (magic == 1) ? "ico" : "cur";
436 break;
437 }
438 case 0x25:
439 {
440 if (!fread(&magic, 1, 1, fp)) {
441 fclose(fp);
442 return nullptr;
443 }
444
445 if (magic == 0x21)
446 ret = "ps";
447 else if (magic == 0x50)
448 ret = "pdf";
449 break;
450 }
451 case 0x42:
452 ret = "bmp";
453 break;
454 case 0x47:
455 ret = "gif";
456 break;
457 case 0x54:
458 ret = "tga";
459 break;
460 case 0x49:
461 ret = "tiff";
462 break;
463 case 0x89:
464 ret = "png";
465 break;
466 case 0xff:
467 ret = "jpg";
468 break;
469 default:
470 ret = "";
471 }
472
473 fclose(fp);
474 return ret;
475}
476
477////////////////////////////////////////////////////////////////////////////////
478/// Read specified image file.
479/// The file type is determined by the file extension (the type argument is
480/// ignored). It will attempt to append .gz and then .Z to the filename and
481/// find such a file. If the filename ends with extension consisting of digits
482/// only, it will attempt to find the file with this extension stripped
483/// off. On success this extension will be used to load subimage from
484/// the file with that number. Subimage is supported for GIF files
485/// (ICO, BMP, CUR, TIFF, XCF to be supported in future).
486/// For example,
487/// ~~~ {.cpp}
488/// i1 = TImage::Open("anim.gif.0"); // read the first subimage
489/// i4 = TImage::Open("anim.gif.3"); // read the forth subimage
490/// ~~~
491/// It is also possible to put XPM raw string (see also SetImageBuffer) as
492/// the first input parameter ("filename"), such string is returned by
493/// GetImageBuffer method.
494
496{
497 if (!InitVisual()) {
498 Warning("ReadImage", "Visual not initiated");
499 return;
500 }
501
502 Bool_t xpm = filename && (filename[0] == '/' &&
503 filename[1] == '*') && filename[2] == ' ';
504
505 if (xpm) { // XPM strings in-memory array
507 fName = "XPM_image";
508 return;
509 }
510
511 if (!gIconPaths[0]) {
513 }
514 // suppress the "root : looking for image ..." messages
516
518 iparams.flags = 0;
519 iparams.width = 0;
520 iparams.height = 0;
521 iparams.filter = SCL_DO_ALL;
522 iparams.gamma = SCREEN_GAMMA;
523 iparams.gamma_table = NULL;
524 iparams.compression = GetImageCompression();
525 iparams.format = ASA_ASImage;
526 iparams.search_path = gIconPaths;
527 iparams.subimage = 0;
528 iparams.return_animation_delay = -1;
529
530 TString ext;
531 const char *dot;
532 if (filename) dot = strrchr(filename, '.');
533 else dot = nullptr;
534 ASImage *image = nullptr;
536
537 if (!dot) {
539 else ext = dot + 1;
540 } else {
541 ext = dot + 1;
542 }
543
544 if (!ext.IsNull() && ext.IsDigit()) { // read subimage
545 iparams.subimage = ext.Atoi();
546 fname = fname(0, fname.Length() - ext.Length() - 1);
547 ext = strrchr(fname.Data(), '.') + 1;
548 }
549
551
552 if (image) { // it's OK
553 goto end;
554 } else { // try to read it via plugin
555 if (ext.IsNull()) {
556 return;
557 }
558 ext.ToLower();
559 ext.Strip();
560 UInt_t w = 0;
561 UInt_t h = 0;
562 unsigned char *bitmap = nullptr;
563
564 TImagePlugin *plug = (TImagePlugin*)fgPlugList->FindObject(ext.Data());
565
566 if (!plug) {
567 TPluginHandler *handler = gROOT->GetPluginManager()->FindHandler("TImagePlugin", ext);
568 if (!handler || ((handler->LoadPlugin() == -1))) {
569 return;
570 }
571 plug = (TImagePlugin*)handler->ExecPlugin(1, ext.Data());
572
573 if (!plug) {
574 return;
575 }
576
577 fgPlugList->Add(plug);
578 }
579
580 if (plug) {
581 if (plug->InheritsFrom(TASImagePlugin::Class())) {
582 image = ((TASImagePlugin*)plug)->File2ASImage(fname.Data());
583 if (image) goto end;
584 }
585 bitmap = plug->ReadFile(fname.Data(), w, h);
586 if (bitmap) {
587 image = bitmap2asimage(bitmap, w, h, 0, nullptr);
588 }
589 if (!image) {
590 return;
591 }
592 }
593 }
594
595end:
596 fName.Form("%s.", gSystem->BaseName(fname.Data()));
597
598 DestroyImage();
600
601 fImage = image;
604 fZoomOffX = 0;
605 fZoomOffY = 0;
606 fZoomWidth = fImage->width;
607 fZoomHeight = fImage->height;
608 fPaintMode = 1;
609}
610
611////////////////////////////////////////////////////////////////////////////////
612/// Write image to specified file.
613///
614/// If there is no file extension or if the file extension is unknown, the
615/// type argument will be used to determine the file type. The quality and
616/// compression is derived from the TAttImage values.
617///
618/// It's possible to write image into an animated GIF file by specifying file
619/// name as "myfile.gif+" or "myfile.gif+NN", where NN is the delay of displaying
620/// subimages during animation in 10ms seconds units. NN is not restricted
621/// to two digits. If NN is omitted the delay between subimages is zero.
622/// For an animation that stops after last subimage is reached, one has to
623/// write the last image as .gif+ (zero delay of last image) or .gif+NN
624/// (NN*10ms delay of last image).
625///
626/// For repeated animation (looping), the last subimage must be specified as:
627/// - "myfile.gif++NN++" if you want an infinite looping gif with NN*10ms
628/// delay of the last image.
629/// - "myfile.gif++" for an infinite loop with zero delay of last image.
630/// - "myfile.gif+NN++RR" if you want a finite looping gif with NN*10ms
631/// delay of the last image and the animation to be stopped after RR
632/// repeats. RR is not restricted to two digits.
633///
634/// A deprecated version for saving the last subimage of a looping gif animation is:
635/// - "myfile.gif++NN" for a finite loop where NN is number of repetitions
636/// and NN*10ms the delay of last image. (No separate control of repeats and delay).
637/// Note: If the file "myfile.gif" already exists, the new frames are appended at
638/// the end of the file. To avoid this, delete it first with gSystem->Unlink(myfile.gif);
639///
640/// The following macro creates animated gif from jpeg images with names
641/// - imageNN.jpg, where 1<= NN <= 10
642/// - The delays are set to 10*10ms.
643/// ~~~ {.cpp}
644/// {
645/// TImage *img = 0;
646/// gSystem->Unlink("anim.gif"); // delete existing file
647///
648/// for (int i = 1; i <= 10; i++) {
649/// delete img; // delete previous image
650///
651/// // Read image data. Image can be in any format, e.g. png, gif, etc.
652/// img = TImage::Open(Form("image%d.jpg", i));
653///
654/// if (i < 10) {
655/// img->WriteImage("anim.gif+10"); // 10 centiseconds delay
656/// } else { // the last image written. "++" stands for infinit animation.
657/// img->WriteImage("anim.gif++10++"); // 10 centiseconds delay of last image
658/// }
659/// }
660/// }
661/// ~~~
662
664{
665 if (!IsValid()) {
666 Error("WriteImage", "no image in memory. Draw something first");
667 return;
668 }
669
670 if (!file || !*file) {
671 Error("WriteImage", "no file name specified");
672 return;
673 }
674
675 const char *s;
676 if ((s = strrchr(file, '.'))) {
677 s++;
679 if (t == kUnknown) {
680 Error("WriteImage", "cannot determine a valid file type");
681 return;
682 }
683 if (t != kUnknown)
684 type = t;
685 }
686
687 if (type == kUnknown) {
688 Error("WriteImage", "not a valid file type was specified");
689 return;
690 }
691
695
697 EImageQuality quality = GetImageQuality();
698 MapQuality(quality, aquality);
699
700 static TString fname;
701 fname = file;
704
705 switch (type) {
706 case kXpm:
707 parms.xpm.type = atype;
708 parms.xpm.flags = EXPORT_ALPHA;
709 parms.xpm.dither = 4;
710 parms.xpm.opaque_threshold = 127;
711 parms.xpm.max_colors = 512;
712 break;
713 case kBmp:
714 ASImage2bmp(im, fname.Data(), nullptr);
715 return;
716 case kXcf:
717 ASImage2xcf(im, fname.Data(), nullptr);
718 return;
719 case kPng:
720 parms.png.type = atype;
721 parms.png.flags = EXPORT_ALPHA;
722 parms.png.compression = !GetImageCompression() ? -1 : int(GetImageCompression());
723 break;
724 case kJpeg:
725 parms.jpeg.type = atype;
726 parms.jpeg.flags = 0;
727 parms.jpeg.quality = aquality;
728 break;
729 case kGif:
730 parms.gif.type = atype;
731 parms.gif.flags = EXPORT_ALPHA;
732 parms.gif.dither = 0;
733 parms.gif.opaque_threshold = 0;
734 break;
735 case kAnimGif:
736 {
737 parms.gif.type = atype;
738 parms.gif.flags = EXPORT_ALPHA | EXPORT_APPEND;
739 parms.gif.dither = 0;
740 parms.gif.opaque_threshold = 0;
741 parms.gif.animate_repeats = 0;
742
743 s += 4; // skip "gif+"
744 int delay = 0;
745
746 const TString sufix = s; // we denote as suffix as everything that is after .gif+
747 const UInt_t sLength = sufix.Length();
748
749 if (sufix=="+") {
750 // .gif++ implies that this is the last image of the animation
751 // and that the gif will loop forever (infinite animation)
752 // and that the delay of last image is 0ms (backward compatibility reasons)
753 delay = 0;
754 parms.gif.flags |= EXPORT_ANIMATION_REPEATS;// activate repetition
755 parms.gif.animate_repeats = 0;// 0 is code for looping forever (if EXPORT_ANIMATION_REPEATS is also set)
756 } else if(sufix=="") {
757 // .gif+ implies that this is a subimage of the animation with zero delay
758 // or the last image of an animation that will not repeat.
759 // Last image delay is zero because atoi("")=0.
760 delay = atoi(s);
761 //Nothing else needed here
762 } else if(!sufix.Contains("+")) {
763 // .gif+NN implies that this is a subimage of the animation
764 // with NN*10ms delay (latency) until the next one.
765 // You can also use this option on the last image if you do not want the gif to replay
766 delay = atoi(s);
767 //Nothing else needed here
768 } else if(sLength>1 && sufix.BeginsWith("+") && sufix.CountChar('+')==1) {
769 // .gif++NN implies that this is the last image of the animation
770 // and that it will loop NN number of times (finite animation)
771 // and that the delay of last image is NN*10ms (backward compatibility reasons).
772 delay = atoi(s);// atoi is smart enough to ignore the "+" sign before.
773 parms.gif.flags |= EXPORT_ANIMATION_REPEATS;// activate repetition
774 parms.gif.animate_repeats = atoi(s);// loops only NN times, then it stops. atoi discards + sign.
775 } else if(sLength>3 && sufix.BeginsWith("+") && sufix.EndsWith("++") && !TString(sufix(1,sLength-3)).Contains("+")) {
776 // .gif++NN++ implies that this is the last image of the animation
777 // and that the gif will loop forever (infinite animation)
778 // and that the delay of last image is NN*10ms.
779 // In contrast, .gif++ is an infinite loop but with 0 delay, whereas the option
780 // .gif++NN is a loop repeated NN times (not infinite) with NN*10ms delay
781 // between last and first loop images.
782 delay = atoi(s);// atoi discards the three plus signs
783 parms.gif.flags |= EXPORT_ANIMATION_REPEATS;// activate repetition
784 parms.gif.animate_repeats = 0;// 0 is code for looping forever (if EXPORT_ANIMATION_REPEATS is also set)
785 } else if(sLength>3 && sufix.CountChar('+')==2 && TString(sufix(1,sLength-2)).Contains("++")) {
786 // .gif+NN++RR implies that this is the last image animation
787 // and that the gif will loop RR number of times (finite animation)
788 // and that the delay of last image is NN*10ms.
789 const TString sDelay = sufix(0,sufix.First('+'));
790 const TString sRepeats = sufix(sufix.First('+')+2,sLength-(sufix.First('+')+2));
791 delay = atoi(sDelay);
792 parms.gif.flags |= EXPORT_ANIMATION_REPEATS;// activate repetition
793 parms.gif.animate_repeats = atoi(sRepeats);// loops NN times.
794 } else {
795 Error("WriteImage", "gif suffix %s not yet supported", s);
796 return;
797 }
798
799 parms.gif.animate_delay = delay;
800
801 int i1 = fname.Index("gif+");
802 if (i1 != kNPOS) {
803 fname = fname(0, i1 + 3);
804 }
805 else {
806 Error("WriteImage", "unexpected gif extension structure %s", fname.Data());
807 return;
808 }
809 break;
810 }
811 case kTiff:
812 parms.tiff.type = atype;
813 parms.tiff.flags = EXPORT_ALPHA;
814 parms.tiff.rows_per_strip = 0;
815 parms.tiff.compression_type = aquality <= 50 ? TIFF_COMPRESSION_JPEG :
817 parms.tiff.jpeg_quality = 100;
818 parms.tiff.opaque_threshold = 0;
819 break;
820 default:
821 Error("WriteImage", "file type %s not yet supported", s);
822 return;
823 }
824
825 if (!ASImage2file(im, nullptr, fname.Data(), atype, &parms)) {
826 Error("WriteImage", "error writing file %s", file);
827 }
828}
829
830////////////////////////////////////////////////////////////////////////////////
831/// Return file type depending on specified extension.
832/// Protected method.
833
835{
836 TString s(ext);
837 s.Strip();
838 s.ToLower();
839
840 if (s == "xpm")
841 return kXpm;
842 if (s == "png")
843 return kPng;
844 if (s == "jpg" || s == "jpeg")
845 return kJpeg;
846 if (s == "xcf")
847 return kXcf;
848 if (s == "ppm")
849 return kPpm;
850 if (s == "pnm")
851 return kPnm;
852 if (s == "bmp")
853 return kBmp;
854 if (s == "ico")
855 return kIco;
856 if (s == "cur")
857 return kCur;
858 if (s == "gif")
859 return kGif;
860 if (s.Contains("gif+"))
861 return kAnimGif;
862 if (s == "tiff")
863 return kTiff;
864 if (s == "xbm")
865 return kXbm;
866 if (s == "tga")
867 return kTga;
868 if (s == "xml")
869 return kXml;
870
871 return kUnknown;
872}
873
874////////////////////////////////////////////////////////////////////////////////
875/// Map file type to/from AfterImage types.
876/// Protected method.
877
879{
880 if (toas) {
881 switch (type) {
882 case kXpm:
883 astype = ASIT_Xpm; break;
884 case kZCompressedXpm:
886 case kGZCompressedXpm:
888 case kPng:
889 astype = ASIT_Png; break;
890 case kJpeg:
891 astype = ASIT_Jpeg; break;
892 case kXcf:
893 astype = ASIT_Xcf; break;
894 case kPpm:
895 astype = ASIT_Ppm; break;
896 case kPnm:
897 astype = ASIT_Pnm; break;
898 case kBmp:
899 astype = ASIT_Bmp; break;
900 case kIco:
901 astype = ASIT_Ico; break;
902 case kCur:
903 astype = ASIT_Cur; break;
904 case kGif:
905 astype = ASIT_Gif; break;
906 case kAnimGif:
907 astype = ASIT_Gif; break;
908 case kTiff:
909 astype = ASIT_Tiff; break;
910 case kXbm:
911 astype = ASIT_Xbm; break;
912 case kTga:
913 astype = ASIT_Targa; break;
914 case kXml:
915 astype = ASIT_XMLScript; break;
916 default:
918 }
919 } else {
920 switch (astype) {
921 case ASIT_Xpm:
922 type = kXpm; break;
924 type = kZCompressedXpm; break;
926 type = kGZCompressedXpm; break;
927 case ASIT_Png:
928 type = kPng; break;
929 case ASIT_Jpeg:
930 type = kJpeg; break;
931 case ASIT_Xcf:
932 type = kXcf; break;
933 case ASIT_Ppm:
934 type = kPpm; break;
935 case ASIT_Pnm:
936 type = kPnm; break;
937 case ASIT_Bmp:
938 type = kBmp; break;
939 case ASIT_Ico:
940 type = kIco; break;
941 case ASIT_Cur:
942 type = kCur; break;
943 case ASIT_Gif:
944 type = kGif; break;
945 case ASIT_Tiff:
946 type = kTiff; break;
947 case ASIT_Xbm:
948 type = kXbm; break;
949 case ASIT_XMLScript:
950 type = kXml; break;
951 case ASIT_Targa:
952 type = kTga; break;
953 default:
954 type = kUnknown;
955 }
956 }
957}
958
959////////////////////////////////////////////////////////////////////////////////
960/// Map quality to/from AfterImage quality.
961/// Protected method.
962
964{
965 if (toas) {
966 switch (quality) {
967 case kImgPoor:
968 asquality = 25; break;
969 case kImgFast:
970 asquality = 75; break;
971 case kImgGood:
972 asquality = 50; break;
973 case kImgBest:
974 asquality = 100; break;
975 default:
976 asquality = 0;
977 }
978 } else {
979 quality = kImgDefault;
980 if (asquality > 0 && asquality <= 25)
981 quality = kImgPoor;
982 if (asquality > 26 && asquality <= 50)
983 quality = kImgFast;
984 if (asquality > 51 && asquality <= 75)
985 quality = kImgGood;
986 if (asquality > 76 && asquality <= 100)
987 quality = kImgBest;
988 }
989}
990
991////////////////////////////////////////////////////////////////////////////////
992/// Deletes the old image and creates a new image depending on the values
993/// of imageData. The size of the image is width X height.
994///
995/// The color of each pixel depends on the imageData of the corresponding
996/// pixel. The palette is used to convert an image value into its color.
997/// If palette is not defined (palette = 0) a default palette is used.
998/// Any previously defined zooming is reset.
999
1002{
1004
1005 if (!InitVisual()) {
1006 Warning("SetImage", "Visual not initiated");
1007 return;
1008 }
1009
1010 DestroyImage();
1012
1013 // get min and max value of image
1015 for (Int_t pixel = 1; pixel < Int_t(width * height); pixel++) {
1016 if (fMinValue > *(imageData + pixel)) fMinValue = *(imageData + pixel);
1017 if (fMaxValue < *(imageData + pixel)) fMaxValue = *(imageData + pixel);
1018 }
1019
1020 // copy ROOT palette to asImage palette
1021 const TImagePalette &pal = GetPalette();
1022
1024
1025 asPalette.npoints = pal.fNumPoints;
1026 Int_t col;
1027 for (col = 0; col < 4; col++)
1028 asPalette.channels[col] = new UShort_t[asPalette.npoints];
1029
1030 memcpy(asPalette.channels[0], pal.fColorBlue, pal.fNumPoints * sizeof(UShort_t));
1031 memcpy(asPalette.channels[1], pal.fColorGreen, pal.fNumPoints * sizeof(UShort_t));
1032 memcpy(asPalette.channels[2], pal.fColorRed, pal.fNumPoints * sizeof(UShort_t));
1033 memcpy(asPalette.channels[3], pal.fColorAlpha, pal.fNumPoints * sizeof(UShort_t));
1034
1035 asPalette.points = new Double_t[asPalette.npoints];
1036 for (Int_t point = 0; point < Int_t(asPalette.npoints); point++)
1037 asPalette.points[point] = fMinValue + (fMaxValue - fMinValue) * pal.fPoints[point];
1038
1042
1043 delete [] asPalette.points;
1044 for (col = 0; col < 4; col++)
1045 delete [] asPalette.channels[col];
1046
1047 fZoomUpdate = 0;
1048 fZoomOffX = 0;
1049 fZoomOffY = 0;
1050 fZoomWidth = width;
1053}
1054
1055////////////////////////////////////////////////////////////////////////////////
1056/// Delete the old image and creates a new image depending on the values
1057/// of imageData. The size of the image is width X (imageData.fN / width).
1058/// The color of each pixel depends on the imageData of the corresponding
1059/// pixel. The palette is used to convert an image value into its color.
1060/// If palette is not defined (palette = 0) a default palette is used.
1061/// Any previously defined zooming is reset.
1062
1067
1068////////////////////////////////////////////////////////////////////////////////
1069/// Delete the old image and creates a new image depending on the values
1070/// of imageData. The size of the image is width X (imageData.fN / width).
1071/// The color of each pixel depends on the imageData of the corresponding
1072/// pixel. The palette is used to convert an image value into its color.
1073/// If palette is not defined (palette = 0) a default palette is used.
1074/// Any previously defined zooming is reset.
1075
1077{
1078 SetImage(imageData.GetMatrixArray(), width,
1079 imageData.GetNoElements() / width, palette);
1080}
1081
1082////////////////////////////////////////////////////////////////////////////////
1083/// Create an image from the given pad, afterwards this image can be
1084/// saved in any of the supported image formats.
1085
1087{
1088 if (!pad) {
1089 Error("FromPad", "pad cannot be 0");
1090 return;
1091 }
1092
1093 if (!InitVisual()) {
1094 Warning("FromPad", "Visual not initiated");
1095 return;
1096 }
1097
1098 SetName(pad->GetName());
1099
1100 DestroyImage();
1102
1103 if (gROOT->IsBatch()) { // in batch mode
1105 gVirtualPS = new TImageDump();
1106 gVirtualPS->Open(pad->GetName(), 114); // in memory
1107 gVirtualPS->SetBit(BIT(11)); //kPrintingPS
1108
1110
1111 if (itmp && itmp->fImage) {
1112 itmp->BeginPaint();
1113 }
1114
1115 {
1117 pad->Paint();
1118 }
1119
1120 if (itmp && itmp->fImage && (itmp != this)) {
1121 fImage = clone_asimage(itmp->fImage, SCL_DO_ALL);
1122 if (itmp->fImage->alt.argb32) {
1123 UInt_t sz = itmp->fImage->width*itmp->fImage->height;
1124 fImage->alt.argb32 = (ARGB32*)safemalloc(sz*sizeof(ARGB32));
1125 memcpy(fImage->alt.argb32, itmp->fImage->alt.argb32, sz*4);
1126 }
1127 }
1128 delete gVirtualPS;
1129 gVirtualPS = psave;
1130 return;
1131 }
1132
1133 // X11 Synchronization
1134 gVirtualX->Update(1);
1135 if (!gThreadXAR) {
1136 gSystem->Sleep(100);
1138 gSystem->Sleep(10);
1140 }
1141
1142 TVirtualPad *canvas = (TVirtualPad*)pad->GetCanvas();
1143 Int_t wid = (pad == canvas) ? pad->GetCanvasID() : pad->GetPixmapID();
1144 gVirtualX->SelectWindow(wid);
1145
1146 Window_t wd = (Window_t)gVirtualX->GetCurrentWindow();
1147 if (!wd) return;
1148
1149 if (w == 0) w = TMath::Abs(pad->UtoPixel(1.));
1150 if (h == 0) h = pad->VtoPixel(0.);
1151
1152 static int x11 = -1;
1153 if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11");
1154
1155 if (x11) { //use built-in optimized version
1156 fImage = pixmap2asimage(fgVisual, wd, x, y, w, h, kAllPlanes, 0, 0);
1157 } else {
1158 unsigned char *bits = gVirtualX->GetColorBits(wd, 0, 0, w, h);
1159
1160 if (!bits) { // error
1161 return;
1162 }
1163 fImage = bitmap2asimage(bits, w, h, 0, nullptr);
1164 delete [] bits;
1165 }
1166}
1167
1168////////////////////////////////////////////////////////////////////////////////
1169/// Draw image.
1170/// Support the following drawing options:
1171/// - "T[x,y[,tint]]" : tile image (use specified offset and tint),
1172/// e.g. "T100,100,#556655"
1173/// with this option the zooming is not possible
1174/// and disabled
1175/// - "N" : display in new canvas (of original image size)
1176/// - "X" : image is drawn expanded to pad size
1177/// - "Z" : image is vectorized and image palette is drawn
1178///
1179/// The default is to display the image in the current gPad.
1180
1182{
1183 if (!fImage) {
1184 Error("Draw", "no image set");
1185 return;
1186 }
1187
1188 TString opt = option;
1189 opt.ToLower();
1190 if (opt.Contains("n") || !gPad || !gPad->IsEditable()) {
1191 Int_t w = -64;
1192 Int_t h = 64;
1193 w = (fImage->width > 64) ? (Int_t)fImage->width : w;
1194 h = (fImage->height > 64) ? (Int_t)fImage->height : h;
1195
1197 w = Int_t(w*cx) + 4;
1198 h = Int_t(h*cx) + 28;
1199 TString rname = GetName();
1200 rname.ReplaceAll(".", "");
1201 rname += TString::Format("\", \"%s (%d x %d)", rname.Data(), fImage->width, fImage->height);
1202 rname = "new TCanvas(\"" + rname + TString::Format("\", %d, %d);", w, h);
1203 gROOT->ProcessLineFast(rname.Data());
1204 }
1205
1206 if (!opt.Contains("x")) {
1207 Double_t left = gPad->GetLeftMargin();
1208 Double_t right = gPad->GetRightMargin();
1209 Double_t top = gPad->GetTopMargin();
1210 Double_t bottom = gPad->GetBottomMargin();
1211
1212 gPad->Range(-left / (1.0 - left - right),
1213 -bottom / (1.0 - top - bottom),
1214 1 + right / (1.0 - left - right),
1215 1 + top / ( 1.0 - top - bottom));
1216 gPad->RangeAxis(0, 0, 1, 1);
1217 }
1218
1219 TFrame *frame = gPad->GetFrame();
1220 if (frame) {
1221 frame->SetBorderMode(0);
1222 frame->SetFillColor(gPad->GetFillColor());
1223 frame->SetLineColor(gPad->GetFillColor());
1224 frame->Draw();
1225 }
1226
1228}
1229
1230////////////////////////////////////////////////////////////////////////////////
1231/// Draw asimage on drawable.
1232
1235 Option_t *opt)
1236{
1237 if (!im) return;
1238
1239 wsrc = wsrc ? wsrc : im->width;
1240 hsrc = hsrc ? hsrc : im->height;
1241
1242 static int x11 = -1;
1243 if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11");
1244
1246
1247 if (x11) {
1248 UInt_t hh = hsrc;
1249 UInt_t ow = wsrc%8;
1250 UInt_t ww = wsrc - ow + (ow ? 8 : 0);
1251
1252 UInt_t bit = 0;
1253 int i = 0;
1254 UInt_t yy = 0;
1255 UInt_t xx = 0;
1256
1257 char *bits = new char[ww*hh]; //an array of bits
1258
1260 xsrc, ysrc, ww, 0, nullptr);
1261 if (imdec) {
1262 for (yy = 0; yy < hh; yy++) {
1263 imdec->decode_image_scanline(imdec);
1264 CARD32 *a = imdec->buffer.alpha;
1265
1266 for (xx = 0; xx < ww; xx++) {
1267 if (a[xx]) {
1268 SETBIT(bits[i], bit);
1269 } else {
1270 CLRBIT(bits[i], bit);
1271 }
1272 bit++;
1273 if (bit == 8) {
1274 bit = 0;
1275 i++;
1276 }
1277 }
1278 }
1279 }
1280
1282
1283 mask = gVirtualX->CreateBitmap(gVirtualX->GetDefaultRootWindow(),
1284 (const char *)bits, ww, hh);
1285 delete [] bits;
1286 }
1287
1288 GCValues_t gv;
1289 static GContext_t gc = 0;
1290
1292 gv.fClipMask = mask;
1293 gv.fClipXOrigin = x;
1294 gv.fClipYOrigin = y;
1295
1296 if (!gc) {
1297 gc = gVirtualX->CreateGC(gVirtualX->GetDefaultRootWindow(), &gv);
1298 } else {
1299 gVirtualX->ChangeGC(gc, &gv);
1300 }
1301
1302 if (x11 && (!gPad || gPad->GetGLDevice() == -1)) { //use built-in optimized version
1303 asimage2drawable(fgVisual, wid, im, (GC)gc, xsrc, ysrc, x, y, wsrc, hsrc, 1);
1304 } else {
1305 ASImage *img = nullptr;
1306 unsigned char *bits = (unsigned char *)im->alt.argb32;
1307 if (!bits) {
1310 if (img)
1311 bits = (unsigned char *)img->alt.argb32;
1312 }
1313
1314 if (bits) {
1315 TString option(opt);
1316 option.ToLower();
1317
1318 if (gPad && gPad->GetGLDevice() != -1) {
1319 if (TVirtualPadPainter *painter = gPad->GetPainter())
1320 painter->DrawPixels(bits, wsrc, hsrc, x, y, !option.Contains("opaque"));
1321 } else {
1322 Pixmap_t pic = gVirtualX->CreatePixmapFromData(bits, wsrc, hsrc);
1323 if (pic) {
1324 if (!option.Contains("opaque")) {
1325 SETBIT(wsrc,31);
1326 SETBIT(hsrc,31);
1327 }
1328 gVirtualX->CopyArea(pic, wid, gc, 0, 0, wsrc, hsrc, x, y);
1329 gVirtualX->DeletePixmap(pic);
1330 }
1331 }
1332 }
1333
1334 if (img) {
1336 }
1337 }
1338
1339 // free mask pixmap
1340 if (gv.fClipMask != kNone) gVirtualX->DeletePixmap(gv.fClipMask);
1341
1342 gv.fMask = kGCClipMask;
1343 gv.fClipMask = kNone;
1344 if (gc) gVirtualX->ChangeGC(gc, &gv);
1345}
1346
1347
1348////////////////////////////////////////////////////////////////////////////////
1349/// Draw image on the drawable wid (pixmap, window) at x,y position.
1350///
1351/// \param[in] wid : Drawable (pixmap or window) on which image is drawn.
1352/// \param[in] x,y : Window coordinates where image is drawn.
1353/// \param[in] xsrc, ysrc : X and Y coordinates of an image area to be drawn.
1354/// \param[in] wsrc, hsrc : Width and height image area to be drawn.
1355/// \param[in] opt : specific options
1356
1363
1364////////////////////////////////////////////////////////////////////////////////
1365/// Paint image.
1366/// Support the following drawing options:
1367/// - "T[x,y[,tint]]" : tile image (use specified offset and tint),
1368/// e.g. "T100,100,#556655"
1369/// with this option the zooming is not possible
1370/// and disabled
1371/// - "N" : display in new canvas (of original image size)
1372/// - "X" : image is drawn expanded to pad size
1373/// - "Z" : image is vectorized and image palette is drawn
1374///
1375/// The default is to display the image in the current gPad.
1376
1378{
1379 if (!fImage) {
1380 Error("Paint", "no image set");
1381 return;
1382 }
1383
1384 if (!InitVisual()) {
1385 Warning("Paint", "Visual not initiated");
1386 return;
1387 }
1388
1389 Int_t tile_x = 0, tile_y = 0;
1390 CARD32 tile_tint = 0;
1391 Bool_t tile = kFALSE;
1393
1394 TString opt = option;
1395 opt.ToLower();
1396
1397 if (opt.Contains("t")) {
1398 char stint[64];
1399 if (sscanf(opt.Data() + opt.Index("t"), "t%d,%d,%s", &tile_x, &tile_y,
1400 stint) <= 3) {
1401 tile = kTRUE;
1403 tile_tint = 0;
1404 } else {
1405 Error("Paint", "tile option error");
1406 }
1407 } else if (opt.Contains("x")) {
1408 expand = kTRUE;
1410 } else if (opt.Contains("z")) {
1412
1413 if (!fImage->alt.vector) {
1414 Vectorize(256);
1415 }
1416 }
1417
1418 ASImage *image = fImage;
1419
1420 // Get geometry of pad
1421 Int_t to_w = gPad->UtoPixel(1.);
1422 Int_t to_h = gPad->VtoPixel(0.);
1423
1424 // remove the size by the margin of the pad
1425 if (!expand) {
1426 to_h = (Int_t)(to_h * (1.0 - gPad->GetBottomMargin() - gPad->GetTopMargin() ) + 0.5);
1427 to_w = (Int_t)(to_w * (1.0 - gPad->GetLeftMargin() - gPad->GetRightMargin() ) + 0.5);
1428 }
1429
1430 if ((to_w < 25 || to_h < 25) && !expand) {
1431 Error("Paint", "pad too small to display an image");
1432 return;
1433 }
1434
1435 if (GetConstRatio()) {
1439 else
1441 }
1442 // upper left corner and size of the palette in pixels
1443 Int_t pal_Ax = to_w + gPad->UtoAbsPixel(gPad->GetLeftMargin()) +
1444 (gPad->UtoAbsPixel(gPad->GetRightMargin()) / 10);
1445 Int_t pal_Ay = gPad->YtoAbsPixel(1.0);
1446 Int_t pal_x = to_w + gPad->UtoPixel(gPad->GetLeftMargin()) +
1447 (gPad->UtoPixel(gPad->GetRightMargin()) / 10);
1448 Int_t pal_y = gPad->YtoPixel(1.0);
1449 Int_t pal_w = gPad->UtoPixel(gPad->GetRightMargin()) / 3;
1450 Int_t pal_h = to_h;
1451
1452 ASImage *grad_im = nullptr;
1453
1454 if (fImage->alt.vector && fPaletteEnabled) {
1455 // draw the palette
1456 ASGradient grad;
1457 const TImagePalette &pal = GetPalette();
1458
1459 grad.npoints = pal.fNumPoints;
1460 grad.type = GRADIENT_Top2Bottom;
1461 grad.color = new ARGB32[grad.npoints];
1462 grad.offset = new double[grad.npoints];
1463
1464 for (Int_t pt = 0; pt < grad.npoints; pt++) {
1465 Int_t oldPt = grad.npoints - pt -1;
1466 grad.offset[pt] = 1 - pal.fPoints[oldPt];
1467 grad.color[pt] = (((ARGB32)(pal.fColorBlue[oldPt] & 0xff00)) >> 8) |
1468 (((ARGB32)(pal.fColorGreen[oldPt] & 0xff00)) ) |
1469 (((ARGB32)(pal.fColorRed[oldPt] & 0xff00)) << 8) |
1470 (((ARGB32)(pal.fColorAlpha[oldPt] & 0xff00)) << 16);
1471 }
1472
1476
1477 delete [] grad.color;
1478 delete [] grad.offset;
1479 }
1480
1481 if (tile) {
1484 if (!fScaledImage) return;
1489
1490 } else if (fZoomUpdate == kZoomOps) {
1491 image = fImage;
1492
1493 } else {
1494 // Scale and zoom image if needed
1495 if (Int_t(fImage->width) != to_w || Int_t(fImage->height) != to_h ||
1496 fImage->width != fZoomWidth || fImage->height != fZoomHeight) {
1497
1498 if (fScaledImage && (Int_t(fScaledImage->GetWidth()) != to_w ||
1500 fZoomUpdate)) {
1501
1503 }
1504
1505 if (!fScaledImage) {
1507 if (!fScaledImage) return;
1508
1509 if (fZoomWidth && fZoomHeight &&
1510 ((fImage->width != fZoomWidth) || (fImage->height != fZoomHeight))) {
1511 // zoom and scale image
1513 fImage->height - fZoomHeight - fZoomOffY,
1516
1517 if (tmpImage) {
1520 GetImageQuality());
1522 }
1523 } else {
1524 // scale image, no zooming
1527 GetImageQuality());
1528 }
1529 }
1531 }
1532 }
1533 fZoomUpdate = 0;
1534
1535 if (!image) {
1536 Error("Paint", "image could not be rendered to display");
1537 return;
1538 }
1539
1540 int tox = expand ? 0 : int(gPad->UtoPixel(1.) * gPad->GetLeftMargin());
1541 int toy = expand ? 0 : int(gPad->VtoPixel(0.) * gPad->GetTopMargin());
1542
1543 auto ps = gPad->GetPainter()->GetPS();
1544
1545 if (!ps) {
1546 Window_t wid = (Window_t)gVirtualX->GetWindowID(gPad->GetPixmapID());
1548
1549 if (grad_im && fPaletteEnabled) {
1550 // draw color bar
1552
1553 // values of palette
1554 TGaxis axis;
1555 Int_t ndiv = 510;
1556 double min = fMinValue;
1557 double max = fMaxValue;
1558 axis.SetLineColor(0); // draw white ticks
1559 Double_t pal_Xpos = gPad->AbsPixeltoX(pal_Ax + pal_w);
1560 axis.PaintAxis(pal_Xpos, gPad->PixeltoY(pal_Ay + pal_h - 1),
1561 pal_Xpos, gPad->PixeltoY(pal_Ay),
1562 min, max, ndiv, "+LU");
1563 min = fMinValue;
1564 max = fMaxValue;
1565 axis.SetLineColor(1); // draw black ticks
1566 axis.PaintAxis(pal_Xpos, gPad->AbsPixeltoY(pal_Ay + pal_h),
1567 pal_Xpos, gPad->AbsPixeltoY(pal_Ay + 1),
1568 min, max, ndiv, "+L");
1569 }
1570 } else {
1571 // loop over pixmap and draw image to PostScript
1572
1574
1575 if (ps->InheritsFrom("TImageDump")) { // PostScript is asimage
1576 TImage *dump = (TImage *)ps->GetStream();
1577 if (!dump) return;
1578 dump->Merge(fScaledImage ? fScaledImage : this, "alphablend",
1579 gPad->XtoAbsPixel(0), gPad->YtoAbsPixel(1));
1580
1581 if (grad_im) {
1583 tgrad.fImage = grad_im;
1584 dump->Merge(&tgrad, "alphablend", pal_Ax, pal_Ay);
1585
1586 // values of palette
1587 TGaxis axis;
1588 Int_t ndiv = 510;
1589 double min = fMinValue;
1590 double max = fMaxValue;
1591 axis.SetLineColor(1); // draw black ticks
1592 Double_t pal_Xpos = gPad->AbsPixeltoX(pal_Ax + pal_w);
1593 axis.PaintAxis(pal_Xpos, gPad->AbsPixeltoY(pal_Ay + pal_h),
1594 pal_Xpos, gPad->AbsPixeltoY(pal_Ay + 1),
1595 min, max, ndiv, "+L");
1596 }
1597 return;
1598 } else if (ps->InheritsFrom("TSVG")) {
1600 }
1601
1602 Double_t dx = gPad->GetX2() - gPad->GetX1();
1603 Double_t dy = gPad->GetY2() - gPad->GetY1();
1604 Double_t x1, x2, y1, y2;
1605
1606 if (expand) {
1607 x1 = gPad->GetX1();
1608 x2 = x1+dx/image->width;
1609 y1 = gPad->GetY2();
1610 y2 = y1+dy/image->height;
1611 } else {
1612 x1 = gPad->GetX1()+dx*gPad->GetLeftMargin();
1613 x2 = x1+(dx*(1-gPad->GetRightMargin()-gPad->GetLeftMargin()))/image->width;
1614 y1 = gPad->GetY2()-dy*gPad->GetTopMargin();
1615 y2 = y1+(dy*(1-gPad->GetTopMargin()-gPad->GetBottomMargin()))/image->height;
1616 }
1617
1618 // get special color cell to be reused during image printing
1619 ps->SetFillColor(TColor::GetColor((Float_t) 1., (Float_t) 1., (Float_t) 1.));
1620 ps->SetFillStyle(1001);
1621
1622 ps->CellArrayBegin(image->width, image->height, x1, x2, y1, y2);
1623
1624 if (paint_as_png) {
1625 char *buffer = nullptr;
1626 int size = 0;
1627 ASImageExportParams params;
1628 params.png.type = ASIT_Png;
1629 params.png.flags = EXPORT_ALPHA;
1630 params.png.compression = GetImageCompression();
1631 if (!params.png.compression)
1632 params.png.compression = -1;
1633 if (ASImage2PNGBuff(image, (CARD8 **)&buffer, &size, &params)) {
1634 ps->CellArrayPng(buffer, size);
1635 free(buffer);
1636 }
1637 } else {
1639 0, 0, image->width, image->height, nullptr);
1640 if (imdec)
1641 for (Int_t yt = 0; yt < (Int_t)image->height; yt++) {
1642 imdec->decode_image_scanline(imdec);
1643 for (Int_t xt = 0; xt < (Int_t)image->width; xt++)
1644 ps->CellArrayFill(imdec->buffer.red[xt],
1645 imdec->buffer.green[xt],
1646 imdec->buffer.blue[xt]);
1647 }
1649 }
1650 ps->CellArrayEnd();
1651
1652 // print the color bar
1653 if (grad_im) {
1654 Double_t xconv = (gPad->AbsPixeltoX(pal_Ax + pal_w) - gPad->AbsPixeltoX(pal_Ax)) / grad_im->width;
1655 Double_t yconv = (gPad->AbsPixeltoY(pal_Ay - pal_h) - gPad->AbsPixeltoY(pal_Ay)) / grad_im->height;
1656 x1 = gPad->AbsPixeltoX(pal_Ax);
1657 x2 = x1 + xconv;
1658 y2 = gPad->AbsPixeltoY(pal_Ay);
1659 y1 = y2 - yconv;
1660 ps->CellArrayBegin(grad_im->width, grad_im->height,
1661 x1, x2, y1, y2);
1662
1663 if (paint_as_png) {
1664 char *buffer = nullptr;
1665 int size = 0;
1666 ASImageExportParams params;
1667 params.png.type = ASIT_Png;
1668 params.png.flags = EXPORT_ALPHA;
1669 params.png.compression = GetImageCompression();
1670 if (!params.png.compression)
1671 params.png.compression = -1;
1672
1673 if (ASImage2PNGBuff(grad_im, (CARD8 **)&buffer, &size, &params)) {
1674 ps->CellArrayPng(buffer, size);
1675 free(buffer);
1676 }
1677 } else {
1679 0, 0, grad_im->width, grad_im->height, nullptr);
1680 if (imdec)
1681 for (Int_t yt = 0; yt < (Int_t)grad_im->height; yt++) {
1682 imdec->decode_image_scanline(imdec);
1683 for (Int_t xt = 0; xt < (Int_t)grad_im->width; xt++)
1684 ps->CellArrayFill(imdec->buffer.red[xt],
1685 imdec->buffer.green[xt],
1686 imdec->buffer.blue[xt]);
1687 }
1689 }
1690 ps->CellArrayEnd();
1691
1692 // values of palette
1693 TGaxis axis;
1694 Int_t ndiv = 510;
1695 double min = fMinValue;
1696 double max = fMaxValue;
1697 axis.SetLineColor(1); // draw black ticks
1698 Double_t pal_Xpos = gPad->AbsPixeltoX(pal_Ax + pal_w);
1699 // TODO: provide PaintAxisOn method
1700 axis.PaintAxis(pal_Xpos, gPad->AbsPixeltoY(pal_Ay + pal_h),
1701 pal_Xpos, gPad->AbsPixeltoY(pal_Ay + 1),
1702 min, max, ndiv, "+L");
1703
1704 }
1705 }
1706
1707 if (grad_im) {
1709 }
1710}
1711
1712////////////////////////////////////////////////////////////////////////////////
1713/// Is the mouse in the image ?
1714
1716{
1717 Int_t pxl, pyl, pxt, pyt;
1718
1719 Int_t px1 = gPad->XtoAbsPixel(0);
1720 Int_t py1 = gPad->YtoAbsPixel(0);
1721 Int_t px2 = gPad->XtoAbsPixel(1);
1722 Int_t py2 = gPad->YtoAbsPixel(1);
1723
1724 if (px1 < px2) {pxl = px1; pxt = px2;}
1725 else {pxl = px2; pxt = px1;}
1726 if (py1 < py2) {pyl = py1; pyt = py2;}
1727 else {pyl = py2; pyt = py1;}
1728
1729 if ((px > pxl && px < pxt) && (py > pyl && py < pyt))
1730 return 0;
1731
1732 return 999999;
1733}
1734
1735////////////////////////////////////////////////////////////////////////////////
1736/// Execute mouse events.
1737
1739{
1740 static std::unique_ptr<TBox> ZoomBox;
1741
1742 if (!gPad) return;
1743
1744 if (IsEditable()) {
1745 gPad->ExecuteEvent(event, px, py);
1746 return;
1747 }
1748
1749 gPad->SetCursor(kCross);
1750
1751 static Int_t px1old, py1old, px2old, py2old;
1752 static Int_t px1, py1, px2, py2, pxl, pyl, pxt, pyt;
1753
1754 if (!IsValid()) return;
1755
1756 if (event == kButton1Motion || event == kButton1Down ||
1757 event == kButton1Up) {
1758
1759 // convert to image pixel on screen
1760 Int_t imgX = px - gPad->XtoAbsPixel(0);
1761 Int_t imgY = py - gPad->YtoAbsPixel(1);
1762
1763 if (imgX < 0) px = px - imgX;
1764 if (imgY < 0) py = py - imgY;
1765
1766 ASImage *image = fImage;
1768
1769 if (imgX >= (int)image->width) px = px - imgX + image->width - 1;
1770 if (imgY >= (int)image->height) py = py - imgY + image->height - 1;
1771
1772 switch (event) {
1773
1774 case kButton1Down:
1775 px1 = gPad->XtoAbsPixel(gPad->GetX1());
1776 py1 = gPad->YtoAbsPixel(gPad->GetY1());
1777 px2 = gPad->XtoAbsPixel(gPad->GetX2());
1778 py2 = gPad->YtoAbsPixel(gPad->GetY2());
1779 px1old = px; py1old = py;
1780 break;
1781
1782 case kButton1Motion:
1783 px2old = px;
1784 px2old = TMath::Max(px2old, px1);
1785 px2old = TMath::Min(px2old, px2);
1786 py2old = py;
1787 py2old = TMath::Max(py2old, py2);
1788 py2old = TMath::Min(py2old, py1);
1793
1794 if (ZoomBox) {
1795 ZoomBox->SetX1(gPad->AbsPixeltoX(pxl));
1796 ZoomBox->SetY1(gPad->AbsPixeltoY(pyl));
1797 ZoomBox->SetX2(gPad->AbsPixeltoX(pxt));
1798 ZoomBox->SetY2(gPad->AbsPixeltoY(pyt));
1799 } else {
1800 ZoomBox = std::make_unique<TBox>(pxl, pyl, pxt, pyt);
1801 ZoomBox->SetFillStyle(0);
1802 ZoomBox->Draw("l*");
1803 }
1804 gPad->Modified(kTRUE);
1805 gPad->Update();
1806 break;
1807
1808 case kButton1Up:
1809 // do nothing if zoom area is too small
1810 if ( TMath::Abs(pxl - pxt) < 5 || TMath::Abs(pyl - pyt) < 5)
1811 return;
1812
1813 pxl = 0;
1814 pxt = 0;
1815 pyl = 0;
1816 pyt = 0;
1817
1820
1821 Int_t imgX1 = px1old - gPad->XtoAbsPixel(0);
1822 Int_t imgY1 = py1old - gPad->YtoAbsPixel(1);
1823 Int_t imgX2 = px - gPad->XtoAbsPixel(0);
1824 Int_t imgY2 = py - gPad->YtoAbsPixel(1);
1825
1826 imgY1 = image->height - 1 - imgY1;
1827 imgY2 = image->height - 1 - imgY2;
1828 imgX1 = (Int_t)(imgX1 / xfact) + fZoomOffX;
1829 imgY1 = (Int_t)(imgY1 / yfact) + fZoomOffY;
1830 imgX2 = (Int_t)(imgX2 / xfact) + fZoomOffX;
1831 imgY2 = (Int_t)(imgY2 / yfact) + fZoomOffY;
1832
1833 Zoom((imgX1 < imgX2) ? imgX1 : imgX2, (imgY1 < imgY2) ? imgY1 : imgY2,
1834 TMath::Abs(imgX1 - imgX2) + 1, TMath::Abs(imgY1 - imgY2) + 1);
1835
1836 if (ZoomBox)
1837 ZoomBox.reset();
1838
1839 gPad->Modified(kTRUE);
1840 gPad->Update();
1841 break;
1842 }
1843 }
1844}
1845
1846////////////////////////////////////////////////////////////////////////////////
1847/// Get image pixel coordinates and the pixel value at the mouse pointer.
1848
1850{
1851 static char info[64];
1852 info[0] = 0;
1853
1854 if (!IsValid()) return info;
1855
1856 // convert to image pixel on screen
1857 px -= gPad->XtoAbsPixel(0);
1858 py -= gPad->YtoAbsPixel(1);
1859
1860 // no info if mouse is outside of image
1861 if (px < 0 || py < 0) return info;
1862
1863 ASImage *image = fImage;
1865 if (px >= (int)image->width || py >= (int)image->height)
1866 return info;
1867
1868 py = image->height - 1 - py;
1869 // convert to original image size and take zooming into account
1870 if (fScaledImage) {
1871 px = (Int_t)(px / (Double_t)fScaledImage->fImage->width * fZoomWidth ) + fZoomOffX;
1872 py = (Int_t)(py / (Double_t)fScaledImage->fImage->height * fZoomHeight) + fZoomOffY;
1873 }
1874
1875 if (fImage->alt.vector) {
1876 snprintf(info,64,"x: %d y: %d %.5g",
1877 px, py, fImage->alt.vector[px + py * fImage->width]);
1878 } else {
1879 snprintf(info,64,"x: %d y: %d", px, py);
1880 }
1881
1882 return info;
1883}
1884
1885////////////////////////////////////////////////////////////////////////////////
1886/// Set a new palette to an image.
1887/// Only images that were created with the SetImage() functions can be
1888/// modified with this function. The previously used palette is destroyed.
1889
1891{
1893
1894 if (!InitVisual()) {
1895 Warning("SetPalette", "Visual not initiated");
1896 return;
1897 }
1898
1899 if (!IsValid()) {
1900 Warning("SetPalette", "Image not valid");
1901 return;
1902 }
1903
1904 if (!fImage->alt.vector)
1905 return;
1906
1907 // copy ROOT palette to asImage palette
1908 const TImagePalette &pal = GetPalette();
1909
1911 asPalette.npoints = pal.fNumPoints;
1912 asPalette.channels[0] = new CARD16 [asPalette.npoints];
1913 asPalette.channels[1] = new CARD16 [asPalette.npoints];
1914 asPalette.channels[2] = new CARD16 [asPalette.npoints];
1915 asPalette.channels[3] = new CARD16 [asPalette.npoints];
1916 memcpy(asPalette.channels[0], pal.fColorBlue, pal.fNumPoints * sizeof(UShort_t));
1917 memcpy(asPalette.channels[1], pal.fColorGreen, pal.fNumPoints * sizeof(UShort_t));
1918 memcpy(asPalette.channels[2], pal.fColorRed, pal.fNumPoints * sizeof(UShort_t));
1919 memcpy(asPalette.channels[3], pal.fColorAlpha, pal.fNumPoints * sizeof(UShort_t));
1920
1921 asPalette.points = new double[asPalette.npoints];
1922 for (Int_t point = 0; point < Int_t(asPalette.npoints); point++)
1923 asPalette.points[point] = fMinValue + (fMaxValue - fMinValue) * pal.fPoints[point];
1924
1925 // use the new palette in this image
1927
1928 delete [] asPalette.points;
1929 for (Int_t col = 0; col < 4; col++)
1930 delete [] asPalette.channels[col];
1931
1933}
1934
1935////////////////////////////////////////////////////////////////////////////////
1936/// Scale the original image.
1937/// The size of the image on the screen does not change because it is defined
1938/// by the size of the pad.
1939/// This function can be used to change the size of an image before writing
1940/// it into a file. The colors of the new pixels are interpolated.
1941/// An image created with the SetImage() functions cannot be modified with
1942/// the function SetPalette() any more after a call of this function!
1943
1945{
1946 if (!IsValid()) {
1947 Warning("Scale", "Image not initiated");
1948 return;
1949 }
1950
1951 if (!InitVisual()) {
1952 Warning("Scale", "Visual not initiated");
1953 return;
1954 }
1955
1956 if (toWidth < 1)
1957 toWidth = 1;
1958 if (toHeight < 1 )
1959 toHeight = 1;
1960 if (toWidth > 30000)
1961 toWidth = 30000;
1962 if (toHeight > 30000)
1963 toHeight = 30000;
1964
1967 GetImageQuality());
1968 DestroyImage();
1969 fImage = img;
1970 UnZoom();
1972}
1973
1974////////////////////////////////////////////////////////////////////////////////
1975/// Another method of enlarging images where corners remain unchanged,
1976/// but middle part gets tiled.
1977
1980{
1981 if (!IsValid()) {
1982 Warning("Slice", "Image not initiated");
1983 return;
1984 }
1985
1986 if (!InitVisual()) {
1987 Warning("Slice", "Visual not initiated");
1988 return;
1989 }
1990
1991 if (toWidth < 1)
1992 toWidth = 1;
1993 if (toHeight < 1 )
1994 toHeight = 1;
1995 if (toWidth > 30000)
1996 toWidth = 30000;
1997 if (toHeight > 30000)
1998 toHeight = 30000;
1999
2003 GetImageQuality());
2004
2005 DestroyImage();
2006 fImage = img;
2007 UnZoom();
2009}
2010
2011////////////////////////////////////////////////////////////////////////////////
2012/// Tile the original image.
2013
2015{
2016 if (!IsValid()) {
2017 Warning("Tile", "Image not initiated");
2018 return;
2019 }
2020
2021 if (!InitVisual()) {
2022 Warning("Tile", "Visual not initiated");
2023 return;
2024 }
2025
2026 if (toWidth < 1)
2027 toWidth = 1;
2028 if (toHeight < 1 )
2029 toHeight = 1;
2030 if (toWidth > 30000)
2031 toWidth = 30000;
2032 if (toHeight > 30000)
2033 toHeight = 30000;
2034
2037 DestroyImage();
2038 fImage = img;
2039 UnZoom();
2041}
2042
2043////////////////////////////////////////////////////////////////////////////////
2044/// The area of an image displayed in a pad is defined by this function.
2045/// Note: the size on the screen is defined by the size of the pad.
2046/// The original image is not modified by this function.
2047/// If width or height is larger than the original image they are reduced to
2048/// the width and height of the image.
2049/// If the off values are too large (off + width > image width) than the off
2050/// values are decreased. For example: offX = image width - width
2051/// Note: the parameters are always relative to the original image not to the
2052/// size of an already zoomed image.
2053
2055{
2056 if (!IsValid()) {
2057 Warning("Zoom", "Image not valid");
2058 return;
2059 }
2061
2062 fZoomWidth = (width == 0) ? 1 : ((width > fImage->width) ? fImage->width : width);
2063 fZoomHeight = (height == 0) ? 1 : ((height > fImage->height) ? fImage->height : height);
2064 fZoomOffX = offX;
2065 if (fZoomOffX + fZoomWidth > fImage->width)
2066 fZoomOffX = fImage->width - fZoomWidth;
2067 fZoomOffY = offY;
2068 if (fZoomOffY + fZoomHeight > fImage->height)
2069 fZoomOffY = fImage->height - fZoomHeight;
2070}
2071
2072////////////////////////////////////////////////////////////////////////////////
2073/// Un-zoom the image to original size.
2074/// UnZoom() - performs undo for Zoom,Crop,Scale actions
2075
2077{
2078 if (!IsValid()) {
2079 Warning("UnZoom", "Image not valid");
2080 return;
2081 }
2083 fZoomOffX = 0;
2084 fZoomOffY = 0;
2085 fZoomWidth = fImage->width;
2086 fZoomHeight = fImage->height;
2087
2089}
2090
2091////////////////////////////////////////////////////////////////////////////////
2092/// Flip image in place.
2093///
2094/// Flip is either 90, 180, 270, 180 is default.
2095/// This function manipulates the original image and destroys the
2096/// scaled and zoomed image which will be recreated at the next call of
2097/// the Draw function. If the image is zoomed the zoom - coordinates are
2098/// now relative to the new image.
2099/// This function cannot be used for images which were created with the
2100/// SetImage() functions, because the original pixel values would be
2101/// destroyed.
2102
2104{
2105 if (!IsValid()) {
2106 Warning("Flip", "Image not valid");
2107 return;
2108 }
2109 if (!InitVisual()) {
2110 Warning("Flip", "Visual not initiated");
2111 return;
2112 }
2113
2114 if (fImage->alt.vector) {
2115 Warning("Flip", "flip does not work for data images");
2116 return;
2117 }
2118
2119 Int_t rflip = flip/90;
2120
2121 UInt_t w = fImage->width;
2122 UInt_t h = fImage->height;
2123
2124 if (rflip & 1) {
2125 w = fImage->height;
2126 h = fImage->width;
2127 }
2128
2131 GetImageQuality());
2132 DestroyImage();
2133 fImage = img;
2134 UnZoom();
2135}
2136
2137////////////////////////////////////////////////////////////////////////////////
2138/// Mirror image in place.
2139///
2140/// If vert is true mirror in vertical axis, horizontal otherwise.
2141/// Vertical is default.
2142/// This function manipulates the original image and destroys the
2143/// scaled and zoomed image which will be recreated at the next call of
2144/// the Draw function. If the image is zoomed the zoom - coordinates are
2145/// now relative to the new image.
2146/// This function cannot be used for images which were created with the
2147/// SetImage() functions, because the original pixel values would be
2148/// destroyed.
2149
2151{
2152 if (!IsValid()) {
2153 Warning("Mirror", "Image not valid");
2154 return;
2155 }
2156
2157 if (!InitVisual()) {
2158 Warning("Mirror", "Visual not initiated");
2159 return;
2160 }
2161
2162 if (fImage->alt.vector) {
2163 Warning("Mirror", "mirror does not work for data images");
2164 return;
2165 }
2166
2168 fImage->width, fImage->height, vert,
2170 GetImageQuality());
2171 DestroyImage();
2172 fImage = img;
2173 UnZoom();
2174}
2175
2176////////////////////////////////////////////////////////////////////////////////
2177/// Return width of original image not of the displayed image.
2178/// (Number of image pixels)
2179
2181{
2182 return fImage ? fImage->width : 0;
2183}
2184
2185////////////////////////////////////////////////////////////////////////////////
2186/// Return height of original image not of the displayed image.
2187/// (Number of image pixels)
2188
2190{
2191 return fImage ? fImage->height : 0;
2192}
2193
2194////////////////////////////////////////////////////////////////////////////////
2195/// Return width of the displayed image not of the original image.
2196/// (Number of screen pixels)
2197
2199{
2200 return fScaledImage ? fScaledImage->fImage->width : GetWidth();
2201}
2202
2203////////////////////////////////////////////////////////////////////////////////
2204/// Return height of the displayed image not of the original image.
2205/// (Number of screen pixels)
2206
2208{
2209 return fScaledImage ? fScaledImage->fImage->height : GetHeight();
2210}
2211
2212////////////////////////////////////////////////////////////////////////////////
2213/// Return the zoom parameters.
2214/// This is useful when the zoom has been done interactively using the mouse.
2215
2217{
2218 x = fZoomOffX;
2219 y = fZoomOffY;
2220 w = fZoomWidth;
2221 h = fZoomHeight;
2222}
2223
2224////////////////////////////////////////////////////////////////////////////////
2225/// Static function to initialize the ASVisual.
2226
2228{
2229 Bool_t noX = gROOT->IsBatch() || !gVirtualX->InheritsFrom("TGX11");
2230
2231 if (fgVisual && (noX == fgBatch))
2232 return kTRUE;
2233
2234 fgVisual = nullptr;
2235 fgBatch = false;
2236
2237#ifndef WIN32
2238#ifndef R__HAS_COCOA
2239 Display *disp = (Display*) gVirtualX->GetDisplay();
2240 Int_t screen = gVirtualX->GetScreen();
2241 Int_t depth = gVirtualX->GetDepth();
2242 Visual *vis = (Visual*) gVirtualX->GetVisual();
2243 Colormap cmap = (Colormap) gVirtualX->GetColormap();
2244
2245 static ASVisual *vis_x = nullptr;
2246
2247 if (vis && cmap && !noX) {
2248 if (!vis_x)
2250 XVisualIDFromVisual(vis), cmap, nullptr);
2251 fgVisual = vis_x;
2252 }
2253#endif
2254#endif
2255
2256 static ASVisual *vis_batch = nullptr;
2257
2258 if (!fgVisual) {
2259 if (!vis_batch) {
2260 // create dummy visual for batch mode
2261 vis_batch = create_asvisual(nullptr, 0, 0, nullptr);
2262 vis_batch->dpy = nullptr; // fake (not used)
2263 }
2264
2266 fgBatch = true;
2267 }
2268
2269 return kTRUE;
2270}
2271
2272////////////////////////////////////////////////////////////////////////////////
2273/// Static function to initialize the image.
2275{
2276 if (!InitVisual()) {
2277 Warning(caller, "Visual not initiated");
2278 return false;
2279 }
2280
2281 if (!fImage) {
2282 Warning(caller, "no image");
2283 return false;
2284 }
2285
2286 if (!fImage->alt.argb32) {
2287 BeginPaint();
2288 }
2289
2290 if (!fImage->alt.argb32) {
2291 Warning(caller, "Failed to get argb32 pixel array");
2292 return false;
2293 }
2294 return true;
2295}
2296
2297////////////////////////////////////////////////////////////////////////////////
2298/// Start palette editor.
2299
2301{
2302 if (!IsValid()) {
2303 Warning("StartPaletteEditor", "Image not valid");
2304 return;
2305 }
2306 if (!fImage->alt.vector) {
2307 Warning("StartPaletteEditor", "palette can be modified only for data images");
2308 return;
2309 }
2310
2311 // Opens a GUI to edit the color palette
2313}
2314
2315////////////////////////////////////////////////////////////////////////////////
2316/// Returns image pixmap.
2317/// The pixmap must deleted by user.
2318
2320{
2321 if (!InitVisual()) {
2322 Warning("GetPixmap", "Visual not initiated");
2323 return 0;
2324 }
2325
2326 Pixmap_t ret;
2327
2329
2330 static int x11 = -1;
2331 if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11");
2332
2333 if (x11) { // use builtin version
2334 ret = (Pixmap_t)asimage2pixmap(fgVisual, gVirtualX->GetDefaultRootWindow(),
2335 img, nullptr, kTRUE);
2336 } else {
2337 if (!fImage->alt.argb32) {
2338 BeginPaint();
2339 }
2340 ret = gVirtualX->CreatePixmapFromData((unsigned char*)fImage->alt.argb32,
2341 fImage->width, fImage->height);
2342 }
2343
2344 return ret;
2345}
2346
2347////////////////////////////////////////////////////////////////////////////////
2348/// Returns image mask pixmap (alpha channel).
2349/// The pixmap must deleted by user.
2350
2352{
2353 Pixmap_t pxmap = 0;
2354
2355 if (!InitVisual()) {
2356 Warning("GetMask", "Visual not initiated");
2357 return pxmap;
2358 }
2359
2361
2362 if (!img) {
2363 Warning("GetMask", "No image");
2364 return pxmap;
2365 }
2366
2367 UInt_t hh = img->height;
2368 UInt_t ow = img->width%8;
2369 UInt_t ww = img->width - ow + (ow ? 8 : 0);
2370
2372 0, 0, ww, 0, nullptr);
2373 if (!imdec)
2374 return pxmap;
2375
2376 std::vector<char> bits(ww * hh / 8); //an array of bits
2377
2378 UInt_t bit = 0, i = 0;
2379 for (UInt_t y = 0; y < hh; y++) {
2380 imdec->decode_image_scanline(imdec);
2381 CARD32 *a = imdec->buffer.alpha;
2382
2383 for (UInt_t x = 0; x < ww; x++) {
2384 if (a[x]) {
2385 SETBIT(bits[i], bit);
2386 } else {
2387 CLRBIT(bits[i], bit);
2388 }
2389 if (++bit == 8) {
2390 bit = 0;
2391 i++;
2392 }
2393 }
2394 }
2395
2397 pxmap = gVirtualX->CreateBitmap(gVirtualX->GetDefaultRootWindow(), bits.data(), ww, hh);
2398 return pxmap;
2399}
2400
2401////////////////////////////////////////////////////////////////////////////////
2402/// Create image from pixmap.
2403
2405{
2406 if (!InitVisual()) {
2407 Warning("SetImage", "Visual not initiated");
2408 return;
2409 }
2410
2411 DestroyImage();
2413
2414 Int_t xy;
2415 UInt_t w, h;
2416 gVirtualX->GetWindowSize(pxm, xy, xy, w, h);
2417
2418 if (fName.IsNull()) fName.Form("img_%dx%d",w, h);
2419
2420 static int x11 = -1;
2421 if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11");
2422
2423 if (x11) { //use built-in optimized version
2424 fImage = picture2asimage(fgVisual, pxm, mask, 0, 0, w, h, kAllPlanes, 1, 0);
2425 } else {
2426 unsigned char *bits = gVirtualX->GetColorBits(pxm, 0, 0, w, h);
2427 if (!bits) { // error
2428 return;
2429 }
2430
2431 // no mask
2432 if (!mask) {
2433 fImage = bitmap2asimage(bits, w, h, 0, nullptr);
2434 delete [] bits;
2435 return;
2436 }
2437 unsigned char *mask_bits = gVirtualX->GetColorBits(mask, 0, 0, w, h);
2438 fImage = bitmap2asimage(bits, w, h, 0, mask_bits);
2439 delete [] mask_bits;
2440 delete [] bits;
2441 }
2442}
2443
2444////////////////////////////////////////////////////////////////////////////////
2445/// Return 2D array of machine dependent pixel values.
2446
2448{
2449 if (!fImage) {
2450 Warning("GetPixels", "Wrong Image");
2451 return nullptr;
2452 }
2453
2456
2457 width = !width ? img->width : width;
2458 height = !height ? img->height : height;
2459
2460 if (x < 0) {
2461 width -= x;
2462 x = 0 ;
2463 }
2464 if (y < 0) {
2465 height -= y;
2466 y = 0;
2467 }
2468
2469 if ((x >= (int)img->width) || (y >= (int)img->height)) {
2470 return nullptr;
2471 }
2472
2473 if ((int)(x + width) > (int)img->width) {
2474 width = img->width - x;
2475 }
2476
2477 if ((int)(y + height) > (int)img->height) {
2478 height = img->height - y;
2479 }
2480
2481 if ((imdec = start_image_decoding(nullptr, fImage, SCL_DO_ALL, 0, y,
2482 img->width, height, nullptr)) == nullptr) {
2483 Warning("GetPixels", "Failed to create image decoder");
2484 return nullptr;
2485 }
2486
2487 TArrayL *ret = new TArrayL(width * height);
2488 Int_t r = 0, g = 0, b = 0;
2489 Long_t p = 0;
2490
2491 for (UInt_t k = 0; k < height; k++) {
2492 imdec->decode_image_scanline(imdec);
2493
2494 for (UInt_t i = 0; i < width; ++i) {
2495 if ((r == (Int_t)imdec->buffer.red[i]) &&
2496 (g == (Int_t)imdec->buffer.green[i]) &&
2497 (b == (Int_t)imdec->buffer.blue[i])) {
2498 } else {
2499 r = (Int_t)imdec->buffer.red[i];
2500 g = (Int_t)imdec->buffer.green[i];
2501 b = (Int_t)imdec->buffer.blue[i];
2502 p = (Long_t)TColor::RGB2Pixel(r, g, b);
2503 }
2504 ret->AddAt(p, k*width + i);
2505 }
2506 }
2507
2509 return ret;
2510}
2511
2512////////////////////////////////////////////////////////////////////////////////
2513/// Return a pointer to internal array[width x height] of double values [0,1].
2514/// This array is directly accessible. That allows to manipulate/change the
2515/// image.
2516
2518{
2519 if (!fImage) {
2520 Warning("GetVecArray", "Bad Image");
2521 return nullptr;
2522 }
2523 if (fImage->alt.vector) {
2524 return fImage->alt.vector;
2525 }
2526 // vectorize
2527 return nullptr;
2528}
2529
2530////////////////////////////////////////////////////////////////////////////////
2531/// In case of vectorized image return an associated array of doubles
2532/// otherwise this method creates and returns a 2D array of doubles corresponding to palette.
2533/// If palette is ZERO a color converted to double value [0, 1] according to formula
2534/// ~~~ {.cpp}
2535/// Double_t((r << 16) + (g << 8) + b)/0xFFFFFF
2536/// ~~~
2537/// The returned array must be deleted after usage.
2538
2540{
2541 if (!fImage) {
2542 Warning("GetArray", "Bad Image");
2543 return nullptr;
2544 }
2545
2546 TArrayD *ret;
2547
2548 if (fImage->alt.vector) {
2549 ret = new TArrayD(fImage->width*fImage->height, fImage->alt.vector);
2550 return ret;
2551 }
2552
2554
2555 w = w ? w : fImage->width;
2556 h = h ? h : fImage->height;
2557
2558 if ((fImage->width != w) || (fImage->height != h)) {
2559 Scale(w, h);
2560 }
2561
2563
2564 if ((imdec = start_image_decoding(nullptr, img, SCL_DO_ALL, 0, 0,
2565 img->width, 0, nullptr)) == nullptr) {
2566 Warning("GetArray", "Failed to create image decoder");
2567 return nullptr;
2568 }
2569
2570 ret = new TArrayD(w * h);
2571 CARD32 r = 0, g = 0, b = 0;
2572 Int_t p = 0;
2573 Double_t v = 0;
2574
2575 for (UInt_t k = 0; k < h; k++) {
2576 imdec->decode_image_scanline(imdec);
2577
2578 for (UInt_t i = 0; i < w; ++i) {
2579 if ((r == imdec->buffer.red[i]) &&
2580 (g == imdec->buffer.green[i]) &&
2581 (b == imdec->buffer.blue[i])) {
2582 } else {
2583 r = imdec->buffer.red[i];
2584 g = imdec->buffer.green[i];
2585 b = imdec->buffer.blue[i];
2586 if (palette) p = palette->FindColor(r, g, b);
2587 }
2588 v = palette ? palette->fPoints[p] : Double_t((r << 16) + (g << 8) + b)/0xFFFFFF;
2589 ret->AddAt(v, (h-k-1)*w + i);
2590 }
2591 }
2592
2594 return ret;
2595}
2596
2597////////////////////////////////////////////////////////////////////////////////
2598/// Draw text of size (in pixels for TrueType fonts)
2599/// at position (x, y) with color specified by hex string.
2600///
2601/// - font_name: TrueType font's filename or X font spec or alias.
2602/// 3D style of text is one of the following:
2603/// * 0 plain 2D text,
2604/// * 1 embossed,
2605/// * 2 sunken,
2606/// * 3 shade above,
2607/// * 4 shade below,
2608/// * 5 embossed thick,
2609/// * 6 sunken thick.
2610/// * 7 outline above,
2611/// * 8 ouline below,
2612/// * 9 full ouline.
2613/// - fore_file specifies foreground texture of text.
2614
2616 const char *color, const char *font_name,
2617 EText3DType type, const char *fore_file, Float_t angle)
2618{
2619 UInt_t width = 0, height = 0;
2621 ASImage *fore_im = nullptr;
2622 ASImage *text_im = nullptr;
2624
2625 if (!InitImage("DrawText")) {
2626 return;
2627 }
2628
2629 TString fn = font_name;
2630 fn.Strip();
2631
2632 // This is for backward compatibility...
2633 if (fn.Last('/') == 0)
2634 fn = fn(1, fn.Length() - 1);
2635
2636 const char *ttpath = gEnv->GetValue("Root.TTFontPath",
2638
2639 // if file will be found, fn will contain full name - otherwise empty
2641
2642 if (fn.EndsWith(".pfa") || fn.EndsWith(".PFA") || fn.EndsWith(".pfb") || fn.EndsWith(".PFB") || fn.EndsWith(".ttf") || fn.EndsWith(".TTF") || fn.EndsWith(".otf") || fn.EndsWith(".OTF"))
2643 ttfont = kTRUE;
2644
2645 if (color) {
2647 }
2648
2649 if (fImage && fImage->alt.argb32 && ttfont) {
2650 DrawTextTTF(x, y, text, size, text_color, fn.Data(), angle);
2651 return;
2652 }
2653
2654 if (!gFontManager) {
2655 gFontManager = create_font_manager(fgVisual->dpy, nullptr, nullptr);
2656 }
2657
2658 if (!gFontManager) {
2659 Warning("DrawText", "cannot create Font Manager");
2660 return;
2661 }
2662
2663 ASFont *font = fn.IsNull() ? nullptr : get_asfont(gFontManager, fn.Data(), 0, size, ASF_GuessWho);
2664
2665 if (!font) {
2666 font = get_asfont(gFontManager, "fixed", 0, size, ASF_GuessWho);
2667 if (!font) {
2668 Warning("DrawText", "cannot find a font %s", font_name);
2669 return;
2670 }
2671 }
2672
2674
2675 if (!fImage) {
2677 fill_asimage(fgVisual, fImage, 0, 0, width, height, 0xFFFFFFFF);
2678 }
2679
2680 text_im = draw_text(text, font, (ASText3DType)type, 0);
2681
2682 ASImage *rimg = fImage;
2683
2684 if (fore_file) {
2685 ASImage *tmp = file2ASImage(fore_file, 0xFFFFFFFF, SCREEN_GAMMA, 0, 0);
2686 if (tmp) {
2687 if ((tmp->width != width) || (tmp->height != height)) {
2690 }
2692 } else {
2693 fore_im = tmp;
2694 }
2695 }
2696
2697 if (fore_im) {
2700 } else {
2701 fore_im = text_im ;
2702 }
2703
2704 release_font(font);
2705
2706 if (fore_im) {
2708 ASImageLayer layers[2];
2709
2710 init_image_layers(&(layers[0]), 2);
2711 fore_im->back_color = text_color;
2712 layers[0].im = rimg;
2713 layers[0].dst_x = 0;
2714 layers[0].dst_y = 0;
2715 layers[0].clip_width = rimg->width;
2716 layers[0].clip_height = rimg->height;
2717 layers[0].bevel = nullptr;
2718 layers[1].im = fore_im;
2719 layers[1].dst_x = x;
2720 layers[1].dst_y = y;
2721 layers[1].clip_width = fore_im->width;
2722 layers[1].clip_height = fore_im->height;
2723
2724 rendered_im = merge_layers(fgVisual, &(layers[0]), 2, rimg->width, rimg->height,
2726
2728 DestroyImage();
2730 UnZoom();
2731 }
2732}
2733
2734////////////////////////////////////////////////////////////////////////////////
2735/// Merge two images.
2736///
2737/// op is string which specifies overlay operation. Supported operations are:
2738///
2739/// - add - color addition with saturation
2740/// - alphablend - alpha-blending
2741/// - allanon - color values averaging
2742/// - colorize - hue and saturate bottom image same as top image
2743/// - darken - use lowest color value from both images
2744/// - diff - use absolute value of the color difference between two images
2745/// - dissipate - randomly alpha-blend images
2746/// - hue - hue bottom image same as top image
2747/// - lighten - use highest color value from both images
2748/// - overlay - some weird image overlaying(see GIMP)
2749/// - saturate - saturate bottom image same as top image
2750/// - screen - another weird image overlaying(see GIMP)
2751/// - sub - color substraction with saturation
2752/// - tint - tinting image with image
2753/// - value - value bottom image same as top image
2754
2755void TASImage::Merge(const TImage *im, const char *op, Int_t x, Int_t y)
2756{
2757 if (!im) return;
2758
2759 if (!InitVisual()) {
2760 Warning("Merge", "Visual not initiated");
2761 return;
2762 }
2763
2765 ASImageLayer layers[2];
2766
2767 init_image_layers(&(layers[0]), 2);
2768 layers[0].im = fImage;
2769 layers[0].dst_x = 0;
2770 layers[0].dst_y = 0;
2771 layers[0].clip_width = fImage->width;
2772 layers[0].clip_height = fImage->height;
2773 layers[0].bevel = nullptr;
2774 layers[1].im = ((TASImage*)im)->fImage;
2775 layers[1].dst_x = x;
2776 layers[1].dst_y = y;
2777 layers[1].clip_width = im->GetWidth();
2778 layers[1].clip_height = im->GetHeight();
2779 layers[1].merge_scanlines = blend_scanlines_name2func(op ? op : "add");
2780
2781 rendered_im = merge_layers(fgVisual, &(layers[0]), 2, fImage->width, fImage->height,
2783
2784 DestroyImage();
2786 UnZoom();
2787}
2788
2789////////////////////////////////////////////////////////////////////////////////
2790/// Perform Gaussian blur of the image (useful for drop shadows).
2791/// - hr - horizontal radius of the blur
2792/// - vr - vertical radius of the blur
2793
2795{
2796 if (!InitVisual()) {
2797 Warning("Blur", "Visual not initiated");
2798 return;
2799 }
2800
2801 if (!fImage) {
2802 fImage = create_asimage(100, 100, 0);
2803
2804 if (!fImage) {
2805 Warning("Blur", "Failed to create image");
2806 return;
2807 }
2808
2809 fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, ARGB32_White);
2810 }
2811
2813 vr > 0 ? vr : 3, SCL_DO_ALL,
2815 DestroyImage();
2817 UnZoom();
2818}
2819
2820////////////////////////////////////////////////////////////////////////////////
2821/// Clone image.
2822
2824{
2825 if (!InitVisual() || !fImage) {
2826 Warning("Clone", "Image not initiated");
2827 return nullptr;
2828 }
2829
2830 TASImage *im = static_cast<TASImage *>(TImage::Create());
2831
2832 if (!im) {
2833 Warning("Clone", "Failed to create image");
2834 return nullptr;
2835 }
2836
2837 im->SetName(newname);
2838
2839 im->fImage = clone_asimage(fImage, SCL_DO_ALL);
2840 im->fMaxValue = fMaxValue;
2841 im->fMinValue = fMinValue;
2842 im->fZoomOffX = fZoomOffX;
2843 im->fZoomOffY = fZoomOffY;
2844 im->fZoomWidth = fZoomWidth;
2845 im->fZoomHeight = fZoomHeight;
2846 im->fZoomUpdate = fZoomUpdate;
2847 im->fScaledImage = fScaledImage ? static_cast<TASImage *>(fScaledImage->Clone()) : nullptr;
2848
2849 if (fImage->alt.argb32) {
2850 UInt_t sz = fImage->width * fImage->height;
2851 im->fImage->alt.argb32 = (ARGB32*)safemalloc(sz*sizeof(ARGB32));
2852 memcpy(im->fImage->alt.argb32, fImage->alt.argb32, sz * sizeof(ARGB32));
2853 }
2854
2855 return im;
2856}
2857
2858////////////////////////////////////////////////////////////////////////////////
2859/// Reduce color-depth of an image and fills vector of "scientific data"
2860/// [0...1]
2861///
2862/// Colors are reduced by allocating color cells to most used colors first,
2863/// and then approximating other colors with those allocated.
2864///
2865/// \param[in] max_colors - maximum size of the colormap.
2866/// \param[in] dither - number of bits to strip off the color data ( 0...7 )
2867/// \param[in] opaque_threshold - alpha channel threshold at which pixel should be treated as opaque
2868
2870{
2871 if (!InitVisual()) {
2872 Warning("Vectorize", "Visual not initiated");
2873 return nullptr;
2874 }
2875
2876 if (!fImage) {
2877 fImage = create_asimage(100, 100, 0);
2878
2879 if (!fImage) {
2880 Warning("Vectorize", "Failed to create image");
2881 return nullptr;
2882 }
2883
2884 fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, ARGB32_White);
2885 }
2886
2888 int *res;
2889 UInt_t r=0, g=0, b=0;
2890
2891 dither = dither > 7 ? 7 : dither;
2892
2894
2895 Double_t *vec = new Double_t[fImage->height*fImage->width];
2896 UInt_t v;
2897 Double_t tmp;
2898 fMinValue = 2;
2899 fMaxValue = -1;
2900
2901 for (UInt_t y = 0; y < fImage->height; y++) {
2902 for (UInt_t x = 0; x < fImage->width; x++) {
2903 int i = y*fImage->width + x;
2904 if (res) {
2905 g = INDEX_SHIFT_GREEN(cmap.entries[res[i]].green);
2906 b = INDEX_SHIFT_BLUE(cmap.entries[res[i]].blue);
2907 r = INDEX_SHIFT_RED(cmap.entries[res[i]].red);
2908 }
2910 v = (v>>12)&0x0FFF;
2911 tmp = Double_t(v)/0x0FFF;
2912 vec[(fImage->height - y - 1)*fImage->width + x] = tmp;
2913 if (fMinValue > tmp) fMinValue = tmp;
2914 if (fMaxValue < tmp) fMaxValue = tmp;
2915 }
2916 }
2917 TImagePalette *pal = new TImagePalette(cmap.count);
2918
2919 for (UInt_t j = 0; j < cmap.count; j++) {
2920 g = INDEX_SHIFT_GREEN(cmap.entries[j].green);
2921 b = INDEX_SHIFT_BLUE(cmap.entries[j].blue);
2922 r = INDEX_SHIFT_RED(cmap.entries[j].red);
2924
2925 v = (v>>12) & 0x0FFF;
2926 pal->fPoints[j] = Double_t(v)/0x0FFF;
2927
2928 pal->fColorRed[j] = cmap.entries[j].red << 8;
2929 pal->fColorGreen[j] = cmap.entries[j].green << 8;
2930 pal->fColorBlue[j] = cmap.entries[j].blue << 8;
2931 pal->fColorAlpha[j] = 0xFF00;
2932 }
2933
2935
2936 fPalette = *pal;
2937 fImage->alt.vector = vec;
2938 UnZoom();
2939 // ROOT-7647: res is allocated with `safemalloc` by colormap_asimage
2940 if (res) safefree(res);
2941 return (Double_t*)fImage->alt.vector;
2942}
2943
2944////////////////////////////////////////////////////////////////////////////////
2945/// This function will tile original image to specified size with offsets
2946/// requested, and then it will go though it and adjust hue, saturation and
2947/// value of those pixels that have specific hue, set by affected_hue/
2948/// affected_radius parameters. When affected_radius is greater then 180
2949/// entire image will be adjusted. Note that since grayscale colors have
2950/// no hue - the will not get adjusted. Only saturation and value will be
2951/// adjusted in gray pixels.
2952///
2953/// Hue is measured as an angle on a 360 degree circle, The following is
2954/// relationship of hue values to regular color names :
2955/// - red - 0
2956/// - yellow - 60
2957/// - green - 120
2958/// - cyan - 180
2959/// - blue - 240
2960/// - magenta - 300
2961/// - red - 360
2962///
2963/// All the hue values in parameters will be adjusted to fall within 0-360 range.
2964///
2965/// \param[in] hue hue in degrees in range 0-360. This allows to limit
2966/// impact of color adjustment to affect only limited range of hues.
2967///
2968/// \param[in] radius value in degrees to be used in order to
2969/// calculate the range of affected hues. Range is determined by
2970/// substracting and adding this value from/to affected_hue.
2971///
2972/// \param[in] H value by which to change hues in affected range.
2973/// \param[in] S value by which to change saturation of the pixels in affected hue range.
2974/// \param[in] V value by which to change Value(brightness) of pixels in affected hue range.
2975///
2976/// \param[in] x,y position on infinite surface tiled with original image, of the
2977/// left-top corner of the area to be used for new image.
2978///
2979/// \param[in] width, height size of the area of the original image to be used for new image.
2980/// Default is current width, height of the image.
2981
2984{
2985 if (!InitVisual()) {
2986 Warning("HSV", "Visual not initiated");
2987 return;
2988 }
2989
2990 if (!fImage) {
2991 fImage = create_asimage(width ? width : 20, height ? height : 20, 0);
2992
2993 if (!fImage) {
2994 Warning("HSV", "Failed to create image");
2995 return;
2996 }
2997
2998 x = 0;
2999 y = 0;
3000 fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, ARGB32_White);
3001 }
3002
3003 width = !width ? fImage->width : width;
3004 height = !height ? fImage->height : height;
3005
3006 ASImage *rendered_im = nullptr;
3007
3008 if (H || S || V) {
3010 hue, radius, H, S, V, ASA_ASImage, 100,
3012 }
3013 if (!rendered_im) {
3014 Warning("HSV", "Failed to create rendered image");
3015 return;
3016 }
3017
3018 DestroyImage();
3020 UnZoom();
3021}
3022
3023////////////////////////////////////////////////////////////////////////////////
3024/// Render multipoint gradient inside rectangle of size (width, height)
3025/// at position (x,y) within the existing image.
3026///
3027/// \param[in] angle Given in degrees. Default is 0. This is the
3028/// direction of the gradient. Currently the only supported
3029/// values are 0, 45, 90, 135, 180, 225, 270, 315. 0 means left
3030/// to right, 90 means top to bottom, etc.
3031///
3032/// \param[in] colors Whitespace-separated list of colors. At least two
3033/// colors are required. Each color in this list will be visited
3034/// in turn, at the intervals given by the offsets attribute.
3035///
3036/// \param[in] offsets Whitespace-separated list of floating point values
3037/// ranging from 0.0 to 1.0. The colors from the colors attribute
3038/// are given these offsets, and the final gradient is rendered
3039/// from the combination of the two. If both colors and offsets
3040/// are given but the number of colors and offsets do not match,
3041/// the minimum of the two will be used, and the other will be
3042/// truncated to match. If offsets are not given, a smooth
3043/// stepping from 0.0 to 1.0 will be used.
3044/// \param[in] x x position coordinate
3045/// \param[in] y y position coordinate
3046/// \param[in] width image width, if 0, it will be read from fImage
3047/// \param[in] height image height, if 0, it will be read from fImage
3048void TASImage::Gradient(UInt_t angle, const char *colors, const char *offsets,
3050{
3051 if (!InitVisual()) {
3052 Warning("Gradient", "Visual not initiated");
3053 return;
3054 }
3055
3056 ASImage *rendered_im = nullptr;
3057 ASGradient gradient;
3058
3059 int reverse = 0, npoints1 = 0, npoints2 = 0;
3060 char *p;
3061 char *pb;
3062 char ch;
3063 TString str = colors;
3064 TString col;
3065
3066 if ((angle > 2 * 180 * 15 / 16) || (angle < 2 * 180 * 1 / 16)) {
3067 gradient.type = GRADIENT_Left2Right;
3068 } else if (angle < 2 * 180 * 3 / 16) {
3069 gradient.type = GRADIENT_TopLeft2BottomRight;
3070 } else if (angle < 2 * 180 * 5 / 16) {
3071 gradient.type = GRADIENT_Top2Bottom;
3072 } else if (angle < 2 * 180 * 7 / 16) {
3073 gradient.type = GRADIENT_BottomLeft2TopRight; reverse = 1;
3074 } else if (angle < 2 * 180 * 9 / 16) {
3075 gradient.type = GRADIENT_Left2Right; reverse = 1;
3076 } else if (angle < 2 * 180 * 11 / 16) {
3077 gradient.type = GRADIENT_TopLeft2BottomRight; reverse = 1;
3078 } else if (angle < 2 * 180 * 13 / 16) {
3079 gradient.type = GRADIENT_Top2Bottom; reverse = 1;
3080 } else {
3081 gradient.type = GRADIENT_BottomLeft2TopRight;
3082 }
3083
3084 for (p = (char*)colors; isspace((int)*p); p++) { }
3085
3086 for (npoints1 = 0; *p; npoints1++) {
3087 if (*p) {
3088 for ( ; *p && !isspace((int)*p); p++) { }
3089 }
3090 for ( ; isspace((int)*p); p++) { }
3091 }
3092 if (offsets) {
3093 for (p = (char*)offsets; isspace((int)*p); p++) { }
3094
3095 for (npoints2 = 0; *p; npoints2++) {
3096 if (*p) {
3097 for ( ; *p && !isspace((int)*p); p++) { }
3098 }
3099 for ( ; isspace((int)*p); p++) { }
3100 }
3101 }
3102 if (npoints1 > 1) {
3103 int i;
3104 if (offsets && (npoints1 > npoints2)) npoints1 = npoints2;
3105
3106 if (!width) {
3107 width = fImage ? fImage->width : 20;
3108 }
3109 if (!height) {
3110 height = fImage ? fImage->height : 20;
3111 }
3112
3113 gradient.color = new ARGB32[npoints1];
3114 gradient.offset = new double[npoints1];
3115
3116 for (p = (char*)colors; isspace((int)*p); p++) { }
3117
3118 for (npoints1 = 0; *p; ) {
3119 pb = p;
3120
3121 if (*p) {
3122 for ( ; *p && !isspace((int)*p); p++) { }
3123 }
3124 for ( ; isspace((int)*p); p++) { }
3125
3126 col = str(pb - colors, p - pb);
3127
3128 if (parse_argb_color(col.Data(), gradient.color + npoints1) != col) {
3129 npoints1++;
3130 } else {
3131 Warning("Gradient", "Failed to parse color [%s] - defaulting to black", pb);
3132 }
3133 }
3134
3135 if (offsets) {
3136 for (p = (char*)offsets; isspace((int)*p); p++) { }
3137
3138 for (npoints2 = 0; *p; ) {
3139 pb = p;
3140
3141 if (*p) {
3142 for ( ; *p && !isspace((int)*p); p++) { }
3143 }
3144 ch = *p; *p = '\0';
3145 gradient.offset[npoints2] = strtod(pb, &pb);
3146
3147 if (pb == p) npoints2++;
3148 *p = ch;
3149 for ( ; isspace((int)*p); p++) { }
3150 }
3151 } else {
3152 for (npoints2 = 0; npoints2 < npoints1; npoints2++) {
3153 gradient.offset[npoints2] = (double)npoints2 / (npoints1 - 1);
3154 }
3155 }
3156 gradient.npoints = npoints1;
3157
3158 if (npoints2 && (gradient.npoints > npoints2)) {
3159 gradient.npoints = npoints2;
3160 }
3161 if (reverse) {
3162 for (i = 0; i < gradient.npoints/2; i++) {
3163 int i2 = gradient.npoints - 1 - i;
3164 ARGB32 c = gradient.color[i];
3165 double o = gradient.offset[i];
3166 gradient.color[i] = gradient.color[i2];
3167 gradient.color[i2] = c;
3168 gradient.offset[i] = gradient.offset[i2];
3169 gradient.offset[i2] = o;
3170 }
3171 for (i = 0; i < gradient.npoints; i++) {
3172 gradient.offset[i] = 1.0 - gradient.offset[i];
3173 }
3174 }
3177
3178 delete [] gradient.color;
3179 delete [] gradient.offset;
3180 }
3181
3182 if (!rendered_im) { // error
3183 Warning("Gradient", "Failed to create gradient image");
3184 return;
3185 }
3186
3187 if (!fImage) {
3189 return;
3190 }
3191
3192 ASImageLayer layers[2];
3193
3194 init_image_layers(&(layers[0]), 2);
3195 layers[0].im = fImage;
3196 layers[0].dst_x = 0;
3197 layers[0].dst_y = 0;
3198 layers[0].clip_width = fImage->width;
3199 layers[0].clip_height = fImage->height;
3200 layers[0].bevel = nullptr;
3201 layers[1].im = rendered_im;
3202 layers[1].dst_x = x;
3203 layers[1].dst_y = y;
3204 layers[1].clip_width = width;
3205 layers[1].clip_height = height;
3206 layers[1].merge_scanlines = alphablend_scanlines;
3207
3208 ASImage *merge_im = merge_layers(fgVisual, &(layers[0]), 2, fImage->width, fImage->height,
3210 if (!merge_im) {
3211 Warning("Gradient", "Failed to create merged image");
3212 return;
3213 }
3214
3216 DestroyImage();
3217 fImage = merge_im;
3218 UnZoom();
3219}
3220
3221////////////////////////////////////////////////////////////////////////////////
3222/// Make component hilite.
3223/// (used internally)
3224
3226{
3227 if (cmp < 51) {
3228 cmp = 51;
3229 }
3230 cmp = (cmp * 12) / 10;
3231
3232 return (cmp > 255) ? 255 : cmp;
3233}
3234
3235////////////////////////////////////////////////////////////////////////////////
3236/// Calculate highlite color.
3237/// (used internally)
3238
3240{
3241 return ((MakeComponentHilite((background>>24) & 0x000000FF) << 24) & 0xFF000000) |
3242 ((MakeComponentHilite((background & 0x00FF0000) >> 16) << 16) & 0x00FF0000) |
3243 ((MakeComponentHilite((background & 0x0000FF00) >> 8) << 8) & 0x0000FF00) |
3244 ((MakeComponentHilite((background & 0x000000FF))) & 0x000000FF);
3245}
3246
3247////////////////////////////////////////////////////////////////////////////////
3248/// Calculate shadow color.
3249/// (used internally)
3250
3252{
3253 return (background >> 1) & 0x7F7F7F7F;
3254}
3255
3256////////////////////////////////////////////////////////////////////////////////
3257/// Get average.
3258/// (used internally)
3259
3261{
3262 CARD16 a, r, g, b;
3263
3265 a = (a<<3)/10;
3267 r = (r<<3)/10;
3269 g = (g<<3)/10;
3271 b = (b<<3)/10;
3272
3273 return MAKE_ARGB32(a, r, g, b);
3274}
3275
3276
3277////////////////////////////////////////////////////////////////////////////////
3278/// Bevel is used to create 3D effect while drawing buttons, or any other
3279/// image that needs to be framed. Bevel is drawn using 2 primary colors:
3280/// one for top and left sides - hi color, and another for bottom and
3281/// right sides - low color. Bevel can be drawn over existing image or
3282/// as newly created, as it is shown in code below:
3283/// ~~~ {.cpp}
3284/// TImage *img = TImage::Create();
3285/// img->Bevel(0, 0, 400, 300, "#dddddd", "#000000", 3);
3286/// ~~~
3287
3289 const char *hi_color, const char *lo_color, UShort_t thick,
3290 Bool_t reverse)
3291{
3292 if (!InitVisual()) {
3293 Warning("Bevel", "Visual not initiated");
3294 return;
3295 }
3296
3298 bevel.type = 0;
3299
3303
3304 if (reverse) {
3305 bevel.lo_color = hi;
3306 bevel.lolo_color = GetHilite(hi);
3307 bevel.hi_color = lo;
3308 bevel.hihi_color = GetShadow(lo);
3309 } else {
3310 bevel.hi_color = hi;
3311 bevel.hihi_color = GetHilite(hi);
3312 bevel.lo_color = lo;
3313 bevel.lolo_color = GetShadow(lo);
3314 }
3315 bevel.hilo_color = GetAverage(hi, lo);
3316
3317 int extra_hilite = 2;
3318 bevel.left_outline = bevel.top_outline = bevel.right_outline = bevel.bottom_outline = thick;
3319 bevel.left_inline = bevel.top_inline = bevel.right_inline = bevel.bottom_inline = extra_hilite + 1;
3320
3321 if (bevel.top_outline > 1) {
3322 bevel.top_inline += bevel.top_outline - 1;
3323 }
3324
3325 if (bevel.left_outline > 1) {
3326 bevel.left_inline += bevel.left_outline - 1;
3327 }
3328
3329 if (bevel.right_outline > 1) {
3330 bevel.right_inline += bevel.right_outline - 1;
3331 }
3332
3333 if (bevel.bottom_outline > 1) {
3334 bevel.bottom_inline += bevel.bottom_outline - 1;
3335 }
3336
3338 ARGB32 fill = ((hi>>24) != 0xff) || ((lo>>24) != 0xff) ? bevel.hilo_color : (bevel.hilo_color | 0xff000000);
3339
3340 if (!fImage) {
3341 fImage = create_asimage(width ? width : 20, height ? height : 20, 0);
3342
3343 if (!fImage) {
3344 Warning("Bevel", "Failed to create image");
3345 return;
3346 }
3347
3348 x = 0;
3349 y = 0;
3350 fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, fill);
3351 }
3352
3353 width = !width ? fImage->width : width;
3354 height = !height ? fImage->height : height;
3355
3356 ASImageLayer layers[2];
3357 init_image_layers(&(layers[0]), 2);
3358
3359 layers[0].im = fImage;
3360 layers[0].dst_x = 0;
3361 layers[0].dst_y = 0;
3362 layers[0].clip_width = fImage->width;
3363 layers[0].clip_height = fImage->height;
3364 layers[0].bevel = nullptr;
3365
3366 UInt_t w = width - (bevel.left_outline + bevel.right_outline);
3367 UInt_t h = height - (bevel.top_outline + bevel.bottom_outline);
3369
3370 if (!bevel_im) {
3371 Warning("Bevel", "Failed to create bevel image");
3372 return;
3373 }
3374
3375 layers[1].im = bevel_im;
3376 fill_asimage(fgVisual, bevel_im, 0, 0, w, h, fill);
3377
3378 layers[1].dst_x = x;
3379 layers[1].dst_y = y;
3380 layers[1].clip_width = width;
3381 layers[1].clip_height = height;
3382 layers[1].bevel = &bevel;
3383 layers[1].merge_scanlines = alphablend_scanlines;
3384
3385 merge_im = merge_layers(fgVisual, &(layers[0]), 2, fImage->width, fImage->height,
3388
3389 if (!merge_im) {
3390 Warning("Bevel", "Failed to image");
3391 return;
3392 }
3393
3394 DestroyImage();
3395 fImage = merge_im;
3396 UnZoom();
3397}
3398
3399
3400////////////////////////////////////////////////////////////////////////////////
3401/// Enlarge image, padding it with specified color on each side in
3402/// accordance with requested geometry.
3403
3404void TASImage::Pad(const char *col, UInt_t l, UInt_t r, UInt_t t, UInt_t b)
3405{
3406 Int_t x, y;
3407 UInt_t w, h;
3408
3409 if (!InitVisual()) {
3410 Warning("Pad", "Visual not initiated");
3411 return;
3412 }
3413
3414 if (!fImage) {
3415 fImage = create_asimage(100, 100, 0);
3416
3417 if (!fImage) {
3418 Warning("Pad", "Failed to create image");
3419 return;
3420 }
3421
3422 fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, ARGB32_White);
3423 }
3424
3425 ARGB32 color = ARGB32_White;
3426 parse_argb_color(col, &color);
3427
3428 x = l;
3429 y = t;
3430 w = l + fImage->width + r;
3431 h = t + fImage->height + b;
3432
3433 ASImage *img = pad_asimage(fgVisual, fImage, x, y, w, h, color,
3435
3436 if (!img) {
3437 Warning("Pad", "Failed to create output image");
3438 return;
3439 }
3440
3441 DestroyImage();
3442 fImage = img;
3443 UnZoom();
3445}
3446
3447
3448////////////////////////////////////////////////////////////////////////////////
3449/// Crop an image.
3450
3452{
3453 if (!InitVisual()) {
3454 Warning("Crop", "Visual not initiated");
3455 return;
3456 }
3457
3458 if (!fImage) {
3459 Warning("Crop", "No image");
3460 return;
3461 }
3462
3463 x = x < 0 ? 0 : x;
3464 y = y < 0 ? 0 : y;
3465
3466 width = x + width > fImage->width ? fImage->width - x : width;
3467 height = y + height > fImage->height ? fImage->height - y : height;
3468
3469 if ((width == fImage->width) && (height == fImage->height)) {
3470 Warning("Crop", "input size larger than image");
3471 return;
3472 }
3474 x, y, width, height, nullptr);
3475
3476 if (!imdec) {
3477 Warning("Crop", "Failed to start image decoding");
3478 return;
3479 }
3480
3482
3483 if (!img) {
3484 delete [] imdec;
3485 Warning("Crop", "Failed to create image");
3486 return;
3487 }
3488
3491
3492 if (!imout) {
3493 Warning("Crop", "Failed to start image output");
3495 if (imdec) delete [] imdec;
3496 return;
3497 }
3498
3499#ifdef HAVE_MMX
3500 mmx_init();
3501#endif
3502
3503 for (UInt_t i = 0; i < height; i++) {
3504 imdec->decode_image_scanline(imdec);
3505 imout->output_image_scanline(imout, &(imdec->buffer), 1);
3506 }
3507
3510
3511#ifdef HAVE_MMX
3512 mmx_off();
3513#endif
3514
3515 DestroyImage();
3516 fImage = img;
3517 UnZoom();
3519}
3520
3521////////////////////////////////////////////////////////////////////////////////
3522/// Append image.
3523///
3524/// option:
3525/// - "+" - appends to the right side
3526/// - "/" - appends to the bottom
3527
3528void TASImage::Append(const TImage *im, const char *option, const char *color )
3529{
3530 if (!im) return;
3531
3532 if (!InitVisual()) {
3533 Warning("Append", "Visual not initiated");
3534 return;
3535 }
3536
3537 if (!fImage) {
3538 fImage = ((TASImage*)im)->fImage;
3539 return;
3540 }
3541
3542 TString opt = option;
3543 opt.Strip();
3544
3545 UInt_t width = fImage->width;
3546 UInt_t height = fImage->height;
3547
3548 if (opt == "+") {
3549 Pad(color, 0, im->GetWidth(), 0, 0);
3550 Merge(im, "alphablend", width, 0);
3551 } else if (opt == "/") {
3552 Pad(color, 0, 0, 0, im->GetHeight());
3553 Merge(im, "alphablend", 0, height);
3554 } else {
3555 return;
3556 }
3557
3558 UnZoom();
3559}
3560
3561////////////////////////////////////////////////////////////////////////////////
3562/// BeginPaint initializes internal array[width x height] of ARGB32 pixel
3563/// values.
3564///
3565/// That provides quick access to image during paint operations.
3566/// To RLE compress image one needs to call EndPaint method when painting
3567/// is over.
3568
3570{
3571 if (!InitVisual()) {
3572 Warning("BeginPaint", "Visual not initiated");
3573 return;
3574 }
3575
3576 if (!fImage) {
3577 return;
3578 }
3579
3580 fPaintMode = mode;
3581
3582 if (!fPaintMode || fImage->alt.argb32) {
3583 return;
3584 }
3585
3586 ASImage *img = tile_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height,
3588
3589 if (!img) {
3590 Warning("BeginPaint", "Failed to create image");
3591 return;
3592 }
3593
3594 DestroyImage();
3595 fImage = img;
3596}
3597
3598////////////////////////////////////////////////////////////////////////////////
3599/// EndPaint does internal RLE compression of image data.
3600
3602{
3603 if (!fImage) {
3604 Warning("EndPaint", "no image");
3605 return;
3606 }
3607
3608 if (!fImage->alt.argb32) return;
3609
3610 ASImage *img = tile_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height,
3612
3613 if (!img) {
3614 Warning("EndPaint", "Failed to create image");
3615 return;
3616 }
3617
3619 DestroyImage();
3620 fImage = img;
3621}
3622
3623////////////////////////////////////////////////////////////////////////////////
3624/// Return a pointer to internal array[width x height] of ARGB32 values
3625/// This array is directly accessible. That allows to manipulate/change the
3626/// image.
3627
3629{
3630 if (!fImage) {
3631 Warning("GetArgbArray", "no image");
3632 return nullptr;
3633 }
3634
3636 if (!img) return nullptr;
3637
3638 if (!img->alt.argb32) {
3639 if (fScaledImage) {
3642 } else {
3643 BeginPaint();
3644 img = fImage;
3645 }
3646 }
3647
3648 return (UInt_t *)img->alt.argb32;
3649}
3650
3651////////////////////////////////////////////////////////////////////////////////
3652/// Return a pointer to an array[width x height] of RGBA32 values.
3653/// This array is created from internal ARGB32 array,
3654/// must be deleted after usage.
3655
3657{
3658 if (!fImage) {
3659 Warning("GetRgbaArray", "no image");
3660 return nullptr;
3661 }
3662
3664 if (!img) return nullptr;
3665
3666 if (!img->alt.argb32) {
3667 if (fScaledImage) {
3670 } else {
3671 BeginPaint();
3672 img = fImage;
3673 }
3674 }
3675
3676 UInt_t i, j;
3677 Int_t y = 0;
3678 Int_t idx = 0;
3679 UInt_t a, rgb, rgba, argb;
3680
3681 UInt_t *ret = new UInt_t[img->width*img->height];
3682
3683 for (i = 0; i < img->height; i++) {
3684 for (j = 0; j < img->width; j++) {
3685 idx = Idx(y + j);
3686 argb = img->alt.argb32[idx];
3687 a = argb >> 24;
3688 rgb = argb & 0x00ffffff;
3689 rgba = (rgb << 8) + a;
3690 ret[idx] = rgba;
3691 }
3692 y += img->width;
3693 }
3694
3695 return ret;
3696}
3697
3698////////////////////////////////////////////////////////////////////////////////
3699/// Return a pointer to scan-line.
3700
3702{
3703 if (!fImage) {
3704 Warning("GetScanline", "no image");
3705 return nullptr;
3706 }
3707
3709 CARD32 *ret = new CARD32[img->width];
3710
3712 0, y, img->width, 1, nullptr);
3713
3714 if (!imdec) {
3715 delete [] ret;
3716 Warning("GetScanline", "Failed to start image decoding");
3717 return nullptr;
3718 }
3719
3720#ifdef HAVE_MMX
3721 mmx_init();
3722#endif
3723
3724 imdec->decode_image_scanline(imdec);
3725 memcpy(imdec->buffer.buffer, ret, img->width*sizeof(CARD32));
3727
3728#ifdef HAVE_MMX
3729 mmx_off();
3730#endif
3731
3732 return (UInt_t*)ret;
3733}
3734
3735
3736//______________________________________________________________________________
3737//
3738// Vector graphics
3739// a couple of macros which can be "assembler accelerated"
3740
3741#if defined(R__GNU) && defined(__i386__) && !defined(__sun)
3742#define _MEMSET_(dst, lng, val) __asm__("movl %0,%%eax \n"\
3743 "movl %1,%%edi \n" \
3744 "movl %2,%%ecx \n" \
3745 "cld \n" \
3746 "rep \n" \
3747 "stosl \n" \
3748 : /* no output registers */ \
3749 :"g" (val), "g" (dst), "g" (lng) \
3750 :"eax","edi","ecx" \
3751 )
3752
3753#else
3754 #define _MEMSET_(dst, lng, val) do {\
3755 for( UInt_t j=0; j < lng; j++) *((dst)+j) = val; } while (0)
3756
3757#endif
3758
3759#define FillSpansInternal(npt, ppt, widths, color) do {\
3760 UInt_t yy = ppt[0].fY*fImage->width;\
3761 for (UInt_t i = 0; i < npt; i++) {\
3762 _MEMSET_(&fImage->alt.argb32[Idx(yy + ppt[i].fX)], widths[i], color);\
3763 yy += ((i+1 < npt) && (ppt[i].fY != ppt[i+1].fY) ? fImage->width : 0);\
3764 }\
3765} while (0)
3766
3767////////////////////////////////////////////////////////////////////////////////
3768/// Fill rectangle of size (width, height) at position (x,y)
3769/// within the existing image with specified color.
3770
3772{
3773
3774 if (!InitImage("FillRectangleInternal")) {
3775 return;
3776 }
3777
3778 ARGB32 color = (ARGB32)col;
3779
3780 if (width == 0) width = 1;
3781 if (height == 0) height = 1;
3782
3783 if (x < 0) {
3784 width += x;
3785 x = 0;
3786 }
3787 if (y < 0) {
3788 height += y;
3789 y = 0;
3790 }
3791
3792 Bool_t has_alpha = (color & 0xff000000) != 0xff000000;
3793
3794 x = x > (int)fImage->width ? (Int_t)fImage->width : x;
3795 y = y > (int)fImage->height ? (Int_t)fImage->height : y;
3796
3797 width = x + width > fImage->width ? fImage->width - x : width;
3798 height = y + height > fImage->height ? fImage->height - y : height;
3799
3800 if (!fImage->alt.argb32) {
3801 fill_asimage(fgVisual, fImage, x, y, width, height, color);
3802 } else {
3803 int yyy = y*fImage->width;
3804 if (!has_alpha) { // use faster memset
3805 ARGB32 *p0 = fImage->alt.argb32 + yyy + x;
3806 ARGB32 *p = p0;
3807 for (UInt_t i = 0; i < height; i++) {
3808 _MEMSET_(p, width, color);
3809 p += fImage->width;
3810 }
3811 } else {
3812 for (UInt_t i = y; i < y + height; i++) {
3813 int j = x + width;
3814 while (j > x) {
3815 j--;
3816 _alphaBlend(&fImage->alt.argb32[Idx(yyy + j)], &color);
3817 }
3818 yyy += fImage->width;
3819 }
3820 }
3821 }
3822}
3823
3824////////////////////////////////////////////////////////////////////////////////
3825/// Fill rectangle of size (width, height) at position (x,y)
3826/// within the existing image with specified color.
3827///
3828/// To create new image with Fill method the following code can be used:
3829/// ~~~ {.cpp}
3830/// TImage *img = TImage::Create();
3831/// img->Fill("#FF00FF", 0, 0, 400, 300);
3832/// ~~~
3833
3835{
3836 if (!InitVisual()) {
3837 Warning("FillRectangle", "Visual not initiated");
3838 return;
3839 }
3840
3841 ARGB32 color = ARGB32_White;
3842
3843 if (col) {
3844 parse_argb_color(col, &color);
3845 }
3846
3847 if (!fImage) {
3848 fImage = create_asimage(width ? width : 20, height ? height : 20, 0);
3849 x = 0;
3850 y = 0;
3851 }
3852
3854 UnZoom();
3855}
3856
3857////////////////////////////////////////////////////////////////////////////////
3858/// Draw a vertical line.
3859
3861{
3862 if (!InitImage("DrawVLine")) {
3863 return;
3864 }
3865
3866 ARGB32 color = (ARGB32)col;
3867 UInt_t half = 0;
3868
3869 if (!thick) thick = 1;
3870
3871 if (thick > 1) {
3872 half = thick >> 1;
3873 if (x > half) {
3874 x = x - half;
3875 } else {
3876 x = 0;
3877 thick += (x - half);
3878 }
3879 }
3880
3881 y2 = y2 >= fImage->height ? fImage->height - 1 : y2;
3882 y1 = y1 >= fImage->height ? fImage->height - 1 : y1;
3883 x = x + thick >= fImage->width ? fImage->width - thick - 1 : x;
3884
3885 int yy = y1*fImage->width;
3886 for (UInt_t y = y1; y <= y2; y++) {
3887 for (UInt_t w = 0; w < thick; w++) {
3888 if (x + w < fImage->width) {
3889 _alphaBlend(&fImage->alt.argb32[Idx(yy + (x + w))], &color);
3890 }
3891 }
3892 yy += fImage->width;
3893 }
3894}
3895
3896////////////////////////////////////////////////////////////////////////////////
3897/// Draw an horizontal line.
3898
3900{
3901 if (!InitImage("DrawHLine")) {
3902 return;
3903 }
3904
3905 ARGB32 color = (ARGB32)col;
3906 UInt_t half = 0;
3907
3908 if (!thick) thick = 1;
3909
3910 if (thick > 1) {
3911 half = thick >> 1;
3912 if (y > half) {
3913 y = y - half;
3914 } else {
3915 y = 0;
3916 thick += (y - half);
3917 }
3918 }
3919
3920 y = y + thick >= fImage->height ? fImage->height - thick - 1 : y;
3921 x2 = x2 >= fImage->width ? fImage->width - 1 : x2;
3922 x1 = x1 >= fImage->width ? fImage->width - 1 : x1;
3923
3924 int yy = y*fImage->width;
3925 for (UInt_t w = 0; w < thick; w++) {
3926 for (UInt_t x = x1; x <= x2; x++) {
3927 if (y + w < fImage->height) {
3928 _alphaBlend(&fImage->alt.argb32[Idx(yy + x)], &color);
3929 }
3930 }
3931 yy += fImage->width;
3932 }
3933}
3934
3935////////////////////////////////////////////////////////////////////////////////
3936/// Draw a line.
3937
3939 const char *col, UInt_t thick)
3940{
3941 ARGB32 color = ARGB32_White;
3942 parse_argb_color(col, &color);
3943 DrawLineInternal(x1, y1, x2, y2, (UInt_t)color, thick);
3944}
3945
3946////////////////////////////////////////////////////////////////////////////////
3947/// Internal line drawing.
3948
3950 UInt_t col, UInt_t thick)
3951{
3952 int dx, dy, d;
3953 int i1, i2;
3954 int x, y, xend, yend;
3955 int xdir, ydir;
3956 int q;
3957 int idx;
3958 int yy;
3959
3960 if (!InitImage("DrawLineInternal")) {
3961 return;
3962 }
3963
3964 ARGB32 color = (ARGB32)col;
3965
3966 dx = TMath::Abs(Int_t(x2) - Int_t(x1));
3967 dy = TMath::Abs(Int_t(y2) - Int_t(y1));
3968
3969 if (!dx && !dy) return; // invisible line
3970
3971 if (!dx) {
3972 DrawVLine(x1, y2 > y1 ? y1 : y2,
3973 y2 > y1 ? y2 : y1, color, thick);
3974 return;
3975 }
3976
3977 if (!dy) {
3978 DrawHLine(y1, x2 > x1 ? x1 : x2,
3979 x2 > x1 ? x2 : x1, color, thick);
3980 return;
3981 }
3982
3983 if (thick > 1) {
3984 DrawWideLine(x1, y1, x2, y2, color, thick);
3985 return;
3986 }
3987
3988 if (dy <= dx) {
3989 UInt_t ddy = dy << 1;
3990 i1 = ddy;
3991 i2 = i1 - (dx << 1);
3992 d = i1 - dx;
3993
3994 if (x1 > x2) {
3995 x = x2;
3996 y = y2;
3997 ydir = -1;
3998 xend = x1;
3999 } else {
4000 x = x1;
4001 y = y1;
4002 ydir = 1;
4003 xend = x2;
4004 }
4005
4006 yy = y*fImage->width;
4007 _alphaBlend(&fImage->alt.argb32[Idx(yy + x)], &color);
4008 q = (y2 - y1) * ydir;
4009
4010 if (q > 0) {
4011 while (x < xend) {
4012
4013 idx = Idx(yy + x);
4014 _alphaBlend(&fImage->alt.argb32[idx], &color);
4015 x++;
4016
4017 if (d >= 0) {
4018 yy += fImage->width;
4019 d += i2;
4020 } else {
4021 d += i1;
4022 }
4023 }
4024 } else {
4025 while (x < xend) {
4026 idx = Idx(yy + x);
4027 _alphaBlend(&fImage->alt.argb32[idx], &color);
4028 x++;
4029
4030 if (d >= 0) {
4031 yy -= fImage->width;
4032 d += i2;
4033 } else {
4034 d += i1;
4035 }
4036 }
4037 }
4038 } else {
4039 UInt_t ddx = dx << 1;
4040 i1 = ddx;
4041 i2 = i1 - (dy << 1);
4042 d = i1 - dy;
4043
4044 if (y1 > y2) {
4045 y = y2;
4046 x = x2;
4047 yend = y1;
4048 xdir = -1;
4049 } else {
4050 y = y1;
4051 x = x1;
4052 yend = y2;
4053 xdir = 1;
4054 }
4055
4056 yy = y*fImage->width;
4057 _alphaBlend(&fImage->alt.argb32[Idx(yy + x)], &color);
4058 q = (x2 - x1) * xdir;
4059
4060 if (q > 0) {
4061 while (y < yend) {
4062 idx = Idx(yy + x);
4063 _alphaBlend(&fImage->alt.argb32[idx], &color);
4064 y++;
4065 yy += fImage->width;
4066
4067 if (d >= 0) {
4068 x++;
4069 d += i2;
4070 } else {
4071 d += i1;
4072 }
4073 }
4074 } else {
4075 while (y < yend) {
4076 idx = Idx(yy + x);
4077 _alphaBlend(&fImage->alt.argb32[idx], &color);
4078 y++;
4079 yy += fImage->width;
4080
4081 if (d >= 0) {
4082 x--;
4083 d += i2;
4084 } else {
4085 d += i1;
4086 }
4087 }
4088 }
4089 }
4090}
4091
4092////////////////////////////////////////////////////////////////////////////////
4093/// Draw a rectangle.
4094
4096 const char *col, UInt_t thick)
4097{
4098 if (!InitVisual()) {
4099 Warning("DrawRectangle", "Visual not initiated");
4100 return;
4101 }
4102
4103 if (!fImage) {
4104 w = w ? w : 20;
4105 h = h ? h : 20;
4106 fImage = create_asimage(w, h, 0);
4107 FillRectangle(col, 0, 0, w, h);
4108 return;
4109 }
4110
4111 if (!fImage->alt.argb32) {
4112 BeginPaint();
4113 }
4114
4115 if (!fImage->alt.argb32) {
4116 Warning("DrawRectangle", "Failed to get argb32 pixel array");
4117 return;
4118 }
4119
4120 ARGB32 color = ARGB32_White;
4121 parse_argb_color(col, &color);
4122
4123 DrawHLine(y, x, x + w, (UInt_t)color, thick);
4124 DrawVLine(x + w, y, y + h, (UInt_t)color, thick);
4125 DrawHLine(y + h, x, x + w, (UInt_t)color, thick);
4126 DrawVLine(x, y, y + h, (UInt_t)color, thick);
4127 UnZoom();
4128}
4129
4130////////////////////////////////////////////////////////////////////////////////
4131/// Draw a box.
4132
4133void TASImage::DrawBox(Int_t x1, Int_t y1, Int_t x2, Int_t y2, const char *col,
4135{
4136 Int_t x = TMath::Min(x1, x2);
4137 Int_t y = TMath::Min(y1, y2);
4138 Int_t w = TMath::Abs(x2 - x1);
4139 Int_t h = TMath::Abs(y2 - y1);
4140
4141 ARGB32 color = ARGB32_White;
4142
4143 if (!fImage) {
4144 w = w ? x+w : x+20;
4145 h = h ? y+h : y+20;
4146 fImage = create_asimage(w, h, 0);
4147 FillRectangle(col, 0, 0, w, h);
4148 return;
4149 }
4150
4151 if (x1 == x2) {
4152 parse_argb_color(col, &color);
4153 DrawVLine(x1, y1, y2, color, 1);
4154 return;
4155 }
4156
4157 if (y1 == y2) {
4158 parse_argb_color(col, &color);
4159 DrawHLine(y1, x1, x2, color, 1);
4160 return;
4161 }
4162
4163
4164 switch (mode) {
4165 case TVirtualX::kHollow:
4166 DrawRectangle(x, y, w, h, col, thick);
4167 break;
4168
4169 case TVirtualX::kFilled:
4170 FillRectangle(col, x, y, w, h);
4171 break;
4172
4173 default:
4174 FillRectangle(col, x, y, w, h);
4175 break;
4176 }
4177}
4178
4179////////////////////////////////////////////////////////////////////////////////
4180/// Draw a dashed horizontal line.
4181
4183 const char *pDash, UInt_t col, UInt_t thick)
4184{
4185 if (!InitImage("DrawDashHLine")) {
4186 return;
4187 }
4188
4189 UInt_t iDash = 0; // index of current dash
4190 int i = 0;
4191
4192 ARGB32 color = (ARGB32)col;
4193
4194 UInt_t half = 0;
4195
4196 if (thick > 1) {
4197 half = thick >> 1;
4198 if (y > half) {
4199 y = y - half;
4200 } else {
4201 y = 0;
4202 thick += (y - half);
4203 }
4204 }
4205 thick = thick <= 0 ? 1 : thick;
4206
4207 y = y + thick >= fImage->height ? fImage->height - thick - 1 : y;
4208 x2 = x2 >= fImage->width ? fImage->width - 1 : x2;
4209 x1 = x1 >= fImage->width ? fImage->width - 1 : x1;
4210
4211 // switch x1, x2
4212 UInt_t tmp = x1;
4213 x1 = x2 < x1 ? x2 : x1;
4214 x2 = x2 < tmp ? tmp : x2;
4215
4216 for (UInt_t x = x1; x <= x2; x++) {
4217 for (UInt_t w = 0; w < thick; w++) {
4218 if (y + w < fImage->height) {
4219 if ((iDash%2)==0) {
4220 _alphaBlend(&fImage->alt.argb32[Idx((y + w)*fImage->width + x)], &color);
4221 }
4222 }
4223 }
4224 i++;
4225
4226 if (i >= pDash[iDash]) {
4227 iDash++;
4228 i = 0;
4229 }
4230 if (iDash >= nDash) {
4231 iDash = 0;
4232 i = 0;
4233 }
4234 }
4235}
4236
4237////////////////////////////////////////////////////////////////////////////////
4238/// Draw a dashed vertical line.
4239
4241 const char *pDash, UInt_t col, UInt_t thick)
4242{
4243 if (!InitImage("DrawDashVLine")) {
4244 return;
4245 }
4246 UInt_t iDash = 0; // index of current dash
4247 int i = 0;
4248
4249 ARGB32 color = (ARGB32)col;
4250
4251 UInt_t half = 0;
4252
4253 if (thick > 1) {
4254 half = thick >> 1;
4255 if (x > half) {
4256 x = x - half;
4257 } else {
4258 x = 0;
4259 thick += (x - half);
4260 }
4261 }
4262 thick = thick <= 0 ? 1 : thick;
4263
4264 y2 = y2 >= fImage->height ? fImage->height - 1 : y2;
4265 y1 = y1 >= fImage->height ? fImage->height - 1 : y1;
4266
4267 // switch x1, x2
4268 UInt_t tmp = y1;
4269 y1 = y2 < y1 ? y2 : y1;
4270 y2 = y2 < tmp ? tmp : y2;
4271
4272 x = x + thick >= fImage->width ? fImage->width - thick - 1 : x;
4273
4274 int yy = y1*fImage->width;
4275 for (UInt_t y = y1; y <= y2; y++) {
4276 for (UInt_t w = 0; w < thick; w++) {
4277 if (x + w < fImage->width) {
4278 if ((iDash%2)==0) {
4279 _alphaBlend(&fImage->alt.argb32[Idx(yy + (x + w))], &color);
4280 }
4281 }
4282 }
4283 i++;
4284
4285 if (i >= pDash[iDash]) {
4286 iDash++;
4287 i = 0;
4288 }
4289 if (iDash >= nDash) {
4290 iDash = 0;
4291 i = 0;
4292 }
4293 yy += fImage->width;
4294 }
4295}
4296
4297////////////////////////////////////////////////////////////////////////////////
4298/// Draw a dashed line with one pixel width.
4299
4301 UInt_t nDash, const char *tDash, UInt_t color)
4302{
4303 if (!InitImage("DrawDashZLine")) {
4304 return;
4305 }
4306 int dx, dy, d;
4307 int i, i1, i2;
4308 int x, y, xend, yend;
4309 int xdir, ydir;
4310 int q;
4311 UInt_t iDash = 0; // index of current dash
4312 int yy;
4313 int idx;
4314
4315 dx = TMath::Abs(Int_t(x2) - Int_t(x1));
4316 dy = TMath::Abs(Int_t(y2) - Int_t(y1));
4317
4318 char *pDash = new char[nDash];
4319
4320 if (dy <= dx) {
4321 double ac = TMath::Cos(TMath::ATan2(dy, dx));
4322
4323 for (i = 0; i < (int)nDash; i++) {
4324 pDash[i] = TMath::Nint(tDash[i] * ac);
4325 }
4326
4327 UInt_t ddy = dy << 1;
4328 i1 = ddy;
4329 i2 = i1 - (dx << 1);
4330 d = i1 - dx;
4331 i = 0;
4332
4333 if (x1 > x2) {
4334 x = x2;
4335 y = y2;
4336 ydir = -1;
4337 xend = x1;
4338 } else {
4339 x = x1;
4340 y = y1;
4341 ydir = 1;
4342 xend = x2;
4343 }
4344
4345 yy = y*fImage->width;
4346 _alphaBlend(&fImage->alt.argb32[Idx(y*fImage->width + x)], &color);
4347 q = (y2 - y1) * ydir;
4348
4349 if (q > 0) {
4350 while (x < xend) {
4351 idx = Idx(yy + x);
4352 if ((iDash%2) == 0) {
4353 _alphaBlend(&fImage->alt.argb32[idx], &color);
4354 }
4355 x++;
4356 if (d >= 0) {
4357 yy += fImage->width;
4358 d += i2;
4359 } else {
4360 d += i1;
4361 }
4362
4363 i++;
4364 if (i >= pDash[iDash]) {
4365 iDash++;
4366 i = 0;
4367 }
4368 if (iDash >= nDash) {
4369 iDash = 0;
4370 i = 0;
4371 }
4372 }
4373 } else {
4374 while (x < xend) {
4375 idx = Idx(yy + x);
4376 if ((iDash%2) == 0) {
4377 _alphaBlend(&fImage->alt.argb32[idx], &color);
4378 }
4379 x++;
4380 if (d >= 0) {
4381 yy -= fImage->width;
4382 d += i2;
4383 } else {
4384 d += i1;
4385 }
4386
4387 i++;
4388 if (i >= pDash[iDash]) {
4389 iDash++;
4390 i = 0;
4391 }
4392 if (iDash >= nDash) {
4393 iDash = 0;
4394 i = 0;
4395 }
4396 }
4397 }
4398 } else {
4399 double as = TMath::Sin(TMath::ATan2(dy, dx));
4400
4401 for (i = 0; i < (int)nDash; i++) {
4402 pDash[i] = TMath::Nint(tDash[i] * as);
4403 }
4404
4405 UInt_t ddx = dx << 1;
4406 i1 = ddx;
4407 i2 = i1 - (dy << 1);
4408 d = i1 - dy;
4409 i = 0;
4410
4411 if (y1 > y2) {
4412 y = y2;
4413 x = x2;
4414 yend = y1;
4415 xdir = -1;
4416 } else {
4417 y = y1;
4418 x = x1;
4419 yend = y2;
4420 xdir = 1;
4421 }
4422
4423 yy = y*fImage->width;
4424 _alphaBlend(&fImage->alt.argb32[Idx(y*fImage->width + x)], &color);
4425 q = (x2 - x1) * xdir;
4426
4427 if (q > 0) {
4428 while (y < yend) {
4429 idx = Idx(yy + x);
4430 if ((iDash%2) == 0) {
4431 _alphaBlend(&fImage->alt.argb32[idx], &color);
4432 }
4433 y++;
4434 yy += fImage->width;
4435
4436 if (d >= 0) {
4437 x++;
4438 d += i2;
4439 } else {
4440 d += i1;
4441 }
4442
4443 i++;
4444 if (i >= pDash[iDash]) {
4445 iDash++;
4446 i = 0;
4447 }
4448 if (iDash >= nDash) {
4449 iDash = 0;
4450 i = 0;
4451 }
4452 }
4453 } else {
4454 while (y < yend) {
4455 idx = Idx(yy + x);
4456 if ((iDash%2) == 0) {
4457 _alphaBlend(&fImage->alt.argb32[idx], &color);
4458 }
4459 y++;
4460 yy += fImage->width;
4461
4462 if (d >= 0) {
4463 x--;
4464 d += i2;
4465 } else {
4466 d += i1;
4467 }
4468
4469 i++;
4470 if (i >= pDash[iDash]) {
4471 iDash++;
4472 i = 0;
4473 }
4474 if (iDash >= nDash) {
4475 iDash = 0;
4476 i = 0;
4477 }
4478 }
4479 }
4480 }
4481 delete [] pDash;
4482}
4483
4484////////////////////////////////////////////////////////////////////////////////
4485/// Draw a dashed line with thick pixel width.
4486
4488 UInt_t nDash, const char *tDash, UInt_t color, UInt_t thick)
4489{
4490 if (!InitImage("DrawDashZTLine")) {
4491 return;
4492 }
4493 int dx, dy;
4494 int i;
4495 double x, y, xend=0, yend=0, x0, y0;
4496 int xdir, ydir;
4497 int q;
4498 UInt_t iDash = 0; // index of current dash
4499
4500 dx = TMath::Abs(Int_t(x2) - Int_t(x1));
4501 dy = TMath::Abs(Int_t(y2) - Int_t(y1));
4502
4503 double *xDash = new double[nDash];
4504 double *yDash = new double[nDash];
4505 double a = TMath::ATan2(dy, dx);
4506 double ac = TMath::Cos(a);
4507 double as = TMath::Sin(a);
4508
4509 for (i = 0; i < (int)nDash; i++) {
4510 xDash[i] = tDash[i] * ac;
4511 yDash[i] = tDash[i] * as;
4512
4513 // dirty trick (must be fixed)
4514 if ((i%2) == 0) {
4515 xDash[i] = xDash[i]/2;
4516 yDash[i] = yDash[i]/2;
4517 } else {
4518 xDash[i] = xDash[i]*2;
4519 yDash[i] = yDash[i]*2;
4520 }
4521 }
4522
4523 if (dy <= dx) {
4524 if (x1 > x2) {
4525 x = x2;
4526 y = y2;
4527 ydir = -1;
4528 xend = x1;
4529 } else {
4530 x = x1;
4531 y = y1;
4532 ydir = 1;
4533 xend = x2;
4534 }
4535
4536 q = (y2 - y1) * ydir;
4537 x0 = x;
4538 y0 = y;
4539 iDash = 0;
4540 yend = y + q;
4541
4542 if (q > 0) {
4543 while ((x < xend) && (y < yend)) {
4544 x += xDash[iDash];
4545 y += yDash[iDash];
4546
4547 if ((iDash%2) == 0) {
4549 TMath::Nint(x), TMath::Nint(y), color, thick);
4550 } else {
4551 x0 = x;
4552 y0 = y;
4553 }
4554
4555 iDash++;
4556
4557 if (iDash >= nDash) {
4558 iDash = 0;
4559 }
4560 }
4561 } else {
4562 while ((x < xend) && (y > yend)) {
4563 x += xDash[iDash];
4564 y -= yDash[iDash];
4565
4566 if ((iDash%2) == 0) {
4568 TMath::Nint(x), TMath::Nint(y), color, thick);
4569 } else {
4570 x0 = x;
4571 y0 = y;
4572 }
4573
4574 iDash++;
4575
4576 if (iDash >= nDash) {
4577 iDash = 0;
4578 }
4579 }
4580 }
4581 } else {
4582
4583 if (y1 > y2) {
4584 y = y2;
4585 x = x2;
4586 yend = y1;
4587 xdir = -1;
4588 } else {
4589 y = y1;
4590 x = x1;
4591 yend = y2;
4592 xdir = 1;
4593 }
4594
4595 q = (x2 - x1) * xdir;
4596 x0 = x;
4597 y0 = y;
4598 iDash = 0;
4599 xend = x + q;
4600
4601 if (q > 0) {
4602 while ((x < xend) && (y < yend)) {
4603 x += xDash[iDash];
4604 y += yDash[iDash];
4605
4606 if ((iDash%2) == 0) {
4608 TMath::Nint(x), TMath::Nint(y), color, thick);
4609 } else {
4610 x0 = x;
4611 y0 = y;
4612 }
4613
4614 iDash++;
4615
4616 if (iDash >= nDash) {
4617 iDash = 0;
4618 }
4619 }
4620 } else {
4621 while ((x > xend) && (y < yend)) {
4622 x -= xDash[iDash];
4623 y += yDash[iDash];
4624
4625 if ((iDash%2) == 0) {
4627 TMath::Nint(x), TMath::Nint(y), color, thick);
4628 } else {
4629 x0 = x;
4630 y0 = y;
4631 }
4632
4633 iDash++;
4634
4635 if (iDash >= nDash) {
4636 iDash = 0;
4637 }
4638 }
4639 }
4640 }
4641 delete [] xDash;
4642 delete [] yDash;
4643}
4644
4645////////////////////////////////////////////////////////////////////////////////
4646/// Draw a dashed line.
4647
4649 const char *pDash, const char *col, UInt_t thick)
4650
4651{
4652 if (!InitImage("DrawDashLine")) {
4653 return;
4654 }
4655
4656 if ((nDash < 2) || !pDash || (nDash%2)) {
4657 Warning("DrawDashLine", "Wrong input parameters n=%d %ld", nDash, (Long_t)sizeof(pDash)-1);
4658 return;
4659 }
4660
4661 ARGB32 color = ARGB32_White;
4662 parse_argb_color(col, &color);
4663
4664 if (x1 == x2) {
4665 DrawDashVLine(x1, y1, y2, nDash, pDash, (UInt_t)color, thick);
4666 } else if (y1 == y2) {
4667 DrawDashHLine(y1, x1, x2, nDash, pDash, (UInt_t)color, thick);
4668 } else {
4669 if (thick < 2) DrawDashZLine(x1, y1, x2, y2, nDash, pDash, (UInt_t)color);
4670 else DrawDashZTLine(x1, y1, x2, y2, nDash, pDash, (UInt_t)color, thick);
4671 }
4672}
4673
4674////////////////////////////////////////////////////////////////////////////////
4675/// Draw a polyline.
4676
4679{
4680 ARGB32 color = ARGB32_White;
4681 parse_argb_color(col, &color);
4682
4683 Int_t x0 = xy[0].GetX();
4684 Int_t y0 = xy[0].GetY();
4685 Int_t x = 0;
4686 Int_t y = 0;
4687
4688 for (UInt_t i = 1; i < nn; i++) {
4689 x = (mode == kCoordModePrevious) ? x + xy[i].GetX() : xy[i].GetX();
4690 y = (mode == kCoordModePrevious) ? y + xy[i].GetY() : xy[i].GetY();
4691
4692 DrawLineInternal(x0, y0, x, y, (UInt_t)color, thick);
4693
4694 x0 = x;
4695 y0 = y;
4696 }
4697}
4698
4699////////////////////////////////////////////////////////////////////////////////
4700/// Draw a point at the specified position.
4701
4702void TASImage::PutPixel(Int_t x, Int_t y, const char *col)
4703{
4704 if (!InitImage("PutPixel")) {
4705 return;
4706 }
4707
4708 ARGB32 color;
4709 parse_argb_color(col, &color);
4710
4711 if ((x < 0) || (y < 0) || (x >= (int)fImage->width) || (y >= (int)fImage->height)) {
4712 Warning("PutPixel", "Out of range width=%d x=%d, height=%d y=%d",
4713 fImage->width, x, fImage->height, y);
4714 return;
4715 }
4716 _alphaBlend(&fImage->alt.argb32[Idx(y*fImage->width + x)], &color);
4717}
4718
4719////////////////////////////////////////////////////////////////////////////////
4720/// Draw a poly point.
4721
4723{
4724 if (!InitImage("PolyPoint")) {
4725 return;
4726 }
4727
4728 if (!npt || !ppt) {
4729 Warning("PolyPoint", "No points specified");
4730 return;
4731 }
4732
4733 TPoint *ipt = nullptr;
4734 UInt_t i = 0;
4735 ARGB32 color;
4736 parse_argb_color(col, &color);
4737
4738 //make pointlist origin relative
4739 if (mode == kCoordModePrevious) {
4740 ipt = new TPoint[npt];
4741
4742 for (i = 0; i < npt; i++) {
4743 ipt[i].fX += ppt[i].fX;
4744 ipt[i].fY += ppt[i].fY;
4745 }
4746 }
4747 int x, y;
4748
4749 for (i = 0; i < npt; i++) {
4750 x = ipt ? ipt[i].fX : ppt[i].fX;
4751 y = ipt ? ipt[i].fY : ppt[i].fY;
4752
4753 if ((x < 0) || (y < 0) || (x >= (int)fImage->width) || (y >= (int)fImage->height)) {
4754 continue;
4755 }
4756 _alphaBlend(&fImage->alt.argb32[Idx(y*fImage->width + x)], &color);
4757 }
4758
4759 if (ipt) {
4760 delete [] ipt;
4761 }
4762}
4763
4764////////////////////////////////////////////////////////////////////////////////
4765/// Draw segments.
4766
4768{
4769 if (!nseg || !seg) {
4770 Warning("DrawSegments", "Invalid data nseg=%d seg=0x%zx", nseg, (size_t)seg);
4771 return;
4772 }
4773
4774 TPoint pt[2];
4775
4776 for (UInt_t i = 0; i < nseg; i++) {
4777 pt[0].fX = seg->fX1;
4778 pt[1].fX = seg->fX2;
4779 pt[0].fY = seg->fY1;
4780 pt[1].fY = seg->fY2;
4781
4783 seg++;
4784 }
4785}
4786
4787////////////////////////////////////////////////////////////////////////////////
4788/// Fill spans with specified color or/and stipple.
4789
4791 const char *stipple, UInt_t w, UInt_t h)
4792{
4793 if (!InitImage("FillSpans")) {
4794 return;
4795 }
4796
4797 if (!npt || !ppt || !widths || (stipple && (!w || !h))) {
4798 Warning("FillSpans", "Invalid input data npt=%d ppt=0x%zx col=%s widths=0x%zx stipple=0x%zx w=%d h=%d",
4799 npt, (size_t)ppt, col, (size_t)widths, (size_t)stipple, w, h);
4800 return;
4801 }
4802
4803 ARGB32 color;
4804 parse_argb_color(col, &color);
4805 Int_t idx = 0;
4806 UInt_t x = 0;
4807 UInt_t yy;
4808
4809 for (UInt_t i = 0; i < npt; i++) {
4810 yy = ppt[i].fY*fImage->width;
4811 for (UInt_t j = 0; j < widths[i]; j++) {
4812 if ((ppt[i].fX >= (Int_t)fImage->width) || (ppt[i].fX < 0) ||
4813 (ppt[i].fY >= (Int_t)fImage->height) || (ppt[i].fY < 0)) continue;
4814
4815 x = ppt[i].fX + j;
4816 idx = Idx(yy + x);
4817
4818 if (!stipple) {
4819 _alphaBlend(&fImage->alt.argb32[idx], &color);
4820 } else {
4821 Int_t ii = (ppt[i].fY%h)*w + x%w;
4822
4823 if (stipple[ii >> 3] & (1 << (ii%8))) {
4824 _alphaBlend(&fImage->alt.argb32[idx], &color);
4825 }
4826 }
4827 }
4828 }
4829}
4830
4831////////////////////////////////////////////////////////////////////////////////
4832/// Fill spans with tile image.
4833
4835{
4836 if (!InitImage("FillSpans")) {
4837 return;
4838 }
4839
4840 if (!npt || !ppt || !widths || !tile) {
4841 Warning("FillSpans", "Invalid input data npt=%d ppt=0x%zx widths=0x%zx tile=0x%zx",
4842 npt, (size_t)ppt, (size_t)widths, (size_t)tile);
4843 return;
4844 }
4845
4846 Int_t idx = 0;
4847 Int_t ii = 0;
4848 UInt_t x = 0;
4849 UInt_t *arr = tile->GetArgbArray();
4850 if (!arr) return;
4851 UInt_t xx = 0;
4852 UInt_t yy = 0;
4853
4854 for (UInt_t i = 0; i < npt; i++) {
4855 UInt_t yyy = ppt[i].fY*fImage->width;
4856
4857 for (UInt_t j = 0; j < widths[i]; j++) {
4858 if ((ppt[i].fX >= (Int_t)fImage->width) || (ppt[i].fX < 0) ||
4859 (ppt[i].fY >= (Int_t)fImage->height) || (ppt[i].fY < 0)) continue;
4860 x = ppt[i].fX + j;
4861 idx = Idx(yyy + x);
4862 xx = x%tile->GetWidth();
4863 yy = ppt[i].fY%tile->GetHeight();
4864 ii = yy*tile->GetWidth() + xx;
4865 _alphaBlend(&fImage->alt.argb32[idx], &arr[ii]);
4866 }
4867 }
4868}
4869
4870////////////////////////////////////////////////////////////////////////////////
4871/// Crop spans.
4872
4874{
4875 if (!InitImage("CropSpans")) {
4876 return;
4877 }
4878
4879 if (!npt || !ppt || !widths) {
4880 Warning("CropSpans", "No points specified npt=%d ppt=0x%zx widths=0x%zx", npt, (size_t)ppt, (size_t)widths);
4881 return;
4882 }
4883
4884 int y0 = ppt[0].fY;
4885 int y1 = ppt[npt-1].fY;
4886 UInt_t y = 0;
4887 UInt_t x = 0;
4888 UInt_t i = 0;
4889 UInt_t idx = 0;
4890 UInt_t sz = fImage->width*fImage->height;
4891 UInt_t yy = y*fImage->width;
4892
4893 for (y = 0; (int)y < y0; y++) {
4894 for (x = 0; x < fImage->width; x++) {
4895 idx = Idx(yy + x);
4896 if (idx < sz) fImage->alt.argb32[idx] = 0;
4897 }
4898 yy += fImage->width;
4899 }
4900
4901 for (i = 0; i < npt; i++) {
4902 for (x = 0; (int)x < ppt[i].fX; x++) {
4903 idx = Idx(ppt[i].fY*fImage->width + x);
4904 if (idx < sz) fImage->alt.argb32[idx] = 0;
4905 }
4906 for (x = ppt[i].fX + widths[i] + 1; x < fImage->width; x++) {
4907 idx = Idx(ppt[i].fY*fImage->width + x);
4908 if (idx < sz) fImage->alt.argb32[idx] = 0;
4909 }
4910 }
4911
4912 yy = y1*fImage->width;
4913 for (y = y1; y < fImage->height; y++) {
4914 for (x = 0; x < fImage->width; x++) {
4915 idx = Idx(yy + x);
4916 if (idx < sz) fImage->alt.argb32[idx] = 0;
4917 }
4918 yy += fImage->width;
4919 }
4920}
4921
4922////////////////////////////////////////////////////////////////////////////////
4923/// Copy source region to the destination image. Copy is done according
4924/// to specified function:
4925/// ~~~ {.cpp}
4926/// enum EGraphicsFunction {
4927/// kGXclear = 0, // 0
4928/// kGXand, // src AND dst
4929/// kGXandReverse, // src AND NOT dst
4930/// kGXcopy, // src (default)
4931/// kGXandInverted, // NOT src AND dst
4932/// kGXnoop, // dst
4933/// kGXxor, // src XOR dst
4934/// kGXor, // src OR dst
4935/// kGXnor, // NOT src AND NOT dst
4936/// kGXequiv, // NOT src XOR dst
4937/// kGXinvert, // NOT dst
4938/// kGXorReverse, // src OR NOT dst
4939/// kGXcopyInverted, // NOT src
4940/// kGXorInverted, // NOT src OR dst
4941/// kGXnand, // NOT src OR NOT dst
4942/// kGXset // 1
4943/// };
4944/// ~~~
4945
4948{
4949 if (!InitVisual()) {
4950 Warning("CopyArea", "Visual not initiated");
4951 return;
4952 }
4953
4954 if (!fImage) {
4955 Warning("CopyArea", "no image");
4956 return;
4957 }
4958 if (!dst) return;
4959
4960 ASImage *out = ((TASImage*)dst)->GetImage();
4961
4962 int x = 0;
4963 int y = 0;
4964 int idx = 0;
4965 int idx2 = 0;
4966 xsrc = xsrc < 0 ? 0 : xsrc;
4967 ysrc = ysrc < 0 ? 0 : ysrc;
4968
4969 if ((xsrc >= (int)fImage->width) || (ysrc >= (int)fImage->height)) return;
4970
4971 w = xsrc + w > fImage->width ? fImage->width - xsrc : w;
4972 h = ysrc + h > fImage->height ? fImage->height - ysrc : h;
4973 UInt_t yy = (ysrc + y)*fImage->width;
4974
4975 if (!fImage->alt.argb32) {
4976 BeginPaint();
4977 }
4978 if (!out->alt.argb32) {
4979 dst->BeginPaint();
4980 out = ((TASImage*)dst)->GetImage();
4981 }
4982
4983 if (fImage->alt.argb32 && out->alt.argb32) {
4984 for (y = 0; y < (int)h; y++) {
4985 for (x = 0; x < (int)w; x++) {
4986 idx = Idx(yy + x + xsrc);
4987 if ((x + xdst < 0) || (ydst + y < 0) ||
4988 (x + xdst >= (int)out->width) || (y + ydst >= (int)out->height) ) continue;
4989
4990 idx2 = Idx((ydst + y)*out->width + x + xdst);
4991
4992 switch ((EGraphicsFunction)gfunc) {
4993 case kGXclear:
4994 out->alt.argb32[idx2] = 0;
4995 break;
4996 case kGXand:
4997 out->alt.argb32[idx2] &= fImage->alt.argb32[idx];
4998 break;
4999 case kGXandReverse:
5000 out->alt.argb32[idx2] = fImage->alt.argb32[idx] & (~out->alt.argb32[idx2]);
5001 break;
5002 case kGXandInverted:
5003 out->alt.argb32[idx2] &= ~fImage->alt.argb32[idx];
5004 break;
5005 case kGXnoop:
5006 break;
5007 case kGXxor:
5008 out->alt.argb32[idx2] ^= fImage->alt.argb32[idx];
5009 break;
5010 case kGXor:
5011 out->alt.argb32[idx2] |= fImage->alt.argb32[idx];
5012 break;
5013 case kGXnor:
5014 out->alt.argb32[idx2] = (~fImage->alt.argb32[idx]) & (~out->alt.argb32[idx2]);
5015 break;
5016 case kGXequiv:
5017 out->alt.argb32[idx2] ^= ~fImage->alt.argb32[idx];
5018 break;
5019 case kGXinvert:
5020 out->alt.argb32[idx2] = ~out->alt.argb32[idx2];
5021 break;
5022 case kGXorReverse:
5023 out->alt.argb32[idx2] = fImage->alt.argb32[idx] | (~out->alt.argb32[idx2]);
5024 break;
5025 case kGXcopyInverted:
5026 out->alt.argb32[idx2] = ~fImage->alt.argb32[idx];
5027 break;
5028 case kGXorInverted:
5029 out->alt.argb32[idx2] |= ~fImage->alt.argb32[idx];
5030 break;
5031 case kGXnand:
5032 out->alt.argb32[idx2] = (~fImage->alt.argb32[idx]) | (~out->alt.argb32[idx2]);
5033 break;
5034 case kGXset:
5035 out->alt.argb32[idx2] = 0xFFFFFFFF;
5036 break;
5037 case kGXcopy:
5038 default:
5039 out->alt.argb32[idx2] = fImage->alt.argb32[idx];
5040 break;
5041 }
5042 }
5043 yy += fImage->width;
5044 }
5045 }
5046}
5047
5048////////////////////////////////////////////////////////////////////////////////
5049/// Draw a cell array.
5050///
5051/// \param[in] x1,y1 : left down corner
5052/// \param[in] x2,y2 : right up corner
5053/// \param[in] nx,ny : array size
5054/// \param[in] ic : array of ARGB32 colors
5055///
5056/// Draw a cell array. The drawing is done with the pixel precision
5057/// if (X2-X1)/NX (or Y) is not a exact pixel number the position of
5058/// the top right corner may be wrong.
5059
5061 Int_t ny, UInt_t *ic)
5062{
5063 int i, j, ix, iy, w, h;
5064
5065 ARGB32 color = 0xFFFFFFFF;
5066 ARGB32 icol;
5067
5068 w = TMath::Max((x2-x1)/(nx),1);
5069 h = TMath::Max((y1-y2)/(ny),1);
5070 ix = x1;
5071
5072 for (i = 0; i < nx; i++) {
5073 iy = y1 - h;
5074 for (j = 0; j < ny; j++) {
5075 icol = (ARGB32)ic[i + (nx*j)];
5076 if (icol != color) {
5077 color = icol;
5078 }
5079 FillRectangleInternal((UInt_t)color, ix, iy, w, h);
5080 iy = iy - h;
5081 }
5082 ix = ix + w;
5083 }
5084}
5085
5086////////////////////////////////////////////////////////////////////////////////
5087/// Return alpha-blended value computed from bottom and top pixel values.
5088
5090{
5091 UInt_t ret = bot;
5092
5093 _alphaBlend(&ret, &top);
5094 return ret;
5095}
5096
5097////////////////////////////////////////////////////////////////////////////////
5098/// Return visual.
5099
5101{
5102 return fgVisual;
5103}
5104
5105////////////////////////////////////////////////////////////////////////////////
5106/// Get poly bounds along Y.
5107
5108static int GetPolyYBounds(TPoint *pts, int n, int *by, int *ty)
5109{
5110 TPoint *ptMin;
5111 int ymin, ymax;
5112 TPoint *ptsStart = pts;
5113
5114 ptMin = pts;
5115 ymin = ymax = (pts++)->fY;
5116
5117 while (--n > 0) {
5118 if (pts->fY < ymin) {
5119 ptMin = pts;
5120 ymin = pts->fY;
5121 }
5122 if (pts->fY > ymax) {
5123 ymax = pts->fY;
5124 }
5125 pts++;
5126 }
5127
5128 *by = ymin;
5129 *ty = ymax;
5130 return (ptMin - ptsStart);
5131}
5132
5133////////////////////////////////////////////////////////////////////////////////
5134/// The code is based on Xserver/mi/mipolycon.c
5135/// "Copyright 1987, 1998 The Open Group"
5136
5139{
5140 int xl = 0; // x vals of leftedges
5141 int xr = 0; // x vals of right edges
5142 int dl = 0; // decision variables
5143 int dr = 0; // decision variables
5144 int ml = 0; // left edge slope
5145 int m1l = 0; // left edge slope+1
5146 int mr = 0, m1r = 0; // right edge slope and slope+1
5147 int incr1l = 0, incr2l = 0; // left edge error increments
5148 int incr1r = 0, incr2r = 0; // right edge error increments
5149 int dy; // delta y
5150 int y; // current scanline
5151 int left, right; // indices to first endpoints
5152 int i; // loop counter
5153 int nextleft, nextright; // indices to second endpoints
5154 TPoint *ptsOut; // output buffer
5155 UInt_t *width; // output buffer
5156 TPoint *firstPoint = nullptr;
5157 UInt_t *firstWidth = nullptr;
5158 int imin; // index of smallest vertex (in y)
5159 int ymin; // y-extents of polygon
5160 int ymax;
5161 Bool_t ret = kTRUE;
5162
5163 *nspans = 0;
5164
5165 if (!InitImage("GetPolygonSpans")) {
5166 return kFALSE;
5167 }
5168
5169 if ((npt < 3) || !ppt) {
5170 Warning("GetPolygonSpans", "No points specified npt=%d ppt=0x%zx", npt, (size_t)ppt);
5171 return kFALSE;
5172 }
5173
5174 // find leftx, bottomy, rightx, topy, and the index
5175 // of bottomy. Also translate the points.
5177
5178 dy = ymax - ymin + 1;
5179 if ((npt < 3) || (dy < 0)) return kFALSE;
5180
5181 ptsOut = firstPoint = new TPoint[dy];
5182 width = firstWidth = new UInt_t[dy];
5183 ret = kTRUE;
5184
5186 y = ppt[nextleft].fY;
5187
5188 // loop through all edges of the polygon
5189 do {
5190 // add a left edge if we need to
5191 if (ppt[nextleft].fY == y) {
5192 left = nextleft;
5193
5194 // find the next edge, considering the end
5195 // conditions of the array.
5196 nextleft++;
5197 if (nextleft >= (int)npt) {
5198 nextleft = 0;
5199 }
5200
5201 // now compute all of the random information
5202 // needed to run the iterative algorithm.
5203 BRESINITPGON(ppt[nextleft].fY - ppt[left].fY,
5204 ppt[left].fX, ppt[nextleft].fX,
5205 xl, dl, ml, m1l, incr1l, incr2l);
5206 }
5207
5208 // add a right edge if we need to
5209 if (ppt[nextright].fY == y) {
5210 right = nextright;
5211
5212 // find the next edge, considering the end
5213 // conditions of the array.
5214 nextright--;
5215 if (nextright < 0) {
5216 nextright = npt-1;
5217 }
5218
5219 // now compute all of the random information
5220 // needed to run the iterative algorithm.
5221 BRESINITPGON(ppt[nextright].fY - ppt[right].fY,
5222 ppt[right].fX, ppt[nextright].fX,
5223 xr, dr, mr, m1r, incr1r, incr2r);
5224 }
5225
5226 // generate scans to fill while we still have
5227 // a right edge as well as a left edge.
5228 i = TMath::Min(ppt[nextleft].fY, ppt[nextright].fY) - y;
5229
5230 // in case of non-convex polygon
5231 if (i < 0) {
5232 delete [] firstWidth;
5233 delete [] firstPoint;
5234 return kTRUE;
5235 }
5236
5237 while (i-- > 0) {
5238 ptsOut->fY = y;
5239
5240 // reverse the edges if necessary
5241 if (xl < xr) {
5242 *(width++) = xr - xl;
5243 (ptsOut++)->fX = xl;
5244 } else {
5245 *(width++) = xl - xr;
5246 (ptsOut++)->fX = xr;
5247 }
5248 y++;
5249
5250 // increment down the edges
5253 }
5254 } while (y != ymax);
5255
5259
5260 return ret;
5261}
5262
5263////////////////////////////////////////////////////////////////////////////////
5264/// Fill a convex polygon with background color or bitmap.
5265/// For non convex polygon one must use DrawFillArea method
5266
5268 const char *stipple, UInt_t w, UInt_t h)
5269{
5270 UInt_t nspans = 0;
5271 TPoint *firstPoint = nullptr; // output buffer
5272 UInt_t *firstWidth = nullptr; // output buffer
5273
5275 ARGB32 color = ARGB32_White;
5276 parse_argb_color(col, &color);
5277
5278 if (nspans) {
5279 if (!stipple && ((color & 0xff000000)==0xff000000)) { //no stipple no alpha
5281 } else {
5283 }
5284
5285 if (del) {
5286 delete [] firstWidth;
5287 delete [] firstPoint;
5288 }
5289 } else {
5290 if (firstWidth) delete [] firstWidth;
5291 if (firstPoint) delete [] firstPoint;
5292 }
5293}
5294
5295////////////////////////////////////////////////////////////////////////////////
5296/// Fill a convex polygon with background image.
5297/// For non convex polygon one must use DrawFillArea method
5298
5300{
5301 UInt_t nspans = 0;
5302 TPoint *firstPoint = nullptr; // output buffer
5303 UInt_t *firstWidth = nullptr; // output buffer
5304
5306
5307 if (nspans) {
5309
5310 if (del) {
5311 delete [] firstWidth;
5312 delete [] firstPoint;
5313 }
5314 } else {
5315 if (firstWidth) delete [] firstWidth;
5316 if (firstPoint) delete [] firstPoint;
5317 }
5318}
5319
5320////////////////////////////////////////////////////////////////////////////////
5321/// Crop a convex polygon.
5322
5324{
5325 UInt_t nspans = 0;
5326 TPoint *firstPoint = nullptr;
5327 UInt_t *firstWidth = nullptr;
5328
5330
5331 if (nspans) {
5333
5334 if (del) {
5335 delete [] firstWidth;
5336 delete [] firstPoint;
5337 }
5338 } else {
5339 if (firstWidth) delete [] firstWidth;
5340 if (firstPoint) delete [] firstPoint;
5341 }
5342}
5343
5344static const UInt_t NUMPTSTOBUFFER = 512;
5345
5346////////////////////////////////////////////////////////////////////////////////
5347/// Fill a polygon (any type convex, non-convex).
5348
5349void TASImage::DrawFillArea(UInt_t count, TPoint *ptsIn, const char *col,
5350 const char *stipple, UInt_t w, UInt_t h)
5351{
5352 if (!InitImage("DrawFillArea")) {
5353 return;
5354 }
5355
5356 if ((count < 3) || !ptsIn) {
5357 Warning("DrawFillArea", "No points specified npt=%d ppt=0x%zx", count, (size_t)ptsIn);
5358 return;
5359 }
5360
5361 if (count < 5) {
5362 FillPolygon(count, ptsIn, col, stipple, w, h);
5363 return;
5364 }
5365
5366 ARGB32 color = ARGB32_White;
5367 parse_argb_color(col, &color);
5368
5369 EdgeTableEntry *pAET; // the Active Edge Table
5370 int y; // the current scanline
5371 UInt_t nPts = 0; // number of pts in buffer
5372
5373 ScanLineList *pSLL; // Current ScanLineList
5374 TPoint *ptsOut; // ptr to output buffers
5375 UInt_t *width;
5376 TPoint firstPoint[NUMPTSTOBUFFER]; // the output buffers
5378 EdgeTableEntry *pPrevAET; // previous AET entry
5379 EdgeTable ET; // Edge Table header node
5380 EdgeTableEntry AET; // Active ET header node
5381 EdgeTableEntry *pETEs; // Edge Table Entries buff
5382 ScanLineListBlock SLLBlock; // header for ScanLineList
5383 Bool_t del = kTRUE;
5384
5385 static const UInt_t gEdgeTableEntryCacheSize = 200;
5387
5388 if (count < gEdgeTableEntryCacheSize) {
5390 del = kFALSE;
5391 } else {
5392 pETEs = new EdgeTableEntry[count];
5393 del = kTRUE;
5394 }
5395
5396 ET.scanlines.next = nullptr; // to avoid compiler warnings
5397 ET.ymin = ET.ymax = 0; // to avoid compiler warnings
5398
5400 width = firstWidth;
5401 CreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock);
5402 pSLL = ET.scanlines.next;
5403
5404 for (y = ET.ymin; y < ET.ymax; y++) {
5405 if (pSLL && y == pSLL->scanline) {
5406 loadAET(&AET, pSLL->edgelist);
5407 pSLL = pSLL->next;
5408 }
5409 pPrevAET = &AET;
5410 pAET = AET.next;
5411
5412 while (pAET) {
5413 ptsOut->fX = pAET->bres.minor_axis;
5414 ptsOut->fY = y;
5415 ptsOut++;
5416 nPts++;
5417
5418 *width++ = pAET->next->bres.minor_axis - pAET->bres.minor_axis;
5419
5420 if (nPts == NUMPTSTOBUFFER) {
5421 if (!stipple && ((color & 0xff000000)==0xff000000)) { //no stipple, no alpha
5423 } else {
5425 }
5427 width = firstWidth;
5428 nPts = 0;
5429 }
5432 }
5434 }
5435
5436 if (nPts) {
5437 if (!stipple && ((color & 0xff000000)==0xff000000)) { //no stipple, no alpha
5439 } else {
5441 }
5442 }
5443
5444 if (del) delete [] pETEs;
5445 FreeStorage(SLLBlock.next);
5446}
5447
5448////////////////////////////////////////////////////////////////////////////////
5449/// Fill a polygon (any type convex, non-convex).
5450
5452{
5453 if (!InitImage("DrawFillArea")) {
5454 return;
5455 }
5456
5457 if ((count < 3) || !ptsIn) {
5458 Warning("DrawFillArea", "No points specified npt=%d ppt=0x%zx", count, (size_t)ptsIn);
5459 return;
5460 }
5461
5462 if (count < 5) {
5463 FillPolygon(count, ptsIn, tile);
5464 return;
5465 }
5466
5467 EdgeTableEntry *pAET; // the Active Edge Table
5468 int y; // the current scanline
5469 UInt_t nPts = 0; // number of pts in buffer
5470
5471 ScanLineList *pSLL; // Current ScanLineList
5472 TPoint *ptsOut; // ptr to output buffers
5473 UInt_t *width;
5474 TPoint firstPoint[NUMPTSTOBUFFER]; // the output buffers
5476 EdgeTableEntry *pPrevAET; // previous AET entry
5477 EdgeTable ET; // Edge Table header node
5478 EdgeTableEntry AET; // Active ET header node
5479 EdgeTableEntry *pETEs; // Edge Table Entries buff
5480 ScanLineListBlock SLLBlock; // header for ScanLineList
5481
5482 pETEs = new EdgeTableEntry[count];
5483
5484 ET.scanlines.next = nullptr; // to avoid compiler warnings
5485 ET.ymin = ET.ymax = 0; // to avoid compiler warnings
5486
5488 width = firstWidth;
5489 CreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock);
5490 pSLL = ET.scanlines.next;
5491
5492 for (y = ET.ymin; y < ET.ymax; y++) {
5493 if (pSLL && y == pSLL->scanline) {
5494 loadAET(&AET, pSLL->edgelist);
5495 pSLL = pSLL->next;
5496 }
5497 pPrevAET = &AET;
5498 pAET = AET.next;
5499
5500 while (pAET) {
5501 ptsOut->fX = pAET->bres.minor_axis;
5502 ptsOut->fY = y;
5503 ptsOut++;
5504 nPts++;
5505
5506 *width++ = pAET->next->bres.minor_axis - pAET->bres.minor_axis;
5507
5508 if (nPts == NUMPTSTOBUFFER) {
5511 width = firstWidth;
5512 nPts = 0;
5513 }
5516 }
5518 }
5520
5521 delete [] pETEs;
5522 FreeStorage(SLLBlock.next);
5523}
5524
5525////////////////////////////////////////////////////////////////////////////////
5526/// Create draw context.
5527
5529{
5530 ASDrawContext *ctx = new ASDrawContext;
5531
5532 ctx->canvas_width = im->width;
5533 ctx->canvas_height = im->height;
5534 ctx->canvas = im->alt.argb32;
5535 ctx->scratch_canvas = nullptr;
5536
5537 ctx->flags = ASDrawCTX_CanvasIsARGB;
5539 return ctx;
5540}
5541
5542////////////////////////////////////////////////////////////////////////////////
5543/// Destroy asdraw context32.
5544
5546{
5547 if (ctx) {
5548 if (ctx->scratch_canvas) free(ctx->scratch_canvas);
5549 delete ctx;
5550 }
5551}
5552
5553static const UInt_t kBrushCacheSize = 20;
5555
5556////////////////////////////////////////////////////////////////////////////////
5557/// Draw wide line.
5558
5560 UInt_t color, UInt_t thick)
5561{
5562 if (!InitImage("DrawWideLine")) {
5563 return;
5564 }
5565 Int_t sz = thick*thick;
5566 CARD32 *matrix;
5568
5569 if (use_cache) {
5571 } else {
5572 matrix = new CARD32[sz];
5573 }
5574
5575 for (int i = 0; i < sz; i++) {
5576 matrix[i] = (CARD32)color;
5577 }
5578
5580 brush.matrix = matrix;
5581 brush.width = thick;
5582 brush.height = thick;
5583 brush.center_y = brush.center_x = thick/2;
5584
5585 // When the first or last point of a wide line is exactly on the
5586 // window limit the line is drawn vertically or horizontally.
5587 // see https://sft.its.cern.ch/jira/browse/ROOT-8021
5588 UInt_t xx1 = x1;
5589 UInt_t yy1 = y1;
5590 UInt_t xx2 = x2;
5591 UInt_t yy2 = y2;
5592 if (xx1 == fImage->width) --xx1;
5593 if (yy1 == fImage->height) --yy1;
5594 if (xx2 == fImage->width) --xx2;
5595 if (yy2 == fImage->height) --yy2;
5597 asim_move_to(ctx, xx1, yy1);
5598 asim_line_to(ctx, xx2, yy2);
5599
5600 if (!use_cache) {
5601 delete [] matrix;
5602 }
5604}
5605
5606////////////////////////////////////////////////////////////////////////////////
5607/// Draw glyph bitmap.
5608
5610{
5611 UInt_t col[5];
5612 Bool_t has_alpha = (color & 0xff000000) != 0xff000000;
5613
5615
5616 auto ndots = source->width * source->rows;
5617 ULong_t r = 0, g = 0, b = 0;
5618
5619 const Int_t y0 = by > 0 ? by * fImage->width : 0;
5620 Int_t yy = y0;
5621 for (UInt_t y = 0; y < source->rows; y++) {
5622 Int_t byy = by + y;
5623 if ((byy >= (Int_t) fImage->height) || (byy < 0)) continue;
5624
5625 for (UInt_t x = 0; x < source->width; x++) {
5626 Int_t bxx = bx + x;
5627 if ((bxx >= (Int_t) fImage->width) || (bxx < 0)) continue;
5628
5629 auto idx = Idx(bxx + yy);
5630 r += ((fImage->alt.argb32[idx] & 0xff0000) >> 16);
5631 g += ((fImage->alt.argb32[idx] & 0x00ff00) >> 8);
5632 b += (fImage->alt.argb32[idx] & 0x0000ff);
5633 }
5634 yy += fImage->width;
5635 }
5636 if (ndots > 0) {
5637 r /= ndots;
5638 g /= ndots;
5639 b /= ndots;
5640 }
5641
5642 col[0] = (r << 16) + (g << 8) + b;
5643 col[4] = color;
5644 Int_t col4r = (col[4] & 0xff0000) >> 16;
5645 Int_t col4g = (col[4] & 0x00ff00) >> 8;
5646 Int_t col4b = (col[4] & 0x0000ff);
5647
5648 // interpolate between fore and background colors
5649 for (Int_t x = 3; x > 0; x--) {
5650 Int_t xx = 4 - x;
5651 Int_t colxr = (col4r*x + r*xx) >> 2;
5652 Int_t colxg = (col4g*x + g*xx) >> 2;
5653 Int_t colxb = (col4b*x + b*xx) >> 2;
5654 col[x] = (colxr << 16) + (colxg << 8) + colxb;
5655 }
5656
5657 Int_t clipx1 = 0, clipx2 = 0, clipy1 = 0, clipy2 = 0;
5659
5660 if (clippad) {
5662 clipx1 = clippad->XtoAbsPixel(clippad->GetX1())*is - offx;
5663 clipx2 = clippad->XtoAbsPixel(clippad->GetX2())*is - offx;
5664 clipy1 = clippad->YtoAbsPixel(clippad->GetY1())*is - offy;
5665 clipy2 = clippad->YtoAbsPixel(clippad->GetY2())*is - offy;
5666 noClip = kFALSE;
5667 }
5668
5669 yy = y0;
5670 UChar_t *s = source->buffer;
5671
5672 for (UInt_t y = 0; y < source->rows; y++) {
5673 Int_t byy = by + y;
5674
5675 for (UInt_t x = 0; x < source->width; x++) {
5676 Int_t bxx = bx + x;
5677
5678 UChar_t d = *s++ & 0xff;
5679 d = ((d + 10) * 5) >> 8;
5680 if (d > 4) d = 4;
5681
5682 if (d > 0) {
5683 if (noClip || ((bxx < clipx2) && (bxx >= clipx1) &&
5684 (byy >= clipy2) && (byy < clipy1))) {
5685 auto idx = Idx(bxx + yy);
5686 auto acolor = (ARGB32) col[d];
5687 if (has_alpha) {
5688 _alphaBlend(&fImage->alt.argb32[idx], &acolor);
5689 } else {
5690 fImage->alt.argb32[idx] = acolor;
5691 }
5692 }
5693 }
5694 }
5695 yy += fImage->width;
5696 }
5697}
5698
5699////////////////////////////////////////////////////////////////////////////////
5700/// Draw text at the pixel position (x,y).
5701
5703{
5704 if (gPad)
5705 DrawTextOnPad(text, x, y, gPad, 0, 0);
5706}
5707
5708
5709////////////////////////////////////////////////////////////////////////////////
5710/// Draw text at the pixel position (x,y) checking clip on pad.
5711
5713{
5714 if (!text || !InitImage("DrawTextOnPad"))
5715 return;
5716
5717 TTFhandle ttf;
5718
5719 // set text font
5720 ttf.SetTextFont(text->GetTextFont());
5721
5722 UInt_t padw = pad ? pad->GetPadWidth() : 100;
5723 UInt_t padh = pad ? pad->GetPadHeight() : 100;
5724
5725 // set text size
5726 Float_t ttfsize = text->GetTextSize() * TMath::Min(padw, padh);
5727 ttf.SetTextSize(ttfsize*kScale);
5728
5729 // set text angle
5730 ttf.SetRotationMatrix(text->GetTextAngle());
5731
5732 // set text
5733 const wchar_t *wcsTitle = reinterpret_cast<const wchar_t *>(text->GetWcsTitle());
5734 if (wcsTitle)
5735 ttf.PrepareString(wcsTitle);
5736 else
5737 ttf.PrepareString(text->GetTitle());
5738
5739 ttf.LayoutGlyphs();
5740
5741 // color
5742 TColor *col = gROOT->GetColor(text->GetTextColor());
5743 if (!col) { // no color, make it black
5744 col = gROOT->GetColor(1);
5745 if (!col) return;
5746 }
5747 ARGB32 color = ARGB32_White;
5748 parse_argb_color(col->AsHexString(), &color);
5749
5750 // Align()
5751 Int_t align = 0;
5752 Int_t txalh = text->GetTextAlign()/10;
5753 Int_t txalv = text->GetTextAlign()%10;
5754
5755 switch (txalh) {
5756 case 0 :
5757 case 1 :
5758 switch (txalv) { //left
5759 case 1 :
5760 align = 7; //bottom
5761 break;
5762 case 2 :
5763 align = 4; //center
5764 break;
5765 case 3 :
5766 align = 1; //top
5767 break;
5768 }
5769 break;
5770 case 2 :
5771 switch (txalv) { //center
5772 case 1 :
5773 align = 8; //bottom
5774 break;
5775 case 2 :
5776 align = 5; //center
5777 break;
5778 case 3 :
5779 align = 2; //top
5780 break;
5781 }
5782 break;
5783 case 3 :
5784 switch (txalv) { //right
5785 case 1 :
5786 align = 9; //bottom
5787 break;
5788 case 2 :
5789 align = 6; //center
5790 break;
5791 case 3 :
5792 align = 3; //top
5793 break;
5794 }
5795 break;
5796 }
5797
5798 FT_Vector ftal;
5799
5800 // vertical alignment
5801 if (align == 1 || align == 2 || align == 3) {
5802 ftal.y = ttf.GetAscent();
5803 } else if (align == 4 || align == 5 || align == 6) {
5804 ftal.y = ttf.GetAscent() / 2;
5805 } else {
5806 ftal.y = 0;
5807 }
5808
5809 // horizontal alignment
5810 if (align == 3 || align == 6 || align == 9) {
5811 ftal.x = ttf.GetWidth();
5812 } else if (align == 2 || align == 5 || align == 8) {
5813 ftal.x = ttf.GetWidth() / 2;
5814 } else {
5815 ftal.x = 0;
5816 }
5817
5818 FT_Vector_Transform(&ftal, ttf.GetRotMatrix());
5819 ftal.x = (ftal.x >> 6);
5820 ftal.y = (ftal.y >> 6);
5821
5822 for (UInt_t n = 0; n < ttf.GetNumGlyphs(); n++) {
5823 if (auto bitmap = ttf.GetGlyphBitmap(n, kTRUE)) {
5824 Int_t bx = x - ftal.x + bitmap->left;
5825 Int_t by = y + ftal.y - bitmap->top;
5826
5827 DrawFTGlyph(&bitmap->bitmap, color, bx, by, pad, offx, offy);
5828 }
5829 }
5830}
5831
5832////////////////////////////////////////////////////////////////////////////////
5833/// Draw text using TrueType fonts.
5834
5836 UInt_t color, const char *font_name, Float_t angle)
5837{
5838 if (!text || !InitImage("DrawTextTTF"))
5839 return;
5840
5841 TTFhandle ttf;
5842
5843 ttf.SetTextFont(font_name);
5844 ttf.SetTextSize(size);
5845 ttf.SetRotationMatrix(angle);
5846 ttf.PrepareString(text);
5847 ttf.LayoutGlyphs();
5848
5849 // compute the size and position that will contain the text
5850 // Int_t Xoff = TMath::Max(0, (Int_t) -ttf.GetBox().xMin);
5851 Int_t Yoff = TMath::Max(0, (Int_t) -ttf.GetBox().yMin);
5852 Int_t h = ttf.GetBox().yMax + Yoff;
5853
5854 for (UInt_t n = 0; n < ttf.GetNumGlyphs(); n++) {
5855 if (auto bitmap = ttf.GetGlyphBitmap(n, kTRUE)) {
5856 Int_t bx = x + bitmap->left;
5857 Int_t by = y + h - bitmap->top;
5858 DrawFTGlyph(&bitmap->bitmap, color, bx, by);
5859 }
5860 }
5861}
5862
5863////////////////////////////////////////////////////////////////////////////////
5864/// Return in-memory buffer compressed according image type.
5865/// Buffer must be deallocated after usage with free(buffer) call.
5866/// This method can be used for sending images over network.
5867
5869{
5870 static ASImageExportParams params;
5871 Bool_t ret = kFALSE;
5873
5874 if (!img) return;
5875
5876 switch (type) {
5877 case TImage::kXpm:
5878 ret = ASImage2xpmRawBuff(img, (CARD8 **)buffer, size, nullptr);
5879 break;
5880 case TImage::kPng:
5881 ret = ASImage2PNGBuff(img, (CARD8 **)buffer, size, &params);
5882 break;
5883 default:
5884 ret = kFALSE;
5885 }
5886
5887 if (!ret) {
5888 *size = 0;
5889 *buffer = nullptr;
5890 }
5891}
5892
5893////////////////////////////////////////////////////////////////////////////////
5894/// Create image from compressed buffer.
5895/// Supported formats:
5896///
5897/// - PNG - by default
5898/// - XPM - two options exist:
5899/// 1. xpm as a single string (raw buffer). Such string
5900/// is returned by GetImageBuffer method.
5901/// For example:
5902/// ~~~ {.cpp}
5903/// char *buf;
5904/// int sz;
5905/// im1->GetImageBuffer(&buf, &int, TImage::kXpm); /*raw buffer*/
5906/// TImage *im2 = TImage::Create();
5907/// im2->SetImageBuffer(&buf, TImage::kXpm);
5908/// ~~~
5909/// 2. xpm as an array of strings (pre-parsed)
5910/// ~~~ {.cpp}
5911/// For example:
5912/// char *xpm[] = {
5913/// "64 28 58 1",
5914/// " c #0A030C",
5915/// ". c #1C171B"
5916/// ...
5917/// TImage *im = TImage::Create();
5918/// im->SetImageBuffer(xpm, TImage::kXpm);
5919/// ~~~
5920
5922{
5923 DestroyImage();
5924
5925 static ASImageImportParams params;
5926 params.flags = 0;
5927 params.width = 0;
5928 params.height = 0 ;
5929 params.filter = SCL_DO_ALL;
5930 params.gamma = SCREEN_GAMMA;
5931 params.gamma_table = nullptr;
5932 params.compression = 0;
5933 params.format = ASA_ASImage;
5934 params.search_path = nullptr;
5935 params.subimage = 0;
5936
5937 switch (type) {
5938 case TImage::kXpm:
5939 {
5940 char *ptr = buffer[0];
5941 while (isspace((int)*ptr)) ++ptr;
5942 if (atoi(ptr)) { // pre-parsed and preloaded data
5943 fImage = xpm_data2ASImage((const char**)buffer, &params);
5944 } else {
5945 fImage = xpmRawBuff2ASImage((const char*)*buffer, &params);
5946 }
5947 break;
5948 }
5949 case TImage::kPng:
5950 fImage = PNGBuff2ASimage((CARD8 *)*buffer, &params);
5951 break;
5952 default:
5953 fImage = nullptr;
5954 }
5955
5956 if (!fImage) {
5957 return kFALSE;
5958 }
5959
5960 if (fName.IsNull()) {
5961 fName.Form("img_%dx%d.%d", fImage->width, fImage->height, gRandom->Integer(1000));
5962 }
5963 UnZoom();
5964 return kTRUE;
5965}
5966
5967////////////////////////////////////////////////////////////////////////////////
5968/// Create image thumbnail.
5969
5971{
5972 int size;
5973 const int sz = 64;
5974
5975 if (!fImage) {
5976 Warning("CreateThumbnail", "No image");
5977 return;
5978 }
5979
5980 if (!InitVisual()) {
5981 Warning("CreateThumbnail", "Visual not initiated");
5982 return;
5983 }
5984
5985 static char *buf = nullptr;
5986 int w, h;
5987 ASImage *img = nullptr;
5988
5989 if (fImage->width > fImage->height) {
5990 w = sz;
5991 h = (fImage->height*sz)/fImage->width;
5992 } else {
5993 h = sz;
5994 w = (fImage->width*sz)/fImage->height;
5995 }
5996
5997 w = w < 8 ? 8 : w;
5998 h = h < 8 ? 8 : h;
5999
6002 if (!img) {
6003 return;
6004 }
6005
6006 // contrasting
6008 ASImageLayer layers[2];
6009 init_image_layers(&(layers[0]), 2);
6010 layers[0].im = img;
6011 layers[0].dst_x = 0;
6012 layers[0].dst_y = 0;
6013 layers[0].clip_width = img->width;
6014 layers[0].clip_height = img->height;
6015 layers[0].bevel = nullptr;
6016 layers[1].im = img;
6017 layers[1].dst_x = 0;
6018 layers[1].dst_y = 0;
6019 layers[1].clip_width = img->width;
6020 layers[1].clip_height = img->height;
6021 layers[1].merge_scanlines = blend_scanlines_name2func("tint");
6022 rendered_im = merge_layers(fgVisual, &(layers[0]), 2, img->width, img->height,
6025 img = rendered_im;
6026
6027 // pad image
6028 ASImage *padimg = nullptr;
6029 int d = 0;
6030
6031 if (w == sz) {
6032 d = (sz - h) >> 1;
6033 padimg = pad_asimage(fgVisual, img, 0, d, sz, sz, 0x00ffffff,
6035 } else {
6036 d = (sz - w) >> 1;
6037 padimg = pad_asimage(fgVisual, img, d, 0, sz, sz, 0x00ffffff,
6039 }
6040
6041 if (!padimg) {
6043 return;
6044 }
6045
6046 void *ptr = &buf;
6047 ASImage2xpmRawBuff(padimg, (CARD8 **)ptr, &size, nullptr);
6048 fTitle = buf;
6049
6051}
6052
6053////////////////////////////////////////////////////////////////////////////////
6054/// Streamer for ROOT I/O.
6055
6057{
6058 Bool_t image_type = 0;
6059 int size = 0;
6060 int w, h;
6061 UInt_t R__s, R__c;
6062
6063 if (b.IsReading()) {
6064 Version_t version = b.ReadVersion(&R__s, &R__c);
6065 if (version == 0) { //dumb prototype for schema evolution
6066 return;
6067 }
6068
6069 if ( version == 1 ) {
6070 Int_t fileVersion = b.GetVersionOwner();
6071 if (fileVersion > 0 && fileVersion < 50000 ) {
6073 b >> fMaxValue;
6074 b >> fMinValue;
6075 b >> fZoomOffX;
6076 b >> fZoomOffY;
6077 b >> fZoomWidth;
6078 b >> fZoomHeight;
6079 if ( fileVersion < 40200 ) {
6081 b >> zoomUpdate;
6083 } else {
6084 b >> fZoomUpdate;
6085 b >> fEditable;
6087 b >> paintMode;
6089 }
6090 b.CheckByteCount(R__s, R__c, TASImage::IsA());
6091 return;
6092 }
6093 }
6094
6096 b >> image_type;
6097
6098 if (image_type != 0) { // read PNG compressed image
6099 b >> size;
6100 char *buffer = new char[size];
6101 b.ReadFastArray(buffer, size);
6102 SetImageBuffer(&buffer, TImage::kPng);
6103 delete [] buffer;
6104 } else { // read vector with palette
6106 b >> w;
6107 b >> h;
6108 size = w*h;
6109 Double_t *vec = new Double_t[size];
6110 b.ReadFastArray(vec, size);
6111 SetImage(vec, w, h, &fPalette);
6112 delete [] vec;
6113 }
6114 b.CheckByteCount(R__s, R__c, TASImage::IsA());
6115 } else {
6116 if (!fImage) {
6117 return;
6118 }
6119 R__c = b.WriteVersion(TASImage::IsA(), kTRUE);
6120
6121 if (fName.IsNull()) {
6122 fName.Form("img_%dx%d.%d", fImage->width, fImage->height, gRandom->Integer(1000));
6123 }
6125
6126 image_type = fImage->alt.vector ? 0 : 1;
6127 b << image_type;
6128
6129 if (image_type != 0) { // write PNG compressed image
6130 char *buffer = nullptr;
6131 GetImageBuffer(&buffer, &size, TImage::kPng);
6132 b << size;
6133 b.WriteFastArray(buffer, size);
6134 free(buffer);
6135 } else { // write vector with palette
6137 b << fImage->width;
6138 b << fImage->height;
6139 b.WriteFastArray(fImage->alt.vector, fImage->width*fImage->height);
6140 }
6141 b.SetByteCount(R__c, kTRUE);
6142 }
6143}
6144
6145////////////////////////////////////////////////////////////////////////////////
6146/// Browse image.
6147
6149{
6150 if (fImage->alt.vector) {
6151 Draw("n");
6152 } else {
6153 Draw("nxxx");
6154 }
6156}
6157
6158////////////////////////////////////////////////////////////////////////////////
6159/// Title is used to keep 32x32 xpm image's thumbnail.
6160
6161const char *TASImage::GetTitle() const
6162{
6163 if (!gDirectory || !gDirectory->IsWritable())
6164 return nullptr;
6165
6166 TASImage *mutble = (TASImage *)this;
6167
6168 if (fTitle.IsNull()) {
6169 mutble->SetTitle(fName.Data());
6170 }
6171
6172 return fTitle.Data();
6173}
6174
6175////////////////////////////////////////////////////////////////////////////////
6176/// Set a title for an image.
6177
6178void TASImage::SetTitle(const char *title)
6179{
6180 if (fTitle.IsNull()) {
6182 }
6183
6184 if (fTitle.IsNull()) {
6185 return;
6186 }
6187
6188 int start = fTitle.Index("/*") + 3;
6189 int stop = fTitle.Index("*/") - 1;
6190
6191 if ((start > 0) && (stop - start > 0)) {
6192 fTitle.Replace(start, stop - start, title);
6193 }
6194}
6195
6196////////////////////////////////////////////////////////////////////////////////
6197/// Draw a cubic bezier line.
6198
6200 Int_t x3, Int_t y3, const char *col, UInt_t thick)
6201{
6202 if (!InitImage("DrawCubeBezier")) {
6203 return;
6204 }
6205 Int_t sz = thick*thick;
6206 CARD32 *matrix;
6208
6209 ARGB32 color = ARGB32_White;
6210 parse_argb_color(col, &color);
6211
6212 if (use_cache) {
6214 } else {
6215 matrix = new CARD32[sz];
6216 }
6217
6218 for (int i = 0; i < sz; i++) {
6219 matrix[i] = (CARD32)color;
6220 }
6221
6223 brush.matrix = matrix;
6224 brush.width = thick;
6225 brush.height = thick;
6226 brush.center_y = brush.center_x = thick/2;
6227
6229 asim_cube_bezier(ctx, x1, y1, x2, y2, x3, y3);
6230
6231 if (!use_cache)
6232 delete [] matrix;
6233
6235}
6236
6237////////////////////////////////////////////////////////////////////////////////
6238/// Draw a straight ellipse.
6239/// If thick < 0 - draw filled ellipse.
6240
6242 const char *col, Int_t thick)
6243{
6244 if (!InitImage("DrawStraightEllips")) {
6245 return;
6246 }
6247 thick = !thick ? 1 : thick;
6248 Int_t sz = thick*thick;
6249 CARD32 *matrix;
6251
6252 ARGB32 color = ARGB32_White;
6253 parse_argb_color(col, &color);
6254
6255 if (use_cache) {
6257 } else {
6258 matrix = new CARD32[sz];
6259 }
6260
6261 for (int i = 0; i < sz; i++) {
6262 matrix[i] = (CARD32)color;
6263 }
6264
6266 brush.matrix = matrix;
6267 brush.width = thick > 0 ? thick : 1;
6268 brush.height = thick > 0 ? thick : 1;
6269 brush.center_y = brush.center_x = thick > 0 ? thick/2 : 0;
6270
6272 asim_straight_ellips(ctx, x, y, rx, ry, thick < 0);
6273
6274 if (!use_cache)
6275 delete [] matrix;
6276
6278}
6279
6280////////////////////////////////////////////////////////////////////////////////
6281/// Draw a circle.
6282/// If thick < 0 - draw filled circle
6283
6285{
6286 if (!InitImage("DrawCircle")) {
6287 return;
6288 }
6289
6290 thick = !thick ? 1 : thick;
6291 Int_t sz = thick*thick;
6292 CARD32 *matrix;
6294
6295 ARGB32 color = ARGB32_White;
6296 parse_argb_color(col, &color);
6297
6298///matrix = new CARD32[sz];
6299 if (use_cache) {
6301 } else {
6302 matrix = new CARD32[sz];
6303 }
6304
6305 for (int i = 0; i < sz; i++) {
6306 matrix[i] = (CARD32)color;
6307 }
6308
6310 brush.matrix = matrix;
6311 brush.height = brush.width = thick > 0 ? thick : 1;
6312 brush.center_y = brush.center_x = thick > 0 ? thick/2 : 0;
6313
6315 asim_circle(ctx, x, y, r, thick < 0);
6316
6317///free (matrix);
6318 if (!use_cache) {
6319 delete [] matrix;
6320 }
6322}
6323
6324////////////////////////////////////////////////////////////////////////////////
6325/// Draw an ellipse.
6326/// If thick < 0 - draw filled ellips
6327
6329 const char *col, Int_t thick)
6330{
6331 if (!InitImage("DrawEllips")) {
6332 return;
6333 }
6334 thick = !thick ? 1 : thick;
6335 Int_t sz = thick*thick;
6336 CARD32 *matrix;
6338
6339 ARGB32 color = ARGB32_White;
6340 parse_argb_color(col, &color);
6341
6342 if (use_cache) {
6344 } else {
6345 matrix = new CARD32[sz];
6346 }
6347
6348 for (int i = 0; i < sz; i++) {
6349 matrix[i] = (CARD32)color;
6350 }
6351
6353 brush.matrix = matrix;
6354 brush.width = thick > 0 ? thick : 1;
6355 brush.height = thick > 0 ? thick : 1;
6356 brush.center_y = brush.center_x = thick > 0 ? thick/2 : 0;
6357
6359 asim_ellips(ctx, x, y, rx, ry, angle, thick < 0);
6360
6361 if (!use_cache)
6362 delete [] matrix;
6363
6365}
6366
6367////////////////////////////////////////////////////////////////////////////////
6368/// Draw an ellipse.
6369/// If thick < 0 - draw filled ellipse.
6370
6372 const char *col, Int_t thick)
6373{
6374 if (!InitImage("DrawEllips2")) {
6375 return;
6376 }
6377 thick = !thick ? 1 : thick;
6378 Int_t sz = thick*thick;
6379 CARD32 *matrix;
6381
6382 ARGB32 color = ARGB32_White;
6383 parse_argb_color(col, &color);
6384
6385 if (use_cache) {
6387 } else {
6388 matrix = new CARD32[sz];
6389 }
6390
6391 for (int i = 0; i < sz; i++) {
6392 matrix[i] = (CARD32)color;
6393 }
6394
6396 brush.matrix = matrix;
6397 brush.width = thick > 0 ? thick : 1;
6398 brush.height = thick > 0 ? thick : 1;
6399 brush.center_y = brush.center_x = thick > 0 ? thick/2 : 0;
6400
6402 asim_ellips2(ctx, x, y, rx, ry, angle, thick < 0);
6403
6404 if (!use_cache) {
6405 delete [] matrix;
6406 }
6408}
6409
6410////////////////////////////////////////////////////////////////////////////////
6411/// Flood fill.
6412
6413void TASImage::FloodFill(Int_t /*x*/, Int_t /*y*/, const char * /*col*/,
6414 const char * /*minc*/, const char * /*maxc*/)
6415{
6416}
6417
6418////////////////////////////////////////////////////////////////////////////////
6419/// Convert RGB image to Gray image and vice versa.
6420
6422{
6423 if (fIsGray == on) {
6424 return;
6425 }
6426
6427 if (!IsValid()) {
6428 Warning("Gray", "Image not initiated");
6429 return;
6430 }
6431
6432 if (!InitVisual()) {
6433 Warning("Gray", "Visual not initiated");
6434 return;
6435 }
6436
6437 if (!fGrayImage && !on) {
6438 return;
6439 }
6440 ASImage *sav = nullptr;
6442
6443 if (fGrayImage) {
6444 sav = fImage;
6446 fGrayImage = sav;
6447 fIsGray = on;
6448 return;
6449 }
6450
6451 if (!on) return;
6452
6453 UInt_t l, r, g, b, idx;
6454 int y = 0;
6455 UInt_t i, j;
6456
6457 if (fImage->alt.argb32) {
6458 fGrayImage = tile_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height,
6460
6461 for (i = 0; i < fImage->height; i++) {
6462 for (j = 0; j < fImage->width; j++) {
6463 idx = Idx(y + j);
6464
6465 r = ((fImage->alt.argb32[idx] & 0xff0000) >> 16);
6466 g = ((fImage->alt.argb32[idx] & 0x00ff00) >> 8);
6467 b = (fImage->alt.argb32[idx] & 0x0000ff);
6468 l = (57*r + 181*g + 18*b)/256;
6469 fGrayImage->alt.argb32[idx] = (l << 16) + (l << 8) + l;
6470 }
6471 y += fImage->width;
6472 }
6473 } else {
6474 fGrayImage = create_asimage(fImage->width, fImage->height, 0);
6475
6477 0, 0, fImage->width, fImage->height, nullptr);
6478
6479 if (!imdec) {
6480 return;
6481 }
6482#ifdef HAVE_MMX
6483 mmx_init();
6484#endif
6487 if (!imout) {
6488 Warning("ToGray", "Failed to start image output");
6490 delete [] imdec;
6491 return;
6492 }
6493
6494 CARD32 *aa = imdec->buffer.alpha;
6495 CARD32 *rr = imdec->buffer.red;
6496 CARD32 *gg = imdec->buffer.green;
6497 CARD32 *bb = imdec->buffer.blue;
6498
6500 prepare_scanline(fImage->width, 0, &result, fgVisual->BGR_mode);
6501
6502 for (i = 0; i < fImage->height; i++) {
6503 imdec->decode_image_scanline(imdec);
6504 result.flags = imdec->buffer.flags;
6505 result.back_color = imdec->buffer.back_color;
6506
6507 for (j = 0; j < fImage->width; j++) {
6508 l = (57*rr[j] + 181*gg[j]+ 18*bb[j])/256;
6509 result.alpha[j] = aa[j];
6510 result.red[j] = l;
6511 result.green[j] = l;
6512 result.blue[j] = l;
6513 }
6514 imout->output_image_scanline(imout, &result, 1);
6515 }
6516
6519#ifdef HAVE_MMX
6520 mmx_off();
6521#endif
6522 }
6523
6524 sav = fImage;
6526 fGrayImage = sav;
6527 fIsGray = kTRUE;
6528}
6529
6530////////////////////////////////////////////////////////////////////////////////
6531/// Create an image (screenshot) from specified window.
6532
6534{
6535 Int_t xy;
6536
6537 x = x < 0 ? 0 : x;
6538 y = y < 0 ? 0 : y;
6539
6540 // X11 Synchronization
6541 gVirtualX->Update(1);
6542 if (!gThreadXAR) {
6543 gSystem->Sleep(10);
6545 gSystem->Sleep(10);
6547 }
6548
6549 if (!w || !h) {
6550 gVirtualX->GetWindowSize(wid, xy, xy, w, h);
6551 }
6552
6553 if ((x >= (Int_t)w) || (y >= (Int_t)h)) {
6554 return;
6555 }
6556
6557 if (!InitVisual()) {
6558 Warning("FromWindow", "Visual not initiated");
6559 return;
6560 }
6561
6562 DestroyImage();
6564
6565 static int x11 = -1;
6566 if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11");
6567
6568 if (x11) { //use built-in optimized version
6569 fImage = pixmap2asimage(fgVisual, wid, x, y, w, h, kAllPlanes, 0, 0);
6570 } else {
6571 unsigned char *bits = gVirtualX->GetColorBits(wid, 0, 0, w, h);
6572
6573 if (!bits) { // error
6574 return;
6575 }
6576 fImage = bitmap2asimage(bits, w, h, 0, nullptr);
6577 delete [] bits;
6578 }
6579}
6580
6581////////////////////////////////////////////////////////////////////////////////
6582/// Creates an image (screenshot) from a RGBA buffer.
6583
6585{
6586 DestroyImage();
6588
6589 UChar_t* xx = new UChar_t[4*w];
6590 for (UInt_t i = 0; i < h/2; ++i) {
6591 memcpy(xx, buf + 4*w*i, 4*w);
6592 memcpy(buf + 4*w*i, buf + 4*w*(h-i-1), 4*w);
6593 memcpy(buf + 4*w*(h-i-1), xx, 4*w);
6594 }
6595 delete [] xx;
6596
6597 fImage = bitmap2asimage(buf, w, h, 0, nullptr);
6598}
6599
6600////////////////////////////////////////////////////////////////////////////////
6601/// Switch on/off the image palette.
6602/// That also invokes calling vectorization of image.
6603
6605{
6606 if (!fImage) {
6607 return;
6608 }
6609
6610 if (!fImage->alt.vector && on) {
6611 Vectorize();
6612 }
6614
6615 if (on) {
6616 Double_t left = gPad->GetLeftMargin();
6617 Double_t right = gPad->GetRightMargin();
6618 Double_t top = gPad->GetTopMargin();
6619 Double_t bottom = gPad->GetBottomMargin();
6620
6621 gPad->Range(-left / (1.0 - left - right),
6622 -bottom / (1.0 - top - bottom),
6623 1 + right / (1.0 - left - right),
6624 1 + top / ( 1.0 - top - bottom));
6625 gPad->RangeAxis(0, 0, 1, 1);
6626 }
6627
6628}
6629
6630////////////////////////////////////////////////////////////////////////////////
6631/// Save a primitive as a C++ statement(s) on output stream "out".
6632
6633void TASImage::SavePrimitive(std::ostream &out, Option_t * /*= ""*/)
6634{
6635 char *buf = nullptr;
6636 int sz;
6638 TString str = buf;
6639 free(buf);
6640
6641 str.ReplaceAll("static", "const");
6642 static int ii = 0;
6643
6644 TString xpm = TString::Format("asimage_xpm_%d", ii++);
6645 str.ReplaceAll("asxpm", xpm.Data());
6646 out << "\n" << str << "\n\n";
6647
6648 out << " ";
6649 if (!gROOT->ClassSaved(TImage::Class()))
6650 out << TImage::Class()->GetName() << " *";
6651 out << "asimage = TImage::Create();\n";
6652 out << " asimage->SetImageBuffer( (char **)" << xpm << ", TImage::kXpm);\n";
6653 SaveImageAttributes(out, "asimage");
6654 out << " asimage->Draw();\n";
6655}
6656
6657////////////////////////////////////////////////////////////////////////////////
6658/// Set an image printing resolution in Dots Per Inch units.
6659///
6660/// \param[in] name - the name of jpeg file.
6661/// \param[in] set - dpi resolution.
6662///
6663/// Returns kFALSE in case of error.
6664
6666{
6667 static char buf[32];
6668 FILE *fp = fopen(name, "rb+");
6669
6670 if (!fp) {
6671 printf("file %s : failed to open\n", name);
6672 return kFALSE;
6673 }
6674
6675 if (!fread(buf, 1, 20, fp)) {
6676 fclose(fp);
6677 return kFALSE;
6678 }
6679
6680 char dpi1 = (set & 0xffff) >> 8;
6681 char dpi2 = set & 0xff;
6682
6683 int i = 0;
6684
6685 int dpi = 0; // start of dpi data
6686 for (i = 0; i < 20; i++) {
6687 if ((buf[i] == 0x4a) && (buf[i+1] == 0x46) && (buf[i+2] == 0x49) &&
6688 (buf[i+3] == 0x46) && (buf[i+4] == 0x00) ) {
6689 dpi = i + 7;
6690 break;
6691 }
6692 }
6693
6694 if (i == 20 || dpi+4 >= 20) { // jpeg maker was not found
6695 fclose(fp);
6696 printf("file %s : wrong JPEG format\n", name);
6697 return kFALSE;
6698 }
6699
6700 buf[dpi] = 1; // format specified in dots per inch
6701
6702 // set x density in dpi units
6703 buf[dpi + 1] = dpi1;
6704 buf[dpi + 2] = dpi2;
6705
6706 // set y density in dpi units
6707 buf[dpi + 3] = dpi1;
6708 buf[dpi + 4] = dpi2;
6709
6710 rewind(fp);
6711 fwrite(buf, 1, 20, fp);
6712 fclose(fp);
6713
6714 return kTRUE;
6715}
6716
6717////////////////////////////////////////////////////////////////////////////////
6718/// Return a valid index in fImage tables to avoid seg-fault by accessing out of
6719/// indices out of array's ranges.
6720
6722{
6723 // The size of arrays like fImage->alt.argb32 is fImage->width*fImage->height
6724 return TMath::Max(0, TMath::Min(idx,(Int_t)(fImage->width*fImage->height)));
6725}
@ kButton1Motion
Definition Buttons.h:20
@ kButton1Up
Definition Buttons.h:19
@ kButton1Down
Definition Buttons.h:17
@ kCross
Definition GuiTypes.h:375
Handle_t Pixmap_t
Pixmap handle.
Definition GuiTypes.h:31
const Mask_t kGCClipXOrigin
Definition GuiTypes.h:304
Handle_t Window_t
Window handle.
Definition GuiTypes.h:29
EGraphicsFunction
Definition GuiTypes.h:68
@ kGXorReverse
src OR NOT dst
Definition GuiTypes.h:80
@ kGXnand
NOT src OR NOT dst.
Definition GuiTypes.h:83
@ kGXandReverse
src AND NOT dst
Definition GuiTypes.h:71
@ kGXor
src OR dst
Definition GuiTypes.h:76
@ kGXcopy
src
Definition GuiTypes.h:72
@ kGXorInverted
NOT src OR dst.
Definition GuiTypes.h:82
@ kGXandInverted
NOT src AND dst.
Definition GuiTypes.h:73
@ kGXequiv
NOT src XOR dst.
Definition GuiTypes.h:78
@ kGXset
1
Definition GuiTypes.h:84
@ kGXnor
NOT src AND NOT dst.
Definition GuiTypes.h:77
@ kGXnoop
dst
Definition GuiTypes.h:74
@ kGXinvert
NOT dst.
Definition GuiTypes.h:79
@ kGXxor
src XOR dst
Definition GuiTypes.h:75
@ kGXand
src AND dst
Definition GuiTypes.h:70
@ kGXclear
0
Definition GuiTypes.h:69
@ kGXcopyInverted
NOT src.
Definition GuiTypes.h:81
Handle_t GContext_t
Graphics context handle.
Definition GuiTypes.h:39
Handle_t Drawable_t
Drawable handle.
Definition GuiTypes.h:32
const Handle_t kNone
Definition GuiTypes.h:89
const Mask_t kGCClipYOrigin
Definition GuiTypes.h:305
const Mask_t kGCClipMask
Definition GuiTypes.h:306
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define c(i)
Definition RSha256.hxx:101
#define g(i)
Definition RSha256.hxx:105
#define a(i)
Definition RSha256.hxx:99
#define h(i)
Definition RSha256.hxx:106
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
bool Bool_t
Boolean (0=false, 1=true) (bool)
Definition RtypesCore.h:77
unsigned short UShort_t
Unsigned Short integer 2 bytes (unsigned short)
Definition RtypesCore.h:54
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:59
short Version_t
Class version identifier (short)
Definition RtypesCore.h:79
unsigned char UChar_t
Unsigned Character 1 byte (unsigned char)
Definition RtypesCore.h:52
int Ssiz_t
String size (currently int)
Definition RtypesCore.h:81
unsigned long ULong_t
Unsigned long integer 4 bytes (unsigned long). Size depends on architecture.
Definition RtypesCore.h:69
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:68
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int)
Definition RtypesCore.h:60
float Float_t
Float 4 bytes (float)
Definition RtypesCore.h:71
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
double Double_t
Double 8 bytes.
Definition RtypesCore.h:73
constexpr Ssiz_t kNPOS
The equivalent of std::string::npos for the ROOT class TString.
Definition RtypesCore.h:131
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
const char Option_t
Option string (const char)
Definition RtypesCore.h:80
#define BIT(n)
Definition Rtypes.h:91
#define SETBIT(n, i)
Definition Rtypes.h:92
#define CLRBIT(n, i)
Definition Rtypes.h:93
static ARGB32 GetShadow(ARGB32 background)
Calculate shadow color.
static const UInt_t kBrushCacheSize
static CARD32 gBrushCache[kBrushCacheSize *kBrushCacheSize]
const Float_t kScale
Definition TASImage.cxx:135
static unsigned long kAllPlanes
Definition TASImage.cxx:128
static ARGB32 GetAverage(ARGB32 foreground, ARGB32 background)
Get average.
static char * gIconPaths[7]
Definition TASImage.cxx:132
static int GetPolyYBounds(TPoint *pts, int n, int *by, int *ty)
Get poly bounds along Y.
static CARD8 MakeComponentHilite(int cmp)
Make component hilite.
static ARGB32 GetHilite(ARGB32 background)
Calculate highlite color.
static const UInt_t NUMPTSTOBUFFER
static ASFontManager * gFontManager
Definition TASImage.cxx:127
static void init_icon_paths()
Set icons paths.
Definition TASImage.cxx:376
#define _MEMSET_(dst, lng, val)
#define FillSpansInternal(npt, ppt, widths, color)
static ASDrawContext * create_draw_context_argb32(ASImage *im, ASDrawTool *brush)
Create draw context.
#define _alphaBlend(bot, top)
Definition TASImage.cxx:161
static void destroy_asdraw_context32(ASDrawContext *ctx)
Destroy asdraw context32.
#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
static int InsertionSort(EdgeTableEntry *AET)
#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2)
static void loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
static void FreeStorage(ScanLineListBlock *pSLLBlock)
static void CreateETandAET(int count, TPoint *pts, EdgeTable *ET, EdgeTableEntry *AET, EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
#define BRESINCRPGON(d, minval, m, m1, incr1, incr2)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define gDirectory
Definition TDirectory.h:385
R__EXTERN TEnv * gEnv
Definition TEnv.h:126
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t mask
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void cmap
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t del
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void pixel
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize wid
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void on
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void foreground
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char FillPolygon
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char bitmap
Option_t Option_t TPoint TPoint const char x2
Option_t Option_t TPoint TPoint const char x1
Option_t Option_t TPoint TPoint angle
Option_t Option_t TPoint xy
Option_t Option_t TPoint TPoint const char mode
Option_t Option_t TPoint TPoint const char y2
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t FillRectangle
Option_t Option_t width
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void pxm
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t height
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void gc
Option_t Option_t TPoint TPoint const char text
Option_t Option_t TPoint TPoint const char y1
char name[80]
Definition TGX11.cxx:148
XID Colormap
Definition TGX11.h:37
#define hi
float * q
float ymin
float ymax
#define gROOT
Definition TROOT.h:417
R__EXTERN TRandom * gRandom
Definition TRandom.h:62
R__EXTERN TStyle * gStyle
Definition TStyle.h:442
R__EXTERN const char * gProgName
Definition TSystem.h:252
@ kReadPermission
Definition TSystem.h:55
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
R__EXTERN TVirtualPS * gVirtualPS
Definition TVirtualPS.h:88
#define gPad
R__EXTERN Int_t(* gThreadXAR)(const char *xact, Int_t nb, void **ar, Int_t *iret)
#define gVirtualX
Definition TVirtualX.h:377
Color * colors
Definition X3DBuffer.c:21
#define free
Definition civetweb.c:1578
#define snprintf
Definition civetweb.c:1579
#define malloc
Definition civetweb.c:1575
static TClass * Class()
Image class.
Definition TASImage.h:31
void CropSpans(UInt_t npt, TPoint *ppt, UInt_t *widths) override
Crop spans.
void Gradient(UInt_t angle=0, const char *colors="#FFFFFF #000000", const char *offsets=nullptr, Int_t x=0, Int_t y=0, UInt_t width=0, UInt_t height=0) override
Render multipoint gradient inside rectangle of size (width, height) at position (x,...
void Blur(Double_t hr=3, Double_t vr=3) override
Perform Gaussian blur of the image (useful for drop shadows).
Bool_t SetJpegDpi(const char *name, UInt_t dpi=72)
Set an image printing resolution in Dots Per Inch units.
void StartPaletteEditor() override
Start palette editor.
void Bevel(Int_t x=0, Int_t y=0, UInt_t width=0, UInt_t height=0, const char *hi="#ffdddddd", const char *lo="#ff555555", UShort_t thick=1, Bool_t pressed=kFALSE) override
Bevel is used to create 3D effect while drawing buttons, or any other image that needs to be framed.
void DrawLineInternal(UInt_t x1, UInt_t y1, UInt_t x2, UInt_t y2, UInt_t col, UInt_t thick)
Internal line drawing.
Int_t fPaintMode
! 1 - fast mode, 0 - low memory slow mode
Definition TASImage.h:68
static Bool_t fgBatch
global flag to signal if batch mode is active ie fgVisual->dpy was set to nullptr
Definition TASImage.h:75
UInt_t GetWidth() const override
Return width of original image not of the displayed image.
Double_t fMinValue
! min value in image
Definition TASImage.h:61
UInt_t GetScaledWidth() const
Return width of the displayed image not of the original image.
void DrawEllips(Int_t x, Int_t y, Int_t rx, Int_t ry, Int_t angle, const char *col="#000000", Int_t thick=1) override
Draw an ellipse.
void Paint(Option_t *option="") override
Paint image.
void DrawHLine(UInt_t y, UInt_t x1, UInt_t x2, UInt_t col, UInt_t thick)
Draw an horizontal line.
void SetPaletteEnabled(Bool_t on=kTRUE) override
Switch on/off the image palette.
Bool_t InitImage(const char *caller)
Static function to initialize the image.
static Bool_t fgInit
global flag to init afterimage only once
Definition TASImage.h:74
const char * GetTitle() const override
Title is used to keep 32x32 xpm image's thumbnail.
void FromGLBuffer(UChar_t *buf, UInt_t w, UInt_t h) override
Creates an image (screenshot) from a RGBA buffer.
void HSV(UInt_t hue=0, UInt_t radius=360, Int_t H=0, Int_t S=0, Int_t V=0, Int_t x=0, Int_t y=0, UInt_t width=0, UInt_t height=0) override
This function will tile original image to specified size with offsets requested, and then it will go ...
void Tile(UInt_t width, UInt_t height) override
Tile the original image.
void WriteImage(const char *file, EImageFileTypes type=TImage::kUnknown) override
Write image to specified file.
Definition TASImage.cxx:663
Int_t DistancetoPrimitive(Int_t px, Int_t py) override
Is the mouse in the image ?
char * GetObjectInfo(Int_t px, Int_t py) const override
Get image pixel coordinates and the pixel value at the mouse pointer.
const char * TypeFromMagicNumber(const char *file)
Guess the file type from the first byte of file.
Definition TASImage.cxx:410
void DrawLine(UInt_t x1, UInt_t y1, UInt_t x2, UInt_t y2, const char *col="#000000", UInt_t thick=1) override
Draw a line.
Double_t fMaxValue
! max value in image
Definition TASImage.h:60
void MapQuality(EImageQuality &quality, UInt_t &asquality, Bool_t toas=kTRUE)
Map quality to/from AfterImage quality.
Definition TASImage.cxx:963
void Zoom(UInt_t offX, UInt_t offY, UInt_t width, UInt_t height) override
The area of an image displayed in a pad is defined by this function.
UInt_t fZoomWidth
! width of zoomed image in image pixels
Definition TASImage.h:64
Bool_t fEditable
! kTRUE image can be resized, moved by resizing/moving gPad
Definition TASImage.h:67
Int_t fZoomUpdate
! kZoom - new zooming required, kZoomOps - other ops in action, kNoZoom - no zooming or ops
Definition TASImage.h:66
Bool_t IsValid() const override
Definition TASImage.h:188
TClass * IsA() const override
Definition TASImage.h:215
void DrawCubeBezier(Int_t x1, Int_t y1, Int_t x2, Int_t y2, Int_t x3, Int_t y3, const char *col="#000000", UInt_t thick=1) override
Draw a cubic bezier line.
void DrawFillArea(UInt_t npt, TPoint *ppt, const char *col="#000000", const char *stipple=nullptr, UInt_t w=16, UInt_t h=16) override
Fill a polygon (any type convex, non-convex).
void DrawVLine(UInt_t x, UInt_t y1, UInt_t y2, UInt_t col, UInt_t thick)
Draw a vertical line.
UInt_t * GetRgbaArray() override
Return a pointer to an array[width x height] of RGBA32 values.
void FillRectangle(const char *col=nullptr, Int_t x=0, Int_t y=0, UInt_t width=0, UInt_t height=0) override
Fill rectangle of size (width, height) at position (x,y) within the existing image with specified col...
void DrawStraightEllips(Int_t x, Int_t y, Int_t rx, Int_t ry, const char *col="#000000", Int_t thick=1) override
Draw a straight ellipse.
Double_t * GetVecArray() override
Return a pointer to internal array[width x height] of double values [0,1].
void DrawCircle(Int_t x, Int_t y, Int_t r, const char *col="#000000", Int_t thick=1) override
Draw a circle.
ASImage * fImage
! pointer to image structure of original image
Definition TASImage.h:58
void Gray(Bool_t on=kTRUE) override
Convert RGB image to Gray image and vice versa.
void DrawText(Int_t x=0, Int_t y=0, const char *text="", Int_t size=12, const char *color=nullptr, const char *font="fixed", EText3DType type=TImage::kPlain, const char *fore_file=nullptr, Float_t angle=0) override
Draw text of size (in pixels for TrueType fonts) at position (x, y) with color specified by hex strin...
UInt_t fZoomHeight
! hight of zoomed image in image pixels
Definition TASImage.h:65
void Pad(const char *color="#00FFFFFF", UInt_t left=0, UInt_t right=0, UInt_t top=0, UInt_t bottom=0) override
Enlarge image, padding it with specified color on each side in accordance with requested geometry.
static THashTable * fgPlugList
! hash table containing loaded plugins
Definition TASImage.h:71
UInt_t * GetArgbArray() override
Return a pointer to internal array[width x height] of ARGB32 values This array is directly accessible...
Bool_t SetImageBuffer(char **buffer, EImageFileTypes type=TImage::kPng) override
Create image from compressed buffer.
Double_t * Vectorize(UInt_t max_colors=256, UInt_t dither=4, Int_t opaque_threshold=1) override
Reduce color-depth of an image and fills vector of "scientific data" [0...1].
Int_t Idx(Int_t idx)
Return a valid index in fImage tables to avoid seg-fault by accessing out of indices out of array's r...
void FillPolygon(UInt_t npt, TPoint *ppt, const char *col="#000000", const char *stipple=nullptr, UInt_t w=16, UInt_t h=16) override
Fill a convex polygon with background color or bitmap.
void SetDefaults()
Set default parameters.
Definition TASImage.cxx:209
void CopyArea(TImage *dst, Int_t xsrc, Int_t ysrc, UInt_t w, UInt_t h, Int_t xdst=0, Int_t ydst=0, Int_t gfunc=3, EColorChan chan=kAllChan) override
Copy source region to the destination image.
void DrawWideLine(UInt_t x1, UInt_t y1, UInt_t x2, UInt_t y2, UInt_t col, UInt_t thick)
Draw wide line.
Pixmap_t GetMask() override
Returns image mask pixmap (alpha channel).
UInt_t * GetScanline(UInt_t y) override
Return a pointer to scan-line.
void FillSpans(UInt_t npt, TPoint *ppt, UInt_t *widths, const char *col="#000000", const char *stipple=nullptr, UInt_t w=16, UInt_t h=16) override
Fill spans with specified color or/and stipple.
void DrawEllips2(Int_t x, Int_t y, Int_t rx, Int_t ry, Int_t angle, const char *col="#000000", Int_t thick=1) override
Draw an ellipse.
TObject * Clone(const char *newname="") const override
Clone image.
void Draw(Option_t *option="") override
Draw image.
void CropPolygon(UInt_t npt, TPoint *ppt) override
Crop a convex polygon.
static const ASVisual * GetVisual()
Return visual.
void DrawPolyLine(UInt_t nn, TPoint *xy, const char *col="#000000", UInt_t thick=1, TImage::ECoordMode mode=kCoordModeOrigin) override
Draw a polyline.
void PolyPoint(UInt_t npt, TPoint *ppt, const char *col="#000000", TImage::ECoordMode mode=kCoordModeOrigin) override
Draw a poly point.
static void Image2Drawable(ASImage *im, 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="")
Draw asimage on drawable.
void Merge(const TImage *im, const char *op="alphablend", Int_t x=0, Int_t y=0) override
Merge two images.
void DrawCellArray(Int_t x1, Int_t y1, Int_t x2, Int_t y2, Int_t nx, Int_t ny, UInt_t *ic) override
Draw a cell array.
void FillRectangleInternal(UInt_t col, Int_t x, Int_t y, UInt_t width, UInt_t height)
Fill rectangle of size (width, height) at position (x,y) within the existing image with specified col...
~TASImage() override
Image destructor, clean up image and visual.
Definition TASImage.cxx:367
void FloodFill(Int_t x, Int_t y, const char *col, const char *min_col, const char *max_col=nullptr) override
Flood fill.
TASImage * fScaledImage
! temporary scaled and zoomed image produced from original image
Definition TASImage.h:59
Bool_t IsEditable() const override
Definition TASImage.h:98
void DrawFTGlyph(void *bitmap, UInt_t color, Int_t x, Int_t y, TVirtualPad *clippad=nullptr, Int_t offx=0, Int_t offy=0)
Draw glyph bitmap.
UInt_t fZoomOffX
! X - offset for zooming in image pixels
Definition TASImage.h:62
void ReadImage(const char *file, EImageFileTypes type=TImage::kUnknown) override
Read specified image file.
Definition TASImage.cxx:495
void GetImageBuffer(char **buffer, int *size, EImageFileTypes type=TImage::kPng) override
Return in-memory buffer compressed according image type.
EImageFileTypes GetFileType(const char *ext)
Return file type depending on specified extension.
Definition TASImage.cxx:834
void Slice(UInt_t xStart, UInt_t xEnd, UInt_t yStart, UInt_t yEnd, UInt_t toWidth, UInt_t toHeight) override
Another method of enlarging images where corners remain unchanged, but middle part gets tiled.
static UInt_t AlphaBlend(UInt_t bot, UInt_t top)
Return alpha-blended value computed from bottom and top pixel values.
void SetImage(const Double_t *imageData, UInt_t width, UInt_t height, TImagePalette *palette=nullptr) override
Deletes the old image and creates a new image depending on the values of imageData.
void DrawTextTTF(Int_t x, Int_t y, const char *text, Int_t size, UInt_t color, const char *font_name, Float_t angle)
Draw text using TrueType fonts.
void PutPixel(Int_t x, Int_t y, const char *col="#000000") override
Draw a point at the specified position.
void Browse(TBrowser *) override
Browse image.
void DrawDashZTLine(UInt_t x1, UInt_t y1, UInt_t x2, UInt_t y2, UInt_t nDash, const char *pDash, UInt_t col, UInt_t thick)
Draw a dashed line with thick pixel width.
void DrawTextOnPad(TText *text, Int_t x=0, Int_t y=0, TVirtualPad *pad=nullptr, Int_t offx=0, Int_t offy=0) override
Draw text at the pixel position (x,y) checking clip on pad.
void DestroyImage()
Destroy image.
Definition TASImage.cxx:179
static Bool_t InitVisual()
Static function to initialize the ASVisual.
UInt_t fZoomOffY
! Y - offset for zooming im image pixels
Definition TASImage.h:63
void UnZoom() override
Un-zoom the image to original size.
void Streamer(TBuffer &) override
Streamer for ROOT I/O.
TArrayL * GetPixels(Int_t x=0, Int_t y=0, UInt_t w=0, UInt_t h=0) override
Return 2D array of machine dependent pixel values.
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="") override
Draw image on the drawable wid (pixmap, window) at x,y position.
void DestroyScaledImage()
Destroy scaled image.
Definition TASImage.cxx:197
ASImage * fGrayImage
! gray image
Definition TASImage.h:69
void DrawDashVLine(UInt_t x, UInt_t y1, UInt_t y2, UInt_t nDash, const char *pDash, UInt_t col, UInt_t thick)
Draw a dashed vertical line.
void SetTitle(const char *title="") override
Set a title for an image.
void MapFileTypes(EImageFileTypes &type, UInt_t &astype, Bool_t toas=kTRUE)
Map file type to/from AfterImage types.
Definition TASImage.cxx:878
void DrawRectangle(UInt_t x, UInt_t y, UInt_t w, UInt_t h, const char *col="#000000", UInt_t thick=1) override
Draw a rectangle.
void Append(const TImage *im, const char *option="+", const char *color="#00000000") override
Append image.
void DrawDashHLine(UInt_t y, UInt_t x1, UInt_t x2, UInt_t nDash, const char *pDash, UInt_t col, UInt_t thick)
Draw a dashed horizontal line.
void DrawDashLine(UInt_t x1, UInt_t y1, UInt_t x2, UInt_t y2, UInt_t nDash, const char *pDash, const char *col="#000000", UInt_t thick=1) override
Draw a dashed line.
@ kNoZoom
Definition TASImage.h:34
@ kZoomOps
Definition TASImage.h:34
void SetPalette(const TImagePalette *palette) override
Set a new palette to an image.
void Scale(UInt_t width, UInt_t height) override
Scale the original image.
TASImage()
Default image constructor.
Definition TASImage.cxx:236
TASImage & operator=(const TASImage &img)
Image assignment operator.
Definition TASImage.cxx:333
void Mirror(Bool_t vert=kTRUE) override
Mirror image in place.
void DrawDashZLine(UInt_t x1, UInt_t y1, UInt_t x2, UInt_t y2, UInt_t nDash, const char *pDash, UInt_t col)
Draw a dashed line with one pixel width.
void DrawSegments(UInt_t nseg, Segment_t *seg, const char *col="#000000", UInt_t thick=1) override
Draw segments.
Pixmap_t GetPixmap() override
Returns image pixmap.
void FromWindow(Drawable_t wid, Int_t x=0, Int_t y=0, UInt_t w=0, UInt_t h=0) override
Create an image (screenshot) from specified window.
TArrayD * GetArray(UInt_t w=0, UInt_t h=0, TImagePalette *pal=gWebImagePalette) override
In case of vectorized image return an associated array of doubles otherwise this method creates and r...
void Flip(Int_t flip=180) override
Flip image in place.
Bool_t GetPolygonSpans(UInt_t npt, TPoint *ppt, UInt_t *nspans, TPoint **firstPoint, UInt_t **firstWidth)
The code is based on Xserver/mi/mipolycon.c "Copyright 1987, 1998 The Open Group".
void Crop(Int_t x=0, Int_t y=0, UInt_t width=0, UInt_t height=0) override
Crop an image.
void EndPaint() override
EndPaint does internal RLE compression of image data.
void BeginPaint(Bool_t fast=kTRUE) override
BeginPaint initializes internal array[width x height] of ARGB32 pixel values.
static ASVisual * fgVisual
pointer to visual structure
Definition TASImage.h:73
void GetZoomPosition(UInt_t &x, UInt_t &y, UInt_t &w, UInt_t &h) const
Return the zoom parameters.
void SavePrimitive(std::ostream &out, Option_t *option="") override
Save a primitive as a C++ statement(s) on output stream "out".
UInt_t GetScaledHeight() const
Return height of the displayed image not of the original image.
void ExecuteEvent(Int_t event, Int_t px, Int_t py) override
Execute mouse events.
void FromPad(TVirtualPad *pad, Int_t x=0, Int_t y=0, UInt_t w=0, UInt_t h=0) override
Create an image from the given pad, afterwards this image can be saved in any of the supported image ...
UInt_t GetHeight() const override
Return height of original image not of the displayed image.
void DrawBox(Int_t x1, Int_t y1, Int_t x2, Int_t y2, const char *col="#000000", UInt_t thick=1, Int_t mode=0) override
Draw a box.
Bool_t fIsGray
! kTRUE if image is gray
Definition TASImage.h:70
void CreateThumbnail()
Create image thumbnail.
Array of doubles (64 bits per element).
Definition TArrayD.h:27
Array of longs (32 or 64 bits per element).
Definition TArrayL.h:27
virtual void SetFillColor(Color_t fcolor)
Set the fill area color.
Definition TAttFill.h:40
virtual void SetPalette(const TImagePalette *palette)
Set a new palette for the image.
Bool_t fConstRatio
keep aspect ratio of image on the screen
Definition TAttImage.h:74
EImageQuality GetImageQuality() const
Definition TAttImage.h:87
Bool_t GetConstRatio() const
Definition TAttImage.h:85
virtual const TImagePalette & GetPalette() const
Definition TAttImage.h:88
@ kImgDefault
Definition TAttImage.h:64
TImagePalette fPalette
color palette for value -> color conversion
Definition TAttImage.h:75
virtual void Streamer(TBuffer &)
UInt_t GetImageCompression() const
Definition TAttImage.h:86
Bool_t fPaletteEnabled
! kTRUE - palette is drawn on the image
Definition TAttImage.h:77
virtual void SaveImageAttributes(std::ostream &out, const char *name, EImageQuality qualdef=kImgPoor, UInt_t comprdef=0, Bool_t constRatiodef=kTRUE)
Save image attributes as C++ statement(s) on output stream, but not the palette.
virtual void StartPaletteEditor()
Opens a GUI to edit the color palette.
virtual void SetLineColor(Color_t lcolor)
Set the line color.
Definition TAttLine.h:44
Using a TBrowser one can browse all ROOT objects.
Definition TBrowser.h:37
Buffer base class used for serializing objects.
Definition TBuffer.h:43
The color creation and management class.
Definition TColor.h:22
static ULong_t RGB2Pixel(Int_t r, Int_t g, Int_t b)
Convert r,g,b to graphics system dependent pixel value.
Definition TColor.cxx:2483
static Int_t GetColor(const char *hexcolor)
Static method returning color number for color specified by hex color string of form: "#rrggbb",...
Definition TColor.cxx:1926
const char * AsHexString() const
Return color as hexadecimal string.
Definition TColor.cxx:1330
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition TEnv.cxx:511
Define a Frame.
Definition TFrame.h:19
void Draw(Option_t *option="") override
Draw this frame with its current attributes.
Definition TFrame.cxx:66
The axis painter class.
Definition TGaxis.h:26
virtual void PaintAxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax, Double_t &wmin, Double_t &wmax, Int_t &ndiv, Option_t *chopt="", Double_t gridlength=0, Bool_t drawGridOnly=kFALSE)
Control function to draw an axis.
Definition TGaxis.cxx:1007
THashTable implements a hash table to store TObject's.
Definition THashTable.h:35
Save canvas as an image (GIF, JPEG, PNG, XPM, TIFF etc.).
Definition TImageDump.h:22
A class to define a conversion from pixel values to pixel color.
Definition TAttImage.h:33
An abstract interface to image processing library.
Definition TImage.h:29
void Streamer(TBuffer &) override
Stream an object of class TObject.
EColorChan
Definition TImage.h:90
ECoordMode
Definition TImage.h:85
@ kCoordModePrevious
Definition TImage.h:87
@ kCoordModeOrigin
Definition TImage.h:86
EImageFileTypes
Definition TImage.h:36
@ kBmp
Definition TImage.h:45
@ kPng
Definition TImage.h:40
@ kJpeg
Definition TImage.h:41
@ kXcf
Definition TImage.h:42
@ kPnm
Definition TImage.h:44
@ kIco
Definition TImage.h:46
@ kXml
Definition TImage.h:53
@ kXpm
Definition TImage.h:37
@ kPpm
Definition TImage.h:43
@ kTga
Definition TImage.h:52
@ kAnimGif
Definition TImage.h:55
@ kZCompressedXpm
Definition TImage.h:38
@ kUnknown
Definition TImage.h:54
@ kXbm
Definition TImage.h:50
@ kCur
Definition TImage.h:47
@ kTiff
Definition TImage.h:49
@ kGZCompressedXpm
Definition TImage.h:39
@ kGif
Definition TImage.h:48
static TImage * Create()
Create an image.
Definition TImage.cxx:34
TImage & operator=(const TImage &img)
Definition TImage.h:104
virtual void Merge(const TImage *, const char *="alphablend", Int_t=0, Int_t=0)
Definition TImage.h:172
static TClass * Class()
EText3DType
Definition TImage.h:58
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
void Streamer(TBuffer &) override
Stream an object of class TObject.
TString fTitle
Definition TNamed.h:33
TString fName
Definition TNamed.h:32
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition TNamed.cxx:149
Mother of all ROOT objects.
Definition TObject.h:42
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1084
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:888
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1098
virtual void Draw(Option_t *option="")
Default Draw method for all objects.
Definition TObject.cxx:293
Longptr_t ExecPlugin(int nargs)
Int_t LoadPlugin()
Load the plugin library for this handler.
SCoord_t GetY() const
Definition TPoint.h:47
SCoord_t GetX() const
Definition TPoint.h:46
static const TString & GetTTFFontDir()
Get the fonts directory in the installation. Static utility function.
Definition TROOT.cxx:3507
static const TString & GetIconPath()
Get the icon path in the installation. Static utility function.
Definition TROOT.cxx:3486
virtual UInt_t Integer(UInt_t imax)
Returns a random integer uniformly distributed on the interval [ 0, imax-1 ].
Definition TRandom.cxx:360
Basic string class.
Definition TString.h:138
void ToLower()
Change string to lower-case.
Definition TString.cxx:1189
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition TString.cxx:1170
TString & Replace(Ssiz_t pos, Ssiz_t n, const char *s)
Definition TString.h:703
const char * Data() const
Definition TString.h:384
Bool_t IsNull() const
Definition TString.h:422
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2385
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2363
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:641
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:660
Float_t GetScreenFactor() const
Definition TStyle.h:258
Float_t GetImageScaling() const
Definition TStyle.h:241
virtual Bool_t ExpandPathName(TString &path)
Expand a pathname getting rid of special shell characters like ~.
Definition TSystem.cxx:1289
virtual const char * FindFile(const char *search, TString &file, EAccessMode mode=kFileExists)
Find location of file in a search path.
Definition TSystem.cxx:1553
virtual const char * PrependPathName(const char *dir, TString &name)
Concatenate a directory and a file name.
Definition TSystem.cxx:1096
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition TSystem.cxx:948
virtual void Sleep(UInt_t milliSec)
Sleep milliSec milli seconds.
Definition TSystem.cxx:439
virtual const char * HomeDirectory(const char *userName=nullptr)
Return the user's home directory.
Definition TSystem.cxx:901
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition TSystem.cxx:418
Dynamic handle to work with freetype 2 library.
Definition TTF.h:119
Base class for several text objects.
Definition TText.h:22
TVirtualPS is an abstract interface to Postscript, PDF, SVG.
Definition TVirtualPS.h:30
virtual void * GetStream() const
Definition TVirtualPS.h:78
virtual void Open(const char *filename, Int_t type=-111)=0
To make it possible to use GL for 2D graphic in a TPad/TCanvas.
small helper class to store/restore gPad context in TPad methods
Definition TVirtualPad.h:61
TVirtualPad is an abstract base class for the Pad and Canvas classes.
Definition TVirtualPad.h:51
virtual void SetBorderMode(Short_t bordermode)
Definition TWbox.h:54
TPaveText * pt
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
#define H(x, y, z)
Int_t Nint(T x)
Round to nearest integer. Rounds half integers to the nearest even integer.
Definition TMath.h:704
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Definition TMathBase.h:249
Double_t ATan2(Double_t y, Double_t x)
Returns the principal value of the arc tangent of y/x, expressed in radians.
Definition TMath.h:657
Short_t Min(Short_t a, Short_t b)
Returns the smallest of a and b.
Definition TMathBase.h:197
Double_t Cos(Double_t)
Returns the cosine of an angle of x radians.
Definition TMath.h:605
Double_t Sin(Double_t)
Returns the sine of an angle of x radians.
Definition TMath.h:599
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:122
Graphics context structure.
Definition GuiTypes.h:225
Used for drawing line segments (maps to the X11 XSegments structure)
Definition GuiTypes.h:352
unsigned char a
Definition TASImage.cxx:152
unsigned char b
Definition TASImage.cxx:155
unsigned char r
Definition TASImage.cxx:153
unsigned char g
Definition TASImage.cxx:154
th1 Draw()
TLine l
Definition textangle.C:4