TASImage.cxx

Go to the documentation of this file.
00001 // @(#)root/asimage:$Id: TASImage.cxx,v 1.54 2006/03/13 15:18:56 rdm E
00002 // Author: Fons Rademakers, Reiner Rohlfs, Valeriy Onuchin   28/11/2001
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2001, Rene Brun, Fons Rademakers and Reiner Rohlfs *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 /**************************************************************************
00013  * Some parts of this source are based on libAfterImage 2.00.00
00014  *          (http://www.afterstep.org/)
00015  *
00016  * Copyright (c) 2002 Sasha Vasko <sasha@aftercode.net>
00017  * Copyright (c) 1998, 1999 Ethan Fischer <allanon@crystaltokyo.com>
00018  *
00019  * This program is free software; you can redistribute it and/or modify
00020  * it under the terms of the GNU Library General Public License as
00021  * published by the Free Software Foundation; either version 2 of the
00022  * License, or (at your option) any later version.
00023  *
00024  * This program is distributed in the hope that it will be useful,
00025  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00026  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00027  * GNU General Public License for more details.
00028  *
00029  * You should have received a copy of the GNU Library General Public
00030  * License along with this program; if not, write to the Free Software
00031  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00032  *
00033  **************************************************************************/
00034 
00035 
00036 //______________________________________________________________________________
00037 /* Begin_Html
00038 <center><h2>Image class</h2></center>
00039 TASImage is the concrete interface to the image processing library
00040 libAfterImage.
00041 <p>
00042 It allows reading and writing of images in different formats, several image
00043 manipulations (scaling, tiling, merging, etc.) and displaying in pads. The size
00044 of the image on the screen does not depend on the original size of the image but
00045 on the size of the pad. Therefore it is very easy to resize the image on the
00046 screen by resizing the pad.
00047 <p>
00048 Besides reading an image from a file an image can be defined by a two
00049 dimensional array of values. A palette defines the color of each value.
00050 <p>
00051 The image can be zoomed by defining a rectangle with the mouse. The color
00052 palette can be modified with a GUI, just select StartPaletteEditor() from the
00053 context menu.
00054 End_Html */
00055 
00056 #include "TASImage.h"
00057 #include "TASImagePlugin.h"
00058 #include "TROOT.h"
00059 #include "TMath.h"
00060 #include "TSystem.h"
00061 #include "TVirtualX.h"
00062 #include "TVirtualPad.h"
00063 #include "TArrayD.h"
00064 #include "TVectorD.h"
00065 #include "TVirtualPS.h"
00066 #include "TGaxis.h"
00067 #include "TColor.h"
00068 #include "TObjArray.h"
00069 #include "TArrayL.h"
00070 #include "TPoint.h"
00071 #include "TFrame.h"
00072 #include "TTF.h"
00073 #include "TRandom.h"
00074 #include "Riostream.h"
00075 #include "THashTable.h"
00076 #include "TPluginManager.h"
00077 #include "TEnv.h"
00078 #include "TStyle.h"
00079 #include "TText.h"
00080 
00081 
00082 #ifndef WIN32
00083 #   include <X11/Xlib.h>
00084 #else
00085 #   include "Windows4root.h"
00086 #endif
00087 extern "C" {
00088 #ifndef WIN32
00089 #   include <afterbase.h>
00090 #else
00091 #   include <win32/config.h>
00092 #   include <win32/afterbase.h>
00093 #   define X_DISPLAY_MISSING 1
00094 #endif
00095 #   include <afterimage.h>
00096 #   include <bmp.h>
00097 #   include <draw.h>
00098 }
00099 
00100 // auxilary functions for general polygon filling
00101 #include "TASPolyUtils.c"
00102 
00103 
00104 ASVisual *TASImage::fgVisual = 0;
00105 Bool_t TASImage::fgInit = kFALSE;
00106 
00107 static ASFontManager *gFontManager = 0;
00108 static unsigned long kAllPlanes = ~0;
00109 THashTable *TASImage::fgPlugList = new THashTable(50);
00110 
00111 // default icon paths
00112 static char *gIconPaths[7] = {0, 0, 0, 0, 0, 0, 0};
00113 
00114 ///////////////////////////// alphablending macros ///////////////////////////////
00115 
00116 #if defined(__GNUC__) && __GNUC__ >= 4 && ((__GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ >= 1) || (__GNUC_MINOR__ >= 3)) && !__INTEL_COMPILER
00117 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
00118 #endif
00119 
00120 #ifdef R__BYTESWAP
00121 typedef struct {
00122    unsigned char b;
00123    unsigned char g;
00124    unsigned char r;
00125    unsigned char a;
00126 } __argb32__;
00127 #else
00128 typedef struct {
00129    unsigned char a;
00130    unsigned char r;
00131    unsigned char g;
00132    unsigned char b;
00133 } __argb32__;
00134 #endif
00135 
00136 
00137 //______________________________________________________________________________
00138 #define _alphaBlend(bot, top) {\
00139    __argb32__ *t = (__argb32__*)(top);\
00140    __argb32__ *b = (__argb32__*)(bot);\
00141    int aa = 255-t->a;\
00142    if (!aa) {\
00143       *bot = *top;\
00144    } else { \
00145       b->a = ((b->a*aa)>>8) + t->a;\
00146       b->r = (b->r*aa + t->r*t->a)>>8;\
00147       b->g = (b->g*aa + t->g*t->a)>>8;\
00148       b->b = (b->b*aa + t->b*t->a)>>8;\
00149    }\
00150 }\
00151 
00152 
00153 ClassImp(TASImage)
00154 ClassImp(TASImagePlugin)
00155 
00156 
00157 //______________________________________________________________________________
00158 void TASImage::DestroyImage()
00159 {
00160    // Destroy image.
00161 
00162    if (fImage) {
00163       destroy_asimage(&fImage);
00164    }
00165 
00166    if (fIsGray && fGrayImage) {
00167       destroy_asimage(&fGrayImage);
00168    }
00169 
00170    fIsGray     = kFALSE;
00171    fGrayImage  = 0;
00172    fImage      = 0;
00173 }
00174 
00175 
00176 //______________________________________________________________________________
00177 void TASImage::SetDefaults()
00178 {
00179    // Set default parameters.
00180 
00181    fImage         = 0;
00182    fScaledImage   = 0;
00183    fMaxValue      = 1;
00184    fMinValue      = 0;
00185    fEditable      = kFALSE;
00186    fPaintMode     = 1;
00187    fZoomOffX      = 0;
00188    fZoomOffY      = 0;
00189    fZoomWidth     = 0;
00190    fZoomHeight    = 0;
00191    fZoomUpdate    = kZoomOps;
00192 
00193    fGrayImage     = 0;
00194    fIsGray        = kFALSE;
00195    fPaletteEnabled = kFALSE;
00196 
00197    if (!fgInit) {
00198       set_application_name((char*)(gProgName ? gProgName : "ROOT"));
00199       fgInit = kTRUE;
00200    }
00201 }
00202 
00203 
00204 //______________________________________________________________________________
00205 TASImage::TASImage()
00206 {
00207    // Default image constructor.
00208 
00209    SetDefaults();
00210 }
00211 
00212 
00213 //______________________________________________________________________________
00214 TASImage::TASImage(UInt_t w, UInt_t h) : TImage(w, h)
00215 {
00216    // Create an empty image.
00217 
00218    SetDefaults();
00219    fImage = create_asimage(w ? w : 20, h ? h : 20, 0);
00220    UnZoom();
00221 }
00222 
00223 
00224 //______________________________________________________________________________
00225 TASImage::TASImage(const char *file, EImageFileTypes) : TImage(file)
00226 {
00227    // Create an image object and read from specified file.
00228    // For more information see description of function ReadImage()
00229    // which is called by this constructor.
00230 
00231    SetDefaults();
00232    TString fname = file;
00233    gSystem->ExpandPathName(fname);
00234    ReadImage(fname.Data());
00235 }
00236 
00237 
00238 //______________________________________________________________________________
00239 TASImage::TASImage(const char *name, const Double_t *imageData, UInt_t width,
00240                    UInt_t height, TImagePalette *palette) : TImage(name)
00241 {
00242    // Create an image depending on the values of imageData.
00243    // For more information see function SetImage() which is called
00244    // by this constructor.
00245 
00246    SetDefaults();
00247    SetImage(imageData, width, height, palette);
00248 }
00249 
00250 
00251 //______________________________________________________________________________
00252 TASImage::TASImage(const char *name, const TArrayD &imageData, UInt_t width,
00253                    TImagePalette *palette) : TImage(name)
00254 {
00255    // Create an image depending on the values of imageData.
00256    // The size of the image is width X (imageData.fN / width).
00257    // For more information see function SetImage() which is called by
00258    // this constructor.
00259 
00260    SetDefaults();
00261    SetImage(imageData, width, palette);
00262 }
00263 
00264 
00265 //______________________________________________________________________________
00266 TASImage::TASImage(const char *name, const TVectorD &imageData, UInt_t width,
00267                    TImagePalette *palette) : TImage(name)
00268 {
00269    // Create an image depending on the values of imageData.
00270    // The size of the image is width X (imageData.fN / width).
00271    // For more information see function SetImage() which is called by
00272    // this constructor.
00273 
00274    SetDefaults();
00275    SetImage(imageData, width, palette);
00276 }
00277 
00278 
00279 //______________________________________________________________________________
00280 TASImage::TASImage(const TASImage &img) : TImage(img)
00281 {
00282    // Image copy constructor.
00283 
00284    SetDefaults();
00285 
00286    if (img.IsValid()) {
00287       fImage = clone_asimage(img.fImage, SCL_DO_ALL);
00288       fScaledImage   = fScaledImage ? (TASImage*)img.fScaledImage->Clone("") : 0;
00289       fGrayImage     = fGrayImage ? clone_asimage(img.fGrayImage, SCL_DO_ALL) : 0;
00290 
00291       if (img.fImage->alt.vector) {
00292          Int_t size = img.fImage->width * img.fImage->height * sizeof(double);
00293          fImage->alt.vector = (double*)malloc(size);
00294          memcpy(fImage->alt.vector, img.fImage->alt.vector, size);
00295       }
00296 
00297       fZoomUpdate = kNoZoom;
00298       fZoomOffX   = img.fZoomOffX;
00299       fZoomOffY   = img.fZoomOffY;
00300       fZoomWidth  = img.fZoomWidth;
00301       fZoomHeight = img.fZoomHeight;
00302       fEditable   = img.fEditable;
00303       fIsGray     = img.fIsGray;
00304    }
00305 }
00306 
00307 
00308 //______________________________________________________________________________
00309 TASImage &TASImage::operator=(const TASImage &img)
00310 {
00311    // Image assignment operator.
00312 
00313    SetDefaults();
00314 
00315    if (this != &img && img.IsValid()) {
00316       TImage::operator=(img);
00317 
00318       DestroyImage();
00319       delete fScaledImage;
00320       fImage = clone_asimage(img.fImage, SCL_DO_ALL);
00321       fScaledImage = fScaledImage ? (TASImage*)img.fScaledImage->Clone("") : 0;
00322       fGrayImage = fGrayImage ? clone_asimage(img.fGrayImage, SCL_DO_ALL) : 0;
00323 
00324       if (img.fImage->alt.vector) {
00325          Int_t size = img.fImage->width * img.fImage->height * sizeof(double);
00326          fImage->alt.vector = (double*)malloc(size);
00327          memcpy(fImage->alt.vector, img.fImage->alt.vector, size);
00328       }
00329 
00330       fScaledImage = img.fScaledImage ? (TASImage*)img.fScaledImage->Clone("") : 0;
00331       fZoomUpdate = kNoZoom;
00332       fZoomOffX   = img.fZoomOffX;
00333       fZoomOffY   = img.fZoomOffY;
00334       fZoomWidth  = img.fZoomWidth;
00335       fZoomHeight = img.fZoomHeight;
00336       fEditable   = img.fEditable;
00337       fIsGray     = img.fIsGray;
00338       fPaintMode  = 1;
00339    }
00340 
00341    return *this;
00342 }
00343 
00344 
00345 //______________________________________________________________________________
00346 TASImage::~TASImage()
00347 {
00348    // Image destructor, clean up image and visual.
00349 
00350    DestroyImage();
00351    delete fScaledImage;
00352    fScaledImage = 0;
00353 }
00354 
00355 
00356 //______________________________________________________________________________
00357 static void init_icon_paths()
00358 {
00359    // Set icons paths.
00360 
00361    const char *icons = "/icons";
00362 #ifdef R__WIN32
00363       icons = "\\icons";
00364 #endif
00365 
00366    TString homeIcons = gSystem->HomeDirectory();
00367    homeIcons += icons;
00368 
00369    TString rootIcons = gSystem->Getenv("ROOTSYS");
00370    rootIcons += icons;
00371 
00372    TString guiIcons = gEnv->GetValue("Gui.IconPath", "");
00373 
00374    gIconPaths[0] = StrDup(".");
00375    gIconPaths[1] = StrDup(homeIcons.Data());
00376    gIconPaths[2] = StrDup(rootIcons.Data());
00377    gIconPaths[3] = StrDup(guiIcons.Data());
00378 
00379 #ifdef ROOTICONPATH
00380    gIconPaths[4] = ROOTICONPATH;
00381 #endif
00382 
00383 #ifdef EXTRAICONPATH
00384    gIconPaths[5] = EXTRAICONPATH;
00385 #endif
00386 
00387    gIconPaths[6] = 0;
00388 }
00389 
00390 
00391 //______________________________________________________________________________
00392 const char *TASImage::TypeFromMagicNumber(const char *file)
00393 {
00394    // Guess the file type from the first byte of file.
00395 
00396    UChar_t magic;
00397    FILE *fp = fopen(file, "rb");
00398    const char *ret = "";
00399 
00400    if (!fp) return 0;
00401 
00402    if (!fread(&magic, 1, 1, fp)) {
00403       fclose(fp);
00404       return 0;
00405    }
00406 
00407    switch (magic) {
00408       case 0x00:
00409       {
00410          if (!fread(&magic, 1, 1, fp)) return 0;
00411          if (!fread(&magic, 1, 1, fp)) return 0;
00412 
00413          ret = (magic == 1) ? "ico" : "cur";
00414          break;
00415       }
00416       case 0x25:
00417       {
00418          if (!fread(&magic, 1, 1, fp)) return 0;
00419          if (magic == 0x21) ret = "ps";
00420          else if (magic == 0x50) ret = "pdf";
00421          break;
00422       }
00423       case 0x42:
00424          ret = "bmp";
00425          break;
00426       case 0x47:
00427          ret = "gif";
00428          break;
00429       case 0x54:
00430          ret = "tga";
00431          break;
00432       case 0x49:
00433          ret = "tiff";
00434          break;
00435       case 0x89:
00436          ret = "png";
00437          break;
00438       case 0xff:
00439          ret = "jpg";
00440          break;
00441       default:
00442          ret = "";
00443    }
00444 
00445    fclose(fp);
00446    return ret;
00447 }
00448 
00449 
00450 //______________________________________________________________________________
00451 void TASImage::ReadImage(const char *filename, EImageFileTypes /*type*/)
00452 {
00453    // Read specified image file.
00454    // The file type is determined by the file extension (the type argument is
00455    // ignored). It will attempt to append .gz and then .Z to the filename and
00456    // find such a file. If the filename ends with extension consisting of digits
00457    // only, it will attempt to find the file with this extension stripped
00458    // off. On success this extension will be used to load subimage from
00459    // the file with that number. Subimage is supported for GIF files
00460    // (ICO, BMP, CUR, TIFF, XCF to be supported in future).
00461    //  For example,
00462    //    i1 = TImage::Open("anim.gif.0"); // read the first subimage
00463    //    i4 = TImage::Open("anim.gif.3"); // read the forth subimage
00464    //
00465    // It is also possible to put XPM raw string (see also SetImageBuffer) as
00466    // the first input parameter ("filename"), such string  is returned by
00467    // GetImageBuffer method.
00468 
00469    if (!InitVisual()) {
00470       Warning("Scale", "Visual not initiated");
00471       return;
00472    }
00473 
00474    Bool_t xpm = filename && (filename[0] == '/' &&
00475                 filename[1] == '*') && filename[2] == ' ';
00476 
00477    if (xpm) {  // XPM strings in-memory array
00478       SetImageBuffer((char**)&filename, TImage::kXpm);
00479       fName = "XPM_image";
00480       return;
00481    }
00482 
00483    if (!gIconPaths[0]) {
00484       init_icon_paths();
00485    }
00486    // suppress the "root : looking for image ..." messages
00487    set_output_threshold(0);
00488 
00489    static ASImageImportParams iparams;
00490    iparams.flags = 0;
00491    iparams.width = 0;
00492    iparams.height = 0;
00493    iparams.filter = SCL_DO_ALL;
00494    iparams.gamma = SCREEN_GAMMA;
00495    iparams.gamma_table = NULL;
00496    iparams.compression = GetImageCompression();
00497    iparams.format = ASA_ASImage;
00498    iparams.search_path = gIconPaths;
00499    iparams.subimage = 0;
00500    iparams.return_animation_delay = -1;
00501 
00502    TString ext;
00503    const char *dot;
00504    if (filename) dot = strrchr(filename, '.');
00505    else          dot = 0;
00506    ASImage *image = 0;
00507    TString fname = filename;
00508 
00509    if (!dot) {
00510       if (filename) ext = TypeFromMagicNumber(filename);
00511       else ext = dot + 1;
00512    } else {
00513       ext = dot + 1;
00514    }
00515 
00516    if (!ext.IsNull() && ext.IsDigit()) { // read subimage
00517       iparams.subimage = ext.Atoi();
00518       fname = fname(0, fname.Length() - ext.Length() - 1);
00519       ext = strrchr(fname.Data(), '.') + 1;
00520    }
00521 
00522    image = file2ASImage_extra(fname.Data(), &iparams);
00523 
00524    if (image) { // it's OK
00525       goto end;
00526    } else {  // try to read it via plugin
00527       if (ext.IsNull()) {
00528          return;
00529       }
00530       ext.ToLower();
00531       ext.Strip();
00532       UInt_t w = 0;
00533       UInt_t h = 0;
00534       unsigned char *bitmap = 0;
00535 
00536       TImagePlugin *plug = (TImagePlugin*)fgPlugList->FindObject(ext.Data());
00537 
00538       if (!plug) {
00539          TPluginHandler *handler = gROOT->GetPluginManager()->FindHandler("TImagePlugin", ext);
00540          if (!handler || ((handler->LoadPlugin() == -1))) {
00541             return;
00542          }
00543          plug = (TImagePlugin*)handler->ExecPlugin(1, ext.Data());
00544 
00545          if (!plug) {
00546             return;
00547          }
00548 
00549          fgPlugList->Add(plug);
00550       }
00551 
00552       if (plug) {
00553          if (plug->InheritsFrom(TASImagePlugin::Class())) {
00554             image = ((TASImagePlugin*)plug)->File2ASImage(fname.Data());
00555             if (image) goto end;
00556          }
00557          bitmap = plug->ReadFile(fname.Data(), w, h);
00558          if (bitmap) {
00559             image = bitmap2asimage(bitmap, w, h, 0, 0);
00560          }
00561          if (!image) {
00562             return;
00563          }
00564       }
00565    }
00566 
00567 end:
00568    fName.Form("%s.", gSystem->BaseName(fname.Data()));
00569 
00570    DestroyImage();
00571    delete fScaledImage;
00572    fScaledImage = 0;
00573 
00574    fImage      = image;
00575    fZoomUpdate = kNoZoom;
00576    fEditable   = kFALSE;
00577    fZoomOffX   = 0;
00578    fZoomOffY   = 0;
00579    fZoomWidth  = fImage->width;
00580    fZoomHeight = fImage->height;
00581    fPaintMode  = 1;
00582 }
00583 
00584 
00585 //______________________________________________________________________________
00586 void TASImage::WriteImage(const char *file, EImageFileTypes type)
00587 {
00588    // Write image to specified file.
00589    // If there is no file extension or if the file extension is unknown, the
00590    // type argument will be used to determine the file type. The quality and
00591    // compression is derived from the TAttImage values.
00592    // It's posiible to write image into an animated GIF file by specifying file
00593    // name as "myfile.gif+" of "myfile.gif+NN", where NN is delay of displaying
00594    // subimages during animation in 10ms seconds units.
00595    // If NN is ommitted the delay between subimages is zero.
00596    // For repeated animation the last subimage must be specified as
00597    // "myfile.gif++NN", where NN is number of cycles. If NN is ommitted the
00598    // animation will be infinite.
00599    //
00600    // The following macro creates animated gif from jpeg images with names
00601    //    imageNN.jpg, where 1<= NN <= 10
00602    // {
00603    //    TImage *img = 0;
00604    //    gSystem->Unlink("anim.gif");  // delete existing file
00605    //
00606    //    for (int i = 1; i <= 10; i++) {
00607    //       delete img; // delete previous image
00608    //
00609    //       // Read image data. Image can be in any format, e.g. png, gif, etc.
00610    //       img = TImage::Open(Form("image%d.jpg", i));
00611    //
00612    //       if (i < 10) {
00613    //          img->WriteImage("anim.gif+");
00614    //       } else { // the last image written.  "++" stands for infinit animation.
00615    //          img->WriteImage("anim.gif++");
00616    //       }
00617    //    }
00618    // }
00619 
00620    if (!IsValid()) {
00621       Error("WriteImage", "no image loaded");
00622       return;
00623    }
00624 
00625    if (!file || !*file) {
00626       Error("WriteImage", "no file name specified");
00627       return;
00628    }
00629 
00630    const char *s;
00631    if ((s = strrchr(file, '.'))) {
00632       s++;
00633       EImageFileTypes t = GetFileType(s);
00634       if (t == kUnknown) {
00635          Error("WriteImage", "cannot determine a valid file type");
00636          return;
00637       }
00638       if (t != kUnknown)
00639          type = t;
00640    }
00641 
00642    if (type == kUnknown) {
00643       Error("WriteImage", "not a valid file type was specified");
00644       return;
00645    }
00646 
00647    UInt_t mytype;
00648    MapFileTypes(type, mytype);
00649    ASImageFileTypes atype = (ASImageFileTypes)mytype;
00650 
00651    UInt_t aquality;
00652    EImageQuality quality = GetImageQuality();
00653    MapQuality(quality, aquality);
00654 
00655    static TString fname;
00656    fname = file;
00657    static ASImageExportParams parms;
00658    ASImage *im = fScaledImage ? fScaledImage->fImage : fImage;
00659 
00660    switch (type) {
00661    case kXpm:
00662       parms.xpm.type = atype;
00663       parms.xpm.flags = EXPORT_ALPHA;
00664       parms.xpm.dither = 4;
00665       parms.xpm.opaque_threshold = 127;
00666       parms.xpm.max_colors = 512;
00667       break;
00668    case kBmp:
00669       ASImage2bmp(im, fname.Data(), 0);
00670       return;
00671    case kXcf:
00672       ASImage2xcf(im, fname.Data(), 0);
00673       return;
00674    case kPng:
00675       parms.png.type = atype;
00676       parms.png.flags = EXPORT_ALPHA;
00677       parms.png.compression = !GetImageCompression() ? -1 : int(GetImageCompression());
00678       break;
00679    case kJpeg:
00680       parms.jpeg.type = atype;
00681       parms.jpeg.flags = 0;
00682       parms.jpeg.quality = aquality;
00683       break;
00684    case kGif:
00685       parms.gif.type = atype;
00686       parms.gif.flags = EXPORT_ALPHA;
00687       parms.gif.dither = 0;
00688       parms.gif.opaque_threshold = 0;
00689       break;
00690    case kAnimGif:
00691    {
00692       parms.gif.type = atype;
00693       parms.gif.flags = EXPORT_ALPHA | EXPORT_APPEND;
00694       parms.gif.dither = 0;
00695       parms.gif.opaque_threshold = 0;
00696       parms.gif.animate_repeats = 0;
00697 
00698       s += 4; // skip "gif+"
00699       int delay = atoi(s);
00700 
00701       if (delay < 0) {
00702          delay = 0;
00703       }
00704       if (s[0] == '+') { // repeat count
00705          parms.gif.flags |= EXPORT_ANIMATION_REPEATS;
00706          s++;
00707          parms.gif.animate_repeats = atoi(s);
00708       }
00709 
00710       parms.gif.animate_delay = delay;
00711 
00712       int i1 = fname.Index("gif+");
00713       if (i1 != kNPOS) {
00714          fname = fname(0, i1 + 3);
00715       }
00716       break;
00717    }
00718    case kTiff:
00719       parms.tiff.type = atype;
00720       parms.tiff.flags = EXPORT_ALPHA;
00721       parms.tiff.rows_per_strip = 0;
00722       parms.tiff.compression_type = aquality <= 50 ? TIFF_COMPRESSION_JPEG :
00723                                                      TIFF_COMPRESSION_NONE;
00724       parms.tiff.jpeg_quality = 100;
00725       parms.tiff.opaque_threshold = 0;
00726       break;
00727    default:
00728       Error("WriteImage", "file type %s not yet supported", s);
00729       return;
00730    }
00731 
00732    if (!ASImage2file(im, 0, fname.Data(), atype, &parms)) {
00733       Error("WriteImage", "error writing file %s", file);
00734    }
00735 }
00736 
00737 
00738 //______________________________________________________________________________
00739 TImage::EImageFileTypes TASImage::GetFileType(const char *ext)
00740 {
00741    // Return file type depending on specified extension.
00742    // Protected method.
00743 
00744    TString s(ext);
00745    s.Strip();
00746    s.ToLower();
00747 
00748    if (s == "xpm")
00749       return kXpm;
00750    if (s == "png")
00751       return kPng;
00752    if (s == "jpg" || s == "jpeg")
00753       return kJpeg;
00754    if (s == "xcf")
00755       return kXcf;
00756    if (s == "ppm")
00757       return kPpm;
00758    if (s == "pnm")
00759       return kPnm;
00760    if (s == "bmp")
00761       return kBmp;
00762    if (s == "ico")
00763       return kIco;
00764    if (s == "cur")
00765       return kCur;
00766    if (s == "gif")
00767       return kGif;
00768    if (s.Contains("gif+"))
00769       return kAnimGif;
00770    if (s == "tiff")
00771       return kTiff;
00772    if (s == "xbm")
00773       return kXbm;
00774    if (s == "tga")
00775       return kTga;
00776    if (s == "xml")
00777       return kXml;
00778 
00779    return kUnknown;
00780 }
00781 
00782 
00783 //______________________________________________________________________________
00784 void TASImage::MapFileTypes(EImageFileTypes &type, UInt_t &astype, Bool_t toas)
00785 {
00786    // Map file type to/from AfterImage types.
00787    // Protected method.
00788 
00789    if (toas) {
00790       switch (type) {
00791          case kXpm:
00792             astype = ASIT_Xpm; break;
00793          case kZCompressedXpm:
00794             astype = ASIT_ZCompressedXpm; break;
00795          case kGZCompressedXpm:
00796             astype = ASIT_GZCompressedXpm; break;
00797          case kPng:
00798             astype = ASIT_Png; break;
00799          case kJpeg:
00800             astype = ASIT_Jpeg; break;
00801          case kXcf:
00802             astype = ASIT_Xcf; break;
00803          case kPpm:
00804             astype = ASIT_Ppm; break;
00805          case kPnm:
00806             astype = ASIT_Pnm; break;
00807          case kBmp:
00808             astype = ASIT_Bmp; break;
00809          case kIco:
00810             astype = ASIT_Ico; break;
00811          case kCur:
00812             astype = ASIT_Cur; break;
00813          case kGif:
00814             astype = ASIT_Gif; break;
00815          case kAnimGif:
00816             astype = ASIT_Gif; break;
00817          case kTiff:
00818             astype = ASIT_Tiff; break;
00819          case kXbm:
00820             astype = ASIT_Xbm; break;
00821          case kTga:
00822             astype = ASIT_Targa; break;
00823          case kXml:
00824             astype = ASIT_XMLScript; break;
00825          default:
00826             astype = ASIT_Unknown;
00827       }
00828    } else {
00829       switch (astype) {
00830          case ASIT_Xpm:
00831             type = kXpm; break;
00832          case ASIT_ZCompressedXpm:
00833             type = kZCompressedXpm; break;
00834          case ASIT_GZCompressedXpm:
00835             type = kGZCompressedXpm; break;
00836          case ASIT_Png:
00837             type = kPng; break;
00838          case ASIT_Jpeg:
00839             type = kJpeg; break;
00840          case ASIT_Xcf:
00841             type = kXcf; break;
00842          case ASIT_Ppm:
00843             type = kPpm; break;
00844          case ASIT_Pnm:
00845             type = kPnm; break;
00846          case ASIT_Bmp:
00847             type = kBmp; break;
00848          case ASIT_Ico:
00849             type = kIco; break;
00850          case ASIT_Cur:
00851             type = kCur; break;
00852          case ASIT_Gif:
00853             type = kGif; break;
00854          case ASIT_Tiff:
00855             type = kTiff; break;
00856          case ASIT_Xbm:
00857             type = kXbm; break;
00858          case ASIT_XMLScript:
00859             type = kXml; break;
00860          case ASIT_Targa:
00861             type = kTga; break;
00862          default:
00863             type = kUnknown;
00864       }
00865    }
00866 }
00867 
00868 
00869 //______________________________________________________________________________
00870 void TASImage::MapQuality(EImageQuality &quality, UInt_t &asquality, Bool_t toas)
00871 {
00872    // Map quality to/from AfterImage quality.
00873    // Protected method.
00874 
00875    if (toas) {
00876       switch (quality) {
00877          case kImgPoor:
00878             asquality = 25; break;
00879          case kImgFast:
00880             asquality = 75; break;
00881          case kImgGood:
00882             asquality = 50; break;
00883          case kImgBest:
00884             asquality = 100; break;
00885          default:
00886             asquality = 0;
00887       }
00888    } else {
00889       quality = kImgDefault;
00890       if (asquality > 0  && asquality <= 25)
00891          quality = kImgPoor;
00892       if (asquality > 26 && asquality <= 50)
00893          quality = kImgFast;
00894       if (asquality > 51 && asquality <= 75)
00895          quality = kImgGood;
00896       if (asquality > 76 && asquality <= 100)
00897          quality = kImgBest;
00898    }
00899 }
00900 
00901 
00902 //______________________________________________________________________________
00903 void TASImage::SetImage(const Double_t *imageData, UInt_t width, UInt_t height,
00904                         TImagePalette *palette)
00905 {
00906    // Deletes the old image and creates a new image depending on the values
00907    // of imageData. The size of the image is width X height.
00908    // The color of each pixel depends on the imageData of the corresponding
00909    // pixel. The palette is used to convert an image value into its color.
00910    // If palette is not defined (palette = 0) a default palette is used.
00911    // Any previously defined zooming is reset.
00912 
00913    TAttImage::SetPalette(palette);
00914 
00915    if (!InitVisual()) {
00916       Warning("SetImage", "Visual not initiated");
00917       return;
00918    }
00919 
00920    DestroyImage();
00921    delete fScaledImage;
00922    fScaledImage = 0;
00923 
00924    // get min and max value of image
00925    fMinValue = fMaxValue = *imageData;
00926    for (Int_t pixel = 1; pixel < Int_t(width * height); pixel++) {
00927       if (fMinValue > *(imageData + pixel)) fMinValue = *(imageData + pixel);
00928       if (fMaxValue < *(imageData + pixel)) fMaxValue = *(imageData + pixel);
00929    }
00930 
00931    // copy ROOT palette to asImage palette
00932    const TImagePalette &pal = GetPalette();
00933 
00934    ASVectorPalette asPalette;
00935 
00936    asPalette.npoints = pal.fNumPoints;
00937    Int_t col;
00938    for (col = 0; col < 4; col++)
00939       asPalette.channels[col] = new UShort_t[asPalette.npoints];
00940 
00941    memcpy(asPalette.channels[0], pal.fColorBlue,  pal.fNumPoints * sizeof(UShort_t));
00942    memcpy(asPalette.channels[1], pal.fColorGreen, pal.fNumPoints * sizeof(UShort_t));
00943    memcpy(asPalette.channels[2], pal.fColorRed,   pal.fNumPoints * sizeof(UShort_t));
00944    memcpy(asPalette.channels[3], pal.fColorAlpha, pal.fNumPoints * sizeof(UShort_t));
00945 
00946    asPalette.points = new Double_t[asPalette.npoints];
00947    for (Int_t point = 0; point < Int_t(asPalette.npoints); point++)
00948       asPalette.points[point] = fMinValue + (fMaxValue - fMinValue) * pal.fPoints[point];
00949 
00950    fImage = create_asimage_from_vector(fgVisual, (Double_t*)imageData, width,
00951                                        height, &asPalette, ASA_ASImage,
00952                                        GetImageCompression(), GetImageQuality());
00953 
00954    delete [] asPalette.points;
00955    for (col = 0; col < 4; col++)
00956       delete [] asPalette.channels[col];
00957 
00958    fZoomUpdate = 0;
00959    fZoomOffX   = 0;
00960    fZoomOffY   = 0;
00961    fZoomWidth  = width;
00962    fZoomHeight = height;
00963    fPaletteEnabled = kTRUE;
00964 }
00965 
00966 
00967 //______________________________________________________________________________
00968 void TASImage::SetImage(const TArrayD &imageData, UInt_t width, TImagePalette *palette)
00969 {
00970    // Delete the old image and creates a new image depending on the values
00971    // of imageData. The size of the image is width X (imageData.fN / width).
00972    // The color of each pixel depends on the imageData of the corresponding
00973    // pixel. The palette is used to convert an image value into its color.
00974    // If palette is not defined (palette = 0) a default palette is used.
00975    // Any previously defined zooming is reset.
00976 
00977    SetImage(imageData.GetArray(), width, imageData.GetSize() / width, palette);
00978 }
00979 
00980 
00981 //______________________________________________________________________________
00982 void TASImage::SetImage(const TVectorD &imageData, UInt_t width, TImagePalette *palette)
00983 {
00984    // Delete the old image and creates a new image depending on the values
00985    // of imageData. The size of the image is width X (imageData.fN / width).
00986    // The color of each pixel depends on the imageData of the corresponding
00987    // pixel. The palette is used to convert an image value into its color.
00988    // If palette is not defined (palette = 0) a default palette is used.
00989    // Any previously defined zooming is reset.
00990 
00991    SetImage(imageData.GetMatrixArray(), width,
00992             imageData.GetNoElements() / width, palette);
00993 }
00994 
00995 
00996 //______________________________________________________________________________
00997 void TASImage::FromPad(TVirtualPad *pad, Int_t x, Int_t y, UInt_t w, UInt_t h)
00998 {
00999    // Create an image from the given pad, afterwards this image can be
01000    // saved in any of the supported image formats.
01001 
01002    if (!pad) {
01003       Error("FromPad", "pad cannot be 0");
01004       return;
01005    }
01006 
01007    if (!InitVisual()) {
01008       Warning("FromPad", "Visual not initiated");
01009       return;
01010    }
01011 
01012    SetName(pad->GetName());
01013 
01014    DestroyImage();
01015    delete fScaledImage;
01016    fScaledImage = 0;
01017 
01018    if (gROOT->IsBatch()) { // in batch mode
01019       TVirtualPS *psave = gVirtualPS;
01020       gVirtualPS = (TVirtualPS*)gROOT->ProcessLineFast("new TImageDump()");
01021       gVirtualPS->Open(pad->GetName(), 114); // in memory
01022       gVirtualPS->SetBit(BIT(11)); //kPrintingPS
01023 
01024       TASImage *itmp = (TASImage*)gVirtualPS->GetStream();
01025 
01026       if (itmp && itmp->fImage) {
01027          itmp->BeginPaint();
01028       }
01029 
01030       TVirtualPad *sav = gPad;
01031       gPad = pad;
01032       pad->Paint();
01033       gPad = sav;
01034 
01035       if (itmp && itmp->fImage && (itmp != this)) {
01036          fImage = clone_asimage(itmp->fImage, SCL_DO_ALL);
01037          if (itmp->fImage->alt.argb32) {
01038             UInt_t sz = itmp->fImage->width*itmp->fImage->height;
01039             fImage->alt.argb32 = (ARGB32*)safemalloc(sz*sizeof(ARGB32));
01040             memcpy(fImage->alt.argb32, itmp->fImage->alt.argb32, sz*4);
01041          }
01042       }
01043       delete gVirtualPS;
01044       gVirtualPS = psave;
01045       return;
01046    }
01047 
01048    if (w == 0) {
01049       w = TMath::Abs(pad->UtoPixel(1.));
01050    }
01051 
01052    if (h == 0) {
01053       h = pad->VtoPixel(0.);
01054    }
01055    // syncronization
01056    gVirtualX->Update(1);
01057    if (!gThreadXAR) {
01058       gSystem->ProcessEvents();
01059       gSystem->Sleep(10);
01060       gSystem->ProcessEvents();
01061    }
01062 
01063    TVirtualPad *canvas = (TVirtualPad*)pad->GetCanvas();
01064    Int_t wid = (pad == canvas) ? pad->GetCanvasID() : pad->GetPixmapID();
01065    gVirtualX->SelectWindow(wid);
01066 
01067    Window_t wd = (Window_t)gVirtualX->GetCurrentWindow();
01068    if (!wd) return;
01069 
01070    static int x11 = -1;
01071    if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11");
01072 
01073    if (x11) { //use built-in optimized version
01074       fImage = pixmap2asimage(fgVisual, wd, x, y, w, h, kAllPlanes, 0, 0);
01075    } else {
01076       unsigned char *bits = gVirtualX->GetColorBits(wd, 0, 0, w, h);
01077 
01078       if (!bits) { // error
01079          return;
01080       }
01081       fImage = bitmap2asimage(bits, w, h, 0, 0);
01082       delete [] bits;
01083    }
01084 }
01085 
01086 
01087 //______________________________________________________________________________
01088 void TASImage::Draw(Option_t *option)
01089 {
01090    // Draw image.
01091    // Support the following drawing options:
01092    // "T[x,y[,tint]]" - tile image (use specified offset and tint),
01093    //                   e.g. "T100,100,#556655"
01094    //                   with this option the zooming is not possible
01095    //                   and disabled
01096    // "N"             - display in new canvas (of original image size)
01097    // "X"             - image is drawn expanded to pad size
01098    // "Z"             - image is vectorized and image palette is drawn
01099    //
01100    // The default is to display the image in the current gPad.
01101 
01102    if (!fImage) {
01103       Error("Draw", "no image set");
01104       return;
01105    }
01106 
01107    TString opt = option;
01108    opt.ToLower();
01109    if (opt.Contains("n") || !gPad || !gPad->IsEditable()) {
01110       Int_t w = -64;
01111       Int_t h = 64;
01112       w = (fImage->width > 64) ? (Int_t)fImage->width : w;
01113       h = (fImage->height > 64) ? (Int_t)fImage->height : h;
01114 
01115       Float_t cx = 1./gStyle->GetScreenFactor();
01116       w = Int_t(w*cx) + 4;
01117       h = Int_t(h*cx) + 28;
01118       TString rname = GetName();
01119       rname.ReplaceAll(".", "");
01120       rname += Form("\", \"%s (%d x %d)", rname.Data(), fImage->width, fImage->height);
01121       rname = "new TCanvas(\"" + rname + Form("\", %d, %d);", w, h);
01122       gROOT->ProcessLineFast(rname.Data());
01123    }
01124 
01125    if (!opt.Contains("x")) {
01126       Double_t left = gPad->GetLeftMargin();
01127       Double_t right = gPad->GetRightMargin();
01128       Double_t top = gPad->GetTopMargin();
01129       Double_t bottom = gPad->GetBottomMargin();
01130 
01131       gPad->Range(-left / (1.0 - left - right),
01132                   -bottom / (1.0 - top - bottom),
01133                   1 + right / (1.0 - left - right),
01134                   1 + top / ( 1.0 - top - bottom));
01135       gPad->RangeAxis(0, 0, 1, 1);
01136    }
01137 
01138    TFrame *frame = gPad->GetFrame();
01139    frame->SetBorderMode(0);
01140    frame->SetFillColor(gPad->GetFillColor());
01141    frame->SetLineColor(gPad->GetFillColor());
01142    frame->Draw();
01143 
01144    TObject::Draw(option);
01145 }
01146 
01147 
01148 //______________________________________________________________________________
01149 void TASImage::Image2Drawable(ASImage *im, Drawable_t wid, Int_t x, Int_t y,
01150                               Int_t xsrc, Int_t ysrc, UInt_t wsrc, UInt_t hsrc,
01151                               Option_t *opt)
01152 {
01153    // Draw asimage on drawable.
01154 
01155    if (!im) return;
01156 
01157    wsrc = wsrc ? wsrc : im->width;
01158    hsrc = hsrc ? hsrc : im->height;
01159 
01160    static int x11 = -1;
01161    if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11");
01162 
01163    Pixmap_t mask = kNone;
01164 
01165    if (x11) {
01166       UInt_t hh = hsrc;
01167       UInt_t ow = wsrc%8;
01168       UInt_t ww = wsrc - ow + (ow ? 8 : 0);
01169 
01170       UInt_t bit = 0;
01171       int i = 0;
01172       UInt_t yy = 0;
01173       UInt_t xx = 0;
01174 
01175       char *bits = new char[ww*hh]; //an array of bits
01176 
01177       ASImageDecoder *imdec = start_image_decoding(fgVisual, im, SCL_DO_ALPHA,
01178                                                    xsrc, ysrc, ww, 0, 0);
01179       if (imdec) {
01180          for (yy = 0; yy < hh; yy++) {
01181             imdec->decode_image_scanline(imdec);
01182             CARD32 *a = imdec->buffer.alpha;
01183 
01184             for (xx = 0; xx < ww; xx++) {
01185                if (a[xx]) {
01186                   SETBIT(bits[i], bit);
01187                } else {
01188                   CLRBIT(bits[i], bit);
01189                }
01190                bit++;
01191                if (bit == 8) {
01192                   bit = 0;
01193                   i++;
01194                }
01195             }
01196          }
01197       }
01198 
01199       stop_image_decoding(&imdec);
01200 
01201       mask = gVirtualX->CreateBitmap(gVirtualX->GetDefaultRootWindow(),
01202                                           (const char *)bits, ww, hh);
01203       delete [] bits;
01204    }
01205 
01206    GCValues_t gv;
01207    static GContext_t gc = 0;
01208 
01209    gv.fMask = kGCClipMask | kGCClipXOrigin | kGCClipYOrigin;
01210    gv.fClipMask = mask;
01211    gv.fClipXOrigin = x;
01212    gv.fClipYOrigin = y;
01213 
01214    if (!gc) {
01215       gc = gVirtualX->CreateGC(gVirtualX->GetDefaultRootWindow(), &gv);
01216    } else {
01217       gVirtualX->ChangeGC(gc, &gv);
01218    }
01219 
01220    if (x11) { //use built-in optimized version
01221       asimage2drawable(fgVisual, wid, im, (GC)gc, xsrc, ysrc, x, y, wsrc, hsrc, 1);
01222    } else {
01223       ASImage *img = 0;
01224       unsigned char *bits = (unsigned char *)im->alt.argb32;
01225       if (!bits) {
01226          img = tile_asimage(fgVisual, im, xsrc, ysrc, wsrc, hsrc,
01227                             0, ASA_ARGB32, 0, ASIMAGE_QUALITY_DEFAULT);
01228          bits = (unsigned char *)img->alt.argb32;
01229       }
01230 
01231       Pixmap_t pic = gVirtualX->CreatePixmapFromData(bits, wsrc, hsrc);
01232       if (pic) {
01233          TString option = opt;
01234          option.ToLower();
01235          if (!option.Contains("opaque")) {
01236             SETBIT(wsrc,31);
01237             SETBIT(hsrc,31);
01238          }
01239          gVirtualX->CopyArea(pic, wid, gc, 0, 0, wsrc, hsrc, x, y);
01240          gVirtualX->DeletePixmap(pic);
01241       } else {
01242          return;
01243       }
01244       if (img) {
01245          destroy_asimage(&img);
01246       }
01247    }
01248 
01249    // free mask pixmap
01250    if (gv.fClipMask != kNone) gVirtualX->DeletePixmap(gv.fClipMask);
01251 
01252    gv.fMask = kGCClipMask;
01253    gv.fClipMask = kNone;
01254    if (gc) gVirtualX->ChangeGC(gc, &gv);
01255 }
01256 
01257 
01258 //______________________________________________________________________________
01259 void TASImage::PaintImage(Drawable_t wid, Int_t x, Int_t y, Int_t xsrc, Int_t ysrc,
01260                           UInt_t wsrc, UInt_t hsrc, Option_t *opt)
01261 {
01262    // Draw image on the drawable wid (pixmap, window) at x,y position.
01263    //
01264    // wid        : Drawable (pixmap or window) on which image is drawn.
01265    // x,y        : Window coordinates where image is drawn.
01266    // xsrc, ysrc : X and Y coordinates of an image area to be drawn.
01267    // wsrc, hsrc : Widh and height image area to be drawn.
01268 
01269    Image2Drawable(fScaledImage ? fScaledImage->fImage : fImage, wid, x, y,
01270                   xsrc, ysrc, wsrc, hsrc, opt);
01271 }
01272 
01273 
01274 //______________________________________________________________________________
01275 void TASImage::Paint(Option_t *option)
01276 {
01277    // Paint image.
01278    // Support the following drawing options:
01279    // "T[x,y[,tint]]" - tile image (use specified offset and tint),
01280    //                   e.g. "T100,100,#556655"
01281    //                   with this option the zooming is not possible
01282    //                   and disabled
01283    // "N"             - display in new canvas (of original image size)
01284    // "X"             - image is drawn expanded to pad size
01285    // "Z"             - image is vectorized and image palette is drawn
01286    //
01287    // The default is to display the image in the current gPad.
01288 
01289    if (!fImage) {
01290       Error("Paint", "no image set");
01291       return;
01292    }
01293 
01294    if (!InitVisual()) {
01295       Warning("Paint", "Visual not initiated");
01296       return;
01297    }
01298 
01299    Int_t   tile_x = 0, tile_y = 0;
01300    CARD32  tile_tint = 0;
01301    Bool_t  tile = kFALSE;
01302    Bool_t  expand = kFALSE;
01303 
01304    TString opt = option;
01305    opt.ToLower();
01306 
01307    if (opt.Contains("t")) {
01308       char stint[64];
01309       if (sscanf(opt.Data() + opt.Index("t"), "t%d,%d,%s", &tile_x, &tile_y,
01310                  stint) <= 3) {
01311          tile = kTRUE;
01312          if (parse_argb_color(stint, (CARD32*)&tile_tint) == stint)
01313             tile_tint = 0;
01314       } else {
01315          Error("Paint", "tile option error");
01316       }
01317    } else if (opt.Contains("x")) {
01318       expand = kTRUE;
01319       fConstRatio = kFALSE;
01320    } else if (opt.Contains("z")) {
01321       fPaletteEnabled = kTRUE;
01322 
01323       if (!fImage->alt.vector) {
01324          Vectorize(256);
01325       }
01326    }
01327 
01328    ASImage *image = fImage;
01329 
01330    // Get geometry of pad
01331    Int_t to_w = gPad->UtoPixel(1.);
01332    Int_t to_h = gPad->VtoPixel(0.);
01333 
01334    // remove the size by the margin of the pad
01335    if (!expand) {
01336       to_h  = (Int_t)(to_h * (1.0 - gPad->GetBottomMargin() - gPad->GetTopMargin() ) + 0.5);
01337       to_w  = (Int_t)(to_w * (1.0 - gPad->GetLeftMargin() - gPad->GetRightMargin() ) + 0.5);
01338    }
01339 
01340    if ((to_w < 25 || to_h < 25) && !expand) {
01341       Error("Paint", "pad too small to display an image");
01342       return;
01343    }
01344 
01345    if (GetConstRatio()) {
01346       if ((Double_t)to_w / (Double_t)fZoomWidth <
01347           (Double_t)to_h / (Double_t)fZoomHeight)
01348          to_h = Int_t(Double_t(fZoomHeight) * to_w / fZoomWidth);
01349       else
01350          to_w = Int_t(Double_t(fZoomWidth) * to_h / fZoomHeight);
01351    }
01352    // upper left corner and size of the palette in pixels
01353    Int_t pal_Ax = to_w + gPad->UtoAbsPixel(gPad->GetLeftMargin()) +
01354                  (gPad->UtoAbsPixel(gPad->GetRightMargin()) / 10);
01355    Int_t pal_Ay = gPad->YtoAbsPixel(1.0);
01356    Int_t pal_x = to_w + gPad->UtoPixel(gPad->GetLeftMargin()) +
01357                  (gPad->UtoPixel(gPad->GetRightMargin()) / 10);
01358    Int_t pal_y = gPad->YtoPixel(1.0);
01359    Int_t pal_w = gPad->UtoPixel(gPad->GetRightMargin()) / 3;
01360    Int_t pal_h = to_h;
01361 
01362    ASImage  *grad_im = 0;
01363 
01364    if (fImage->alt.vector && fPaletteEnabled) {
01365       // draw the palette
01366       ASGradient grad;
01367       const TImagePalette &pal = GetPalette();
01368 
01369       grad.npoints = pal.fNumPoints;
01370       grad.type    = GRADIENT_Top2Bottom;
01371       grad.color   = new ARGB32[grad.npoints];
01372       grad.offset  = new double[grad.npoints];
01373 
01374       for (Int_t pt = 0; pt < grad.npoints; pt++) {
01375          Int_t oldPt = grad.npoints - pt -1;
01376          grad.offset[pt] = 1 - pal.fPoints[oldPt];
01377          grad.color[pt] = (((ARGB32)(pal.fColorBlue[oldPt]  & 0xff00)) >>  8) |
01378                           (((ARGB32)(pal.fColorGreen[oldPt] & 0xff00))      ) |
01379                           (((ARGB32)(pal.fColorRed[oldPt]   & 0xff00)) <<  8) |
01380                           (((ARGB32)(pal.fColorAlpha[oldPt] & 0xff00)) << 16);
01381       }
01382 
01383       grad_im = make_gradient(fgVisual, &grad , UInt_t(pal_w),
01384                               pal_h, SCL_DO_COLOR,
01385                               ASA_ARGB32, GetImageCompression(), GetImageQuality());
01386 
01387       delete [] grad.color;
01388       delete [] grad.offset;
01389    }
01390 
01391    if (tile) {
01392       delete fScaledImage;
01393       fScaledImage = (TASImage*)TImage::Create();
01394       fScaledImage->fImage = tile_asimage(fgVisual, fImage, tile_x, tile_y,
01395                                           to_w, to_h, tile_tint, ASA_ASImage,
01396                                           GetImageCompression(), GetImageQuality());
01397       image = fScaledImage->fImage;
01398 
01399    } else if (fZoomUpdate == kZoomOps) {
01400       image = fImage;
01401 
01402    } else {
01403       // Scale and zoom image if needed
01404       if (Int_t(fImage->width) != to_w || Int_t(fImage->height) != to_h ||
01405           fImage->width != fZoomWidth || fImage->height != fZoomHeight) {
01406 
01407          if (fScaledImage && (Int_t(fScaledImage->GetWidth()) != to_w ||
01408                 Int_t(fScaledImage->GetHeight()) != to_h ||
01409                 fZoomUpdate)) {
01410 
01411             delete fScaledImage;
01412             fScaledImage = 0;
01413          }
01414 
01415          if (!fScaledImage) {
01416             fScaledImage = (TASImage*)TImage::Create();
01417 
01418             if (fZoomWidth && fZoomHeight &&
01419                 ((fImage->width != fZoomWidth) || (fImage->height != fZoomHeight))) {
01420                // zoom and scale image
01421                ASImage *tmpImage = 0;
01422 
01423                tmpImage = tile_asimage(fgVisual, fImage, fZoomOffX,
01424                                           fImage->height - fZoomHeight - fZoomOffY,
01425                                           fZoomWidth, fZoomHeight, 0, ASA_ASImage,
01426                                           GetImageCompression(), GetImageQuality());
01427 
01428                if (tmpImage) {
01429                   fScaledImage->fImage = scale_asimage(fgVisual, tmpImage, to_w, to_h,
01430                                                        ASA_ASImage, GetImageCompression(),
01431                                                       GetImageQuality());
01432                   destroy_asimage(&tmpImage);
01433                }
01434             } else {
01435                // scale image, no zooming
01436                fScaledImage->fImage = scale_asimage(fgVisual, fImage, to_w, to_h,
01437                                                     ASA_ASImage, GetImageCompression(),
01438                                                     GetImageQuality());
01439             }
01440          }
01441          image = fScaledImage->fImage;
01442       }
01443    }
01444    fZoomUpdate = 0;
01445 
01446    if (!image) {
01447       Error("Paint", "image could not be rendered to display");
01448       return;
01449    }
01450 
01451    int tox = expand  ? 0 : int(gPad->UtoPixel(1.) * gPad->GetLeftMargin());
01452    int toy = expand  ? 0 : int(gPad->VtoPixel(0.) * gPad->GetTopMargin());
01453 
01454    if (!gROOT->IsBatch()) {
01455       Window_t wid = (Window_t)gVirtualX->GetWindowID(gPad->GetPixmapID());
01456       Image2Drawable(fScaledImage ? fScaledImage->fImage : fImage, wid, tox, toy);
01457 
01458       if (grad_im && fPaletteEnabled) {
01459          // draw color bar
01460          Image2Drawable(grad_im, wid, pal_x, pal_y);
01461 
01462          // values of palette
01463          TGaxis axis;
01464          Int_t ndiv = 510;
01465          double min = fMinValue;
01466          double max = fMaxValue;
01467          axis.SetLineColor(0);       // draw white ticks
01468          Double_t pal_Xpos = gPad->AbsPixeltoX(pal_Ax + pal_w);
01469          axis.PaintAxis(pal_Xpos, gPad->PixeltoY(pal_Ay + pal_h - 1),
01470                         pal_Xpos, gPad->PixeltoY(pal_Ay),
01471                         min, max, ndiv, "+LU");
01472          min = fMinValue;
01473          max = fMaxValue;
01474          axis.SetLineColor(1);       // draw black ticks
01475          axis.PaintAxis(pal_Xpos, gPad->AbsPixeltoY(pal_Ay + pal_h),
01476                         pal_Xpos, gPad->AbsPixeltoY(pal_Ay + 1),
01477                         min, max, ndiv, "+L");
01478       }
01479    }
01480 
01481    // loop over pxmap and draw image to PostScript
01482    if (gVirtualPS) {
01483       if (gVirtualPS->InheritsFrom("TImageDump")) { // PostScript is asimage
01484          TImage *dump = (TImage *)gVirtualPS->GetStream();
01485          dump->Merge(fScaledImage ? fScaledImage : this, "alphablend",
01486                      gPad->XtoAbsPixel(0), gPad->YtoAbsPixel(1));
01487 
01488          if (grad_im) {
01489             TASImage tgrad;
01490             tgrad.fImage = grad_im;
01491             dump->Merge(&tgrad, "alphablend", pal_Ax, pal_Ay);
01492 
01493             // values of palette
01494             TGaxis axis;
01495             Int_t ndiv = 510;
01496             double min = fMinValue;
01497             double max = fMaxValue;
01498             axis.SetLineColor(1);       // draw black ticks
01499             Double_t pal_Xpos = gPad->AbsPixeltoX(pal_Ax + pal_w);
01500             axis.PaintAxis(pal_Xpos, gPad->AbsPixeltoY(pal_Ay + pal_h),
01501                            pal_Xpos, gPad->AbsPixeltoY(pal_Ay + 1),
01502                            min, max, ndiv, "+L");
01503          }
01504          return;
01505       } else if (gVirtualPS->InheritsFrom("TPDF")) {
01506          Warning("Paint", "PDF not implemeted yet");
01507          return;
01508       } else if (gVirtualPS->InheritsFrom("TSVG")) {
01509          Warning("Paint", "SVG not implemeted yet");
01510          return;
01511       }
01512 
01513       // get special color cell to be reused during image printing
01514       TObjArray *colors = (TObjArray*) gROOT->GetListOfColors();
01515       TColor *color = 0;
01516       // Look for color by name
01517       if ((color = (TColor*)colors->FindObject("Image_PS")) == 0)
01518          color = new TColor(colors->GetEntries(), 1., 1., 1., "Image_PS");
01519 
01520       gVirtualPS->SetFillColor(color->GetNumber());
01521       gVirtualPS->SetFillStyle(1001);
01522 
01523       Double_t dx = gPad->GetX2()-gPad->GetX1();
01524       Double_t dy = gPad->GetY2()-gPad->GetY1();
01525       Double_t x1,x2,y1,y2;
01526 
01527       if (expand) {
01528          x1 = gPad->GetX1();
01529          x2 = x1+dx/image->width;
01530          y1 = gPad->GetY2();
01531          y2 = y1+dy/image->height;
01532       } else {
01533          x1 = gPad->GetX1()+dx*gPad->GetLeftMargin();
01534          x2 = x1+(dx*(1-gPad->GetRightMargin()-gPad->GetLeftMargin()))/image->width;
01535          y1 = gPad->GetY2()-dy*gPad->GetTopMargin();
01536          y2 = y1+(dy*(1-gPad->GetTopMargin()-gPad->GetBottomMargin()))/image->height;
01537       }
01538 
01539       gVirtualPS->CellArrayBegin(image->width, image->height, x1, x2, y1, y2);
01540 
01541       ASImageDecoder *imdec = start_image_decoding(fgVisual, image, SCL_DO_ALL,
01542                                                    0, 0, image->width, image->height, 0);
01543       for (Int_t yt = 0; yt < (Int_t)image->height; yt++) {
01544          imdec->decode_image_scanline(imdec);
01545          for (Int_t xt = 0; xt < (Int_t)image->width; xt++)
01546             gVirtualPS->CellArrayFill(imdec->buffer.red[xt],
01547                                       imdec->buffer.green[xt],
01548                                       imdec->buffer.blue[xt]);
01549       }
01550       stop_image_decoding(&imdec);
01551       gVirtualPS->CellArrayEnd();
01552 
01553       // print the color bar
01554       if (grad_im) {
01555          Double_t xconv = (gPad->AbsPixeltoX(pal_Ax + pal_w) - gPad->AbsPixeltoX(pal_Ax)) / grad_im->width;
01556          Double_t yconv = (gPad->AbsPixeltoY(pal_Ay - pal_h) - gPad->AbsPixeltoY(pal_Ay)) / grad_im->height;
01557          x1 = gPad->AbsPixeltoX(pal_Ax);
01558          x2 = x1 + xconv;
01559          y2 = gPad->AbsPixeltoY(pal_Ay);
01560          y1 = y2 - yconv;
01561          gVirtualPS->CellArrayBegin(grad_im->width, grad_im->height,
01562                                     x1, x2, y1, y2);
01563 
01564          imdec = start_image_decoding(fgVisual, grad_im, SCL_DO_ALL,
01565                                       0, 0, grad_im->width, grad_im->height, 0);
01566          for (Int_t yt = 0; yt < (Int_t)grad_im->height; yt++) {
01567             imdec->decode_image_scanline(imdec);
01568             for (Int_t xt = 0; xt < (Int_t)grad_im->width; xt++)
01569                gVirtualPS->CellArrayFill(imdec->buffer.red[xt],
01570                                          imdec->buffer.green[xt],
01571                                          imdec->buffer.blue[xt]);
01572          }
01573          stop_image_decoding(&imdec);
01574          gVirtualPS->CellArrayEnd();
01575 
01576          // values of palette
01577          TGaxis axis;
01578          Int_t ndiv = 510;
01579          double min = fMinValue;
01580          double max = fMaxValue;
01581          axis.SetLineColor(1);       // draw black ticks
01582          Double_t pal_Xpos = gPad->AbsPixeltoX(pal_Ax + pal_w);
01583          axis.PaintAxis(pal_Xpos, gPad->AbsPixeltoY(pal_Ay + pal_h),
01584                         pal_Xpos, gPad->AbsPixeltoY(pal_Ay + 1),
01585                         min, max, ndiv, "+L");
01586 
01587       }
01588    }
01589 
01590    if (grad_im) {
01591       destroy_asimage(&grad_im);
01592    }
01593 }
01594 
01595 
01596 //______________________________________________________________________________
01597 Int_t TASImage::DistancetoPrimitive(Int_t px, Int_t py)
01598 {
01599    // Is the mouse in the image ?
01600 
01601    Int_t pxl, pyl, pxt, pyt;
01602 
01603    Int_t px1 = gPad->XtoAbsPixel(0);
01604    Int_t py1 = gPad->YtoAbsPixel(0);
01605    Int_t px2 = gPad->XtoAbsPixel(1);
01606    Int_t py2 = gPad->YtoAbsPixel(1);
01607 
01608    if (px1 < px2) {pxl = px1; pxt = px2;}
01609    else           {pxl = px2; pxt = px1;}
01610    if (py1 < py2) {pyl = py1; pyt = py2;}
01611    else           {pyl = py2; pyt = py1;}
01612 
01613    if ((px > pxl && px < pxt) && (py > pyl && py < pyt))
01614       return 0;
01615 
01616    return 999999;
01617 }
01618 
01619 
01620 //______________________________________________________________________________
01621 void TASImage::ExecuteEvent(Int_t event, Int_t px, Int_t py)
01622 {
01623    // Execute mouse events.
01624 
01625    if (IsEditable()) {
01626       gPad->ExecuteEvent(event, px, py);
01627       return;
01628    }
01629 
01630    gPad->SetCursor(kCross);
01631 
01632    static Int_t stx, sty;
01633    static Int_t oldx, oldy;
01634 
01635    if (!IsValid()) return;
01636 
01637    if (event == kButton1Motion || event == kButton1Down  ||
01638        event == kButton1Up) {
01639 
01640       // convert to image pixel on screen
01641       Int_t imgX = px - gPad->XtoAbsPixel(0);
01642       Int_t imgY = py - gPad->YtoAbsPixel(1);
01643 
01644       if (imgX < 0)  px = px - imgX;
01645       if (imgY < 0)  py = py - imgY;
01646 
01647       ASImage *image = fImage;
01648       if (fScaledImage) image = fScaledImage->fImage;
01649 
01650       if (imgX >= (int)image->width)  px = px - imgX + image->width - 1;
01651       if (imgY >= (int)image->height) py = py - imgY + image->height - 1;
01652 
01653       switch (event) {
01654 
01655          case kButton1Down:
01656             gVirtualX->SetLineColor(-1);
01657 
01658             stx = oldx = px;
01659             sty = oldy = py;
01660             break;
01661 
01662          case kButton1Motion:
01663             gVirtualX->DrawBox(oldx, oldy, stx, sty, TVirtualX::kHollow);
01664             oldx = px;
01665             oldy = py;
01666             gVirtualX->DrawBox(oldx, oldy, stx, sty, TVirtualX::kHollow);
01667             break;
01668 
01669          case kButton1Up:
01670             // do nothing if zoom area is too small
01671             if ( TMath::Abs(stx - px) < 5 || TMath::Abs(sty - py) < 5)
01672                return;
01673 
01674             Double_t xfact = (fScaledImage) ? (Double_t)fScaledImage->fImage->width  / fZoomWidth  : 1;
01675             Double_t yfact = (fScaledImage) ? (Double_t)fScaledImage->fImage->height / fZoomHeight : 1;
01676 
01677             Int_t imgX1 = stx - gPad->XtoAbsPixel(0);
01678             Int_t imgY1 = sty - gPad->YtoAbsPixel(1);
01679             Int_t imgX2 = px  - gPad->XtoAbsPixel(0);
01680             Int_t imgY2 = py  - gPad->YtoAbsPixel(1);
01681 
01682             imgY1 = image->height - 1 - imgY1;
01683             imgY2 = image->height - 1 - imgY2;
01684             imgX1 = (Int_t)(imgX1 / xfact) + fZoomOffX;
01685             imgY1 = (Int_t)(imgY1 / yfact) + fZoomOffY;
01686             imgX2 = (Int_t)(imgX2 / xfact) + fZoomOffX;
01687             imgY2 = (Int_t)(imgY2 / yfact) + fZoomOffY;
01688 
01689             Zoom((imgX1 < imgX2) ? imgX1 : imgX2, (imgY1 < imgY2) ? imgY1 : imgY2,
01690                  TMath::Abs(imgX1 - imgX2) + 1, TMath::Abs(imgY1 - imgY2) + 1);
01691 
01692             gVirtualX->SetLineColor(-1);
01693             gPad->Modified(kTRUE);
01694             gPad->Update();
01695             break;
01696       }
01697    }
01698 }
01699 
01700 
01701 //______________________________________________________________________________
01702 char *TASImage::GetObjectInfo(Int_t px, Int_t py) const
01703 {
01704    // Get image pixel coordinates and the pixel value at the mouse pointer.
01705 
01706    static char info[64];
01707    info[0] = 0;
01708 
01709    if (!IsValid()) return info;
01710 
01711    // convert to image pixel on screen
01712    px -= gPad->XtoAbsPixel(0);
01713    py -= gPad->YtoAbsPixel(1);
01714 
01715    // no info if mouse is outside of image
01716    if (px < 0 || py < 0)  return info;
01717 
01718    ASImage *image = fImage;
01719    if (fScaledImage) image = fScaledImage->fImage;
01720    if (px >= (int)image->width || py >= (int)image->height)
01721       return info;
01722 
01723    py = image->height - 1 - py;
01724    // convert to original image size and take zooming into account
01725    if (fScaledImage) {
01726       px = (Int_t)(px / (Double_t)fScaledImage->fImage->width  * fZoomWidth ) + fZoomOffX;
01727       py = (Int_t)(py / (Double_t)fScaledImage->fImage->height * fZoomHeight) + fZoomOffY;
01728    }
01729 
01730    if (fImage->alt.vector) {
01731       snprintf(info,64,"x: %d  y: %d   %.5g",
01732               px, py, fImage->alt.vector[px + py * fImage->width]);
01733    } else {
01734       snprintf(info,64,"x: %d  y: %d", px, py);
01735    }
01736 
01737    return info;
01738 }
01739 
01740 
01741 //______________________________________________________________________________
01742 void TASImage::SetPalette(const TImagePalette *palette)
01743 {
01744    // Set a new palette to an image.
01745    // Only images that were created with the SetImage() functions can be
01746    // modified with this function. The previously used palette is destroyed.
01747 
01748    TAttImage::SetPalette(palette);
01749 
01750    if (!InitVisual()) {
01751       Warning("SetPalette", "Visual not initiated");
01752       return;
01753    }
01754 
01755    if (!IsValid()) {
01756       Warning("SetPalette", "Image not valid");
01757       return;
01758    }
01759 
01760    if (fImage->alt.vector == 0)
01761       return;
01762 
01763    // copy ROOT palette to asImage palette
01764    const TImagePalette &pal = GetPalette();
01765 
01766    ASVectorPalette asPalette;
01767    asPalette.npoints = pal.fNumPoints;
01768    asPalette.channels[0] = new CARD16 [asPalette.npoints];
01769    asPalette.channels[1] = new CARD16 [asPalette.npoints];
01770    asPalette.channels[2] = new CARD16 [asPalette.npoints];
01771    asPalette.channels[3] = new CARD16 [asPalette.npoints];
01772    memcpy(asPalette.channels[0], pal.fColorBlue,  pal.fNumPoints * sizeof(UShort_t));
01773    memcpy(asPalette.channels[1], pal.fColorGreen, pal.fNumPoints * sizeof(UShort_t));
01774    memcpy(asPalette.channels[2], pal.fColorRed,   pal.fNumPoints * sizeof(UShort_t));
01775    memcpy(asPalette.channels[3], pal.fColorAlpha, pal.fNumPoints * sizeof(UShort_t));
01776 
01777    asPalette.points = new double[asPalette.npoints];
01778    for (Int_t point = 0; point < Int_t(asPalette.npoints); point++)
01779       asPalette.points[point] = fMinValue + (fMaxValue - fMinValue) * pal.fPoints[point];
01780 
01781    // use the new palette in this image
01782    colorize_asimage_vector(fgVisual, fImage, &asPalette, ASA_ASImage, GetImageQuality());
01783 
01784    delete [] asPalette.points;
01785    for (Int_t col = 0; col < 4; col++)
01786       delete [] asPalette.channels[col];
01787 
01788 
01789    delete fScaledImage;
01790    fScaledImage = 0;
01791 }
01792 
01793 
01794 //______________________________________________________________________________
01795 void TASImage::Scale(UInt_t toWidth, UInt_t toHeight)
01796 {
01797    // Scale the original image.
01798    // The size of the image on the screen does not change because it is defined
01799    // by the size of the pad.
01800    // This function can be used to change the size of an image before writing
01801    // it into a file. The colors of the new pixels are interpolated.
01802    // An image created with the SetImage() functions cannot be modified with
01803    // the function SetPalette() any more after a call of this function!
01804 
01805    if (!IsValid()) {
01806       Warning("Scale", "Image not initiated");
01807       return;
01808    }
01809 
01810    if (!InitVisual()) {
01811       Warning("Scale", "Visual not initiated");
01812       return;
01813    }
01814 
01815    if (toWidth < 1)
01816        toWidth = 1;
01817    if (toHeight < 1 )
01818       toHeight = 1;
01819    if (toWidth > 30000)
01820       toWidth = 30000;
01821    if (toHeight > 30000)
01822       toHeight = 30000;
01823 
01824    ASImage *img = scale_asimage(fgVisual, fImage, toWidth, toHeight,
01825                                 ASA_ASImage, GetImageCompression(),
01826                                 GetImageQuality());
01827    DestroyImage();
01828    fImage = img;
01829    UnZoom();
01830    fZoomUpdate = kZoomOps;
01831 }
01832 
01833 
01834 //______________________________________________________________________________
01835 void TASImage::Slice(UInt_t xStart, UInt_t xEnd, UInt_t yStart,  UInt_t yEnd,
01836                      UInt_t toWidth, UInt_t toHeight)
01837 {
01838    // Another method of enlarging images where corners remain unchanged,
01839    // but middle part gets tiled.
01840 
01841    if (!IsValid()) {
01842       Warning("Scale", "Image not initiated");
01843       return;
01844    }
01845 
01846    if (!InitVisual()) {
01847       Warning("Scale", "Visual not initiated");
01848       return;
01849    }
01850 
01851    if (toWidth < 1)
01852        toWidth = 1;
01853    if (toHeight < 1 )
01854       toHeight = 1;
01855    if (toWidth > 30000)
01856       toWidth = 30000;
01857    if (toHeight > 30000)
01858       toHeight = 30000;
01859 
01860    ASImage *img = slice_asimage(fgVisual, fImage, xStart, xEnd,
01861                                 yStart, yEnd, toWidth, toHeight,
01862                                 ASA_ASImage, GetImageCompression(),
01863                                 GetImageQuality());
01864 
01865    DestroyImage();
01866    fImage = img;
01867    UnZoom();
01868    fZoomUpdate = kZoomOps;
01869 }
01870 
01871 
01872 //______________________________________________________________________________
01873 void TASImage::Tile(UInt_t toWidth, UInt_t toHeight)
01874 {
01875    // Tile the original image.
01876 
01877    if (!IsValid()) {
01878       Warning("Tile", "Image not initiated");
01879       return;
01880    }
01881 
01882    if (!InitVisual()) {
01883       Warning("Tile", "Visual not initiated");
01884       return;
01885    }
01886 
01887    if (toWidth < 1)
01888        toWidth = 1;
01889    if (toHeight < 1 )
01890       toHeight = 1;
01891    if (toWidth > 30000)
01892       toWidth = 30000;
01893    if (toHeight > 30000)
01894       toHeight = 30000;
01895 
01896    ASImage *img = tile_asimage(fgVisual, fImage, 0, 0, toWidth, toHeight, 0,
01897                                 ASA_ASImage, GetImageCompression(), GetImageQuality());
01898    DestroyImage();
01899    fImage = img;
01900    UnZoom();
01901    fZoomUpdate = kZoomOps;
01902 }
01903 
01904 
01905 //______________________________________________________________________________
01906 void TASImage::Zoom(UInt_t offX, UInt_t offY, UInt_t width, UInt_t height)
01907 {
01908    // The area of an image displayed in a pad is defined by this function.
01909    // Note: the size on the screen is defined by the size of the pad.
01910    // The original image is not modified by this function.
01911    // If width or height is larger than the original image they are reduced to
01912    // the width and height of the image.
01913    // If the off values are too large (off + width > image width) than the off
01914    // values are decreased. For example: offX = image width - width
01915    // Note: the parameters are always relative to the original image not to the
01916    // size of an already zoomed image.
01917 
01918    if (!IsValid()) {
01919       Warning("Zoom", "Image not valid");
01920       return;
01921    }
01922    fZoomUpdate = kZoom;
01923 
01924    fZoomWidth  = (width == 0) ? 1 : ((width > fImage->width) ? fImage->width : width);
01925    fZoomHeight = (height == 0) ? 1 : ((height > fImage->height) ? fImage->height : height);
01926    fZoomOffX   = offX;
01927    if (fZoomOffX + fZoomWidth > fImage->width)
01928       fZoomOffX = fImage->width - fZoomWidth;
01929    fZoomOffY   = offY;
01930    if (fZoomOffY + fZoomHeight > fImage->height)
01931       fZoomOffY = fImage->height - fZoomHeight;
01932 }
01933 
01934 
01935 //______________________________________________________________________________
01936 void TASImage::UnZoom()
01937 {
01938    // Un-zoom the image to original size.
01939    // UnZoom() - performs undo for Zoom,Crop,Scale actions
01940 
01941    if (!IsValid()) {
01942       Warning("UnZoom", "Image not valid");
01943       return;
01944    }
01945    fZoomUpdate = kZoom;
01946    fZoomOffX   = 0;
01947    fZoomOffY   = 0;
01948    fZoomWidth  = fImage->width;
01949    fZoomHeight = fImage->height;
01950 
01951    delete fScaledImage;
01952    fScaledImage = 0;
01953 }
01954 
01955 
01956 //______________________________________________________________________________
01957 void TASImage::Flip(Int_t flip)
01958 {
01959    // Flip image in place.
01960    // Flip is either 90, 180, 270, 180 is default.
01961    // This function manipulates the original image and destroys the
01962    // scaled and zoomed image which will be recreated at the next call of
01963    // the Draw function. If the image is zoomed the zoom - coordinates are
01964    // now relative to the new image.
01965    // This function cannot be used for images which were created with the
01966    // SetImage() functions, because the original pixel values would be
01967    // destroyed.
01968 
01969    if (!IsValid()) {
01970       Warning("Flip", "Image not valid");
01971       return;
01972    }
01973    if (!InitVisual()) {
01974       Warning("Flip", "Visual not initiated");
01975       return;
01976    }
01977 
01978    if (fImage->alt.vector) {
01979       Warning("Flip", "flip does not work for data images");
01980       return;
01981    }
01982 
01983    Int_t rflip = flip/90;
01984 
01985    UInt_t w = fImage->width;
01986    UInt_t h = fImage->height;
01987 
01988    if (rflip & 1) {
01989       w = fImage->height;
01990       h = fImage->width;
01991    }
01992 
01993    ASImage *img = flip_asimage(fgVisual, fImage, 0, 0, w, h, rflip,
01994                                ASA_ASImage, GetImageCompression(),
01995                                GetImageQuality());
01996    DestroyImage();
01997    fImage = img;
01998    UnZoom();
01999 }
02000 
02001 
02002 //______________________________________________________________________________
02003 void TASImage::Mirror(Bool_t vert)
02004 {
02005    // Mirror image in place.
02006    // If vert is true mirror in vertical axis, horizontal otherwise.
02007    // Vertical is default.
02008    // This function manipulates the original image and destroys the
02009    // scaled and zoomed image which will be recreated at the next call of
02010    // the Draw function. If the image is zoomed the zoom - coordinates are
02011    // now relative to the new image.
02012    // This function cannot be used for images which were created with the
02013    // SetImage() functions, because the original pixel values would be
02014    // destroyed.
02015 
02016    if (!IsValid()) {
02017       Warning("Mirror", "Image not valid");
02018       return;
02019    }
02020 
02021    if (!InitVisual()) {
02022       Warning("Mirrow", "Visual not initiated");
02023       return;
02024    }
02025 
02026    if (fImage->alt.vector) {
02027       Warning("Mirror", "mirror does not work for data images");
02028       return;
02029    }
02030 
02031    ASImage *img = mirror_asimage(fgVisual, fImage, 0, 0,
02032                                  fImage->width, fImage->height, vert,
02033                                  ASA_ASImage, GetImageCompression(),
02034                                  GetImageQuality());
02035    DestroyImage();
02036    fImage = img;
02037    UnZoom();
02038 }
02039 
02040 
02041 //______________________________________________________________________________
02042 UInt_t TASImage::GetWidth() const
02043 {
02044    // Return width of original image not of the displayed image.
02045    // (Number of image pixels)
02046 
02047    return fImage ? fImage->width : 0;
02048 }
02049 
02050 
02051 //______________________________________________________________________________
02052 UInt_t TASImage::GetHeight() const
02053 {
02054    // Return height of original image not of the displayed image.
02055    // (Number of image pixels)
02056 
02057    return fImage ? fImage->height : 0;
02058 }
02059 
02060 
02061 //______________________________________________________________________________
02062 UInt_t TASImage::GetScaledWidth() const
02063 {
02064    // Return width of the displayed image not of the original image.
02065    // (Number of screen pixels)
02066 
02067    return fScaledImage ? fScaledImage->fImage->width : GetWidth();
02068 }
02069 
02070 
02071 //______________________________________________________________________________
02072 UInt_t TASImage::GetScaledHeight() const
02073 {
02074    // Return height of the displayed image not of the original image.
02075    // (Number of screen pixels)
02076 
02077    return fScaledImage ? fScaledImage->fImage->height : GetHeight();
02078 }
02079 
02080 
02081 //______________________________________________________________________________
02082 void TASImage::GetZoomPosition(UInt_t &x, UInt_t &y, UInt_t &w, UInt_t &h) const
02083 {
02084    // Return the zoom parameters.
02085    // This is useful when the zoom has been done interactively using the mouse.
02086 
02087    x = fZoomOffX;
02088    y = fZoomOffY;
02089    w = fZoomWidth;
02090    h = fZoomHeight;
02091 }
02092 
02093 
02094 //______________________________________________________________________________
02095 Bool_t TASImage::InitVisual()
02096 {
02097    // Static function to initialize the ASVisual.
02098 
02099    Display *disp;
02100 
02101    Bool_t inbatch = fgVisual && (fgVisual->dpy == (void*)1); // was in batch
02102    Bool_t noX = gROOT->IsBatch() || gVirtualX->InheritsFrom("TGWin32");
02103 
02104    // was in batch, but switched to gui
02105    if (inbatch && !noX) {
02106       destroy_asvisual(fgVisual, kFALSE);
02107       fgVisual = 0;
02108    }
02109 
02110    if (fgVisual && fgVisual->dpy) { // already initialized
02111       return kTRUE;
02112    }
02113 
02114    // batch or win32 mode
02115    if (!fgVisual && noX) {
02116       disp = 0;
02117       fgVisual = create_asvisual(0, 0, 0, 0);
02118       fgVisual->dpy = (Display*)1; //fake (not used)
02119       return kTRUE;
02120    }
02121 
02122    disp = (Display*) gVirtualX->GetDisplay();
02123    Int_t screen  = gVirtualX->GetScreen();
02124    Int_t depth   = gVirtualX->GetDepth();
02125    Visual *vis   = (Visual*) gVirtualX->GetVisual();
02126    Colormap cmap = (Colormap) gVirtualX->GetColormap();
02127 #ifndef WIN32
02128    if (vis == 0 || cmap == 0) {
02129       fgVisual = create_asvisual(0, 0, 0, 0);
02130    } else {
02131       fgVisual = create_asvisual_for_id(disp, screen, depth,
02132                                         XVisualIDFromVisual(vis), cmap, 0);
02133    }
02134 #else
02135    fgVisual = create_asvisual(0, 0, 0, 0);
02136    fgVisual->dpy = (Display*)1; //fake (not used)
02137 #endif
02138 
02139    return kTRUE;
02140 }
02141 
02142 
02143 //______________________________________________________________________________
02144 void TASImage::StartPaletteEditor()
02145 {
02146    // Start palette editor.
02147 
02148    if (!IsValid()) {
02149       Warning("StartPaletteEditor", "Image not valid");
02150       return;
02151    }
02152    if (fImage->alt.vector == 0) {
02153       Warning("StartPaletteEditor", "palette can be modified only for data images");
02154       return;
02155    }
02156 
02157    // Opens a GUI to edit the color palette
02158    TAttImage::StartPaletteEditor();
02159 }
02160 
02161 
02162 //______________________________________________________________________________
02163 Pixmap_t TASImage::GetPixmap()
02164 {
02165    // Returns image pixmap.
02166    // The pixmap must deleted by user.
02167 
02168    if (!InitVisual()) {
02169       Warning("GetPixmap", "Visual not initiated");
02170       return 0;
02171    }
02172 
02173    Pixmap_t ret;
02174 
02175    ASImage *img = fScaledImage ? fScaledImage->fImage : fImage;
02176 
02177    static int x11 = -1;
02178    if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11");
02179 
02180    if (x11) {   // use builtin version
02181       ret = (Pixmap_t)asimage2pixmap(fgVisual, gVirtualX->GetDefaultRootWindow(),
02182                                        img, 0, kTRUE);
02183    } else {
02184       if (!fImage->alt.argb32) {
02185          BeginPaint();
02186       }
02187       ret = gVirtualX->CreatePixmapFromData((unsigned char*)fImage->alt.argb32,
02188                                              fImage->width, fImage->height);
02189    }
02190 
02191    return ret;
02192 }
02193 
02194 
02195 //______________________________________________________________________________
02196 Pixmap_t TASImage::GetMask()
02197 {
02198    // Returns image mask pixmap (alpha channel).
02199    // The pixmap must deleted by user.
02200 
02201    Pixmap_t pxmap = 0;
02202 
02203    if (!InitVisual()) {
02204       Warning("GetMask", "Visual not initiated");
02205       return pxmap;
02206    }
02207 
02208    ASImage *img = fScaledImage ? fScaledImage->fImage : fImage;
02209 
02210    if (!img) {
02211       Warning("GetMask", "No image");
02212       return pxmap;
02213    }
02214 
02215    UInt_t hh = img->height;
02216    UInt_t ow = img->width%8;
02217    UInt_t ww = img->width - ow + (ow ? 8 : 0);
02218 
02219    UInt_t bit = 0;
02220    int i = 0;
02221    UInt_t y = 0;
02222    UInt_t x = 0;
02223 
02224    char *bits = new char[ww*hh]; //an array of bits
02225 
02226    ASImageDecoder *imdec = start_image_decoding(fgVisual, img, SCL_DO_ALPHA,
02227                                                 0, 0, ww, 0, 0);
02228    if(!imdec) {
02229       delete [] bits;
02230       return 0;
02231    }
02232 
02233    for (y = 0; y < hh; y++) {
02234       imdec->decode_image_scanline(imdec);
02235       CARD32 *a = imdec->buffer.alpha;
02236 
02237       for (x = 0; x < ww; x++) {
02238          if (a[x]) {
02239             SETBIT(bits[i], bit);
02240          } else {
02241             CLRBIT(bits[i], bit);
02242          }
02243          bit++;
02244          if (bit == 8) {
02245             bit = 0;
02246             i++;
02247          }
02248       }
02249    }
02250 
02251    stop_image_decoding(&imdec);
02252    pxmap = gVirtualX->CreateBitmap(gVirtualX->GetDefaultRootWindow(), (const char *)bits,
02253                                    ww, hh);
02254    delete [] bits;
02255    return pxmap;
02256 }
02257 
02258 
02259 //______________________________________________________________________________
02260 void TASImage::SetImage(Pixmap_t pxm, Pixmap_t mask)
02261 {
02262    // Create image from pixmap.
02263 
02264    if (!InitVisual()) {
02265       Warning("SetImage", "Visual not initiated");
02266       return;
02267    }
02268 
02269    DestroyImage();
02270    delete fScaledImage;
02271    fScaledImage = 0;
02272 
02273    Int_t xy;
02274    UInt_t w, h;
02275    gVirtualX->GetWindowSize(pxm, xy, xy, w, h);
02276 
02277    if (fName.IsNull()) fName.Form("img_%dx%d",w, h);
02278 
02279    static int x11 = -1;
02280    if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11");
02281 
02282    if (x11) { //use built-in optimized version
02283       fImage = picture2asimage(fgVisual, pxm, mask, 0, 0, w, h, kAllPlanes, 1, 0);
02284    } else {
02285       unsigned char *bits = gVirtualX->GetColorBits(pxm, 0, 0, w, h);
02286       if (!bits) {   // error
02287          return;
02288       }
02289 
02290       // no mask
02291       if (!mask) {
02292          fImage = bitmap2asimage(bits, w, h, 0, 0);
02293          delete [] bits;
02294          return;
02295       }
02296       unsigned char *mask_bits = gVirtualX->GetColorBits(mask, 0, 0, w, h);
02297       fImage = bitmap2asimage(bits, w, h, 0, mask_bits);
02298       delete [] mask_bits;
02299       delete [] bits;
02300    }
02301 }
02302 
02303 
02304 //______________________________________________________________________________
02305 TArrayL *TASImage::GetPixels(Int_t x, Int_t y, UInt_t width, UInt_t height)
02306 {
02307    // Return 2D array of machine dependent pixel values.
02308 
02309    if (!fImage) {
02310       Warning("GetPixels", "Wrong Image");
02311       return 0;
02312    }
02313 
02314    ASImage *img =  fScaledImage ? fScaledImage->fImage : fImage;
02315    ASImageDecoder *imdec;
02316 
02317    width = !width  ? img->width : width;
02318    height = !height ? img->height : height;
02319 
02320    if (x < 0) {
02321       width -= x;
02322       x = 0 ;
02323    }
02324    if (y < 0) {
02325       height -= y;
02326       y = 0;
02327    }
02328 
02329    if ((x >= (int)img->width) || (y >= (int)img->height)) {
02330       return 0;
02331    }
02332 
02333    if ((int)(x + width) > (int)img->width) {
02334       width = img->width - x;
02335    }
02336 
02337    if ((int)(y + height) > (int)img->height) {
02338       height = img->height - y;
02339    }
02340 
02341    if ((imdec = start_image_decoding(0, fImage, SCL_DO_ALL, 0, y,
02342                                      img->width, height, 0)) == 0) {
02343       Warning("GetPixels", "Failed to create image decoder");
02344       return 0;
02345    }
02346 
02347    TArrayL *ret = new TArrayL(width * height);
02348    Int_t r = 0;
02349    Int_t g = 0;
02350    Int_t b = 0;
02351    Long_t p = 0;
02352 
02353    for (UInt_t k = 0; k < height; k++) {
02354       imdec->decode_image_scanline(imdec);
02355 
02356       for (UInt_t i = 0; i < width; ++i)  {
02357          if ((r == (Int_t)imdec->buffer.red[i]) &&
02358              (g == (Int_t)imdec->buffer.green[i]) &&
02359              (b == (Int_t)imdec->buffer.blue[i])) {
02360          } else {
02361             r = (Int_t)imdec->buffer.red[i];
02362             g = (Int_t)imdec->buffer.green[i];
02363             b = (Int_t)imdec->buffer.blue[i];
02364             p = (Long_t)TColor::RGB2Pixel(r, g, b);
02365          }
02366          ret->AddAt(p, k*width + i);
02367       }
02368    }
02369 
02370    stop_image_decoding(&imdec);
02371    return ret;
02372 }
02373 
02374 
02375 //______________________________________________________________________________
02376 Double_t *TASImage::GetVecArray()
02377 {
02378    // Return a pointer to internal array[width x height] of double values [0,1].
02379    // This array is directly accessible. That allows to manipulate/change the
02380    // image.
02381 
02382    if (!fImage) {
02383       Warning("GetVecArray", "Bad Image");
02384       return 0;
02385    }
02386    if (fImage->alt.vector) {
02387       return fImage->alt.vector;
02388    }
02389    // vectorize
02390    return 0;
02391 }
02392 
02393 
02394 //______________________________________________________________________________
02395 TArrayD *TASImage::GetArray(UInt_t w, UInt_t h, TImagePalette *palette)
02396 {
02397    // In case of vectorized image return an associated array of doubles
02398    // otherwise this method creates and returns a 2D array of doubles corresponding to palette.
02399    // If palette is ZERO a color converted to double value [0, 1] according to formula
02400    //   Double_t((r << 16) + (g << 8) + b)/0xFFFFFF
02401    // The returned array must be deleted after usage.
02402 
02403    if (!fImage) {
02404       Warning("GetArray", "Bad Image");
02405       return 0;
02406    }
02407 
02408    TArrayD *ret;
02409 
02410    if (fImage->alt.vector) {
02411       ret = new TArrayD(fImage->width*fImage->height, fImage->alt.vector);
02412       return ret;
02413    }
02414 
02415    ASImageDecoder *imdec;
02416 
02417    w = w ? w : fImage->width;
02418    h = h ? h : fImage->height;
02419 
02420    if ((fImage->width != w) || (fImage->height != h)) {
02421       Scale(w, h);
02422    }
02423 
02424    ASImage *img = fScaledImage ? fScaledImage->fImage : fImage;
02425 
02426    if ((imdec = start_image_decoding(0, img, SCL_DO_ALL, 0, 0,
02427                                      img->width, 0, 0)) == 0) {
02428       Warning("GetArray", "Failed to create image decoder");
02429       return 0;
02430    }
02431 
02432    ret = new TArrayD(w * h);
02433    CARD32 r = 0;
02434    CARD32 g = 0;
02435    CARD32 b = 0;
02436    Int_t p = 0;
02437    Double_t v = 0;
02438 
02439    for (UInt_t k = 0; k < h; k++) {
02440       imdec->decode_image_scanline(imdec);
02441 
02442       for (UInt_t i = 0; i < w; ++i)  {
02443          if ((r == imdec->buffer.red[i]) &&
02444              (g == imdec->buffer.green[i]) &&
02445              (b == imdec->buffer.blue[i])) {
02446          } else {
02447             r = imdec->buffer.red[i];
02448             g = imdec->buffer.green[i];
02449             b = imdec->buffer.blue[i];
02450             if (palette) p = palette->FindColor(r, g, b);
02451          }
02452          v = palette ? palette->fPoints[p] : Double_t((r << 16) + (g << 8) + b)/0xFFFFFF;
02453          ret->AddAt(v, (h-k-1)*w + i);
02454       }
02455    }
02456 
02457    stop_image_decoding(&imdec);
02458    return ret;
02459 }
02460 
02461 
02462 //______________________________________________________________________________
02463 void TASImage::DrawText(Int_t x, Int_t y, const char *text, Int_t size,
02464                         const char *color, const char *font_name,
02465                         EText3DType type, const char *fore_file, Float_t angle)
02466 {
02467    // Draw text of size (in pixels for TrueType fonts)
02468    // at position (x, y) with color  specified by hex string.
02469    //   font_name - TrueType font's filename or X font spec or alias.
02470    //   3D style of text is one of the following:
02471    //     0 - plain 2D text, 1 - embossed, 2 - sunken, 3 - shade above,
02472    //     4 - shade below, 5 - embossed thick, 6 - sunken thick.
02473    //     7 - ouline above, 8 - ouline below, 9 - full ouline.
02474    //  fore_file specifies foreground texture of text.
02475 
02476    UInt_t width, height;
02477    ARGB32 text_color = ARGB32_Black;
02478    ASImage *fore_im = 0;
02479    ASImage *text_im = 0;
02480    Bool_t ttfont = kFALSE;
02481 
02482    if (!InitVisual()) {
02483       Warning("DrawText", "Visual not initiated");
02484       return;
02485    }
02486 
02487    TString fn = font_name;
02488    fn.Strip();
02489    char *tmpstr = 0;
02490 
02491    if (fn.EndsWith(".ttf") || fn.EndsWith(".TTF")) {
02492       tmpstr = gSystem->ExpandPathName(fn.Data());
02493       fn = tmpstr;
02494       ttfont = kTRUE;
02495    }
02496    delete [] tmpstr;
02497 
02498    if (color) {
02499       parse_argb_color(color, &text_color);
02500    }
02501 
02502    if (fImage && fImage->alt.argb32 && ttfont) {
02503       DrawTextTTF(x, y, text, size, text_color, fn.Data(), angle);
02504       return;
02505    }
02506 
02507    if (!gFontManager) {
02508       gFontManager = create_font_manager(fgVisual->dpy, 0, 0);
02509    }
02510 
02511    if (!gFontManager) {
02512       Warning("DrawText", "cannot create Font Manager");
02513       return;
02514    }
02515 
02516    ASFont *font = get_asfont(gFontManager, fn.Data(), 0, size, ASF_GuessWho);
02517 
02518    if (!font) {
02519       font = get_asfont(gFontManager, "fixed", 0, size, ASF_GuessWho);
02520       if (!font) {
02521          Warning("DrawText", "cannot find a font %s", font_name);
02522          return;
02523       }
02524    }
02525 
02526    get_text_size(text, font, (ASText3DType)type, &width, &height);
02527 
02528    if (!fImage) {
02529       fImage = create_asimage(width, height, 0);
02530       fill_asimage(fgVisual, fImage, 0, 0, width, height, 0xFFFFFFFF);
02531    }
02532 
02533    text_im = draw_text(text, font, (ASText3DType)type, 0);
02534 
02535    ASImage *rimg = fImage;
02536 
02537    if (fore_file) {
02538       ASImage *tmp = file2ASImage(fore_file, 0xFFFFFFFF, SCREEN_GAMMA, 0, 0);
02539       if (tmp) {
02540          if ((tmp->width != width) || (tmp->height != height)) {
02541             fore_im = tile_asimage(fgVisual, tmp, 0, 0, width, height, 0,
02542                                    ASA_ASImage, GetImageCompression(), GetImageQuality());
02543          }
02544          destroy_asimage(&tmp);
02545       } else {
02546          fore_im = tmp;
02547       }
02548    }
02549 
02550    if (fore_im) {
02551       move_asimage_channel(fore_im, IC_ALPHA, text_im, IC_ALPHA);
02552       destroy_asimage(&text_im);
02553    } else {
02554       fore_im = text_im ;
02555    }
02556 
02557    release_font(font);
02558 
02559    if (fore_im) {
02560       ASImage *rendered_im;
02561       ASImageLayer layers[2];
02562 
02563       init_image_layers(&(layers[0]), 2);
02564       fore_im->back_color = text_color;
02565       layers[0].im = rimg;
02566       layers[0].dst_x = 0;
02567       layers[0].dst_y = 0;
02568       layers[0].clip_width = rimg->width;
02569       layers[0].clip_height = rimg->height;
02570       layers[0].bevel = 0;
02571       layers[1].im = fore_im;
02572       layers[1].dst_x = x;
02573       layers[1].dst_y = y;
02574       layers[1].clip_width = fore_im->width;
02575       layers[1].clip_height = fore_im->height;
02576 
02577       rendered_im = merge_layers(fgVisual, &(layers[0]), 2, rimg->width, rimg->height,
02578                                  ASA_ASImage, GetImageCompression(), GetImageQuality());
02579 
02580       destroy_asimage(&fore_im);
02581       DestroyImage();
02582       fImage = rendered_im;
02583       UnZoom();
02584    }
02585 }
02586 
02587 
02588 //______________________________________________________________________________
02589 void TASImage::Merge(const TImage *im, const char *op, Int_t x, Int_t y)
02590 {
02591    // Merge two images.
02592    //
02593    // op is string which specifies overlay operation. Supported operations are:
02594    //    add            - color addition with saturation
02595    //    alphablend     - alpha-blending
02596    //    allanon        - color values averaging
02597    //    colorize       - hue and saturate bottom image same as top image
02598    //    darken         - use lowest color value from both images
02599    //    diff           - use absolute value of the color difference between two images
02600    //    dissipate      - randomly alpha-blend images
02601    //    hue            - hue bottom image same as top image
02602    //    lighten        - use highest color value from both images
02603    //    overlay        - some wierd image overlaying(see GIMP)
02604    //    saturate       - saturate bottom image same as top image
02605    //    screen         - another wierd image overlaying(see GIMP)
02606    //    sub            - color substraction with saturation
02607    //    tint           - tinting image with image
02608    //    value          - value bottom image same as top image
02609 
02610    if (!im) return;
02611 
02612    if (!InitVisual()) {
02613       Warning("Merge", "Visual not initiated");
02614       return;
02615    }
02616 
02617    ASImage *rendered_im;
02618    ASImageLayer layers[2];
02619 
02620    init_image_layers(&(layers[0]), 2);
02621    layers[0].im = fImage;
02622    layers[0].dst_x = 0;
02623    layers[0].dst_y = 0;
02624    layers[0].clip_width = fImage->width;
02625    layers[0].clip_height = fImage->height;
02626    layers[0].bevel = 0;
02627    layers[1].im = ((TASImage*)im)->fImage;
02628    layers[1].dst_x = x;
02629    layers[1].dst_y = y;
02630    layers[1].clip_width  = im->GetWidth();
02631    layers[1].clip_height = im->GetHeight();
02632    layers[1].merge_scanlines = blend_scanlines_name2func(op ? op : "add");
02633 
02634    rendered_im = merge_layers(fgVisual, &(layers[0]), 2, fImage->width, fImage->height,
02635                               ASA_ASImage, GetImageCompression(), GetImageQuality());
02636 
02637    DestroyImage();
02638    fImage = rendered_im;
02639    UnZoom();
02640 }
02641 
02642 
02643 //______________________________________________________________________________
02644 void TASImage::Blur(Double_t hr, Double_t vr)
02645 {
02646    // Perform Gaussian blurr of the image (usefull for drop shadows).
02647    //    hr         - horizontal radius of the blurr
02648    //    vr         - vertical radius of the blurr
02649 
02650    if (!InitVisual()) {
02651       Warning("Blur", "Visual not initiated");
02652       return;
02653    }
02654 
02655    if (!fImage) {
02656       fImage = create_asimage(100, 100, 0);
02657 
02658       if (!fImage) {
02659          Warning("Blur", "Failed to create image");
02660          return;
02661       }
02662 
02663       fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, ARGB32_White);
02664    }
02665 
02666    ASImage *rendered_im = blur_asimage_gauss(fgVisual, fImage, hr > 0 ? hr : 3,
02667                                              vr > 0 ? vr : 3, SCL_DO_ALL,
02668                                              ASA_ASImage, GetImageCompression(), GetImageQuality());
02669    DestroyImage();
02670    fImage = rendered_im;
02671    UnZoom();
02672 }
02673 
02674 
02675 //______________________________________________________________________________
02676 TObject *TASImage::Clone(const char *newname) const
02677 {
02678    // Clone image.
02679 
02680    if (!InitVisual() || !fImage) {
02681       Warning("Clone", "Image not initiated");
02682       return 0;
02683    }
02684 
02685    TASImage *im = (TASImage*)TImage::Create();
02686 
02687    if (!im) {
02688       Warning("Clone", "Failed to create image");
02689       return 0;
02690    }
02691 
02692    im->SetName(newname);
02693 
02694    im->fImage = clone_asimage(fImage, SCL_DO_ALL);
02695    im->fMaxValue = fMaxValue;
02696    im->fMinValue = fMinValue;
02697    im->fZoomOffX = fZoomOffX;
02698    im->fZoomOffY = fZoomOffY;
02699    im->fZoomWidth = fZoomWidth;
02700    im->fZoomHeight = fZoomHeight;
02701    im->fZoomUpdate = fZoomUpdate;
02702    im->fScaledImage = fScaledImage ? (TASImage*)fScaledImage->Clone("") : 0;
02703 
02704    if (fImage->alt.argb32) {
02705       UInt_t sz = fImage->width * fImage->height;
02706       im->fImage->alt.argb32 = (ARGB32*)safemalloc(sz*sizeof(ARGB32));
02707       memcpy(im->fImage->alt.argb32, fImage->alt.argb32, sz * sizeof(ARGB32));
02708    }
02709 
02710    return im;
02711 }
02712 
02713 
02714 //______________________________________________________________________________
02715 Double_t *TASImage::Vectorize(UInt_t max_colors, UInt_t dither, Int_t opaque_threshold)
02716 {
02717    // Reduce colordepth of an image and fills vector of "scientific data"
02718    // [0...1]
02719    //
02720    // Colors are reduced by allocating colorcells to most used colors first,
02721    // and then approximating other colors with those allocated.
02722    // max_colors       - maximum size of the colormap.
02723    // dither           - number of bits to strip off the color data ( 0...7 )
02724    // opaque_threshold - alpha channel threshold at which pixel should be
02725    //                    treated as opaque
02726 
02727    if (!InitVisual()) {
02728       Warning("Vectorize", "Visual not initiated");
02729       return 0;
02730    }
02731 
02732    if (!fImage) {
02733       fImage = create_asimage(100, 100, 0);
02734 
02735       if (!fImage) {
02736          Warning("Vectorize", "Failed to create image");
02737          return 0;
02738       }
02739 
02740       fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, ARGB32_White);
02741    }
02742 
02743    ASColormap cmap;
02744    int *res;
02745    UInt_t r, g, b;
02746 
02747    dither = dither > 7 ? 7 : dither;
02748 
02749    res = colormap_asimage(fImage, &cmap, max_colors, dither, opaque_threshold);
02750 
02751    Double_t *vec = new Double_t[fImage->height*fImage->width];
02752    UInt_t v;
02753    Double_t tmp;
02754    fMinValue = 2;
02755    fMaxValue = -1;
02756 
02757    for (UInt_t y = 0; y < fImage->height; y++) {
02758       for (UInt_t x = 0; x < fImage->width; x++) {
02759          int i = y*fImage->width + x;
02760          g = INDEX_SHIFT_GREEN(cmap.entries[res[i]].green);
02761          b = INDEX_SHIFT_BLUE(cmap.entries[res[i]].blue);
02762          r = INDEX_SHIFT_RED(cmap.entries[res[i]].red);
02763          v = MAKE_INDEXED_COLOR24(r,g,b);
02764          v = (v>>12)&0x0FFF;
02765          tmp = Double_t(v)/0x0FFF;
02766          vec[(fImage->height - y - 1)*fImage->width + x] = tmp;
02767          if (fMinValue > tmp) fMinValue = tmp;
02768          if (fMaxValue < tmp) fMaxValue = tmp;
02769       }
02770    }
02771    TImagePalette *pal = new TImagePalette(cmap.count);
02772 
02773    for (UInt_t j = 0; j < cmap.count; j++) {
02774       g = INDEX_SHIFT_GREEN(cmap.entries[j].green);
02775       b = INDEX_SHIFT_BLUE(cmap.entries[j].blue);
02776       r = INDEX_SHIFT_RED(cmap.entries[j].red);
02777       v = MAKE_INDEXED_COLOR24(r,g,b);
02778 
02779       v = (v>>12) & 0x0FFF;
02780       pal->fPoints[j] = Double_t(v)/0x0FFF;
02781 
02782       pal->fColorRed[j] = cmap.entries[j].red << 8;
02783       pal->fColorGreen[j] = cmap.entries[j].green << 8;
02784       pal->fColorBlue[j] = cmap.entries[j].blue << 8;
02785       pal->fColorAlpha[j] = 0xFF00;
02786    }
02787 
02788    destroy_colormap(&cmap, kTRUE);
02789 
02790    fPalette = *pal;
02791    fImage->alt.vector = vec;
02792    UnZoom();
02793    if (res) delete res;
02794    return (Double_t*)fImage->alt.vector;
02795 }
02796 
02797 
02798 //______________________________________________________________________________
02799 void TASImage::HSV(UInt_t hue, UInt_t radius, Int_t H, Int_t S, Int_t V,
02800                    Int_t x, Int_t y, UInt_t width, UInt_t height)
02801 {
02802    // This function will tile original image to specified size with offsets
02803    // requested, and then it will go though it and adjust hue, saturation and
02804    // value of those pixels that have specific hue, set by affected_hue/
02805    // affected_radius parameters. When affected_radius is greater then 180
02806    // entire image will be adjusted. Note that since grayscale colors have
02807    // no hue - the will not get adjusted. Only saturation and value will be
02808    // adjusted in gray pixels.
02809    // Hue is measured as an angle on a 360 degree circle, The following is
02810    // relationship of hue values to regular color names :
02811    // red      - 0
02812    // yellow   - 60
02813    // green    - 120
02814    // cyan     - 180
02815    // blue     - 240
02816    // magenta  - 300
02817    // red      - 360
02818    //
02819    // All the hue values in parameters will be adjusted to fall withing 0-360 range.
02820 
02821    // hue - hue in degrees in range 0-360. This allows to limit
02822    //       impact of color adjustment to affect only limited range of hues.
02823    //
02824    // radius - value in degrees to be used in order to
02825    //          calculate the range of affected hues. Range is determined by
02826    //          substracting and adding this value from/to affected_hue.
02827    //
02828    // H -   value by which to change hues in affected range.
02829    // S -   value by which to change saturation of the pixels in affected hue range.
02830    // V -   value by which to change Value(brightness) of pixels in affected hue range.
02831    //
02832    // x,y - position on infinite surface tiled with original image, of the
02833    //       left-top corner of the area to be used for new image.
02834    //
02835    // width, height - size of the area of the original image to be used for new image.
02836    //                 Default is current width, height of the image.
02837 
02838    if (!InitVisual()) {
02839       Warning("HSV", "Visual not initiated");
02840       return;
02841    }
02842 
02843    if (!fImage) {
02844       fImage = create_asimage(width ? width : 20, height ? height : 20, 0);
02845 
02846       if (!fImage) {
02847          Warning("HSV", "Failed to create image");
02848          return;
02849       }
02850 
02851       x = 0;
02852       y = 0;
02853       fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, ARGB32_White);
02854    }
02855 
02856    width = !width ? fImage->width : width;
02857    height = !height ? fImage->height : height;
02858 
02859    ASImage *rendered_im = 0;
02860 
02861    if (H || S || V) {
02862       rendered_im = adjust_asimage_hsv(fgVisual, fImage, x, y, width, height,
02863                                        hue, radius, H, S, V, ASA_ASImage, 100,
02864                                        ASIMAGE_QUALITY_TOP);
02865    }
02866    if (!rendered_im) {
02867       Warning("HSV", "Failed to create rendered image");
02868       return;
02869    }
02870 
02871    DestroyImage();
02872    fImage = rendered_im;
02873    UnZoom();
02874 }
02875 
02876 
02877 //______________________________________________________________________________
02878 void TASImage::Gradient(UInt_t angle, const char *colors, const char *offsets,
02879                         Int_t x, Int_t y, UInt_t width, UInt_t height)
02880 {
02881    // Render multipoint gradient inside rectangle of size (width, height)
02882    // at position (x,y) within the existing image.
02883    //
02884    // angle    Given in degrees.  Default is 0.  This is the
02885    //          direction of the gradient.  Currently the only supported
02886    //          values are 0, 45, 90, 135, 180, 225, 270, 315.  0 means left
02887    //          to right, 90 means top to bottom, etc.
02888    //
02889    // colors   Whitespace-separated list of colors.  At least two
02890    //          colors are required.  Each color in this list will be visited
02891    //          in turn, at the intervals given by the offsets attribute.
02892    //
02893    // offsets  Whitespace-separated list of floating point values
02894    //          ranging from 0.0 to 1.0.  The colors from the colors attribute
02895    //          are given these offsets, and the final gradient is rendered
02896    //          from the combination of the two.  If both colors and offsets
02897    //          are given but the number of colors and offsets do not match,
02898    //          the minimum of the two will be used, and the other will be
02899    //          truncated to match.  If offsets are not given, a smooth
02900    //          stepping from 0.0 to 1.0 will be used.
02901 
02902    if (!InitVisual()) {
02903       Warning("Gradient", "Visual not initiated");
02904       return;
02905    }
02906 
02907    ASImage *rendered_im = 0;
02908    ASGradient gradient;
02909 
02910    int reverse = 0, npoints1 = 0, npoints2 = 0;
02911    char *p;
02912    char *pb;
02913    char ch;
02914    TString str = colors;
02915    TString col;
02916 
02917    if ((angle > 2 * 180 * 15 / 16) || (angle < 2 * 180 * 1 / 16)) {
02918       gradient.type = GRADIENT_Left2Right;
02919    } else if (angle < 2 * 180 * 3 / 16) {
02920       gradient.type = GRADIENT_TopLeft2BottomRight;
02921    } else if (angle < 2 * 180 * 5 / 16) {
02922       gradient.type = GRADIENT_Top2Bottom;
02923    } else if (angle < 2 * 180 * 7 / 16) {
02924       gradient.type = GRADIENT_BottomLeft2TopRight; reverse = 1;
02925    } else if (angle < 2 * 180 * 9 / 16) {
02926       gradient.type = GRADIENT_Left2Right; reverse = 1;
02927    } else if (angle < 2 * 180 * 11 / 16) {
02928       gradient.type = GRADIENT_TopLeft2BottomRight; reverse = 1;
02929    } else if (angle < 2 * 180 * 13 / 16) {
02930       gradient.type = GRADIENT_Top2Bottom; reverse = 1;
02931    } else {
02932       gradient.type = GRADIENT_BottomLeft2TopRight;
02933    }
02934 
02935    for (p = (char*)colors; isspace((int)*p); p++) { }
02936 
02937    for (npoints1 = 0; *p; npoints1++) {
02938       if (*p) {
02939          for ( ; *p && !isspace((int)*p); p++) { }
02940       }
02941       for ( ; isspace((int)*p); p++) { }
02942    }
02943    if (offsets) {
02944       for (p = (char*)offsets; isspace((int)*p); p++) { }
02945 
02946       for (npoints2 = 0; *p; npoints2++) {
02947          if (*p) {
02948             for ( ; *p && !isspace((int)*p); p++) { }
02949          }
02950          for ( ; isspace((int)*p); p++) { }
02951       }
02952    }
02953    if (npoints1 > 1) {
02954       int i;
02955       if (offsets && (npoints1 > npoints2)) npoints1 = npoints2;
02956 
02957       if (!width) {
02958          width = fImage ? fImage->width : 20;
02959       }
02960       if (!height) {
02961          height = fImage ? fImage->height : 20;
02962       }
02963 
02964       gradient.color = new ARGB32[npoints1];
02965       gradient.offset = new double[npoints1];
02966 
02967       for (p = (char*)colors; isspace((int)*p); p++) { }
02968 
02969       for (npoints1 = 0; *p; ) {
02970          pb = p;
02971 
02972          if (*p) {
02973             for ( ; *p && !isspace((int)*p); p++) { }
02974          }
02975          for ( ; isspace((int)*p); p++) { }
02976 
02977          col = str(pb - colors, p - pb);
02978 
02979          if (parse_argb_color(col.Data(), gradient.color + npoints1) != col) {
02980             npoints1++;
02981          } else {
02982             Warning("Gradient", "Failed to parse color [%s] - defaulting to black", pb);
02983          }
02984       }
02985 
02986       if (offsets) {
02987          for (p = (char*)offsets; isspace((int)*p); p++) { }
02988 
02989          for (npoints2 = 0; *p; ) {
02990             pb = p;
02991 
02992             if (*p) {
02993                for ( ; *p && !isspace((int)*p); p++) { }
02994             }
02995             ch = *p; *p = '\0';
02996             gradient.offset[npoints2] = strtod(pb, &pb);
02997 
02998             if (pb == p) npoints2++;
02999             *p = ch;
03000             for ( ; isspace((int)*p); p++) { }
03001          }
03002       } else {
03003          for (npoints2 = 0; npoints2 < npoints1; npoints2++) {
03004             gradient.offset[npoints2] = (double)npoints2 / (npoints1 - 1);
03005          }
03006       }
03007       gradient.npoints = npoints1;
03008 
03009       if (npoints2 && (gradient.npoints > npoints2)) {
03010          gradient.npoints = npoints2;
03011       }
03012       if (reverse) {
03013          for (i = 0; i < gradient.npoints/2; i++) {
03014             int i2 = gradient.npoints - 1 - i;
03015             ARGB32 c = gradient.color[i];
03016             double o = gradient.offset[i];
03017             gradient.color[i] = gradient.color[i2];
03018             gradient.color[i2] = c;
03019             gradient.offset[i] = gradient.offset[i2];
03020             gradient.offset[i2] = o;
03021          }
03022          for (i = 0; i < gradient.npoints; i++) {
03023             gradient.offset[i] = 1.0 - gradient.offset[i];
03024          }
03025       }
03026       rendered_im = make_gradient(fgVisual, &gradient, width, height, SCL_DO_ALL,
03027                                   ASA_ASImage, GetImageCompression(), GetImageQuality());
03028 
03029       delete [] gradient.color;
03030       delete [] gradient.offset;
03031    }
03032 
03033    if (!rendered_im) {  // error
03034       Warning("Gradient", "Failed to create gradient image");
03035       return;
03036    }
03037 
03038    if (!fImage) {
03039       fImage = rendered_im;
03040       return;
03041    }
03042 
03043    ASImageLayer layers[2];
03044 
03045    init_image_layers(&(layers[0]), 2);
03046    layers[0].im = fImage;
03047    layers[0].dst_x = 0;
03048    layers[0].dst_y = 0;
03049    layers[0].clip_width = fImage->width;
03050    layers[0].clip_height = fImage->height;
03051    layers[0].bevel = 0;
03052    layers[1].im = rendered_im;
03053    layers[1].dst_x = x;
03054    layers[1].dst_y = y;
03055    layers[1].clip_width = width;
03056    layers[1].clip_height = height;
03057    layers[1].merge_scanlines = alphablend_scanlines;
03058 
03059    ASImage *merge_im = merge_layers(fgVisual, &(layers[0]), 2, fImage->width, fImage->height,
03060                                     ASA_ASImage, GetImageCompression(), GetImageQuality());
03061    if (!merge_im) {
03062       Warning("Gradient", "Failed to create merged image");
03063       return;
03064    }
03065 
03066    destroy_asimage(&rendered_im);
03067    DestroyImage();
03068    fImage = merge_im;
03069    UnZoom();
03070 }
03071 
03072 
03073 //______________________________________________________________________________
03074 static CARD8 MakeComponentHilite(int cmp)
03075 {
03076    // Make component hilite.
03077    // (used internally)
03078 
03079    if (cmp < 51) {
03080       cmp = 51;
03081    }
03082    cmp = (cmp * 12) / 10;
03083 
03084    return (cmp > 255) ? 255 : cmp;
03085 }
03086 
03087 
03088 //______________________________________________________________________________
03089 static ARGB32 GetHilite(ARGB32 background)
03090 {
03091    // Calculate highlite color.
03092    // (used internally)
03093 
03094    return ((MakeComponentHilite((background>>24) & 0x000000FF) << 24) & 0xFF000000) |
03095            ((MakeComponentHilite((background & 0x00FF0000) >> 16) << 16) & 0x00FF0000) |
03096            ((MakeComponentHilite((background & 0x0000FF00) >> 8) << 8) & 0x0000FF00) |
03097            ((MakeComponentHilite((background & 0x000000FF))) & 0x000000FF);
03098 }
03099 
03100 
03101 //______________________________________________________________________________
03102 static ARGB32 GetShadow(ARGB32 background)
03103 {
03104    // Calculate shadow color.
03105    // (used internally)
03106 
03107    return (background >> 1) & 0x7F7F7F7F;
03108 }
03109 
03110 
03111 //______________________________________________________________________________
03112 static ARGB32 GetAverage(ARGB32 foreground, ARGB32 background)
03113 {
03114    // Get average.
03115    // (used internally)
03116 
03117    CARD16   a, r, g, b;
03118 
03119    a = ARGB32_ALPHA8(foreground) + ARGB32_ALPHA8(background);
03120    a = (a<<3)/10;
03121    r = ARGB32_RED8(foreground) + ARGB32_RED8(background);
03122    r = (r<<3)/10;
03123    g = ARGB32_GREEN8(foreground) + ARGB32_GREEN8(background);
03124    g = (g<<3)/10;
03125    b = ARGB32_BLUE8(foreground) + ARGB32_BLUE8(background);
03126    b = (b<<3)/10;
03127 
03128    return MAKE_ARGB32(a, r, g, b);
03129 }
03130 
03131 
03132 //______________________________________________________________________________
03133 void TASImage::Bevel(Int_t x, Int_t y, UInt_t width, UInt_t height,
03134                      const char *hi_color, const char *lo_color, UShort_t thick,
03135                      Bool_t reverse)
03136 {
03137    // Bevel is used to create 3D effect while drawing buttons, or any other
03138    // image that needs to be framed. Bevel is drawn using 2 primary colors:
03139    // one for top and left sides - hi color, and another for bottom and
03140    // right sides - low color. Bevel can be drawn over exisiting image or
03141    // as newly created,  as it is shown in code below:
03142    //
03143    //  TImage *img = TImage::Create();
03144    //  img->Bevel(0, 0, 400, 300, "#dddddd", "#000000", 3);
03145 
03146    if (!InitVisual()) {
03147       Warning("Bevel", "Visual not initiated");
03148       return;
03149    }
03150 
03151    ASImageBevel bevel;
03152    bevel.type = 0;
03153 
03154    ARGB32 hi, lo;
03155    parse_argb_color(hi_color, &hi);
03156    parse_argb_color(lo_color, &lo);
03157 
03158    if (reverse) {
03159       bevel.lo_color = hi;
03160       bevel.lolo_color = GetHilite(hi);
03161       bevel.hi_color = lo;
03162       bevel.hihi_color = GetShadow(lo);
03163    } else {
03164       bevel.hi_color = hi;
03165       bevel.hihi_color = GetHilite(hi);
03166       bevel.lo_color = lo;
03167       bevel.lolo_color = GetShadow(lo);
03168    }
03169    bevel.hilo_color = GetAverage(hi, lo);
03170 
03171    int extra_hilite = 2;
03172    bevel.left_outline = bevel.top_outline = bevel.right_outline = bevel.bottom_outline = thick;
03173    bevel.left_inline = bevel.top_inline = bevel.right_inline = bevel.bottom_inline = extra_hilite + 1;
03174 
03175    if (bevel.top_outline > 1) {
03176       bevel.top_inline += bevel.top_outline - 1;
03177    }
03178 
03179    if (bevel.left_outline > 1) {
03180       bevel.left_inline += bevel.left_outline - 1;
03181    }
03182 
03183    if (bevel.right_outline > 1) {
03184       bevel.right_inline += bevel.right_outline - 1;
03185    }
03186 
03187    if (bevel.bottom_outline > 1) {
03188       bevel.bottom_inline += bevel.bottom_outline - 1;
03189    }
03190 
03191    ASImage *merge_im;
03192    ARGB32 fill = ((hi>>24) != 0xff) || ((lo>>24) != 0xff) ? bevel.hilo_color : (bevel.hilo_color | 0xff000000);
03193 
03194    if (!fImage) {
03195       fImage = create_asimage(width ? width : 20, height ? height : 20, 0);
03196 
03197       if (!fImage) {
03198          Warning("Bevel", "Failed to create image");
03199          return;
03200       }
03201 
03202       x = 0;
03203       y = 0;
03204       fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, fill);
03205    }
03206 
03207    width = !width ? fImage->width : width;
03208    height = !height ? fImage->height : height;
03209 
03210    ASImageLayer layers[2];
03211    init_image_layers(&(layers[0]), 2);
03212 
03213    layers[0].im = fImage;
03214    layers[0].dst_x = 0;
03215    layers[0].dst_y = 0;
03216    layers[0].clip_width = fImage->width;
03217    layers[0].clip_height = fImage->height;
03218    layers[0].bevel = 0;
03219 
03220    UInt_t w = width - (bevel.left_outline + bevel.right_outline);
03221    UInt_t h = height - (bevel.top_outline + bevel.bottom_outline);
03222    ASImage *bevel_im = create_asimage(w, h, 0);
03223 
03224    if (!bevel_im) {
03225       Warning("Bevel", "Failed to create bevel image");
03226       return;
03227    }
03228 
03229    layers[1].im = bevel_im;
03230    fill_asimage(fgVisual, bevel_im, 0, 0, w, h, fill);
03231 
03232    layers[1].dst_x = x;
03233    layers[1].dst_y = y;
03234    layers[1].clip_width = width;
03235    layers[1].clip_height = height;
03236    layers[1].bevel = &bevel;
03237    layers[1].merge_scanlines = alphablend_scanlines;
03238 
03239    merge_im = merge_layers(fgVisual, &(layers[0]), 2, fImage->width, fImage->height,
03240                            ASA_ASImage, GetImageCompression(), GetImageQuality());
03241    destroy_asimage(&bevel_im);
03242 
03243    if (!merge_im) {
03244       Warning("Bevel", "Failed to image");
03245       return;
03246    }
03247 
03248    DestroyImage();
03249    fImage = merge_im;
03250    UnZoom();
03251 }
03252 
03253 
03254 //______________________________________________________________________________
03255 void TASImage::Pad(const char *col, UInt_t l, UInt_t r, UInt_t t, UInt_t b)
03256 {
03257    // Enlarge image, padding it with specified color on each side in
03258    // accordance with requested geometry.
03259 
03260    Int_t x, y;
03261    UInt_t w, h;
03262 
03263    if (!InitVisual()) {
03264       Warning("Pad", "Visual not initiated");
03265       return;
03266    }
03267 
03268    if (!fImage) {
03269       fImage = create_asimage(100, 100, 0);
03270 
03271       if (!fImage) {
03272          Warning("Pad", "Failed to create image");
03273          return;
03274       }
03275 
03276       x = 0;
03277       y = 0;
03278       fill_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height, ARGB32_White);
03279    }
03280 
03281    ARGB32 color;
03282    parse_argb_color(col, &color);
03283 
03284    x = l;
03285    y = t;
03286    w = l + fImage->width + r;
03287    h = t + fImage->height + b;
03288 
03289    ASImage *img = pad_asimage(fgVisual, fImage, x, y, w, h, color,
03290                               ASA_ASImage, GetImageCompression(), GetImageQuality());
03291 
03292    if (!img) {
03293       Warning("Pad", "Failed to create output image");
03294       return;
03295    }
03296 
03297    DestroyImage();
03298    fImage = img;
03299    UnZoom();
03300    fZoomUpdate = kZoomOps;
03301 }
03302 
03303 
03304 //______________________________________________________________________________
03305 void TASImage::Crop(Int_t x, Int_t y, UInt_t width, UInt_t height)
03306 {
03307    // Crop an image.
03308 
03309    if (!InitVisual()) {
03310       Warning("Crop", "Visual not initiated");
03311       return;
03312    }
03313 
03314    if (!fImage) {
03315       Warning("Crop", "No image");
03316       return;
03317    }
03318 
03319    x = x < 0 ? 0 : x;
03320    y = y < 0 ? 0 : y;
03321 
03322    width = x + width > fImage->width ? fImage->width - x : width;
03323    height = y + height > fImage->height ? fImage->height - y : height;
03324 
03325    if ((width == fImage->width) && (height == fImage->height)) {
03326       Warning("Crop", "input size larger than image");
03327       return;
03328    }
03329    ASImageDecoder *imdec = start_image_decoding(fgVisual, fImage, SCL_DO_ALL,
03330                                                 x, y, width, height, 0);
03331 
03332    if (!imdec) {
03333       Warning("Crop", "Failed to start image decoding");
03334       return;
03335    }
03336 
03337    ASImage *img = create_asimage(width, height, 0);
03338 
03339    if (!img) {
03340       delete [] imdec;
03341       Warning("Crop", "Failed to create image");
03342       return;
03343    }
03344 
03345    ASImageOutput *imout = start_image_output(fgVisual, img, ASA_ASImage,
03346                                              GetImageCompression(), GetImageQuality());
03347 
03348    if (!imout) {
03349       Warning("Crop", "Failed to start image output");
03350       destroy_asimage(&img);
03351       if (imdec) delete [] imdec;
03352       return;
03353    }
03354 
03355 #ifdef HAVE_MMX
03356    mmx_init();
03357 #endif
03358 
03359    for (UInt_t i = 0; i < height; i++) {
03360       imdec->decode_image_scanline(imdec);
03361       imout->output_image_scanline(imout, &(imdec->buffer), 1);
03362    }
03363 
03364    stop_image_decoding(&imdec);
03365    stop_image_output(&imout);
03366 
03367 #ifdef HAVE_MMX
03368    mmx_off();
03369 #endif
03370 
03371    DestroyImage();
03372    fImage = img;
03373    UnZoom();
03374    fZoomUpdate = kZoomOps;
03375 }
03376 
03377 
03378 //______________________________________________________________________________
03379 void TASImage::Append(const TImage *im, const char *option, const char *color )
03380 {
03381    // Append image.
03382    //
03383    // option:
03384    //       "+" - appends to the right side
03385    //       "/" - appends to the bottom
03386 
03387    if (!im) return;
03388 
03389    if (!InitVisual()) {
03390       Warning("Append", "Visual not initiated");
03391       return;
03392    }
03393 
03394    if (!fImage) {
03395       fImage = ((TASImage*)im)->fImage;
03396       return;
03397    }
03398 
03399    TString opt = option;
03400    opt.Strip();
03401 
03402    UInt_t width = fImage->width;
03403    UInt_t height = fImage->height;
03404 
03405    if (opt == "+") {
03406       Pad(color, 0, im->GetWidth(), 0, 0);
03407       Merge(im, "alphablend", width, 0);
03408    } else if (opt == "/") {
03409       Pad(color, 0, 0, 0, im->GetHeight());
03410       Merge(im, "alphablend", 0, height);
03411    } else {
03412       return;
03413    }
03414 
03415    UnZoom();
03416 }
03417 
03418 
03419 //______________________________________________________________________________
03420 void TASImage::BeginPaint(Bool_t mode)
03421 {
03422    // BeginPaint initializes internal array[width x height] of ARGB32 pixel
03423    // values.
03424    // That provides quick access to image during paint operations.
03425    // To RLE compress image one needs to call EndPaint method when paintinig
03426    // is over.
03427 
03428    if (!InitVisual()) {
03429       Warning("BeginPaint", "Visual not initiated");
03430       return;
03431    }
03432 
03433    if (!fImage) {
03434       return;
03435    }
03436 
03437    fPaintMode = mode;
03438 
03439    if (!fPaintMode || fImage->alt.argb32) {
03440       return;
03441    }
03442 
03443    ASImage *img = tile_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height,
03444                                0, ASA_ARGB32, 0, ASIMAGE_QUALITY_DEFAULT);
03445 
03446    if (!img) {
03447       Warning("BeginPaint", "Failed to create image");
03448       return;
03449    }
03450 
03451    DestroyImage();
03452    fImage = img;
03453 }
03454 
03455 
03456 //______________________________________________________________________________
03457 void TASImage::EndPaint()
03458 {
03459    // EndPaint does internal RLE compression of image data.
03460 
03461    if (!fImage) {
03462       Warning("EndPaint", "no image");
03463       return;
03464    }
03465 
03466    if (!fImage->alt.argb32) return;
03467 
03468    ASImage *img = tile_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height,
03469                                0, ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT);
03470 
03471    if (!img) {
03472       Warning("EndPaint", "Failed to create image");
03473       return;
03474    }
03475 
03476    fPaintMode = kFALSE;
03477    DestroyImage();
03478    fImage = img;
03479 }
03480 
03481 
03482 //______________________________________________________________________________
03483 UInt_t *TASImage::GetArgbArray()
03484 {
03485    // Return a pointer to internal array[width x height] of ARGB32 values
03486    // This array is directly accessible. That allows to manipulate/change the
03487    // image.
03488 
03489    if (!fImage) {
03490       Warning("GetArgbArray", "no image");
03491       return 0;
03492    }
03493 
03494    ASImage *img = fScaledImage ? fScaledImage->fImage : fImage;
03495    if (!img) return 0;
03496 
03497    if (!img->alt.argb32) {
03498       if (fScaledImage) {
03499          fScaledImage->BeginPaint();
03500          img = fScaledImage->fImage;
03501       } else {
03502          BeginPaint();
03503          img = fImage;
03504       }
03505    }
03506 
03507    return (UInt_t *)img->alt.argb32;
03508 }
03509 
03510 
03511 //______________________________________________________________________________
03512 UInt_t *TASImage::GetRgbaArray()
03513 {
03514    // Return a pointer to an array[width x height] of RGBA32 values.
03515    // This array is created from internal ARGB32 array,
03516    // must be deleted after usage.
03517 
03518    if (!fImage) {
03519       Warning("GetRgbaArray", "no image");
03520       return 0;
03521    }
03522 
03523    ASImage *img = fScaledImage ? fScaledImage->fImage : fImage;
03524    if (!img) return 0;
03525 
03526    if (!img->alt.argb32) {
03527       if (fScaledImage) {
03528          fScaledImage->BeginPaint();
03529          img = fScaledImage->fImage;
03530       } else {
03531          BeginPaint();
03532          img = fImage;
03533       }
03534    }
03535 
03536    UInt_t i, j;
03537    Int_t y = 0;
03538    Int_t idx = 0;
03539    UInt_t a, rgb, rgba, argb;
03540    y = 0;
03541 
03542    UInt_t *ret = new UInt_t[img->width*img->height];
03543 
03544    for (i = 0; i < img->height; i++) {
03545       for (j = 0; j < img->width; j++) {
03546          idx = y + j;
03547          argb = img->alt.argb32[idx];
03548          a = argb >> 24;
03549          rgb =  argb & 0x00ffffff;
03550          rgba = (rgb <<  8) + a;
03551          ret[idx] = rgba;
03552       }
03553       y += img->width;
03554    }
03555 
03556    return ret;
03557 }
03558 
03559 
03560 //______________________________________________________________________________
03561 UInt_t *TASImage::GetScanline(UInt_t y)
03562 {
03563    // Return a pointer to scanline.
03564 
03565    if (!fImage) {
03566       Warning("GetScanline", "no image");
03567       return 0;
03568    }
03569 
03570    ASImage *img = fScaledImage ? fScaledImage->fImage : fImage;
03571    CARD32 *ret = new CARD32[img->width];
03572 
03573    ASImageDecoder *imdec = start_image_decoding(fgVisual, img, SCL_DO_ALL,
03574                                                 0, y, img->width, 1, 0);
03575 
03576    if (!imdec) {
03577       delete [] ret;
03578       Warning("GetScanline", "Failed to start image decoding");
03579       return 0;
03580    }
03581 
03582 #ifdef HAVE_MMX
03583    mmx_init();
03584 #endif
03585 
03586    imdec->decode_image_scanline(imdec);
03587    memcpy(imdec->buffer.buffer, ret, img->width*sizeof(CARD32));
03588    stop_image_decoding(&imdec);
03589 
03590 #ifdef HAVE_MMX
03591    mmx_off();
03592 #endif
03593 
03594    return (UInt_t*)ret;
03595 }
03596 
03597 
03598 //______________________________________________________________________________
03599 //
03600 // Vector graphics
03601 // a couple of macros which can be "assembler accelerated"
03602 
03603 #if defined(R__GNU) && defined(__i386__) && !defined(__sun)
03604 #define _MEMSET_(dst, lng, val)   __asm__("movl  %0,%%eax \n"\
03605                                       "movl  %1,%%edi \n"              \
03606                                       "movl  %2,%%ecx \n"              \
03607                                       "cld \n"                         \
03608                                       "rep \n"                         \
03609                                       "stosl %%eax,(%%edi) \n"         \
03610                                       : /* no output registers */      \
03611                                       :"g" (val), "g" (dst), "g" (lng) \
03612                                       :"eax","edi","ecx"               \
03613                                      )
03614 
03615 #else
03616  #define _MEMSET_(dst, lng, val) do {\
03617  for( UInt_t j=0; j < lng; j++) *((dst)+j) = val; } while (0)
03618 
03619 #endif
03620 
03621 #define FillSpansInternal(npt, ppt, widths, color) do {\
03622    UInt_t yy = ppt[0].fY*fImage->width;\
03623    for (UInt_t i = 0; i < npt; i++) {\
03624       _MEMSET_(&fImage->alt.argb32[yy + ppt[i].fX], widths[i], color);\
03625       yy += ((i+1 < npt) && (ppt[i].fY != ppt[i+1].fY) ? fImage->width : 0);\
03626    }\
03627 } while (0)
03628 
03629 
03630 //______________________________________________________________________________
03631 void TASImage::FillRectangleInternal(UInt_t col, Int_t x, Int_t y, UInt_t width, UInt_t height)
03632 {
03633    // Fill rectangle of size (width, height) at position (x,y)
03634    // within the existing image with specified color.
03635 
03636    ARGB32 color = (ARGB32)col;
03637 
03638    if (width  == 0) width = 1;
03639    if (height == 0) height = 1;
03640 
03641    if (x < 0) {
03642       width += x;
03643       x = 0;
03644    }
03645    if (y < 0) {
03646       height += y;
03647       y = 0;
03648    }
03649 
03650    Bool_t has_alpha = (color & 0xff000000) != 0xff000000;
03651 
03652    x = x > (int)fImage->width ? (Int_t)fImage->width : x;
03653    y = y > (int)fImage->height ? (Int_t)fImage->height : y;
03654 
03655    width = x + width > fImage->width ? fImage->width - x : width;
03656    height = y + height > fImage->height ? fImage->height - y : height;
03657 
03658    if (!fImage->alt.argb32) {
03659       fill_asimage(fgVisual, fImage, x, y, width, height, color);
03660    } else {
03661       int yyy = y*fImage->width;
03662       if (!has_alpha) { // use faster memset
03663          ARGB32 *p0 = fImage->alt.argb32 + yyy + x;
03664          ARGB32 *p = p0;
03665          for (UInt_t i = 0; i < height; i++) {
03666             _MEMSET_(p, width, color);
03667             p += fImage->width;
03668          }
03669       } else {
03670          for (UInt_t i = y; i < y + height; i++) {
03671             int j = x + width;
03672             while (j > x) {
03673                j--;
03674                _alphaBlend(&fImage->alt.argb32[yyy + j], &color);
03675             }
03676          }
03677          yyy += fImage->width;
03678       }
03679    }
03680 }
03681 
03682 
03683 //______________________________________________________________________________
03684 void TASImage::FillRectangle(const char *col, Int_t x, Int_t y, UInt_t width, UInt_t height)
03685 {
03686    // Fill rectangle of size (width, height) at position (x,y)
03687    // within the existing image with specified color.
03688    //
03689    // To create new image with Fill method the following code can be used:
03690    //
03691    //  TImage *img = TImage::Create();
03692    //  img->Fill("#FF00FF", 0, 0, 400, 300);
03693 
03694    if (!InitVisual()) {
03695       Warning("Fill", "Visual not initiated");
03696       return;
03697    }
03698 
03699    ARGB32 color = ARGB32_White;
03700 
03701    if (col) {
03702       parse_argb_color(col, &color);
03703    }
03704 
03705    if (!fImage) {
03706       fImage = create_asimage(width ? width : 20, height ? height : 20, 0);
03707       x = 0;
03708       y = 0;
03709    }
03710 
03711    FillRectangleInternal((UInt_t)color, x, y, width, height);
03712    UnZoom();
03713 }
03714 
03715 
03716 //______________________________________________________________________________
03717 void TASImage::DrawVLine(UInt_t x, UInt_t y1, UInt_t y2, UInt_t col, UInt_t thick)
03718 {
03719    // Draw a vertical line.
03720 
03721    ARGB32 color = (ARGB32)col;
03722    UInt_t half = 0;
03723 
03724    if (!thick)  thick = 1;
03725 
03726    if (thick > 1) {
03727       half = thick >> 1;
03728       if (x > half) {
03729          x =  x - half;
03730       } else {
03731          x = 0;
03732          thick += (x - half);
03733       }
03734    }
03735 
03736    y2 = y2 >= fImage->height ? fImage->height - 1 : y2;
03737    y1 = y1 >= fImage->height ? fImage->height - 1 : y1;
03738    x = x + thick >= fImage->width ? fImage->width - thick - 1 : x;
03739 
03740    int yy = y1*fImage->width;
03741    for (UInt_t y = y1; y <= y2; y++) {
03742       for (UInt_t w = 0; w < thick; w++) {
03743          if (x + w < fImage->width) {
03744             _alphaBlend(&fImage->alt.argb32[yy + (x + w)], &color);
03745          }
03746       }
03747       yy += fImage->width;
03748    }
03749 }
03750 
03751 
03752 //______________________________________________________________________________
03753 void TASImage::DrawHLine(UInt_t y, UInt_t x1, UInt_t x2, UInt_t col, UInt_t thick)
03754 {
03755    // Draw an horizontal line.
03756 
03757    ARGB32 color = (ARGB32)col;
03758    UInt_t half = 0;
03759 
03760    if (!thick)  thick = 1;
03761 
03762    if (thick > 1) {
03763       half = thick >> 1;
03764       if (y > half) {
03765          y =  y - half;
03766       } else {
03767          y = 0;
03768          thick += (y - half);
03769       }
03770    }
03771 
03772    y = y + thick >= fImage->height ? fImage->height - thick - 1 : y;
03773    x2 = x2 >= fImage->width ? fImage->width - 1 : x2;
03774    x1 = x1 >= fImage->width ? fImage->width - 1 : x1;
03775 
03776    int yy = y*fImage->width;
03777    for (UInt_t w = 0; w < thick; w++) {
03778       for (UInt_t x = x1; x <= x2; x++) {
03779          if (y + w < fImage->height) {
03780             _alphaBlend(&fImage->alt.argb32[yy + x], &color);
03781          }
03782       }
03783       yy += fImage->width;
03784    }
03785 }
03786 
03787 
03788 //______________________________________________________________________________
03789 void TASImage::DrawLine(UInt_t x1,  UInt_t y1, UInt_t x2, UInt_t y2,
03790                         const char *col, UInt_t thick)
03791 {
03792    // Draw a line.
03793 
03794    ARGB32 color;
03795    parse_argb_color(col, &color);
03796    DrawLineInternal(x1, y1, x2, y2, (UInt_t)color, thick);
03797 }
03798 
03799 
03800 //______________________________________________________________________________
03801 void TASImage::DrawLineInternal(UInt_t x1, UInt_t y1, UInt_t x2, UInt_t y2,
03802                                 UInt_t col, UInt_t thick)
03803 {
03804    // Internal line drawing.
03805 
03806    int dx, dy, d;
03807    int i1, i2;
03808    int x, y, xend, yend;
03809    int xdir, ydir;
03810    int wid, q;
03811    int idx;
03812    int yy;
03813 
03814    if (!InitVisual()) {
03815       Warning("DrawLine", "Visual not initiated");
03816       return;
03817    }
03818 
03819    if (!fImage) {
03820       Warning("DrawLine", "no image");
03821       return;
03822    }
03823 
03824    if (!fImage->alt.argb32) {
03825       BeginPaint();
03826    }
03827 
03828    if (!fImage->alt.argb32) {
03829       Warning("DrawLine", "Failed to get pixel array");
03830       return;
03831    }
03832 
03833    ARGB32 color = (ARGB32)col;
03834 
03835    dx = TMath::Abs(Int_t(x2) - Int_t(x1));
03836    dy = TMath::Abs(Int_t(y2) - Int_t(y1));
03837 
03838    if (!dx) {
03839       DrawVLine(x1, y2 > y1 ? y1 : y2,
03840                     y2 > y1 ? y2 : y1, color, thick);
03841       return;
03842    }
03843 
03844    if (!dy) {
03845       DrawHLine(y1, x2 > x1 ? x1 : x2,
03846                     x2 > x1 ? x2 : x1, color, thick);
03847       return;
03848    }
03849 
03850    if (thick > 1) {
03851       DrawWideLine(x1, y1, x2, y2, color, thick);
03852       return;
03853    }
03854 
03855    wid = 1;
03856 
03857    if (dy <= dx) {
03858       UInt_t ddy = dy << 1;
03859       i1 = ddy;
03860       i2 = i1 - (dx << 1);
03861       d = i1 - dx;
03862 
03863       if (x1 > x2) {
03864          x = x2;
03865          y = y2;
03866          ydir = -1;
03867          xend = x1;
03868       } else {
03869          x = x1;
03870          y = y1;
03871          ydir = 1;
03872          xend = x2;
03873       }
03874 
03875       yy = y*fImage->width;
03876       _alphaBlend(&fImage->alt.argb32[yy + x], &color);
03877       q = (y2 - y1) * ydir;
03878 
03879       if (q > 0) {
03880          while (x < xend) {
03881             idx = yy + x;
03882             _alphaBlend(&fImage->alt.argb32[idx], &color);
03883             x++;
03884 
03885             if (d >= 0) {
03886                yy += fImage->width;
03887                d += i2;
03888             } else {
03889                d += i1;
03890             }
03891          }
03892       } else {
03893          while (x < xend) {
03894             idx = yy + x;
03895             _alphaBlend(&fImage->alt.argb32[idx], &color);
03896             x++;
03897 
03898             if (d >= 0) {
03899                yy -= fImage->width;
03900                d += i2;
03901             } else {
03902                d += i1;
03903             }
03904          }
03905       }
03906    } else {
03907       UInt_t ddx = dx << 1;
03908       i1 = ddx;
03909       i2 = i1 - (dy << 1);
03910       d = i1 - dy;
03911 
03912       if (y1 > y2) {
03913          y = y2;
03914          x = x2;
03915          yend = y1;
03916          xdir = -1;
03917       } else {
03918          y = y1;
03919          x = x1;
03920          yend = y2;
03921          xdir = 1;
03922       }
03923 
03924       yy = y*fImage->width;
03925       _alphaBlend(&fImage->alt.argb32[yy + x], &color);
03926       q = (x2 - x1) * xdir;
03927 
03928       if (q > 0) {
03929          while (y < yend) {
03930             idx = yy + x;
03931             _alphaBlend(&fImage->alt.argb32[idx], &color);
03932             y++;
03933             yy += fImage->width;
03934 
03935             if (d >= 0) {
03936                x++;
03937                d += i2;
03938             } else {
03939                d += i1;
03940             }
03941          }
03942       } else {
03943          while (y < yend) {
03944             idx = yy + x;
03945             _alphaBlend(&fImage->alt.argb32[idx], &color);
03946             y++;
03947             yy += fImage->width;
03948 
03949             if (d >= 0) {
03950                x--;
03951                d += i2;
03952             } else {
03953                d += i1;
03954             }
03955          }
03956       }
03957    }
03958 }
03959 
03960 
03961 //______________________________________________________________________________
03962 void TASImage::DrawRectangle(UInt_t x, UInt_t y, UInt_t w, UInt_t h,
03963                              const char *col, UInt_t thick)
03964 {
03965    // Draw a rectangle.
03966 
03967    if (!InitVisual()) {
03968       Warning("DrawRectangle", "Visual not initiated");
03969       return;
03970    }
03971 
03972    if (!fImage) {
03973       w = w ? w : 20;
03974       h = h ? h : 20;
03975       x = 0;
03976       y = 0;
03977       fImage = create_asimage(w, h, 0);
03978       FillRectangle(col, 0, 0, w, h);
03979       return;
03980    }
03981 
03982    if (!fImage->alt.argb32) {
03983       BeginPaint();
03984    }
03985 
03986    if (!fImage->alt.argb32) {
03987       Warning("DrawRectangle", "Failed to get pixel array");
03988       return;
03989    }
03990 
03991    ARGB32 color;
03992    parse_argb_color(col, &color);
03993 
03994    DrawHLine(y, x, x + w, (UInt_t)color, thick);
03995    DrawVLine(x + w, y, y + h, (UInt_t)color, thick);
03996    DrawHLine(y + h, x, x + w, (UInt_t)color, thick);
03997    DrawVLine(x, y, y + h, (UInt_t)color, thick);
03998    UnZoom();
03999 }
04000 
04001 
04002 //______________________________________________________________________________
04003 void TASImage::DrawBox(Int_t x1, Int_t y1, Int_t x2, Int_t y2, const char *col,
04004                        UInt_t thick, Int_t mode)
04005 {
04006    // Draw a box.
04007 
04008    Int_t x = TMath::Min(x1, x2);
04009    Int_t y = TMath::Min(y1, y2);
04010    Int_t w = TMath::Abs(x2 - x1);
04011    Int_t h = TMath::Abs(y2 - y1);
04012 
04013    ARGB32 color;
04014 
04015    if (!fImage) {
04016       w = w ? x+w : x+20;
04017       h = h ? y+h : y+20;
04018       fImage = create_asimage(w, h, 0);
04019       FillRectangle(col, 0, 0, w, h);
04020       return;
04021    }
04022 
04023    if (x1 == x2) {
04024       parse_argb_color(col, &color);
04025       DrawVLine(x1, y1, y2, color, 1);
04026       return;
04027    }
04028 
04029    if (y1 == y2) {
04030       parse_argb_color(col, &color);
04031       DrawHLine(y1, x1, x2, color, 1);
04032       return;
04033    }
04034 
04035 
04036    switch (mode) {
04037       case TVirtualX::kHollow:
04038          DrawRectangle(x, y, w, h, col, thick);
04039          break;
04040 
04041       case TVirtualX::kFilled:
04042          FillRectangle(col, x, y, w, h);
04043          break;
04044 
04045       default:
04046          FillRectangle(col, x, y, w, h);
04047          break;
04048    }
04049 }
04050 
04051 
04052 //______________________________________________________________________________
04053 void TASImage::DrawDashHLine(UInt_t y, UInt_t x1, UInt_t x2, UInt_t nDash,
04054                              const char *pDash, UInt_t col, UInt_t thick)
04055 {
04056    // Draw a dashed horizontal line.
04057 
04058    UInt_t iDash = 0;    // index of current dash
04059    int i = 0;
04060 
04061    ARGB32 color = (ARGB32)col;
04062 
04063    UInt_t half = 0;
04064 
04065    if (thick > 1) {
04066       half = thick >> 1;
04067       if (y > half) {
04068          y =  y - half;
04069       } else {
04070          y = 0;
04071          thick += (y - half);
04072       }
04073    }
04074    thick = thick <= 0 ? 1 : thick;
04075 
04076    y = y + thick >= fImage->height ? fImage->height - thick - 1 : y;
04077    x2 = x2 >= fImage->width ? fImage->width - 1 : x2;
04078    x1 = x1 >= fImage->width ? fImage->width - 1 : x1;
04079 
04080    // switch x1, x2
04081    UInt_t tmp = x1;
04082    x1 = x2 < x1 ? x2 : x1;
04083    x2 = x2 < tmp ? tmp : x2;
04084 
04085    int yy = y*fImage->width;
04086    for (UInt_t w = 0; w < thick; w++) {
04087       for (UInt_t x = x1; x <= x2; x++) {
04088          if (y + w < fImage->height) {
04089             if ((iDash%2)==0) {
04090                _alphaBlend(&fImage->alt.argb32[yy + x], &color);
04091             }
04092          }
04093          i++;
04094 
04095          if (i >= pDash[iDash]) {
04096             iDash++;
04097             i = 0;
04098          }
04099          if (iDash >= nDash) {
04100             iDash = 0;
04101             i = 0;
04102          }
04103       }
04104       yy += fImage->width;
04105    }
04106 }
04107 
04108 
04109 //______________________________________________________________________________
04110 void TASImage::DrawDashVLine(UInt_t x, UInt_t y1, UInt_t y2, UInt_t nDash,
04111                              const char *pDash, UInt_t col, UInt_t thick)
04112 {
04113    // Draw a dashed vertical line.
04114 
04115    UInt_t iDash = 0;    // index of current dash
04116    int i = 0;
04117 
04118    ARGB32 color = (ARGB32)col;
04119 
04120    UInt_t half = 0;
04121 
04122    if (thick > 1) {
04123       half = thick >> 1;
04124       if (x > half) {
04125          x =  x - half;
04126       } else {
04127          x = 0;
04128          thick += (x - half);
04129       }
04130    }
04131    thick = thick <= 0 ? 1 : thick;
04132 
04133    y2 = y2 >= fImage->height ? fImage->height - 1 : y2;
04134    y1 = y1 >= fImage->height ? fImage->height - 1 : y1;
04135 
04136    // switch x1, x2
04137    UInt_t tmp = y1;
04138    y1 = y2 < y1 ? y2 : y1;
04139    y2 = y2 < tmp ? tmp : y2;
04140 
04141    x = x + thick >= fImage->width ? fImage->width - thick - 1 : x;
04142 
04143    int yy = y1*fImage->width;
04144    for (UInt_t y = y1; y <= y2; y++) {
04145       for (UInt_t w = 0; w < thick; w++) {
04146          if (x + w < fImage->width) {
04147             if ((iDash%2)==0) {
04148                _alphaBlend(&fImage->alt.argb32[yy + (x + w)], &color);
04149             }
04150          }
04151       }
04152       i++;
04153 
04154       if (i >= pDash[iDash]) {
04155          iDash++;
04156          i = 0;
04157       }
04158       if (iDash >= nDash) {
04159          iDash = 0;
04160          i = 0;
04161       }
04162       yy += fImage->width;
04163    }
04164 }
04165 
04166 
04167 //______________________________________________________________________________
04168 void TASImage::DrawDashZLine(UInt_t x1, UInt_t y1, UInt_t x2, UInt_t y2,
04169                              UInt_t nDash, const char *tDash, UInt_t color)
04170 {
04171    // Draw a dashed line with one pixel width.
04172 
04173    int dx, dy, d;
04174    int i, i1, i2;
04175    int x, y, xend, yend;
04176    int xdir, ydir;
04177    int q;
04178    UInt_t iDash = 0;    // index of current dash
04179    int yy;
04180    int idx;
04181 
04182    dx = TMath::Abs(Int_t(x2) - Int_t(x1));
04183    dy = TMath::Abs(Int_t(y2) - Int_t(y1));
04184 
04185    char *pDash = new char[nDash];
04186 
04187    if (dy <= dx) {
04188       double ac = TMath::Cos(TMath::ATan2(dy, dx));
04189 
04190       for (i = 0; i < (int)nDash; i++) {
04191          pDash[i] = TMath::Nint(tDash[i] * ac);
04192       }
04193 
04194       UInt_t ddy = dy << 1;
04195       i1 = ddy;
04196       i2 = i1 - (dx << 1);
04197       d = i1 - dx;
04198       i = 0;
04199 
04200       if (x1 > x2) {
04201          x = x2;
04202          y = y2;
04203          ydir = -1;
04204          xend = x1;
04205       } else {
04206          x = x1;
04207          y = y1;
04208          ydir = 1;
04209          xend = x2;
04210       }
04211 
04212       yy = y*fImage->width;
04213       _alphaBlend(&fImage->alt.argb32[y*fImage->width + x], &color);
04214       q = (y2 - y1) * ydir;
04215 
04216       if (q > 0) {
04217          while (x < xend) {
04218             idx = yy + x;
04219             if ((iDash%2) == 0) {
04220                _alphaBlend(&fImage->alt.argb32[idx], &color);
04221             }
04222             x++;
04223             if (d >= 0) {
04224                yy += fImage->width;
04225                d += i2;
04226             } else {
04227                d += i1;
04228             }
04229 
04230             i++;
04231             if (i >= pDash[iDash]) {
04232                iDash++;
04233                i = 0;
04234             }
04235             if (iDash >= nDash) {
04236                iDash = 0;
04237                i = 0;
04238             }
04239          }
04240       } else {
04241          while (x < xend) {
04242             idx = yy + x;
04243             if ((iDash%2) == 0) {
04244                _alphaBlend(&fImage->alt.argb32[idx], &color);
04245             }
04246             x++;
04247             if (d >= 0) {
04248                yy -= fImage->width;
04249                d += i2;
04250             } else {
04251                d += i1;
04252             }
04253 
04254             i++;
04255             if (i >= pDash[iDash]) {
04256                iDash++;
04257                i = 0;
04258             }
04259             if (iDash >= nDash) {
04260                iDash = 0;
04261                i = 0;
04262             }
04263          }
04264       }
04265    } else {
04266       double as = TMath::Sin(TMath::ATan2(dy, dx));
04267 
04268       for (i = 0; i < (int)nDash; i++) {
04269          pDash[i] = TMath::Nint(tDash[i] * as);
04270       }
04271 
04272       UInt_t ddx = dx << 1;
04273       i1 = ddx;
04274       i2 = i1 - (dy << 1);
04275       d = i1 - dy;
04276       i = 0;
04277 
04278       if (y1 > y2) {
04279          y = y2;
04280          x = x2;
04281          yend = y1;
04282          xdir = -1;
04283       } else {
04284          y = y1;
04285          x = x1;
04286          yend = y2;
04287          xdir = 1;
04288       }
04289 
04290       yy = y*fImage->width;
04291       _alphaBlend(&fImage->alt.argb32[y*fImage->width + x], &color);
04292       q = (x2 - x1) * xdir;
04293 
04294       if (q > 0) {
04295          while (y < yend) {
04296             idx = yy + x;
04297             if ((iDash%2) == 0) {
04298                _alphaBlend(&fImage->alt.argb32[idx], &color);
04299             }
04300             y++;
04301             yy += fImage->width;
04302 
04303             if (d >= 0) {
04304                x++;
04305                d += i2;
04306             } else {
04307                d += i1;
04308             }
04309 
04310             i++;
04311             if (i >= pDash[iDash]) {
04312                iDash++;
04313                i = 0;
04314             }
04315             if (iDash >= nDash) {
04316                iDash = 0;
04317                i = 0;
04318             }
04319          }
04320       } else {
04321          while (y < yend) {
04322             idx = yy + x;
04323             if ((iDash%2) == 0) {
04324                _alphaBlend(&fImage->alt.argb32[idx], &color);
04325             }
04326             y++;
04327             yy += fImage->width;
04328 
04329             if (d >= 0) {
04330                x--;
04331                d += i2;
04332             } else {
04333                d += i1;
04334             }
04335 
04336             i++;
04337             if (i >= pDash[iDash]) {
04338                iDash++;
04339                i = 0;
04340             }
04341             if (iDash >= nDash) {
04342                iDash = 0;
04343                i = 0;
04344             }
04345          }
04346       }
04347    }
04348    delete [] pDash;
04349 }
04350 
04351 
04352 //______________________________________________________________________________
04353 void TASImage::DrawDashZTLine(UInt_t x1, UInt_t y1, UInt_t x2, UInt_t y2,
04354                              UInt_t nDash, const char *tDash, UInt_t color, UInt_t thick)
04355 {
04356    // Draw a dashed line with thick pixel width.
04357 
04358    int dx, dy;
04359    int i;
04360    double x, y, xend=0, yend=0, x0, y0;
04361    int xdir, ydir;
04362    int q;
04363    UInt_t iDash = 0;    // index of current dash
04364 
04365    dx = TMath::Abs(Int_t(x2) - Int_t(x1));
04366    dy = TMath::Abs(Int_t(y2) - Int_t(y1));
04367 
04368    double *xDash = new double[nDash];
04369    double *yDash = new double[nDash];
04370    double a = TMath::ATan2(dy, dx);
04371    double ac = TMath::Cos(a);
04372    double as = TMath::Sin(a);
04373 
04374    for (i = 0; i < (int)nDash; i++) {
04375       xDash[i] = tDash[i] * ac;
04376       yDash[i] = tDash[i] * as;
04377 
04378       // dirty trick (must be fixed)
04379       if ((i%2) == 0) {
04380          xDash[i] = xDash[i]/2;
04381          yDash[i] = yDash[i]/2;
04382       } else {
04383          xDash[i] = xDash[i]*2;
04384          yDash[i] = yDash[i]*2;
04385       }
04386    }
04387 
04388    if (dy <= dx) {
04389       if (x1 > x2) {
04390          x = x2;
04391          y = y2;
04392          ydir = -1;
04393          xend = x1;
04394       } else {
04395          x = x1;
04396          y = y1;
04397          ydir = 1;
04398          xend = x2;
04399       }
04400 
04401       q = (y2 - y1) * ydir;
04402       x0 = x;
04403       y0 = y;
04404       iDash = 0;
04405       yend = y + q;
04406 
04407       if (q > 0) {
04408          while ((x < xend) && (y < yend)) {
04409             x += xDash[iDash];
04410             y += yDash[iDash];
04411 
04412             if ((iDash%2) == 0) {
04413               DrawWideLine(TMath::Nint(x0), TMath::Nint(y0),
04414                            TMath::Nint(x), TMath::Nint(y), color, thick);
04415             } else {
04416                x0 = x;
04417                y0 = y;
04418             }
04419 
04420             iDash++;
04421 
04422             if (iDash >= nDash) {
04423                iDash = 0;
04424             }
04425         }
04426       } else {
04427          while ((x < xend) && (y > yend)) {
04428             x += xDash[iDash];
04429             y -= yDash[iDash];
04430 
04431             if ((iDash%2) == 0) {
04432                DrawWideLine(TMath::Nint(x0), TMath::Nint(y0),
04433                             TMath::Nint(x), TMath::Nint(y), color, thick);
04434             } else {
04435                x0 = x;
04436                y0 = y;
04437             }
04438 
04439             iDash++;
04440 
04441             if (iDash >= nDash) {
04442                iDash = 0;
04443             }
04444          }
04445       }
04446    } else {
04447 
04448       if (y1 > y2) {
04449          y = y2;
04450          x = x2;
04451          yend = y1;
04452          xdir = -1;
04453       } else {
04454          y = y1;
04455          x = x1;
04456          yend = y2;
04457          xdir = 1;
04458       }
04459 
04460       q = (x2 - x1) * xdir;
04461       x0 = x;
04462       y0 = y;
04463       iDash = 0;
04464 
04465       if (q > 0) {
04466          while ((x < xend) && (y < yend)) {
04467             x += xDash[iDash];
04468             y += yDash[iDash];
04469 
04470             if ((iDash%2) == 0) {
04471                DrawWideLine(TMath::Nint(x0), TMath::Nint(y0),
04472                             TMath::Nint(x), TMath::Nint(y), color, thick);
04473             } else {
04474                x0 = x;
04475                y0 = y;
04476             }
04477 
04478             iDash++;
04479 
04480             if (iDash >= nDash) {
04481                iDash = 0;
04482             }
04483          }
04484       } else {
04485          while ((x > xend) && (y < yend)) {
04486             x -= xDash[iDash];
04487             y += yDash[iDash];
04488 
04489             if ((iDash%2) == 0) {
04490                DrawWideLine(TMath::Nint(x0), TMath::Nint(y0),
04491                             TMath::Nint(x), TMath::Nint(y), color, thick);
04492             } else {
04493                x0 = x;
04494                y0 = y;
04495             }
04496 
04497             iDash++;
04498 
04499             if (iDash >= nDash) {
04500                iDash = 0;
04501             }
04502          }
04503       }
04504    }
04505    delete [] xDash;
04506    delete [] yDash;
04507 }
04508 
04509 
04510 //______________________________________________________________________________
04511 void TASImage::DrawDashLine(UInt_t x1,  UInt_t y1, UInt_t x2, UInt_t y2, UInt_t nDash,
04512                             const char *pDash, const char *col, UInt_t thick)
04513 
04514 {
04515    // Draw a dashed line.
04516 
04517    if (!InitVisual()) {
04518       Warning("DrawDashLine", "Visual not initiated");
04519       return;
04520    }
04521 
04522    if (!fImage) {
04523       Warning("DrawDashLine", "no image");
04524       return;
04525    }
04526 
04527    if (!fImage->alt.argb32) {
04528       BeginPaint();
04529    }
04530 
04531    if (!fImage->alt.argb32) {
04532       Warning("DrawDashLine", "Failed to get pixel array");
04533       return;
04534    }
04535 
04536    if ((nDash < 2) || !pDash || (nDash%2)) {
04537       Warning("DrawDashLine", "Wrong input parameters n=%d %ld", nDash, (Long_t)sizeof(pDash)-1);
04538       return;
04539    }
04540 
04541    ARGB32 color;
04542    parse_argb_color(col, &color);
04543 
04544    if (x1 == x2) {
04545       DrawDashVLine(x1, y1, y2, nDash, pDash, (UInt_t)color, thick);
04546    } else if (y1 == y2) {
04547       DrawDashHLine(y1, x1, x2, nDash, pDash, (UInt_t)color, thick);
04548    } else {
04549       if (thick < 2) DrawDashZLine(x1, y1, x2, y2, nDash, pDash, (UInt_t)color);
04550       else DrawDashZTLine(x1, y1, x2, y2, nDash, pDash, (UInt_t)color, thick);
04551    }
04552 }
04553 
04554 
04555 //______________________________________________________________________________
04556 void TASImage::DrawPolyLine(UInt_t nn, TPoint *xy, const char *col, UInt_t thick,
04557                             TImage::ECoordMode mode)
04558 {
04559    // Draw a polyline.
04560 
04561    ARGB32 color;
04562    parse_argb_color(col, &color);
04563 
04564    Int_t x0 = xy[0].GetX();
04565    Int_t y0 = xy[0].GetY();
04566    Int_t x = 0;
04567    Int_t y = 0;
04568 
04569    for (UInt_t i = 1; i < nn; i++) {
04570       x = (mode == kCoordModePrevious) ? x + xy[i].GetX() : xy[i].GetX();
04571       y = (mode == kCoordModePrevious) ? y + xy[i].GetY() : xy[i].GetY();
04572 
04573       DrawLineInternal(x0, y0, x, y, (UInt_t)color, thick);
04574 
04575       x0 = x;
04576       y0 = y;
04577    }
04578 }
04579 
04580 
04581 //______________________________________________________________________________
04582 void TASImage::PutPixel(Int_t x, Int_t y, const char *col)
04583 {
04584    // Draw a point at the specified position.
04585 
04586    if (!InitVisual()) {
04587       Warning("PutPixel", "Visual not initiated");
04588       return;
04589    }
04590 
04591    if (!fImage) {
04592       Warning("PutPixel", "no image");
04593       return;
04594    }
04595 
04596    if (!fImage->alt.argb32) {
04597       BeginPaint();
04598    }
04599 
04600    if (!fImage->alt.argb32) {
04601       Warning("PutPixel", "Failed to get pixel array");
04602       return;
04603    }
04604 
04605    ARGB32 color;
04606    parse_argb_color(col, &color);
04607 
04608    if ((x < 0) || (y < 0) || (x >= (int)fImage->width) || (y >= (int)fImage->height)) {
04609       Warning("PutPixel", "Out of range width=%d x=%d, height=%d y=%d",
04610                fImage->width, x, fImage->height, y);
04611       return;
04612    }
04613    _alphaBlend(&fImage->alt.argb32[y*fImage->width + x], &color);
04614 }
04615 
04616 
04617 //______________________________________________________________________________
04618 void TASImage::PolyPoint(UInt_t npt, TPoint *ppt, const char *col, TImage::ECoordMode mode)
04619 {
04620    // Draw a poly point.
04621 
04622    if (!InitVisual()) {
04623       Warning("PolyPoint", "Visual not initiated");
04624       return;
04625    }
04626 
04627    if (!fImage) {
04628       Warning("PolyPoint", "no image");
04629       return;
04630    }
04631 
04632    if (!fImage->alt.argb32) {
04633       BeginPaint();
04634    }
04635 
04636    if (!fImage->alt.argb32) {
04637       Warning("PolyPoint", "Failed to get pixel array");
04638       return;
04639    }
04640 
04641    if (!npt || !ppt) {
04642       Warning("PolyPoint", "No points specified");
04643       return;
04644    }
04645 
04646    TPoint *ipt = 0;
04647    UInt_t i = 0;
04648    ARGB32 color;
04649    parse_argb_color(col, &color);
04650 
04651    //make pointlist origin relative
04652    if (mode == kCoordModePrevious) {
04653       ipt = new TPoint[npt];
04654 
04655       for (i = 0; i < npt; i++) {
04656          ipt[i].fX += ppt[i].fX;
04657          ipt[i].fY += ppt[i].fY;
04658       }
04659    }
04660    int x, y;
04661 
04662    for (i = 0; i < npt; i++) {
04663       x = ipt ? ipt[i].fX : ppt[i].fX;
04664       y = ipt ? ipt[i].fY : ppt[i].fY;
04665 
04666       if ((x < 0) || (y < 0) || (x >= (int)fImage->width) || (y >= (int)fImage->height)) {
04667          continue;
04668       }
04669       _alphaBlend(&fImage->alt.argb32[y*fImage->width + x], &color);
04670    }
04671 
04672    if (ipt) {
04673       delete [] ipt;
04674    }
04675 }
04676 
04677 
04678 //______________________________________________________________________________
04679 void TASImage::DrawSegments(UInt_t nseg, Segment_t *seg, const char *col, UInt_t thick)
04680 {
04681    // Draw segments.
04682 
04683    if (!nseg || !seg) {
04684       Warning("DrawSegments", "Ivalid data nseg=%d seg=0x%lx", nseg, (Long_t)seg);
04685       return;
04686    }
04687 
04688    TPoint pt[2];
04689 
04690    for (UInt_t i = 0; i < nseg; i++) {
04691       pt[0].fX = seg->fX1;
04692       pt[1].fX = seg->fX2;
04693       pt[0].fY = seg->fY1;
04694       pt[1].fY = seg->fY2;
04695 
04696       DrawPolyLine(2, pt, col, thick, kCoordModeOrigin);
04697       seg++;
04698    }
04699 }
04700 
04701 
04702 //______________________________________________________________________________
04703 void TASImage::FillSpans(UInt_t npt, TPoint *ppt, UInt_t *widths, const char *col,
04704                          const char *stipple, UInt_t w, UInt_t h)
04705 {
04706    // Fill spans with specified color or/and stipple.
04707 
04708    if (!InitVisual()) {
04709       Warning("FillSpans", "Visual not initiated");
04710       return;
04711    }
04712 
04713    if (!fImage) {
04714       Warning("FillSpans", "no image");
04715       return;
04716    }
04717 
04718    if (!fImage->alt.argb32) {
04719       BeginPaint();
04720    }
04721 
04722    if (!fImage->alt.argb32) {
04723       Warning("FillSpans", "Failed to get pixel array");
04724       return;
04725    }
04726 
04727    if (!npt || !ppt || !widths || (stipple && (!w || !h))) {
04728       Warning("FillSpans", "Invalid input data npt=%d ppt=0x%lx col=%s widths=0x%lx stipple=0x%lx w=%d h=%d",
04729               npt, (Long_t)ppt, col, (Long_t)widths, (Long_t)stipple, w, h);
04730       return;
04731    }
04732 
04733    ARGB32 color;
04734    parse_argb_color(col, &color);
04735    Int_t idx = 0;
04736    UInt_t x = 0;
04737    UInt_t yy;
04738 
04739    for (UInt_t i = 0; i < npt; i++) {
04740       yy = ppt[i].fY*fImage->width;
04741       for (UInt_t j = 0; j < widths[i]; j++) {
04742          if ((ppt[i].fX >= (Int_t)fImage->width) || (ppt[i].fX < 0) ||
04743              (ppt[i].fY >= (Int_t)fImage->height) || (ppt[i].fY < 0)) continue;
04744 
04745          x = ppt[i].fX + j;
04746          idx = yy + x;
04747 
04748          if (!stipple) {
04749             _alphaBlend(&fImage->alt.argb32[idx], &color);
04750          } else {
04751             Int_t ii = (ppt[i].fY%h)*w + x%w;
04752 
04753             if (stipple[ii >> 3] & (1 << (ii%8))) {
04754                _alphaBlend(&fImage->alt.argb32[idx], &color);
04755             }
04756          }
04757       }
04758    }
04759 }
04760 
04761 
04762 //______________________________________________________________________________
04763 void TASImage::FillSpans(UInt_t npt, TPoint *ppt, UInt_t *widths, TImage *tile)
04764 {
04765    // Fill spans with tile image.
04766 
04767    if (!InitVisual()) {
04768       Warning("FillSpans", "Visual not initiated");
04769       return;
04770    }
04771 
04772    if (!fImage) {
04773       Warning("FillSpans", "no image");
04774       return;
04775    }
04776 
04777    if (!fImage->alt.argb32) {
04778       BeginPaint();
04779    }
04780 
04781    if (!fImage->alt.argb32) {
04782       Warning("FillSpans", "Failed to get pixel array");
04783       return;
04784    }
04785 
04786    if (!npt || !ppt || !widths || !tile) {
04787       Warning("FillSpans", "Invalid input data npt=%d ppt=0x%lx widths=0x%lx tile=0x%lx",
04788               npt, (Long_t)ppt, (Long_t)widths, (Long_t)tile);
04789       return;
04790    }
04791 
04792    Int_t idx = 0;
04793    Int_t ii = 0;
04794    UInt_t x = 0;
04795    UInt_t *arr = tile->GetArgbArray();
04796    UInt_t xx = 0;
04797    UInt_t yy = 0;
04798    UInt_t yyy = 0;
04799 
04800    for (UInt_t i = 0; i < npt; i++) {
04801       yyy = ppt[i].fY*fImage->width;
04802 
04803       for (UInt_t j = 0; j < widths[i]; j++) {
04804          if ((ppt[i].fX >= (Int_t)fImage->width) || (ppt[i].fX < 0) ||
04805              (ppt[i].fY >= (Int_t)fImage->height) || (ppt[i].fY < 0)) continue;
04806          x = ppt[i].fX + j;
04807          idx = yyy + x;
04808          xx = x%tile->GetWidth();
04809          yy = ppt[i].fY%tile->GetHeight();
04810          ii = yy*tile->GetWidth() + xx;
04811          _alphaBlend(&fImage->alt.argb32[idx], &arr[ii]);
04812       }
04813       yyy += fImage->width;;
04814    }
04815 }
04816 
04817 
04818 //______________________________________________________________________________
04819 void TASImage::CropSpans(UInt_t npt, TPoint *ppt, UInt_t *widths)
04820 {
04821    // Crop spans.
04822 
04823    if (!InitVisual()) {
04824       Warning("CropSpans", "Visual not initiated");
04825       return;
04826    }
04827 
04828    if (!fImage) {
04829       Warning("CropSpans", "no image");
04830       return;
04831    }
04832 
04833    if (!fImage->alt.argb32) {
04834       BeginPaint();
04835    }
04836 
04837    if (!fImage->alt.argb32) {
04838       Warning("CropSpans", "Failed to get pixel array");
04839       return;
04840    }
04841 
04842    if (!npt || !ppt || !widths) {
04843       Warning("CropSpans", "No points specified npt=%d ppt=0x%lx widths=0x%lx", npt, (Long_t)ppt, (Long_t)widths);
04844       return;
04845    }
04846 
04847    int y0 = ppt[0].fY;
04848    int y1 = ppt[npt-1].fY;
04849    UInt_t y = 0;
04850    UInt_t x = 0;
04851    UInt_t i = 0;
04852    UInt_t idx = 0;
04853    UInt_t sz = fImage->width*fImage->height;
04854    UInt_t yy = y*fImage->width;
04855 
04856    for (y = 0; (int)y < y0; y++) {
04857       for (x = 0; x < fImage->width; x++) {
04858          idx = yy + x;
04859          if (idx < sz) fImage->alt.argb32[idx] = 0;
04860       }
04861       yy += fImage->width;
04862    }
04863 
04864    for (i = 0; i < npt; i++) {
04865       for (x = 0; (int)x < ppt[i].fX; x++) {
04866          idx = ppt[i].fY*fImage->width + x;
04867          if (idx < sz) fImage->alt.argb32[idx] = 0;
04868       }
04869       for (x = ppt[i].fX + widths[i] + 1; x < fImage->width; x++) {
04870          idx = ppt[i].fY*fImage->width + x;
04871          if (idx < sz) fImage->alt.argb32[idx] = 0;
04872       }
04873    }
04874 
04875    yy = y1*fImage->width;
04876    for (y = y1; y < fImage->height; y++) {
04877       for (x = 0; x < fImage->width; x++) {
04878          idx = yy + x;
04879          if (idx < sz) fImage->alt.argb32[idx] = 0;
04880       }
04881       yy += fImage->width;
04882    }
04883 }
04884 
04885 
04886 //______________________________________________________________________________
04887 void TASImage::CopyArea(TImage *dst, Int_t xsrc, Int_t ysrc, UInt_t w,  UInt_t h,
04888                         Int_t xdst, Int_t ydst, Int_t gfunc, EColorChan)
04889 {
04890    // Copy source region to the destination image. Copy is done according
04891    // to specified function:
04892    //
04893    // enum EGraphicsFunction {
04894    //    kGXclear = 0,               // 0
04895    //    kGXand,                     // src AND dst
04896    //    kGXandReverse,              // src AND NOT dst
04897    //    kGXcopy,                    // src (default)
04898    //    kGXandInverted,             // NOT src AND dst
04899    //    kGXnoop,                    // dst
04900    //    kGXxor,                     // src XOR dst
04901    //    kGXor,                      // src OR dst
04902    //    kGXnor,                     // NOT src AND NOT dst
04903    //    kGXequiv,                   // NOT src XOR dst
04904    //    kGXinvert,                  // NOT dst
04905    //    kGXorReverse,               // src OR NOT dst
04906    //    kGXcopyInverted,            // NOT src
04907    //    kGXorInverted,              // NOT src OR dst
04908    //    kGXnand,                    // NOT src OR NOT dst
04909    //    kGXset                      // 1
04910    // };
04911 
04912    if (!InitVisual()) {
04913       Warning("CopyArea", "Visual not initiated");
04914       return;
04915    }
04916 
04917    if (!fImage) {
04918       Warning("CopyArea", "no image");
04919       return;
04920    }
04921    if (!dst) return;
04922 
04923    ASImage *out = ((TASImage*)dst)->GetImage();
04924 
04925    int x = 0;
04926    int y = 0;
04927    int idx = 0;
04928    int idx2 = 0;
04929    xsrc = xsrc < 0 ? 0 : xsrc;
04930    ysrc = ysrc < 0 ? 0 : ysrc;
04931 
04932    if ((xsrc >= (int)fImage->width) || (ysrc >= (int)fImage->height)) return;
04933 
04934    w = xsrc + w > fImage->width ? fImage->width - xsrc : w;
04935    h = ysrc + h > fImage->height ? fImage->height - ysrc : h;
04936    UInt_t yy = (ysrc + y)*fImage->width;
04937 
04938    if (!fImage->alt.argb32) {
04939       BeginPaint();
04940    }
04941    if (!out->alt.argb32) {
04942       dst->BeginPaint();
04943       out = ((TASImage*)dst)->GetImage();
04944    }
04945 
04946    if (fImage->alt.argb32 && out->alt.argb32) {
04947       for (y = 0; y < (int)h; y++) {
04948          for (x = 0; x < (int)w; x++) {
04949             idx = yy + x + xsrc;
04950             if ((x + xdst < 0) || (ydst + y < 0) ||
04951                 (x + xdst >= (int)out->width) || (y + ydst >= (int)out->height) ) continue;
04952 
04953             idx2 = (ydst + y)*out->width + x + xdst;
04954 
04955             switch ((EGraphicsFunction)gfunc) {
04956                case kGXclear:
04957                   out->alt.argb32[idx2] = 0;
04958                   break;
04959                case kGXand:
04960                   out->alt.argb32[idx2] &= fImage->alt.argb32[idx];
04961                   break;
04962                case kGXandReverse:
04963                   out->alt.argb32[idx2] = fImage->alt.argb32[idx] & (~out->alt.argb32[idx2]);
04964                   break;
04965                case kGXandInverted:
04966                   out->alt.argb32[idx2] &= ~fImage->alt.argb32[idx];
04967                   break;
04968                case kGXnoop:
04969                   break;
04970                case kGXxor:
04971                   out->alt.argb32[idx2] ^= fImage->alt.argb32[idx];
04972                   break;
04973                case kGXor:
04974                   out->alt.argb32[idx2] |= fImage->alt.argb32[idx];
04975                   break;
04976                case kGXnor:
04977                   out->alt.argb32[idx2] = (~fImage->alt.argb32[idx]) & (~out->alt.argb32[idx2]);
04978                   break;
04979                case kGXequiv:
04980                   out->alt.argb32[idx2] ^= ~fImage->alt.argb32[idx];
04981                   break;
04982                case kGXinvert:
04983                   out->alt.argb32[idx2] = ~out->alt.argb32[idx2];
04984                   break;
04985                case kGXorReverse:
04986                   out->alt.argb32[idx2] = fImage->alt.argb32[idx] | (~out->alt.argb32[idx2]);
04987                   break;
04988                case kGXcopyInverted:
04989                   out->alt.argb32[idx2] = ~fImage->alt.argb32[idx];
04990                   break;
04991                case kGXorInverted:
04992                   out->alt.argb32[idx2] |= ~fImage->alt.argb32[idx];
04993                   break;
04994                case kGXnand:
04995                   out->alt.argb32[idx2] = (~fImage->alt.argb32[idx]) | (~out->alt.argb32[idx2]);
04996                   break;
04997                case kGXset:
04998                   out->alt.argb32[idx2] = 0xFFFFFFFF;
04999                   break;
05000                case kGXcopy:
05001                default:
05002                   out->alt.argb32[idx2] = fImage->alt.argb32[idx];
05003                   break;
05004             }
05005          }
05006          yy += fImage->width;
05007       }
05008    }
05009 }
05010 
05011 
05012 //______________________________________________________________________________
05013 void TASImage::DrawCellArray(Int_t x1, Int_t y1, Int_t x2, Int_t y2, Int_t nx,
05014                              Int_t ny, UInt_t *ic)
05015 {
05016    // Draw a cell array.
05017    // x1,y1        : left down corner
05018    // x2,y2        : right up corner
05019    // nx,ny        : array size
05020    // ic           : array of ARGB32 colors
05021    //
05022    // Draw a cell array. The drawing is done with the pixel presicion
05023    // if (X2-X1)/NX (or Y) is not a exact pixel number the position of
05024    // the top rigth corner may be wrong.
05025 
05026    int i, j, ix, iy, w, h;
05027 
05028    ARGB32 color = 0xFFFFFFFF;
05029    ARGB32 icol;
05030 
05031    w  = TMath::Max((x2-x1)/(nx),1);
05032    h  = TMath::Max((y1-y2)/(ny),1);
05033    ix = x1;
05034 
05035    for (i = 0; i < nx; i++) {
05036       iy = y1 - h;
05037       for (j = 0; j < ny; j++) {
05038          icol = (ARGB32)ic[i + (nx*j)];
05039          if (icol != color) {
05040             color = icol;
05041          }
05042          FillRectangleInternal((UInt_t)color, ix, iy, w, h);
05043          iy = iy - h;
05044       }
05045       ix = ix + w;
05046    }
05047 }
05048 
05049 
05050 //______________________________________________________________________________
05051 UInt_t TASImage::AlphaBlend(UInt_t bot, UInt_t top)
05052 {
05053    // Return alphablended value computed from bottom and top pixel values.
05054 
05055    UInt_t ret = bot;
05056 
05057    _alphaBlend(&ret, &top);
05058    return ret;
05059 }
05060 
05061 
05062 //______________________________________________________________________________
05063 const ASVisual *TASImage::GetVisual()
05064 {
05065    // Return visual.
05066 
05067    return fgVisual;
05068 }
05069 
05070 
05071 //______________________________________________________________________________
05072 static int GetPolyYBounds(TPoint *pts, int n, int *by, int *ty)
05073 {
05074    // Get poly bounds along Y.
05075 
05076    register TPoint *ptMin;
05077    int ymin, ymax;
05078    TPoint *ptsStart = pts;
05079 
05080    ptMin = pts;
05081    ymin = ymax = (pts++)->fY;
05082 
05083    while (--n > 0) {
05084       if (pts->fY < ymin) {
05085          ptMin = pts;
05086          ymin = pts->fY;
05087       }
05088       if (pts->fY > ymax) {
05089          ymax = pts->fY;
05090       }
05091       pts++;
05092     }
05093 
05094     *by = ymin;
05095     *ty = ymax;
05096     return (ptMin - ptsStart);
05097 }
05098 
05099 
05100 //______________________________________________________________________________
05101 Bool_t TASImage::GetPolygonSpans(UInt_t npt, TPoint *ppt, UInt_t *nspans,
05102                                  TPoint **outPoint, UInt_t **outWidth)
05103 {
05104    // The code is based on Xserver/mi/mipolycon.c
05105    //    "Copyright 1987, 1998  The Open Group"
05106 
05107    int xl = 0;                   // x vals of leftedges
05108    int xr = 0;                   // x vals of right edges
05109    int dl = 0;                   // decision variables
05110    int dr = 0;                   // decision variables
05111    int ml = 0;                   // left edge slope
05112    int m1l = 0;                  // left edge slope+1
05113    int mr = 0, m1r = 0;          // right edge slope and slope+1
05114    int incr1l = 0, incr2l = 0;   // left edge error increments
05115    int incr1r = 0, incr2r = 0;   // right edge error increments
05116    int dy;                       // delta y
05117    int y;                        // current scanline
05118    int left, right;              // indices to first endpoints
05119    int i;                        // loop counter
05120    int nextleft, nextright;      // indices to second endpoints
05121    TPoint *ptsOut;               // output buffer
05122    UInt_t *width;                // output buffer
05123    TPoint *firstPoint=0;
05124    UInt_t *firstWidth=0;
05125    int imin;                     // index of smallest vertex (in y)
05126    int ymin;                     // y-extents of polygon
05127    int ymax;
05128    Bool_t  ret = kTRUE;
05129 
05130    *nspans = 0;
05131 
05132    if (!InitVisual()) {
05133       Warning("GetPolygonSpans", "Visual not initiated");
05134       return kFALSE;
05135    }
05136 
05137    if (!fImage) {
05138       Warning("GetPolygonSpans", "no image");
05139       return kFALSE;
05140    }
05141 
05142    if (!fImage->alt.argb32) {
05143       BeginPaint();
05144    }
05145 
05146    if (!fImage->alt.argb32) {
05147       Warning("GetPolygonSpans", "Failed to get pixel array");
05148       return kFALSE;
05149    }
05150 
05151    if ((npt < 3) || !ppt) {
05152       Warning("GetPolygonSpans", "No points specified npt=%d ppt=0x%lx", npt, (Long_t)ppt);
05153       return kFALSE;
05154    }
05155 
05156    //  find leftx, bottomy, rightx, topy, and the index
05157    //  of bottomy. Also translate the points.
05158    imin = GetPolyYBounds(ppt, npt, &ymin, &ymax);
05159 
05160    dy = ymax - ymin + 1;
05161    if ((npt < 3) || (dy < 0)) return kFALSE;
05162 
05163    ptsOut = firstPoint = new TPoint[dy];
05164    width = firstWidth = new UInt_t[dy];
05165    ret = kTRUE;
05166 
05167    nextleft = nextright = imin;
05168    y = ppt[nextleft].fY;
05169 
05170    //  loop through all edges of the polygon
05171    do {
05172       // add a left edge if we need to
05173       if (ppt[nextleft].fY == y) {
05174          left = nextleft;
05175 
05176          //  find the next edge, considering the end
05177          //  conditions of the array.
05178          nextleft++;
05179          if (nextleft >= (int)npt) {
05180             nextleft = 0;
05181          }
05182 
05183          // now compute all of the random information
05184          // needed to run the iterative algorithm.
05185          BRESINITPGON(ppt[nextleft].fY - ppt[left].fY,
05186                       ppt[left].fX, ppt[nextleft].fX,
05187                       xl, dl, ml, m1l, incr1l, incr2l);
05188       }
05189 
05190       // add a right edge if we need to
05191       if (ppt[nextright].fY == y) {
05192          right = nextright;
05193 
05194          // find the next edge, considering the end
05195          // conditions of the array.
05196          nextright--;
05197          if (nextright < 0) {
05198             nextright = npt-1;
05199          }
05200 
05201          //  now compute all of the random information
05202          //  needed to run the iterative algorithm.
05203          BRESINITPGON(ppt[nextright].fY - ppt[right].fY,
05204                       ppt[right].fX, ppt[nextright].fX,
05205                       xr, dr, mr, m1r, incr1r, incr2r);
05206       }
05207 
05208       // generate scans to fill while we still have
05209       //  a right edge as well as a left edge.
05210       i = min(ppt[nextleft].fY, ppt[nextright].fY) - y;
05211 
05212       // in case of non-convex polygon
05213       if (i < 0) {
05214          delete [] firstWidth;
05215          delete [] firstPoint;
05216          return kTRUE;
05217       }
05218 
05219       while (i-- > 0)  {
05220          ptsOut->fY = y;
05221 
05222          // reverse the edges if necessary
05223          if (xl < xr) {
05224             *(width++) = xr - xl;
05225             (ptsOut++)->fX = xl;
05226          } else {
05227             *(width++) = xl - xr;
05228             (ptsOut++)->fX = xr;
05229          }
05230          y++;
05231 
05232          // increment down the edges
05233          BRESINCRPGON(dl, xl, ml, m1l, incr1l, incr2l);
05234          BRESINCRPGON(dr, xr, mr, m1r, incr1r, incr2r);
05235       }
05236    }  while (y != ymax);
05237 
05238    *nspans = UInt_t(ptsOut - firstPoint);
05239    *outPoint = firstPoint;
05240    *outWidth = firstWidth;
05241 
05242    return ret;
05243 }
05244 
05245 
05246 //______________________________________________________________________________
05247 void TASImage::FillPolygon(UInt_t npt, TPoint *ppt, const char *col,
05248                            const char *stipple, UInt_t w, UInt_t h)
05249 {
05250    // Fill a convex polygon with background color or bitmap.
05251    // For non convex polygon one must use DrawFillArea method
05252 
05253    UInt_t  nspans = 0;
05254    TPoint *firstPoint = 0;   // output buffer
05255    UInt_t *firstWidth = 0;   // output buffer
05256 
05257    Bool_t del = GetPolygonSpans(npt, ppt, &nspans, &firstPoint, &firstWidth);
05258    ARGB32 color;
05259    parse_argb_color(col, &color);
05260 
05261    if (nspans) {
05262       if (!stipple && ((color & 0xff000000)==0xff000000)) { //no stipple no alpha
05263          FillSpansInternal(nspans, firstPoint, firstWidth, color);
05264       } else {
05265          FillSpans(nspans, firstPoint, firstWidth, col, stipple, w, h);
05266       }
05267 
05268       if (del) {
05269          delete [] firstWidth;
05270          delete [] firstPoint;
05271       }
05272    } else {
05273       if (firstWidth) delete [] firstWidth;
05274       if (firstPoint) delete [] firstPoint;
05275    }
05276 }
05277 
05278 
05279 //______________________________________________________________________________
05280 void TASImage::FillPolygon(UInt_t npt, TPoint *ppt, TImage *tile)
05281 {
05282    // Fill a convex polygon with background image.
05283    // For non convex polygon one must use DrawFillArea method
05284 
05285    UInt_t  nspans = 0;
05286    TPoint *firstPoint = 0;   // output buffer
05287    UInt_t *firstWidth = 0;   // output buffer
05288 
05289    Bool_t del = GetPolygonSpans(npt, ppt, &nspans, &firstPoint, &firstWidth);
05290 
05291    if (nspans) {
05292       FillSpans(nspans, firstPoint, firstWidth, tile);
05293 
05294       if (del) {
05295          delete [] firstWidth;
05296          delete [] firstPoint;
05297       }
05298    } else {
05299       if (firstWidth) delete [] firstWidth;
05300       if (firstPoint) delete [] firstPoint;
05301    }
05302 }
05303 
05304 
05305 //______________________________________________________________________________
05306 void TASImage::CropPolygon(UInt_t npt, TPoint *ppt)
05307 {
05308    // Crop a convex polygon.
05309 
05310    UInt_t  nspans = 0;
05311    TPoint *firstPoint = 0;
05312    UInt_t *firstWidth = 0;
05313 
05314    Bool_t del = GetPolygonSpans(npt, ppt, &nspans, &firstPoint, &firstWidth);
05315 
05316    if (nspans) {
05317       CropSpans(nspans, firstPoint, firstWidth);
05318 
05319       if (del) {
05320          delete [] firstWidth;
05321          delete [] firstPoint;
05322       }
05323    } else {
05324          if (firstWidth) delete [] firstWidth;
05325          if (firstPoint) delete [] firstPoint;
05326    }
05327 }
05328 
05329 static const UInt_t NUMPTSTOBUFFER = 512;
05330 
05331 
05332 //______________________________________________________________________________
05333 void TASImage::DrawFillArea(UInt_t count, TPoint *ptsIn, const char *col,
05334                            const char *stipple, UInt_t w, UInt_t h)
05335 {
05336    // Fill a polygon (any type convex, non-convex).
05337 
05338    if (!InitVisual()) {
05339       Warning("DrawFillArea", "Visual not initiated");
05340       return;
05341    }
05342 
05343    if (!fImage) {
05344       Warning("DrawFillArea", "no image");
05345       return;
05346    }
05347 
05348    if (!fImage->alt.argb32) {
05349       BeginPaint();
05350    }
05351 
05352    if (!fImage->alt.argb32) {
05353       Warning("DrawFillArea", "Failed to get pixel array");
05354       return;
05355    }
05356 
05357    if ((count < 3) || !ptsIn) {
05358       Warning("DrawFillArea", "No points specified npt=%d ppt=0x%lx", count, (Long_t)ptsIn);
05359       return;
05360    }
05361 
05362    if (count < 5) {
05363       FillPolygon(count, ptsIn, col, stipple, w, h);
05364       return;
05365    }
05366 
05367    ARGB32 color;
05368    parse_argb_color(col, &color);
05369 
05370    EdgeTableEntry *pAET;  // the Active Edge Table
05371    int y;                 // the current scanline
05372    UInt_t nPts = 0;          // number of pts in buffer
05373 
05374    ScanLineList *pSLL;   // Current ScanLineList
05375    TPoint *ptsOut;       // ptr to output buffers
05376    UInt_t *width;
05377    TPoint firstPoint[NUMPTSTOBUFFER];  // the output buffers
05378    UInt_t firstWidth[NUMPTSTOBUFFER];
05379    EdgeTableEntry *pPrevAET;       // previous AET entry
05380    EdgeTable ET;                   // Edge Table header node
05381    EdgeTableEntry AET;             // Active ET header node
05382    EdgeTableEntry *pETEs;          // Edge Table Entries buff
05383    ScanLineListBlock SLLBlock;     // header for ScanLineList
05384    Bool_t del = kTRUE;
05385 
05386    static const UInt_t gEdgeTableEntryCacheSize = 200;
05387    static EdgeTableEntry gEdgeTableEntryCache[gEdgeTableEntryCacheSize];
05388 
05389    if (count < gEdgeTableEntryCacheSize) {
05390       pETEs = (EdgeTableEntry*)&gEdgeTableEntryCache;
05391       del = kFALSE;
05392    } else {
05393       pETEs = new EdgeTableEntry[count];
05394       del = kTRUE;
05395    }
05396 
05397    ptsOut = firstPoint;
05398    width = firstWidth;
05399    CreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock);
05400    pSLL = ET.scanlines.next;
05401 
05402    for (y = ET.ymin; y < ET.ymax; y++) {
05403       if (pSLL && y == pSLL->scanline) {
05404          loadAET(&AET, pSLL->edgelist);
05405          pSLL = pSLL->next;
05406       }
05407       pPrevAET = &AET;
05408       pAET = AET.next;
05409 
05410       while (pAET) {
05411          ptsOut->fX = pAET->bres.minor_axis;
05412          ptsOut->fY = y;
05413          ptsOut++;
05414          nPts++;
05415 
05416          *width++ = pAET->next->bres.minor_axis - pAET->bres.minor_axis;
05417 
05418          if (nPts == NUMPTSTOBUFFER) {
05419             if (!stipple && ((color & 0xff000000)==0xff000000)) { //no stipple, no alpha
05420                FillSpansInternal(nPts, firstPoint, firstWidth, color);
05421             } else {
05422                FillSpans(nPts, firstPoint, firstWidth, col, stipple, w, h);
05423             }
05424             ptsOut = firstPoint;
05425             width = firstWidth;
05426             nPts = 0;
05427          }
05428          EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
05429          EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
05430       }
05431       InsertionSort(&AET);
05432    }
05433 
05434    if (nPts) {
05435       if (!stipple && ((color & 0xff000000)==0xff000000)) {  //no stipple, no alpha
05436          FillSpansInternal(nPts, firstPoint, firstWidth, color);
05437       } else {
05438          FillSpans(nPts, firstPoint, firstWidth, col, stipple, w, h);
05439       }
05440    }
05441 
05442    if (del) delete [] pETEs;
05443    FreeStorage(SLLBlock.next);
05444 }
05445 
05446 
05447 //______________________________________________________________________________
05448 void TASImage::DrawFillArea(UInt_t count, TPoint *ptsIn, TImage *tile)
05449 {
05450    // Fill a polygon (any type convex, non-convex).
05451 
05452    if (!InitVisual()) {
05453       Warning("DrawFillArea", "Visual not initiated");
05454       return;
05455    }
05456 
05457    if (!fImage) {
05458       Warning("DrawFillArea", "no image");
05459       return;
05460    }
05461 
05462    if (!fImage->alt.argb32) {
05463       BeginPaint();
05464    }
05465 
05466    if (!fImage->alt.argb32) {
05467       Warning("DrawFillArea", "Failed to get pixel array");
05468       return;
05469    }
05470 
05471    if ((count < 3) || !ptsIn) {
05472       Warning("DrawFillArea", "No points specified npt=%d ppt=0x%lx", count, (Long_t)ptsIn);
05473       return;
05474    }
05475 
05476    if (count < 5) {
05477       FillPolygon(count, ptsIn, tile);
05478       return;
05479    }
05480 
05481    EdgeTableEntry *pAET;   // the Active Edge Table
05482    int y;                  // the current scanline
05483    UInt_t nPts = 0;       // number of pts in buffer
05484 
05485    ScanLineList *pSLL;    // Current ScanLineList
05486    TPoint *ptsOut;        // ptr to output buffers
05487    UInt_t *width;
05488    TPoint firstPoint[NUMPTSTOBUFFER]; // the output buffers
05489    UInt_t firstWidth[NUMPTSTOBUFFER];
05490    EdgeTableEntry *pPrevAET;       // previous AET entry
05491    EdgeTable ET;                   // Edge Table header node
05492    EdgeTableEntry AET;             // Active ET header node
05493    EdgeTableEntry *pETEs;          // Edge Table Entries buff
05494    ScanLineListBlock SLLBlock;     // header for ScanLineList
05495 
05496    pETEs = new EdgeTableEntry[count];
05497 
05498    ptsOut = firstPoint;
05499    width = firstWidth;
05500    CreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock);
05501    pSLL = ET.scanlines.next;
05502 
05503    for (y = ET.ymin; y < ET.ymax; y++) {
05504       if (pSLL && y == pSLL->scanline) {
05505          loadAET(&AET, pSLL->edgelist);
05506          pSLL = pSLL->next;
05507       }
05508       pPrevAET = &AET;
05509       pAET = AET.next;
05510 
05511       while (pAET) {
05512          ptsOut->fX = pAET->bres.minor_axis;
05513          ptsOut->fY = y;
05514          ptsOut++;
05515          nPts++;
05516 
05517          *width++ = pAET->next->bres.minor_axis - pAET->bres.minor_axis;
05518 
05519          if (nPts == NUMPTSTOBUFFER) {
05520             FillSpans(nPts, firstPoint, firstWidth, tile);
05521             ptsOut = firstPoint;
05522             width = firstWidth;
05523             nPts = 0;
05524          }
05525          EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
05526          EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
05527       }
05528       InsertionSort(&AET);
05529    }
05530    FillSpans(nPts, firstPoint, firstWidth, tile);
05531 
05532    delete [] pETEs;
05533    FreeStorage(SLLBlock.next);
05534 }
05535 
05536 
05537 //______________________________________________________________________________
05538 static ASDrawContext *create_draw_context_argb32(ASImage *im, ASDrawTool *brush)
05539 {
05540    // Create draw context.
05541 
05542    ASDrawContext *ctx = new ASDrawContext;
05543 
05544    ctx->canvas_width = im->width;
05545    ctx->canvas_height = im->height;
05546    ctx->canvas = im->alt.argb32;
05547    ctx->scratch_canvas = 0;
05548 
05549    ctx->flags = ASDrawCTX_CanvasIsARGB;
05550    asim_set_custom_brush_colored( ctx, brush);
05551    return ctx;
05552 }
05553 
05554 
05555 //______________________________________________________________________________
05556 static void destroy_asdraw_context32( ASDrawContext *ctx )
05557 {
05558    // Destroy asdraw context32.
05559 
05560    if (ctx) {
05561       if (ctx->scratch_canvas) free(ctx->scratch_canvas);
05562       delete ctx;
05563    }
05564 }
05565 
05566 static const UInt_t kBrushCacheSize = 20;
05567 static CARD32 gBrushCache[kBrushCacheSize*kBrushCacheSize];
05568 
05569 
05570 //______________________________________________________________________________
05571 void TASImage::DrawWideLine(UInt_t x1, UInt_t y1, UInt_t x2, UInt_t y2,
05572                             UInt_t color, UInt_t thick)
05573 {
05574    // Draw wide line.
05575 
05576    Int_t sz = thick*thick;
05577    CARD32 *matrix;
05578    Bool_t use_cache = thick < kBrushCacheSize;
05579 
05580    if (use_cache) {
05581       matrix = gBrushCache;
05582    } else {
05583       matrix = new CARD32[sz];
05584    }
05585 
05586    for (int i = 0; i < sz; i++) {
05587       matrix[i] = (CARD32)color;
05588    };
05589 
05590    ASDrawTool brush;
05591    brush.matrix = matrix;
05592    brush.width = thick;
05593    brush.height = thick;
05594    brush.center_y = brush.center_x = thick/2;
05595 
05596    ASDrawContext *ctx = create_draw_context_argb32(fImage, &brush);
05597    asim_move_to(ctx, x1, y1);
05598    asim_line_to(ctx, x2, y2);
05599 
05600    if (!use_cache) {
05601       delete [] matrix;
05602    }
05603    destroy_asdraw_context32(ctx);
05604 }
05605 
05606 
05607 //______________________________________________________________________________
05608 void TASImage::DrawGlyph(void *bitmap, UInt_t color, Int_t bx, Int_t by)
05609 {
05610    // Draw glyph bitmap.
05611 
05612    static UInt_t col[5];
05613    Int_t x, y, yy, y0, xx;
05614 
05615    ULong_t r, g, b;
05616    int idx = 0;
05617    FT_Bitmap *source = (FT_Bitmap*)bitmap;
05618    UChar_t d = 0, *s = source->buffer;
05619 
05620    Int_t dots = Int_t(source->width * source->rows);
05621    r = g = b = 0;
05622    Int_t bxx, byy;
05623 
05624    yy = y0 = by > 0 ? by * fImage->width : 0;
05625    for (y = 0; y < (int) source->rows; y++) {
05626       byy = by + y;
05627       if ((byy >= (int)fImage->height) || (byy <0)) continue;
05628 
05629       for (x = 0; x < (int) source->width; x++) {
05630          bxx = bx + x;
05631          if ((bxx >= (int)fImage->width) || (bxx < 0)) continue;
05632 
05633          idx = bxx + yy;
05634          r += ((fImage->alt.argb32[idx] & 0xff0000) >> 16);
05635          g += ((fImage->alt.argb32[idx] & 0x00ff00) >> 8);
05636          b += (fImage->alt.argb32[idx] & 0x0000ff);
05637       }
05638       yy += fImage->width;
05639    }
05640    if (dots != 0) {
05641       r /= dots;
05642       g /= dots;
05643       b /= dots;
05644    }
05645 
05646    col[0] = (r << 16) + (g << 8) + b;
05647    col[4] = color;
05648    Int_t col4r = (col[4] & 0xff0000) >> 16;
05649    Int_t col4g = (col[4] & 0x00ff00) >> 8;
05650    Int_t col4b = (col[4] & 0x0000ff);
05651 
05652    // interpolate between fore and backgound colors
05653    for (x = 3; x > 0; x--) {
05654       xx = 4-x;
05655       Int_t colxr = (col4r*x + r*xx) >> 2;
05656       Int_t colxg = (col4g*x + g*xx) >> 2;
05657       Int_t colxb = (col4b*x + b*xx) >> 2;
05658       col[x] = (colxr << 16) + (colxg << 8) + colxb;
05659    }
05660 
05661    yy = y0;
05662    for (y = 0; y < (int) source->rows; y++) {
05663       byy = by + y;
05664       if ((byy >= (int)fImage->height) || (byy <0)) continue;
05665 
05666       for (x = 0; x < (int) source->width; x++) {
05667          bxx = bx + x;
05668          //if ((bxx >= (int)fImage->width) || (bxx < 0)) continue;
05669 
05670          d = *s++ & 0xff;
05671          d = ((d + 10) * 5) >> 8;
05672          if (d > 4) d = 4;
05673 
05674          if (d && (x < (int) source->width) && (bxx < (int)fImage->width) && (bxx >= 0)) {
05675             idx = bxx + yy;
05676             fImage->alt.argb32[idx] = (ARGB32)col[d];
05677          }
05678       }
05679       yy += fImage->width;
05680    }
05681 }
05682 
05683 
05684 //______________________________________________________________________________
05685 void TASImage::DrawText(TText *text, Int_t x, Int_t y)
05686 {
05687    // Draw text at the pixel position (x,y).
05688 
05689    if (!text)   return;
05690    if (!fImage) return;
05691    if (!gPad)   return;
05692 
05693    if (!InitVisual()) {
05694       Warning("DrawText", "Visual not initiated");
05695       return;
05696    }
05697 
05698    if (!fImage->alt.argb32) {
05699       BeginPaint();
05700    }
05701 
05702    if (!TTF::IsInitialized()) TTF::Init();
05703 
05704    // set text font
05705    TTF::SetTextFont(text->GetTextFont());
05706 
05707    Int_t wh = gPad->XtoPixel(gPad->GetX2());
05708    Int_t hh = gPad->YtoPixel(gPad->GetY1());
05709 
05710    // set text size in pixels
05711    Int_t ttfsize;
05712 
05713    if (wh < hh) {
05714       ttfsize = (Int_t)(text->GetTextSize()*wh);
05715    } else {
05716       ttfsize = (Int_t)(text->GetTextSize()*hh);
05717    }
05718    TTF::SetTextSize(ttfsize);
05719 
05720    // set text angle
05721    TTF::SetRotationMatrix(text->GetTextAngle());
05722 
05723    // set text
05724    TTF::PrepareString(text->GetTitle());
05725    TTF::LayoutGlyphs();
05726 
05727    // color
05728    TColor *col = gROOT->GetColor(text->GetTextColor());
05729    if (!col) { // no color, make it black
05730       col = gROOT->GetColor(1);
05731    }
05732    ARGB32 color;
05733    parse_argb_color(col->AsHexString(), &color);
05734 
05735    // Align()
05736    Int_t align = 0;
05737    Int_t txalh = text->GetTextAlign()/10;
05738    Int_t txalv = text->GetTextAlign()%10;
05739 
05740    switch (txalh) {
05741       case 0 :
05742       case 1 :
05743          switch (txalv) {  //left
05744             case 1 :
05745                align = 7;   //bottom
05746                break;
05747             case 2 :
05748                align = 4;   //center
05749                break;
05750             case 3 :
05751                align = 1;   //top
05752                break;
05753          }
05754          break;
05755       case 2 :
05756          switch (txalv) { //center
05757             case 1 :
05758                align = 8;   //bottom
05759                break;
05760             case 2 :
05761                align = 5;   //center
05762                break;
05763             case 3 :
05764                align = 2;   //top
05765                break;
05766          }
05767          break;
05768       case 3 :
05769          switch (txalv) {  //right
05770             case 1 :
05771                align = 9;   //bottom
05772                break;
05773             case 2 :
05774                align = 6;   //center
05775                break;
05776             case 3 :
05777                align = 3;   //top
05778                break;
05779          }
05780          break;
05781    }
05782 
05783    FT_Vector ftal;
05784 
05785    // vertical alignment
05786    if (align == 1 || align == 2 || align == 3) {
05787       ftal.y = TTF::GetAscent();
05788    } else if (align == 4 || align == 5 || align == 6) {
05789       ftal.y = TTF::GetAscent()/2;
05790    } else {
05791       ftal.y = 0;
05792    }
05793 
05794    // horizontal alignment
05795    if (align == 3 || align == 6 || align == 9) {
05796       ftal.x = TTF::GetWidth();
05797    } else if (align == 2 || align == 5 || align == 8) {
05798       ftal.x = TTF::GetWidth()/2;
05799    } else {
05800       ftal.x = 0;
05801    }
05802 
05803    FT_Vector_Transform(&ftal, TTF::GetRotMatrix());
05804    ftal.x = (ftal.x >> 6);
05805    ftal.y = (ftal.y >> 6);
05806 
05807    TTGlyph *glyph = TTF::GetGlyphs();
05808 
05809    for (int n = 0; n < TTF::GetNumGlyphs(); n++, glyph++) {
05810       if (FT_Glyph_To_Bitmap(&glyph->fImage, ft_render_mode_normal, 0, 1 )) continue;
05811 
05812       FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph->fImage;
05813       FT_Bitmap *source = &bitmap->bitmap;
05814 
05815       Int_t bx = x - ftal.x + bitmap->left;
05816       Int_t by = y + ftal.y - bitmap->top;
05817 
05818       DrawGlyph(source, color, bx, by);
05819    }
05820 }
05821 
05822 
05823 //______________________________________________________________________________
05824 void TASImage::DrawTextTTF(Int_t x, Int_t y, const char *text, Int_t size,
05825                            UInt_t color, const char *font_name, Float_t angle)
05826 {
05827    // Draw text using TrueType fonts.
05828 
05829    if (!TTF::IsInitialized()) TTF::Init();
05830 
05831    TTF::SetTextFont(font_name);
05832    TTF::SetTextSize(size);
05833    TTF::SetRotationMatrix(angle);
05834    TTF::PrepareString(text);
05835    TTF::LayoutGlyphs();
05836 
05837    TTGlyph *glyph = TTF::GetGlyphs();
05838 
05839    // compute the size and position  that will contain the text
05840    Int_t Xoff = 0; if (TTF::GetBox().xMin < 0) Xoff = -TTF::GetBox().xMin;
05841    Int_t Yoff = 0; if (TTF::GetBox().yMin < 0) Yoff = -TTF::GetBox().yMin;
05842    Int_t h    = TTF::GetBox().yMax + Yoff;
05843 
05844    for (int n = 0; n < TTF::GetNumGlyphs(); n++, glyph++) {
05845       if (FT_Glyph_To_Bitmap(&glyph->fImage, ft_render_mode_normal, 0, 1 )) continue;
05846 
05847       FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph->fImage;
05848       FT_Bitmap *source = &bitmap->bitmap;
05849 
05850       Int_t bx = x + bitmap->left;
05851       Int_t by = y + h - bitmap->top;
05852       DrawGlyph(source, color, bx, by);
05853    }
05854 }
05855 
05856 
05857 //______________________________________________________________________________
05858 void TASImage::GetImageBuffer(char **buffer, int *size, EImageFileTypes type)
05859 {
05860    // Return in-memory buffer compressed according image type.
05861    // Buffer must be deallocated after usage.
05862    // This method can be used for sending images over network.
05863 
05864    static ASImageExportParams params;
05865    Bool_t ret = kFALSE;
05866    int   isize = 0;
05867    char *ibuff = 0;
05868    ASImage *img = fScaledImage ? fScaledImage->fImage : fImage;
05869 
05870    if (!img) return;
05871 
05872    switch (type) {
05873       case TImage::kXpm:
05874          ret = ASImage2xpmRawBuff(img, (CARD8 **)buffer, size, 0);
05875          break;
05876       default:
05877          ret = ASImage2PNGBuff(img, (CARD8 **)buffer, size, &params);
05878    }
05879 
05880    if (!ret) {
05881       *size = isize;
05882       *buffer = ibuff;
05883    }
05884 }
05885 
05886 
05887 //______________________________________________________________________________
05888 Bool_t TASImage::SetImageBuffer(char **buffer, EImageFileTypes type)
05889 {
05890    // Create image from compressed buffer.
05891    // Supported formats:
05892    //
05893    //    PNG - by default
05894    //    XPM - two options exist:
05895    //      1.  xpm as a single string (raw buffer). Such string
05896    //          is returned by GetImageBuffer method.
05897    //
05898    //    For example:
05899    //       char *buf;
05900    //       int sz;
05901    //       im1->GetImageBuffer(&buf, &int, TImage::kXpm); /*raw buffer*/
05902    //       TImage *im2 = TImage::Create();
05903    //       im2->SetImageBuffer(&buf, TImage::kXpm);
05904    //
05905    //      2.  xpm as an array of strigs (preparsed)
05906    //
05907    //    For example:
05908    //       char *xpm[] = {
05909    //          "64 28 58 1",
05910    //          "  c #0A030C",
05911    //          ". c #1C171B"
05912    //             ...
05913    //    TImage *im = TImage::Create();
05914    //    im->SetImageBuffer(xpm, TImage::kXpm);
05915 
05916    DestroyImage();
05917 
05918    static ASImageImportParams params;
05919    params.flags = 0;
05920    params.width = 0;
05921    params.height = 0 ;
05922    params.filter = SCL_DO_ALL;
05923    params.gamma = 0;
05924    params.gamma_table = 0;
05925    params.compression = 0;
05926    params.format = ASA_ASImage;
05927    params.search_path = 0;
05928    params.subimage = 0;
05929 
05930    switch (type) {
05931       case TImage::kXpm:
05932       {
05933          char *ptr = buffer[0];
05934          while (isspace((int)*ptr)) ++ptr;
05935          if (atoi(ptr)) {  // preparsed and preloaded data
05936             fImage = xpm_data2ASImage((const char**)buffer, &params);
05937          } else {
05938             fImage = xpmRawBuff2ASImage((const char*)*buffer, &params);
05939          }
05940          break;
05941       }
05942       default:
05943          fImage = PNGBuff2ASimage((CARD8 *)*buffer, &params);
05944          break;
05945    }
05946 
05947    if (!fImage) {
05948       return kFALSE;
05949    }
05950 
05951    if (fName.IsNull()) {
05952       fName.Form("img_%dx%d.%d", fImage->width, fImage->height, gRandom->Integer(1000));
05953    }
05954    UnZoom();
05955    return kTRUE;
05956 }
05957 
05958 
05959 //______________________________________________________________________________
05960 void TASImage::CreateThumbnail()
05961 {
05962    // Create image thumbnail.
05963 
05964    int size;
05965    const int sz = 64;
05966 
05967    if (!fImage) {
05968       return;
05969    }
05970 
05971    if (!InitVisual()) {
05972       return;
05973    }
05974 
05975    static char *buf = 0;
05976    int w, h;
05977    ASImage *img = 0;
05978 
05979    if (fImage->width > fImage->height) {
05980       w = sz;
05981       h = (fImage->height*sz)/fImage->width;
05982    } else {
05983       h = sz;
05984       w = (fImage->width*sz)/fImage->height;
05985    }
05986 
05987    w = w < 8 ? 8 : w;
05988    h = h < 8 ? 8 : h;
05989 
05990    img = scale_asimage(fgVisual, fImage, w, h, ASA_ASImage,
05991                        GetImageCompression(), GetImageQuality());
05992    if (!img) {
05993       return;
05994    }
05995 
05996    // contrasing
05997    ASImage *rendered_im;
05998    ASImageLayer layers[2];
05999    init_image_layers(&(layers[0]), 2);
06000    layers[0].im = img;
06001    layers[0].dst_x = 0;
06002    layers[0].dst_y = 0;
06003    layers[0].clip_width = img->width;
06004    layers[0].clip_height = img->height;
06005    layers[0].bevel = 0;
06006    layers[1].im = img;
06007    layers[1].dst_x = 0;
06008    layers[1].dst_y = 0;
06009    layers[1].clip_width = img->width;
06010    layers[1].clip_height = img->height;
06011    layers[1].merge_scanlines = blend_scanlines_name2func("tint");
06012    rendered_im = merge_layers(fgVisual, &(layers[0]), 2, img->width, img->height,
06013                               ASA_ASImage, GetImageCompression(), GetImageQuality());
06014    destroy_asimage(&img);
06015    img = rendered_im;
06016 
06017    // pad image
06018    ASImage *padimg = 0;
06019    int d = 0;
06020 
06021    if (w == sz) {
06022       d = (sz - h) >> 1;
06023       padimg = pad_asimage(fgVisual, img, 0, d, sz, sz, 0x00ffffff,
06024                            ASA_ASImage, GetImageCompression(), GetImageQuality());
06025    } else {
06026       d = (sz - w) >> 1;
06027       padimg = pad_asimage(fgVisual, img, d, 0, sz, sz, 0x00ffffff,
06028                            ASA_ASImage, GetImageCompression(), GetImageQuality());
06029    }
06030 
06031    if (!padimg) {
06032       destroy_asimage(&img);
06033       return;
06034    }
06035 
06036    void *ptr = &buf;
06037    ASImage2xpmRawBuff(padimg, (CARD8 **)ptr, &size, 0);
06038    fTitle = buf;
06039 
06040    destroy_asimage(&padimg);
06041 }
06042 
06043 
06044 //______________________________________________________________________________
06045 void TASImage::Streamer(TBuffer &b)
06046 {
06047    // Streamer for ROOT I/O.
06048 
06049    Bool_t image_type = 0;
06050    char *buffer = 0;
06051    int size = 0;
06052    int w, h;
06053    UInt_t R__s, R__c;
06054 
06055    if (b.IsReading()) {
06056       Version_t version = b.ReadVersion(&R__s, &R__c);
06057       if (version == 0) { //dumb prototype for scheema evolution
06058          return;
06059       }
06060 
06061       if ( version == 1 ) {
06062          Int_t fileVersion = b.GetVersionOwner();
06063          if (fileVersion > 0 && fileVersion < 50000 ) {
06064             TImage::Streamer(b);
06065             b >> fMaxValue;
06066             b >> fMinValue;
06067             b >> fZoomOffX;
06068             b >> fZoomOffY;
06069             b >> fZoomWidth;
06070             b >> fZoomHeight;
06071             if ( fileVersion < 40200 ) {
06072                Bool_t zoomUpdate;
06073                b >> zoomUpdate;
06074                fZoomUpdate = zoomUpdate;
06075             } else {
06076                b >> fZoomUpdate;
06077                b >> fEditable;
06078                Bool_t paintMode;
06079                b >> paintMode;
06080                fPaintMode = paintMode;
06081             }
06082             b.CheckByteCount(R__s, R__c, TASImage::IsA());
06083             return;
06084          }
06085       }
06086 
06087       TNamed::Streamer(b);
06088       b >> image_type;
06089 
06090       if (image_type != 0) {     // read PNG compressed image
06091          b >> size;
06092          buffer = new char[size];
06093          b.ReadFastArray(buffer, size);
06094          SetImageBuffer(&buffer, TImage::kPng);
06095          delete [] buffer;
06096       } else {                   // read vector with palette
06097          TAttImage::Streamer(b);
06098          b >> w;
06099          b >> h;
06100          size = w*h;
06101          Double_t *vec = new Double_t[size];
06102          b.ReadFastArray(vec, size);
06103          SetImage(vec, w, h, &fPalette);
06104          delete [] vec;
06105       }
06106       b.CheckByteCount(R__s, R__c, TASImage::IsA());
06107    } else {
06108       if (!fImage) {
06109          return;
06110       }
06111       R__c = b.WriteVersion(TASImage::IsA(), kTRUE);
06112 
06113       if (fName.IsNull()) {
06114          fName.Form("img_%dx%d.%d", fImage->width, fImage->height, gRandom->Integer(1000));
06115       }
06116       TNamed::Streamer(b);
06117 
06118       image_type = fImage->alt.vector ? 0 : 1;
06119       b << image_type;
06120 
06121       if (image_type != 0) {     // write PNG compressed image
06122          GetImageBuffer(&buffer, &size, TImage::kPng);
06123          b << size;
06124          b.WriteFastArray(buffer, size);
06125          delete buffer;
06126       } else {                   // write vector  with palette
06127          TAttImage::Streamer(b);
06128          b << fImage->width;
06129          b << fImage->height;
06130          b.WriteFastArray(fImage->alt.vector, fImage->width*fImage->height);
06131       }
06132       b.SetByteCount(R__c, kTRUE);
06133    }
06134 }
06135 
06136 
06137 //______________________________________________________________________________
06138 void TASImage::Browse(TBrowser *)
06139 {
06140    // Browse image.
06141 
06142    if (fImage->alt.vector) {
06143       Draw("n");
06144    } else {
06145       Draw("nxxx");
06146    }
06147    CreateThumbnail();
06148 }
06149 
06150 
06151 //______________________________________________________________________________
06152 const char *TASImage::GetTitle() const
06153 {
06154    // Title is used to keep 32x32 xpm image's thumbnail.
06155 
06156    if (!gDirectory || !gDirectory->IsWritable()) {
06157       return 0;
06158    }
06159 
06160    TASImage *mutble = (TASImage *)this;
06161 
06162    if (fTitle.IsNull()) {
06163       mutble->SetTitle(fName.Data());
06164    }
06165 
06166    return fTitle.Data();
06167 }
06168 
06169 
06170 //______________________________________________________________________________
06171 void TASImage::SetTitle(const char *title)
06172 {
06173    // Set a title for an image.
06174 
06175    if (fTitle.IsNull()) {
06176       CreateThumbnail();
06177    }
06178 
06179    if (fTitle.IsNull()) {
06180       return;
06181    }
06182 
06183    int start = fTitle.Index("/*") + 3;
06184    int stop = fTitle.Index("*/") - 1;
06185 
06186    if ((start > 0) && (stop - start > 0)) {
06187       fTitle.Replace(start, stop - start, title);
06188    }
06189 }
06190 
06191 
06192 //______________________________________________________________________________
06193 void TASImage::DrawCubeBezier(Int_t x1, Int_t y1, Int_t x2, Int_t y2,
06194                              Int_t x3, Int_t y3, const char *col, UInt_t thick)
06195 {
06196    // Draw a cubic bezier line.
06197 
06198    Int_t sz = thick*thick;
06199    CARD32 *matrix;
06200    Bool_t use_cache = thick < kBrushCacheSize;
06201 
06202    ARGB32 color;
06203    parse_argb_color(col, &color);
06204 
06205    if (use_cache) {
06206       matrix = gBrushCache;
06207    } else {
06208       matrix = new CARD32[sz];
06209    }
06210 
06211    for (int i = 0; i < sz; i++) {
06212       matrix[i] = (CARD32)color;
06213    };
06214 
06215    ASDrawTool brush;
06216    brush.matrix = matrix;
06217    brush.width = thick;
06218    brush.height = thick;
06219    brush.center_y = brush.center_x = thick/2;
06220 
06221    ASDrawContext *ctx = 0;
06222 
06223    ctx = create_draw_context_argb32(fImage, &brush);
06224    asim_cube_bezier(ctx, x1, y1, x2, y2, x3, y3);
06225 
06226    if (!use_cache) {
06227       delete [] matrix;
06228    }
06229    destroy_asdraw_context32(ctx);
06230 }
06231 
06232 
06233 //______________________________________________________________________________
06234 void TASImage::DrawStraightEllips(Int_t x, Int_t y, Int_t rx, Int_t ry,
06235                                   const char *col, Int_t thick)
06236 {
06237    // Draw a straight ellipse.
06238    // If thick < 0 - draw filled ellipse.
06239 
06240    thick = !thick ? 1 : thick;
06241    Int_t sz = thick*thick;
06242    CARD32 *matrix;
06243    Bool_t use_cache = (thick > 0) && ((UInt_t)thick < kBrushCacheSize);
06244 
06245    ARGB32 color;
06246    parse_argb_color(col, &color);
06247 
06248    if (use_cache) {
06249       matrix = gBrushCache;
06250    } else {
06251       matrix = new CARD32[sz];
06252    }
06253 
06254    for (int i = 0; i < sz; i++) {
06255       matrix[i] = (CARD32)color;
06256    };
06257 
06258    ASDrawTool brush;
06259    brush.matrix = matrix;
06260    brush.width = thick > 0 ? thick : 1;
06261    brush.height = thick > 0 ? thick : 1;
06262    brush.center_y = brush.center_x = thick > 0 ? thick/2 : 0;
06263 
06264    ASDrawContext *ctx = create_draw_context_argb32(fImage, &brush);
06265    asim_straight_ellips(ctx, x, y, rx, ry, thick < 0);
06266 
06267    if (!use_cache) {
06268       delete [] matrix;
06269    }
06270    destroy_asdraw_context32(ctx);
06271 }
06272 
06273 
06274 //______________________________________________________________________________
06275 void TASImage::DrawCircle(Int_t x, Int_t y, Int_t r, const char *col, Int_t thick)
06276 {
06277    // Draw a circle.
06278    // If thick < 0 - draw filled circle
06279 
06280    thick = !thick ? 1 : thick;
06281    Int_t sz = thick*thick;
06282    CARD32 *matrix;
06283    Bool_t use_cache = (thick > 0) && ((UInt_t)thick < kBrushCacheSize);
06284 
06285    ARGB32 color;
06286    parse_argb_color(col, &color);
06287 
06288 ///matrix = new CARD32[sz];
06289    if (use_cache) {
06290       matrix = gBrushCache;
06291    } else {
06292       matrix = new CARD32[sz];
06293    }
06294 
06295    for (int i = 0; i < sz; i++) {
06296       matrix[i] = (CARD32)color;
06297    }
06298 
06299    ASDrawTool brush;
06300    brush.matrix = matrix;
06301    brush.height = brush.width = thick > 0 ? thick : 1;
06302    brush.center_y = brush.center_x = thick > 0 ? thick/2 : 0;
06303 
06304    ASDrawContext *ctx = create_draw_context_argb32(fImage, &brush);
06305    asim_circle(ctx, x,  y, r, thick < 0);
06306 
06307 ///free (matrix);
06308    if (!use_cache) {
06309       delete [] matrix;
06310    }
06311    destroy_asdraw_context32(ctx);
06312 }
06313 
06314 
06315 //______________________________________________________________________________
06316 void TASImage::DrawEllips(Int_t x, Int_t y, Int_t rx, Int_t ry, Int_t angle,
06317                            const char *col, Int_t thick)
06318 {
06319    // Draw an ellipse.
06320    // If thick < 0 - draw filled ellips
06321 
06322    thick = !thick ? 1 : thick;
06323    Int_t sz = thick*thick;
06324    CARD32 *matrix;
06325    Bool_t use_cache = (thick > 0) && ((UInt_t)thick < kBrushCacheSize);
06326 
06327    ARGB32 color;
06328    parse_argb_color(col, &color);
06329 
06330    if (use_cache) {
06331       matrix = gBrushCache;
06332    } else {
06333       matrix = new CARD32[sz];
06334    }
06335 
06336    for (int i = 0; i < sz; i++) {
06337       matrix[i] = (CARD32)color;
06338    };
06339 
06340    ASDrawTool brush;
06341    brush.matrix = matrix;
06342    brush.width = thick > 0 ? thick : 1;
06343    brush.height = thick > 0 ? thick : 1;
06344    brush.center_y = brush.center_x = thick > 0 ? thick/2 : 0;
06345 
06346    ASDrawContext *ctx = create_draw_context_argb32(fImage, &brush);
06347    asim_ellips(ctx, x, y, rx, ry, angle, thick < 0);
06348 
06349    if (!use_cache) {
06350       delete [] matrix;
06351    }
06352    destroy_asdraw_context32(ctx);
06353 }
06354 
06355 
06356 //______________________________________________________________________________
06357 void TASImage::DrawEllips2(Int_t x, Int_t y, Int_t rx, Int_t ry, Int_t angle,
06358                            const char *col, Int_t thick)
06359 {
06360    // Draw an ellipse.
06361    // If thick < 0 - draw filled ellipse.
06362 
06363    thick = !thick ? 1 : thick;
06364    Int_t sz = thick*thick;
06365    CARD32 *matrix;
06366    Bool_t use_cache = (thick > 0) && ((UInt_t)thick < kBrushCacheSize);
06367 
06368    ARGB32 color;
06369    parse_argb_color(col, &color);
06370 
06371    if (use_cache) {
06372       matrix = gBrushCache;
06373    } else {
06374       matrix = new CARD32[sz];
06375    }
06376 
06377    for (int i = 0; i < sz; i++) {
06378       matrix[i] = (CARD32)color;
06379    };
06380 
06381    ASDrawTool brush;
06382    brush.matrix = matrix;
06383    brush.width = thick > 0 ? thick : 1;
06384    brush.height = thick > 0 ? thick : 1;
06385    brush.center_y = brush.center_x = thick > 0 ? thick/2 : 0;
06386 
06387    ASDrawContext *ctx = create_draw_context_argb32(fImage, &brush);
06388    asim_ellips2(ctx, x, y, rx, ry, angle, thick < 0);
06389 
06390    if (!use_cache) {
06391       delete [] matrix;
06392    }
06393    destroy_asdraw_context32(ctx);
06394 }
06395 
06396 
06397 //______________________________________________________________________________
06398 void TASImage::FloodFill(Int_t /*x*/, Int_t /*y*/, const char * /*col*/,
06399                          const char * /*minc*/, const char * /*maxc*/)
06400 {
06401    // Flood fill.
06402 }
06403 
06404 
06405 //______________________________________________________________________________
06406 void TASImage::Gray(Bool_t on)
06407 {
06408    // Convert RGB image to Gray image and vice versa.
06409 
06410    if (fIsGray == on) {
06411       return;
06412    }
06413 
06414    if (!IsValid()) {
06415       Warning("Gray", "Image not initiated");
06416       return;
06417    }
06418 
06419    if (!InitVisual()) {
06420       Warning("Gray", "Visual not initiated");
06421       return;
06422    }
06423 
06424    if (!fGrayImage && !on) {
06425       return;
06426    }
06427    ASImage *sav = 0;
06428    delete fScaledImage;
06429    fScaledImage = 0;
06430 
06431    if (fGrayImage)  {
06432       sav = fImage;
06433       fImage = fGrayImage;
06434       fGrayImage = sav;
06435       fIsGray = on;
06436       return;
06437    }
06438 
06439    if (!on) return;
06440 
06441    UInt_t l, r, g, b, idx;
06442    int y = 0;
06443    UInt_t i, j;
06444 
06445    if (fImage->alt.argb32) {
06446       fGrayImage = tile_asimage(fgVisual, fImage, 0, 0, fImage->width, fImage->height,
06447                                 0, ASA_ARGB32, 0, ASIMAGE_QUALITY_DEFAULT);
06448 
06449       for (i = 0; i < fImage->height; i++) {
06450          for (j = 0; j < fImage->width; j++) {
06451             idx = y + j;
06452 
06453             r = ((fImage->alt.argb32[idx] & 0xff0000) >> 16);
06454             g = ((fImage->alt.argb32[idx] & 0x00ff00) >> 8);
06455             b = (fImage->alt.argb32[idx] & 0x0000ff);
06456             l = (57*r + 181*g + 18*b)/256;
06457             fGrayImage->alt.argb32[idx] = (l << 16) + (l << 8) + l;
06458          }
06459          y += fImage->width;
06460       }
06461    } else {
06462       fGrayImage = create_asimage(fImage->width, fImage->height, 0);
06463 
06464       ASImageDecoder *imdec = start_image_decoding(fgVisual, fImage, SCL_DO_ALL,
06465                                                    0, 0, fImage->width, fImage->height, 0);
06466 
06467       if (!imdec) {
06468          return;
06469       }
06470 #ifdef HAVE_MMX
06471    mmx_init();
06472 #endif
06473       ASImageOutput *imout = start_image_output(fgVisual, fGrayImage, ASA_ASImage,
06474                                                 GetImageCompression(), GetImageQuality());
06475       if (!imout) {
06476          Warning("ToGray", "Failed to start image output");
06477          delete fScaledImage;
06478          fScaledImage = 0;
06479          delete [] imdec;
06480          return;
06481       }
06482 
06483       CARD32 *aa = imdec->buffer.alpha;
06484       CARD32 *rr = imdec->buffer.red;
06485       CARD32 *gg = imdec->buffer.green;
06486       CARD32 *bb = imdec->buffer.blue;
06487 
06488       ASScanline result;
06489       ASScanline *sl = prepare_scanline(fImage->width, 0, &result, fgVisual->BGR_mode);
06490       if (sl) delete sl;
06491 
06492       for (i = 0; i < fImage->height; i++) {
06493          imdec->decode_image_scanline(imdec);
06494          result.flags = imdec->buffer.flags;
06495          result.back_color = imdec->buffer.back_color;
06496 
06497          for (j = 0; j < fImage->width; j++) {
06498             l = (57*rr[j] + 181*gg[j]+ 18*bb[j])/256;
06499             result.alpha[j] = aa[j];
06500             result.red[j] = l;
06501             result.green[j] = l;
06502             result.blue[j] = l;
06503          }
06504          imout->output_image_scanline(imout, &result, 1);
06505       }
06506 
06507       stop_image_decoding(&imdec);
06508       stop_image_output(&imout);
06509 #ifdef HAVE_MMX
06510    mmx_off();
06511 #endif
06512    }
06513 
06514    sav = fImage;
06515    fImage = fGrayImage;
06516    fGrayImage = sav;
06517    fIsGray = kTRUE;
06518 }
06519 
06520 
06521 //______________________________________________________________________________
06522 void TASImage::FromWindow(Drawable_t wid, Int_t x, Int_t y, UInt_t w, UInt_t h)
06523 {
06524    // Create an image (screenshot) from specified window.
06525 
06526    Int_t xy;
06527 
06528    x = x < 0 ? 0 : x;
06529    y = y < 0 ? 0 : y;
06530 
06531    // syncronization
06532    gVirtualX->Update(1);
06533    if (!gThreadXAR) {
06534       gSystem->ProcessEvents();
06535       gSystem->Sleep(10);
06536       gSystem->ProcessEvents();
06537    }
06538 
06539    if (!w || !h) {
06540       gVirtualX->GetWindowSize(wid, xy, xy, w, h);
06541    }
06542 
06543    if ((x >= (Int_t)w) || (y >= (Int_t)h)) {
06544       return;
06545    }
06546 
06547    if (!InitVisual()) {
06548       Warning("FromWindow", "Visual not initiated");
06549       return;
06550    }
06551 
06552    DestroyImage();
06553    delete fScaledImage;
06554    fScaledImage = 0;
06555 
06556    static int x11 = -1;
06557    if (x11 < 0) x11 = gVirtualX->InheritsFrom("TGX11");
06558 
06559    if (x11) { //use built-in optimized version
06560       fImage = pixmap2asimage(fgVisual, wid, x, y, w, h, kAllPlanes, 0, 0);
06561    } else {
06562       unsigned char *bits = gVirtualX->GetColorBits(wid, 0, 0, w, h);
06563 
06564       if (!bits) { // error
06565          return;
06566       }
06567       fImage = bitmap2asimage(bits, w, h, 0, 0);
06568       delete [] bits;
06569    }
06570 }
06571 
06572 
06573 //______________________________________________________________________________
06574 void TASImage::FromGLBuffer(UChar_t* buf, UInt_t w, UInt_t h)
06575 {
06576    // Creates an image (screenshot) from a RGBA buffer.
06577 
06578    DestroyImage();
06579    delete fScaledImage;
06580    fScaledImage = 0;
06581 
06582    UChar_t* xx = new UChar_t[4*w];
06583    for (UInt_t i = 0; i < h/2; ++i) {
06584       memcpy(xx, buf + 4*w*i, 4*w);
06585       memcpy(buf + 4*w*i, buf + 4*w*(h-i-1), 4*w);
06586       memcpy(buf + 4*w*(h-i-1), xx, 4*w);
06587    }
06588    delete [] xx;
06589 
06590    fImage = bitmap2asimage(buf, w, h, 0, 0);
06591 }
06592 
06593 
06594 //______________________________________________________________________________
06595 void TASImage::SetPaletteEnabled(Bool_t on)
06596 {
06597    // Switch on/off the image palette.
06598    // That also invokes calling vectorization of image.
06599 
06600    if (!fImage) {
06601       return;
06602    }
06603 
06604    if (!fImage->alt.vector && on) {
06605       Vectorize();
06606    }
06607    fPaletteEnabled = on;
06608 
06609    if (on) {
06610       Double_t left = gPad->GetLeftMargin();
06611       Double_t right = gPad->GetRightMargin();
06612       Double_t top = gPad->GetTopMargin();
06613       Double_t bottom = gPad->GetBottomMargin();
06614 
06615       gPad->Range(-left / (1.0 - left - right),
06616                   -bottom / (1.0 - top - bottom),
06617                   1 + right / (1.0 - left - right),
06618                   1 + top / ( 1.0 - top - bottom));
06619       gPad->RangeAxis(0, 0, 1, 1);
06620    }
06621 
06622 }
06623 
06624 
06625 //______________________________________________________________________________
06626 void TASImage::SavePrimitive(ostream &out, Option_t * /*= ""*/)
06627 {
06628     // Save a primitive as a C++ statement(s) on output stream "out".
06629 
06630    char *buf;
06631    int sz;
06632 
06633    UInt_t w = GetWidth();
06634    UInt_t h = GetHeight();
06635 
06636    if (w > 500) { // workarond CINT limitations
06637       w = 500;
06638       Double_t scale = 500./GetWidth();
06639       h = TMath::Nint(GetHeight()*scale);
06640       Scale(w, h);
06641    }
06642 
06643    GetImageBuffer(&buf, &sz, TImage::kXpm);
06644 
06645    TString name = GetName();
06646    name.ReplaceAll(".", "_");
06647    TString str = buf;
06648    static int ii = 0;
06649    ii++;
06650 
06651    str.ReplaceAll("static", "");
06652    TString xpm = "xpm_";
06653    xpm += name;
06654    xpm += ii;
06655    str.ReplaceAll("asxpm", xpm.Data());
06656    out << endl << str << endl << endl;
06657    out << "   TImage *";
06658    out << name << " = TImage::Create();" << endl;
06659    out << "   " << name << "->SetImageBuffer(" << xpm << ", TImage::kXpm);" << endl;
06660    out << "   " << name << "->Draw();" << endl;
06661 }
06662 
06663 
06664 //______________________________________________________________________________
06665 Bool_t TASImage::SetJpegDpi(const char *name, UInt_t set)
06666 {
06667    // Set an image printing resolution in Dots Per Inch units.
06668    // name - the name of jpeg file.
06669    // set - dpi resolution.
06670    // Returns kFALSE in case of error.
06671 
06672    static char buf[32];
06673    FILE *fp = fopen(name, "rb+");
06674 
06675    if (!fp) {
06676       printf("file %s : failed to open\n", name);
06677       return kFALSE;
06678    }
06679 
06680    if (!fread(buf, 1, 20, fp)) {
06681       fclose(fp);
06682       return kFALSE;
06683    }
06684 
06685    char dpi1 = (set & 0xffff) >> 8;
06686    char dpi2 = set & 0xff;
06687 
06688    int i = 0;
06689 
06690    int dpi = 0; // start of dpi data
06691    for (i = 0; i < 20; i++) {
06692       if ((buf[i] == 0x4a) && (buf[i+1] == 0x46) &&  (buf[i+2] == 0x49) &&
06693           (buf[i+3] == 0x46) && (buf[i+4] == 0x00) ) {
06694          dpi = i + 7;
06695          break;
06696       }
06697    }
06698 
06699    if (i == 20 || dpi+4 >= 20) { // jpeg maker was not found
06700       fclose(fp);
06701       printf("file %s : wrong JPEG format\n", name);
06702       return kFALSE;
06703    }
06704 
06705    buf[dpi] = 1;   // format specified in  dots per inch
06706 
06707    // set x density in dpi units
06708    buf[dpi + 1] = dpi1;
06709    buf[dpi + 2] = dpi2;
06710 
06711    // set y density in dpi units
06712    buf[dpi + 3] = dpi1;
06713    buf[dpi + 4] = dpi2;
06714 
06715    rewind(fp);
06716    fwrite(buf, 1, 20, fp);
06717    fclose(fp);
06718 
06719    return kTRUE;
06720 }

Generated on Tue Jul 5 14:13:33 2011 for ROOT_528-00b_version by  doxygen 1.5.1