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