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