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