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