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;
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 Bool_t inbatch = fgVisual && (fgVisual->dpy == (void*)1); // was in batch
2200 Bool_t noX = gROOT->IsBatch() || gVirtualX->InheritsFrom("TGWin32");
2201
2202 // was in batch, but switched to gui
2203 if (inbatch && !noX) {
2204 destroy_asvisual(fgVisual, kFALSE);
2205 fgVisual = 0;
2206 }
2207
2208 if (fgVisual && fgVisual->dpy) { // already initialized
2209 return kTRUE;
2210 }
2211
2212 // batch or win32 mode
2213 if (!fgVisual && noX) {
2214 fgVisual = create_asvisual(0, 0, 0, 0);
2215 fgVisual->dpy = (Display*)1; //fake (not used)
2216 return kTRUE;
2217 }
2218
2219#ifndef WIN32
2220#ifdef R__HAS_COCOA
2221 fgVisual = create_asvisual(0, 0, 0, 0);
2222 fgVisual->dpy = (Display*)1; //fake (not used)
2223#else
2224 Display *disp = (Display*) gVirtualX->GetDisplay();
2225 Int_t screen = gVirtualX->GetScreen();
2226 Int_t depth = gVirtualX->GetDepth();
2227 Visual *vis = (Visual*) gVirtualX->GetVisual();
2228 Colormap cmap = (Colormap) gVirtualX->GetColormap();
2229
2230 if (vis == 0 || cmap == 0) {
2231 fgVisual = create_asvisual(0, 0, 0, 0);
2232 } else {
2233 fgVisual = create_asvisual_for_id(disp, screen, depth,
2234 XVisualIDFromVisual(vis), cmap, 0);
2235 }
2236#endif
2237#else
2238 fgVisual = create_asvisual(0, 0, 0, 0);
2239 fgVisual->dpy = (Display*)1; //fake (not used)
2240#endif
2241
2242 return kTRUE;
2243}
2244
2245////////////////////////////////////////////////////////////////////////////////
2246/// Start palette editor.
2247
2249{
2250 if (!IsValid()) {
2251 Warning("StartPaletteEditor", "Image not valid");
2252 return;
2253 }
2254 if (fImage->alt.vector == 0) {
2255 Warning("StartPaletteEditor", "palette can be modified only for data images");
2256 return;
2257 }
2258
2259 // Opens a GUI to edit the color palette
2261}
2262
2263////////////////////////////////////////////////////////////////////////////////
2264/// Returns image pixmap.
2265/// The pixmap must deleted by user.
2266
2268{
2269 if (!InitVisual()) {
2270 Warning("GetPixmap", "Visual not initiated");
2271 return 0;
2272 }
2273
2274 Pixmap_t ret;
2275
2276 ASImage *img = fScaledImage ? fScaledImage->fImage : fImage;
2277
2278 static int x11 = -1;
2279 if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11");
2280
2281 if (x11) { // use builtin version
2282 ret = (Pixmap_t)asimage2pixmap(fgVisual, gVirtualX->GetDefaultRootWindow(),
2283 img, 0, kTRUE);
2284 } else {
2285 if (!fImage->alt.argb32) {
2286 BeginPaint();
2287 }
2288 ret = gVirtualX->CreatePixmapFromData((unsigned char*)fImage->alt.argb32,
2289 fImage->width, fImage->height);
2290 }
2291
2292 return ret;
2293}
2294
2295////////////////////////////////////////////////////////////////////////////////
2296/// Returns image mask pixmap (alpha channel).
2297/// The pixmap must deleted by user.
2298
2300{
2301 Pixmap_t pxmap = 0;
2302
2303 if (!InitVisual()) {
2304 Warning("GetMask", "Visual not initiated");
2305 return pxmap;
2306 }
2307
2308 ASImage *img = fScaledImage ? fScaledImage->fImage : fImage;
2309
2310 if (!img) {
2311 Warning("GetMask", "No image");
2312 return pxmap;
2313 }
2314
2315 UInt_t hh = img->height;
2316 UInt_t ow = img->width%8;
2317 UInt_t ww = img->width - ow + (ow ? 8 : 0);
2318
2319 UInt_t bit = 0;
2320 int i = 0;
2321 UInt_t y = 0;
2322 UInt_t x = 0;
2323
2324 char *bits = new char[ww*hh]; //an array of bits
2325
2326 ASImageDecoder *imdec = start_image_decoding(fgVisual, img, SCL_DO_ALPHA,
2327 0, 0, ww, 0, 0);
2328 if (!imdec) {
2329 delete [] bits;
2330 return 0;
2331 }
2332
2333 for (y = 0; y < hh; y++) {
2334 imdec->decode_image_scanline(imdec);
2335 CARD32 *a = imdec->buffer.alpha;
2336
2337 for (x = 0; x < ww; x++) {
2338 if (a[x]) {
2339 SETBIT(bits[i], bit);
2340 } else {
2341 CLRBIT(bits[i], bit);
2342 }
2343 bit++;
2344 if (bit == 8) {
2345 bit = 0;
2346 i++;
2347 }
2348 }
2349 }
2350
2351 stop_image_decoding(&imdec);
2352 pxmap = gVirtualX->CreateBitmap(gVirtualX->GetDefaultRootWindow(), (const char *)bits,
2353 ww, hh);
2354 delete [] bits;
2355 return pxmap;
2356}
2357
2358////////////////////////////////////////////////////////////////////////////////
2359/// Create image from pixmap.
2360
2362{
2363 if (!InitVisual()) {
2364 Warning("SetImage", "Visual not initiated");
2365 return;
2366 }
2367
2368 DestroyImage();
2369 delete fScaledImage;
2370 fScaledImage = 0;
2371
2372 Int_t xy;
2373 UInt_t w, h;
2374 gVirtualX->GetWindowSize(pxm, xy, xy, w, h);
2375
2376 if (fName.IsNull()) fName.Form("img_%dx%d",w, h);
2377
2378 static int x11 = -1;
2379 if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11");
2380
2381 if (x11) { //use built-in optimized version
2382 fImage = picture2asimage(fgVisual, pxm, mask, 0, 0, w, h, kAllPlanes, 1, 0);
2383 } else {
2384 unsigned char *bits = gVirtualX->GetColorBits(pxm, 0, 0, w, h);
2385 if (!bits) { // error
2386 return;
2387 }
2388
2389 // no mask
2390 if (!mask) {
2391 fImage = bitmap2asimage(bits, w, h, 0, 0);
2392 delete [] bits;
2393 return;
2394 }
2395 unsigned char *mask_bits = gVirtualX->GetColorBits(mask, 0, 0, w, h);
2396 fImage = bitmap2asimage(bits, w, h, 0, mask_bits);
2397 delete [] mask_bits;
2398 delete [] bits;
2399 }
2400}
2401
2402////////////////////////////////////////////////////////////////////////////////
2403/// Return 2D array of machine dependent pixel values.
2404
2406{
2407 if (!fImage) {
2408 Warning("GetPixels", "Wrong Image");
2409 return 0;
2410 }
2411
2412 ASImage *img = fScaledImage ? fScaledImage->fImage : fImage;
2413 ASImageDecoder *imdec;
2414
2415 width = !width ? img->width : width;
2416 height = !height ? img->height : height;
2417
2418 if (x < 0) {
2419 width -= x;
2420 x = 0 ;
2421 }
2422 if (y < 0) {
2423 height -= y;
2424 y = 0;
2425 }
2426
2427 if ((x >= (int)img->width) || (y >= (int)img->height)) {
2428 return 0;
2429 }
2430
2431 if ((int)(x + width) > (int)img->width) {
2432 width = img->width - x;
2433 }
2434
2435 if ((int)(y + height) > (int)img->height) {
2436 height = img->height - y;
2437 }
2438
2439 if ((imdec = start_image_decoding(0, fImage, SCL_DO_ALL, 0, y,
2440 img->width, height, 0)) == 0) {
2441 Warning("GetPixels", "Failed to create image decoder");
2442 return 0;
2443 }
2444
2445 TArrayL *ret = new TArrayL(width * height);
2446 Int_t r = 0;
2447 Int_t g = 0;
2448 Int_t b = 0;
2449 Long_t p = 0;
2450
2451 for (UInt_t k = 0; k < height; k++) {
2452 imdec->decode_image_scanline(imdec);
2453
2454 for (UInt_t i = 0; i < width; ++i) {
2455 if ((r == (Int_t)imdec->buffer.red[i]) &&
2456 (g == (Int_t)imdec->buffer.green[i]) &&
2457 (b == (Int_t)imdec->buffer.blue[i])) {
2458 } else {
2459 r = (Int_t)imdec->buffer.red[i];
2460 g = (Int_t)imdec->buffer.green[i];
2461 b = (Int_t)imdec->buffer.blue[i];
2462 p = (Long_t)TColor::RGB2Pixel(r, g, b);
2463 }
2464 ret->AddAt(p, k*width + i);
2465 }
2466 }
2467
2468 stop_image_decoding(&imdec);
2469 return ret;
2470}
2471
2472////////////////////////////////////////////////////////////////////////////////
2473/// Return a pointer to internal array[width x height] of double values [0,1].
2474/// This array is directly accessible. That allows to manipulate/change the
2475/// image.
2476
2478{
2479 if (!fImage) {
2480 Warning("GetVecArray", "Bad Image");
2481 return 0;
2482 }
2483 if (fImage->alt.vector) {
2484 return fImage->alt.vector;
2485 }
2486 // vectorize
2487 return 0;
2488}
2489
2490////////////////////////////////////////////////////////////////////////////////
2491/// In case of vectorized image return an associated array of doubles
2492/// otherwise this method creates and returns a 2D array of doubles corresponding to palette.
2493/// If palette is ZERO a color converted to double value [0, 1] according to formula
2494/// ~~~ {.cpp}
2495/// Double_t((r << 16) + (g << 8) + b)/0xFFFFFF
2496/// ~~~
2497/// The returned array must be deleted after usage.
2498
2500{
2501 if (!fImage) {
2502 Warning("GetArray", "Bad Image");
2503 return 0;
2504 }
2505
2506 TArrayD *ret;
2507
2508 if (fImage->alt.vector) {
2509 ret = new TArrayD(fImage->width*fImage->height, fImage->alt.vector);
2510 return ret;
2511 }
2512
2513 ASImageDecoder *imdec;
2514
2515 w = w ? w : fImage->width;
2516 h = h ? h : fImage->height;
2517
2518 if ((fImage->width != w) || (fImage->height != h)) {
2519 Scale(w, h);
2520 }
2521
2522 ASImage *img = fScaledImage ? fScaledImage->fImage : fImage;
2523
2524 if ((imdec = start_image_decoding(0, img, SCL_DO_ALL, 0, 0,
2525 img->width, 0, 0)) == 0) {
2526 Warning("GetArray", "Failed to create image decoder");
2527 return 0;
2528 }
2529
2530 ret = new TArrayD(w * h);
2531 CARD32 r = 0;
2532 CARD32 g = 0;
2533 CARD32 b = 0;
2534 Int_t p = 0;
2535 Double_t v = 0;
2536
2537 for (UInt_t k = 0; k < h; k++) {
2538 imdec->decode_image_scanline(imdec);
2539
2540 for (UInt_t i = 0; i < w; ++i) {
2541 if ((r == imdec->buffer.red[i]) &&
2542 (g == imdec->buffer.green[i]) &&
2543 (b == imdec->buffer.blue[i])) {
2544 } else {
2545 r = imdec->buffer.red[i];
2546 g = imdec->buffer.green[i];
2547 b = imdec->buffer.blue[i];
2548 if (palette) p = palette->FindColor(r, g, b);
2549 }
2550 v = palette ? palette->fPoints[p] : Double_t((r << 16) + (g << 8) + b)/0xFFFFFF;
2551 ret->AddAt(v, (h-k-1)*w + i);
2552 }
2553 }
2554
2555 stop_image_decoding(&imdec);
2556 return ret;
2557}
2558
2559////////////////////////////////////////////////////////////////////////////////
2560/// Draw text of size (in pixels for TrueType fonts)
2561/// at position (x, y) with color specified by hex string.
2562///
2563/// - font_name: TrueType font's filename or X font spec or alias.
2564/// 3D style of text is one of the following:
2565/// * 0 plain 2D text,
2566/// * 1 embossed,
2567/// * 2 sunken,
2568/// * 3 shade above,
2569/// * 4 shade below,
2570/// * 5 embossed thick,
2571/// * 6 sunken thick.
2572/// * 7 outline above,
2573/// * 8 ouline below,
2574/// * 9 full ouline.
2575/// - fore_file specifies foreground texture of text.
2576
2578 const char *color, const char *font_name,
2579 EText3DType type, const char *fore_file, Float_t angle)
2580{
2581 UInt_t width=0, height=0;
2582 ARGB32 text_color = ARGB32_Black;
2583 ASImage *fore_im = 0;
2584 ASImage *text_im = 0;
2585 Bool_t ttfont = kFALSE;
2586
2587 if (!InitVisual()) {
2588 Warning("DrawText", "Visual not initiated");
2589 return;
2590 }
2591
2592 TString fn = font_name;
2593 fn.Strip();
2594
2595 // This is for backward compatibility...
2596 if (fn.Last('/') == 0) fn = fn(1, fn.Length() - 1);
2597
2598 const char *ttpath = gEnv->GetValue("Root.TTFontPath",
2600 char *tmpstr = gSystem->Which(ttpath, fn, kReadPermission);
2601 fn = tmpstr;
2602 delete [] tmpstr;
2603
2604 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")) {
2605 ttfont = kTRUE;
2606 }
2607
2608 if (color) {
2609 parse_argb_color(color, &text_color);
2610 }
2611
2612 if (fImage && fImage->alt.argb32 && ttfont) {
2613 DrawTextTTF(x, y, text, size, text_color, fn.Data(), angle);
2614 return;
2615 }
2616
2617 if (!gFontManager) {
2618 gFontManager = create_font_manager(fgVisual->dpy, 0, 0);
2619 }
2620
2621 if (!gFontManager) {
2622 Warning("DrawText", "cannot create Font Manager");
2623 return;
2624 }
2625
2626 ASFont *font = get_asfont(gFontManager, fn.Data(), 0, size, ASF_GuessWho);
2627
2628 if (!font) {
2629 font = get_asfont(gFontManager, "fixed", 0, size, ASF_GuessWho);
2630 if (!font) {
2631 Warning("DrawText", "cannot find a font %s", font_name);
2632 return;
2633 }
2634 }
2635
2636 get_text_size(text, font, (ASText3DType)type, &width, &height);
2637
2638 if (!fImage) {
2639 fImage = create_asimage(width, height, 0);
2640 fill_asimage(fgVisual, fImage, 0, 0, width, height, 0xFFFFFFFF);
2641 }
2642
2643 text_im = draw_text(text, font, (ASText3DType)type, 0);
2644
2645 ASImage *rimg = fImage;
2646
2647 if (fore_file) {
2648 ASImage *tmp = file2ASImage(fore_file, 0xFFFFFFFF, SCREEN_GAMMA, 0, 0);
2649 if (tmp) {
2650 if ((tmp->width != width) || (tmp->height != height)) {
2651 fore_im = tile_asimage(fgVisual, tmp, 0, 0, width, height, 0,
2652 ASA_ASImage, GetImageCompression(), GetImageQuality());
2653 }
2654 destroy_asimage(&tmp);
2655 } else {
2656 fore_im = tmp;
2657 }
2658 }
2659
2660 if (fore_im) {
2661 move_asimage_channel(fore_im, IC_ALPHA, text_im, IC_ALPHA);
2662 destroy_asimage(&text_im);
2663 } else {
2664 fore_im = text_im ;
2665 }
2666
2667 release_font(font);
2668
2669 if (fore_im) {
2670 ASImage *rendered_im;
2671 ASImageLayer layers[2];
2672
2673 init_image_layers(&(layers[0]), 2);
2674 fore_im->back_color = text_color;
2675 layers[0].im = rimg;
2676 layers[0].dst_x = 0;
2677 layers[0].dst_y = 0;
2678 layers[0].clip_width = rimg->width;
2679 layers[0].clip_height = rimg->height;
2680 layers[0].bevel = 0;
2681 layers[1].im = fore_im;
2682 layers[1].dst_x = x;
2683 layers[1].dst_y = y;
2684 layers[1].clip_width = fore_im->width;
2685 layers[1].clip_height = fore_im->height;
2686
2687 rendered_im = merge_layers(fgVisual, &(layers[0]), 2, rimg->width, rimg->height,
2688 ASA_ASImage, GetImageCompression(), GetImageQuality());
2689
2690 destroy_asimage(&fore_im);
2691 DestroyImage();
2692 fImage = rendered_im;
2693 UnZoom();
2694 }
2695}
2696
2697////////////////////////////////////////////////////////////////////////////////
2698/// Merge two images.
2699///
2700/// op is string which specifies overlay operation. Supported operations are:
2701///
2702/// - add - color addition with saturation
2703/// - alphablend - alpha-blending
2704/// - allanon - color values averaging
2705/// - colorize - hue and saturate bottom image same as top image
2706/// - darken - use lowest color value from both images
2707/// - diff - use absolute value of the color difference between two images
2708/// - dissipate - randomly alpha-blend images
2709/// - hue - hue bottom image same as top image
2710/// - lighten - use highest color value from both images
2711/// - overlay - some weird image overlaying(see GIMP)
2712/// - saturate - saturate bottom image same as top image
2713/// - screen - another weird image overlaying(see GIMP)
2714/// - sub - color substraction with saturation
2715/// - tint - tinting image with image
2716/// - value - value bottom image same as top image
2717
2718void TASImage::Merge(const TImage *im, const char *op, Int_t x, Int_t y)
2719{
2720 if (!im) return;
2721
2722 if (!InitVisual()) {
2723 Warning("Merge", "Visual not initiated");
2724 return;
2725 }
2726
2727 ASImage *rendered_im;
2728 ASImageLayer layers[2];
2729
2730 init_image_layers(&(layers[0]), 2);
2731 layers[0].im = fImage;
2732 layers[0].dst_x = 0;
2733 layers[0].dst_y = 0;
2734 layers[0].clip_width = fImage->width;
2735 layers[0].clip_height = fImage->height;
2736 layers[0].bevel = 0;
2737 layers[1].im = ((TASImage*)im)->fImage;
2738 layers[1].dst_x = x;
2739 layers[1].dst_y = y;
2740 layers[1].clip_width = im->GetWidth();
2741 layers[1].clip_height = im->GetHeight();
2742 layers[1].merge_scanlines = blend_scanlines_name2func(op ? op : "add");
2743
2744 rendered_im = merge_layers(fgVisual, &(layers[0]), 2, fImage->width, fImage->height,
2745 ASA_ASImage, GetImageCompression(), GetImageQuality());
2746
2747 DestroyImage();
2748 fImage = rendered_im;
2749 UnZoom();
2750}
2751
2752////////////////////////////////////////////////////////////////////////////////
2753/// Perform Gaussian blur of the image (useful for drop shadows).
2754/// - hr - horizontal radius of the blur
2755/// - vr - vertical radius of the blur
2756
2758{
2759 if (!InitVisual()) {
2760 Warning("Blur", "Visual not initiated");
2761 return;
2762 }
2763
2764 if (!fImage) {
2765 fImage = create_asimage(100, 100, 0);
2766
2767 if (!fImage) {
2768 Warning("Blur", "Failed to create image");
2769 return;
2770 }
2771
2772 fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, ARGB32_White);
2773 }
2774
2775 ASImage *rendered_im = blur_asimage_gauss(fgVisual, fImage, hr > 0 ? hr : 3,
2776 vr > 0 ? vr : 3, SCL_DO_ALL,
2777 ASA_ASImage, GetImageCompression(), GetImageQuality());
2778 DestroyImage();
2779 fImage = rendered_im;
2780 UnZoom();
2781}
2782
2783////////////////////////////////////////////////////////////////////////////////
2784/// Clone image.
2785
2786TObject *TASImage::Clone(const char *newname) const
2787{
2788 if (!InitVisual() || !fImage) {
2789 Warning("Clone", "Image not initiated");
2790 return 0;
2791 }
2792
2794
2795 if (!im) {
2796 Warning("Clone", "Failed to create image");
2797 return 0;
2798 }
2799
2800 im->SetName(newname);
2801
2802 im->fImage = clone_asimage(fImage, SCL_DO_ALL);
2803 im->fMaxValue = fMaxValue;
2804 im->fMinValue = fMinValue;
2805 im->fZoomOffX = fZoomOffX;
2806 im->fZoomOffY = fZoomOffY;
2807 im->fZoomWidth = fZoomWidth;
2811
2812 if (fImage->alt.argb32) {
2813 UInt_t sz = fImage->width * fImage->height;
2814 im->fImage->alt.argb32 = (ARGB32*)safemalloc(sz*sizeof(ARGB32));
2815 memcpy(im->fImage->alt.argb32, fImage->alt.argb32, sz * sizeof(ARGB32));
2816 }
2817
2818 return im;
2819}
2820
2821////////////////////////////////////////////////////////////////////////////////
2822/// Reduce color-depth of an image and fills vector of "scientific data"
2823/// [0...1]
2824///
2825/// Colors are reduced by allocating color cells to most used colors first,
2826/// and then approximating other colors with those allocated.
2827///
2828/// \param[in] max_colors - maximum size of the colormap.
2829/// \param[in] dither - number of bits to strip off the color data ( 0...7 )
2830/// \param[in] opaque_threshold - alpha channel threshold at which pixel should be treated as opaque
2831
2832Double_t *TASImage::Vectorize(UInt_t max_colors, UInt_t dither, Int_t opaque_threshold)
2833{
2834 if (!InitVisual()) {
2835 Warning("Vectorize", "Visual not initiated");
2836 return 0;
2837 }
2838
2839 if (!fImage) {
2840 fImage = create_asimage(100, 100, 0);
2841
2842 if (!fImage) {
2843 Warning("Vectorize", "Failed to create image");
2844 return 0;
2845 }
2846
2847 fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, ARGB32_White);
2848 }
2849
2850 ASColormap cmap;
2851 int *res;
2852 UInt_t r=0, g=0, b=0;
2853
2854 dither = dither > 7 ? 7 : dither;
2855
2856 res = colormap_asimage(fImage, &cmap, max_colors, dither, opaque_threshold);
2857
2858 Double_t *vec = new Double_t[fImage->height*fImage->width];
2859 UInt_t v;
2860 Double_t tmp;
2861 fMinValue = 2;
2862 fMaxValue = -1;
2863
2864 for (UInt_t y = 0; y < fImage->height; y++) {
2865 for (UInt_t x = 0; x < fImage->width; x++) {
2866 int i = y*fImage->width + x;
2867 if (res) {
2868 g = INDEX_SHIFT_GREEN(cmap.entries[res[i]].green);
2869 b = INDEX_SHIFT_BLUE(cmap.entries[res[i]].blue);
2870 r = INDEX_SHIFT_RED(cmap.entries[res[i]].red);
2871 }
2872 v = MAKE_INDEXED_COLOR24(r,g,b);
2873 v = (v>>12)&0x0FFF;
2874 tmp = Double_t(v)/0x0FFF;
2875 vec[(fImage->height - y - 1)*fImage->width + x] = tmp;
2876 if (fMinValue > tmp) fMinValue = tmp;
2877 if (fMaxValue < tmp) fMaxValue = tmp;
2878 }
2879 }
2880 TImagePalette *pal = new TImagePalette(cmap.count);
2881
2882 for (UInt_t j = 0; j < cmap.count; j++) {
2883 g = INDEX_SHIFT_GREEN(cmap.entries[j].green);
2884 b = INDEX_SHIFT_BLUE(cmap.entries[j].blue);
2885 r = INDEX_SHIFT_RED(cmap.entries[j].red);
2886 v = MAKE_INDEXED_COLOR24(r,g,b);
2887
2888 v = (v>>12) & 0x0FFF;
2889 pal->fPoints[j] = Double_t(v)/0x0FFF;
2890
2891 pal->fColorRed[j] = cmap.entries[j].red << 8;
2892 pal->fColorGreen[j] = cmap.entries[j].green << 8;
2893 pal->fColorBlue[j] = cmap.entries[j].blue << 8;
2894 pal->fColorAlpha[j] = 0xFF00;
2895 }
2896
2897 destroy_colormap(&cmap, kTRUE);
2898
2899 fPalette = *pal;
2900 fImage->alt.vector = vec;
2901 UnZoom();
2902 // ROOT-7647: res is allocated with `safemalloc` by colormap_asimage
2903 if (res) safefree(res);
2904 return (Double_t*)fImage->alt.vector;
2905}
2906
2907////////////////////////////////////////////////////////////////////////////////
2908/// This function will tile original image to specified size with offsets
2909/// requested, and then it will go though it and adjust hue, saturation and
2910/// value of those pixels that have specific hue, set by affected_hue/
2911/// affected_radius parameters. When affected_radius is greater then 180
2912/// entire image will be adjusted. Note that since grayscale colors have
2913/// no hue - the will not get adjusted. Only saturation and value will be
2914/// adjusted in gray pixels.
2915///
2916/// Hue is measured as an angle on a 360 degree circle, The following is
2917/// relationship of hue values to regular color names :
2918/// - red - 0
2919/// - yellow - 60
2920/// - green - 120
2921/// - cyan - 180
2922/// - blue - 240
2923/// - magenta - 300
2924/// - red - 360
2925///
2926/// All the hue values in parameters will be adjusted to fall within 0-360 range.
2927///
2928/// \param[in] hue hue in degrees in range 0-360. This allows to limit
2929/// impact of color adjustment to affect only limited range of hues.
2930///
2931/// \param[in] radius value in degrees to be used in order to
2932/// calculate the range of affected hues. Range is determined by
2933/// substracting and adding this value from/to affected_hue.
2934///
2935/// \param[in] H value by which to change hues in affected range.
2936/// \param[in] S value by which to change saturation of the pixels in affected hue range.
2937/// \param[in] V value by which to change Value(brightness) of pixels in affected hue range.
2938///
2939/// \param[in] x,y position on infinite surface tiled with original image, of the
2940/// left-top corner of the area to be used for new image.
2941///
2942/// \param[in] width, height size of the area of the original image to be used for new image.
2943/// Default is current width, height of the image.
2944
2945void TASImage::HSV(UInt_t hue, UInt_t radius, Int_t H, Int_t S, Int_t V,
2946 Int_t x, Int_t y, UInt_t width, UInt_t height)
2947{
2948 if (!InitVisual()) {
2949 Warning("HSV", "Visual not initiated");
2950 return;
2951 }
2952
2953 if (!fImage) {
2954 fImage = create_asimage(width ? width : 20, height ? height : 20, 0);
2955
2956 if (!fImage) {
2957 Warning("HSV", "Failed to create image");
2958 return;
2959 }
2960
2961 x = 0;
2962 y = 0;
2963 fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, ARGB32_White);
2964 }
2965
2966 width = !width ? fImage->width : width;
2967 height = !height ? fImage->height : height;
2968
2969 ASImage *rendered_im = 0;
2970
2971 if (H || S || V) {
2972 rendered_im = adjust_asimage_hsv(fgVisual, fImage, x, y, width, height,
2973 hue, radius, H, S, V, ASA_ASImage, 100,
2974 ASIMAGE_QUALITY_TOP);
2975 }
2976 if (!rendered_im) {
2977 Warning("HSV", "Failed to create rendered image");
2978 return;
2979 }
2980
2981 DestroyImage();
2982 fImage = rendered_im;
2983 UnZoom();
2984}
2985
2986////////////////////////////////////////////////////////////////////////////////
2987/// Render multipoint gradient inside rectangle of size (width, height)
2988/// at position (x,y) within the existing image.
2989///
2990/// \param[in] angle Given in degrees. Default is 0. This is the
2991/// direction of the gradient. Currently the only supported
2992/// values are 0, 45, 90, 135, 180, 225, 270, 315. 0 means left
2993/// to right, 90 means top to bottom, etc.
2994///
2995/// \param[in] colors Whitespace-separated list of colors. At least two
2996/// colors are required. Each color in this list will be visited
2997/// in turn, at the intervals given by the offsets attribute.
2998///
2999/// \param[in] offsets Whitespace-separated list of floating point values
3000/// ranging from 0.0 to 1.0. The colors from the colors attribute
3001/// are given these offsets, and the final gradient is rendered
3002/// from the combination of the two. If both colors and offsets
3003/// are given but the number of colors and offsets do not match,
3004/// the minimum of the two will be used, and the other will be
3005/// truncated to match. If offsets are not given, a smooth
3006/// stepping from 0.0 to 1.0 will be used.
3007
3008void TASImage::Gradient(UInt_t angle, const char *colors, const char *offsets,
3009 Int_t x, Int_t y, UInt_t width, UInt_t height)
3010{
3011 if (!InitVisual()) {
3012 Warning("Gradient", "Visual not initiated");
3013 return;
3014 }
3015
3016 ASImage *rendered_im = 0;
3017 ASGradient gradient;
3018
3019 int reverse = 0, npoints1 = 0, npoints2 = 0;
3020 char *p;
3021 char *pb;
3022 char ch;
3023 TString str = colors;
3024 TString col;
3025
3026 if ((angle > 2 * 180 * 15 / 16) || (angle < 2 * 180 * 1 / 16)) {
3027 gradient.type = GRADIENT_Left2Right;
3028 } else if (angle < 2 * 180 * 3 / 16) {
3029 gradient.type = GRADIENT_TopLeft2BottomRight;
3030 } else if (angle < 2 * 180 * 5 / 16) {
3031 gradient.type = GRADIENT_Top2Bottom;
3032 } else if (angle < 2 * 180 * 7 / 16) {
3033 gradient.type = GRADIENT_BottomLeft2TopRight; reverse = 1;
3034 } else if (angle < 2 * 180 * 9 / 16) {
3035 gradient.type = GRADIENT_Left2Right; reverse = 1;
3036 } else if (angle < 2 * 180 * 11 / 16) {
3037 gradient.type = GRADIENT_TopLeft2BottomRight; reverse = 1;
3038 } else if (angle < 2 * 180 * 13 / 16) {
3039 gradient.type = GRADIENT_Top2Bottom; reverse = 1;
3040 } else {
3041 gradient.type = GRADIENT_BottomLeft2TopRight;
3042 }
3043
3044 for (p = (char*)colors; isspace((int)*p); p++) { }
3045
3046 for (npoints1 = 0; *p; npoints1++) {
3047 if (*p) {
3048 for ( ; *p && !isspace((int)*p); p++) { }
3049 }
3050 for ( ; isspace((int)*p); p++) { }
3051 }
3052 if (offsets) {
3053 for (p = (char*)offsets; isspace((int)*p); p++) { }
3054
3055 for (npoints2 = 0; *p; npoints2++) {
3056 if (*p) {
3057 for ( ; *p && !isspace((int)*p); p++) { }
3058 }
3059 for ( ; isspace((int)*p); p++) { }
3060 }
3061 }
3062 if (npoints1 > 1) {
3063 int i;
3064 if (offsets && (npoints1 > npoints2)) npoints1 = npoints2;
3065
3066 if (!width) {
3067 width = fImage ? fImage->width : 20;
3068 }
3069 if (!height) {
3070 height = fImage ? fImage->height : 20;
3071 }
3072
3073 gradient.color = new ARGB32[npoints1];
3074 gradient.offset = new double[npoints1];
3075
3076 for (p = (char*)colors; isspace((int)*p); p++) { }
3077
3078 for (npoints1 = 0; *p; ) {
3079 pb = p;
3080
3081 if (*p) {
3082 for ( ; *p && !isspace((int)*p); p++) { }
3083 }
3084 for ( ; isspace((int)*p); p++) { }
3085
3086 col = str(pb - colors, p - pb);
3087
3088 if (parse_argb_color(col.Data(), gradient.color + npoints1) != col) {
3089 npoints1++;
3090 } else {
3091 Warning("Gradient", "Failed to parse color [%s] - defaulting to black", pb);
3092 }
3093 }
3094
3095 if (offsets) {
3096 for (p = (char*)offsets; isspace((int)*p); p++) { }
3097
3098 for (npoints2 = 0; *p; ) {
3099 pb = p;
3100
3101 if (*p) {
3102 for ( ; *p && !isspace((int)*p); p++) { }
3103 }
3104 ch = *p; *p = '\0';
3105 gradient.offset[npoints2] = strtod(pb, &pb);
3106
3107 if (pb == p) npoints2++;
3108 *p = ch;
3109 for ( ; isspace((int)*p); p++) { }
3110 }
3111 } else {
3112 for (npoints2 = 0; npoints2 < npoints1; npoints2++) {
3113 gradient.offset[npoints2] = (double)npoints2 / (npoints1 - 1);
3114 }
3115 }
3116 gradient.npoints = npoints1;
3117
3118 if (npoints2 && (gradient.npoints > npoints2)) {
3119 gradient.npoints = npoints2;
3120 }
3121 if (reverse) {
3122 for (i = 0; i < gradient.npoints/2; i++) {
3123 int i2 = gradient.npoints - 1 - i;
3124 ARGB32 c = gradient.color[i];
3125 double o = gradient.offset[i];
3126 gradient.color[i] = gradient.color[i2];
3127 gradient.color[i2] = c;
3128 gradient.offset[i] = gradient.offset[i2];
3129 gradient.offset[i2] = o;
3130 }
3131 for (i = 0; i < gradient.npoints; i++) {
3132 gradient.offset[i] = 1.0 - gradient.offset[i];
3133 }
3134 }
3135 rendered_im = make_gradient(fgVisual, &gradient, width, height, SCL_DO_ALL,
3136 ASA_ASImage, GetImageCompression(), GetImageQuality());
3137
3138 delete [] gradient.color;
3139 delete [] gradient.offset;
3140 }
3141
3142 if (!rendered_im) { // error
3143 Warning("Gradient", "Failed to create gradient image");
3144 return;
3145 }
3146
3147 if (!fImage) {
3148 fImage = rendered_im;
3149 return;
3150 }
3151
3152 ASImageLayer layers[2];
3153
3154 init_image_layers(&(layers[0]), 2);
3155 layers[0].im = fImage;
3156 layers[0].dst_x = 0;
3157 layers[0].dst_y = 0;
3158 layers[0].clip_width = fImage->width;
3159 layers[0].clip_height = fImage->height;
3160 layers[0].bevel = 0;
3161 layers[1].im = rendered_im;
3162 layers[1].dst_x = x;
3163 layers[1].dst_y = y;
3164 layers[1].clip_width = width;
3165 layers[1].clip_height = height;
3166 layers[1].merge_scanlines = alphablend_scanlines;
3167
3168 ASImage *merge_im = merge_layers(fgVisual, &(layers[0]), 2, fImage->width, fImage->height,
3169 ASA_ASImage, GetImageCompression(), GetImageQuality());
3170 if (!merge_im) {
3171 Warning("Gradient", "Failed to create merged image");
3172 return;
3173 }
3174
3175 destroy_asimage(&rendered_im);
3176 DestroyImage();
3177 fImage = merge_im;
3178 UnZoom();
3179}
3180
3181////////////////////////////////////////////////////////////////////////////////
3182/// Make component hilite.
3183/// (used internally)
3184
3185static CARD8 MakeComponentHilite(int cmp)
3186{
3187 if (cmp < 51) {
3188 cmp = 51;
3189 }
3190 cmp = (cmp * 12) / 10;
3191
3192 return (cmp > 255) ? 255 : cmp;
3193}
3194
3195////////////////////////////////////////////////////////////////////////////////
3196/// Calculate highlite color.
3197/// (used internally)
3198
3199static ARGB32 GetHilite(ARGB32 background)
3200{
3201 return ((MakeComponentHilite((background>>24) & 0x000000FF) << 24) & 0xFF000000) |
3202 ((MakeComponentHilite((background & 0x00FF0000) >> 16) << 16) & 0x00FF0000) |
3203 ((MakeComponentHilite((background & 0x0000FF00) >> 8) << 8) & 0x0000FF00) |
3204 ((MakeComponentHilite((background & 0x000000FF))) & 0x000000FF);
3205}
3206
3207////////////////////////////////////////////////////////////////////////////////
3208/// Calculate shadow color.
3209/// (used internally)
3210
3211static ARGB32 GetShadow(ARGB32 background)
3212{
3213 return (background >> 1) & 0x7F7F7F7F;
3214}
3215
3216////////////////////////////////////////////////////////////////////////////////
3217/// Get average.
3218/// (used internally)
3219
3220static ARGB32 GetAverage(ARGB32 foreground, ARGB32 background)
3221{
3222 CARD16 a, r, g, b;
3223
3224 a = ARGB32_ALPHA8(foreground) + ARGB32_ALPHA8(background);
3225 a = (a<<3)/10;
3226 r = ARGB32_RED8(foreground) + ARGB32_RED8(background);
3227 r = (r<<3)/10;
3228 g = ARGB32_GREEN8(foreground) + ARGB32_GREEN8(background);
3229 g = (g<<3)/10;
3230 b = ARGB32_BLUE8(foreground) + ARGB32_BLUE8(background);
3231 b = (b<<3)/10;
3232
3233 return MAKE_ARGB32(a, r, g, b);
3234}
3235
3236
3237////////////////////////////////////////////////////////////////////////////////
3238/// Bevel is used to create 3D effect while drawing buttons, or any other
3239/// image that needs to be framed. Bevel is drawn using 2 primary colors:
3240/// one for top and left sides - hi color, and another for bottom and
3241/// right sides - low color. Bevel can be drawn over existing image or
3242/// as newly created, as it is shown in code below:
3243/// ~~~ {.cpp}
3244/// TImage *img = TImage::Create();
3245/// img->Bevel(0, 0, 400, 300, "#dddddd", "#000000", 3);
3246/// ~~~
3247
3249 const char *hi_color, const char *lo_color, UShort_t thick,
3250 Bool_t reverse)
3251{
3252 if (!InitVisual()) {
3253 Warning("Bevel", "Visual not initiated");
3254 return;
3255 }
3256
3257 ASImageBevel bevel;
3258 bevel.type = 0;
3259
3260 ARGB32 hi=ARGB32_White, lo=ARGB32_White;
3261 parse_argb_color(hi_color, &hi);
3262 parse_argb_color(lo_color, &lo);
3263
3264 if (reverse) {
3265 bevel.lo_color = hi;
3266 bevel.lolo_color = GetHilite(hi);
3267 bevel.hi_color = lo;
3268 bevel.hihi_color = GetShadow(lo);
3269 } else {
3270 bevel.hi_color = hi;
3271 bevel.hihi_color = GetHilite(hi);
3272 bevel.lo_color = lo;
3273 bevel.lolo_color = GetShadow(lo);
3274 }
3275 bevel.hilo_color = GetAverage(hi, lo);
3276
3277 int extra_hilite = 2;
3278 bevel.left_outline = bevel.top_outline = bevel.right_outline = bevel.bottom_outline = thick;
3279 bevel.left_inline = bevel.top_inline = bevel.right_inline = bevel.bottom_inline = extra_hilite + 1;
3280
3281 if (bevel.top_outline > 1) {
3282 bevel.top_inline += bevel.top_outline - 1;
3283 }
3284
3285 if (bevel.left_outline > 1) {
3286 bevel.left_inline += bevel.left_outline - 1;
3287 }
3288
3289 if (bevel.right_outline > 1) {
3290 bevel.right_inline += bevel.right_outline - 1;
3291 }
3292
3293 if (bevel.bottom_outline > 1) {
3294 bevel.bottom_inline += bevel.bottom_outline - 1;
3295 }
3296
3297 ASImage *merge_im;
3298 ARGB32 fill = ((hi>>24) != 0xff) || ((lo>>24) != 0xff) ? bevel.hilo_color : (bevel.hilo_color | 0xff000000);
3299
3300 if (!fImage) {
3301 fImage = create_asimage(width ? width : 20, height ? height : 20, 0);
3302
3303 if (!fImage) {
3304 Warning("Bevel", "Failed to create image");
3305 return;
3306 }
3307
3308 x = 0;
3309 y = 0;
3310 fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, fill);
3311 }
3312
3313 width = !width ? fImage->width : width;
3314 height = !height ? fImage->height : height;
3315
3316 ASImageLayer layers[2];
3317 init_image_layers(&(layers[0]), 2);
3318
3319 layers[0].im = fImage;
3320 layers[0].dst_x = 0;
3321 layers[0].dst_y = 0;
3322 layers[0].clip_width = fImage->width;
3323 layers[0].clip_height = fImage->height;
3324 layers[0].bevel = 0;
3325
3326 UInt_t w = width - (bevel.left_outline + bevel.right_outline);
3327 UInt_t h = height - (bevel.top_outline + bevel.bottom_outline);
3328 ASImage *bevel_im = create_asimage(w, h, 0);
3329
3330 if (!bevel_im) {
3331 Warning("Bevel", "Failed to create bevel image");
3332 return;
3333 }
3334
3335 layers[1].im = bevel_im;
3336 fill_asimage(fgVisual, bevel_im, 0, 0, w, h, fill);
3337
3338 layers[1].dst_x = x;
3339 layers[1].dst_y = y;
3340 layers[1].clip_width = width;
3341 layers[1].clip_height = height;
3342 layers[1].bevel = &bevel;
3343 layers[1].merge_scanlines = alphablend_scanlines;
3344
3345 merge_im = merge_layers(fgVisual, &(layers[0]), 2, fImage->width, fImage->height,
3346 ASA_ASImage, GetImageCompression(), GetImageQuality());
3347 destroy_asimage(&bevel_im);
3348
3349 if (!merge_im) {
3350 Warning("Bevel", "Failed to image");
3351 return;
3352 }
3353
3354 DestroyImage();
3355 fImage = merge_im;
3356 UnZoom();
3357}
3358
3359
3360////////////////////////////////////////////////////////////////////////////////
3361/// Enlarge image, padding it with specified color on each side in
3362/// accordance with requested geometry.
3363
3364void TASImage::Pad(const char *col, UInt_t l, UInt_t r, UInt_t t, UInt_t b)
3365{
3366 Int_t x, y;
3367 UInt_t w, h;
3368
3369 if (!InitVisual()) {
3370 Warning("Pad", "Visual not initiated");
3371 return;
3372 }
3373
3374 if (!fImage) {
3375 fImage = create_asimage(100, 100, 0);
3376
3377 if (!fImage) {
3378 Warning("Pad", "Failed to create image");
3379 return;
3380 }
3381
3382 fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, ARGB32_White);
3383 }
3384
3385 ARGB32 color = ARGB32_White;
3386 parse_argb_color(col, &color);
3387
3388 x = l;
3389 y = t;
3390 w = l + fImage->width + r;
3391 h = t + fImage->height + b;
3392
3393 ASImage *img = pad_asimage(fgVisual, fImage, x, y, w, h, color,
3394 ASA_ASImage, GetImageCompression(), GetImageQuality());
3395
3396 if (!img) {
3397 Warning("Pad", "Failed to create output image");
3398 return;
3399 }
3400
3401 DestroyImage();
3402 fImage = img;
3403 UnZoom();
3405}
3406
3407
3408////////////////////////////////////////////////////////////////////////////////
3409/// Crop an image.
3410
3412{
3413 if (!InitVisual()) {
3414 Warning("Crop", "Visual not initiated");
3415 return;
3416 }
3417
3418 if (!fImage) {
3419 Warning("Crop", "No image");
3420 return;
3421 }
3422
3423 x = x < 0 ? 0 : x;
3424 y = y < 0 ? 0 : y;
3425
3426 width = x + width > fImage->width ? fImage->width - x : width;
3427 height = y + height > fImage->height ? fImage->height - y : height;
3428
3429 if ((width == fImage->width) && (height == fImage->height)) {
3430 Warning("Crop", "input size larger than image");
3431 return;
3432 }
3433 ASImageDecoder *imdec = start_image_decoding(fgVisual, fImage, SCL_DO_ALL,
3434 x, y, width, height, 0);
3435
3436 if (!imdec) {
3437 Warning("Crop", "Failed to start image decoding");
3438 return;
3439 }
3440
3441 ASImage *img = create_asimage(width, height, 0);
3442
3443 if (!img) {
3444 delete [] imdec;
3445 Warning("Crop", "Failed to create image");
3446 return;
3447 }
3448
3449 ASImageOutput *imout = start_image_output(fgVisual, img, ASA_ASImage,
3451
3452 if (!imout) {
3453 Warning("Crop", "Failed to start image output");
3454 destroy_asimage(&img);
3455 if (imdec) delete [] imdec;
3456 return;
3457 }
3458
3459#ifdef HAVE_MMX
3460 mmx_init();
3461#endif
3462
3463 for (UInt_t i = 0; i < height; i++) {
3464 imdec->decode_image_scanline(imdec);
3465 imout->output_image_scanline(imout, &(imdec->buffer), 1);
3466 }
3467
3468 stop_image_decoding(&imdec);
3469 stop_image_output(&imout);
3470
3471#ifdef HAVE_MMX
3472 mmx_off();
3473#endif
3474
3475 DestroyImage();
3476 fImage = img;
3477 UnZoom();
3479}
3480
3481////////////////////////////////////////////////////////////////////////////////
3482/// Append image.
3483///
3484/// option:
3485/// - "+" - appends to the right side
3486/// - "/" - appends to the bottom
3487
3488void TASImage::Append(const TImage *im, const char *option, const char *color )
3489{
3490 if (!im) return;
3491
3492 if (!InitVisual()) {
3493 Warning("Append", "Visual not initiated");
3494 return;
3495 }
3496
3497 if (!fImage) {
3498 fImage = ((TASImage*)im)->fImage;
3499 return;
3500 }
3501
3502 TString opt = option;
3503 opt.Strip();
3504
3505 UInt_t width = fImage->width;
3506 UInt_t height = fImage->height;
3507
3508 if (opt == "+") {
3509 Pad(color, 0, im->GetWidth(), 0, 0);
3510 Merge(im, "alphablend", width, 0);
3511 } else if (opt == "/") {
3512 Pad(color, 0, 0, 0, im->GetHeight());
3513 Merge(im, "alphablend", 0, height);
3514 } else {
3515 return;
3516 }
3517
3518 UnZoom();
3519}
3520
3521////////////////////////////////////////////////////////////////////////////////
3522/// BeginPaint initializes internal array[width x height] of ARGB32 pixel
3523/// values.
3524///
3525/// That provides quick access to image during paint operations.
3526/// To RLE compress image one needs to call EndPaint method when painting
3527/// is over.
3528
3530{
3531 if (!InitVisual()) {
3532 Warning("BeginPaint", "Visual not initiated");
3533 return;
3534 }
3535
3536 if (!fImage) {
3537 return;
3538 }
3539
3540 fPaintMode = mode;
3541
3542 if (!fPaintMode || fImage->alt.argb32) {
3543 return;
3544 }
3545
3546 ASImage *img = tile_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height,
3547 0, ASA_ARGB32, 0, ASIMAGE_QUALITY_DEFAULT);
3548
3549 if (!img) {
3550 Warning("BeginPaint", "Failed to create image");
3551 return;
3552 }
3553
3554 DestroyImage();
3555 fImage = img;
3556}
3557
3558////////////////////////////////////////////////////////////////////////////////
3559/// EndPaint does internal RLE compression of image data.
3560
3562{
3563 if (!fImage) {
3564 Warning("EndPaint", "no image");
3565 return;
3566 }
3567
3568 if (!fImage->alt.argb32) return;
3569
3570 ASImage *img = tile_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height,
3571 0, ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT);
3572
3573 if (!img) {
3574 Warning("EndPaint", "Failed to create image");
3575 return;
3576 }
3577
3579 DestroyImage();
3580 fImage = img;
3581}
3582
3583////////////////////////////////////////////////////////////////////////////////
3584/// Return a pointer to internal array[width x height] of ARGB32 values
3585/// This array is directly accessible. That allows to manipulate/change the
3586/// image.
3587
3589{
3590 if (!fImage) {
3591 Warning("GetArgbArray", "no image");
3592 return 0;
3593 }
3594
3595 ASImage *img = fScaledImage ? fScaledImage->fImage : fImage;
3596 if (!img) return 0;
3597
3598 if (!img->alt.argb32) {
3599 if (fScaledImage) {
3601 img = fScaledImage->fImage;
3602 } else {
3603 BeginPaint();
3604 img = fImage;
3605 }
3606 }
3607
3608 return (UInt_t *)img->alt.argb32;
3609}
3610
3611////////////////////////////////////////////////////////////////////////////////
3612/// Return a pointer to an array[width x height] of RGBA32 values.
3613/// This array is created from internal ARGB32 array,
3614/// must be deleted after usage.
3615
3617{
3618 if (!fImage) {
3619 Warning("GetRgbaArray", "no image");
3620 return 0;
3621 }
3622
3623 ASImage *img = fScaledImage ? fScaledImage->fImage : fImage;
3624 if (!img) return 0;
3625
3626 if (!img->alt.argb32) {
3627 if (fScaledImage) {
3629 img = fScaledImage->fImage;
3630 } else {
3631 BeginPaint();
3632 img = fImage;
3633 }
3634 }
3635
3636 UInt_t i, j;
3637 Int_t y = 0;
3638 Int_t idx = 0;
3639 UInt_t a, rgb, rgba, argb;
3640 y = 0;
3641
3642 UInt_t *ret = new UInt_t[img->width*img->height];
3643
3644 for (i = 0; i < img->height; i++) {
3645 for (j = 0; j < img->width; j++) {
3646 idx = Idx(y + j);
3647 argb = img->alt.argb32[idx];
3648 a = argb >> 24;
3649 rgb = argb & 0x00ffffff;
3650 rgba = (rgb << 8) + a;
3651 ret[idx] = rgba;
3652 }
3653 y += img->width;
3654 }
3655
3656 return ret;
3657}
3658
3659////////////////////////////////////////////////////////////////////////////////
3660/// Return a pointer to scan-line.
3661
3663{
3664 if (!fImage) {
3665 Warning("GetScanline", "no image");
3666 return 0;
3667 }
3668
3669 ASImage *img = fScaledImage ? fScaledImage->fImage : fImage;
3670 CARD32 *ret = new CARD32[img->width];
3671
3672 ASImageDecoder *imdec = start_image_decoding(fgVisual, img, SCL_DO_ALL,
3673 0, y, img->width, 1, 0);
3674
3675 if (!imdec) {
3676 delete [] ret;
3677 Warning("GetScanline", "Failed to start image decoding");
3678 return 0;
3679 }
3680
3681#ifdef HAVE_MMX
3682 mmx_init();
3683#endif
3684
3685 imdec->decode_image_scanline(imdec);
3686 memcpy(imdec->buffer.buffer, ret, img->width*sizeof(CARD32));
3687 stop_image_decoding(&imdec);
3688
3689#ifdef HAVE_MMX
3690 mmx_off();
3691#endif
3692
3693 return (UInt_t*)ret;
3694}
3695
3696
3697//______________________________________________________________________________
3698//
3699// Vector graphics
3700// a couple of macros which can be "assembler accelerated"
3701
3702#if defined(R__GNU) && defined(__i386__) && !defined(__sun)
3703#define _MEMSET_(dst, lng, val) __asm__("movl %0,%%eax \n"\
3704 "movl %1,%%edi \n" \
3705 "movl %2,%%ecx \n" \
3706 "cld \n" \
3707 "rep \n" \
3708 "stosl \n" \
3709 : /* no output registers */ \
3710 :"g" (val), "g" (dst), "g" (lng) \
3711 :"eax","edi","ecx" \
3712 )
3713
3714#else
3715 #define _MEMSET_(dst, lng, val) do {\
3716 for( UInt_t j=0; j < lng; j++) *((dst)+j) = val; } while (0)
3717
3718#endif
3719
3720#define FillSpansInternal(npt, ppt, widths, color) do {\
3721 UInt_t yy = ppt[0].fY*fImage->width;\
3722 for (UInt_t i = 0; i < npt; i++) {\
3723 _MEMSET_(&fImage->alt.argb32[Idx(yy + ppt[i].fX)], widths[i], color);\
3724 yy += ((i+1 < npt) && (ppt[i].fY != ppt[i+1].fY) ? fImage->width : 0);\
3725 }\
3726} while (0)
3727
3728////////////////////////////////////////////////////////////////////////////////
3729/// Fill rectangle of size (width, height) at position (x,y)
3730/// within the existing image with specified color.
3731
3733{
3734
3735 if (!InitVisual()) {
3736 Warning("FillRectangle", "Visual not initiated");
3737 return;
3738 }
3739
3740 if (!fImage) {
3741 Warning("FillRectangle", "no image");
3742 return;
3743 }
3744
3745 if (!fImage->alt.argb32) {
3746 BeginPaint();
3747 }
3748
3749 if (!fImage->alt.argb32) {
3750 Warning("FillRectangle", "Failed to get pixel array");
3751 return;
3752 }
3753
3754 ARGB32 color = (ARGB32)col;
3755
3756 if (width == 0) width = 1;
3757 if (height == 0) height = 1;
3758
3759 if (x < 0) {
3760 width += x;
3761 x = 0;
3762 }
3763 if (y < 0) {
3764 height += y;
3765 y = 0;
3766 }
3767
3768 Bool_t has_alpha = (color & 0xff000000) != 0xff000000;
3769
3770 x = x > (int)fImage->width ? (Int_t)fImage->width : x;
3771 y = y > (int)fImage->height ? (Int_t)fImage->height : y;
3772
3773 width = x + width > fImage->width ? fImage->width - x : width;
3774 height = y + height > fImage->height ? fImage->height - y : height;
3775
3776 if (!fImage->alt.argb32) {
3777 fill_asimage(fgVisual, fImage, x, y, width, height, color);
3778 } else {
3779 int yyy = y*fImage->width;
3780 if (!has_alpha) { // use faster memset
3781 ARGB32 *p0 = fImage->alt.argb32 + yyy + x;
3782 ARGB32 *p = p0;
3783 for (UInt_t i = 0; i < height; i++) {
3784 _MEMSET_(p, width, color);
3785 p += fImage->width;
3786 }
3787 } else {
3788 for (UInt_t i = y; i < y + height; i++) {
3789 int j = x + width;
3790 while (j > x) {
3791 j--;
3792 _alphaBlend(&fImage->alt.argb32[Idx(yyy + j)], &color);
3793 }
3794 yyy += fImage->width;
3795 }
3796 }
3797 }
3798}
3799
3800////////////////////////////////////////////////////////////////////////////////
3801/// Fill rectangle of size (width, height) at position (x,y)
3802/// within the existing image with specified color.
3803///
3804/// To create new image with Fill method the following code can be used:
3805/// ~~~ {.cpp}
3806/// TImage *img = TImage::Create();
3807/// img->Fill("#FF00FF", 0, 0, 400, 300);
3808/// ~~~
3809
3810void TASImage::FillRectangle(const char *col, Int_t x, Int_t y, UInt_t width, UInt_t height)
3811{
3812 if (!InitVisual()) {
3813 Warning("Fill", "Visual not initiated");
3814 return;
3815 }
3816
3817 ARGB32 color = ARGB32_White;
3818
3819 if (col) {
3820 parse_argb_color(col, &color);
3821 }
3822
3823 if (!fImage) {
3824 fImage = create_asimage(width ? width : 20, height ? height : 20, 0);
3825 x = 0;
3826 y = 0;
3827 }
3828
3829 FillRectangleInternal((UInt_t)color, x, y, width, height);
3830 UnZoom();
3831}
3832
3833////////////////////////////////////////////////////////////////////////////////
3834/// Draw a vertical line.
3835
3837{
3838 ARGB32 color = (ARGB32)col;
3839 UInt_t half = 0;
3840
3841 if (!thick) thick = 1;
3842
3843 if (thick > 1) {
3844 half = thick >> 1;
3845 if (x > half) {
3846 x = x - half;
3847 } else {
3848 x = 0;
3849 thick += (x - half);
3850 }
3851 }
3852
3853 y2 = y2 >= fImage->height ? fImage->height - 1 : y2;
3854 y1 = y1 >= fImage->height ? fImage->height - 1 : y1;
3855 x = x + thick >= fImage->width ? fImage->width - thick - 1 : x;
3856
3857 int yy = y1*fImage->width;
3858 for (UInt_t y = y1; y <= y2; y++) {
3859 for (UInt_t w = 0; w < thick; w++) {
3860 if (x + w < fImage->width) {
3861 _alphaBlend(&fImage->alt.argb32[Idx(yy + (x + w))], &color);
3862 }
3863 }
3864 yy += fImage->width;
3865 }
3866}
3867
3868////////////////////////////////////////////////////////////////////////////////
3869/// Draw an horizontal line.
3870
3872{
3873 ARGB32 color = (ARGB32)col;
3874 UInt_t half = 0;
3875
3876 if (!thick) thick = 1;
3877
3878 if (thick > 1) {
3879 half = thick >> 1;
3880 if (y > half) {
3881 y = y - half;
3882 } else {
3883 y = 0;
3884 thick += (y - half);
3885 }
3886 }
3887
3888 y = y + thick >= fImage->height ? fImage->height - thick - 1 : y;
3889 x2 = x2 >= fImage->width ? fImage->width - 1 : x2;
3890 x1 = x1 >= fImage->width ? fImage->width - 1 : x1;
3891
3892 int yy = y*fImage->width;
3893 for (UInt_t w = 0; w < thick; w++) {
3894 for (UInt_t x = x1; x <= x2; x++) {
3895 if (y + w < fImage->height) {
3896 _alphaBlend(&fImage->alt.argb32[Idx(yy + x)], &color);
3897 }
3898 }
3899 yy += fImage->width;
3900 }
3901}
3902
3903////////////////////////////////////////////////////////////////////////////////
3904/// Draw a line.
3905
3907 const char *col, UInt_t thick)
3908{
3909 ARGB32 color = ARGB32_White;
3910 parse_argb_color(col, &color);
3911 DrawLineInternal(x1, y1, x2, y2, (UInt_t)color, thick);
3912}
3913
3914////////////////////////////////////////////////////////////////////////////////
3915/// Internal line drawing.
3916
3918 UInt_t col, UInt_t thick)
3919{
3920 int dx, dy, d;
3921 int i1, i2;
3922 int x, y, xend, yend;
3923 int xdir, ydir;
3924 int q;
3925 int idx;
3926 int yy;
3927
3928 if (!InitVisual()) {
3929 Warning("DrawLine", "Visual not initiated");
3930 return;
3931 }
3932
3933 if (!fImage) {
3934 Warning("DrawLine", "no image");
3935 return;
3936 }
3937
3938 if (!fImage->alt.argb32) {
3939 BeginPaint();
3940 }
3941
3942 if (!fImage->alt.argb32) {
3943 Warning("DrawLine", "Failed to get pixel array");
3944 return;
3945 }
3946
3947 ARGB32 color = (ARGB32)col;
3948
3949 dx = TMath::Abs(Int_t(x2) - Int_t(x1));
3950 dy = TMath::Abs(Int_t(y2) - Int_t(y1));
3951
3952 if (!dx && !dy) return; // invisible line
3953
3954 if (!dx) {
3955 DrawVLine(x1, y2 > y1 ? y1 : y2,
3956 y2 > y1 ? y2 : y1, color, thick);
3957 return;
3958 }
3959
3960 if (!dy) {
3961 DrawHLine(y1, x2 > x1 ? x1 : x2,
3962 x2 > x1 ? x2 : x1, color, thick);
3963 return;
3964 }
3965
3966 if (thick > 1) {
3967 DrawWideLine(x1, y1, x2, y2, color, thick);
3968 return;
3969 }
3970
3971 if (dy <= dx) {
3972 UInt_t ddy = dy << 1;
3973 i1 = ddy;
3974 i2 = i1 - (dx << 1);
3975 d = i1 - dx;
3976
3977 if (x1 > x2) {
3978 x = x2;
3979 y = y2;
3980 ydir = -1;
3981 xend = x1;
3982 } else {
3983 x = x1;
3984 y = y1;
3985 ydir = 1;
3986 xend = x2;
3987 }
3988
3989 yy = y*fImage->width;
3990 _alphaBlend(&fImage->alt.argb32[Idx(yy + x)], &color);
3991 q = (y2 - y1) * ydir;
3992
3993 if (q > 0) {
3994 while (x < xend) {
3995
3996 idx = Idx(yy + x);
3997 _alphaBlend(&fImage->alt.argb32[idx], &color);
3998 x++;
3999
4000 if (d >= 0) {
4001 yy += fImage->width;
4002 d += i2;
4003 } else {
4004 d += i1;
4005 }
4006 }
4007 } else {
4008 while (x < xend) {
4009 idx = Idx(yy + x);
4010 _alphaBlend(&fImage->alt.argb32[idx], &color);
4011 x++;
4012
4013 if (d >= 0) {
4014 yy -= fImage->width;
4015 d += i2;
4016 } else {
4017 d += i1;
4018 }
4019 }
4020 }
4021 } else {
4022 UInt_t ddx = dx << 1;
4023 i1 = ddx;
4024 i2 = i1 - (dy << 1);
4025 d = i1 - dy;
4026
4027 if (y1 > y2) {
4028 y = y2;
4029 x = x2;
4030 yend = y1;
4031 xdir = -1;
4032 } else {
4033 y = y1;
4034 x = x1;
4035 yend = y2;
4036 xdir = 1;
4037 }
4038
4039 yy = y*fImage->width;
4040 _alphaBlend(&fImage->alt.argb32[Idx(yy + x)], &color);
4041 q = (x2 - x1) * xdir;
4042
4043 if (q > 0) {
4044 while (y < yend) {
4045 idx = Idx(yy + x);
4046 _alphaBlend(&fImage->alt.argb32[idx], &color);
4047 y++;
4048 yy += fImage->width;
4049
4050 if (d >= 0) {
4051 x++;
4052 d += i2;
4053 } else {
4054 d += i1;
4055 }
4056 }
4057 } else {
4058 while (y < yend) {
4059 idx = Idx(yy + x);
4060 _alphaBlend(&fImage->alt.argb32[idx], &color);
4061 y++;
4062 yy += fImage->width;
4063
4064 if (d >= 0) {
4065 x--;
4066 d += i2;
4067 } else {
4068 d += i1;
4069 }
4070 }
4071 }
4072 }
4073}
4074
4075////////////////////////////////////////////////////////////////////////////////
4076/// Draw a rectangle.
4077
4079 const char *col, UInt_t thick)
4080{
4081 if (!InitVisual()) {
4082 Warning("DrawRectangle", "Visual not initiated");
4083 return;
4084 }
4085
4086 if (!fImage) {
4087 w = w ? w : 20;
4088 h = h ? h : 20;
4089 fImage = create_asimage(w, h, 0);
4090 FillRectangle(col, 0, 0, w, h);
4091 return;
4092 }
4093
4094 if (!fImage->alt.argb32) {
4095 BeginPaint();
4096 }
4097
4098 if (!fImage->alt.argb32) {
4099 Warning("DrawRectangle", "Failed to get pixel array");
4100 return;
4101 }
4102
4103 ARGB32 color = ARGB32_White;
4104 parse_argb_color(col, &color);
4105
4106 DrawHLine(y, x, x + w, (UInt_t)color, thick);
4107 DrawVLine(x + w, y, y + h, (UInt_t)color, thick);
4108 DrawHLine(y + h, x, x + w, (UInt_t)color, thick);
4109 DrawVLine(x, y, y + h, (UInt_t)color, thick);
4110 UnZoom();
4111}
4112
4113////////////////////////////////////////////////////////////////////////////////
4114/// Draw a box.
4115
4116void TASImage::DrawBox(Int_t x1, Int_t y1, Int_t x2, Int_t y2, const char *col,
4117 UInt_t thick, Int_t mode)
4118{
4119 Int_t x = TMath::Min(x1, x2);
4120 Int_t y = TMath::Min(y1, y2);
4121 Int_t w = TMath::Abs(x2 - x1);
4122 Int_t h = TMath::Abs(y2 - y1);
4123
4124 ARGB32 color = ARGB32_White;
4125
4126 if (!fImage) {
4127 w = w ? x+w : x+20;
4128 h = h ? y+h : y+20;
4129 fImage = create_asimage(w, h, 0);
4130 FillRectangle(col, 0, 0, w, h);
4131 return;
4132 }
4133
4134 if (x1 == x2) {
4135 parse_argb_color(col, &color);
4136 DrawVLine(x1, y1, y2, color, 1);
4137 return;
4138 }
4139
4140 if (y1 == y2) {
4141 parse_argb_color(col, &color);
4142 DrawHLine(y1, x1, x2, color, 1);
4143 return;
4144 }
4145
4146
4147 switch (mode) {
4148 case TVirtualX::kHollow:
4149 DrawRectangle(x, y, w, h, col, thick);
4150 break;
4151
4152 case TVirtualX::kFilled:
4153 FillRectangle(col, x, y, w, h);
4154 break;
4155
4156 default:
4157 FillRectangle(col, x, y, w, h);
4158 break;
4159 }
4160}
4161
4162////////////////////////////////////////////////////////////////////////////////
4163/// Draw a dashed horizontal line.
4164
4166 const char *pDash, UInt_t col, UInt_t thick)
4167{
4168 UInt_t iDash = 0; // index of current dash
4169 int i = 0;
4170
4171 ARGB32 color = (ARGB32)col;
4172
4173 UInt_t half = 0;
4174
4175 if (thick > 1) {
4176 half = thick >> 1;
4177 if (y > half) {
4178 y = y - half;
4179 } else {
4180 y = 0;
4181 thick += (y - half);
4182 }
4183 }
4184 thick = thick <= 0 ? 1 : thick;
4185
4186 y = y + thick >= fImage->height ? fImage->height - thick - 1 : y;
4187 x2 = x2 >= fImage->width ? fImage->width - 1 : x2;
4188 x1 = x1 >= fImage->width ? fImage->width - 1 : x1;
4189
4190 // switch x1, x2
4191 UInt_t tmp = x1;
4192 x1 = x2 < x1 ? x2 : x1;
4193 x2 = x2 < tmp ? tmp : x2;
4194
4195 for (UInt_t x = x1; x <= x2; x++) {
4196 for (UInt_t w = 0; w < thick; w++) {
4197 if (y + w < fImage->height) {
4198 if ((iDash%2)==0) {
4199 _alphaBlend(&fImage->alt.argb32[Idx((y + w)*fImage->width + x)], &color);
4200 }
4201 }
4202 }
4203 i++;
4204
4205 if (i >= pDash[iDash]) {
4206 iDash++;
4207 i = 0;
4208 }
4209 if (iDash >= nDash) {
4210 iDash = 0;
4211 i = 0;
4212 }
4213 }
4214}
4215
4216////////////////////////////////////////////////////////////////////////////////
4217/// Draw a dashed vertical line.
4218
4220 const char *pDash, UInt_t col, UInt_t thick)
4221{
4222 UInt_t iDash = 0; // index of current dash
4223 int i = 0;
4224
4225 ARGB32 color = (ARGB32)col;
4226
4227 UInt_t half = 0;
4228
4229 if (thick > 1) {
4230 half = thick >> 1;
4231 if (x > half) {
4232 x = x - half;
4233 } else {
4234 x = 0;
4235 thick += (x - half);
4236 }
4237 }
4238 thick = thick <= 0 ? 1 : thick;
4239
4240 y2 = y2 >= fImage->height ? fImage->height - 1 : y2;
4241 y1 = y1 >= fImage->height ? fImage->height - 1 : y1;
4242
4243 // switch x1, x2
4244 UInt_t tmp = y1;
4245 y1 = y2 < y1 ? y2 : y1;
4246 y2 = y2 < tmp ? tmp : y2;
4247
4248 x = x + thick >= fImage->width ? fImage->width - thick - 1 : x;
4249
4250 int yy = y1*fImage->width;
4251 for (UInt_t y = y1; y <= y2; y++) {
4252 for (UInt_t w = 0; w < thick; w++) {
4253 if (x + w < fImage->width) {
4254 if ((iDash%2)==0) {
4255 _alphaBlend(&fImage->alt.argb32[Idx(yy + (x + w))], &color);
4256 }
4257 }
4258 }
4259 i++;
4260
4261 if (i >= pDash[iDash]) {
4262 iDash++;
4263 i = 0;
4264 }
4265 if (iDash >= nDash) {
4266 iDash = 0;
4267 i = 0;
4268 }
4269 yy += fImage->width;
4270 }
4271}
4272
4273////////////////////////////////////////////////////////////////////////////////
4274/// Draw a dashed line with one pixel width.
4275
4277 UInt_t nDash, const char *tDash, UInt_t color)
4278{
4279 int dx, dy, d;
4280 int i, i1, i2;
4281 int x, y, xend, yend;
4282 int xdir, ydir;
4283 int q;
4284 UInt_t iDash = 0; // index of current dash
4285 int yy;
4286 int idx;
4287
4288 dx = TMath::Abs(Int_t(x2) - Int_t(x1));
4289 dy = TMath::Abs(Int_t(y2) - Int_t(y1));
4290
4291 char *pDash = new char[nDash];
4292
4293 if (dy <= dx) {
4294 double ac = TMath::Cos(TMath::ATan2(dy, dx));
4295
4296 for (i = 0; i < (int)nDash; i++) {
4297 pDash[i] = TMath::Nint(tDash[i] * ac);
4298 }
4299
4300 UInt_t ddy = dy << 1;
4301 i1 = ddy;
4302 i2 = i1 - (dx << 1);
4303 d = i1 - dx;
4304 i = 0;
4305
4306 if (x1 > x2) {
4307 x = x2;
4308 y = y2;
4309 ydir = -1;
4310 xend = x1;
4311 } else {
4312 x = x1;
4313 y = y1;
4314 ydir = 1;
4315 xend = x2;
4316 }
4317
4318 yy = y*fImage->width;
4319 _alphaBlend(&fImage->alt.argb32[Idx(y*fImage->width + x)], &color);
4320 q = (y2 - y1) * ydir;
4321
4322 if (q > 0) {
4323 while (x < xend) {
4324 idx = Idx(yy + x);
4325 if ((iDash%2) == 0) {
4326 _alphaBlend(&fImage->alt.argb32[idx], &color);
4327 }
4328 x++;
4329 if (d >= 0) {
4330 yy += fImage->width;
4331 d += i2;
4332 } else {
4333 d += i1;
4334 }
4335
4336 i++;
4337 if (i >= pDash[iDash]) {
4338 iDash++;
4339 i = 0;
4340 }
4341 if (iDash >= nDash) {
4342 iDash = 0;
4343 i = 0;
4344 }
4345 }
4346 } else {
4347 while (x < xend) {
4348 idx = Idx(yy + x);
4349 if ((iDash%2) == 0) {
4350 _alphaBlend(&fImage->alt.argb32[idx], &color);
4351 }
4352 x++;
4353 if (d >= 0) {
4354 yy -= fImage->width;
4355 d += i2;
4356 } else {
4357 d += i1;
4358 }
4359
4360 i++;
4361 if (i >= pDash[iDash]) {
4362 iDash++;
4363 i = 0;
4364 }
4365 if (iDash >= nDash) {
4366 iDash = 0;
4367 i = 0;
4368 }
4369 }
4370 }
4371 } else {
4372 double as = TMath::Sin(TMath::ATan2(dy, dx));
4373
4374 for (i = 0; i < (int)nDash; i++) {
4375 pDash[i] = TMath::Nint(tDash[i] * as);
4376 }
4377
4378 UInt_t ddx = dx << 1;
4379 i1 = ddx;
4380 i2 = i1 - (dy << 1);
4381 d = i1 - dy;
4382 i = 0;
4383
4384 if (y1 > y2) {
4385 y = y2;
4386 x = x2;
4387 yend = y1;
4388 xdir = -1;
4389 } else {
4390 y = y1;
4391 x = x1;
4392 yend = y2;
4393 xdir = 1;
4394 }
4395
4396 yy = y*fImage->width;
4397 _alphaBlend(&fImage->alt.argb32[Idx(y*fImage->width + x)], &color);
4398 q = (x2 - x1) * xdir;
4399
4400 if (q > 0) {
4401 while (y < yend) {
4402 idx = Idx(yy + x);
4403 if ((iDash%2) == 0) {
4404 _alphaBlend(&fImage->alt.argb32[idx], &color);
4405 }
4406 y++;
4407 yy += fImage->width;
4408
4409 if (d >= 0) {
4410 x++;
4411 d += i2;
4412 } else {
4413 d += i1;
4414 }
4415
4416 i++;
4417 if (i >= pDash[iDash]) {
4418 iDash++;
4419 i = 0;
4420 }
4421 if (iDash >= nDash) {
4422 iDash = 0;
4423 i = 0;
4424 }
4425 }
4426 } else {
4427 while (y < yend) {
4428 idx = Idx(yy + x);
4429 if ((iDash%2) == 0) {
4430 _alphaBlend(&fImage->alt.argb32[idx], &color);
4431 }
4432 y++;
4433 yy += fImage->width;
4434
4435 if (d >= 0) {
4436 x--;
4437 d += i2;
4438 } else {
4439 d += i1;
4440 }
4441
4442 i++;
4443 if (i >= pDash[iDash]) {
4444 iDash++;
4445 i = 0;
4446 }
4447 if (iDash >= nDash) {
4448 iDash = 0;
4449 i = 0;
4450 }
4451 }
4452 }
4453 }
4454 delete [] pDash;
4455}
4456
4457////////////////////////////////////////////////////////////////////////////////
4458/// Draw a dashed line with thick pixel width.
4459
4461 UInt_t nDash, const char *tDash, UInt_t color, UInt_t thick)
4462{
4463 int dx, dy;
4464 int i;
4465 double x, y, xend=0, yend=0, x0, y0;
4466 int xdir, ydir;
4467 int q;
4468 UInt_t iDash = 0; // index of current dash
4469
4470 dx = TMath::Abs(Int_t(x2) - Int_t(x1));
4471 dy = TMath::Abs(Int_t(y2) - Int_t(y1));
4472
4473 double *xDash = new double[nDash];
4474 double *yDash = new double[nDash];
4475 double a = TMath::ATan2(dy, dx);
4476 double ac = TMath::Cos(a);
4477 double as = TMath::Sin(a);
4478
4479 for (i = 0; i < (int)nDash; i++) {
4480 xDash[i] = tDash[i] * ac;
4481 yDash[i] = tDash[i] * as;
4482
4483 // dirty trick (must be fixed)
4484 if ((i%2) == 0) {
4485 xDash[i] = xDash[i]/2;
4486 yDash[i] = yDash[i]/2;
4487 } else {
4488 xDash[i] = xDash[i]*2;
4489 yDash[i] = yDash[i]*2;
4490 }
4491 }
4492
4493 if (dy <= dx) {
4494 if (x1 > x2) {
4495 x = x2;
4496 y = y2;
4497 ydir = -1;
4498 xend = x1;
4499 } else {
4500 x = x1;
4501 y = y1;
4502 ydir = 1;
4503 xend = x2;
4504 }
4505
4506 q = (y2 - y1) * ydir;
4507 x0 = x;
4508 y0 = y;
4509 iDash = 0;
4510 yend = y + q;
4511
4512 if (q > 0) {
4513 while ((x < xend) && (y < yend)) {
4514 x += xDash[iDash];
4515 y += yDash[iDash];
4516
4517 if ((iDash%2) == 0) {
4519 TMath::Nint(x), TMath::Nint(y), color, thick);
4520 } else {
4521 x0 = x;
4522 y0 = y;
4523 }
4524
4525 iDash++;
4526
4527 if (iDash >= nDash) {
4528 iDash = 0;
4529 }
4530 }
4531 } else {
4532 while ((x < xend) && (y > yend)) {
4533 x += xDash[iDash];
4534 y -= yDash[iDash];
4535
4536 if ((iDash%2) == 0) {
4538 TMath::Nint(x), TMath::Nint(y), color, thick);
4539 } else {
4540 x0 = x;
4541 y0 = y;
4542 }
4543
4544 iDash++;
4545
4546 if (iDash >= nDash) {
4547 iDash = 0;
4548 }
4549 }
4550 }
4551 } else {
4552
4553 if (y1 > y2) {
4554 y = y2;
4555 x = x2;
4556 yend = y1;
4557 xdir = -1;
4558 } else {
4559 y = y1;
4560 x = x1;
4561 yend = y2;
4562 xdir = 1;
4563 }
4564
4565 q = (x2 - x1) * xdir;
4566 x0 = x;
4567 y0 = y;
4568 iDash = 0;
4569 xend = x + q;
4570
4571 if (q > 0) {
4572 while ((x < xend) && (y < yend)) {
4573 x += xDash[iDash];
4574 y += yDash[iDash];
4575
4576 if ((iDash%2) == 0) {
4578 TMath::Nint(x), TMath::Nint(y), color, thick);
4579 } else {
4580 x0 = x;
4581 y0 = y;
4582 }
4583
4584 iDash++;
4585
4586 if (iDash >= nDash) {
4587 iDash = 0;
4588 }
4589 }
4590 } else {
4591 while ((x > xend) && (y < yend)) {
4592 x -= xDash[iDash];
4593 y += yDash[iDash];
4594
4595 if ((iDash%2) == 0) {
4597 TMath::Nint(x), TMath::Nint(y), color, thick);
4598 } else {
4599 x0 = x;
4600 y0 = y;
4601 }
4602
4603 iDash++;
4604
4605 if (iDash >= nDash) {
4606 iDash = 0;
4607 }
4608 }
4609 }
4610 }
4611 delete [] xDash;
4612 delete [] yDash;
4613}
4614
4615////////////////////////////////////////////////////////////////////////////////
4616/// Draw a dashed line.
4617
4619 const char *pDash, const char *col, UInt_t thick)
4620
4621{
4622 if (!InitVisual()) {
4623 Warning("DrawDashLine", "Visual not initiated");
4624 return;
4625 }
4626
4627 if (!fImage) {
4628 Warning("DrawDashLine", "no image");
4629 return;
4630 }
4631
4632 if (!fImage->alt.argb32) {
4633 BeginPaint();
4634 }
4635
4636 if (!fImage->alt.argb32) {
4637 Warning("DrawDashLine", "Failed to get pixel array");
4638 return;
4639 }
4640
4641 if ((nDash < 2) || !pDash || (nDash%2)) {
4642 Warning("DrawDashLine", "Wrong input parameters n=%d %ld", nDash, (Long_t)sizeof(pDash)-1);
4643 return;
4644 }
4645
4646 ARGB32 color = ARGB32_White;
4647 parse_argb_color(col, &color);
4648
4649 if (x1 == x2) {
4650 DrawDashVLine(x1, y1, y2, nDash, pDash, (UInt_t)color, thick);
4651 } else if (y1 == y2) {
4652 DrawDashHLine(y1, x1, x2, nDash, pDash, (UInt_t)color, thick);
4653 } else {
4654 if (thick < 2) DrawDashZLine(x1, y1, x2, y2, nDash, pDash, (UInt_t)color);
4655 else DrawDashZTLine(x1, y1, x2, y2, nDash, pDash, (UInt_t)color, thick);
4656 }
4657}
4658
4659////////////////////////////////////////////////////////////////////////////////
4660/// Draw a polyline.
4661
4662void TASImage::DrawPolyLine(UInt_t nn, TPoint *xy, const char *col, UInt_t thick,
4663 TImage::ECoordMode mode)
4664{
4665 ARGB32 color = ARGB32_White;
4666 parse_argb_color(col, &color);
4667
4668 Int_t x0 = xy[0].GetX();
4669 Int_t y0 = xy[0].GetY();
4670 Int_t x = 0;
4671 Int_t y = 0;
4672
4673 for (UInt_t i = 1; i < nn; i++) {
4674 x = (mode == kCoordModePrevious) ? x + xy[i].GetX() : xy[i].GetX();
4675 y = (mode == kCoordModePrevious) ? y + xy[i].GetY() : xy[i].GetY();
4676
4677 DrawLineInternal(x0, y0, x, y, (UInt_t)color, thick);
4678
4679 x0 = x;
4680 y0 = y;
4681 }
4682}
4683
4684////////////////////////////////////////////////////////////////////////////////
4685/// Draw a point at the specified position.
4686
4687void TASImage::PutPixel(Int_t x, Int_t y, const char *col)
4688{
4689 if (!InitVisual()) {
4690 Warning("PutPixel", "Visual not initiated");
4691 return;
4692 }
4693
4694 if (!fImage) {
4695 Warning("PutPixel", "no image");
4696 return;
4697 }
4698
4699 if (!fImage->alt.argb32) {
4700 BeginPaint();
4701 }
4702
4703 if (!fImage->alt.argb32) {
4704 Warning("PutPixel", "Failed to get pixel array");
4705 return;
4706 }
4707
4708 ARGB32 color;
4709 parse_argb_color(col, &color);
4710
4711 if ((x < 0) || (y < 0) || (x >= (int)fImage->width) || (y >= (int)fImage->height)) {
4712 Warning("PutPixel", "Out of range width=%d x=%d, height=%d y=%d",
4713 fImage->width, x, fImage->height, y);
4714 return;
4715 }
4716 _alphaBlend(&fImage->alt.argb32[Idx(y*fImage->width + x)], &color);
4717}
4718
4719////////////////////////////////////////////////////////////////////////////////
4720/// Draw a poly point.
4721
4722void TASImage::PolyPoint(UInt_t npt, TPoint *ppt, const char *col, TImage::ECoordMode mode)
4723{
4724 if (!InitVisual()) {
4725 Warning("PolyPoint", "Visual not initiated");
4726 return;
4727 }
4728
4729 if (!fImage) {
4730 Warning("PolyPoint", "no image");
4731 return;
4732 }
4733
4734 if (!fImage->alt.argb32) {
4735 BeginPaint();
4736 }
4737
4738 if (!fImage->alt.argb32) {
4739 Warning("PolyPoint", "Failed to get pixel array");
4740 return;
4741 }
4742
4743 if (!npt || !ppt) {
4744 Warning("PolyPoint", "No points specified");
4745 return;
4746 }
4747
4748 TPoint *ipt = 0;
4749 UInt_t i = 0;
4750 ARGB32 color;
4751 parse_argb_color(col, &color);
4752
4753 //make pointlist origin relative
4754 if (mode == kCoordModePrevious) {
4755 ipt = new TPoint[npt];
4756
4757 for (i = 0; i < npt; i++) {
4758 ipt[i].fX += ppt[i].fX;
4759 ipt[i].fY += ppt[i].fY;
4760 }
4761 }
4762 int x, y;
4763
4764 for (i = 0; i < npt; i++) {
4765 x = ipt ? ipt[i].fX : ppt[i].fX;
4766 y = ipt ? ipt[i].fY : ppt[i].fY;
4767
4768 if ((x < 0) || (y < 0) || (x >= (int)fImage->width) || (y >= (int)fImage->height)) {
4769 continue;
4770 }
4771 _alphaBlend(&fImage->alt.argb32[Idx(y*fImage->width + x)], &color);
4772 }
4773
4774 if (ipt) {
4775 delete [] ipt;
4776 }
4777}
4778
4779////////////////////////////////////////////////////////////////////////////////
4780/// Draw segments.
4781
4782void TASImage::DrawSegments(UInt_t nseg, Segment_t *seg, const char *col, UInt_t thick)
4783{
4784 if (!nseg || !seg) {
4785 Warning("DrawSegments", "Invalid data nseg=%d seg=0x%zx", nseg, (size_t)seg);
4786 return;
4787 }
4788
4789 TPoint pt[2];
4790
4791 for (UInt_t i = 0; i < nseg; i++) {
4792 pt[0].fX = seg->fX1;
4793 pt[1].fX = seg->fX2;
4794 pt[0].fY = seg->fY1;
4795 pt[1].fY = seg->fY2;
4796
4797 DrawPolyLine(2, pt, col, thick, kCoordModeOrigin);
4798 seg++;
4799 }
4800}
4801
4802////////////////////////////////////////////////////////////////////////////////
4803/// Fill spans with specified color or/and stipple.
4804
4805void TASImage::FillSpans(UInt_t npt, TPoint *ppt, UInt_t *widths, const char *col,
4806 const char *stipple, UInt_t w, UInt_t h)
4807{
4808 if (!InitVisual()) {
4809 Warning("FillSpans", "Visual not initiated");
4810 return;
4811 }
4812
4813 if (!fImage) {
4814 Warning("FillSpans", "no image");
4815 return;
4816 }
4817
4818 if (!fImage->alt.argb32) {
4819 BeginPaint();
4820 }
4821
4822 if (!fImage->alt.argb32) {
4823 Warning("FillSpans", "Failed to get pixel array");
4824 return;
4825 }
4826
4827 if (!npt || !ppt || !widths || (stipple && (!w || !h))) {
4828 Warning("FillSpans", "Invalid input data npt=%d ppt=0x%zx col=%s widths=0x%zx stipple=0x%zx w=%d h=%d",
4829 npt, (size_t)ppt, col, (size_t)widths, (size_t)stipple, w, h);
4830 return;
4831 }
4832
4833 ARGB32 color;
4834 parse_argb_color(col, &color);
4835 Int_t idx = 0;
4836 UInt_t x = 0;
4837 UInt_t yy;
4838
4839 for (UInt_t i = 0; i < npt; i++) {
4840 yy = ppt[i].fY*fImage->width;
4841 for (UInt_t j = 0; j < widths[i]; j++) {
4842 if ((ppt[i].fX >= (Int_t)fImage->width) || (ppt[i].fX < 0) ||
4843 (ppt[i].fY >= (Int_t)fImage->height) || (ppt[i].fY < 0)) continue;
4844
4845 x = ppt[i].fX + j;
4846 idx = Idx(yy + x);
4847
4848 if (!stipple) {
4849 _alphaBlend(&fImage->alt.argb32[idx], &color);
4850 } else {
4851 Int_t ii = (ppt[i].fY%h)*w + x%w;
4852
4853 if (stipple[ii >> 3] & (1 << (ii%8))) {
4854 _alphaBlend(&fImage->alt.argb32[idx], &color);
4855 }
4856 }
4857 }
4858 }
4859}
4860
4861////////////////////////////////////////////////////////////////////////////////
4862/// Fill spans with tile image.
4863
4864void TASImage::FillSpans(UInt_t npt, TPoint *ppt, UInt_t *widths, TImage *tile)
4865{
4866 if (!InitVisual()) {
4867 Warning("FillSpans", "Visual not initiated");
4868 return;
4869 }
4870
4871 if (!fImage) {
4872 Warning("FillSpans", "no image");
4873 return;
4874 }
4875
4876 if (!fImage->alt.argb32) {
4877 BeginPaint();
4878 }
4879
4880 if (!fImage->alt.argb32) {
4881 Warning("FillSpans", "Failed to get pixel array");
4882 return;
4883 }
4884
4885 if (!npt || !ppt || !widths || !tile) {
4886 Warning("FillSpans", "Invalid input data npt=%d ppt=0x%zx widths=0x%zx tile=0x%zx",
4887 npt, (size_t)ppt, (size_t)widths, (size_t)tile);
4888 return;
4889 }
4890
4891 Int_t idx = 0;
4892 Int_t ii = 0;
4893 UInt_t x = 0;
4894 UInt_t *arr = tile->GetArgbArray();
4895 if (!arr) return;
4896 UInt_t xx = 0;
4897 UInt_t yy = 0;
4898
4899 for (UInt_t i = 0; i < npt; i++) {
4900 UInt_t yyy = ppt[i].fY*fImage->width;
4901
4902 for (UInt_t j = 0; j < widths[i]; j++) {
4903 if ((ppt[i].fX >= (Int_t)fImage->width) || (ppt[i].fX < 0) ||
4904 (ppt[i].fY >= (Int_t)fImage->height) || (ppt[i].fY < 0)) continue;
4905 x = ppt[i].fX + j;
4906 idx = Idx(yyy + x);
4907 xx = x%tile->GetWidth();
4908 yy = ppt[i].fY%tile->GetHeight();
4909 ii = yy*tile->GetWidth() + xx;
4910 _alphaBlend(&fImage->alt.argb32[idx], &arr[ii]);
4911 }
4912 }
4913}
4914
4915////////////////////////////////////////////////////////////////////////////////
4916/// Crop spans.
4917
4918void TASImage::CropSpans(UInt_t npt, TPoint *ppt, UInt_t *widths)
4919{
4920 if (!InitVisual()) {
4921 Warning("CropSpans", "Visual not initiated");
4922 return;
4923 }
4924
4925 if (!fImage) {
4926 Warning("CropSpans", "no image");
4927 return;
4928 }
4929
4930 if (!fImage->alt.argb32) {
4931 BeginPaint();
4932 }
4933
4934 if (!fImage->alt.argb32) {
4935 Warning("CropSpans", "Failed to get pixel array");
4936 return;
4937 }
4938
4939 if (!npt || !ppt || !widths) {
4940 Warning("CropSpans", "No points specified npt=%d ppt=0x%zx widths=0x%zx", npt, (size_t)ppt, (size_t)widths);
4941 return;
4942 }
4943
4944 int y0 = ppt[0].fY;
4945 int y1 = ppt[npt-1].fY;
4946 UInt_t y = 0;
4947 UInt_t x = 0;
4948 UInt_t i = 0;
4949 UInt_t idx = 0;
4950 UInt_t sz = fImage->width*fImage->height;
4951 UInt_t yy = y*fImage->width;
4952
4953 for (y = 0; (int)y < y0; y++) {
4954 for (x = 0; x < fImage->width; x++) {
4955 idx = Idx(yy + x);
4956 if (idx < sz) fImage->alt.argb32[idx] = 0;
4957 }
4958 yy += fImage->width;
4959 }
4960
4961 for (i = 0; i < npt; i++) {
4962 for (x = 0; (int)x < ppt[i].fX; x++) {
4963 idx = Idx(ppt[i].fY*fImage->width + x);
4964 if (idx < sz) fImage->alt.argb32[idx] = 0;
4965 }
4966 for (x = ppt[i].fX + widths[i] + 1; x < fImage->width; x++) {
4967 idx = Idx(ppt[i].fY*fImage->width + x);
4968 if (idx < sz) fImage->alt.argb32[idx] = 0;
4969 }
4970 }
4971
4972 yy = y1*fImage->width;
4973 for (y = y1; y < fImage->height; y++) {
4974 for (x = 0; x < fImage->width; x++) {
4975 idx = Idx(yy + x);
4976 if (idx < sz) fImage->alt.argb32[idx] = 0;
4977 }
4978 yy += fImage->width;
4979 }
4980}
4981
4982////////////////////////////////////////////////////////////////////////////////
4983/// Copy source region to the destination image. Copy is done according
4984/// to specified function:
4985/// ~~~ {.cpp}
4986/// enum EGraphicsFunction {
4987/// kGXclear = 0, // 0
4988/// kGXand, // src AND dst
4989/// kGXandReverse, // src AND NOT dst
4990/// kGXcopy, // src (default)
4991/// kGXandInverted, // NOT src AND dst
4992/// kGXnoop, // dst
4993/// kGXxor, // src XOR dst
4994/// kGXor, // src OR dst
4995/// kGXnor, // NOT src AND NOT dst
4996/// kGXequiv, // NOT src XOR dst
4997/// kGXinvert, // NOT dst
4998/// kGXorReverse, // src OR NOT dst
4999/// kGXcopyInverted, // NOT src
5000/// kGXorInverted, // NOT src OR dst
5001/// kGXnand, // NOT src OR NOT dst
5002/// kGXset // 1
5003/// };
5004/// ~~~
5005
5007 Int_t xdst, Int_t ydst, Int_t gfunc, EColorChan)
5008{
5009 if (!InitVisual()) {
5010 Warning("CopyArea", "Visual not initiated");
5011 return;
5012 }
5013
5014 if (!fImage) {
5015 Warning("CopyArea", "no image");
5016 return;
5017 }
5018 if (!dst) return;
5019
5020 ASImage *out = ((TASImage*)dst)->GetImage();
5021
5022 int x = 0;
5023 int y = 0;
5024 int idx = 0;
5025 int idx2 = 0;
5026 xsrc = xsrc < 0 ? 0 : xsrc;
5027 ysrc = ysrc < 0 ? 0 : ysrc;
5028
5029 if ((xsrc >= (int)fImage->width) || (ysrc >= (int)fImage->height)) return;
5030
5031 w = xsrc + w > fImage->width ? fImage->width - xsrc : w;
5032 h = ysrc + h > fImage->height ? fImage->height - ysrc : h;
5033 UInt_t yy = (ysrc + y)*fImage->width;
5034
5035 if (!fImage->alt.argb32) {
5036 BeginPaint();
5037 }
5038 if (!out->alt.argb32) {
5039 dst->BeginPaint();
5040 out = ((TASImage*)dst)->GetImage();
5041 }
5042
5043 if (fImage->alt.argb32 && out->alt.argb32) {
5044 for (y = 0; y < (int)h; y++) {
5045 for (x = 0; x < (int)w; x++) {
5046 idx = Idx(yy + x + xsrc);
5047 if ((x + xdst < 0) || (ydst + y < 0) ||
5048 (x + xdst >= (int)out->width) || (y + ydst >= (int)out->height) ) continue;
5049
5050 idx2 = Idx((ydst + y)*out->width + x + xdst);
5051
5052 switch ((EGraphicsFunction)gfunc) {
5053 case kGXclear:
5054 out->alt.argb32[idx2] = 0;
5055 break;
5056 case kGXand:
5057 out->alt.argb32[idx2] &= fImage->alt.argb32[idx];
5058 break;
5059 case kGXandReverse:
5060 out->alt.argb32[idx2] = fImage->alt.argb32[idx] & (~out->alt.argb32[idx2]);
5061 break;
5062 case kGXandInverted:
5063 out->alt.argb32[idx2] &= ~fImage->alt.argb32[idx];
5064 break;
5065 case kGXnoop:
5066 break;
5067 case kGXxor:
5068 out->alt.argb32[idx2] ^= fImage->alt.argb32[idx];
5069 break;
5070 case kGXor:
5071 out->alt.argb32[idx2] |= fImage->alt.argb32[idx];
5072 break;
5073 case kGXnor:
5074 out->alt.argb32[idx2] = (~fImage->alt.argb32[idx]) & (~out->alt.argb32[idx2]);
5075 break;
5076 case kGXequiv:
5077 out->alt.argb32[idx2] ^= ~fImage->alt.argb32[idx];
5078 break;
5079 case kGXinvert:
5080 out->alt.argb32[idx2] = ~out->alt.argb32[idx2];
5081 break;
5082 case kGXorReverse:
5083 out->alt.argb32[idx2] = fImage->alt.argb32[idx] | (~out->alt.argb32[idx2]);
5084 break;
5085 case kGXcopyInverted:
5086 out->alt.argb32[idx2] = ~fImage->alt.argb32[idx];
5087 break;
5088 case kGXorInverted:
5089 out->alt.argb32[idx2] |= ~fImage->alt.argb32[idx];
5090 break;
5091 case kGXnand:
5092 out->alt.argb32[idx2] = (~fImage->alt.argb32[idx]) | (~out->alt.argb32[idx2]);
5093 break;
5094 case kGXset:
5095 out->alt.argb32[idx2] = 0xFFFFFFFF;
5096 break;
5097 case kGXcopy:
5098 default:
5099 out->alt.argb32[idx2] = fImage->alt.argb32[idx];
5100 break;
5101 }
5102 }
5103 yy += fImage->width;
5104 }
5105 }
5106}
5107
5108////////////////////////////////////////////////////////////////////////////////
5109/// Draw a cell array.
5110///
5111/// \param[in] x1,y1 : left down corner
5112/// \param[in] x2,y2 : right up corner
5113/// \param[in] nx,ny : array size
5114/// \param[in] ic : array of ARGB32 colors
5115///
5116/// Draw a cell array. The drawing is done with the pixel precision
5117/// if (X2-X1)/NX (or Y) is not a exact pixel number the position of
5118/// the top right corner may be wrong.
5119
5121 Int_t ny, UInt_t *ic)
5122{
5123 int i, j, ix, iy, w, h;
5124
5125 ARGB32 color = 0xFFFFFFFF;
5126 ARGB32 icol;
5127
5128 w = TMath::Max((x2-x1)/(nx),1);
5129 h = TMath::Max((y1-y2)/(ny),1);
5130 ix = x1;
5131
5132 for (i = 0; i < nx; i++) {
5133 iy = y1 - h;
5134 for (j = 0; j < ny; j++) {
5135 icol = (ARGB32)ic[i + (nx*j)];
5136 if (icol != color) {
5137 color = icol;
5138 }
5139 FillRectangleInternal((UInt_t)color, ix, iy, w, h);
5140 iy = iy - h;
5141 }
5142 ix = ix + w;
5143 }
5144}
5145
5146////////////////////////////////////////////////////////////////////////////////
5147/// Return alpha-blended value computed from bottom and top pixel values.
5148
5150{
5151 UInt_t ret = bot;
5152
5153 _alphaBlend(&ret, &top);
5154 return ret;
5155}
5156
5157////////////////////////////////////////////////////////////////////////////////
5158/// Return visual.
5159
5160const ASVisual *TASImage::GetVisual()
5161{
5162 return fgVisual;
5163}
5164
5165////////////////////////////////////////////////////////////////////////////////
5166/// Get poly bounds along Y.
5167
5168static int GetPolyYBounds(TPoint *pts, int n, int *by, int *ty)
5169{
5170 TPoint *ptMin;
5171 int ymin, ymax;
5172 TPoint *ptsStart = pts;
5173
5174 ptMin = pts;
5175 ymin = ymax = (pts++)->fY;
5176
5177 while (--n > 0) {
5178 if (pts->fY < ymin) {
5179 ptMin = pts;
5180 ymin = pts->fY;
5181 }
5182 if (pts->fY > ymax) {
5183 ymax = pts->fY;
5184 }
5185 pts++;
5186 }
5187
5188 *by = ymin;
5189 *ty = ymax;
5190 return (ptMin - ptsStart);
5191}
5192
5193////////////////////////////////////////////////////////////////////////////////
5194/// The code is based on Xserver/mi/mipolycon.c
5195/// "Copyright 1987, 1998 The Open Group"
5196
5198 TPoint **outPoint, UInt_t **outWidth)
5199{
5200 int xl = 0; // x vals of leftedges
5201 int xr = 0; // x vals of right edges
5202 int dl = 0; // decision variables
5203 int dr = 0; // decision variables
5204 int ml = 0; // left edge slope
5205 int m1l = 0; // left edge slope+1
5206 int mr = 0, m1r = 0; // right edge slope and slope+1
5207 int incr1l = 0, incr2l = 0; // left edge error increments
5208 int incr1r = 0, incr2r = 0; // right edge error increments
5209 int dy; // delta y
5210 int y; // current scanline
5211 int left, right; // indices to first endpoints
5212 int i; // loop counter
5213 int nextleft, nextright; // indices to second endpoints
5214 TPoint *ptsOut; // output buffer
5215 UInt_t *width; // output buffer
5216 TPoint *firstPoint=0;
5217 UInt_t *firstWidth=0;
5218 int imin; // index of smallest vertex (in y)
5219 int ymin; // y-extents of polygon
5220 int ymax;
5221 Bool_t ret = kTRUE;
5222
5223 *nspans = 0;
5224
5225 if (!InitVisual()) {
5226 Warning("GetPolygonSpans", "Visual not initiated");
5227 return kFALSE;
5228 }
5229
5230 if (!fImage) {
5231 Warning("GetPolygonSpans", "no image");
5232 return kFALSE;
5233 }
5234
5235 if (!fImage->alt.argb32) {
5236 BeginPaint();
5237 }
5238
5239 if (!fImage->alt.argb32) {
5240 Warning("GetPolygonSpans", "Failed to get pixel array");
5241 return kFALSE;
5242 }
5243
5244 if ((npt < 3) || !ppt) {
5245 Warning("GetPolygonSpans", "No points specified npt=%d ppt=0x%zx", npt, (size_t)ppt);
5246 return kFALSE;
5247 }
5248
5249 // find leftx, bottomy, rightx, topy, and the index
5250 // of bottomy. Also translate the points.
5251 imin = GetPolyYBounds(ppt, npt, &ymin, &ymax);
5252
5253 dy = ymax - ymin + 1;
5254 if ((npt < 3) || (dy < 0)) return kFALSE;
5255
5256 ptsOut = firstPoint = new TPoint[dy];
5257 width = firstWidth = new UInt_t[dy];
5258 ret = kTRUE;
5259
5260 nextleft = nextright = imin;
5261 y = ppt[nextleft].fY;
5262
5263 // loop through all edges of the polygon
5264 do {
5265 // add a left edge if we need to
5266 if (ppt[nextleft].fY == y) {
5267 left = nextleft;
5268
5269 // find the next edge, considering the end
5270 // conditions of the array.
5271 nextleft++;
5272 if (nextleft >= (int)npt) {
5273 nextleft = 0;
5274 }
5275
5276 // now compute all of the random information
5277 // needed to run the iterative algorithm.
5278 BRESINITPGON(ppt[nextleft].fY - ppt[left].fY,
5279 ppt[left].fX, ppt[nextleft].fX,
5280 xl, dl, ml, m1l, incr1l, incr2l);
5281 }
5282
5283 // add a right edge if we need to
5284 if (ppt[nextright].fY == y) {
5285 right = nextright;
5286
5287 // find the next edge, considering the end
5288 // conditions of the array.
5289 nextright--;
5290 if (nextright < 0) {
5291 nextright = npt-1;
5292 }
5293
5294 // now compute all of the random information
5295 // needed to run the iterative algorithm.
5296 BRESINITPGON(ppt[nextright].fY - ppt[right].fY,
5297 ppt[right].fX, ppt[nextright].fX,
5298 xr, dr, mr, m1r, incr1r, incr2r);
5299 }
5300
5301 // generate scans to fill while we still have
5302 // a right edge as well as a left edge.
5303 i = TMath::Min(ppt[nextleft].fY, ppt[nextright].fY) - y;
5304
5305 // in case of non-convex polygon
5306 if (i < 0) {
5307 delete [] firstWidth;
5308 delete [] firstPoint;
5309 return kTRUE;
5310 }
5311
5312 while (i-- > 0) {
5313 ptsOut->fY = y;
5314
5315 // reverse the edges if necessary
5316 if (xl < xr) {
5317 *(width++) = xr - xl;
5318 (ptsOut++)->fX = xl;
5319 } else {
5320 *(width++) = xl - xr;
5321 (ptsOut++)->fX = xr;
5322 }
5323 y++;
5324
5325 // increment down the edges
5326 BRESINCRPGON(dl, xl, ml, m1l, incr1l, incr2l);
5327 BRESINCRPGON(dr, xr, mr, m1r, incr1r, incr2r);
5328 }
5329 } while (y != ymax);
5330
5331 *nspans = UInt_t(ptsOut - firstPoint);
5332 *outPoint = firstPoint;
5333 *outWidth = firstWidth;
5334
5335 return ret;
5336}
5337
5338////////////////////////////////////////////////////////////////////////////////
5339/// Fill a convex polygon with background color or bitmap.
5340/// For non convex polygon one must use DrawFillArea method
5341
5342void TASImage::FillPolygon(UInt_t npt, TPoint *ppt, const char *col,
5343 const char *stipple, UInt_t w, UInt_t h)
5344{
5345 UInt_t nspans = 0;
5346 TPoint *firstPoint = 0; // output buffer
5347 UInt_t *firstWidth = 0; // output buffer
5348
5349 Bool_t del = GetPolygonSpans(npt, ppt, &nspans, &firstPoint, &firstWidth);
5350 ARGB32 color = ARGB32_White;
5351 parse_argb_color(col, &color);
5352
5353 if (nspans) {
5354 if (!stipple && ((color & 0xff000000)==0xff000000)) { //no stipple no alpha
5355 FillSpansInternal(nspans, firstPoint, firstWidth, color);
5356 } else {
5357 FillSpans(nspans, firstPoint, firstWidth, col, stipple, w, h);
5358 }
5359
5360 if (del) {
5361 delete [] firstWidth;
5362 delete [] firstPoint;
5363 }
5364 } else {
5365 if (firstWidth) delete [] firstWidth;
5366 if (firstPoint) delete [] firstPoint;
5367 }
5368}
5369
5370////////////////////////////////////////////////////////////////////////////////
5371/// Fill a convex polygon with background image.
5372/// For non convex polygon one must use DrawFillArea method
5373
5375{
5376 UInt_t nspans = 0;
5377 TPoint *firstPoint = 0; // output buffer
5378 UInt_t *firstWidth = 0; // output buffer
5379
5380 Bool_t del = GetPolygonSpans(npt, ppt, &nspans, &firstPoint, &firstWidth);
5381
5382 if (nspans) {
5383 FillSpans(nspans, firstPoint, firstWidth, tile);
5384
5385 if (del) {
5386 delete [] firstWidth;
5387 delete [] firstPoint;
5388 }
5389 } else {
5390 if (firstWidth) delete [] firstWidth;
5391 if (firstPoint) delete [] firstPoint;
5392 }
5393}
5394
5395////////////////////////////////////////////////////////////////////////////////
5396/// Crop a convex polygon.
5397
5399{
5400 UInt_t nspans = 0;
5401 TPoint *firstPoint = 0;
5402 UInt_t *firstWidth = 0;
5403
5404 Bool_t del = GetPolygonSpans(npt, ppt, &nspans, &firstPoint, &firstWidth);
5405
5406 if (nspans) {
5407 CropSpans(nspans, firstPoint, firstWidth);
5408
5409 if (del) {
5410 delete [] firstWidth;
5411 delete [] firstPoint;
5412 }
5413 } else {
5414 if (firstWidth) delete [] firstWidth;
5415 if (firstPoint) delete [] firstPoint;
5416 }
5417}
5418
5419static const UInt_t NUMPTSTOBUFFER = 512;
5420
5421////////////////////////////////////////////////////////////////////////////////
5422/// Fill a polygon (any type convex, non-convex).
5423
5424void TASImage::DrawFillArea(UInt_t count, TPoint *ptsIn, const char *col,
5425 const char *stipple, UInt_t w, UInt_t h)
5426{
5427 if (!InitVisual()) {
5428 Warning("DrawFillArea", "Visual not initiated");
5429 return;
5430 }
5431
5432 if (!fImage) {
5433 Warning("DrawFillArea", "no image");
5434 return;
5435 }
5436
5437 if (!fImage->alt.argb32) {
5438 BeginPaint();
5439 }
5440
5441 if (!fImage->alt.argb32) {
5442 Warning("DrawFillArea", "Failed to get pixel array");
5443 return;
5444 }
5445
5446 if ((count < 3) || !ptsIn) {
5447 Warning("DrawFillArea", "No points specified npt=%d ppt=0x%zx", count, (size_t)ptsIn);
5448 return;
5449 }
5450
5451 if (count < 5) {
5452 FillPolygon(count, ptsIn, col, stipple, w, h);
5453 return;
5454 }
5455
5456 ARGB32 color = ARGB32_White;
5457 parse_argb_color(col, &color);
5458
5459 EdgeTableEntry *pAET; // the Active Edge Table
5460 int y; // the current scanline
5461 UInt_t nPts = 0; // number of pts in buffer
5462
5463 ScanLineList *pSLL; // Current ScanLineList
5464 TPoint *ptsOut; // ptr to output buffers
5465 UInt_t *width;
5466 TPoint firstPoint[NUMPTSTOBUFFER]; // the output buffers
5467 UInt_t firstWidth[NUMPTSTOBUFFER];
5468 EdgeTableEntry *pPrevAET; // previous AET entry
5469 EdgeTable ET; // Edge Table header node
5470 EdgeTableEntry AET; // Active ET header node
5471 EdgeTableEntry *pETEs; // Edge Table Entries buff
5472 ScanLineListBlock SLLBlock; // header for ScanLineList
5473 Bool_t del = kTRUE;
5474
5475 static const UInt_t gEdgeTableEntryCacheSize = 200;
5476 static EdgeTableEntry gEdgeTableEntryCache[gEdgeTableEntryCacheSize];
5477
5478 if (count < gEdgeTableEntryCacheSize) {
5479 pETEs = (EdgeTableEntry*)&gEdgeTableEntryCache;
5480 del = kFALSE;
5481 } else {
5482 pETEs = new EdgeTableEntry[count];
5483 del = kTRUE;
5484 }
5485
5486 ET.scanlines.next = nullptr; // to avoid compiler warnings
5487 ET.ymin = ET.ymax = 0; // to avoid compiler warnings
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%zx", count, (size_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 ET.scanlines.next = nullptr; // to avoid compiler warnings
5590 ET.ymin = ET.ymax = 0; // to avoid compiler warnings
5591
5592 ptsOut = firstPoint;
5593 width = firstWidth;
5594 CreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock);
5595 pSLL = ET.scanlines.next;
5596
5597 for (y = ET.ymin; y < ET.ymax; y++) {
5598 if (pSLL && y == pSLL->scanline) {
5599 loadAET(&AET, pSLL->edgelist);
5600 pSLL = pSLL->next;
5601 }
5602 pPrevAET = &AET;
5603 pAET = AET.next;
5604
5605 while (pAET) {
5606 ptsOut->fX = pAET->bres.minor_axis;
5607 ptsOut->fY = y;
5608 ptsOut++;
5609 nPts++;
5610
5611 *width++ = pAET->next->bres.minor_axis - pAET->bres.minor_axis;
5612
5613 if (nPts == NUMPTSTOBUFFER) {
5614 FillSpans(nPts, firstPoint, firstWidth, tile);
5615 ptsOut = firstPoint;
5616 width = firstWidth;
5617 nPts = 0;
5618 }
5619 EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
5620 EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
5621 }
5622 InsertionSort(&AET);
5623 }
5624 FillSpans(nPts, firstPoint, firstWidth, tile);
5625
5626 delete [] pETEs;
5627 FreeStorage(SLLBlock.next);
5628}
5629
5630////////////////////////////////////////////////////////////////////////////////
5631/// Create draw context.
5632
5633static ASDrawContext *create_draw_context_argb32(ASImage *im, ASDrawTool *brush)
5634{
5635 ASDrawContext *ctx = new ASDrawContext;
5636
5637 ctx->canvas_width = im->width;
5638 ctx->canvas_height = im->height;
5639 ctx->canvas = im->alt.argb32;
5640 ctx->scratch_canvas = 0;
5641
5642 ctx->flags = ASDrawCTX_CanvasIsARGB;
5643 asim_set_custom_brush_colored( ctx, brush);
5644 return ctx;
5645}
5646
5647////////////////////////////////////////////////////////////////////////////////
5648/// Destroy asdraw context32.
5649
5650static void destroy_asdraw_context32( ASDrawContext *ctx )
5651{
5652 if (ctx) {
5653 if (ctx->scratch_canvas) free(ctx->scratch_canvas);
5654 delete ctx;
5655 }
5656}
5657
5658static const UInt_t kBrushCacheSize = 20;
5660
5661////////////////////////////////////////////////////////////////////////////////
5662/// Draw wide line.
5663
5665 UInt_t color, UInt_t thick)
5666{
5667 Int_t sz = thick*thick;
5668 CARD32 *matrix;
5669 Bool_t use_cache = thick < kBrushCacheSize;
5670
5671 if (use_cache) {
5672 matrix = gBrushCache;
5673 } else {
5674 matrix = new CARD32[sz];
5675 }
5676
5677 for (int i = 0; i < sz; i++) {
5678 matrix[i] = (CARD32)color;
5679 };
5680
5681 ASDrawTool brush;
5682 brush.matrix = matrix;
5683 brush.width = thick;
5684 brush.height = thick;
5685 brush.center_y = brush.center_x = thick/2;
5686
5687 // When the first or last point of a wide line is exactly on the
5688 // window limit the line is drawn vertically or horizontally.
5689 // see https://sft.its.cern.ch/jira/browse/ROOT-8021
5690 UInt_t xx1 = x1;
5691 UInt_t yy1 = y1;
5692 UInt_t xx2 = x2;
5693 UInt_t yy2 = y2;
5694 if (xx1 == fImage->width) --xx1;
5695 if (yy1 == fImage->height) --yy1;
5696 if (xx2 == fImage->width) --xx2;
5697 if (yy2 == fImage->height) --yy2;
5698 ASDrawContext *ctx = create_draw_context_argb32(fImage, &brush);
5699 asim_move_to(ctx, xx1, yy1);
5700 asim_line_to(ctx, xx2, yy2);
5701
5702 if (!use_cache) {
5703 delete [] matrix;
5704 }
5706}
5707
5708////////////////////////////////////////////////////////////////////////////////
5709/// Draw glyph bitmap.
5710
5711void TASImage::DrawGlyph(void *bitmap, UInt_t color, Int_t bx, Int_t by)
5712{
5713 static UInt_t col[5];
5714 Int_t x, y, yy, y0, xx;
5715 Bool_t has_alpha = (color & 0xff000000) != 0xff000000;
5716
5717 ULong_t r, g, b;
5718 int idx = 0;
5719 FT_Bitmap *source = (FT_Bitmap*)bitmap;
5720 UChar_t d = 0, *s = source->buffer;
5721
5722 Int_t dots = Int_t(source->width * source->rows);
5723 r = g = b = 0;
5724 Int_t bxx, byy;
5725
5726 yy = y0 = by > 0 ? by * fImage->width : 0;
5727 for (y = 0; y < (int) source->rows; y++) {
5728 byy = by + y;
5729 if ((byy >= (int)fImage->height) || (byy <0)) continue;
5730
5731 for (x = 0; x < (int) source->width; x++) {
5732 bxx = bx + x;
5733 if ((bxx >= (int)fImage->width) || (bxx < 0)) continue;
5734
5735 idx = Idx(bxx + yy);
5736 r += ((fImage->alt.argb32[idx] & 0xff0000) >> 16);
5737 g += ((fImage->alt.argb32[idx] & 0x00ff00) >> 8);
5738 b += (fImage->alt.argb32[idx] & 0x0000ff);
5739 }
5740 yy += fImage->width;
5741 }
5742 if (dots != 0) {
5743 r /= dots;
5744 g /= dots;
5745 b /= dots;
5746 }
5747
5748 col[0] = (r << 16) + (g << 8) + b;
5749 col[4] = color;
5750 Int_t col4r = (col[4] & 0xff0000) >> 16;
5751 Int_t col4g = (col[4] & 0x00ff00) >> 8;
5752 Int_t col4b = (col[4] & 0x0000ff);
5753
5754 // interpolate between fore and background colors
5755 for (x = 3; x > 0; x--) {
5756 xx = 4-x;
5757 Int_t colxr = (col4r*x + r*xx) >> 2;
5758 Int_t colxg = (col4g*x + g*xx) >> 2;
5759 Int_t colxb = (col4b*x + b*xx) >> 2;
5760 col[x] = (colxr << 16) + (colxg << 8) + colxb;
5761 }
5762
5763 yy = y0;
5764 ARGB32 acolor;
5765
5766 Int_t clipx1=0, clipx2=0, clipy1=0, clipy2=0;
5767 Bool_t noClip = kTRUE;
5768
5769 if (gPad) {
5771 clipx1 = gPad->XtoAbsPixel(gPad->GetX1())*is;
5772 clipx2 = gPad->XtoAbsPixel(gPad->GetX2())*is;
5773 clipy1 = gPad->YtoAbsPixel(gPad->GetY1())*is;
5774 clipy2 = gPad->YtoAbsPixel(gPad->GetY2())*is;
5775 noClip = kFALSE;
5776 }
5777
5778 for (y = 0; y < (int) source->rows; y++) {
5779 byy = by + y;
5780
5781 for (x = 0; x < (int) source->width; x++) {
5782 bxx = bx + x;
5783
5784 d = *s++ & 0xff;
5785 d = ((d + 10) * 5) >> 8;
5786 if (d > 4) d = 4;
5787
5788 if (d) {
5789 if ( noClip || ((x < (int) source->width) &&
5790 (bxx < (int)clipx2) && (bxx >= (int)clipx1) &&
5791 (byy >= (int)clipy2) && (byy < (int)clipy1) )) {
5792 idx = Idx(bxx + yy);
5793 acolor = (ARGB32)col[d];
5794 if (has_alpha) {
5795 _alphaBlend(&fImage->alt.argb32[idx], &acolor);
5796 } else {
5797 fImage->alt.argb32[idx] = acolor;
5798 }
5799 }
5800 }
5801 }
5802 yy += fImage->width;
5803 }
5804}
5805
5806////////////////////////////////////////////////////////////////////////////////
5807/// Draw text at the pixel position (x,y).
5808
5810{
5811 if (!text) return;
5812 if (!fImage) return;
5813 if (!gPad) return;
5814
5815 if (!InitVisual()) {
5816 Warning("DrawText", "Visual not initiated");
5817 return;
5818 }
5819
5820 if (!fImage->alt.argb32) {
5821 BeginPaint();
5822 }
5823
5824 if (!TTF::IsInitialized()) TTF::Init();
5825
5826 // set text font
5828
5829 Int_t wh = gPad->XtoPixel(gPad->GetX2());
5830 Int_t hh = gPad->YtoPixel(gPad->GetY1());
5831
5832 // set text size
5833 Float_t ttfsize;
5834 if (wh < hh) {
5835 ttfsize = text->GetTextSize()*wh;
5836 } else {
5837 ttfsize = text->GetTextSize()*hh;
5838 }
5839 TTF::SetTextSize(ttfsize*kScale);
5840
5841 // set text angle
5843
5844 // set text
5845 const wchar_t *wcsTitle = reinterpret_cast<const wchar_t *>(text->GetWcsTitle());
5846 if (wcsTitle != NULL) {
5847 TTF::PrepareString(wcsTitle);
5848 } else {
5850 }
5852
5853 // color
5855 if (!col) { // no color, make it black
5856 col = gROOT->GetColor(1);
5857 if (!col) return;
5858 }
5859 ARGB32 color = ARGB32_White;
5860 parse_argb_color(col->AsHexString(), &color);
5861
5862 // Align()
5863 Int_t align = 0;
5864 Int_t txalh = text->GetTextAlign()/10;
5865 Int_t txalv = text->GetTextAlign()%10;
5866
5867 switch (txalh) {
5868 case 0 :
5869 case 1 :
5870 switch (txalv) { //left
5871 case 1 :
5872 align = 7; //bottom
5873 break;
5874 case 2 :
5875 align = 4; //center
5876 break;
5877 case 3 :
5878 align = 1; //top
5879 break;
5880 }
5881 break;
5882 case 2 :
5883 switch (txalv) { //center
5884 case 1 :
5885 align = 8; //bottom
5886 break;
5887 case 2 :
5888 align = 5; //center
5889 break;
5890 case 3 :
5891 align = 2; //top
5892 break;
5893 }
5894 break;
5895 case 3 :
5896 switch (txalv) { //right
5897 case 1 :
5898 align = 9; //bottom
5899 break;
5900 case 2 :
5901 align = 6; //center
5902 break;
5903 case 3 :
5904 align = 3; //top
5905 break;
5906 }
5907 break;
5908 }
5909
5910 FT_Vector ftal;
5911
5912 // vertical alignment
5913 if (align == 1 || align == 2 || align == 3) {
5914 ftal.y = TTF::GetAscent();
5915 } else if (align == 4 || align == 5 || align == 6) {
5916 ftal.y = TTF::GetAscent()/2;
5917 } else {
5918 ftal.y = 0;
5919 }
5920
5921 // horizontal alignment
5922 if (align == 3 || align == 6 || align == 9) {
5923 ftal.x = TTF::GetWidth();
5924 } else if (align == 2 || align == 5 || align == 8) {
5925 ftal.x = TTF::GetWidth()/2;
5926 } else {
5927 ftal.x = 0;
5928 }
5929
5930 FT_Vector_Transform(&ftal, TTF::GetRotMatrix());
5931 ftal.x = (ftal.x >> 6);
5932 ftal.y = (ftal.y >> 6);
5933
5934 TTF::TTGlyph *glyph = TTF::GetGlyphs();
5935
5936 for (int n = 0; n < TTF::GetNumGlyphs(); n++, glyph++) {
5937 if (FT_Glyph_To_Bitmap(&glyph->fImage, ft_render_mode_normal, 0, 1 )) continue;
5938
5939 FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph->fImage;
5940 FT_Bitmap *source = &bitmap->bitmap;
5941
5942 Int_t bx = x - ftal.x + bitmap->left;
5943 Int_t by = y + ftal.y - bitmap->top;
5944
5945 DrawGlyph(source, color, bx, by);
5946 }
5947}
5948
5949////////////////////////////////////////////////////////////////////////////////
5950/// Draw text using TrueType fonts.
5951
5953 UInt_t color, const char *font_name, Float_t angle)
5954{
5955 if (!TTF::IsInitialized()) TTF::Init();
5956
5957 TTF::SetTextFont(font_name);
5962
5963 TTF::TTGlyph *glyph = TTF::GetGlyphs();
5964
5965 // compute the size and position that will contain the text
5966 // Int_t Xoff = 0; if (TTF::GetBox().xMin < 0) Xoff = -TTF::GetBox().xMin;
5967 Int_t Yoff = 0; if (TTF::GetBox().yMin < 0) Yoff = -TTF::GetBox().yMin;
5968 Int_t h = TTF::GetBox().yMax + Yoff;
5969
5970 for (int n = 0; n < TTF::GetNumGlyphs(); n++, glyph++) {
5971 if (FT_Glyph_To_Bitmap(&glyph->fImage, ft_render_mode_normal, 0, 1 )) continue;
5972
5973 FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph->fImage;
5974 FT_Bitmap *source = &bitmap->bitmap;
5975
5976 Int_t bx = x + bitmap->left;
5977 Int_t by = y + h - bitmap->top;
5978 DrawGlyph(source, color, bx, by);
5979 }
5980}
5981
5982////////////////////////////////////////////////////////////////////////////////
5983/// Return in-memory buffer compressed according image type.
5984/// Buffer must be deallocated after usage with free(buffer) call.
5985/// This method can be used for sending images over network.
5986
5988{
5989 static ASImageExportParams params;
5990 Bool_t ret = kFALSE;
5991 ASImage *img = fScaledImage ? fScaledImage->fImage : fImage;
5992
5993 if (!img) return;
5994
5995 switch (type) {
5996 case TImage::kXpm:
5997 ret = ASImage2xpmRawBuff(img, (CARD8 **)buffer, size, 0);
5998 break;
5999 case TImage::kPng:
6000 ret = ASImage2PNGBuff(img, (CARD8 **)buffer, size, &params);
6001 break;
6002 default:
6003 ret = kFALSE;
6004 }
6005
6006 if (!ret) {
6007 *size = 0;
6008 *buffer = nullptr;
6009 }
6010}
6011
6012////////////////////////////////////////////////////////////////////////////////
6013/// Create image from compressed buffer.
6014/// Supported formats:
6015///
6016/// - PNG - by default
6017/// - XPM - two options exist:
6018/// 1. xpm as a single string (raw buffer). Such string
6019/// is returned by GetImageBuffer method.
6020/// For example:
6021/// ~~~ {.cpp}
6022/// char *buf;
6023/// int sz;
6024/// im1->GetImageBuffer(&buf, &int, TImage::kXpm); /*raw buffer*/
6025/// TImage *im2 = TImage::Create();
6026/// im2->SetImageBuffer(&buf, TImage::kXpm);
6027/// ~~~
6028/// 2. xpm as an array of strings (pre-parsed)
6029/// ~~~ {.cpp}
6030/// For example:
6031/// char *xpm[] = {
6032/// "64 28 58 1",
6033/// " c #0A030C",
6034/// ". c #1C171B"
6035/// ...
6036/// TImage *im = TImage::Create();
6037/// im->SetImageBuffer(xpm, TImage::kXpm);
6038/// ~~~
6039
6041{
6042 DestroyImage();
6043
6044 static ASImageImportParams params;
6045 params.flags = 0;
6046 params.width = 0;
6047 params.height = 0 ;
6048 params.filter = SCL_DO_ALL;
6049 params.gamma = SCREEN_GAMMA;
6050 params.gamma_table = nullptr;
6051 params.compression = 0;
6052 params.format = ASA_ASImage;
6053 params.search_path = 0;
6054 params.subimage = 0;
6055
6056 switch (type) {
6057 case TImage::kXpm:
6058 {
6059 char *ptr = buffer[0];
6060 while (isspace((int)*ptr)) ++ptr;
6061 if (atoi(ptr)) { // pre-parsed and preloaded data
6062 fImage = xpm_data2ASImage((const char**)buffer, &params);
6063 } else {
6064 fImage = xpmRawBuff2ASImage((const char*)*buffer, &params);
6065 }
6066 break;
6067 }
6068 case TImage::kPng:
6069 fImage = PNGBuff2ASimage((CARD8 *)*buffer, &params);
6070 break;
6071 default:
6072 fImage = nullptr;
6073 }
6074
6075 if (!fImage) {
6076 return kFALSE;
6077 }
6078
6079 if (fName.IsNull()) {
6080 fName.Form("img_%dx%d.%d", fImage->width, fImage->height, gRandom->Integer(1000));
6081 }
6082 UnZoom();
6083 return kTRUE;
6084}
6085
6086////////////////////////////////////////////////////////////////////////////////
6087/// Create image thumbnail.
6088
6090{
6091 int size;
6092 const int sz = 64;
6093
6094 if (!fImage) {
6095 return;
6096 }
6097
6098 if (!InitVisual()) {
6099 return;
6100 }
6101
6102 static char *buf = 0;
6103 int w, h;
6104 ASImage *img = 0;
6105
6106 if (fImage->width > fImage->height) {
6107 w = sz;
6108 h = (fImage->height*sz)/fImage->width;
6109 } else {
6110 h = sz;
6111 w = (fImage->width*sz)/fImage->height;
6112 }
6113
6114 w = w < 8 ? 8 : w;
6115 h = h < 8 ? 8 : h;
6116
6117 img = scale_asimage(fgVisual, fImage, w, h, ASA_ASImage,
6119 if (!img) {
6120 return;
6121 }
6122
6123 // contrasting
6124 ASImage *rendered_im;
6125 ASImageLayer layers[2];
6126 init_image_layers(&(layers[0]), 2);
6127 layers[0].im = img;
6128 layers[0].dst_x = 0;
6129 layers[0].dst_y = 0;
6130 layers[0].clip_width = img->width;
6131 layers[0].clip_height = img->height;
6132 layers[0].bevel = 0;
6133 layers[1].im = img;
6134 layers[1].dst_x = 0;
6135 layers[1].dst_y = 0;
6136 layers[1].clip_width = img->width;
6137 layers[1].clip_height = img->height;
6138 layers[1].merge_scanlines = blend_scanlines_name2func("tint");
6139 rendered_im = merge_layers(fgVisual, &(layers[0]), 2, img->width, img->height,
6140 ASA_ASImage, GetImageCompression(), GetImageQuality());
6141 destroy_asimage(&img);
6142 img = rendered_im;
6143
6144 // pad image
6145 ASImage *padimg = 0;
6146 int d = 0;
6147
6148 if (w == sz) {
6149 d = (sz - h) >> 1;
6150 padimg = pad_asimage(fgVisual, img, 0, d, sz, sz, 0x00ffffff,
6151 ASA_ASImage, GetImageCompression(), GetImageQuality());
6152 } else {
6153 d = (sz - w) >> 1;
6154 padimg = pad_asimage(fgVisual, img, d, 0, sz, sz, 0x00ffffff,
6155 ASA_ASImage, GetImageCompression(), GetImageQuality());
6156 }
6157
6158 if (!padimg) {
6159 destroy_asimage(&img);
6160 return;
6161 }
6162
6163 void *ptr = &buf;
6164 ASImage2xpmRawBuff(padimg, (CARD8 **)ptr, &size, 0);
6165 fTitle = buf;
6166
6167 destroy_asimage(&padimg);
6168}
6169
6170////////////////////////////////////////////////////////////////////////////////
6171/// Streamer for ROOT I/O.
6172
6173void TASImage::Streamer(TBuffer &b)
6174{
6175 Bool_t image_type = 0;
6176 int size = 0;
6177 int w, h;
6178 UInt_t R__s, R__c;
6179
6180 if (b.IsReading()) {
6181 Version_t version = b.ReadVersion(&R__s, &R__c);
6182 if (version == 0) { //dumb prototype for schema evolution
6183 return;
6184 }
6185
6186 if ( version == 1 ) {
6187 Int_t fileVersion = b.GetVersionOwner();
6188 if (fileVersion > 0 && fileVersion < 50000 ) {
6189 TImage::Streamer(b);
6190 b >> fMaxValue;
6191 b >> fMinValue;
6192 b >> fZoomOffX;
6193 b >> fZoomOffY;
6194 b >> fZoomWidth;
6195 b >> fZoomHeight;
6196 if ( fileVersion < 40200 ) {
6197 Bool_t zoomUpdate;
6198 b >> zoomUpdate;
6199 fZoomUpdate = zoomUpdate;
6200 } else {
6201 b >> fZoomUpdate;
6202 b >> fEditable;
6203 Bool_t paintMode;
6204 b >> paintMode;
6205 fPaintMode = paintMode;
6206 }
6207 b.CheckByteCount(R__s, R__c, TASImage::IsA());
6208 return;
6209 }
6210 }
6211
6212 TNamed::Streamer(b);
6213 b >> image_type;
6214
6215 if (image_type != 0) { // read PNG compressed image
6216 b >> size;
6217 char *buffer = new char[size];
6218 b.ReadFastArray(buffer, size);
6219 SetImageBuffer(&buffer, TImage::kPng);
6220 delete [] buffer;
6221 } else { // read vector with palette
6222 TAttImage::Streamer(b);
6223 b >> w;
6224 b >> h;
6225 size = w*h;
6226 Double_t *vec = new Double_t[size];
6227 b.ReadFastArray(vec, size);
6228 SetImage(vec, w, h, &fPalette);
6229 delete [] vec;
6230 }
6231 b.CheckByteCount(R__s, R__c, TASImage::IsA());
6232 } else {
6233 if (!fImage) {
6234 return;
6235 }
6236 R__c = b.WriteVersion(TASImage::IsA(), kTRUE);
6237
6238 if (fName.IsNull()) {
6239 fName.Form("img_%dx%d.%d", fImage->width, fImage->height, gRandom->Integer(1000));
6240 }
6241 TNamed::Streamer(b);
6242
6243 image_type = fImage->alt.vector ? 0 : 1;
6244 b << image_type;
6245
6246 if (image_type != 0) { // write PNG compressed image
6247 char *buffer = nullptr;
6248 GetImageBuffer(&buffer, &size, TImage::kPng);
6249 b << size;
6250 b.WriteFastArray(buffer, size);
6251 free(buffer);
6252 } else { // write vector with palette
6253 TAttImage::Streamer(b);
6254 b << fImage->width;
6255 b << fImage->height;
6256 b.WriteFastArray(fImage->alt.vector, fImage->width*fImage->height);
6257 }
6258 b.SetByteCount(R__c, kTRUE);
6259 }
6260}
6261
6262////////////////////////////////////////////////////////////////////////////////
6263/// Browse image.
6264
6266{
6267 if (fImage->alt.vector) {
6268 Draw("n");
6269 } else {
6270 Draw("nxxx");
6271 }
6273}
6274
6275////////////////////////////////////////////////////////////////////////////////
6276/// Title is used to keep 32x32 xpm image's thumbnail.
6277
6278const char *TASImage::GetTitle() const
6279{
6280 if (!gDirectory || !gDirectory->IsWritable()) {
6281 return 0;
6282 }
6283
6284 TASImage *mutble = (TASImage *)this;
6285
6286 if (fTitle.IsNull()) {
6287 mutble->SetTitle(fName.Data());
6288 }
6289
6290 return fTitle.Data();
6291}
6292
6293////////////////////////////////////////////////////////////////////////////////
6294/// Set a title for an image.
6295
6296void TASImage::SetTitle(const char *title)
6297{
6298 if (fTitle.IsNull()) {
6300 }
6301
6302 if (fTitle.IsNull()) {
6303 return;
6304 }
6305
6306 int start = fTitle.Index("/*") + 3;
6307 int stop = fTitle.Index("*/") - 1;
6308
6309 if ((start > 0) && (stop - start > 0)) {
6310 fTitle.Replace(start, stop - start, title);
6311 }
6312}
6313
6314////////////////////////////////////////////////////////////////////////////////
6315/// Draw a cubic bezier line.
6316
6318 Int_t x3, Int_t y3, const char *col, UInt_t thick)
6319{
6320 Int_t sz = thick*thick;
6321 CARD32 *matrix;
6322 Bool_t use_cache = thick < kBrushCacheSize;
6323
6324 ARGB32 color = ARGB32_White;
6325 parse_argb_color(col, &color);
6326
6327 if (use_cache) {
6328 matrix = gBrushCache;
6329 } else {
6330 matrix = new CARD32[sz];
6331 }
6332
6333 for (int i = 0; i < sz; i++) {
6334 matrix[i] = (CARD32)color;
6335 };
6336
6337 ASDrawTool brush;
6338 brush.matrix = matrix;
6339 brush.width = thick;
6340 brush.height = thick;
6341 brush.center_y = brush.center_x = thick/2;
6342
6343 ASDrawContext *ctx = 0;
6344
6345 ctx = create_draw_context_argb32(fImage, &brush);
6346 asim_cube_bezier(ctx, x1, y1, x2, y2, x3, y3);
6347
6348 if (!use_cache) {
6349 delete [] matrix;
6350 }
6352}
6353
6354////////////////////////////////////////////////////////////////////////////////
6355/// Draw a straight ellipse.
6356/// If thick < 0 - draw filled ellipse.
6357
6359 const char *col, Int_t thick)
6360{
6361 thick = !thick ? 1 : thick;
6362 Int_t sz = thick*thick;
6363 CARD32 *matrix;
6364 Bool_t use_cache = (thick > 0) && ((UInt_t)thick < kBrushCacheSize);
6365
6366 ARGB32 color = ARGB32_White;
6367 parse_argb_color(col, &color);
6368
6369 if (use_cache) {
6370 matrix = gBrushCache;
6371 } else {
6372 matrix = new CARD32[sz];
6373 }
6374
6375 for (int i = 0; i < sz; i++) {
6376 matrix[i] = (CARD32)color;
6377 };
6378
6379 ASDrawTool brush;
6380 brush.matrix = matrix;
6381 brush.width = thick > 0 ? thick : 1;
6382 brush.height = thick > 0 ? thick : 1;
6383 brush.center_y = brush.center_x = thick > 0 ? thick/2 : 0;
6384
6385 ASDrawContext *ctx = create_draw_context_argb32(fImage, &brush);
6386 asim_straight_ellips(ctx, x, y, rx, ry, thick < 0);
6387
6388 if (!use_cache) {
6389 delete [] matrix;
6390 }
6392}
6393
6394////////////////////////////////////////////////////////////////////////////////
6395/// Draw a circle.
6396/// If thick < 0 - draw filled circle
6397
6398void TASImage::DrawCircle(Int_t x, Int_t y, Int_t r, const char *col, Int_t thick)
6399{
6400 thick = !thick ? 1 : thick;
6401 Int_t sz = thick*thick;
6402 CARD32 *matrix;
6403 Bool_t use_cache = (thick > 0) && ((UInt_t)thick < kBrushCacheSize);
6404
6405 ARGB32 color = ARGB32_White;
6406 parse_argb_color(col, &color);
6407
6408///matrix = new CARD32[sz];
6409 if (use_cache) {
6410 matrix = gBrushCache;
6411 } else {
6412 matrix = new CARD32[sz];
6413 }
6414
6415 for (int i = 0; i < sz; i++) {
6416 matrix[i] = (CARD32)color;
6417 }
6418
6419 ASDrawTool brush;
6420 brush.matrix = matrix;
6421 brush.height = brush.width = thick > 0 ? thick : 1;
6422 brush.center_y = brush.center_x = thick > 0 ? thick/2 : 0;
6423
6424 ASDrawContext *ctx = create_draw_context_argb32(fImage, &brush);
6425 asim_circle(ctx, x, y, r, thick < 0);
6426
6427///free (matrix);
6428 if (!use_cache) {
6429 delete [] matrix;
6430 }
6432}
6433
6434////////////////////////////////////////////////////////////////////////////////
6435/// Draw an ellipse.
6436/// If thick < 0 - draw filled ellips
6437
6439 const char *col, Int_t thick)
6440{
6441 thick = !thick ? 1 : thick;
6442 Int_t sz = thick*thick;
6443 CARD32 *matrix;
6444 Bool_t use_cache = (thick > 0) && ((UInt_t)thick < kBrushCacheSize);
6445
6446 ARGB32 color = ARGB32_White;
6447 parse_argb_color(col, &color);
6448
6449 if (use_cache) {
6450 matrix = gBrushCache;
6451 } else {
6452 matrix = new CARD32[sz];
6453 }
6454
6455 for (int i = 0; i < sz; i++) {
6456 matrix[i] = (CARD32)color;
6457 };
6458
6459 ASDrawTool brush;
6460 brush.matrix = matrix;
6461 brush.width = thick > 0 ? thick : 1;
6462 brush.height = thick > 0 ? thick : 1;
6463 brush.center_y = brush.center_x = thick > 0 ? thick/2 : 0;
6464
6465 ASDrawContext *ctx = create_draw_context_argb32(fImage, &brush);
6466 asim_ellips(ctx, x, y, rx, ry, angle, thick < 0);
6467
6468 if (!use_cache) {
6469 delete [] matrix;
6470 }
6472}
6473
6474////////////////////////////////////////////////////////////////////////////////
6475/// Draw an ellipse.
6476/// If thick < 0 - draw filled ellipse.
6477
6479 const char *col, Int_t thick)
6480{
6481 thick = !thick ? 1 : thick;
6482 Int_t sz = thick*thick;
6483 CARD32 *matrix;
6484 Bool_t use_cache = (thick > 0) && ((UInt_t)thick < kBrushCacheSize);
6485
6486 ARGB32 color = ARGB32_White;
6487 parse_argb_color(col, &color);
6488
6489 if (use_cache) {
6490 matrix = gBrushCache;
6491 } else {
6492 matrix = new CARD32[sz];
6493 }
6494
6495 for (int i = 0; i < sz; i++) {
6496 matrix[i] = (CARD32)color;
6497 };
6498
6499 ASDrawTool brush;
6500 brush.matrix = matrix;
6501 brush.width = thick > 0 ? thick : 1;
6502 brush.height = thick > 0 ? thick : 1;
6503 brush.center_y = brush.center_x = thick > 0 ? thick/2 : 0;
6504
6505 ASDrawContext *ctx = create_draw_context_argb32(fImage, &brush);
6506 asim_ellips2(ctx, x, y, rx, ry, angle, thick < 0);
6507
6508 if (!use_cache) {
6509 delete [] matrix;
6510 }
6512}
6513
6514////////////////////////////////////////////////////////////////////////////////
6515/// Flood fill.
6516
6517void TASImage::FloodFill(Int_t /*x*/, Int_t /*y*/, const char * /*col*/,
6518 const char * /*minc*/, const char * /*maxc*/)
6519{
6520}
6521
6522////////////////////////////////////////////////////////////////////////////////
6523/// Convert RGB image to Gray image and vice versa.
6524
6526{
6527 if (fIsGray == on) {
6528 return;
6529 }
6530
6531 if (!IsValid()) {
6532 Warning("Gray", "Image not initiated");
6533 return;
6534 }
6535
6536 if (!InitVisual()) {
6537 Warning("Gray", "Visual not initiated");
6538 return;
6539 }
6540
6541 if (!fGrayImage && !on) {
6542 return;
6543 }
6544 ASImage *sav = 0;
6545 delete fScaledImage;
6546 fScaledImage = 0;
6547
6548 if (fGrayImage) {
6549 sav = fImage;
6551 fGrayImage = sav;
6552 fIsGray = on;
6553 return;
6554 }
6555
6556 if (!on) return;
6557
6558 UInt_t l, r, g, b, idx;
6559 int y = 0;
6560 UInt_t i, j;
6561
6562 if (fImage->alt.argb32) {
6563 fGrayImage = tile_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height,
6564 0, ASA_ARGB32, 0, ASIMAGE_QUALITY_DEFAULT);
6565
6566 for (i = 0; i < fImage->height; i++) {
6567 for (j = 0; j < fImage->width; j++) {
6568 idx = Idx(y + j);
6569
6570 r = ((fImage->alt.argb32[idx] & 0xff0000) >> 16);
6571 g = ((fImage->alt.argb32[idx] & 0x00ff00) >> 8);
6572 b = (fImage->alt.argb32[idx] & 0x0000ff);
6573 l = (57*r + 181*g + 18*b)/256;
6574 fGrayImage->alt.argb32[idx] = (l << 16) + (l << 8) + l;
6575 }
6576 y += fImage->width;
6577 }
6578 } else {
6579 fGrayImage = create_asimage(fImage->width, fImage->height, 0);
6580
6581 ASImageDecoder *imdec = start_image_decoding(fgVisual, fImage, SCL_DO_ALL,
6582 0, 0, fImage->width, fImage->height, 0);
6583
6584 if (!imdec) {
6585 return;
6586 }
6587#ifdef HAVE_MMX
6588 mmx_init();
6589#endif
6590 ASImageOutput *imout = start_image_output(fgVisual, fGrayImage, ASA_ASImage,
6592 if (!imout) {
6593 Warning("ToGray", "Failed to start image output");
6594 delete fScaledImage;
6595 fScaledImage = 0;
6596 delete [] imdec;
6597 return;
6598 }
6599
6600 CARD32 *aa = imdec->buffer.alpha;
6601 CARD32 *rr = imdec->buffer.red;
6602 CARD32 *gg = imdec->buffer.green;
6603 CARD32 *bb = imdec->buffer.blue;
6604
6605 ASScanline result;
6606 prepare_scanline(fImage->width, 0, &result, fgVisual->BGR_mode);
6607
6608 for (i = 0; i < fImage->height; i++) {
6609 imdec->decode_image_scanline(imdec);
6610 result.flags = imdec->buffer.flags;
6611 result.back_color = imdec->buffer.back_color;
6612
6613 for (j = 0; j < fImage->width; j++) {
6614 l = (57*rr[j] + 181*gg[j]+ 18*bb[j])/256;
6615 result.alpha[j] = aa[j];
6616 result.red[j] = l;
6617 result.green[j] = l;
6618 result.blue[j] = l;
6619 }
6620 imout->output_image_scanline(imout, &result, 1);
6621 }
6622
6623 stop_image_decoding(&imdec);
6624 stop_image_output(&imout);
6625#ifdef HAVE_MMX
6626 mmx_off();
6627#endif
6628 }
6629
6630 sav = fImage;
6632 fGrayImage = sav;
6633 fIsGray = kTRUE;
6634}
6635
6636////////////////////////////////////////////////////////////////////////////////
6637/// Create an image (screenshot) from specified window.
6638
6640{
6641 Int_t xy;
6642
6643 x = x < 0 ? 0 : x;
6644 y = y < 0 ? 0 : y;
6645
6646 // X11 Synchronization
6647 gVirtualX->Update(1);
6648 if (!gThreadXAR) {
6649 gSystem->Sleep(10);
6651 gSystem->Sleep(10);
6653 }
6654
6655 if (!w || !h) {
6656 gVirtualX->GetWindowSize(wid, xy, xy, w, h);
6657 }
6658
6659 if ((x >= (Int_t)w) || (y >= (Int_t)h)) {
6660 return;
6661 }
6662
6663 if (!InitVisual()) {
6664 Warning("FromWindow", "Visual not initiated");
6665 return;
6666 }
6667
6668 DestroyImage();
6669 delete fScaledImage;
6670 fScaledImage = 0;
6671
6672 static int x11 = -1;
6673 if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11");
6674
6675 if (x11) { //use built-in optimized version
6676 fImage = pixmap2asimage(fgVisual, wid, x, y, w, h, kAllPlanes, 0, 0);
6677 } else {
6678 unsigned char *bits = gVirtualX->GetColorBits(wid, 0, 0, w, h);
6679
6680 if (!bits) { // error
6681 return;
6682 }
6683 fImage = bitmap2asimage(bits, w, h, 0, 0);
6684 delete [] bits;
6685 }
6686}
6687
6688////////////////////////////////////////////////////////////////////////////////
6689/// Creates an image (screenshot) from a RGBA buffer.
6690
6692{
6693 DestroyImage();
6694 delete fScaledImage;
6695 fScaledImage = 0;
6696
6697 UChar_t* xx = new UChar_t[4*w];
6698 for (UInt_t i = 0; i < h/2; ++i) {
6699 memcpy(xx, buf + 4*w*i, 4*w);
6700 memcpy(buf + 4*w*i, buf + 4*w*(h-i-1), 4*w);
6701 memcpy(buf + 4*w*(h-i-1), xx, 4*w);
6702 }
6703 delete [] xx;
6704
6705 fImage = bitmap2asimage(buf, w, h, 0, 0);
6706}
6707
6708////////////////////////////////////////////////////////////////////////////////
6709/// Switch on/off the image palette.
6710/// That also invokes calling vectorization of image.
6711
6713{
6714 if (!fImage) {
6715 return;
6716 }
6717
6718 if (!fImage->alt.vector && on) {
6719 Vectorize();
6720 }
6721 fPaletteEnabled = on;
6722
6723 if (on) {
6724 Double_t left = gPad->GetLeftMargin();
6725 Double_t right = gPad->GetRightMargin();
6726 Double_t top = gPad->GetTopMargin();
6727 Double_t bottom = gPad->GetBottomMargin();
6728
6729 gPad->Range(-left / (1.0 - left - right),
6730 -bottom / (1.0 - top - bottom),
6731 1 + right / (1.0 - left - right),
6732 1 + top / ( 1.0 - top - bottom));
6733 gPad->RangeAxis(0, 0, 1, 1);
6734 }
6735
6736}
6737
6738////////////////////////////////////////////////////////////////////////////////
6739/// Save a primitive as a C++ statement(s) on output stream "out".
6740
6741void TASImage::SavePrimitive(std::ostream &out, Option_t * /*= ""*/)
6742{
6743 char *buf = 0;
6744 int sz;
6745
6746 if (GetWidth() > 500) { // workaround CINT limitations
6747 UInt_t w = 500;
6748 Double_t scale = 500./GetWidth();
6749 UInt_t h = TMath::Nint(GetHeight()*scale);
6750 Scale(w, h);
6751 }
6752
6753 GetImageBuffer(&buf, &sz, TImage::kXpm);
6754 TString str = buf;
6755 free(buf);
6756
6757 TString name = GetName();
6758 name.ReplaceAll(".", "_");
6759 static int ii = 0;
6760 ii++;
6761
6762 str.ReplaceAll("static", "const");
6763 TString xpm = "xpm_";
6764 xpm += name;
6765 xpm += ii;
6766 str.ReplaceAll("asxpm", xpm.Data());
6767 out << std::endl << str << std::endl << std::endl;
6768
6769 out << " TImage *";
6770 out << xpm << "_img = TImage::Create();" << std::endl;
6771 out << " " << xpm << "_img->SetImageBuffer( (char **)" << xpm << ", TImage::kXpm);" << std::endl;
6772 out << " " << xpm << "_img->Draw();" << std::endl;
6773}
6774
6775////////////////////////////////////////////////////////////////////////////////
6776/// Set an image printing resolution in Dots Per Inch units.
6777///
6778/// \param[in] name - the name of jpeg file.
6779/// \param[in] set - dpi resolution.
6780///
6781/// Returns kFALSE in case of error.
6782
6784{
6785 static char buf[32];
6786 FILE *fp = fopen(name, "rb+");
6787
6788 if (!fp) {
6789 printf("file %s : failed to open\n", name);
6790 return kFALSE;
6791 }
6792
6793 if (!fread(buf, 1, 20, fp)) {
6794 fclose(fp);
6795 return kFALSE;
6796 }
6797
6798 char dpi1 = (set & 0xffff) >> 8;
6799 char dpi2 = set & 0xff;
6800
6801 int i = 0;
6802
6803 int dpi = 0; // start of dpi data
6804 for (i = 0; i < 20; i++) {
6805 if ((buf[i] == 0x4a) && (buf[i+1] == 0x46) && (buf[i+2] == 0x49) &&
6806 (buf[i+3] == 0x46) && (buf[i+4] == 0x00) ) {
6807 dpi = i + 7;
6808 break;
6809 }
6810 }
6811
6812 if (i == 20 || dpi+4 >= 20) { // jpeg maker was not found
6813 fclose(fp);
6814 printf("file %s : wrong JPEG format\n", name);
6815 return kFALSE;
6816 }
6817
6818 buf[dpi] = 1; // format specified in dots per inch
6819
6820 // set x density in dpi units
6821 buf[dpi + 1] = dpi1;
6822 buf[dpi + 2] = dpi2;
6823
6824 // set y density in dpi units
6825 buf[dpi + 3] = dpi1;
6826 buf[dpi + 4] = dpi2;
6827
6828 rewind(fp);
6829 fwrite(buf, 1, 20, fp);
6830 fclose(fp);
6831
6832 return kTRUE;
6833}
6834
6835////////////////////////////////////////////////////////////////////////////////
6836/// Return a valid index in fImage tables to avoid seg-fault by accessing out of
6837/// indices out of array's ranges.
6838
6840{
6841 // The size of arrays like fImage->alt.argb32 is fImage->width*fImage->height
6842 return TMath::Min(idx,(Int_t)(fImage->width*fImage->height));
6843}
6844
@ 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]
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
unsigned short UShort_t
Definition RtypesCore.h:40
const Ssiz_t kNPOS
Definition RtypesCore.h:124
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:101
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:100
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.
#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:385
include TDocParser_001 C image html pict1_TDocParser_001 png width
R__EXTERN TEnv * gEnv
Definition TEnv.h:170
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:404
R__EXTERN TRandom * gRandom
Definition TRandom.h:62
char * Form(const char *fmt,...)
R__EXTERN TStyle * gStyle
Definition TStyle.h:413
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:2107
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:1822
const char * AsHexString() const
Return color as hexadecimal string.
Definition TColor.cxx:1268
Int_t GetNumber() const
Definition TColor.h:56
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:975
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:31
Mother of all ROOT objects.
Definition TObject.h:41
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:949
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition TObject.cxx:393
virtual void Delete(Option_t *option="")
Delete this object.
Definition TObject.cxx:241
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:766
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:515
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:963
virtual void Draw(Option_t *option="")
Default Draw method for all objects.
Definition TObject.cxx:267
Longptr_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:1150
Int_t Atoi() const
Return integer value of string.
Definition TString.cxx:1946
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
Return true if string ends with the specified string.
Definition TString.cxx:2202
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition TString.cxx:1131
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:523
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:1788
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:916
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition TString.cxx:2222
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:500
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2314
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:1274
virtual const char * PrependPathName(const char *dir, TString &name)
Concatenate a directory and a file name.
Definition TSystem.cxx:1081
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition TSystem.cxx:935
virtual void Sleep(UInt_t milliSec)
Sleep milliSec milli seconds.
Definition TSystem.cxx:440
virtual char * Which(const char *search, const char *file, EAccessMode mode=kFileExists)
Find location of file in a search path.
Definition TSystem.cxx:1546
virtual const char * HomeDirectory(const char *userName=nullptr)
Return the user's home directory.
Definition TSystem.cxx:888
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition TSystem.cxx:419
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:663
Short_t Max(Short_t a, Short_t b)
Definition TMathBase.h:208
Double_t ATan2(Double_t y, Double_t x)
Definition TMath.h:629
Short_t Min(Short_t a, Short_t b)
Definition TMathBase.h:176
Double_t Cos(Double_t)
Definition TMath.h:593
Double_t Sin(Double_t)
Definition TMath.h:589
Short_t Abs(Short_t d)
Definition TMathBase.h:120
Definition file.py:1
ScanLineList scanlines
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
struct _EdgeTableEntry * next
struct _ScanLineListBlock * next
EdgeTableEntry * edgelist
struct _ScanLineList * next
unsigned char a
Definition TASImage.cxx:147
unsigned char b
Definition TASImage.cxx:150
unsigned char r
Definition TASImage.cxx:148
unsigned char g
Definition TASImage.cxx:149
th1 Draw()
auto * l
Definition textangle.C:4
void flip(struct mesh *m, struct behavior *b, struct otri *flipedge)
Definition triangle.c:7890