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