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