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("TPDF")) {
1599 Warning("Paint", "PDF not implemented yet");
1600 return;
1601 } else if (ps->InheritsFrom("TSVG")) {
1603 }
1604
1605 Double_t dx = gPad->GetX2() - gPad->GetX1();
1606 Double_t dy = gPad->GetY2() - gPad->GetY1();
1607 Double_t x1, x2, y1, y2;
1608
1609 if (expand) {
1610 x1 = gPad->GetX1();
1611 x2 = x1+dx/image->width;
1612 y1 = gPad->GetY2();
1613 y2 = y1+dy/image->height;
1614 } else {
1615 x1 = gPad->GetX1()+dx*gPad->GetLeftMargin();
1616 x2 = x1+(dx*(1-gPad->GetRightMargin()-gPad->GetLeftMargin()))/image->width;
1617 y1 = gPad->GetY2()-dy*gPad->GetTopMargin();
1618 y2 = y1+(dy*(1-gPad->GetTopMargin()-gPad->GetBottomMargin()))/image->height;
1619 }
1620
1621 // get special color cell to be reused during image printing
1622 ps->SetFillColor(TColor::GetColor((Float_t) 1., (Float_t) 1., (Float_t) 1.));
1623 ps->SetFillStyle(1001);
1624
1625 ps->CellArrayBegin(image->width, image->height, x1, x2, y1, y2);
1626
1627 if (paint_as_png) {
1628 char *buffer = nullptr;
1629 int size = 0;
1630 ASImageExportParams params;
1631 params.png.type = ASIT_Png;
1632 params.png.flags = EXPORT_ALPHA;
1633 params.png.compression = GetImageCompression();
1634 if (!params.png.compression)
1635 params.png.compression = -1;
1636 if (ASImage2PNGBuff(image, (CARD8 **)&buffer, &size, &params)) {
1637 ps->CellArrayPng(buffer, size);
1638 free(buffer);
1639 }
1640 } else {
1642 0, 0, image->width, image->height, nullptr);
1643 if (imdec)
1644 for (Int_t yt = 0; yt < (Int_t)image->height; yt++) {
1645 imdec->decode_image_scanline(imdec);
1646 for (Int_t xt = 0; xt < (Int_t)image->width; xt++)
1647 ps->CellArrayFill(imdec->buffer.red[xt],
1648 imdec->buffer.green[xt],
1649 imdec->buffer.blue[xt]);
1650 }
1652 }
1653 ps->CellArrayEnd();
1654
1655 // print the color bar
1656 if (grad_im) {
1657 Double_t xconv = (gPad->AbsPixeltoX(pal_Ax + pal_w) - gPad->AbsPixeltoX(pal_Ax)) / grad_im->width;
1658 Double_t yconv = (gPad->AbsPixeltoY(pal_Ay - pal_h) - gPad->AbsPixeltoY(pal_Ay)) / grad_im->height;
1659 x1 = gPad->AbsPixeltoX(pal_Ax);
1660 x2 = x1 + xconv;
1661 y2 = gPad->AbsPixeltoY(pal_Ay);
1662 y1 = y2 - yconv;
1663 ps->CellArrayBegin(grad_im->width, grad_im->height,
1664 x1, x2, y1, y2);
1665
1666 if (paint_as_png) {
1667 char *buffer = nullptr;
1668 int size = 0;
1669 ASImageExportParams params;
1670 params.png.type = ASIT_Png;
1671 params.png.flags = EXPORT_ALPHA;
1672 params.png.compression = GetImageCompression();
1673 if (!params.png.compression)
1674 params.png.compression = -1;
1675
1676 if (ASImage2PNGBuff(grad_im, (CARD8 **)&buffer, &size, &params)) {
1677 ps->CellArrayPng(buffer, size);
1678 free(buffer);
1679 }
1680 } else {
1682 0, 0, grad_im->width, grad_im->height, nullptr);
1683 if (imdec)
1684 for (Int_t yt = 0; yt < (Int_t)grad_im->height; yt++) {
1685 imdec->decode_image_scanline(imdec);
1686 for (Int_t xt = 0; xt < (Int_t)grad_im->width; xt++)
1687 ps->CellArrayFill(imdec->buffer.red[xt],
1688 imdec->buffer.green[xt],
1689 imdec->buffer.blue[xt]);
1690 }
1692 }
1693 ps->CellArrayEnd();
1694
1695 // values of palette
1696 TGaxis axis;
1697 Int_t ndiv = 510;
1698 double min = fMinValue;
1699 double max = fMaxValue;
1700 axis.SetLineColor(1); // draw black ticks
1701 Double_t pal_Xpos = gPad->AbsPixeltoX(pal_Ax + pal_w);
1702 // TODO: provide PaintAxisOn method
1703 axis.PaintAxis(pal_Xpos, gPad->AbsPixeltoY(pal_Ay + pal_h),
1704 pal_Xpos, gPad->AbsPixeltoY(pal_Ay + 1),
1705 min, max, ndiv, "+L");
1706
1707 }
1708 }
1709
1710 if (grad_im) {
1712 }
1713}
1714
1715////////////////////////////////////////////////////////////////////////////////
1716/// Is the mouse in the image ?
1717
1719{
1720 Int_t pxl, pyl, pxt, pyt;
1721
1722 Int_t px1 = gPad->XtoAbsPixel(0);
1723 Int_t py1 = gPad->YtoAbsPixel(0);
1724 Int_t px2 = gPad->XtoAbsPixel(1);
1725 Int_t py2 = gPad->YtoAbsPixel(1);
1726
1727 if (px1 < px2) {pxl = px1; pxt = px2;}
1728 else {pxl = px2; pxt = px1;}
1729 if (py1 < py2) {pyl = py1; pyt = py2;}
1730 else {pyl = py2; pyt = py1;}
1731
1732 if ((px > pxl && px < pxt) && (py > pyl && py < pyt))
1733 return 0;
1734
1735 return 999999;
1736}
1737
1738////////////////////////////////////////////////////////////////////////////////
1739/// Execute mouse events.
1740
1742{
1743 static std::unique_ptr<TBox> ZoomBox;
1744
1745 if (!gPad) return;
1746
1747 if (IsEditable()) {
1748 gPad->ExecuteEvent(event, px, py);
1749 return;
1750 }
1751
1752 gPad->SetCursor(kCross);
1753
1754 static Int_t px1old, py1old, px2old, py2old;
1755 static Int_t px1, py1, px2, py2, pxl, pyl, pxt, pyt;
1756
1757 if (!IsValid()) return;
1758
1759 if (event == kButton1Motion || event == kButton1Down ||
1760 event == kButton1Up) {
1761
1762 // convert to image pixel on screen
1763 Int_t imgX = px - gPad->XtoAbsPixel(0);
1764 Int_t imgY = py - gPad->YtoAbsPixel(1);
1765
1766 if (imgX < 0) px = px - imgX;
1767 if (imgY < 0) py = py - imgY;
1768
1769 ASImage *image = fImage;
1771
1772 if (imgX >= (int)image->width) px = px - imgX + image->width - 1;
1773 if (imgY >= (int)image->height) py = py - imgY + image->height - 1;
1774
1775 switch (event) {
1776
1777 case kButton1Down:
1778 px1 = gPad->XtoAbsPixel(gPad->GetX1());
1779 py1 = gPad->YtoAbsPixel(gPad->GetY1());
1780 px2 = gPad->XtoAbsPixel(gPad->GetX2());
1781 py2 = gPad->YtoAbsPixel(gPad->GetY2());
1782 px1old = px; py1old = py;
1783 break;
1784
1785 case kButton1Motion:
1786 px2old = px;
1787 px2old = TMath::Max(px2old, px1);
1788 px2old = TMath::Min(px2old, px2);
1789 py2old = py;
1790 py2old = TMath::Max(py2old, py2);
1791 py2old = TMath::Min(py2old, py1);
1796
1797 if (ZoomBox) {
1798 ZoomBox->SetX1(gPad->AbsPixeltoX(pxl));
1799 ZoomBox->SetY1(gPad->AbsPixeltoY(pyl));
1800 ZoomBox->SetX2(gPad->AbsPixeltoX(pxt));
1801 ZoomBox->SetY2(gPad->AbsPixeltoY(pyt));
1802 } else {
1803 ZoomBox = std::make_unique<TBox>(pxl, pyl, pxt, pyt);
1804 ZoomBox->SetFillStyle(0);
1805 ZoomBox->Draw("l*");
1806 }
1807 gPad->Modified(kTRUE);
1808 gPad->Update();
1809 break;
1810
1811 case kButton1Up:
1812 // do nothing if zoom area is too small
1813 if ( TMath::Abs(pxl - pxt) < 5 || TMath::Abs(pyl - pyt) < 5)
1814 return;
1815
1816 pxl = 0;
1817 pxt = 0;
1818 pyl = 0;
1819 pyt = 0;
1820
1823
1824 Int_t imgX1 = px1old - gPad->XtoAbsPixel(0);
1825 Int_t imgY1 = py1old - gPad->YtoAbsPixel(1);
1826 Int_t imgX2 = px - gPad->XtoAbsPixel(0);
1827 Int_t imgY2 = py - gPad->YtoAbsPixel(1);
1828
1829 imgY1 = image->height - 1 - imgY1;
1830 imgY2 = image->height - 1 - imgY2;
1831 imgX1 = (Int_t)(imgX1 / xfact) + fZoomOffX;
1832 imgY1 = (Int_t)(imgY1 / yfact) + fZoomOffY;
1833 imgX2 = (Int_t)(imgX2 / xfact) + fZoomOffX;
1834 imgY2 = (Int_t)(imgY2 / yfact) + fZoomOffY;
1835
1836 Zoom((imgX1 < imgX2) ? imgX1 : imgX2, (imgY1 < imgY2) ? imgY1 : imgY2,
1837 TMath::Abs(imgX1 - imgX2) + 1, TMath::Abs(imgY1 - imgY2) + 1);
1838
1839 if (ZoomBox)
1840 ZoomBox.reset();
1841
1842 gPad->Modified(kTRUE);
1843 gPad->Update();
1844 break;
1845 }
1846 }
1847}
1848
1849////////////////////////////////////////////////////////////////////////////////
1850/// Get image pixel coordinates and the pixel value at the mouse pointer.
1851
1853{
1854 static char info[64];
1855 info[0] = 0;
1856
1857 if (!IsValid()) return info;
1858
1859 // convert to image pixel on screen
1860 px -= gPad->XtoAbsPixel(0);
1861 py -= gPad->YtoAbsPixel(1);
1862
1863 // no info if mouse is outside of image
1864 if (px < 0 || py < 0) return info;
1865
1866 ASImage *image = fImage;
1868 if (px >= (int)image->width || py >= (int)image->height)
1869 return info;
1870
1871 py = image->height - 1 - py;
1872 // convert to original image size and take zooming into account
1873 if (fScaledImage) {
1874 px = (Int_t)(px / (Double_t)fScaledImage->fImage->width * fZoomWidth ) + fZoomOffX;
1875 py = (Int_t)(py / (Double_t)fScaledImage->fImage->height * fZoomHeight) + fZoomOffY;
1876 }
1877
1878 if (fImage->alt.vector) {
1879 snprintf(info,64,"x: %d y: %d %.5g",
1880 px, py, fImage->alt.vector[px + py * fImage->width]);
1881 } else {
1882 snprintf(info,64,"x: %d y: %d", px, py);
1883 }
1884
1885 return info;
1886}
1887
1888////////////////////////////////////////////////////////////////////////////////
1889/// Set a new palette to an image.
1890/// Only images that were created with the SetImage() functions can be
1891/// modified with this function. The previously used palette is destroyed.
1892
1894{
1896
1897 if (!InitVisual()) {
1898 Warning("SetPalette", "Visual not initiated");
1899 return;
1900 }
1901
1902 if (!IsValid()) {
1903 Warning("SetPalette", "Image not valid");
1904 return;
1905 }
1906
1907 if (!fImage->alt.vector)
1908 return;
1909
1910 // copy ROOT palette to asImage palette
1911 const TImagePalette &pal = GetPalette();
1912
1914 asPalette.npoints = pal.fNumPoints;
1915 asPalette.channels[0] = new CARD16 [asPalette.npoints];
1916 asPalette.channels[1] = new CARD16 [asPalette.npoints];
1917 asPalette.channels[2] = new CARD16 [asPalette.npoints];
1918 asPalette.channels[3] = new CARD16 [asPalette.npoints];
1919 memcpy(asPalette.channels[0], pal.fColorBlue, pal.fNumPoints * sizeof(UShort_t));
1920 memcpy(asPalette.channels[1], pal.fColorGreen, pal.fNumPoints * sizeof(UShort_t));
1921 memcpy(asPalette.channels[2], pal.fColorRed, pal.fNumPoints * sizeof(UShort_t));
1922 memcpy(asPalette.channels[3], pal.fColorAlpha, pal.fNumPoints * sizeof(UShort_t));
1923
1924 asPalette.points = new double[asPalette.npoints];
1925 for (Int_t point = 0; point < Int_t(asPalette.npoints); point++)
1926 asPalette.points[point] = fMinValue + (fMaxValue - fMinValue) * pal.fPoints[point];
1927
1928 // use the new palette in this image
1930
1931 delete [] asPalette.points;
1932 for (Int_t col = 0; col < 4; col++)
1933 delete [] asPalette.channels[col];
1934
1936}
1937
1938////////////////////////////////////////////////////////////////////////////////
1939/// Scale the original image.
1940/// The size of the image on the screen does not change because it is defined
1941/// by the size of the pad.
1942/// This function can be used to change the size of an image before writing
1943/// it into a file. The colors of the new pixels are interpolated.
1944/// An image created with the SetImage() functions cannot be modified with
1945/// the function SetPalette() any more after a call of this function!
1946
1948{
1949 if (!IsValid()) {
1950 Warning("Scale", "Image not initiated");
1951 return;
1952 }
1953
1954 if (!InitVisual()) {
1955 Warning("Scale", "Visual not initiated");
1956 return;
1957 }
1958
1959 if (toWidth < 1)
1960 toWidth = 1;
1961 if (toHeight < 1 )
1962 toHeight = 1;
1963 if (toWidth > 30000)
1964 toWidth = 30000;
1965 if (toHeight > 30000)
1966 toHeight = 30000;
1967
1970 GetImageQuality());
1971 DestroyImage();
1972 fImage = img;
1973 UnZoom();
1975}
1976
1977////////////////////////////////////////////////////////////////////////////////
1978/// Another method of enlarging images where corners remain unchanged,
1979/// but middle part gets tiled.
1980
1983{
1984 if (!IsValid()) {
1985 Warning("Slice", "Image not initiated");
1986 return;
1987 }
1988
1989 if (!InitVisual()) {
1990 Warning("Slice", "Visual not initiated");
1991 return;
1992 }
1993
1994 if (toWidth < 1)
1995 toWidth = 1;
1996 if (toHeight < 1 )
1997 toHeight = 1;
1998 if (toWidth > 30000)
1999 toWidth = 30000;
2000 if (toHeight > 30000)
2001 toHeight = 30000;
2002
2006 GetImageQuality());
2007
2008 DestroyImage();
2009 fImage = img;
2010 UnZoom();
2012}
2013
2014////////////////////////////////////////////////////////////////////////////////
2015/// Tile the original image.
2016
2018{
2019 if (!IsValid()) {
2020 Warning("Tile", "Image not initiated");
2021 return;
2022 }
2023
2024 if (!InitVisual()) {
2025 Warning("Tile", "Visual not initiated");
2026 return;
2027 }
2028
2029 if (toWidth < 1)
2030 toWidth = 1;
2031 if (toHeight < 1 )
2032 toHeight = 1;
2033 if (toWidth > 30000)
2034 toWidth = 30000;
2035 if (toHeight > 30000)
2036 toHeight = 30000;
2037
2040 DestroyImage();
2041 fImage = img;
2042 UnZoom();
2044}
2045
2046////////////////////////////////////////////////////////////////////////////////
2047/// The area of an image displayed in a pad is defined by this function.
2048/// Note: the size on the screen is defined by the size of the pad.
2049/// The original image is not modified by this function.
2050/// If width or height is larger than the original image they are reduced to
2051/// the width and height of the image.
2052/// If the off values are too large (off + width > image width) than the off
2053/// values are decreased. For example: offX = image width - width
2054/// Note: the parameters are always relative to the original image not to the
2055/// size of an already zoomed image.
2056
2058{
2059 if (!IsValid()) {
2060 Warning("Zoom", "Image not valid");
2061 return;
2062 }
2064
2065 fZoomWidth = (width == 0) ? 1 : ((width > fImage->width) ? fImage->width : width);
2066 fZoomHeight = (height == 0) ? 1 : ((height > fImage->height) ? fImage->height : height);
2067 fZoomOffX = offX;
2068 if (fZoomOffX + fZoomWidth > fImage->width)
2069 fZoomOffX = fImage->width - fZoomWidth;
2070 fZoomOffY = offY;
2071 if (fZoomOffY + fZoomHeight > fImage->height)
2072 fZoomOffY = fImage->height - fZoomHeight;
2073}
2074
2075////////////////////////////////////////////////////////////////////////////////
2076/// Un-zoom the image to original size.
2077/// UnZoom() - performs undo for Zoom,Crop,Scale actions
2078
2080{
2081 if (!IsValid()) {
2082 Warning("UnZoom", "Image not valid");
2083 return;
2084 }
2086 fZoomOffX = 0;
2087 fZoomOffY = 0;
2088 fZoomWidth = fImage->width;
2089 fZoomHeight = fImage->height;
2090
2092}
2093
2094////////////////////////////////////////////////////////////////////////////////
2095/// Flip image in place.
2096///
2097/// Flip is either 90, 180, 270, 180 is default.
2098/// This function manipulates the original image and destroys the
2099/// scaled and zoomed image which will be recreated at the next call of
2100/// the Draw function. If the image is zoomed the zoom - coordinates are
2101/// now relative to the new image.
2102/// This function cannot be used for images which were created with the
2103/// SetImage() functions, because the original pixel values would be
2104/// destroyed.
2105
2107{
2108 if (!IsValid()) {
2109 Warning("Flip", "Image not valid");
2110 return;
2111 }
2112 if (!InitVisual()) {
2113 Warning("Flip", "Visual not initiated");
2114 return;
2115 }
2116
2117 if (fImage->alt.vector) {
2118 Warning("Flip", "flip does not work for data images");
2119 return;
2120 }
2121
2122 Int_t rflip = flip/90;
2123
2124 UInt_t w = fImage->width;
2125 UInt_t h = fImage->height;
2126
2127 if (rflip & 1) {
2128 w = fImage->height;
2129 h = fImage->width;
2130 }
2131
2134 GetImageQuality());
2135 DestroyImage();
2136 fImage = img;
2137 UnZoom();
2138}
2139
2140////////////////////////////////////////////////////////////////////////////////
2141/// Mirror image in place.
2142///
2143/// If vert is true mirror in vertical axis, horizontal otherwise.
2144/// Vertical is default.
2145/// This function manipulates the original image and destroys the
2146/// scaled and zoomed image which will be recreated at the next call of
2147/// the Draw function. If the image is zoomed the zoom - coordinates are
2148/// now relative to the new image.
2149/// This function cannot be used for images which were created with the
2150/// SetImage() functions, because the original pixel values would be
2151/// destroyed.
2152
2154{
2155 if (!IsValid()) {
2156 Warning("Mirror", "Image not valid");
2157 return;
2158 }
2159
2160 if (!InitVisual()) {
2161 Warning("Mirror", "Visual not initiated");
2162 return;
2163 }
2164
2165 if (fImage->alt.vector) {
2166 Warning("Mirror", "mirror does not work for data images");
2167 return;
2168 }
2169
2171 fImage->width, fImage->height, vert,
2173 GetImageQuality());
2174 DestroyImage();
2175 fImage = img;
2176 UnZoom();
2177}
2178
2179////////////////////////////////////////////////////////////////////////////////
2180/// Return width of original image not of the displayed image.
2181/// (Number of image pixels)
2182
2184{
2185 return fImage ? fImage->width : 0;
2186}
2187
2188////////////////////////////////////////////////////////////////////////////////
2189/// Return height of original image not of the displayed image.
2190/// (Number of image pixels)
2191
2193{
2194 return fImage ? fImage->height : 0;
2195}
2196
2197////////////////////////////////////////////////////////////////////////////////
2198/// Return width of the displayed image not of the original image.
2199/// (Number of screen pixels)
2200
2202{
2203 return fScaledImage ? fScaledImage->fImage->width : GetWidth();
2204}
2205
2206////////////////////////////////////////////////////////////////////////////////
2207/// Return height of the displayed image not of the original image.
2208/// (Number of screen pixels)
2209
2211{
2212 return fScaledImage ? fScaledImage->fImage->height : GetHeight();
2213}
2214
2215////////////////////////////////////////////////////////////////////////////////
2216/// Return the zoom parameters.
2217/// This is useful when the zoom has been done interactively using the mouse.
2218
2220{
2221 x = fZoomOffX;
2222 y = fZoomOffY;
2223 w = fZoomWidth;
2224 h = fZoomHeight;
2225}
2226
2227////////////////////////////////////////////////////////////////////////////////
2228/// Static function to initialize the ASVisual.
2229
2231{
2232 Bool_t noX = gROOT->IsBatch() || !gVirtualX->InheritsFrom("TGX11");
2233
2234 if (fgVisual && (noX == fgBatch))
2235 return kTRUE;
2236
2237 fgVisual = nullptr;
2238 fgBatch = false;
2239
2240#ifndef WIN32
2241#ifndef R__HAS_COCOA
2242 Display *disp = (Display*) gVirtualX->GetDisplay();
2243 Int_t screen = gVirtualX->GetScreen();
2244 Int_t depth = gVirtualX->GetDepth();
2245 Visual *vis = (Visual*) gVirtualX->GetVisual();
2246 Colormap cmap = (Colormap) gVirtualX->GetColormap();
2247
2248 static ASVisual *vis_x = nullptr;
2249
2250 if (vis && cmap && !noX) {
2251 if (!vis_x)
2253 XVisualIDFromVisual(vis), cmap, nullptr);
2254 fgVisual = vis_x;
2255 }
2256#endif
2257#endif
2258
2259 static ASVisual *vis_batch = nullptr;
2260
2261 if (!fgVisual) {
2262 if (!vis_batch) {
2263 // create dummy visual for batch mode
2264 vis_batch = create_asvisual(nullptr, 0, 0, nullptr);
2265 vis_batch->dpy = nullptr; // fake (not used)
2266 }
2267
2269 fgBatch = true;
2270 }
2271
2272 return kTRUE;
2273}
2274
2275////////////////////////////////////////////////////////////////////////////////
2276/// Static function to initialize the image.
2278{
2279 if (!InitVisual()) {
2280 Warning(caller, "Visual not initiated");
2281 return false;
2282 }
2283
2284 if (!fImage) {
2285 Warning(caller, "no image");
2286 return false;
2287 }
2288
2289 if (!fImage->alt.argb32) {
2290 BeginPaint();
2291 }
2292
2293 if (!fImage->alt.argb32) {
2294 Warning(caller, "Failed to get argb32 pixel array");
2295 return false;
2296 }
2297 return true;
2298}
2299
2300////////////////////////////////////////////////////////////////////////////////
2301/// Start palette editor.
2302
2304{
2305 if (!IsValid()) {
2306 Warning("StartPaletteEditor", "Image not valid");
2307 return;
2308 }
2309 if (!fImage->alt.vector) {
2310 Warning("StartPaletteEditor", "palette can be modified only for data images");
2311 return;
2312 }
2313
2314 // Opens a GUI to edit the color palette
2316}
2317
2318////////////////////////////////////////////////////////////////////////////////
2319/// Returns image pixmap.
2320/// The pixmap must deleted by user.
2321
2323{
2324 if (!InitVisual()) {
2325 Warning("GetPixmap", "Visual not initiated");
2326 return 0;
2327 }
2328
2329 Pixmap_t ret;
2330
2332
2333 static int x11 = -1;
2334 if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11");
2335
2336 if (x11) { // use builtin version
2337 ret = (Pixmap_t)asimage2pixmap(fgVisual, gVirtualX->GetDefaultRootWindow(),
2338 img, nullptr, kTRUE);
2339 } else {
2340 if (!fImage->alt.argb32) {
2341 BeginPaint();
2342 }
2343 ret = gVirtualX->CreatePixmapFromData((unsigned char*)fImage->alt.argb32,
2344 fImage->width, fImage->height);
2345 }
2346
2347 return ret;
2348}
2349
2350////////////////////////////////////////////////////////////////////////////////
2351/// Returns image mask pixmap (alpha channel).
2352/// The pixmap must deleted by user.
2353
2355{
2356 Pixmap_t pxmap = 0;
2357
2358 if (!InitVisual()) {
2359 Warning("GetMask", "Visual not initiated");
2360 return pxmap;
2361 }
2362
2364
2365 if (!img) {
2366 Warning("GetMask", "No image");
2367 return pxmap;
2368 }
2369
2370 UInt_t hh = img->height;
2371 UInt_t ow = img->width%8;
2372 UInt_t ww = img->width - ow + (ow ? 8 : 0);
2373
2375 0, 0, ww, 0, nullptr);
2376 if (!imdec)
2377 return pxmap;
2378
2379 std::vector<char> bits(ww * hh / 8); //an array of bits
2380
2381 UInt_t bit = 0, i = 0;
2382 for (UInt_t y = 0; y < hh; y++) {
2383 imdec->decode_image_scanline(imdec);
2384 CARD32 *a = imdec->buffer.alpha;
2385
2386 for (UInt_t x = 0; x < ww; x++) {
2387 if (a[x]) {
2388 SETBIT(bits[i], bit);
2389 } else {
2390 CLRBIT(bits[i], bit);
2391 }
2392 if (++bit == 8) {
2393 bit = 0;
2394 i++;
2395 }
2396 }
2397 }
2398
2400 pxmap = gVirtualX->CreateBitmap(gVirtualX->GetDefaultRootWindow(), bits.data(), ww, hh);
2401 return pxmap;
2402}
2403
2404////////////////////////////////////////////////////////////////////////////////
2405/// Create image from pixmap.
2406
2408{
2409 if (!InitVisual()) {
2410 Warning("SetImage", "Visual not initiated");
2411 return;
2412 }
2413
2414 DestroyImage();
2416
2417 Int_t xy;
2418 UInt_t w, h;
2419 gVirtualX->GetWindowSize(pxm, xy, xy, w, h);
2420
2421 if (fName.IsNull()) fName.Form("img_%dx%d",w, h);
2422
2423 static int x11 = -1;
2424 if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11");
2425
2426 if (x11) { //use built-in optimized version
2427 fImage = picture2asimage(fgVisual, pxm, mask, 0, 0, w, h, kAllPlanes, 1, 0);
2428 } else {
2429 unsigned char *bits = gVirtualX->GetColorBits(pxm, 0, 0, w, h);
2430 if (!bits) { // error
2431 return;
2432 }
2433
2434 // no mask
2435 if (!mask) {
2436 fImage = bitmap2asimage(bits, w, h, 0, nullptr);
2437 delete [] bits;
2438 return;
2439 }
2440 unsigned char *mask_bits = gVirtualX->GetColorBits(mask, 0, 0, w, h);
2441 fImage = bitmap2asimage(bits, w, h, 0, mask_bits);
2442 delete [] mask_bits;
2443 delete [] bits;
2444 }
2445}
2446
2447////////////////////////////////////////////////////////////////////////////////
2448/// Return 2D array of machine dependent pixel values.
2449
2451{
2452 if (!fImage) {
2453 Warning("GetPixels", "Wrong Image");
2454 return nullptr;
2455 }
2456
2459
2460 width = !width ? img->width : width;
2461 height = !height ? img->height : height;
2462
2463 if (x < 0) {
2464 width -= x;
2465 x = 0 ;
2466 }
2467 if (y < 0) {
2468 height -= y;
2469 y = 0;
2470 }
2471
2472 if ((x >= (int)img->width) || (y >= (int)img->height)) {
2473 return nullptr;
2474 }
2475
2476 if ((int)(x + width) > (int)img->width) {
2477 width = img->width - x;
2478 }
2479
2480 if ((int)(y + height) > (int)img->height) {
2481 height = img->height - y;
2482 }
2483
2484 if ((imdec = start_image_decoding(nullptr, fImage, SCL_DO_ALL, 0, y,
2485 img->width, height, nullptr)) == nullptr) {
2486 Warning("GetPixels", "Failed to create image decoder");
2487 return nullptr;
2488 }
2489
2490 TArrayL *ret = new TArrayL(width * height);
2491 Int_t r = 0, g = 0, b = 0;
2492 Long_t p = 0;
2493
2494 for (UInt_t k = 0; k < height; k++) {
2495 imdec->decode_image_scanline(imdec);
2496
2497 for (UInt_t i = 0; i < width; ++i) {
2498 if ((r == (Int_t)imdec->buffer.red[i]) &&
2499 (g == (Int_t)imdec->buffer.green[i]) &&
2500 (b == (Int_t)imdec->buffer.blue[i])) {
2501 } else {
2502 r = (Int_t)imdec->buffer.red[i];
2503 g = (Int_t)imdec->buffer.green[i];
2504 b = (Int_t)imdec->buffer.blue[i];
2505 p = (Long_t)TColor::RGB2Pixel(r, g, b);
2506 }
2507 ret->AddAt(p, k*width + i);
2508 }
2509 }
2510
2512 return ret;
2513}
2514
2515////////////////////////////////////////////////////////////////////////////////
2516/// Return a pointer to internal array[width x height] of double values [0,1].
2517/// This array is directly accessible. That allows to manipulate/change the
2518/// image.
2519
2521{
2522 if (!fImage) {
2523 Warning("GetVecArray", "Bad Image");
2524 return nullptr;
2525 }
2526 if (fImage->alt.vector) {
2527 return fImage->alt.vector;
2528 }
2529 // vectorize
2530 return nullptr;
2531}
2532
2533////////////////////////////////////////////////////////////////////////////////
2534/// In case of vectorized image return an associated array of doubles
2535/// otherwise this method creates and returns a 2D array of doubles corresponding to palette.
2536/// If palette is ZERO a color converted to double value [0, 1] according to formula
2537/// ~~~ {.cpp}
2538/// Double_t((r << 16) + (g << 8) + b)/0xFFFFFF
2539/// ~~~
2540/// The returned array must be deleted after usage.
2541
2543{
2544 if (!fImage) {
2545 Warning("GetArray", "Bad Image");
2546 return nullptr;
2547 }
2548
2549 TArrayD *ret;
2550
2551 if (fImage->alt.vector) {
2552 ret = new TArrayD(fImage->width*fImage->height, fImage->alt.vector);
2553 return ret;
2554 }
2555
2557
2558 w = w ? w : fImage->width;
2559 h = h ? h : fImage->height;
2560
2561 if ((fImage->width != w) || (fImage->height != h)) {
2562 Scale(w, h);
2563 }
2564
2566
2567 if ((imdec = start_image_decoding(nullptr, img, SCL_DO_ALL, 0, 0,
2568 img->width, 0, nullptr)) == nullptr) {
2569 Warning("GetArray", "Failed to create image decoder");
2570 return nullptr;
2571 }
2572
2573 ret = new TArrayD(w * h);
2574 CARD32 r = 0, g = 0, b = 0;
2575 Int_t p = 0;
2576 Double_t v = 0;
2577
2578 for (UInt_t k = 0; k < h; k++) {
2579 imdec->decode_image_scanline(imdec);
2580
2581 for (UInt_t i = 0; i < w; ++i) {
2582 if ((r == imdec->buffer.red[i]) &&
2583 (g == imdec->buffer.green[i]) &&
2584 (b == imdec->buffer.blue[i])) {
2585 } else {
2586 r = imdec->buffer.red[i];
2587 g = imdec->buffer.green[i];
2588 b = imdec->buffer.blue[i];
2589 if (palette) p = palette->FindColor(r, g, b);
2590 }
2591 v = palette ? palette->fPoints[p] : Double_t((r << 16) + (g << 8) + b)/0xFFFFFF;
2592 ret->AddAt(v, (h-k-1)*w + i);
2593 }
2594 }
2595
2597 return ret;
2598}
2599
2600////////////////////////////////////////////////////////////////////////////////
2601/// Draw text of size (in pixels for TrueType fonts)
2602/// at position (x, y) with color specified by hex string.
2603///
2604/// - font_name: TrueType font's filename or X font spec or alias.
2605/// 3D style of text is one of the following:
2606/// * 0 plain 2D text,
2607/// * 1 embossed,
2608/// * 2 sunken,
2609/// * 3 shade above,
2610/// * 4 shade below,
2611/// * 5 embossed thick,
2612/// * 6 sunken thick.
2613/// * 7 outline above,
2614/// * 8 ouline below,
2615/// * 9 full ouline.
2616/// - fore_file specifies foreground texture of text.
2617
2619 const char *color, const char *font_name,
2620 EText3DType type, const char *fore_file, Float_t angle)
2621{
2622 UInt_t width = 0, height = 0;
2624 ASImage *fore_im = nullptr;
2625 ASImage *text_im = nullptr;
2627
2628 if (!InitImage("DrawText")) {
2629 return;
2630 }
2631
2632 TString fn = font_name;
2633 fn.Strip();
2634
2635 // This is for backward compatibility...
2636 if (fn.Last('/') == 0)
2637 fn = fn(1, fn.Length() - 1);
2638
2639 const char *ttpath = gEnv->GetValue("Root.TTFontPath",
2641
2642 // if file will be found, fn will contain full name - otherwise empty
2644
2645 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"))
2646 ttfont = kTRUE;
2647
2648 if (color) {
2650 }
2651
2652 if (fImage && fImage->alt.argb32 && ttfont) {
2653 DrawTextTTF(x, y, text, size, text_color, fn.Data(), angle);
2654 return;
2655 }
2656
2657 if (!gFontManager) {
2658 gFontManager = create_font_manager(fgVisual->dpy, nullptr, nullptr);
2659 }
2660
2661 if (!gFontManager) {
2662 Warning("DrawText", "cannot create Font Manager");
2663 return;
2664 }
2665
2666 ASFont *font = fn.IsNull() ? nullptr : get_asfont(gFontManager, fn.Data(), 0, size, ASF_GuessWho);
2667
2668 if (!font) {
2669 font = get_asfont(gFontManager, "fixed", 0, size, ASF_GuessWho);
2670 if (!font) {
2671 Warning("DrawText", "cannot find a font %s", font_name);
2672 return;
2673 }
2674 }
2675
2677
2678 if (!fImage) {
2680 fill_asimage(fgVisual, fImage, 0, 0, width, height, 0xFFFFFFFF);
2681 }
2682
2683 text_im = draw_text(text, font, (ASText3DType)type, 0);
2684
2685 ASImage *rimg = fImage;
2686
2687 if (fore_file) {
2688 ASImage *tmp = file2ASImage(fore_file, 0xFFFFFFFF, SCREEN_GAMMA, 0, 0);
2689 if (tmp) {
2690 if ((tmp->width != width) || (tmp->height != height)) {
2693 }
2695 } else {
2696 fore_im = tmp;
2697 }
2698 }
2699
2700 if (fore_im) {
2703 } else {
2704 fore_im = text_im ;
2705 }
2706
2707 release_font(font);
2708
2709 if (fore_im) {
2711 ASImageLayer layers[2];
2712
2713 init_image_layers(&(layers[0]), 2);
2714 fore_im->back_color = text_color;
2715 layers[0].im = rimg;
2716 layers[0].dst_x = 0;
2717 layers[0].dst_y = 0;
2718 layers[0].clip_width = rimg->width;
2719 layers[0].clip_height = rimg->height;
2720 layers[0].bevel = nullptr;
2721 layers[1].im = fore_im;
2722 layers[1].dst_x = x;
2723 layers[1].dst_y = y;
2724 layers[1].clip_width = fore_im->width;
2725 layers[1].clip_height = fore_im->height;
2726
2727 rendered_im = merge_layers(fgVisual, &(layers[0]), 2, rimg->width, rimg->height,
2729
2731 DestroyImage();
2733 UnZoom();
2734 }
2735}
2736
2737////////////////////////////////////////////////////////////////////////////////
2738/// Merge two images.
2739///
2740/// op is string which specifies overlay operation. Supported operations are:
2741///
2742/// - add - color addition with saturation
2743/// - alphablend - alpha-blending
2744/// - allanon - color values averaging
2745/// - colorize - hue and saturate bottom image same as top image
2746/// - darken - use lowest color value from both images
2747/// - diff - use absolute value of the color difference between two images
2748/// - dissipate - randomly alpha-blend images
2749/// - hue - hue bottom image same as top image
2750/// - lighten - use highest color value from both images
2751/// - overlay - some weird image overlaying(see GIMP)
2752/// - saturate - saturate bottom image same as top image
2753/// - screen - another weird image overlaying(see GIMP)
2754/// - sub - color substraction with saturation
2755/// - tint - tinting image with image
2756/// - value - value bottom image same as top image
2757
2758void TASImage::Merge(const TImage *im, const char *op, Int_t x, Int_t y)
2759{
2760 if (!im) return;
2761
2762 if (!InitVisual()) {
2763 Warning("Merge", "Visual not initiated");
2764 return;
2765 }
2766
2768 ASImageLayer layers[2];
2769
2770 init_image_layers(&(layers[0]), 2);
2771 layers[0].im = fImage;
2772 layers[0].dst_x = 0;
2773 layers[0].dst_y = 0;
2774 layers[0].clip_width = fImage->width;
2775 layers[0].clip_height = fImage->height;
2776 layers[0].bevel = nullptr;
2777 layers[1].im = ((TASImage*)im)->fImage;
2778 layers[1].dst_x = x;
2779 layers[1].dst_y = y;
2780 layers[1].clip_width = im->GetWidth();
2781 layers[1].clip_height = im->GetHeight();
2782 layers[1].merge_scanlines = blend_scanlines_name2func(op ? op : "add");
2783
2784 rendered_im = merge_layers(fgVisual, &(layers[0]), 2, fImage->width, fImage->height,
2786
2787 DestroyImage();
2789 UnZoom();
2790}
2791
2792////////////////////////////////////////////////////////////////////////////////
2793/// Perform Gaussian blur of the image (useful for drop shadows).
2794/// - hr - horizontal radius of the blur
2795/// - vr - vertical radius of the blur
2796
2798{
2799 if (!InitVisual()) {
2800 Warning("Blur", "Visual not initiated");
2801 return;
2802 }
2803
2804 if (!fImage) {
2805 fImage = create_asimage(100, 100, 0);
2806
2807 if (!fImage) {
2808 Warning("Blur", "Failed to create image");
2809 return;
2810 }
2811
2812 fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, ARGB32_White);
2813 }
2814
2816 vr > 0 ? vr : 3, SCL_DO_ALL,
2818 DestroyImage();
2820 UnZoom();
2821}
2822
2823////////////////////////////////////////////////////////////////////////////////
2824/// Clone image.
2825
2827{
2828 if (!InitVisual() || !fImage) {
2829 Warning("Clone", "Image not initiated");
2830 return nullptr;
2831 }
2832
2833 TASImage *im = static_cast<TASImage *>(TImage::Create());
2834
2835 if (!im) {
2836 Warning("Clone", "Failed to create image");
2837 return nullptr;
2838 }
2839
2840 im->SetName(newname);
2841
2842 im->fImage = clone_asimage(fImage, SCL_DO_ALL);
2843 im->fMaxValue = fMaxValue;
2844 im->fMinValue = fMinValue;
2845 im->fZoomOffX = fZoomOffX;
2846 im->fZoomOffY = fZoomOffY;
2847 im->fZoomWidth = fZoomWidth;
2848 im->fZoomHeight = fZoomHeight;
2849 im->fZoomUpdate = fZoomUpdate;
2850 im->fScaledImage = fScaledImage ? static_cast<TASImage *>(fScaledImage->Clone()) : nullptr;
2851
2852 if (fImage->alt.argb32) {
2853 UInt_t sz = fImage->width * fImage->height;
2854 im->fImage->alt.argb32 = (ARGB32*)safemalloc(sz*sizeof(ARGB32));
2855 memcpy(im->fImage->alt.argb32, fImage->alt.argb32, sz * sizeof(ARGB32));
2856 }
2857
2858 return im;
2859}
2860
2861////////////////////////////////////////////////////////////////////////////////
2862/// Reduce color-depth of an image and fills vector of "scientific data"
2863/// [0...1]
2864///
2865/// Colors are reduced by allocating color cells to most used colors first,
2866/// and then approximating other colors with those allocated.
2867///
2868/// \param[in] max_colors - maximum size of the colormap.
2869/// \param[in] dither - number of bits to strip off the color data ( 0...7 )
2870/// \param[in] opaque_threshold - alpha channel threshold at which pixel should be treated as opaque
2871
2873{
2874 if (!InitVisual()) {
2875 Warning("Vectorize", "Visual not initiated");
2876 return nullptr;
2877 }
2878
2879 if (!fImage) {
2880 fImage = create_asimage(100, 100, 0);
2881
2882 if (!fImage) {
2883 Warning("Vectorize", "Failed to create image");
2884 return nullptr;
2885 }
2886
2887 fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, ARGB32_White);
2888 }
2889
2891 int *res;
2892 UInt_t r=0, g=0, b=0;
2893
2894 dither = dither > 7 ? 7 : dither;
2895
2897
2898 Double_t *vec = new Double_t[fImage->height*fImage->width];
2899 UInt_t v;
2900 Double_t tmp;
2901 fMinValue = 2;
2902 fMaxValue = -1;
2903
2904 for (UInt_t y = 0; y < fImage->height; y++) {
2905 for (UInt_t x = 0; x < fImage->width; x++) {
2906 int i = y*fImage->width + x;
2907 if (res) {
2908 g = INDEX_SHIFT_GREEN(cmap.entries[res[i]].green);
2909 b = INDEX_SHIFT_BLUE(cmap.entries[res[i]].blue);
2910 r = INDEX_SHIFT_RED(cmap.entries[res[i]].red);
2911 }
2913 v = (v>>12)&0x0FFF;
2914 tmp = Double_t(v)/0x0FFF;
2915 vec[(fImage->height - y - 1)*fImage->width + x] = tmp;
2916 if (fMinValue > tmp) fMinValue = tmp;
2917 if (fMaxValue < tmp) fMaxValue = tmp;
2918 }
2919 }
2920 TImagePalette *pal = new TImagePalette(cmap.count);
2921
2922 for (UInt_t j = 0; j < cmap.count; j++) {
2923 g = INDEX_SHIFT_GREEN(cmap.entries[j].green);
2924 b = INDEX_SHIFT_BLUE(cmap.entries[j].blue);
2925 r = INDEX_SHIFT_RED(cmap.entries[j].red);
2927
2928 v = (v>>12) & 0x0FFF;
2929 pal->fPoints[j] = Double_t(v)/0x0FFF;
2930
2931 pal->fColorRed[j] = cmap.entries[j].red << 8;
2932 pal->fColorGreen[j] = cmap.entries[j].green << 8;
2933 pal->fColorBlue[j] = cmap.entries[j].blue << 8;
2934 pal->fColorAlpha[j] = 0xFF00;
2935 }
2936
2938
2939 fPalette = *pal;
2940 fImage->alt.vector = vec;
2941 UnZoom();
2942 // ROOT-7647: res is allocated with `safemalloc` by colormap_asimage
2943 if (res) safefree(res);
2944 return (Double_t*)fImage->alt.vector;
2945}
2946
2947////////////////////////////////////////////////////////////////////////////////
2948/// This function will tile original image to specified size with offsets
2949/// requested, and then it will go though it and adjust hue, saturation and
2950/// value of those pixels that have specific hue, set by affected_hue/
2951/// affected_radius parameters. When affected_radius is greater then 180
2952/// entire image will be adjusted. Note that since grayscale colors have
2953/// no hue - the will not get adjusted. Only saturation and value will be
2954/// adjusted in gray pixels.
2955///
2956/// Hue is measured as an angle on a 360 degree circle, The following is
2957/// relationship of hue values to regular color names :
2958/// - red - 0
2959/// - yellow - 60
2960/// - green - 120
2961/// - cyan - 180
2962/// - blue - 240
2963/// - magenta - 300
2964/// - red - 360
2965///
2966/// All the hue values in parameters will be adjusted to fall within 0-360 range.
2967///
2968/// \param[in] hue hue in degrees in range 0-360. This allows to limit
2969/// impact of color adjustment to affect only limited range of hues.
2970///
2971/// \param[in] radius value in degrees to be used in order to
2972/// calculate the range of affected hues. Range is determined by
2973/// substracting and adding this value from/to affected_hue.
2974///
2975/// \param[in] H value by which to change hues in affected range.
2976/// \param[in] S value by which to change saturation of the pixels in affected hue range.
2977/// \param[in] V value by which to change Value(brightness) of pixels in affected hue range.
2978///
2979/// \param[in] x,y position on infinite surface tiled with original image, of the
2980/// left-top corner of the area to be used for new image.
2981///
2982/// \param[in] width, height size of the area of the original image to be used for new image.
2983/// Default is current width, height of the image.
2984
2987{
2988 if (!InitVisual()) {
2989 Warning("HSV", "Visual not initiated");
2990 return;
2991 }
2992
2993 if (!fImage) {
2994 fImage = create_asimage(width ? width : 20, height ? height : 20, 0);
2995
2996 if (!fImage) {
2997 Warning("HSV", "Failed to create image");
2998 return;
2999 }
3000
3001 x = 0;
3002 y = 0;
3003 fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, ARGB32_White);
3004 }
3005
3006 width = !width ? fImage->width : width;
3007 height = !height ? fImage->height : height;
3008
3009 ASImage *rendered_im = nullptr;
3010
3011 if (H || S || V) {
3013 hue, radius, H, S, V, ASA_ASImage, 100,
3015 }
3016 if (!rendered_im) {
3017 Warning("HSV", "Failed to create rendered image");
3018 return;
3019 }
3020
3021 DestroyImage();
3023 UnZoom();
3024}
3025
3026////////////////////////////////////////////////////////////////////////////////
3027/// Render multipoint gradient inside rectangle of size (width, height)
3028/// at position (x,y) within the existing image.
3029///
3030/// \param[in] angle Given in degrees. Default is 0. This is the
3031/// direction of the gradient. Currently the only supported
3032/// values are 0, 45, 90, 135, 180, 225, 270, 315. 0 means left
3033/// to right, 90 means top to bottom, etc.
3034///
3035/// \param[in] colors Whitespace-separated list of colors. At least two
3036/// colors are required. Each color in this list will be visited
3037/// in turn, at the intervals given by the offsets attribute.
3038///
3039/// \param[in] offsets Whitespace-separated list of floating point values
3040/// ranging from 0.0 to 1.0. The colors from the colors attribute
3041/// are given these offsets, and the final gradient is rendered
3042/// from the combination of the two. If both colors and offsets
3043/// are given but the number of colors and offsets do not match,
3044/// the minimum of the two will be used, and the other will be
3045/// truncated to match. If offsets are not given, a smooth
3046/// stepping from 0.0 to 1.0 will be used.
3047/// \param[in] x x position coordinate
3048/// \param[in] y y position coordinate
3049/// \param[in] width image width, if 0, it will be read from fImage
3050/// \param[in] height image height, if 0, it will be read from fImage
3051void TASImage::Gradient(UInt_t angle, const char *colors, const char *offsets,
3053{
3054 if (!InitVisual()) {
3055 Warning("Gradient", "Visual not initiated");
3056 return;
3057 }
3058
3059 ASImage *rendered_im = nullptr;
3060 ASGradient gradient;
3061
3062 int reverse = 0, npoints1 = 0, npoints2 = 0;
3063 char *p;
3064 char *pb;
3065 char ch;
3066 TString str = colors;
3067 TString col;
3068
3069 if ((angle > 2 * 180 * 15 / 16) || (angle < 2 * 180 * 1 / 16)) {
3070 gradient.type = GRADIENT_Left2Right;
3071 } else if (angle < 2 * 180 * 3 / 16) {
3072 gradient.type = GRADIENT_TopLeft2BottomRight;
3073 } else if (angle < 2 * 180 * 5 / 16) {
3074 gradient.type = GRADIENT_Top2Bottom;
3075 } else if (angle < 2 * 180 * 7 / 16) {
3076 gradient.type = GRADIENT_BottomLeft2TopRight; reverse = 1;
3077 } else if (angle < 2 * 180 * 9 / 16) {
3078 gradient.type = GRADIENT_Left2Right; reverse = 1;
3079 } else if (angle < 2 * 180 * 11 / 16) {
3080 gradient.type = GRADIENT_TopLeft2BottomRight; reverse = 1;
3081 } else if (angle < 2 * 180 * 13 / 16) {
3082 gradient.type = GRADIENT_Top2Bottom; reverse = 1;
3083 } else {
3084 gradient.type = GRADIENT_BottomLeft2TopRight;
3085 }
3086
3087 for (p = (char*)colors; isspace((int)*p); p++) { }
3088
3089 for (npoints1 = 0; *p; npoints1++) {
3090 if (*p) {
3091 for ( ; *p && !isspace((int)*p); p++) { }
3092 }
3093 for ( ; isspace((int)*p); p++) { }
3094 }
3095 if (offsets) {
3096 for (p = (char*)offsets; isspace((int)*p); p++) { }
3097
3098 for (npoints2 = 0; *p; npoints2++) {
3099 if (*p) {
3100 for ( ; *p && !isspace((int)*p); p++) { }
3101 }
3102 for ( ; isspace((int)*p); p++) { }
3103 }
3104 }
3105 if (npoints1 > 1) {
3106 int i;
3107 if (offsets && (npoints1 > npoints2)) npoints1 = npoints2;
3108
3109 if (!width) {
3110 width = fImage ? fImage->width : 20;
3111 }
3112 if (!height) {
3113 height = fImage ? fImage->height : 20;
3114 }
3115
3116 gradient.color = new ARGB32[npoints1];
3117 gradient.offset = new double[npoints1];
3118
3119 for (p = (char*)colors; isspace((int)*p); p++) { }
3120
3121 for (npoints1 = 0; *p; ) {
3122 pb = p;
3123
3124 if (*p) {
3125 for ( ; *p && !isspace((int)*p); p++) { }
3126 }
3127 for ( ; isspace((int)*p); p++) { }
3128
3129 col = str(pb - colors, p - pb);
3130
3131 if (parse_argb_color(col.Data(), gradient.color + npoints1) != col) {
3132 npoints1++;
3133 } else {
3134 Warning("Gradient", "Failed to parse color [%s] - defaulting to black", pb);
3135 }
3136 }
3137
3138 if (offsets) {
3139 for (p = (char*)offsets; isspace((int)*p); p++) { }
3140
3141 for (npoints2 = 0; *p; ) {
3142 pb = p;
3143
3144 if (*p) {
3145 for ( ; *p && !isspace((int)*p); p++) { }
3146 }
3147 ch = *p; *p = '\0';
3148 gradient.offset[npoints2] = strtod(pb, &pb);
3149
3150 if (pb == p) npoints2++;
3151 *p = ch;
3152 for ( ; isspace((int)*p); p++) { }
3153 }
3154 } else {
3155 for (npoints2 = 0; npoints2 < npoints1; npoints2++) {
3156 gradient.offset[npoints2] = (double)npoints2 / (npoints1 - 1);
3157 }
3158 }
3159 gradient.npoints = npoints1;
3160
3161 if (npoints2 && (gradient.npoints > npoints2)) {
3162 gradient.npoints = npoints2;
3163 }
3164 if (reverse) {
3165 for (i = 0; i < gradient.npoints/2; i++) {
3166 int i2 = gradient.npoints - 1 - i;
3167 ARGB32 c = gradient.color[i];
3168 double o = gradient.offset[i];
3169 gradient.color[i] = gradient.color[i2];
3170 gradient.color[i2] = c;
3171 gradient.offset[i] = gradient.offset[i2];
3172 gradient.offset[i2] = o;
3173 }
3174 for (i = 0; i < gradient.npoints; i++) {
3175 gradient.offset[i] = 1.0 - gradient.offset[i];
3176 }
3177 }
3180
3181 delete [] gradient.color;
3182 delete [] gradient.offset;
3183 }
3184
3185 if (!rendered_im) { // error
3186 Warning("Gradient", "Failed to create gradient image");
3187 return;
3188 }
3189
3190 if (!fImage) {
3192 return;
3193 }
3194
3195 ASImageLayer layers[2];
3196
3197 init_image_layers(&(layers[0]), 2);
3198 layers[0].im = fImage;
3199 layers[0].dst_x = 0;
3200 layers[0].dst_y = 0;
3201 layers[0].clip_width = fImage->width;
3202 layers[0].clip_height = fImage->height;
3203 layers[0].bevel = nullptr;
3204 layers[1].im = rendered_im;
3205 layers[1].dst_x = x;
3206 layers[1].dst_y = y;
3207 layers[1].clip_width = width;
3208 layers[1].clip_height = height;
3209 layers[1].merge_scanlines = alphablend_scanlines;
3210
3211 ASImage *merge_im = merge_layers(fgVisual, &(layers[0]), 2, fImage->width, fImage->height,
3213 if (!merge_im) {
3214 Warning("Gradient", "Failed to create merged image");
3215 return;
3216 }
3217
3219 DestroyImage();
3220 fImage = merge_im;
3221 UnZoom();
3222}
3223
3224////////////////////////////////////////////////////////////////////////////////
3225/// Make component hilite.
3226/// (used internally)
3227
3229{
3230 if (cmp < 51) {
3231 cmp = 51;
3232 }
3233 cmp = (cmp * 12) / 10;
3234
3235 return (cmp > 255) ? 255 : cmp;
3236}
3237
3238////////////////////////////////////////////////////////////////////////////////
3239/// Calculate highlite color.
3240/// (used internally)
3241
3243{
3244 return ((MakeComponentHilite((background>>24) & 0x000000FF) << 24) & 0xFF000000) |
3245 ((MakeComponentHilite((background & 0x00FF0000) >> 16) << 16) & 0x00FF0000) |
3246 ((MakeComponentHilite((background & 0x0000FF00) >> 8) << 8) & 0x0000FF00) |
3247 ((MakeComponentHilite((background & 0x000000FF))) & 0x000000FF);
3248}
3249
3250////////////////////////////////////////////////////////////////////////////////
3251/// Calculate shadow color.
3252/// (used internally)
3253
3255{
3256 return (background >> 1) & 0x7F7F7F7F;
3257}
3258
3259////////////////////////////////////////////////////////////////////////////////
3260/// Get average.
3261/// (used internally)
3262
3264{
3265 CARD16 a, r, g, b;
3266
3268 a = (a<<3)/10;
3270 r = (r<<3)/10;
3272 g = (g<<3)/10;
3274 b = (b<<3)/10;
3275
3276 return MAKE_ARGB32(a, r, g, b);
3277}
3278
3279
3280////////////////////////////////////////////////////////////////////////////////
3281/// Bevel is used to create 3D effect while drawing buttons, or any other
3282/// image that needs to be framed. Bevel is drawn using 2 primary colors:
3283/// one for top and left sides - hi color, and another for bottom and
3284/// right sides - low color. Bevel can be drawn over existing image or
3285/// as newly created, as it is shown in code below:
3286/// ~~~ {.cpp}
3287/// TImage *img = TImage::Create();
3288/// img->Bevel(0, 0, 400, 300, "#dddddd", "#000000", 3);
3289/// ~~~
3290
3292 const char *hi_color, const char *lo_color, UShort_t thick,
3293 Bool_t reverse)
3294{
3295 if (!InitVisual()) {
3296 Warning("Bevel", "Visual not initiated");
3297 return;
3298 }
3299
3301 bevel.type = 0;
3302
3306
3307 if (reverse) {
3308 bevel.lo_color = hi;
3309 bevel.lolo_color = GetHilite(hi);
3310 bevel.hi_color = lo;
3311 bevel.hihi_color = GetShadow(lo);
3312 } else {
3313 bevel.hi_color = hi;
3314 bevel.hihi_color = GetHilite(hi);
3315 bevel.lo_color = lo;
3316 bevel.lolo_color = GetShadow(lo);
3317 }
3318 bevel.hilo_color = GetAverage(hi, lo);
3319
3320 int extra_hilite = 2;
3321 bevel.left_outline = bevel.top_outline = bevel.right_outline = bevel.bottom_outline = thick;
3322 bevel.left_inline = bevel.top_inline = bevel.right_inline = bevel.bottom_inline = extra_hilite + 1;
3323
3324 if (bevel.top_outline > 1) {
3325 bevel.top_inline += bevel.top_outline - 1;
3326 }
3327
3328 if (bevel.left_outline > 1) {
3329 bevel.left_inline += bevel.left_outline - 1;
3330 }
3331
3332 if (bevel.right_outline > 1) {
3333 bevel.right_inline += bevel.right_outline - 1;
3334 }
3335
3336 if (bevel.bottom_outline > 1) {
3337 bevel.bottom_inline += bevel.bottom_outline - 1;
3338 }
3339
3341 ARGB32 fill = ((hi>>24) != 0xff) || ((lo>>24) != 0xff) ? bevel.hilo_color : (bevel.hilo_color | 0xff000000);
3342
3343 if (!fImage) {
3344 fImage = create_asimage(width ? width : 20, height ? height : 20, 0);
3345
3346 if (!fImage) {
3347 Warning("Bevel", "Failed to create image");
3348 return;
3349 }
3350
3351 x = 0;
3352 y = 0;
3353 fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, fill);
3354 }
3355
3356 width = !width ? fImage->width : width;
3357 height = !height ? fImage->height : height;
3358
3359 ASImageLayer layers[2];
3360 init_image_layers(&(layers[0]), 2);
3361
3362 layers[0].im = fImage;
3363 layers[0].dst_x = 0;
3364 layers[0].dst_y = 0;
3365 layers[0].clip_width = fImage->width;
3366 layers[0].clip_height = fImage->height;
3367 layers[0].bevel = nullptr;
3368
3369 UInt_t w = width - (bevel.left_outline + bevel.right_outline);
3370 UInt_t h = height - (bevel.top_outline + bevel.bottom_outline);
3372
3373 if (!bevel_im) {
3374 Warning("Bevel", "Failed to create bevel image");
3375 return;
3376 }
3377
3378 layers[1].im = bevel_im;
3379 fill_asimage(fgVisual, bevel_im, 0, 0, w, h, fill);
3380
3381 layers[1].dst_x = x;
3382 layers[1].dst_y = y;
3383 layers[1].clip_width = width;
3384 layers[1].clip_height = height;
3385 layers[1].bevel = &bevel;
3386 layers[1].merge_scanlines = alphablend_scanlines;
3387
3388 merge_im = merge_layers(fgVisual, &(layers[0]), 2, fImage->width, fImage->height,
3391
3392 if (!merge_im) {
3393 Warning("Bevel", "Failed to image");
3394 return;
3395 }
3396
3397 DestroyImage();
3398 fImage = merge_im;
3399 UnZoom();
3400}
3401
3402
3403////////////////////////////////////////////////////////////////////////////////
3404/// Enlarge image, padding it with specified color on each side in
3405/// accordance with requested geometry.
3406
3407void TASImage::Pad(const char *col, UInt_t l, UInt_t r, UInt_t t, UInt_t b)
3408{
3409 Int_t x, y;
3410 UInt_t w, h;
3411
3412 if (!InitVisual()) {
3413 Warning("Pad", "Visual not initiated");
3414 return;
3415 }
3416
3417 if (!fImage) {
3418 fImage = create_asimage(100, 100, 0);
3419
3420 if (!fImage) {
3421 Warning("Pad", "Failed to create image");
3422 return;
3423 }
3424
3425 fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, ARGB32_White);
3426 }
3427
3428 ARGB32 color = ARGB32_White;
3429 parse_argb_color(col, &color);
3430
3431 x = l;
3432 y = t;
3433 w = l + fImage->width + r;
3434 h = t + fImage->height + b;
3435
3436 ASImage *img = pad_asimage(fgVisual, fImage, x, y, w, h, color,
3438
3439 if (!img) {
3440 Warning("Pad", "Failed to create output image");
3441 return;
3442 }
3443
3444 DestroyImage();
3445 fImage = img;
3446 UnZoom();
3448}
3449
3450
3451////////////////////////////////////////////////////////////////////////////////
3452/// Crop an image.
3453
3455{
3456 if (!InitVisual()) {
3457 Warning("Crop", "Visual not initiated");
3458 return;
3459 }
3460
3461 if (!fImage) {
3462 Warning("Crop", "No image");
3463 return;
3464 }
3465
3466 x = x < 0 ? 0 : x;
3467 y = y < 0 ? 0 : y;
3468
3469 width = x + width > fImage->width ? fImage->width - x : width;
3470 height = y + height > fImage->height ? fImage->height - y : height;
3471
3472 if ((width == fImage->width) && (height == fImage->height)) {
3473 Warning("Crop", "input size larger than image");
3474 return;
3475 }
3477 x, y, width, height, nullptr);
3478
3479 if (!imdec) {
3480 Warning("Crop", "Failed to start image decoding");
3481 return;
3482 }
3483
3485
3486 if (!img) {
3487 delete [] imdec;
3488 Warning("Crop", "Failed to create image");
3489 return;
3490 }
3491
3494
3495 if (!imout) {
3496 Warning("Crop", "Failed to start image output");
3498 if (imdec) delete [] imdec;
3499 return;
3500 }
3501
3502#ifdef HAVE_MMX
3503 mmx_init();
3504#endif
3505
3506 for (UInt_t i = 0; i < height; i++) {
3507 imdec->decode_image_scanline(imdec);
3508 imout->output_image_scanline(imout, &(imdec->buffer), 1);
3509 }
3510
3513
3514#ifdef HAVE_MMX
3515 mmx_off();
3516#endif
3517
3518 DestroyImage();
3519 fImage = img;
3520 UnZoom();
3522}
3523
3524////////////////////////////////////////////////////////////////////////////////
3525/// Append image.
3526///
3527/// option:
3528/// - "+" - appends to the right side
3529/// - "/" - appends to the bottom
3530
3531void TASImage::Append(const TImage *im, const char *option, const char *color )
3532{
3533 if (!im) return;
3534
3535 if (!InitVisual()) {
3536 Warning("Append", "Visual not initiated");
3537 return;
3538 }
3539
3540 if (!fImage) {
3541 fImage = ((TASImage*)im)->fImage;
3542 return;
3543 }
3544
3545 TString opt = option;
3546 opt.Strip();
3547
3548 UInt_t width = fImage->width;
3549 UInt_t height = fImage->height;
3550
3551 if (opt == "+") {
3552 Pad(color, 0, im->GetWidth(), 0, 0);
3553 Merge(im, "alphablend", width, 0);
3554 } else if (opt == "/") {
3555 Pad(color, 0, 0, 0, im->GetHeight());
3556 Merge(im, "alphablend", 0, height);
3557 } else {
3558 return;
3559 }
3560
3561 UnZoom();
3562}
3563
3564////////////////////////////////////////////////////////////////////////////////
3565/// BeginPaint initializes internal array[width x height] of ARGB32 pixel
3566/// values.
3567///
3568/// That provides quick access to image during paint operations.
3569/// To RLE compress image one needs to call EndPaint method when painting
3570/// is over.
3571
3573{
3574 if (!InitVisual()) {
3575 Warning("BeginPaint", "Visual not initiated");
3576 return;
3577 }
3578
3579 if (!fImage) {
3580 return;
3581 }
3582
3583 fPaintMode = mode;
3584
3585 if (!fPaintMode || fImage->alt.argb32) {
3586 return;
3587 }
3588
3589 ASImage *img = tile_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height,
3591
3592 if (!img) {
3593 Warning("BeginPaint", "Failed to create image");
3594 return;
3595 }
3596
3597 DestroyImage();
3598 fImage = img;
3599}
3600
3601////////////////////////////////////////////////////////////////////////////////
3602/// EndPaint does internal RLE compression of image data.
3603
3605{
3606 if (!fImage) {
3607 Warning("EndPaint", "no image");
3608 return;
3609 }
3610
3611 if (!fImage->alt.argb32) return;
3612
3613 ASImage *img = tile_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height,
3615
3616 if (!img) {
3617 Warning("EndPaint", "Failed to create image");
3618 return;
3619 }
3620
3622 DestroyImage();
3623 fImage = img;
3624}
3625
3626////////////////////////////////////////////////////////////////////////////////
3627/// Return a pointer to internal array[width x height] of ARGB32 values
3628/// This array is directly accessible. That allows to manipulate/change the
3629/// image.
3630
3632{
3633 if (!fImage) {
3634 Warning("GetArgbArray", "no image");
3635 return nullptr;
3636 }
3637
3639 if (!img) return nullptr;
3640
3641 if (!img->alt.argb32) {
3642 if (fScaledImage) {
3645 } else {
3646 BeginPaint();
3647 img = fImage;
3648 }
3649 }
3650
3651 return (UInt_t *)img->alt.argb32;
3652}
3653
3654////////////////////////////////////////////////////////////////////////////////
3655/// Return a pointer to an array[width x height] of RGBA32 values.
3656/// This array is created from internal ARGB32 array,
3657/// must be deleted after usage.
3658
3660{
3661 if (!fImage) {
3662 Warning("GetRgbaArray", "no image");
3663 return nullptr;
3664 }
3665
3667 if (!img) return nullptr;
3668
3669 if (!img->alt.argb32) {
3670 if (fScaledImage) {
3673 } else {
3674 BeginPaint();
3675 img = fImage;
3676 }
3677 }
3678
3679 UInt_t i, j;
3680 Int_t y = 0;
3681 Int_t idx = 0;
3682 UInt_t a, rgb, rgba, argb;
3683
3684 UInt_t *ret = new UInt_t[img->width*img->height];
3685
3686 for (i = 0; i < img->height; i++) {
3687 for (j = 0; j < img->width; j++) {
3688 idx = Idx(y + j);
3689 argb = img->alt.argb32[idx];
3690 a = argb >> 24;
3691 rgb = argb & 0x00ffffff;
3692 rgba = (rgb << 8) + a;
3693 ret[idx] = rgba;
3694 }
3695 y += img->width;
3696 }
3697
3698 return ret;
3699}
3700
3701////////////////////////////////////////////////////////////////////////////////
3702/// Return a pointer to scan-line.
3703
3705{
3706 if (!fImage) {
3707 Warning("GetScanline", "no image");
3708 return nullptr;
3709 }
3710
3712 CARD32 *ret = new CARD32[img->width];
3713
3715 0, y, img->width, 1, nullptr);
3716
3717 if (!imdec) {
3718 delete [] ret;
3719 Warning("GetScanline", "Failed to start image decoding");
3720 return nullptr;
3721 }
3722
3723#ifdef HAVE_MMX
3724 mmx_init();
3725#endif
3726
3727 imdec->decode_image_scanline(imdec);
3728 memcpy(imdec->buffer.buffer, ret, img->width*sizeof(CARD32));
3730
3731#ifdef HAVE_MMX
3732 mmx_off();
3733#endif
3734
3735 return (UInt_t*)ret;
3736}
3737
3738
3739//______________________________________________________________________________
3740//
3741// Vector graphics
3742// a couple of macros which can be "assembler accelerated"
3743
3744#if defined(R__GNU) && defined(__i386__) && !defined(__sun)
3745#define _MEMSET_(dst, lng, val) __asm__("movl %0,%%eax \n"\
3746 "movl %1,%%edi \n" \
3747 "movl %2,%%ecx \n" \
3748 "cld \n" \
3749 "rep \n" \
3750 "stosl \n" \
3751 : /* no output registers */ \
3752 :"g" (val), "g" (dst), "g" (lng) \
3753 :"eax","edi","ecx" \
3754 )
3755
3756#else
3757 #define _MEMSET_(dst, lng, val) do {\
3758 for( UInt_t j=0; j < lng; j++) *((dst)+j) = val; } while (0)
3759
3760#endif
3761
3762#define FillSpansInternal(npt, ppt, widths, color) do {\
3763 UInt_t yy = ppt[0].fY*fImage->width;\
3764 for (UInt_t i = 0; i < npt; i++) {\
3765 _MEMSET_(&fImage->alt.argb32[Idx(yy + ppt[i].fX)], widths[i], color);\
3766 yy += ((i+1 < npt) && (ppt[i].fY != ppt[i+1].fY) ? fImage->width : 0);\
3767 }\
3768} while (0)
3769
3770////////////////////////////////////////////////////////////////////////////////
3771/// Fill rectangle of size (width, height) at position (x,y)
3772/// within the existing image with specified color.
3773
3775{
3776
3777 if (!InitImage("FillRectangleInternal")) {
3778 return;
3779 }
3780
3781 ARGB32 color = (ARGB32)col;
3782
3783 if (width == 0) width = 1;
3784 if (height == 0) height = 1;
3785
3786 if (x < 0) {
3787 width += x;
3788 x = 0;
3789 }
3790 if (y < 0) {
3791 height += y;
3792 y = 0;
3793 }
3794
3795 Bool_t has_alpha = (color & 0xff000000) != 0xff000000;
3796
3797 x = x > (int)fImage->width ? (Int_t)fImage->width : x;
3798 y = y > (int)fImage->height ? (Int_t)fImage->height : y;
3799
3800 width = x + width > fImage->width ? fImage->width - x : width;
3801 height = y + height > fImage->height ? fImage->height - y : height;
3802
3803 if (!fImage->alt.argb32) {
3804 fill_asimage(fgVisual, fImage, x, y, width, height, color);
3805 } else {
3806 int yyy = y*fImage->width;
3807 if (!has_alpha) { // use faster memset
3808 ARGB32 *p0 = fImage->alt.argb32 + yyy + x;
3809 ARGB32 *p = p0;
3810 for (UInt_t i = 0; i < height; i++) {
3811 _MEMSET_(p, width, color);
3812 p += fImage->width;
3813 }
3814 } else {
3815 for (UInt_t i = y; i < y + height; i++) {
3816 int j = x + width;
3817 while (j > x) {
3818 j--;
3819 _alphaBlend(&fImage->alt.argb32[Idx(yyy + j)], &color);
3820 }
3821 yyy += fImage->width;
3822 }
3823 }
3824 }
3825}
3826
3827////////////////////////////////////////////////////////////////////////////////
3828/// Fill rectangle of size (width, height) at position (x,y)
3829/// within the existing image with specified color.
3830///
3831/// To create new image with Fill method the following code can be used:
3832/// ~~~ {.cpp}
3833/// TImage *img = TImage::Create();
3834/// img->Fill("#FF00FF", 0, 0, 400, 300);
3835/// ~~~
3836
3838{
3839 if (!InitVisual()) {
3840 Warning("FillRectangle", "Visual not initiated");
3841 return;
3842 }
3843
3844 ARGB32 color = ARGB32_White;
3845
3846 if (col) {
3847 parse_argb_color(col, &color);
3848 }
3849
3850 if (!fImage) {
3851 fImage = create_asimage(width ? width : 20, height ? height : 20, 0);
3852 x = 0;
3853 y = 0;
3854 }
3855
3857 UnZoom();
3858}
3859
3860////////////////////////////////////////////////////////////////////////////////
3861/// Draw a vertical line.
3862
3864{
3865 if (!InitImage("DrawVLine")) {
3866 return;
3867 }
3868
3869 ARGB32 color = (ARGB32)col;
3870 UInt_t half = 0;
3871
3872 if (!thick) thick = 1;
3873
3874 if (thick > 1) {
3875 half = thick >> 1;
3876 if (x > half) {
3877 x = x - half;
3878 } else {
3879 x = 0;
3880 thick += (x - half);
3881 }
3882 }
3883
3884 y2 = y2 >= fImage->height ? fImage->height - 1 : y2;
3885 y1 = y1 >= fImage->height ? fImage->height - 1 : y1;
3886 x = x + thick >= fImage->width ? fImage->width - thick - 1 : x;
3887
3888 int yy = y1*fImage->width;
3889 for (UInt_t y = y1; y <= y2; y++) {
3890 for (UInt_t w = 0; w < thick; w++) {
3891 if (x + w < fImage->width) {
3892 _alphaBlend(&fImage->alt.argb32[Idx(yy + (x + w))], &color);
3893 }
3894 }
3895 yy += fImage->width;
3896 }
3897}
3898
3899////////////////////////////////////////////////////////////////////////////////
3900/// Draw an horizontal line.
3901
3903{
3904 if (!InitImage("DrawHLine")) {
3905 return;
3906 }
3907
3908 ARGB32 color = (ARGB32)col;
3909 UInt_t half = 0;
3910
3911 if (!thick) thick = 1;
3912
3913 if (thick > 1) {
3914 half = thick >> 1;
3915 if (y > half) {
3916 y = y - half;
3917 } else {
3918 y = 0;
3919 thick += (y - half);
3920 }
3921 }
3922
3923 y = y + thick >= fImage->height ? fImage->height - thick - 1 : y;
3924 x2 = x2 >= fImage->width ? fImage->width - 1 : x2;
3925 x1 = x1 >= fImage->width ? fImage->width - 1 : x1;
3926
3927 int yy = y*fImage->width;
3928 for (UInt_t w = 0; w < thick; w++) {
3929 for (UInt_t x = x1; x <= x2; x++) {
3930 if (y + w < fImage->height) {
3931 _alphaBlend(&fImage->alt.argb32[Idx(yy + x)], &color);
3932 }
3933 }
3934 yy += fImage->width;
3935 }
3936}
3937
3938////////////////////////////////////////////////////////////////////////////////
3939/// Draw a line.
3940
3942 const char *col, UInt_t thick)
3943{
3944 ARGB32 color = ARGB32_White;
3945 parse_argb_color(col, &color);
3946 DrawLineInternal(x1, y1, x2, y2, (UInt_t)color, thick);
3947}
3948
3949////////////////////////////////////////////////////////////////////////////////
3950/// Internal line drawing.
3951
3953 UInt_t col, UInt_t thick)
3954{
3955 int dx, dy, d;
3956 int i1, i2;
3957 int x, y, xend, yend;
3958 int xdir, ydir;
3959 int q;
3960 int idx;
3961 int yy;
3962
3963 if (!InitImage("DrawLineInternal")) {
3964 return;
3965 }
3966
3967 ARGB32 color = (ARGB32)col;
3968
3969 dx = TMath::Abs(Int_t(x2) - Int_t(x1));
3970 dy = TMath::Abs(Int_t(y2) - Int_t(y1));
3971
3972 if (!dx && !dy) return; // invisible line
3973
3974 if (!dx) {
3975 DrawVLine(x1, y2 > y1 ? y1 : y2,
3976 y2 > y1 ? y2 : y1, color, thick);
3977 return;
3978 }
3979
3980 if (!dy) {
3981 DrawHLine(y1, x2 > x1 ? x1 : x2,
3982 x2 > x1 ? x2 : x1, color, thick);
3983 return;
3984 }
3985
3986 if (thick > 1) {
3987 DrawWideLine(x1, y1, x2, y2, color, thick);
3988 return;
3989 }
3990
3991 if (dy <= dx) {
3992 UInt_t ddy = dy << 1;
3993 i1 = ddy;
3994 i2 = i1 - (dx << 1);
3995 d = i1 - dx;
3996
3997 if (x1 > x2) {
3998 x = x2;
3999 y = y2;
4000 ydir = -1;
4001 xend = x1;
4002 } else {
4003 x = x1;
4004 y = y1;
4005 ydir = 1;
4006 xend = x2;
4007 }
4008
4009 yy = y*fImage->width;
4010 _alphaBlend(&fImage->alt.argb32[Idx(yy + x)], &color);
4011 q = (y2 - y1) * ydir;
4012
4013 if (q > 0) {
4014 while (x < xend) {
4015
4016 idx = Idx(yy + x);
4017 _alphaBlend(&fImage->alt.argb32[idx], &color);
4018 x++;
4019
4020 if (d >= 0) {
4021 yy += fImage->width;
4022 d += i2;
4023 } else {
4024 d += i1;
4025 }
4026 }
4027 } else {
4028 while (x < xend) {
4029 idx = Idx(yy + x);
4030 _alphaBlend(&fImage->alt.argb32[idx], &color);
4031 x++;
4032
4033 if (d >= 0) {
4034 yy -= fImage->width;
4035 d += i2;
4036 } else {
4037 d += i1;
4038 }
4039 }
4040 }
4041 } else {
4042 UInt_t ddx = dx << 1;
4043 i1 = ddx;
4044 i2 = i1 - (dy << 1);
4045 d = i1 - dy;
4046
4047 if (y1 > y2) {
4048 y = y2;
4049 x = x2;
4050 yend = y1;
4051 xdir = -1;
4052 } else {
4053 y = y1;
4054 x = x1;
4055 yend = y2;
4056 xdir = 1;
4057 }
4058
4059 yy = y*fImage->width;
4060 _alphaBlend(&fImage->alt.argb32[Idx(yy + x)], &color);
4061 q = (x2 - x1) * xdir;
4062
4063 if (q > 0) {
4064 while (y < yend) {
4065 idx = Idx(yy + x);
4066 _alphaBlend(&fImage->alt.argb32[idx], &color);
4067 y++;
4068 yy += fImage->width;
4069
4070 if (d >= 0) {
4071 x++;
4072 d += i2;
4073 } else {
4074 d += i1;
4075 }
4076 }
4077 } else {
4078 while (y < yend) {
4079 idx = Idx(yy + x);
4080 _alphaBlend(&fImage->alt.argb32[idx], &color);
4081 y++;
4082 yy += fImage->width;
4083
4084 if (d >= 0) {
4085 x--;
4086 d += i2;
4087 } else {
4088 d += i1;
4089 }
4090 }
4091 }
4092 }
4093}
4094
4095////////////////////////////////////////////////////////////////////////////////
4096/// Draw a rectangle.
4097
4099 const char *col, UInt_t thick)
4100{
4101 if (!InitVisual()) {
4102 Warning("DrawRectangle", "Visual not initiated");
4103 return;
4104 }
4105
4106 if (!fImage) {
4107 w = w ? w : 20;
4108 h = h ? h : 20;
4109 fImage = create_asimage(w, h, 0);
4110 FillRectangle(col, 0, 0, w, h);
4111 return;
4112 }
4113
4114 if (!fImage->alt.argb32) {
4115 BeginPaint();
4116 }
4117
4118 if (!fImage->alt.argb32) {
4119 Warning("DrawRectangle", "Failed to get argb32 pixel array");
4120 return;
4121 }
4122
4123 ARGB32 color = ARGB32_White;
4124 parse_argb_color(col, &color);
4125
4126 DrawHLine(y, x, x + w, (UInt_t)color, thick);
4127 DrawVLine(x + w, y, y + h, (UInt_t)color, thick);
4128 DrawHLine(y + h, x, x + w, (UInt_t)color, thick);
4129 DrawVLine(x, y, y + h, (UInt_t)color, thick);
4130 UnZoom();
4131}
4132
4133////////////////////////////////////////////////////////////////////////////////
4134/// Draw a box.
4135
4136void TASImage::DrawBox(Int_t x1, Int_t y1, Int_t x2, Int_t y2, const char *col,
4138{
4139 Int_t x = TMath::Min(x1, x2);
4140 Int_t y = TMath::Min(y1, y2);
4141 Int_t w = TMath::Abs(x2 - x1);
4142 Int_t h = TMath::Abs(y2 - y1);
4143
4144 ARGB32 color = ARGB32_White;
4145
4146 if (!fImage) {
4147 w = w ? x+w : x+20;
4148 h = h ? y+h : y+20;
4149 fImage = create_asimage(w, h, 0);
4150 FillRectangle(col, 0, 0, w, h);
4151 return;
4152 }
4153
4154 if (x1 == x2) {
4155 parse_argb_color(col, &color);
4156 DrawVLine(x1, y1, y2, color, 1);
4157 return;
4158 }
4159
4160 if (y1 == y2) {
4161 parse_argb_color(col, &color);
4162 DrawHLine(y1, x1, x2, color, 1);
4163 return;
4164 }
4165
4166
4167 switch (mode) {
4168 case TVirtualX::kHollow:
4169 DrawRectangle(x, y, w, h, col, thick);
4170 break;
4171
4172 case TVirtualX::kFilled:
4173 FillRectangle(col, x, y, w, h);
4174 break;
4175
4176 default:
4177 FillRectangle(col, x, y, w, h);
4178 break;
4179 }
4180}
4181
4182////////////////////////////////////////////////////////////////////////////////
4183/// Draw a dashed horizontal line.
4184
4186 const char *pDash, UInt_t col, UInt_t thick)
4187{
4188 if (!InitImage("DrawDashHLine")) {
4189 return;
4190 }
4191
4192 UInt_t iDash = 0; // index of current dash
4193 int i = 0;
4194
4195 ARGB32 color = (ARGB32)col;
4196
4197 UInt_t half = 0;
4198
4199 if (thick > 1) {
4200 half = thick >> 1;
4201 if (y > half) {
4202 y = y - half;
4203 } else {
4204 y = 0;
4205 thick += (y - half);
4206 }
4207 }
4208 thick = thick <= 0 ? 1 : thick;
4209
4210 y = y + thick >= fImage->height ? fImage->height - thick - 1 : y;
4211 x2 = x2 >= fImage->width ? fImage->width - 1 : x2;
4212 x1 = x1 >= fImage->width ? fImage->width - 1 : x1;
4213
4214 // switch x1, x2
4215 UInt_t tmp = x1;
4216 x1 = x2 < x1 ? x2 : x1;
4217 x2 = x2 < tmp ? tmp : x2;
4218
4219 for (UInt_t x = x1; x <= x2; x++) {
4220 for (UInt_t w = 0; w < thick; w++) {
4221 if (y + w < fImage->height) {
4222 if ((iDash%2)==0) {
4223 _alphaBlend(&fImage->alt.argb32[Idx((y + w)*fImage->width + x)], &color);
4224 }
4225 }
4226 }
4227 i++;
4228
4229 if (i >= pDash[iDash]) {
4230 iDash++;
4231 i = 0;
4232 }
4233 if (iDash >= nDash) {
4234 iDash = 0;
4235 i = 0;
4236 }
4237 }
4238}
4239
4240////////////////////////////////////////////////////////////////////////////////
4241/// Draw a dashed vertical line.
4242
4244 const char *pDash, UInt_t col, UInt_t thick)
4245{
4246 if (!InitImage("DrawDashVLine")) {
4247 return;
4248 }
4249 UInt_t iDash = 0; // index of current dash
4250 int i = 0;
4251
4252 ARGB32 color = (ARGB32)col;
4253
4254 UInt_t half = 0;
4255
4256 if (thick > 1) {
4257 half = thick >> 1;
4258 if (x > half) {
4259 x = x - half;
4260 } else {
4261 x = 0;
4262 thick += (x - half);
4263 }
4264 }
4265 thick = thick <= 0 ? 1 : thick;
4266
4267 y2 = y2 >= fImage->height ? fImage->height - 1 : y2;
4268 y1 = y1 >= fImage->height ? fImage->height - 1 : y1;
4269
4270 // switch x1, x2
4271 UInt_t tmp = y1;
4272 y1 = y2 < y1 ? y2 : y1;
4273 y2 = y2 < tmp ? tmp : y2;
4274
4275 x = x + thick >= fImage->width ? fImage->width - thick - 1 : x;
4276
4277 int yy = y1*fImage->width;
4278 for (UInt_t y = y1; y <= y2; y++) {
4279 for (UInt_t w = 0; w < thick; w++) {
4280 if (x + w < fImage->width) {
4281 if ((iDash%2)==0) {
4282 _alphaBlend(&fImage->alt.argb32[Idx(yy + (x + w))], &color);
4283 }
4284 }
4285 }
4286 i++;
4287
4288 if (i >= pDash[iDash]) {
4289 iDash++;
4290 i = 0;
4291 }
4292 if (iDash >= nDash) {
4293 iDash = 0;
4294 i = 0;
4295 }
4296 yy += fImage->width;
4297 }
4298}
4299
4300////////////////////////////////////////////////////////////////////////////////
4301/// Draw a dashed line with one pixel width.
4302
4304 UInt_t nDash, const char *tDash, UInt_t color)
4305{
4306 if (!InitImage("DrawDashZLine")) {
4307 return;
4308 }
4309 int dx, dy, d;
4310 int i, i1, i2;
4311 int x, y, xend, yend;
4312 int xdir, ydir;
4313 int q;
4314 UInt_t iDash = 0; // index of current dash
4315 int yy;
4316 int idx;
4317
4318 dx = TMath::Abs(Int_t(x2) - Int_t(x1));
4319 dy = TMath::Abs(Int_t(y2) - Int_t(y1));
4320
4321 char *pDash = new char[nDash];
4322
4323 if (dy <= dx) {
4324 double ac = TMath::Cos(TMath::ATan2(dy, dx));
4325
4326 for (i = 0; i < (int)nDash; i++) {
4327 pDash[i] = TMath::Nint(tDash[i] * ac);
4328 }
4329
4330 UInt_t ddy = dy << 1;
4331 i1 = ddy;
4332 i2 = i1 - (dx << 1);
4333 d = i1 - dx;
4334 i = 0;
4335
4336 if (x1 > x2) {
4337 x = x2;
4338 y = y2;
4339 ydir = -1;
4340 xend = x1;
4341 } else {
4342 x = x1;
4343 y = y1;
4344 ydir = 1;
4345 xend = x2;
4346 }
4347
4348 yy = y*fImage->width;
4349 _alphaBlend(&fImage->alt.argb32[Idx(y*fImage->width + x)], &color);
4350 q = (y2 - y1) * ydir;
4351
4352 if (q > 0) {
4353 while (x < xend) {
4354 idx = Idx(yy + x);
4355 if ((iDash%2) == 0) {
4356 _alphaBlend(&fImage->alt.argb32[idx], &color);
4357 }
4358 x++;
4359 if (d >= 0) {
4360 yy += fImage->width;
4361 d += i2;
4362 } else {
4363 d += i1;
4364 }
4365
4366 i++;
4367 if (i >= pDash[iDash]) {
4368 iDash++;
4369 i = 0;
4370 }
4371 if (iDash >= nDash) {
4372 iDash = 0;
4373 i = 0;
4374 }
4375 }
4376 } else {
4377 while (x < xend) {
4378 idx = Idx(yy + x);
4379 if ((iDash%2) == 0) {
4380 _alphaBlend(&fImage->alt.argb32[idx], &color);
4381 }
4382 x++;
4383 if (d >= 0) {
4384 yy -= fImage->width;
4385 d += i2;
4386 } else {
4387 d += i1;
4388 }
4389
4390 i++;
4391 if (i >= pDash[iDash]) {
4392 iDash++;
4393 i = 0;
4394 }
4395 if (iDash >= nDash) {
4396 iDash = 0;
4397 i = 0;
4398 }
4399 }
4400 }
4401 } else {
4402 double as = TMath::Sin(TMath::ATan2(dy, dx));
4403
4404 for (i = 0; i < (int)nDash; i++) {
4405 pDash[i] = TMath::Nint(tDash[i] * as);
4406 }
4407
4408 UInt_t ddx = dx << 1;
4409 i1 = ddx;
4410 i2 = i1 - (dy << 1);
4411 d = i1 - dy;
4412 i = 0;
4413
4414 if (y1 > y2) {
4415 y = y2;
4416 x = x2;
4417 yend = y1;
4418 xdir = -1;
4419 } else {
4420 y = y1;
4421 x = x1;
4422 yend = y2;
4423 xdir = 1;
4424 }
4425
4426 yy = y*fImage->width;
4427 _alphaBlend(&fImage->alt.argb32[Idx(y*fImage->width + x)], &color);
4428 q = (x2 - x1) * xdir;
4429
4430 if (q > 0) {
4431 while (y < yend) {
4432 idx = Idx(yy + x);
4433 if ((iDash%2) == 0) {
4434 _alphaBlend(&fImage->alt.argb32[idx], &color);
4435 }
4436 y++;
4437 yy += fImage->width;
4438
4439 if (d >= 0) {
4440 x++;
4441 d += i2;
4442 } else {
4443 d += i1;
4444 }
4445
4446 i++;
4447 if (i >= pDash[iDash]) {
4448 iDash++;
4449 i = 0;
4450 }
4451 if (iDash >= nDash) {
4452 iDash = 0;
4453 i = 0;
4454 }
4455 }
4456 } else {
4457 while (y < yend) {
4458 idx = Idx(yy + x);
4459 if ((iDash%2) == 0) {
4460 _alphaBlend(&fImage->alt.argb32[idx], &color);
4461 }
4462 y++;
4463 yy += fImage->width;
4464
4465 if (d >= 0) {
4466 x--;
4467 d += i2;
4468 } else {
4469 d += i1;
4470 }
4471
4472 i++;
4473 if (i >= pDash[iDash]) {
4474 iDash++;
4475 i = 0;
4476 }
4477 if (iDash >= nDash) {
4478 iDash = 0;
4479 i = 0;
4480 }
4481 }
4482 }
4483 }
4484 delete [] pDash;
4485}
4486
4487////////////////////////////////////////////////////////////////////////////////
4488/// Draw a dashed line with thick pixel width.
4489
4491 UInt_t nDash, const char *tDash, UInt_t color, UInt_t thick)
4492{
4493 if (!InitImage("DrawDashZTLine")) {
4494 return;
4495 }
4496 int dx, dy;
4497 int i;
4498 double x, y, xend=0, yend=0, x0, y0;
4499 int xdir, ydir;
4500 int q;
4501 UInt_t iDash = 0; // index of current dash
4502
4503 dx = TMath::Abs(Int_t(x2) - Int_t(x1));
4504 dy = TMath::Abs(Int_t(y2) - Int_t(y1));
4505
4506 double *xDash = new double[nDash];
4507 double *yDash = new double[nDash];
4508 double a = TMath::ATan2(dy, dx);
4509 double ac = TMath::Cos(a);
4510 double as = TMath::Sin(a);
4511
4512 for (i = 0; i < (int)nDash; i++) {
4513 xDash[i] = tDash[i] * ac;
4514 yDash[i] = tDash[i] * as;
4515
4516 // dirty trick (must be fixed)
4517 if ((i%2) == 0) {
4518 xDash[i] = xDash[i]/2;
4519 yDash[i] = yDash[i]/2;
4520 } else {
4521 xDash[i] = xDash[i]*2;
4522 yDash[i] = yDash[i]*2;
4523 }
4524 }
4525
4526 if (dy <= dx) {
4527 if (x1 > x2) {
4528 x = x2;
4529 y = y2;
4530 ydir = -1;
4531 xend = x1;
4532 } else {
4533 x = x1;
4534 y = y1;
4535 ydir = 1;
4536 xend = x2;
4537 }
4538
4539 q = (y2 - y1) * ydir;
4540 x0 = x;
4541 y0 = y;
4542 iDash = 0;
4543 yend = y + q;
4544
4545 if (q > 0) {
4546 while ((x < xend) && (y < yend)) {
4547 x += xDash[iDash];
4548 y += yDash[iDash];
4549
4550 if ((iDash%2) == 0) {
4552 TMath::Nint(x), TMath::Nint(y), color, thick);
4553 } else {
4554 x0 = x;
4555 y0 = y;
4556 }
4557
4558 iDash++;
4559
4560 if (iDash >= nDash) {
4561 iDash = 0;
4562 }
4563 }
4564 } else {
4565 while ((x < xend) && (y > yend)) {
4566 x += xDash[iDash];
4567 y -= yDash[iDash];
4568
4569 if ((iDash%2) == 0) {
4571 TMath::Nint(x), TMath::Nint(y), color, thick);
4572 } else {
4573 x0 = x;
4574 y0 = y;
4575 }
4576
4577 iDash++;
4578
4579 if (iDash >= nDash) {
4580 iDash = 0;
4581 }
4582 }
4583 }
4584 } else {
4585
4586 if (y1 > y2) {
4587 y = y2;
4588 x = x2;
4589 yend = y1;
4590 xdir = -1;
4591 } else {
4592 y = y1;
4593 x = x1;
4594 yend = y2;
4595 xdir = 1;
4596 }
4597
4598 q = (x2 - x1) * xdir;
4599 x0 = x;
4600 y0 = y;
4601 iDash = 0;
4602 xend = x + q;
4603
4604 if (q > 0) {
4605 while ((x < xend) && (y < yend)) {
4606 x += xDash[iDash];
4607 y += yDash[iDash];
4608
4609 if ((iDash%2) == 0) {
4611 TMath::Nint(x), TMath::Nint(y), color, thick);
4612 } else {
4613 x0 = x;
4614 y0 = y;
4615 }
4616
4617 iDash++;
4618
4619 if (iDash >= nDash) {
4620 iDash = 0;
4621 }
4622 }
4623 } else {
4624 while ((x > xend) && (y < yend)) {
4625 x -= xDash[iDash];
4626 y += yDash[iDash];
4627
4628 if ((iDash%2) == 0) {
4630 TMath::Nint(x), TMath::Nint(y), color, thick);
4631 } else {
4632 x0 = x;
4633 y0 = y;
4634 }
4635
4636 iDash++;
4637
4638 if (iDash >= nDash) {
4639 iDash = 0;
4640 }
4641 }
4642 }
4643 }
4644 delete [] xDash;
4645 delete [] yDash;
4646}
4647
4648////////////////////////////////////////////////////////////////////////////////
4649/// Draw a dashed line.
4650
4652 const char *pDash, const char *col, UInt_t thick)
4653
4654{
4655 if (!InitImage("DrawDashLine")) {
4656 return;
4657 }
4658
4659 if ((nDash < 2) || !pDash || (nDash%2)) {
4660 Warning("DrawDashLine", "Wrong input parameters n=%d %ld", nDash, (Long_t)sizeof(pDash)-1);
4661 return;
4662 }
4663
4664 ARGB32 color = ARGB32_White;
4665 parse_argb_color(col, &color);
4666
4667 if (x1 == x2) {
4668 DrawDashVLine(x1, y1, y2, nDash, pDash, (UInt_t)color, thick);
4669 } else if (y1 == y2) {
4670 DrawDashHLine(y1, x1, x2, nDash, pDash, (UInt_t)color, thick);
4671 } else {
4672 if (thick < 2) DrawDashZLine(x1, y1, x2, y2, nDash, pDash, (UInt_t)color);
4673 else DrawDashZTLine(x1, y1, x2, y2, nDash, pDash, (UInt_t)color, thick);
4674 }
4675}
4676
4677////////////////////////////////////////////////////////////////////////////////
4678/// Draw a polyline.
4679
4682{
4683 ARGB32 color = ARGB32_White;
4684 parse_argb_color(col, &color);
4685
4686 Int_t x0 = xy[0].GetX();
4687 Int_t y0 = xy[0].GetY();
4688 Int_t x = 0;
4689 Int_t y = 0;
4690
4691 for (UInt_t i = 1; i < nn; i++) {
4692 x = (mode == kCoordModePrevious) ? x + xy[i].GetX() : xy[i].GetX();
4693 y = (mode == kCoordModePrevious) ? y + xy[i].GetY() : xy[i].GetY();
4694
4695 DrawLineInternal(x0, y0, x, y, (UInt_t)color, thick);
4696
4697 x0 = x;
4698 y0 = y;
4699 }
4700}
4701
4702////////////////////////////////////////////////////////////////////////////////
4703/// Draw a point at the specified position.
4704
4705void TASImage::PutPixel(Int_t x, Int_t y, const char *col)
4706{
4707 if (!InitImage("PutPixel")) {
4708 return;
4709 }
4710
4711 ARGB32 color;
4712 parse_argb_color(col, &color);
4713
4714 if ((x < 0) || (y < 0) || (x >= (int)fImage->width) || (y >= (int)fImage->height)) {
4715 Warning("PutPixel", "Out of range width=%d x=%d, height=%d y=%d",
4716 fImage->width, x, fImage->height, y);
4717 return;
4718 }
4719 _alphaBlend(&fImage->alt.argb32[Idx(y*fImage->width + x)], &color);
4720}
4721
4722////////////////////////////////////////////////////////////////////////////////
4723/// Draw a poly point.
4724
4726{
4727 if (!InitImage("PolyPoint")) {
4728 return;
4729 }
4730
4731 if (!npt || !ppt) {
4732 Warning("PolyPoint", "No points specified");
4733 return;
4734 }
4735
4736 TPoint *ipt = nullptr;
4737 UInt_t i = 0;
4738 ARGB32 color;
4739 parse_argb_color(col, &color);
4740
4741 //make pointlist origin relative
4742 if (mode == kCoordModePrevious) {
4743 ipt = new TPoint[npt];
4744
4745 for (i = 0; i < npt; i++) {
4746 ipt[i].fX += ppt[i].fX;
4747 ipt[i].fY += ppt[i].fY;
4748 }
4749 }
4750 int x, y;
4751
4752 for (i = 0; i < npt; i++) {
4753 x = ipt ? ipt[i].fX : ppt[i].fX;
4754 y = ipt ? ipt[i].fY : ppt[i].fY;
4755
4756 if ((x < 0) || (y < 0) || (x >= (int)fImage->width) || (y >= (int)fImage->height)) {
4757 continue;
4758 }
4759 _alphaBlend(&fImage->alt.argb32[Idx(y*fImage->width + x)], &color);
4760 }
4761
4762 if (ipt) {
4763 delete [] ipt;
4764 }
4765}
4766
4767////////////////////////////////////////////////////////////////////////////////
4768/// Draw segments.
4769
4771{
4772 if (!nseg || !seg) {
4773 Warning("DrawSegments", "Invalid data nseg=%d seg=0x%zx", nseg, (size_t)seg);
4774 return;
4775 }
4776
4777 TPoint pt[2];
4778
4779 for (UInt_t i = 0; i < nseg; i++) {
4780 pt[0].fX = seg->fX1;
4781 pt[1].fX = seg->fX2;
4782 pt[0].fY = seg->fY1;
4783 pt[1].fY = seg->fY2;
4784
4786 seg++;
4787 }
4788}
4789
4790////////////////////////////////////////////////////////////////////////////////
4791/// Fill spans with specified color or/and stipple.
4792
4794 const char *stipple, UInt_t w, UInt_t h)
4795{
4796 if (!InitImage("FillSpans")) {
4797 return;
4798 }
4799
4800 if (!npt || !ppt || !widths || (stipple && (!w || !h))) {
4801 Warning("FillSpans", "Invalid input data npt=%d ppt=0x%zx col=%s widths=0x%zx stipple=0x%zx w=%d h=%d",
4802 npt, (size_t)ppt, col, (size_t)widths, (size_t)stipple, w, h);
4803 return;
4804 }
4805
4806 ARGB32 color;
4807 parse_argb_color(col, &color);
4808 Int_t idx = 0;
4809 UInt_t x = 0;
4810 UInt_t yy;
4811
4812 for (UInt_t i = 0; i < npt; i++) {
4813 yy = ppt[i].fY*fImage->width;
4814 for (UInt_t j = 0; j < widths[i]; j++) {
4815 if ((ppt[i].fX >= (Int_t)fImage->width) || (ppt[i].fX < 0) ||
4816 (ppt[i].fY >= (Int_t)fImage->height) || (ppt[i].fY < 0)) continue;
4817
4818 x = ppt[i].fX + j;
4819 idx = Idx(yy + x);
4820
4821 if (!stipple) {
4822 _alphaBlend(&fImage->alt.argb32[idx], &color);
4823 } else {
4824 Int_t ii = (ppt[i].fY%h)*w + x%w;
4825
4826 if (stipple[ii >> 3] & (1 << (ii%8))) {
4827 _alphaBlend(&fImage->alt.argb32[idx], &color);
4828 }
4829 }
4830 }
4831 }
4832}
4833
4834////////////////////////////////////////////////////////////////////////////////
4835/// Fill spans with tile image.
4836
4838{
4839 if (!InitImage("FillSpans")) {
4840 return;
4841 }
4842
4843 if (!npt || !ppt || !widths || !tile) {
4844 Warning("FillSpans", "Invalid input data npt=%d ppt=0x%zx widths=0x%zx tile=0x%zx",
4845 npt, (size_t)ppt, (size_t)widths, (size_t)tile);
4846 return;
4847 }
4848
4849 Int_t idx = 0;
4850 Int_t ii = 0;
4851 UInt_t x = 0;
4852 UInt_t *arr = tile->GetArgbArray();
4853 if (!arr) return;
4854 UInt_t xx = 0;
4855 UInt_t yy = 0;
4856
4857 for (UInt_t i = 0; i < npt; i++) {
4858 UInt_t yyy = ppt[i].fY*fImage->width;
4859
4860 for (UInt_t j = 0; j < widths[i]; j++) {
4861 if ((ppt[i].fX >= (Int_t)fImage->width) || (ppt[i].fX < 0) ||
4862 (ppt[i].fY >= (Int_t)fImage->height) || (ppt[i].fY < 0)) continue;
4863 x = ppt[i].fX + j;
4864 idx = Idx(yyy + x);
4865 xx = x%tile->GetWidth();
4866 yy = ppt[i].fY%tile->GetHeight();
4867 ii = yy*tile->GetWidth() + xx;
4868 _alphaBlend(&fImage->alt.argb32[idx], &arr[ii]);
4869 }
4870 }
4871}
4872
4873////////////////////////////////////////////////////////////////////////////////
4874/// Crop spans.
4875
4877{
4878 if (!InitImage("CropSpans")) {
4879 return;
4880 }
4881
4882 if (!npt || !ppt || !widths) {
4883 Warning("CropSpans", "No points specified npt=%d ppt=0x%zx widths=0x%zx", npt, (size_t)ppt, (size_t)widths);
4884 return;
4885 }
4886
4887 int y0 = ppt[0].fY;
4888 int y1 = ppt[npt-1].fY;
4889 UInt_t y = 0;
4890 UInt_t x = 0;
4891 UInt_t i = 0;
4892 UInt_t idx = 0;
4893 UInt_t sz = fImage->width*fImage->height;
4894 UInt_t yy = y*fImage->width;
4895
4896 for (y = 0; (int)y < y0; y++) {
4897 for (x = 0; x < fImage->width; x++) {
4898 idx = Idx(yy + x);
4899 if (idx < sz) fImage->alt.argb32[idx] = 0;
4900 }
4901 yy += fImage->width;
4902 }
4903
4904 for (i = 0; i < npt; i++) {
4905 for (x = 0; (int)x < ppt[i].fX; x++) {
4906 idx = Idx(ppt[i].fY*fImage->width + x);
4907 if (idx < sz) fImage->alt.argb32[idx] = 0;
4908 }
4909 for (x = ppt[i].fX + widths[i] + 1; x < fImage->width; x++) {
4910 idx = Idx(ppt[i].fY*fImage->width + x);
4911 if (idx < sz) fImage->alt.argb32[idx] = 0;
4912 }
4913 }
4914
4915 yy = y1*fImage->width;
4916 for (y = y1; y < fImage->height; y++) {
4917 for (x = 0; x < fImage->width; x++) {
4918 idx = Idx(yy + x);
4919 if (idx < sz) fImage->alt.argb32[idx] = 0;
4920 }
4921 yy += fImage->width;
4922 }
4923}
4924
4925////////////////////////////////////////////////////////////////////////////////
4926/// Copy source region to the destination image. Copy is done according
4927/// to specified function:
4928/// ~~~ {.cpp}
4929/// enum EGraphicsFunction {
4930/// kGXclear = 0, // 0
4931/// kGXand, // src AND dst
4932/// kGXandReverse, // src AND NOT dst
4933/// kGXcopy, // src (default)
4934/// kGXandInverted, // NOT src AND dst
4935/// kGXnoop, // dst
4936/// kGXxor, // src XOR dst
4937/// kGXor, // src OR dst
4938/// kGXnor, // NOT src AND NOT dst
4939/// kGXequiv, // NOT src XOR dst
4940/// kGXinvert, // NOT dst
4941/// kGXorReverse, // src OR NOT dst
4942/// kGXcopyInverted, // NOT src
4943/// kGXorInverted, // NOT src OR dst
4944/// kGXnand, // NOT src OR NOT dst
4945/// kGXset // 1
4946/// };
4947/// ~~~
4948
4951{
4952 if (!InitVisual()) {
4953 Warning("CopyArea", "Visual not initiated");
4954 return;
4955 }
4956
4957 if (!fImage) {
4958 Warning("CopyArea", "no image");
4959 return;
4960 }
4961 if (!dst) return;
4962
4963 ASImage *out = ((TASImage*)dst)->GetImage();
4964
4965 int x = 0;
4966 int y = 0;
4967 int idx = 0;
4968 int idx2 = 0;
4969 xsrc = xsrc < 0 ? 0 : xsrc;
4970 ysrc = ysrc < 0 ? 0 : ysrc;
4971
4972 if ((xsrc >= (int)fImage->width) || (ysrc >= (int)fImage->height)) return;
4973
4974 w = xsrc + w > fImage->width ? fImage->width - xsrc : w;
4975 h = ysrc + h > fImage->height ? fImage->height - ysrc : h;
4976 UInt_t yy = (ysrc + y)*fImage->width;
4977
4978 if (!fImage->alt.argb32) {
4979 BeginPaint();
4980 }
4981 if (!out->alt.argb32) {
4982 dst->BeginPaint();
4983 out = ((TASImage*)dst)->GetImage();
4984 }
4985
4986 if (fImage->alt.argb32 && out->alt.argb32) {
4987 for (y = 0; y < (int)h; y++) {
4988 for (x = 0; x < (int)w; x++) {
4989 idx = Idx(yy + x + xsrc);
4990 if ((x + xdst < 0) || (ydst + y < 0) ||
4991 (x + xdst >= (int)out->width) || (y + ydst >= (int)out->height) ) continue;
4992
4993 idx2 = Idx((ydst + y)*out->width + x + xdst);
4994
4995 switch ((EGraphicsFunction)gfunc) {
4996 case kGXclear:
4997 out->alt.argb32[idx2] = 0;
4998 break;
4999 case kGXand:
5000 out->alt.argb32[idx2] &= fImage->alt.argb32[idx];
5001 break;
5002 case kGXandReverse:
5003 out->alt.argb32[idx2] = fImage->alt.argb32[idx] & (~out->alt.argb32[idx2]);
5004 break;
5005 case kGXandInverted:
5006 out->alt.argb32[idx2] &= ~fImage->alt.argb32[idx];
5007 break;
5008 case kGXnoop:
5009 break;
5010 case kGXxor:
5011 out->alt.argb32[idx2] ^= fImage->alt.argb32[idx];
5012 break;
5013 case kGXor:
5014 out->alt.argb32[idx2] |= fImage->alt.argb32[idx];
5015 break;
5016 case kGXnor:
5017 out->alt.argb32[idx2] = (~fImage->alt.argb32[idx]) & (~out->alt.argb32[idx2]);
5018 break;
5019 case kGXequiv:
5020 out->alt.argb32[idx2] ^= ~fImage->alt.argb32[idx];
5021 break;
5022 case kGXinvert:
5023 out->alt.argb32[idx2] = ~out->alt.argb32[idx2];
5024 break;
5025 case kGXorReverse:
5026 out->alt.argb32[idx2] = fImage->alt.argb32[idx] | (~out->alt.argb32[idx2]);
5027 break;
5028 case kGXcopyInverted:
5029 out->alt.argb32[idx2] = ~fImage->alt.argb32[idx];
5030 break;
5031 case kGXorInverted:
5032 out->alt.argb32[idx2] |= ~fImage->alt.argb32[idx];
5033 break;
5034 case kGXnand:
5035 out->alt.argb32[idx2] = (~fImage->alt.argb32[idx]) | (~out->alt.argb32[idx2]);
5036 break;
5037 case kGXset:
5038 out->alt.argb32[idx2] = 0xFFFFFFFF;
5039 break;
5040 case kGXcopy:
5041 default:
5042 out->alt.argb32[idx2] = fImage->alt.argb32[idx];
5043 break;
5044 }
5045 }
5046 yy += fImage->width;
5047 }
5048 }
5049}
5050
5051////////////////////////////////////////////////////////////////////////////////
5052/// Draw a cell array.
5053///
5054/// \param[in] x1,y1 : left down corner
5055/// \param[in] x2,y2 : right up corner
5056/// \param[in] nx,ny : array size
5057/// \param[in] ic : array of ARGB32 colors
5058///
5059/// Draw a cell array. The drawing is done with the pixel precision
5060/// if (X2-X1)/NX (or Y) is not a exact pixel number the position of
5061/// the top right corner may be wrong.
5062
5064 Int_t ny, UInt_t *ic)
5065{
5066 int i, j, ix, iy, w, h;
5067
5068 ARGB32 color = 0xFFFFFFFF;
5069 ARGB32 icol;
5070
5071 w = TMath::Max((x2-x1)/(nx),1);
5072 h = TMath::Max((y1-y2)/(ny),1);
5073 ix = x1;
5074
5075 for (i = 0; i < nx; i++) {
5076 iy = y1 - h;
5077 for (j = 0; j < ny; j++) {
5078 icol = (ARGB32)ic[i + (nx*j)];
5079 if (icol != color) {
5080 color = icol;
5081 }
5082 FillRectangleInternal((UInt_t)color, ix, iy, w, h);
5083 iy = iy - h;
5084 }
5085 ix = ix + w;
5086 }
5087}
5088
5089////////////////////////////////////////////////////////////////////////////////
5090/// Return alpha-blended value computed from bottom and top pixel values.
5091
5093{
5094 UInt_t ret = bot;
5095
5096 _alphaBlend(&ret, &top);
5097 return ret;
5098}
5099
5100////////////////////////////////////////////////////////////////////////////////
5101/// Return visual.
5102
5104{
5105 return fgVisual;
5106}
5107
5108////////////////////////////////////////////////////////////////////////////////
5109/// Get poly bounds along Y.
5110
5111static int GetPolyYBounds(TPoint *pts, int n, int *by, int *ty)
5112{
5113 TPoint *ptMin;
5114 int ymin, ymax;
5115 TPoint *ptsStart = pts;
5116
5117 ptMin = pts;
5118 ymin = ymax = (pts++)->fY;
5119
5120 while (--n > 0) {
5121 if (pts->fY < ymin) {
5122 ptMin = pts;
5123 ymin = pts->fY;
5124 }
5125 if (pts->fY > ymax) {
5126 ymax = pts->fY;
5127 }
5128 pts++;
5129 }
5130
5131 *by = ymin;
5132 *ty = ymax;
5133 return (ptMin - ptsStart);
5134}
5135
5136////////////////////////////////////////////////////////////////////////////////
5137/// The code is based on Xserver/mi/mipolycon.c
5138/// "Copyright 1987, 1998 The Open Group"
5139
5142{
5143 int xl = 0; // x vals of leftedges
5144 int xr = 0; // x vals of right edges
5145 int dl = 0; // decision variables
5146 int dr = 0; // decision variables
5147 int ml = 0; // left edge slope
5148 int m1l = 0; // left edge slope+1
5149 int mr = 0, m1r = 0; // right edge slope and slope+1
5150 int incr1l = 0, incr2l = 0; // left edge error increments
5151 int incr1r = 0, incr2r = 0; // right edge error increments
5152 int dy; // delta y
5153 int y; // current scanline
5154 int left, right; // indices to first endpoints
5155 int i; // loop counter
5156 int nextleft, nextright; // indices to second endpoints
5157 TPoint *ptsOut; // output buffer
5158 UInt_t *width; // output buffer
5159 TPoint *firstPoint = nullptr;
5160 UInt_t *firstWidth = nullptr;
5161 int imin; // index of smallest vertex (in y)
5162 int ymin; // y-extents of polygon
5163 int ymax;
5164 Bool_t ret = kTRUE;
5165
5166 *nspans = 0;
5167
5168 if (!InitImage("GetPolygonSpans")) {
5169 return kFALSE;
5170 }
5171
5172 if ((npt < 3) || !ppt) {
5173 Warning("GetPolygonSpans", "No points specified npt=%d ppt=0x%zx", npt, (size_t)ppt);
5174 return kFALSE;
5175 }
5176
5177 // find leftx, bottomy, rightx, topy, and the index
5178 // of bottomy. Also translate the points.
5180
5181 dy = ymax - ymin + 1;
5182 if ((npt < 3) || (dy < 0)) return kFALSE;
5183
5184 ptsOut = firstPoint = new TPoint[dy];
5185 width = firstWidth = new UInt_t[dy];
5186 ret = kTRUE;
5187
5189 y = ppt[nextleft].fY;
5190
5191 // loop through all edges of the polygon
5192 do {
5193 // add a left edge if we need to
5194 if (ppt[nextleft].fY == y) {
5195 left = nextleft;
5196
5197 // find the next edge, considering the end
5198 // conditions of the array.
5199 nextleft++;
5200 if (nextleft >= (int)npt) {
5201 nextleft = 0;
5202 }
5203
5204 // now compute all of the random information
5205 // needed to run the iterative algorithm.
5206 BRESINITPGON(ppt[nextleft].fY - ppt[left].fY,
5207 ppt[left].fX, ppt[nextleft].fX,
5208 xl, dl, ml, m1l, incr1l, incr2l);
5209 }
5210
5211 // add a right edge if we need to
5212 if (ppt[nextright].fY == y) {
5213 right = nextright;
5214
5215 // find the next edge, considering the end
5216 // conditions of the array.
5217 nextright--;
5218 if (nextright < 0) {
5219 nextright = npt-1;
5220 }
5221
5222 // now compute all of the random information
5223 // needed to run the iterative algorithm.
5224 BRESINITPGON(ppt[nextright].fY - ppt[right].fY,
5225 ppt[right].fX, ppt[nextright].fX,
5226 xr, dr, mr, m1r, incr1r, incr2r);
5227 }
5228
5229 // generate scans to fill while we still have
5230 // a right edge as well as a left edge.
5231 i = TMath::Min(ppt[nextleft].fY, ppt[nextright].fY) - y;
5232
5233 // in case of non-convex polygon
5234 if (i < 0) {
5235 delete [] firstWidth;
5236 delete [] firstPoint;
5237 return kTRUE;
5238 }
5239
5240 while (i-- > 0) {
5241 ptsOut->fY = y;
5242
5243 // reverse the edges if necessary
5244 if (xl < xr) {
5245 *(width++) = xr - xl;
5246 (ptsOut++)->fX = xl;
5247 } else {
5248 *(width++) = xl - xr;
5249 (ptsOut++)->fX = xr;
5250 }
5251 y++;
5252
5253 // increment down the edges
5256 }
5257 } while (y != ymax);
5258
5262
5263 return ret;
5264}
5265
5266////////////////////////////////////////////////////////////////////////////////
5267/// Fill a convex polygon with background color or bitmap.
5268/// For non convex polygon one must use DrawFillArea method
5269
5271 const char *stipple, UInt_t w, UInt_t h)
5272{
5273 UInt_t nspans = 0;
5274 TPoint *firstPoint = nullptr; // output buffer
5275 UInt_t *firstWidth = nullptr; // output buffer
5276
5278 ARGB32 color = ARGB32_White;
5279 parse_argb_color(col, &color);
5280
5281 if (nspans) {
5282 if (!stipple && ((color & 0xff000000)==0xff000000)) { //no stipple no alpha
5284 } else {
5286 }
5287
5288 if (del) {
5289 delete [] firstWidth;
5290 delete [] firstPoint;
5291 }
5292 } else {
5293 if (firstWidth) delete [] firstWidth;
5294 if (firstPoint) delete [] firstPoint;
5295 }
5296}
5297
5298////////////////////////////////////////////////////////////////////////////////
5299/// Fill a convex polygon with background image.
5300/// For non convex polygon one must use DrawFillArea method
5301
5303{
5304 UInt_t nspans = 0;
5305 TPoint *firstPoint = nullptr; // output buffer
5306 UInt_t *firstWidth = nullptr; // output buffer
5307
5309
5310 if (nspans) {
5312
5313 if (del) {
5314 delete [] firstWidth;
5315 delete [] firstPoint;
5316 }
5317 } else {
5318 if (firstWidth) delete [] firstWidth;
5319 if (firstPoint) delete [] firstPoint;
5320 }
5321}
5322
5323////////////////////////////////////////////////////////////////////////////////
5324/// Crop a convex polygon.
5325
5327{
5328 UInt_t nspans = 0;
5329 TPoint *firstPoint = nullptr;
5330 UInt_t *firstWidth = nullptr;
5331
5333
5334 if (nspans) {
5336
5337 if (del) {
5338 delete [] firstWidth;
5339 delete [] firstPoint;
5340 }
5341 } else {
5342 if (firstWidth) delete [] firstWidth;
5343 if (firstPoint) delete [] firstPoint;
5344 }
5345}
5346
5347static const UInt_t NUMPTSTOBUFFER = 512;
5348
5349////////////////////////////////////////////////////////////////////////////////
5350/// Fill a polygon (any type convex, non-convex).
5351
5352void TASImage::DrawFillArea(UInt_t count, TPoint *ptsIn, const char *col,
5353 const char *stipple, UInt_t w, UInt_t h)
5354{
5355 if (!InitImage("DrawFillArea")) {
5356 return;
5357 }
5358
5359 if ((count < 3) || !ptsIn) {
5360 Warning("DrawFillArea", "No points specified npt=%d ppt=0x%zx", count, (size_t)ptsIn);
5361 return;
5362 }
5363
5364 if (count < 5) {
5365 FillPolygon(count, ptsIn, col, stipple, w, h);
5366 return;
5367 }
5368
5369 ARGB32 color = ARGB32_White;
5370 parse_argb_color(col, &color);
5371
5372 EdgeTableEntry *pAET; // the Active Edge Table
5373 int y; // the current scanline
5374 UInt_t nPts = 0; // number of pts in buffer
5375
5376 ScanLineList *pSLL; // Current ScanLineList
5377 TPoint *ptsOut; // ptr to output buffers
5378 UInt_t *width;
5379 TPoint firstPoint[NUMPTSTOBUFFER]; // the output buffers
5381 EdgeTableEntry *pPrevAET; // previous AET entry
5382 EdgeTable ET; // Edge Table header node
5383 EdgeTableEntry AET; // Active ET header node
5384 EdgeTableEntry *pETEs; // Edge Table Entries buff
5385 ScanLineListBlock SLLBlock; // header for ScanLineList
5386 Bool_t del = kTRUE;
5387
5388 static const UInt_t gEdgeTableEntryCacheSize = 200;
5390
5391 if (count < gEdgeTableEntryCacheSize) {
5393 del = kFALSE;
5394 } else {
5395 pETEs = new EdgeTableEntry[count];
5396 del = kTRUE;
5397 }
5398
5399 ET.scanlines.next = nullptr; // to avoid compiler warnings
5400 ET.ymin = ET.ymax = 0; // to avoid compiler warnings
5401
5403 width = firstWidth;
5404 CreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock);
5405 pSLL = ET.scanlines.next;
5406
5407 for (y = ET.ymin; y < ET.ymax; y++) {
5408 if (pSLL && y == pSLL->scanline) {
5409 loadAET(&AET, pSLL->edgelist);
5410 pSLL = pSLL->next;
5411 }
5412 pPrevAET = &AET;
5413 pAET = AET.next;
5414
5415 while (pAET) {
5416 ptsOut->fX = pAET->bres.minor_axis;
5417 ptsOut->fY = y;
5418 ptsOut++;
5419 nPts++;
5420
5421 *width++ = pAET->next->bres.minor_axis - pAET->bres.minor_axis;
5422
5423 if (nPts == NUMPTSTOBUFFER) {
5424 if (!stipple && ((color & 0xff000000)==0xff000000)) { //no stipple, no alpha
5426 } else {
5428 }
5430 width = firstWidth;
5431 nPts = 0;
5432 }
5435 }
5437 }
5438
5439 if (nPts) {
5440 if (!stipple && ((color & 0xff000000)==0xff000000)) { //no stipple, no alpha
5442 } else {
5444 }
5445 }
5446
5447 if (del) delete [] pETEs;
5448 FreeStorage(SLLBlock.next);
5449}
5450
5451////////////////////////////////////////////////////////////////////////////////
5452/// Fill a polygon (any type convex, non-convex).
5453
5455{
5456 if (!InitImage("DrawFillArea")) {
5457 return;
5458 }
5459
5460 if ((count < 3) || !ptsIn) {
5461 Warning("DrawFillArea", "No points specified npt=%d ppt=0x%zx", count, (size_t)ptsIn);
5462 return;
5463 }
5464
5465 if (count < 5) {
5466 FillPolygon(count, ptsIn, tile);
5467 return;
5468 }
5469
5470 EdgeTableEntry *pAET; // the Active Edge Table
5471 int y; // the current scanline
5472 UInt_t nPts = 0; // number of pts in buffer
5473
5474 ScanLineList *pSLL; // Current ScanLineList
5475 TPoint *ptsOut; // ptr to output buffers
5476 UInt_t *width;
5477 TPoint firstPoint[NUMPTSTOBUFFER]; // the output buffers
5479 EdgeTableEntry *pPrevAET; // previous AET entry
5480 EdgeTable ET; // Edge Table header node
5481 EdgeTableEntry AET; // Active ET header node
5482 EdgeTableEntry *pETEs; // Edge Table Entries buff
5483 ScanLineListBlock SLLBlock; // header for ScanLineList
5484
5485 pETEs = new EdgeTableEntry[count];
5486
5487 ET.scanlines.next = nullptr; // to avoid compiler warnings
5488 ET.ymin = ET.ymax = 0; // to avoid compiler warnings
5489
5491 width = firstWidth;
5492 CreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock);
5493 pSLL = ET.scanlines.next;
5494
5495 for (y = ET.ymin; y < ET.ymax; y++) {
5496 if (pSLL && y == pSLL->scanline) {
5497 loadAET(&AET, pSLL->edgelist);
5498 pSLL = pSLL->next;
5499 }
5500 pPrevAET = &AET;
5501 pAET = AET.next;
5502
5503 while (pAET) {
5504 ptsOut->fX = pAET->bres.minor_axis;
5505 ptsOut->fY = y;
5506 ptsOut++;
5507 nPts++;
5508
5509 *width++ = pAET->next->bres.minor_axis - pAET->bres.minor_axis;
5510
5511 if (nPts == NUMPTSTOBUFFER) {
5514 width = firstWidth;
5515 nPts = 0;
5516 }
5519 }
5521 }
5523
5524 delete [] pETEs;
5525 FreeStorage(SLLBlock.next);
5526}
5527
5528////////////////////////////////////////////////////////////////////////////////
5529/// Create draw context.
5530
5532{
5533 ASDrawContext *ctx = new ASDrawContext;
5534
5535 ctx->canvas_width = im->width;
5536 ctx->canvas_height = im->height;
5537 ctx->canvas = im->alt.argb32;
5538 ctx->scratch_canvas = nullptr;
5539
5540 ctx->flags = ASDrawCTX_CanvasIsARGB;
5542 return ctx;
5543}
5544
5545////////////////////////////////////////////////////////////////////////////////
5546/// Destroy asdraw context32.
5547
5549{
5550 if (ctx) {
5551 if (ctx->scratch_canvas) free(ctx->scratch_canvas);
5552 delete ctx;
5553 }
5554}
5555
5556static const UInt_t kBrushCacheSize = 20;
5558
5559////////////////////////////////////////////////////////////////////////////////
5560/// Draw wide line.
5561
5563 UInt_t color, UInt_t thick)
5564{
5565 if (!InitImage("DrawWideLine")) {
5566 return;
5567 }
5568 Int_t sz = thick*thick;
5569 CARD32 *matrix;
5571
5572 if (use_cache) {
5574 } else {
5575 matrix = new CARD32[sz];
5576 }
5577
5578 for (int i = 0; i < sz; i++) {
5579 matrix[i] = (CARD32)color;
5580 }
5581
5583 brush.matrix = matrix;
5584 brush.width = thick;
5585 brush.height = thick;
5586 brush.center_y = brush.center_x = thick/2;
5587
5588 // When the first or last point of a wide line is exactly on the
5589 // window limit the line is drawn vertically or horizontally.
5590 // see https://sft.its.cern.ch/jira/browse/ROOT-8021
5591 UInt_t xx1 = x1;
5592 UInt_t yy1 = y1;
5593 UInt_t xx2 = x2;
5594 UInt_t yy2 = y2;
5595 if (xx1 == fImage->width) --xx1;
5596 if (yy1 == fImage->height) --yy1;
5597 if (xx2 == fImage->width) --xx2;
5598 if (yy2 == fImage->height) --yy2;
5600 asim_move_to(ctx, xx1, yy1);
5601 asim_line_to(ctx, xx2, yy2);
5602
5603 if (!use_cache) {
5604 delete [] matrix;
5605 }
5607}
5608
5609////////////////////////////////////////////////////////////////////////////////
5610/// Draw glyph bitmap.
5611
5613{
5614 UInt_t col[5];
5615 Bool_t has_alpha = (color & 0xff000000) != 0xff000000;
5616
5618
5619 auto ndots = source->width * source->rows;
5620 ULong_t r = 0, g = 0, b = 0;
5621
5622 const Int_t y0 = by > 0 ? by * fImage->width : 0;
5623 Int_t yy = y0;
5624 for (UInt_t y = 0; y < source->rows; y++) {
5625 Int_t byy = by + y;
5626 if ((byy >= (Int_t) fImage->height) || (byy < 0)) continue;
5627
5628 for (UInt_t x = 0; x < source->width; x++) {
5629 Int_t bxx = bx + x;
5630 if ((bxx >= (Int_t) fImage->width) || (bxx < 0)) continue;
5631
5632 auto idx = Idx(bxx + yy);
5633 r += ((fImage->alt.argb32[idx] & 0xff0000) >> 16);
5634 g += ((fImage->alt.argb32[idx] & 0x00ff00) >> 8);
5635 b += (fImage->alt.argb32[idx] & 0x0000ff);
5636 }
5637 yy += fImage->width;
5638 }
5639 if (ndots > 0) {
5640 r /= ndots;
5641 g /= ndots;
5642 b /= ndots;
5643 }
5644
5645 col[0] = (r << 16) + (g << 8) + b;
5646 col[4] = color;
5647 Int_t col4r = (col[4] & 0xff0000) >> 16;
5648 Int_t col4g = (col[4] & 0x00ff00) >> 8;
5649 Int_t col4b = (col[4] & 0x0000ff);
5650
5651 // interpolate between fore and background colors
5652 for (Int_t x = 3; x > 0; x--) {
5653 Int_t xx = 4 - x;
5654 Int_t colxr = (col4r*x + r*xx) >> 2;
5655 Int_t colxg = (col4g*x + g*xx) >> 2;
5656 Int_t colxb = (col4b*x + b*xx) >> 2;
5657 col[x] = (colxr << 16) + (colxg << 8) + colxb;
5658 }
5659
5660 Int_t clipx1 = 0, clipx2 = 0, clipy1 = 0, clipy2 = 0;
5662
5663 if (clippad) {
5665 clipx1 = clippad->XtoAbsPixel(clippad->GetX1())*is - offx;
5666 clipx2 = clippad->XtoAbsPixel(clippad->GetX2())*is - offx;
5667 clipy1 = clippad->YtoAbsPixel(clippad->GetY1())*is - offy;
5668 clipy2 = clippad->YtoAbsPixel(clippad->GetY2())*is - offy;
5669 noClip = kFALSE;
5670 }
5671
5672 yy = y0;
5673 UChar_t *s = source->buffer;
5674
5675 for (UInt_t y = 0; y < source->rows; y++) {
5676 Int_t byy = by + y;
5677
5678 for (UInt_t x = 0; x < source->width; x++) {
5679 Int_t bxx = bx + x;
5680
5681 UChar_t d = *s++ & 0xff;
5682 d = ((d + 10) * 5) >> 8;
5683 if (d > 4) d = 4;
5684
5685 if (d > 0) {
5686 if (noClip || ((bxx < clipx2) && (bxx >= clipx1) &&
5687 (byy >= clipy2) && (byy < clipy1))) {
5688 auto idx = Idx(bxx + yy);
5689 auto acolor = (ARGB32) col[d];
5690 if (has_alpha) {
5691 _alphaBlend(&fImage->alt.argb32[idx], &acolor);
5692 } else {
5693 fImage->alt.argb32[idx] = acolor;
5694 }
5695 }
5696 }
5697 }
5698 yy += fImage->width;
5699 }
5700}
5701
5702////////////////////////////////////////////////////////////////////////////////
5703/// Draw text at the pixel position (x,y).
5704
5706{
5707 if (gPad)
5708 DrawTextOnPad(text, x, y, gPad, 0, 0);
5709}
5710
5711
5712////////////////////////////////////////////////////////////////////////////////
5713/// Draw text at the pixel position (x,y) checking clip on pad.
5714
5716{
5717 if (!text || !InitImage("DrawTextOnPad"))
5718 return;
5719
5720 TTFhandle ttf;
5721
5722 // set text font
5723 ttf.SetTextFont(text->GetTextFont());
5724
5725 UInt_t padw = pad ? pad->GetPadWidth() : 100;
5726 UInt_t padh = pad ? pad->GetPadHeight() : 100;
5727
5728 // set text size
5729 Float_t ttfsize = text->GetTextSize() * TMath::Min(padw, padh);
5730 ttf.SetTextSize(ttfsize*kScale);
5731
5732 // set text angle
5733 ttf.SetRotationMatrix(text->GetTextAngle());
5734
5735 // set text
5736 const wchar_t *wcsTitle = reinterpret_cast<const wchar_t *>(text->GetWcsTitle());
5737 if (wcsTitle)
5738 ttf.PrepareString(wcsTitle);
5739 else
5740 ttf.PrepareString(text->GetTitle());
5741
5742 ttf.LayoutGlyphs();
5743
5744 // color
5745 TColor *col = gROOT->GetColor(text->GetTextColor());
5746 if (!col) { // no color, make it black
5747 col = gROOT->GetColor(1);
5748 if (!col) return;
5749 }
5750 ARGB32 color = ARGB32_White;
5751 parse_argb_color(col->AsHexString(), &color);
5752
5753 // Align()
5754 Int_t align = 0;
5755 Int_t txalh = text->GetTextAlign()/10;
5756 Int_t txalv = text->GetTextAlign()%10;
5757
5758 switch (txalh) {
5759 case 0 :
5760 case 1 :
5761 switch (txalv) { //left
5762 case 1 :
5763 align = 7; //bottom
5764 break;
5765 case 2 :
5766 align = 4; //center
5767 break;
5768 case 3 :
5769 align = 1; //top
5770 break;
5771 }
5772 break;
5773 case 2 :
5774 switch (txalv) { //center
5775 case 1 :
5776 align = 8; //bottom
5777 break;
5778 case 2 :
5779 align = 5; //center
5780 break;
5781 case 3 :
5782 align = 2; //top
5783 break;
5784 }
5785 break;
5786 case 3 :
5787 switch (txalv) { //right
5788 case 1 :
5789 align = 9; //bottom
5790 break;
5791 case 2 :
5792 align = 6; //center
5793 break;
5794 case 3 :
5795 align = 3; //top
5796 break;
5797 }
5798 break;
5799 }
5800
5801 FT_Vector ftal;
5802
5803 // vertical alignment
5804 if (align == 1 || align == 2 || align == 3) {
5805 ftal.y = ttf.GetAscent();
5806 } else if (align == 4 || align == 5 || align == 6) {
5807 ftal.y = ttf.GetAscent() / 2;
5808 } else {
5809 ftal.y = 0;
5810 }
5811
5812 // horizontal alignment
5813 if (align == 3 || align == 6 || align == 9) {
5814 ftal.x = ttf.GetWidth();
5815 } else if (align == 2 || align == 5 || align == 8) {
5816 ftal.x = ttf.GetWidth() / 2;
5817 } else {
5818 ftal.x = 0;
5819 }
5820
5821 FT_Vector_Transform(&ftal, ttf.GetRotMatrix());
5822 ftal.x = (ftal.x >> 6);
5823 ftal.y = (ftal.y >> 6);
5824
5825 for (UInt_t n = 0; n < ttf.GetNumGlyphs(); n++) {
5826 if (auto bitmap = ttf.GetGlyphBitmap(n, kTRUE)) {
5827 Int_t bx = x - ftal.x + bitmap->left;
5828 Int_t by = y + ftal.y - bitmap->top;
5829
5830 DrawFTGlyph(&bitmap->bitmap, color, bx, by, pad, offx, offy);
5831 }
5832 }
5833}
5834
5835////////////////////////////////////////////////////////////////////////////////
5836/// Draw text using TrueType fonts.
5837
5839 UInt_t color, const char *font_name, Float_t angle)
5840{
5841 if (!text || !InitImage("DrawTextTTF"))
5842 return;
5843
5844 TTFhandle ttf;
5845
5846 ttf.SetTextFont(font_name);
5847 ttf.SetTextSize(size);
5848 ttf.SetRotationMatrix(angle);
5849 ttf.PrepareString(text);
5850 ttf.LayoutGlyphs();
5851
5852 // compute the size and position that will contain the text
5853 // Int_t Xoff = TMath::Max(0, (Int_t) -ttf.GetBox().xMin);
5854 Int_t Yoff = TMath::Max(0, (Int_t) -ttf.GetBox().yMin);
5855 Int_t h = ttf.GetBox().yMax + Yoff;
5856
5857 for (UInt_t n = 0; n < ttf.GetNumGlyphs(); n++) {
5858 if (auto bitmap = ttf.GetGlyphBitmap(n, kTRUE)) {
5859 Int_t bx = x + bitmap->left;
5860 Int_t by = y + h - bitmap->top;
5861 DrawFTGlyph(&bitmap->bitmap, color, bx, by);
5862 }
5863 }
5864}
5865
5866////////////////////////////////////////////////////////////////////////////////
5867/// Return in-memory buffer compressed according image type.
5868/// Buffer must be deallocated after usage with free(buffer) call.
5869/// This method can be used for sending images over network.
5870
5872{
5873 static ASImageExportParams params;
5874 Bool_t ret = kFALSE;
5876
5877 if (!img) return;
5878
5879 switch (type) {
5880 case TImage::kXpm:
5881 ret = ASImage2xpmRawBuff(img, (CARD8 **)buffer, size, nullptr);
5882 break;
5883 case TImage::kPng:
5884 ret = ASImage2PNGBuff(img, (CARD8 **)buffer, size, &params);
5885 break;
5886 default:
5887 ret = kFALSE;
5888 }
5889
5890 if (!ret) {
5891 *size = 0;
5892 *buffer = nullptr;
5893 }
5894}
5895
5896////////////////////////////////////////////////////////////////////////////////
5897/// Create image from compressed buffer.
5898/// Supported formats:
5899///
5900/// - PNG - by default
5901/// - XPM - two options exist:
5902/// 1. xpm as a single string (raw buffer). Such string
5903/// is returned by GetImageBuffer method.
5904/// For example:
5905/// ~~~ {.cpp}
5906/// char *buf;
5907/// int sz;
5908/// im1->GetImageBuffer(&buf, &int, TImage::kXpm); /*raw buffer*/
5909/// TImage *im2 = TImage::Create();
5910/// im2->SetImageBuffer(&buf, TImage::kXpm);
5911/// ~~~
5912/// 2. xpm as an array of strings (pre-parsed)
5913/// ~~~ {.cpp}
5914/// For example:
5915/// char *xpm[] = {
5916/// "64 28 58 1",
5917/// " c #0A030C",
5918/// ". c #1C171B"
5919/// ...
5920/// TImage *im = TImage::Create();
5921/// im->SetImageBuffer(xpm, TImage::kXpm);
5922/// ~~~
5923
5925{
5926 DestroyImage();
5927
5928 static ASImageImportParams params;
5929 params.flags = 0;
5930 params.width = 0;
5931 params.height = 0 ;
5932 params.filter = SCL_DO_ALL;
5933 params.gamma = SCREEN_GAMMA;
5934 params.gamma_table = nullptr;
5935 params.compression = 0;
5936 params.format = ASA_ASImage;
5937 params.search_path = nullptr;
5938 params.subimage = 0;
5939
5940 switch (type) {
5941 case TImage::kXpm:
5942 {
5943 char *ptr = buffer[0];
5944 while (isspace((int)*ptr)) ++ptr;
5945 if (atoi(ptr)) { // pre-parsed and preloaded data
5946 fImage = xpm_data2ASImage((const char**)buffer, &params);
5947 } else {
5948 fImage = xpmRawBuff2ASImage((const char*)*buffer, &params);
5949 }
5950 break;
5951 }
5952 case TImage::kPng:
5953 fImage = PNGBuff2ASimage((CARD8 *)*buffer, &params);
5954 break;
5955 default:
5956 fImage = nullptr;
5957 }
5958
5959 if (!fImage) {
5960 return kFALSE;
5961 }
5962
5963 if (fName.IsNull()) {
5964 fName.Form("img_%dx%d.%d", fImage->width, fImage->height, gRandom->Integer(1000));
5965 }
5966 UnZoom();
5967 return kTRUE;
5968}
5969
5970////////////////////////////////////////////////////////////////////////////////
5971/// Create image thumbnail.
5972
5974{
5975 int size;
5976 const int sz = 64;
5977
5978 if (!fImage) {
5979 Warning("CreateThumbnail", "No image");
5980 return;
5981 }
5982
5983 if (!InitVisual()) {
5984 Warning("CreateThumbnail", "Visual not initiated");
5985 return;
5986 }
5987
5988 static char *buf = nullptr;
5989 int w, h;
5990 ASImage *img = nullptr;
5991
5992 if (fImage->width > fImage->height) {
5993 w = sz;
5994 h = (fImage->height*sz)/fImage->width;
5995 } else {
5996 h = sz;
5997 w = (fImage->width*sz)/fImage->height;
5998 }
5999
6000 w = w < 8 ? 8 : w;
6001 h = h < 8 ? 8 : h;
6002
6005 if (!img) {
6006 return;
6007 }
6008
6009 // contrasting
6011 ASImageLayer layers[2];
6012 init_image_layers(&(layers[0]), 2);
6013 layers[0].im = img;
6014 layers[0].dst_x = 0;
6015 layers[0].dst_y = 0;
6016 layers[0].clip_width = img->width;
6017 layers[0].clip_height = img->height;
6018 layers[0].bevel = nullptr;
6019 layers[1].im = img;
6020 layers[1].dst_x = 0;
6021 layers[1].dst_y = 0;
6022 layers[1].clip_width = img->width;
6023 layers[1].clip_height = img->height;
6024 layers[1].merge_scanlines = blend_scanlines_name2func("tint");
6025 rendered_im = merge_layers(fgVisual, &(layers[0]), 2, img->width, img->height,
6028 img = rendered_im;
6029
6030 // pad image
6031 ASImage *padimg = nullptr;
6032 int d = 0;
6033
6034 if (w == sz) {
6035 d = (sz - h) >> 1;
6036 padimg = pad_asimage(fgVisual, img, 0, d, sz, sz, 0x00ffffff,
6038 } else {
6039 d = (sz - w) >> 1;
6040 padimg = pad_asimage(fgVisual, img, d, 0, sz, sz, 0x00ffffff,
6042 }
6043
6044 if (!padimg) {
6046 return;
6047 }
6048
6049 void *ptr = &buf;
6050 ASImage2xpmRawBuff(padimg, (CARD8 **)ptr, &size, nullptr);
6051 fTitle = buf;
6052
6054}
6055
6056////////////////////////////////////////////////////////////////////////////////
6057/// Streamer for ROOT I/O.
6058
6060{
6061 Bool_t image_type = 0;
6062 int size = 0;
6063 int w, h;
6064 UInt_t R__s, R__c;
6065
6066 if (b.IsReading()) {
6067 Version_t version = b.ReadVersion(&R__s, &R__c);
6068 if (version == 0) { //dumb prototype for schema evolution
6069 return;
6070 }
6071
6072 if ( version == 1 ) {
6073 Int_t fileVersion = b.GetVersionOwner();
6074 if (fileVersion > 0 && fileVersion < 50000 ) {
6076 b >> fMaxValue;
6077 b >> fMinValue;
6078 b >> fZoomOffX;
6079 b >> fZoomOffY;
6080 b >> fZoomWidth;
6081 b >> fZoomHeight;
6082 if ( fileVersion < 40200 ) {
6084 b >> zoomUpdate;
6086 } else {
6087 b >> fZoomUpdate;
6088 b >> fEditable;
6090 b >> paintMode;
6092 }
6093 b.CheckByteCount(R__s, R__c, TASImage::IsA());
6094 return;
6095 }
6096 }
6097
6099 b >> image_type;
6100
6101 if (image_type != 0) { // read PNG compressed image
6102 b >> size;
6103 char *buffer = new char[size];
6104 b.ReadFastArray(buffer, size);
6105 SetImageBuffer(&buffer, TImage::kPng);
6106 delete [] buffer;
6107 } else { // read vector with palette
6109 b >> w;
6110 b >> h;
6111 size = w*h;
6112 Double_t *vec = new Double_t[size];
6113 b.ReadFastArray(vec, size);
6114 SetImage(vec, w, h, &fPalette);
6115 delete [] vec;
6116 }
6117 b.CheckByteCount(R__s, R__c, TASImage::IsA());
6118 } else {
6119 if (!fImage) {
6120 return;
6121 }
6122 R__c = b.WriteVersion(TASImage::IsA(), kTRUE);
6123
6124 if (fName.IsNull()) {
6125 fName.Form("img_%dx%d.%d", fImage->width, fImage->height, gRandom->Integer(1000));
6126 }
6128
6129 image_type = fImage->alt.vector ? 0 : 1;
6130 b << image_type;
6131
6132 if (image_type != 0) { // write PNG compressed image
6133 char *buffer = nullptr;
6134 GetImageBuffer(&buffer, &size, TImage::kPng);
6135 b << size;
6136 b.WriteFastArray(buffer, size);
6137 free(buffer);
6138 } else { // write vector with palette
6140 b << fImage->width;
6141 b << fImage->height;
6142 b.WriteFastArray(fImage->alt.vector, fImage->width*fImage->height);
6143 }
6144 b.SetByteCount(R__c, kTRUE);
6145 }
6146}
6147
6148////////////////////////////////////////////////////////////////////////////////
6149/// Browse image.
6150
6152{
6153 if (fImage->alt.vector) {
6154 Draw("n");
6155 } else {
6156 Draw("nxxx");
6157 }
6159}
6160
6161////////////////////////////////////////////////////////////////////////////////
6162/// Title is used to keep 32x32 xpm image's thumbnail.
6163
6164const char *TASImage::GetTitle() const
6165{
6166 if (!gDirectory || !gDirectory->IsWritable())
6167 return nullptr;
6168
6169 TASImage *mutble = (TASImage *)this;
6170
6171 if (fTitle.IsNull()) {
6172 mutble->SetTitle(fName.Data());
6173 }
6174
6175 return fTitle.Data();
6176}
6177
6178////////////////////////////////////////////////////////////////////////////////
6179/// Set a title for an image.
6180
6181void TASImage::SetTitle(const char *title)
6182{
6183 if (fTitle.IsNull()) {
6185 }
6186
6187 if (fTitle.IsNull()) {
6188 return;
6189 }
6190
6191 int start = fTitle.Index("/*") + 3;
6192 int stop = fTitle.Index("*/") - 1;
6193
6194 if ((start > 0) && (stop - start > 0)) {
6195 fTitle.Replace(start, stop - start, title);
6196 }
6197}
6198
6199////////////////////////////////////////////////////////////////////////////////
6200/// Draw a cubic bezier line.
6201
6203 Int_t x3, Int_t y3, const char *col, UInt_t thick)
6204{
6205 if (!InitImage("DrawCubeBezier")) {
6206 return;
6207 }
6208 Int_t sz = thick*thick;
6209 CARD32 *matrix;
6211
6212 ARGB32 color = ARGB32_White;
6213 parse_argb_color(col, &color);
6214
6215 if (use_cache) {
6217 } else {
6218 matrix = new CARD32[sz];
6219 }
6220
6221 for (int i = 0; i < sz; i++) {
6222 matrix[i] = (CARD32)color;
6223 }
6224
6226 brush.matrix = matrix;
6227 brush.width = thick;
6228 brush.height = thick;
6229 brush.center_y = brush.center_x = thick/2;
6230
6232 asim_cube_bezier(ctx, x1, y1, x2, y2, x3, y3);
6233
6234 if (!use_cache)
6235 delete [] matrix;
6236
6238}
6239
6240////////////////////////////////////////////////////////////////////////////////
6241/// Draw a straight ellipse.
6242/// If thick < 0 - draw filled ellipse.
6243
6245 const char *col, Int_t thick)
6246{
6247 if (!InitImage("DrawStraightEllips")) {
6248 return;
6249 }
6250 thick = !thick ? 1 : thick;
6251 Int_t sz = thick*thick;
6252 CARD32 *matrix;
6254
6255 ARGB32 color = ARGB32_White;
6256 parse_argb_color(col, &color);
6257
6258 if (use_cache) {
6260 } else {
6261 matrix = new CARD32[sz];
6262 }
6263
6264 for (int i = 0; i < sz; i++) {
6265 matrix[i] = (CARD32)color;
6266 }
6267
6269 brush.matrix = matrix;
6270 brush.width = thick > 0 ? thick : 1;
6271 brush.height = thick > 0 ? thick : 1;
6272 brush.center_y = brush.center_x = thick > 0 ? thick/2 : 0;
6273
6275 asim_straight_ellips(ctx, x, y, rx, ry, thick < 0);
6276
6277 if (!use_cache)
6278 delete [] matrix;
6279
6281}
6282
6283////////////////////////////////////////////////////////////////////////////////
6284/// Draw a circle.
6285/// If thick < 0 - draw filled circle
6286
6288{
6289 if (!InitImage("DrawCircle")) {
6290 return;
6291 }
6292
6293 thick = !thick ? 1 : thick;
6294 Int_t sz = thick*thick;
6295 CARD32 *matrix;
6297
6298 ARGB32 color = ARGB32_White;
6299 parse_argb_color(col, &color);
6300
6301///matrix = new CARD32[sz];
6302 if (use_cache) {
6304 } else {
6305 matrix = new CARD32[sz];
6306 }
6307
6308 for (int i = 0; i < sz; i++) {
6309 matrix[i] = (CARD32)color;
6310 }
6311
6313 brush.matrix = matrix;
6314 brush.height = brush.width = thick > 0 ? thick : 1;
6315 brush.center_y = brush.center_x = thick > 0 ? thick/2 : 0;
6316
6318 asim_circle(ctx, x, y, r, thick < 0);
6319
6320///free (matrix);
6321 if (!use_cache) {
6322 delete [] matrix;
6323 }
6325}
6326
6327////////////////////////////////////////////////////////////////////////////////
6328/// Draw an ellipse.
6329/// If thick < 0 - draw filled ellips
6330
6332 const char *col, Int_t thick)
6333{
6334 if (!InitImage("DrawEllips")) {
6335 return;
6336 }
6337 thick = !thick ? 1 : thick;
6338 Int_t sz = thick*thick;
6339 CARD32 *matrix;
6341
6342 ARGB32 color = ARGB32_White;
6343 parse_argb_color(col, &color);
6344
6345 if (use_cache) {
6347 } else {
6348 matrix = new CARD32[sz];
6349 }
6350
6351 for (int i = 0; i < sz; i++) {
6352 matrix[i] = (CARD32)color;
6353 }
6354
6356 brush.matrix = matrix;
6357 brush.width = thick > 0 ? thick : 1;
6358 brush.height = thick > 0 ? thick : 1;
6359 brush.center_y = brush.center_x = thick > 0 ? thick/2 : 0;
6360
6362 asim_ellips(ctx, x, y, rx, ry, angle, thick < 0);
6363
6364 if (!use_cache)
6365 delete [] matrix;
6366
6368}
6369
6370////////////////////////////////////////////////////////////////////////////////
6371/// Draw an ellipse.
6372/// If thick < 0 - draw filled ellipse.
6373
6375 const char *col, Int_t thick)
6376{
6377 if (!InitImage("DrawEllips2")) {
6378 return;
6379 }
6380 thick = !thick ? 1 : thick;
6381 Int_t sz = thick*thick;
6382 CARD32 *matrix;
6384
6385 ARGB32 color = ARGB32_White;
6386 parse_argb_color(col, &color);
6387
6388 if (use_cache) {
6390 } else {
6391 matrix = new CARD32[sz];
6392 }
6393
6394 for (int i = 0; i < sz; i++) {
6395 matrix[i] = (CARD32)color;
6396 }
6397
6399 brush.matrix = matrix;
6400 brush.width = thick > 0 ? thick : 1;
6401 brush.height = thick > 0 ? thick : 1;
6402 brush.center_y = brush.center_x = thick > 0 ? thick/2 : 0;
6403
6405 asim_ellips2(ctx, x, y, rx, ry, angle, thick < 0);
6406
6407 if (!use_cache) {
6408 delete [] matrix;
6409 }
6411}
6412
6413////////////////////////////////////////////////////////////////////////////////
6414/// Flood fill.
6415
6416void TASImage::FloodFill(Int_t /*x*/, Int_t /*y*/, const char * /*col*/,
6417 const char * /*minc*/, const char * /*maxc*/)
6418{
6419}
6420
6421////////////////////////////////////////////////////////////////////////////////
6422/// Convert RGB image to Gray image and vice versa.
6423
6425{
6426 if (fIsGray == on) {
6427 return;
6428 }
6429
6430 if (!IsValid()) {
6431 Warning("Gray", "Image not initiated");
6432 return;
6433 }
6434
6435 if (!InitVisual()) {
6436 Warning("Gray", "Visual not initiated");
6437 return;
6438 }
6439
6440 if (!fGrayImage && !on) {
6441 return;
6442 }
6443 ASImage *sav = nullptr;
6445
6446 if (fGrayImage) {
6447 sav = fImage;
6449 fGrayImage = sav;
6450 fIsGray = on;
6451 return;
6452 }
6453
6454 if (!on) return;
6455
6456 UInt_t l, r, g, b, idx;
6457 int y = 0;
6458 UInt_t i, j;
6459
6460 if (fImage->alt.argb32) {
6461 fGrayImage = tile_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height,
6463
6464 for (i = 0; i < fImage->height; i++) {
6465 for (j = 0; j < fImage->width; j++) {
6466 idx = Idx(y + j);
6467
6468 r = ((fImage->alt.argb32[idx] & 0xff0000) >> 16);
6469 g = ((fImage->alt.argb32[idx] & 0x00ff00) >> 8);
6470 b = (fImage->alt.argb32[idx] & 0x0000ff);
6471 l = (57*r + 181*g + 18*b)/256;
6472 fGrayImage->alt.argb32[idx] = (l << 16) + (l << 8) + l;
6473 }
6474 y += fImage->width;
6475 }
6476 } else {
6477 fGrayImage = create_asimage(fImage->width, fImage->height, 0);
6478
6480 0, 0, fImage->width, fImage->height, nullptr);
6481
6482 if (!imdec) {
6483 return;
6484 }
6485#ifdef HAVE_MMX
6486 mmx_init();
6487#endif
6490 if (!imout) {
6491 Warning("ToGray", "Failed to start image output");
6493 delete [] imdec;
6494 return;
6495 }
6496
6497 CARD32 *aa = imdec->buffer.alpha;
6498 CARD32 *rr = imdec->buffer.red;
6499 CARD32 *gg = imdec->buffer.green;
6500 CARD32 *bb = imdec->buffer.blue;
6501
6503 prepare_scanline(fImage->width, 0, &result, fgVisual->BGR_mode);
6504
6505 for (i = 0; i < fImage->height; i++) {
6506 imdec->decode_image_scanline(imdec);
6507 result.flags = imdec->buffer.flags;
6508 result.back_color = imdec->buffer.back_color;
6509
6510 for (j = 0; j < fImage->width; j++) {
6511 l = (57*rr[j] + 181*gg[j]+ 18*bb[j])/256;
6512 result.alpha[j] = aa[j];
6513 result.red[j] = l;
6514 result.green[j] = l;
6515 result.blue[j] = l;
6516 }
6517 imout->output_image_scanline(imout, &result, 1);
6518 }
6519
6522#ifdef HAVE_MMX
6523 mmx_off();
6524#endif
6525 }
6526
6527 sav = fImage;
6529 fGrayImage = sav;
6530 fIsGray = kTRUE;
6531}
6532
6533////////////////////////////////////////////////////////////////////////////////
6534/// Create an image (screenshot) from specified window.
6535
6537{
6538 Int_t xy;
6539
6540 x = x < 0 ? 0 : x;
6541 y = y < 0 ? 0 : y;
6542
6543 // X11 Synchronization
6544 gVirtualX->Update(1);
6545 if (!gThreadXAR) {
6546 gSystem->Sleep(10);
6548 gSystem->Sleep(10);
6550 }
6551
6552 if (!w || !h) {
6553 gVirtualX->GetWindowSize(wid, xy, xy, w, h);
6554 }
6555
6556 if ((x >= (Int_t)w) || (y >= (Int_t)h)) {
6557 return;
6558 }
6559
6560 if (!InitVisual()) {
6561 Warning("FromWindow", "Visual not initiated");
6562 return;
6563 }
6564
6565 DestroyImage();
6567
6568 static int x11 = -1;
6569 if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11");
6570
6571 if (x11) { //use built-in optimized version
6572 fImage = pixmap2asimage(fgVisual, wid, x, y, w, h, kAllPlanes, 0, 0);
6573 } else {
6574 unsigned char *bits = gVirtualX->GetColorBits(wid, 0, 0, w, h);
6575
6576 if (!bits) { // error
6577 return;
6578 }
6579 fImage = bitmap2asimage(bits, w, h, 0, nullptr);
6580 delete [] bits;
6581 }
6582}
6583
6584////////////////////////////////////////////////////////////////////////////////
6585/// Creates an image (screenshot) from a RGBA buffer.
6586
6588{
6589 DestroyImage();
6591
6592 UChar_t* xx = new UChar_t[4*w];
6593 for (UInt_t i = 0; i < h/2; ++i) {
6594 memcpy(xx, buf + 4*w*i, 4*w);
6595 memcpy(buf + 4*w*i, buf + 4*w*(h-i-1), 4*w);
6596 memcpy(buf + 4*w*(h-i-1), xx, 4*w);
6597 }
6598 delete [] xx;
6599
6600 fImage = bitmap2asimage(buf, w, h, 0, nullptr);
6601}
6602
6603////////////////////////////////////////////////////////////////////////////////
6604/// Switch on/off the image palette.
6605/// That also invokes calling vectorization of image.
6606
6608{
6609 if (!fImage) {
6610 return;
6611 }
6612
6613 if (!fImage->alt.vector && on) {
6614 Vectorize();
6615 }
6617
6618 if (on) {
6619 Double_t left = gPad->GetLeftMargin();
6620 Double_t right = gPad->GetRightMargin();
6621 Double_t top = gPad->GetTopMargin();
6622 Double_t bottom = gPad->GetBottomMargin();
6623
6624 gPad->Range(-left / (1.0 - left - right),
6625 -bottom / (1.0 - top - bottom),
6626 1 + right / (1.0 - left - right),
6627 1 + top / ( 1.0 - top - bottom));
6628 gPad->RangeAxis(0, 0, 1, 1);
6629 }
6630
6631}
6632
6633////////////////////////////////////////////////////////////////////////////////
6634/// Save a primitive as a C++ statement(s) on output stream "out".
6635
6636void TASImage::SavePrimitive(std::ostream &out, Option_t * /*= ""*/)
6637{
6638 char *buf = nullptr;
6639 int sz;
6641 TString str = buf;
6642 free(buf);
6643
6644 str.ReplaceAll("static", "const");
6645 static int ii = 0;
6646
6647 TString xpm = TString::Format("asimage_xpm_%d", ii++);
6648 str.ReplaceAll("asxpm", xpm.Data());
6649 out << "\n" << str << "\n\n";
6650
6651 out << " ";
6652 if (!gROOT->ClassSaved(TImage::Class()))
6653 out << TImage::Class()->GetName() << " *";
6654 out << "asimage = TImage::Create();\n";
6655 out << " asimage->SetImageBuffer( (char **)" << xpm << ", TImage::kXpm);\n";
6656 SaveImageAttributes(out, "asimage");
6657 out << " asimage->Draw();\n";
6658}
6659
6660////////////////////////////////////////////////////////////////////////////////
6661/// Set an image printing resolution in Dots Per Inch units.
6662///
6663/// \param[in] name - the name of jpeg file.
6664/// \param[in] set - dpi resolution.
6665///
6666/// Returns kFALSE in case of error.
6667
6669{
6670 static char buf[32];
6671 FILE *fp = fopen(name, "rb+");
6672
6673 if (!fp) {
6674 printf("file %s : failed to open\n", name);
6675 return kFALSE;
6676 }
6677
6678 if (!fread(buf, 1, 20, fp)) {
6679 fclose(fp);
6680 return kFALSE;
6681 }
6682
6683 char dpi1 = (set & 0xffff) >> 8;
6684 char dpi2 = set & 0xff;
6685
6686 int i = 0;
6687
6688 int dpi = 0; // start of dpi data
6689 for (i = 0; i < 20; i++) {
6690 if ((buf[i] == 0x4a) && (buf[i+1] == 0x46) && (buf[i+2] == 0x49) &&
6691 (buf[i+3] == 0x46) && (buf[i+4] == 0x00) ) {
6692 dpi = i + 7;
6693 break;
6694 }
6695 }
6696
6697 if (i == 20 || dpi+4 >= 20) { // jpeg maker was not found
6698 fclose(fp);
6699 printf("file %s : wrong JPEG format\n", name);
6700 return kFALSE;
6701 }
6702
6703 buf[dpi] = 1; // format specified in dots per inch
6704
6705 // set x density in dpi units
6706 buf[dpi + 1] = dpi1;
6707 buf[dpi + 2] = dpi2;
6708
6709 // set y density in dpi units
6710 buf[dpi + 3] = dpi1;
6711 buf[dpi + 4] = dpi2;
6712
6713 rewind(fp);
6714 fwrite(buf, 1, 20, fp);
6715 fclose(fp);
6716
6717 return kTRUE;
6718}
6719
6720////////////////////////////////////////////////////////////////////////////////
6721/// Return a valid index in fImage tables to avoid seg-fault by accessing out of
6722/// indices out of array's ranges.
6723
6725{
6726 // The size of arrays like fImage->alt.argb32 is fImage->width*fImage->height
6727 return TMath::Max(0, TMath::Min(idx,(Int_t)(fImage->width*fImage->height)));
6728}
@ 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:170
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:375
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:503
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:1081
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:885
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1095
virtual void Draw(Option_t *option="")
Default Draw method for all objects.
Definition TObject.cxx:290
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