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