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