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