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