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