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