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