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