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