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