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