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