diff --git a/core/base/inc/TVirtualX.h b/core/base/inc/TVirtualX.h index de2c1b3c5c99b..70a0884432bec 100644 --- a/core/base/inc/TVirtualX.h +++ b/core/base/inc/TVirtualX.h @@ -123,6 +123,7 @@ class TVirtualX : public TNamed, public TAttLine, public TAttFill, public TAttTe virtual void DrawPolyMarkerW(WinContext_t wctxt, Int_t n, TPoint *xy); virtual void DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Float_t mgn, const char *text, ETextMode mode); virtual void DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Float_t mgn, const wchar_t *text, ETextMode mode); + virtual Int_t WriteGIFW(WinContext_t wctxt, const char *name); //---- OpenGL related stuff, required only with R__HAS_COCOA ---- diff --git a/core/base/src/TVirtualX.cxx b/core/base/src/TVirtualX.cxx index f4e05e3f07b5f..1fbf1e8616d37 100644 --- a/core/base/src/TVirtualX.cxx +++ b/core/base/src/TVirtualX.cxx @@ -540,6 +540,14 @@ void TVirtualX::DrawTextW(WinContext_t /* wctxt */, Int_t x, Int_t y, Float_t an DrawText(x, y, angle, mgn, text, mode); } +//////////////////////////////////////////////////////////////////////////////// +/// Save specified window as GIF image + +Int_t TVirtualX::WriteGIFW(WinContext_t /* wctxt */, const char *name) +{ + return WriteGIF((char *) name); +} + //////////////////////////////////////////////////////////////////////////////// /// Executes the command "code" coming from the other threads (Win32) diff --git a/graf2d/asimage/src/TASImage.cxx b/graf2d/asimage/src/TASImage.cxx index dedeff20eb1f7..01a937db61104 100644 --- a/graf2d/asimage/src/TASImage.cxx +++ b/graf2d/asimage/src/TASImage.cxx @@ -2231,8 +2231,6 @@ Bool_t TASImage::InitVisual() if (fgVisual && (noX == fgBatch)) return kTRUE; - if (fgVisual) - destroy_asvisual(fgVisual, kFALSE); fgVisual = nullptr; fgBatch = false; @@ -2244,16 +2242,27 @@ Bool_t TASImage::InitVisual() Visual *vis = (Visual*) gVirtualX->GetVisual(); Colormap cmap = (Colormap) gVirtualX->GetColormap(); - if (vis && cmap) - fgVisual = create_asvisual_for_id(disp, screen, depth, + static ASVisual *vis_x = nullptr; + + if (vis && cmap && !noX) { + if (!vis_x) + vis_x = create_asvisual_for_id(disp, screen, depth, XVisualIDFromVisual(vis), cmap, nullptr); + fgVisual = vis_x; + } #endif #endif + static ASVisual *vis_batch = nullptr; + if (!fgVisual) { - // create dummy fgVisual for batch mode - fgVisual = create_asvisual(nullptr, 0, 0, nullptr); - fgVisual->dpy = nullptr; // fake (not used) + if (!vis_batch) { + // create dummy visual for batch mode + vis_batch = create_asvisual(nullptr, 0, 0, nullptr); + vis_batch->dpy = nullptr; // fake (not used) + } + + fgVisual = vis_batch; fgBatch = true; } diff --git a/graf2d/gifencode/Readme.md b/graf2d/gifencode/Readme.md new file mode 100644 index 0000000000000..67a99751b6056 --- /dev/null +++ b/graf2d/gifencode/Readme.md @@ -0,0 +1,7 @@ +# gifencode and gifdecode + +Originally it was plain C code to create GIF images from pixmap +and read GIF images to create new pixmap + +Later C++ interface was provided to exclude static variables usage + diff --git a/graf2d/x11/src/gifdecode.c b/graf2d/gifencode/gifdecode.cxx similarity index 86% rename from graf2d/x11/src/gifdecode.c rename to graf2d/gifencode/gifdecode.cxx index 26af335ae285b..35b009aa5c6c2 100644 --- a/graf2d/x11/src/gifdecode.c +++ b/graf2d/gifencode/gifdecode.cxx @@ -1,46 +1,32 @@ /* @(#)root/x11:$Id$ */ -/* Author: Rene Brun 11/06/97*/ -#include -#include +/* Author: Rene Brun 11/06/97 */ +/* C++ interface Sergey Linev 21/04/2026 */ +#include "gifdecode.h" -#define BITS 12 /* largest code size */ -#define TSIZE 4096 /* tables size */ - -typedef unsigned char byte; +#include +#include -static int Prefix[TSIZE]; /* prefix table */ -static byte Suffix[TSIZE]; /* suffix table */ -static byte OutCode[TSIZE]; /* output stack */ -static byte *ptr1, /* pointer to GIF array */ - *ptr2; /* pointer to PIX array */ -static int CurCodeSize, /* current number of bits per code */ - CurMaxCode; /* maximum code, given CurCodeSize */ - -static long CurBit; /* current bit in GIF image data */ +#define BITS 12 /* largest code size */ +#define TSIZE 4096 /* tables size */ /*************************************************************** * * ***************************************************************/ -static int ReadCode() +int TGifDecode::ReadCode() { - static long b3[3], CurByte; - static byte lblk; - int shift, nbyte; - long OldByte; - if (CurBit == -1) { lblk = 0; CurByte = -1; } CurBit += CurCodeSize; - OldByte = CurByte; + long OldByte = CurByte; CurByte = CurBit/8; - nbyte = CurByte - OldByte; - shift = 17 + (CurBit%8) - CurCodeSize; + int nbyte = CurByte - OldByte; + int shift = 17 + (CurBit%8) - CurCodeSize; while (nbyte-- > 0) { if (lblk == 0) { lblk = *ptr1++; @@ -57,7 +43,7 @@ static int ReadCode() /*************************************************************** * * ***************************************************************/ -static void OutPixel(byte pix) +void TGifDecode::OutPixel(unsigned char pix) { *ptr2++ = pix; } @@ -77,15 +63,15 @@ static void OutPixel(byte pix) * 1 - if error * * * ***************************************************************/ -int GIFinfo(byte *GIFarr, int *Width, int *Height, int *Ncols) +int TGifDecode::GIFinfo(unsigned char *GIFarr, int *Width, int *Height, int *Ncols) { - byte b; + unsigned char b; - ptr1 = GIFarr; + unsigned char *ptr1 = GIFarr; /* R E A D H E A D E R */ - if (strncmp((char *)GIFarr,"GIF87a",6) && strncmp((char *)GIFarr,"GIF89a",6)) + if (strncmp((const char *)GIFarr,"GIF87a",6) && strncmp((const char *)GIFarr,"GIF89a",6)) { fprintf(stderr,"\nGIFinfo: not a GIF\n"); return 1; @@ -146,9 +132,9 @@ int GIFinfo(byte *GIFarr, int *Width, int *Height, int *Ncols) * 1 - if error * * * ***************************************************************/ -int GIFdecode(byte *GIFarr, byte *PIXarr, int *Width, int *Height, int *Ncols, byte *R, byte *G, byte *B) +int TGifDecode::GIFdecode(unsigned char *GIFarr, unsigned char *PIXarr, int *Width, int *Height, int *Ncols, unsigned char *R, unsigned char *G, unsigned char *B) { - byte b, /* working variable */ + unsigned char b, /* working variable */ FinChar; /* final character */ int i, /* working variable for loops */ @@ -165,6 +151,10 @@ int GIFdecode(byte *GIFarr, byte *PIXarr, int *Width, int *Height, int *Ncols, b long Npix; /* number of pixels */ + int Prefix[TSIZE]; /* prefix table */ + unsigned char Suffix[TSIZE]; /* suffix table */ + unsigned char OutCode[TSIZE]; /* output stack */ + ptr1 = GIFarr; ptr2 = PIXarr; OldCode = 0; @@ -271,8 +261,8 @@ int GIFdecode(byte *GIFarr, byte *PIXarr, int *Width, int *Height, int *Ncols, b fprintf(stderr,"\nGIFdecode: corrupted GIF (big output count)\n"); return 1; } - OutCode[OutCount++] = Suffix[CurCode]; - CurCode = Prefix[CurCode]; + OutCode[OutCount++] = Suffix[CurCode]; + CurCode = Prefix[CurCode]; } FinChar = CurCode; OutCode[OutCount++] = FinChar; diff --git a/graf2d/gifencode/gifdecode.h b/graf2d/gifencode/gifdecode.h new file mode 100644 index 0000000000000..933d6bd6145f4 --- /dev/null +++ b/graf2d/gifencode/gifdecode.h @@ -0,0 +1,33 @@ +/* @(#)root/x11:$Id$ */ +/* Author: S.Linev 20/04/2026 */ +/* C++ interface for gifdecode.c */ + +#ifndef gifdecode_h +#define gifdecode_h + +class TGifDecode { + private: + unsigned char *ptr1 = nullptr; /* pointer to GIF array */ + unsigned char *ptr2 = nullptr; /* pointer to PIX array */ + + int CurCodeSize = 0; /* current number of bits per code */ + int CurMaxCode = 0; /* maximum code, given CurCodeSize */ + long CurBit = -1; /* current bit in GIF image data */ + + long b3[3] = {0, 0, 0}; + long CurByte = -1; + unsigned char lblk = 0; + + int ReadCode(); + void OutPixel(unsigned char pix); + + public: + + static int GIFinfo(unsigned char *GIFarr, int *Width, int *Height, int *Ncols); + + int GIFdecode(unsigned char *GIFarr, unsigned char *PIXarr, int *Width, int *Height, int *Ncols, unsigned char *R, unsigned char *G, unsigned char *B); + +}; + + +#endif \ No newline at end of file diff --git a/graf2d/x11/src/gifencode.c b/graf2d/gifencode/gifencode.cxx similarity index 77% rename from graf2d/x11/src/gifencode.c rename to graf2d/gifencode/gifencode.cxx index 0e1d133224e22..3673e679659ed 100644 --- a/graf2d/x11/src/gifencode.c +++ b/graf2d/gifencode/gifencode.cxx @@ -1,43 +1,132 @@ /* @(#)root/x11:$Id$ */ -/* Author: E.Chernyaev 19/01/94*/ -#include -#include -#include +/* Author: E.Chernyaev 19/01/94 + * C++ interface: S.Linev 20/04/2026 */ + +#include "gifencode.h" + +#include -#ifdef __STDC__ -#define ARGS(alist) alist -#else -#define ARGS(alist) () -#endif #define BITS 12 /* largest code size */ #define THELIMIT 4096 /* NEVER generate this */ -#define HSIZE 5003 /* hash table size */ #define SHIFT 4 /* shift for hashing */ -#define put_byte(A) (*put_b)((byte)(A)); Nbyte++ -typedef unsigned char byte; +void TGifEncode::put_byte(unsigned char b) +{ + if (fOut && (ferror(fOut) == 0)) { + fputc(b, fOut); + fNbyte++; + } +} + +bool TGifEncode::OpenFile(const char *fname, const char *opt) +{ + fOut = fopen(fname, opt); + return fOut != nullptr; +} + +void TGifEncode::CloseFile() +{ + if (fOut) + fclose(fOut); + fOut = nullptr; +} + + +void TGifEncode::char_init() +{ + a_count = 0; + cur_accum = 0; + cur_bits = 0; +} + +void TGifEncode::char_out(unsigned char c) +{ + accum[a_count++] = c; + if (a_count >= 254) + char_flush(); +} + +void TGifEncode::char_flush() +{ + if (a_count == 0) return; + put_byte(a_count); + for (int i=0; i>8) & 0xFF); +} + +/*************************************************************** + * * + * Name: output Date: 02.10.92 * + * * + * Function: output GIF code * + * * + * Input: code - GIF code * + * * + ***************************************************************/ +void TGifEncode::output(int code) +{ + /* O U T P U T C O D E */ + + static unsigned long masks[] = { 0x0000, + 0x0001, 0x0003, 0x0007, 0x000F, + 0x001F, 0x003F, 0x007F, 0x00FF, + 0x01FF, 0x03FF, 0x07FF, 0x0FFF, + 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + + cur_accum &= masks[cur_bits]; + if (cur_bits > 0) + cur_accum |= ((long)code << cur_bits); + else + cur_accum = code; + cur_bits += CurCodeSize; + while( cur_bits >= 8 ) { + char_out(cur_accum & 0xFF); + cur_accum >>= 8; + cur_bits -= 8; + } -static long HashTab [HSIZE]; /* hash table */ -static int CodeTab [HSIZE]; /* code table */ + /* R E S E T */ + + if (code == ClearCode ) { + memset((char *) HashTab, -1, sizeof(HashTab)); + FreeCode = ClearCode + 2; + CurCodeSize = IniCodeSize; + CurMaxCode = (1 << (IniCodeSize)) - 1; + } -static int BitsPixel, /* number of bits per pixel */ - IniCodeSize, /* initial number of bits per code */ - CurCodeSize, /* current number of bits per code */ - CurMaxCode, /* maximum code, given CurCodeSize */ - ClearCode, /* reset code */ - EOFCode, /* end of file code */ - FreeCode; /* first unused entry */ + /* I N C R E A S E C O D E S I Z E */ + + if (FreeCode > CurMaxCode ) { + CurCodeSize++; + if ( CurCodeSize == BITS ) + CurMaxCode = THELIMIT; + else + CurMaxCode = (1 << (CurCodeSize)) - 1; + } + + /* E N D O F F I L E : write the rest of the buffer */ + + if( code == EOFCode ) { + while( cur_bits > 0 ) { + char_out(cur_accum & 0xff); + cur_accum >>= 8; + cur_bits -= 8; + } + char_flush(); + } +} -static long Nbyte; -static void (*put_b) ARGS((byte)); -static void output ARGS((int)); -static void char_init(); -static void char_out ARGS((int)); -static void char_flush(); -static void put_short ARGS((int)); /*********************************************************************** * * @@ -60,12 +149,14 @@ static void put_short ARGS((int)); * Return: size of GIF * * * ***********************************************************************/ -long GIFencode(int Width, int Height, int Ncol, byte R[], byte G[], byte B[], byte ScLine[], - void(*get_scline) ARGS((int, int, byte *)), void(*pb) ARGS((byte))) +long TGifEncode::GIFencode(int Width, int Height, int Ncol, unsigned char *R, unsigned char *G, unsigned char *B) +// void(*get_scline) ARGS((int, int, byte *)), void(*pb) ARGS((byte))) { long CodeK; int ncol, i, x, y, disp, Code, K; + std::vector ScLine(Width); + /* C H E C K P A R A M E T E R S */ Code = 0; @@ -82,8 +173,7 @@ long GIFencode(int Width, int Height, int Ncol, byte R[], byte G[], byte B[], by /* I N I T I A L I S A T I O N */ - put_b = pb; - Nbyte = 0; + fNbyte = 0; char_init(); /* initialise "char_..." routines */ /* F I N D # O F B I T S P E R P I X E L */ @@ -149,7 +239,7 @@ long GIFencode(int Width, int Height, int Ncol, byte R[], byte G[], byte B[], by FreeCode = ClearCode + 2; output(ClearCode); for (y=0; y 0) - cur_accum |= ((long)code << cur_bits); - else - cur_accum = code; - cur_bits += CurCodeSize; - while( cur_bits >= 8 ) { - char_out( (unsigned int) (cur_accum & 0xFF) ); - cur_accum >>= 8; - cur_bits -= 8; - } - - /* R E S E T */ - - if (code == ClearCode ) { - memset((char *) HashTab, -1, sizeof(HashTab)); - FreeCode = ClearCode + 2; - CurCodeSize = IniCodeSize; - CurMaxCode = (1 << (IniCodeSize)) - 1; - } - - /* I N C R E A S E C O D E S I Z E */ - - if (FreeCode > CurMaxCode ) { - CurCodeSize++; - if ( CurCodeSize == BITS ) - CurMaxCode = THELIMIT; - else - CurMaxCode = (1 << (CurCodeSize)) - 1; - } - - /* E N D O F F I L E : write the rest of the buffer */ - - if( code == EOFCode ) { - while( cur_bits > 0 ) { - char_out( (unsigned int)(cur_accum & 0xff) ); - cur_accum >>= 8; - cur_bits -= 8; - } - char_flush(); - } -} - -static void char_init() -{ - a_count = 0; - cur_accum = 0; - cur_bits = 0; -} - -static void char_out(int c) -{ - accum[a_count++] = c; - if (a_count >= 254) - char_flush(); -} - -static void char_flush() -{ - int i; - - if (a_count == 0) return; - put_byte(a_count); - for (i=0; i>8) & 0xFF); -} diff --git a/graf2d/gifencode/gifencode.h b/graf2d/gifencode/gifencode.h new file mode 100644 index 0000000000000..0224f98c66149 --- /dev/null +++ b/graf2d/gifencode/gifencode.h @@ -0,0 +1,60 @@ +/* @(#)root/x11:$Id$ */ +/* Author: S.Linev 20/04/2026 */ +/* C++ interface for gifencode.c */ + + +#ifndef gifencode_h +#define gifencode_h + +#include +#include +#include + + +class TGifEncode { + + private: + + enum { HSIZE = 5003 }; /* hash table size */ + + unsigned long cur_accum = 0; + int cur_bits = 0; + int a_count = 0; + + int BitsPixel = 0; /* number of bits per pixel */ + int IniCodeSize = 0; /* initial number of bits per code */ + int CurCodeSize = 0; /* current number of bits per code */ + int CurMaxCode = 0; /* maximum code, given CurCodeSize */ + int ClearCode = 0; /* reset code */ + int EOFCode = 0; /* end of file code */ + int FreeCode = 0; /* first unused entry */ + + long HashTab [HSIZE]; /* hash table */ + int CodeTab [HSIZE]; /* code table */ + unsigned char accum[256]; + + long fNbyte = 0; + FILE *fOut = nullptr; + + void put_byte(unsigned char b); + void char_init(); + void char_out(unsigned char c); + void char_flush(); + void put_short(int word); + void output(int code); + + protected: + + virtual void get_scline(int y, int width, unsigned char *buf) = 0; + + public: + virtual ~TGifEncode() { CloseFile(); } + + bool OpenFile(const char *fname, const char *opt = "w+"); + void CloseFile(); + + long GIFencode(int Width, int Height, int Ncol, unsigned char *R, unsigned char *G, unsigned char *B); +}; + + +#endif diff --git a/graf2d/gpad/src/TPad.cxx b/graf2d/gpad/src/TPad.cxx index 3a0ff72783443..66cb2d9370da6 100644 --- a/graf2d/gpad/src/TPad.cxx +++ b/graf2d/gpad/src/TPad.cxx @@ -3626,8 +3626,10 @@ void TPad::Paint(Option_t * /*option*/) lnk = lnk->Next(); } - if (fCanvas && (fCanvas->fHilightPadBorder == this)) - PaintBorder(-GetHighLightColor(), kTRUE); + if (fCanvas && (fCanvas->fHilightPadBorder == this)) { + auto col = GetHighLightColor(); + if (col > 0) PaintBorder(-col, kTRUE); + } } fPadPaint = 0; diff --git a/graf2d/gpad/src/TPadPainter.cxx b/graf2d/gpad/src/TPadPainter.cxx index 8fbffdce21476..c91e838d5bf91 100644 --- a/graf2d/gpad/src/TPadPainter.cxx +++ b/graf2d/gpad/src/TPadPainter.cxx @@ -572,7 +572,10 @@ void TPadPainter::SaveImage(TVirtualPad *pad, const char *fileName, Int_t type) } if (type == TImage::kGif) { - gVirtualX->WriteGIF((char*)fileName); + Int_t wid = (pad == pad->GetCanvas()) ? pad->GetCanvasID() : pad->GetPixmapID(); + auto ctxt = gVirtualX->GetWindowContext(wid); + // TODO: if fail, one can use TImage functionality instead + gVirtualX->WriteGIFW(ctxt, fileName); } else { const std::unique_ptr img(TImage::Create()); if (img.get()) { diff --git a/graf2d/win32gdk/CMakeLists.txt b/graf2d/win32gdk/CMakeLists.txt index fefd4b9b3387a..66e3967cec63b 100644 --- a/graf2d/win32gdk/CMakeLists.txt +++ b/graf2d/win32gdk/CMakeLists.txt @@ -105,9 +105,8 @@ ROOT_STANDARD_LIBRARY_PACKAGE(Win32gdk TGWin32.h TGWin32GL.h SOURCES - src/gifdecode.c - src/gifencode.c - src/gifquantize.c + ../gifencode/gifdecode.cxx + ../gifencode/gifencode.cxx src/TGWin32.cxx src/TGWin32GL.cxx src/TGWin32ProxyBase.cxx @@ -128,5 +127,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(Win32gdk FREETYPE ) +target_include_directories(Win32gdk PRIVATE ../gifencode) + add_dependencies(Win32gdk GDKLIB glib) install(FILES ${gdkdlla} ${glibdlla} ${iconvdlla} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/graf2d/win32gdk/inc/TGWin32.h b/graf2d/win32gdk/inc/TGWin32.h index 236192defbcab..b7f65541241c2 100644 --- a/graf2d/win32gdk/inc/TGWin32.h +++ b/graf2d/win32gdk/inc/TGWin32.h @@ -86,7 +86,6 @@ class TGWin32 : public TVirtualX { void RemovePixmap(GdkDrawable *pix); void SetColor(XWindow_t *ctxt, GdkGC *gc, Int_t ci); void SetInput(Int_t inp); - void ImgPickPalette(GdkImage *image, Int_t &ncol, Int_t *&R, Int_t *&G, Int_t *&B); //---- Private methods used for GUI ---- void MapGCValues(GCValues_t &gval, ULong_t &xmask, GdkGCValues &xgval, Bool_t tox = kTRUE); @@ -218,6 +217,7 @@ class TGWin32 : public TVirtualX { void UpdateWindowW(WinContext_t wctxt, Int_t mode) override; void SetOpacityW(WinContext_t wctxt, Int_t percent) override; void CopyPixmapW(WinContext_t wctxt, Int_t wid, Int_t xpos, Int_t ypos) override; + Int_t WriteGIFW(WinContext_t wctxt, const char *name) override; void DrawBoxW(WinContext_t wctxt, Int_t x1, Int_t y1, Int_t x2, Int_t y2, EBoxMode mode) override; void DrawFillAreaW(WinContext_t wctxt, Int_t n, TPoint *xy) override; diff --git a/graf2d/win32gdk/src/TGWin32.cxx b/graf2d/win32gdk/src/TGWin32.cxx index da3810ee89554..24c5b47a0994e 100644 --- a/graf2d/win32gdk/src/TGWin32.cxx +++ b/graf2d/win32gdk/src/TGWin32.cxx @@ -60,6 +60,9 @@ by Olivier Couet (package X11INT). #include "RStipples.h" #include "GuiTypes.h" +#include "gifencode.h" +#include "gifdecode.h" + // DND protocol version #define XDND_PROTOCOL_VERSION 5 #ifndef IDC_HAND @@ -4313,170 +4316,125 @@ void TGWin32::WritePixmap(int wid, unsigned int w, unsigned int h, // XWriteBitmapFile(fDisplay,pxname,(Pixmap)gTws->drawing,wval,hval,-1,-1); } +class TWin32GifEncode : public TGifEncode { + private: + GdkImage *fImage = nullptr; + protected: + void get_scline(int y, int width, unsigned char *buf) override + { + for (int x = 0; x < width; x++) { + ULong_t pixel = GetPixelImage((Drawable_t)fImage, x, y); + buf[x] = 0; + + auto iter = std::find(orgcolors.begin(), orgcolors.end(), pixel); + if (iter != orgcolors.end()) { + auto idx = iter - orgcolors.begin(); + if (idx < 256) + buf[x] = (unsigned char) idx; + } + } + } + public: + std::vector orgcolors; -// -// Functions for GIFencode() -// - -static FILE *gGifFile; // output unit used WriteGIF and PutByte -static GdkImage *gGifImage = 0; // image used in WriteGIF and GetPixel - -extern "C" { - int GIFquantize(UInt_t width, UInt_t height, Int_t * ncol, Byte_t * red, - Byte_t * green, Byte_t * blue, Byte_t * outputBuf, - Byte_t * outputCmap); - long GIFencode(int Width, int Height, Int_t Ncol, Byte_t R[], - Byte_t G[], Byte_t B[], Byte_t ScLine[], - void (*get_scline) (int, int, Byte_t *), - void (*pb) (Byte_t)); - int GIFdecode(Byte_t * GIFarr, Byte_t * PIXarr, int *Width, int *Height, - int *Ncols, Byte_t * R, Byte_t * G, Byte_t * B); - int GIFinfo(Byte_t * GIFarr, int *Width, int *Height, int *Ncols); -} + TWin32GifEncode(GdkImage *image) : fImage(image) {} +}; //////////////////////////////////////////////////////////////////////////////// -/// Get pixels in line y and put in array scline. +/// Writes the current window into GIF file. -static void GetPixel(int y, int width, Byte_t * scline) +Int_t TGWin32::WriteGIF(char *name) { - for (int i = 0; i < width; i++) { - scline[i] = Byte_t(GetPixelImage((Drawable_t)gGifImage, i, y)); - } + return WriteGIFW((WinContext_t)gCws, name); } //////////////////////////////////////////////////////////////////////////////// -/// Put byte b in output stream. +/// Writes the specified window into GIF file. -static void PutByte(Byte_t b) +Int_t TGWin32::WriteGIFW(WinContext_t wctxt, const char *name) { - if (ferror(gGifFile) == 0) fputc(b, gGifFile); -} + auto ctxt = (XWindow_t *) wctxt; + if (!ctxt) + return 0; -//////////////////////////////////////////////////////////////////////////////// -/// Returns in R G B the ncol colors of the palette used by the image. -/// The image pixels are changed to index values in these R G B arrays. -/// This produces a colormap with only the used colors (so even on displays -/// with more than 8 planes we will be able to create GIF's when the image -/// contains no more than 256 different colors). If it does contain more -/// colors we will have to use GIFquantize to reduce the number of colors. -/// The R G B arrays must be deleted by the caller. + GdkImage *image = gdk_image_get((GdkDrawable*)ctxt->drawing, 0, 0, + ctxt->width, ctxt->height); + if (!image) { + Error("WriteGIFW", "Cannot create image for writing GIF. Try in batch mode."); + return 0; + } -void TGWin32::ImgPickPalette(GdkImage * image, Int_t & ncol, Int_t * &R, - Int_t * &G, Int_t * &B) -{ - std::vector orgcolors; + TWin32GifEncode gif(image); + + /// Collect R G B of colors of the palette used by the image. + /// The image pixels are changed to index values in these R G B arrays. + /// This produces a colormap with only the used colors (so even on displays + /// with more than 8 planes we will be able to create GIF's when the image + /// contains no more than 256 different colors). If it does contain more + /// colors we will have to use GIFquantize to reduce the number of colors. // collect different image colors - for (UInt_t x = 0; x < (int) gCws->width; x++) { - for (UInt_t y = 0; y < (int) gCws->height; y++) { + for (UInt_t x = 0; x < ctxt->width; x++) { + for (UInt_t y = 0; y < ctxt->height; y++) { ULong_t pixel = GetPixelImage((Drawable_t)image, x, y); - if (std::find(orgcolors.begin(), orgcolors.end(), pixel) == orgcolors.end()) - orgcolors.emplace_back(pixel); + if (std::find(gif.orgcolors.begin(), gif.orgcolors.end(), pixel) == gif.orgcolors.end()) + gif.orgcolors.emplace_back(pixel); } } + auto ncolors = gif.orgcolors.size(); + + if (ncolors > 256) { + Error("WriteGIFW", "can not create GIF of image containing more than 256 colors"); + gdk_image_unref(image); + return 0; + } + // get RGB values belonging to pixels - std::vector xcol(orgcolors.size()); + std::vector xcol(ncolors); - for (std::size_t i = 0; i < orgcolors.size(); i++) { - xcol[i].pixel = orgcolors[i]; + for (std::size_t i = 0; i < ncolors; i++) { + xcol[i].pixel = gif.orgcolors[i]; xcol[i].red = GetRValue(xcol[i].pixel); xcol[i].green = GetGValue(xcol[i].pixel); xcol[i].blue = GetBValue(xcol[i].pixel); } GdkColorContext *cc = gdk_color_context_new(gdk_visual_get_system(), (GdkColormap *)fColormap); - gdk_color_context_query_colors(cc, xcol.data(), orgcolors.size()); + gdk_color_context_query_colors(cc, xcol.data(), ncolors); gdk_color_context_free(cc); - // create RGB arrays and store RGB's for each color and set number of colors - // (space must be delete by caller) - R = new Int_t[orgcolors.size()]; - G = new Int_t[orgcolors.size()]; - B = new Int_t[orgcolors.size()]; - - for (std::size_t i = 0; i < orgcolors.size(); i++) { - R[i] = xcol[i].red; - G[i] = xcol[i].green; - B[i] = xcol[i].blue; - } - ncol = (Int_t) orgcolors.size(); - - // update image with indices (pixels) into the new RGB colormap - for (UInt_t x = 0; x < gCws->width; x++) { - for (UInt_t y = 0; y < gCws->height; y++) { - ULong_t pixel = GetPixelImage((Drawable_t)image, x, y); - auto iter = std::find(orgcolors.begin(), orgcolors.end(), pixel); - if (iter != orgcolors.end()) { - auto idx = iter - orgcolors.begin(); - PutPixel((Drawable_t)image, x, y, idx); - } - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// Writes the current window into GIF file. - -Int_t TGWin32::WriteGIF(char *name) -{ - Byte_t scline[2000], r[256], b[256], g[256]; - Int_t *R, *G, *B; - Int_t ncol, maxcol, i; - - if (gGifImage) { - gdk_image_unref((GdkImage *)gGifImage); + UShort_t maxcol = 0; + for (std::size_t i = 0; i < ncolors; i++) { + maxcol = TMath::Max(maxcol, xcol[i].red); + maxcol = TMath::Max(maxcol, xcol[i].green); + maxcol = TMath::Max(maxcol, xcol[i].blue); } + if (maxcol == 0) + maxcol = 255; - gGifImage = gdk_image_get((GdkDrawable*)gCws->drawing, 0, 0, - gCws->width, gCws->height); + std::vector r(ncolors), b(ncolors), g(ncolors); - ImgPickPalette(gGifImage, ncol, R, G, B); - - if (ncol > 256) { - //GIFquantize(...); - Error("WriteGIF", - "can not create GIF of image containing more than 256 colors"); - delete[]R; - delete[]G; - delete[]B; - return 0; + for (std::size_t i = 0; i < ncolors; i++) { + r[i] = (unsigned char) (xcol[i].red * 255 / maxcol); + g[i] = (unsigned char) (xcol[i].green * 255 / maxcol); + b[i] = (unsigned char) (xcol[i].blue * 255 / maxcol); } - maxcol = 0; - for (i = 0; i < ncol; i++) { - if (maxcol < R[i]) maxcol = R[i]; - if (maxcol < G[i]) maxcol = G[i]; - if (maxcol < B[i]) maxcol = B[i]; - r[i] = 0; - g[i] = 0; - b[i] = 0; - } - if (maxcol != 0) { - for (i = 0; i < ncol; i++) { - r[i] = R[i] * 255 / maxcol; - g[i] = G[i] * 255 / maxcol; - b[i] = B[i] * 255 / maxcol; - } - } - - gGifFile = fopen(name, "wb"); + Int_t ret = 0; - if (gGifFile) { - GIFencode(gCws->width, gCws->height, - ncol, r, g, b, scline, ::GetPixel, PutByte); - fclose(gGifFile); - i = 1; + if (gif.OpenFile(name, "wb")) { + auto len = gif.GIFencode(ctxt->width, ctxt->height, ncolors, r.data(), g.data(), b.data()); + if (len > 0) + ret = 1; + gif.CloseFile(); } else { - Error("WriteGIF","cannot write file: %s",name); - i = 0; + Error("WriteGIFW", "cannot write file: %s",name); } - delete[]R; - delete[]G; - delete[]B; + gdk_image_unref(image); - return i; + return ret; } //////////////////////////////////////////////////////////////////////////////// @@ -4566,14 +4524,13 @@ void TGWin32::PutImage(Int_t offset, Int_t itran, Int_t x0, Int_t y0, Int_t nx, Pixmap_t TGWin32::ReadGIF(int x0, int y0, const char *file, Window_t id) { - FILE *fd; Seek_t filesize; unsigned char *GIFarr, *PIXarr, R[256], G[256], B[256], *j1, *j2, icol; int i, j, k, width, height, ncolor, irep, offset; float rr, gg, bb; Pixmap_t pic = 0; - fd = fopen(file, "r+b"); + FILE *fd = fopen(file, "r+b"); if (!fd) { Error("ReadGIF", "unable to open GIF file"); return pic; @@ -4597,7 +4554,7 @@ Pixmap_t TGWin32::ReadGIF(int x0, int y0, const char *file, Window_t id) } fclose(fd); - irep = GIFinfo(GIFarr, &width, &height, &ncolor); + irep = TGifDecode::GIFinfo(GIFarr, &width, &height, &ncolor); if (irep != 0) { return pic; } @@ -4607,7 +4564,9 @@ Pixmap_t TGWin32::ReadGIF(int x0, int y0, const char *file, Window_t id) return pic; } - irep = GIFdecode(GIFarr, PIXarr, &width, &height, &ncolor, R, G, B); + TGifDecode gif; + + irep = gif.GIFdecode(GIFarr, PIXarr, &width, &height, &ncolor, R, G, B); if (irep != 0) { return pic; } @@ -4635,12 +4594,15 @@ Pixmap_t TGWin32::ReadGIF(int x0, int y0, const char *file, Window_t id) } } - if (id) pic = CreatePixmap(id, width, height); + if (id) + pic = CreatePixmap(id, width, height); PutImage(offset, -1, x0, y0, width, height, 0, 0, width-1, height-1, PIXarr, pic); - if (pic) return pic; - else if (gCws->drawing) return (Pixmap_t)gCws->drawing; - else return 0; + if (pic) + return pic; + if (gCws->drawing) + return (Pixmap_t)gCws->drawing; + return 0; } //////////////////////////// GWin32Gui ////////////////////////////////////////// diff --git a/graf2d/win32gdk/src/gifdecode.c b/graf2d/win32gdk/src/gifdecode.c deleted file mode 100644 index 73685c90e867d..0000000000000 --- a/graf2d/win32gdk/src/gifdecode.c +++ /dev/null @@ -1,301 +0,0 @@ -/* @(#)root/win32gdk:$Id$ */ -/* Author: Rene Brun 11/06/97*/ -#include -#include - - -#define BITS 12 /* largest code size */ -#define TSIZE 4096 /* tables size */ - -typedef unsigned char byte; - -static int Prefix[TSIZE]; /* prefix table */ -static byte Suffix[TSIZE]; /* suffix table */ -static byte OutCode[TSIZE]; /* output stack */ - -static byte *ptr1, /* pointer to GIF array */ - *ptr2; /* pointer to PIX array */ - -static int CurCodeSize, /* current number of bits per code */ - CurMaxCode; /* maximum code, given CurCodeSize */ - -static long CurBit; /* current bit in GIF image data */ - -/*************************************************************** - * * - ***************************************************************/ -static int ReadCode() -{ - static long b3[3], CurByte; - static byte lblk; - int shift, nbyte; - long OldByte; - - if (CurBit == -1) { - lblk = 0; - CurByte = -1; - } - - CurBit += CurCodeSize; - OldByte = CurByte; - CurByte = CurBit/8; - nbyte = CurByte - OldByte; - shift = 17 + (CurBit%8) - CurCodeSize; - while (nbyte-- > 0) { - if (lblk == 0) { - lblk = *ptr1++; - if (lblk == 0) return -1; - } - b3[0] = b3[1]; - b3[1] = b3[2]; - b3[2] = *ptr1++; - lblk--; - } - return (((b3[0]+0x100*b3[1]+0x10000*b3[2])>>shift) & (CurMaxCode-1)); -} - -/*************************************************************** - * * - ***************************************************************/ -static void OutPixel(byte pix) -{ - *ptr2++ = pix; -} - -/*************************************************************** - * * - * Name: GIFinfo Date: 03.10.94 * - * * - * Function: Get information on GIF image * - * * - * Input: GIFarr[] - compressed image in GIF format * - * * - * Output: Width - image width * - * Height - image height * - * Ncols - number of colors * - * return - 0 - if O.K. * - * 1 - if error * - * * - ***************************************************************/ -int GIFinfo(byte *GIFarr, int *Width, int *Height, int *Ncols) -{ - byte b; - - ptr1 = GIFarr; - - /* R E A D H E A D E R */ - - if (strncmp((char *)GIFarr,"GIF87a",6) && strncmp((char *)GIFarr,"GIF89a",6)) - { - fprintf(stderr,"\nGIFinfo: not a GIF\n"); - return 1; - } - - ptr1 += 6; - - ptr1 += 2; /* screen width ... ignore */ - ptr1 += 2; /* screen height ... ignore */ - - b = *ptr1++; - *Ncols = 1 << ((b & 7) + 1); - if ((b & 0x80) == 0) { /* is there color map? */ - fprintf(stderr,"\nGIFinfo: warning! no color map\n"); - *Ncols = 0; - } - - ++ptr1; /* background color ... ignore */ - b = *ptr1++; /* supposed to be NULL */ - if (b) { - fprintf(stderr,"\nGIFdecode: bad screen descriptor\n"); - return 1; - } - - ptr1 += (*Ncols) * 3; /* skip color map */ - - b = *ptr1++; /* image separator */ - if (b != ',') { - fprintf(stderr,"\nGIFinfo: no image separator\n"); - return 1; - } - - ptr1 += 2; /* left offset ... ignore */ - ptr1 += 2; /* top offset ... ignore */ - b = *ptr1++; /* image width */ - *Width = b + 0x100*(*ptr1++); - b = *ptr1++; /* image height */ - *Height = b + 0x100*(*ptr1++); - return 0; -} - -/*************************************************************** - * * - * Name: GIFdecode Date: 06.10.92 * - * * - * Function: Decode image from GIF array * - * * - * Input: GIFarr[] - compressed image in GIF format * - * * - * Output: PIXarr[] - image (byte per pixel) * - * Width - image width * - * Height - image height * - * Ncols - number of colors * - * R[] - red components * - * G[] - green components * - * B[] - blue components * - * return - 0 - if O.K. * - * 1 - if error * - * * - ***************************************************************/ -int GIFdecode(byte *GIFarr, byte *PIXarr, int *Width, int *Height, int *Ncols, byte *R, byte *G, byte *B) -{ - byte b, /* working variable */ - FinChar; /* final character */ - - int i, /* working variable for loops */ - BitsPixel, /* number of bits per pixel */ - IniCodeSize, /* initial number of bits per code */ - ClearCode, /* reset code */ - EOFCode, /* end of file code */ - FreeCode, /* first unused entry */ - CurCode, /* current code */ - InCode, /* input code */ - OldCode, /* previous code */ - PixMask, /* mask for pixel */ - OutCount; /* output stack counter */ - - long Npix; /* number of pixels */ - - ptr1 = GIFarr; - ptr2 = PIXarr; - OldCode = 0; - FinChar = 0; - - /* R E A D H E A D E R */ - if (strncmp((char *)GIFarr,"GIF87a",6) && strncmp((char *)GIFarr,"GIF89a",6)) - { - fprintf(stderr,"\nGIFinfo: not a GIF\n"); - return 1; - } - - ptr1 += 6; - - ptr1 += 2; /* screen width ... ignore */ - ptr1 += 2; /* screen height ... ignore */ - - b = *ptr1++; - BitsPixel = (b & 7) + 1; /* # of bits per pixel */ - *Ncols = 1 << BitsPixel; - PixMask = (*Ncols) - 1; /* mask for pixel code */ - if ((b & 0x80) == 0) { /* is there color map? */ - fprintf(stderr,"\nGIFdecode: warning! no color map\n"); - *Ncols = 0; - } - - ++ptr1; /* background color ... ignore */ - b = *ptr1++; /* supposed to be NULL */ - if (b) { - fprintf(stderr,"\nGIFdecode: bad screen descriptor\n"); - return 1; - } - - for (i=0; i<(*Ncols); i++) { /* global color map */ - R[i] = *ptr1++; - G[i] = *ptr1++; - B[i] = *ptr1++; - } - - b = *ptr1++; /* image separator */ - if (b != ',') { - fprintf(stderr,"\nGIFdecode: no image separator\n"); - return 1; - } - - ptr1 += 2; /* left offset ... ignore */ - ptr1 += 2; /* top offset ... ignore */ - b = *ptr1++; /* image width */ - *Width = b + 0x100*(*ptr1++); - b = *ptr1++; /* image height */ - *Height = b + 0x100*(*ptr1++); - - b = *ptr1++; /* local colors, interlace */ - if ((b & 0xc0) != 0) { - fprintf(stderr, - "\nGIFdecode: unexpected item (local colors or interlace)\n"); - return 1; - } - - IniCodeSize = *ptr1++; - CurCodeSize = ++IniCodeSize; - CurMaxCode = (1 << IniCodeSize); - ClearCode = (1 << (IniCodeSize - 1)); - EOFCode = ClearCode + 1; - FreeCode = ClearCode + 2; - - /* D E C O D E I M A G E */ - - Npix =(long) (*Width) * (*Height); - OutCount = 0; - CurBit = -1; - CurCode = ReadCode(); - while (Npix > 0) { - - if (CurCode < 0) { - fprintf(stderr,"\nGIFdecode: corrupted GIF (zero block length)\n"); - return 1; - } - - if (CurCode == EOFCode) { - fprintf(stderr,"\nGIFdecode: corrupted GIF (unexpected EOF)\n"); - return 1; - } - - if (CurCode == ClearCode) { /* clear code ... reset */ - - CurCodeSize = IniCodeSize; - CurMaxCode = (1 << IniCodeSize); - FreeCode = ClearCode + 2; - OldCode = CurCode = ReadCode(); - FinChar = CurCode; - OutPixel(FinChar); - Npix--; - - } else { /* image code */ - - InCode = CurCode; - if (CurCode >= FreeCode) { - CurCode = OldCode; - OutCode[OutCount++] = FinChar; - } - while (CurCode > PixMask) { /* build output pixel chain */ - if (OutCount >= TSIZE) { - fprintf(stderr,"\nGIFdecode: corrupted GIF (big output count)\n"); - return 1; - } - OutCode[OutCount++] = Suffix[CurCode]; - CurCode = Prefix[CurCode]; - } - FinChar = CurCode; - OutCode[OutCount++] = FinChar; - - for (i=OutCount-1; i>=0; i--) { /* put out pixel chain */ - OutPixel(OutCode[i]); - Npix--; - } - OutCount = 0; - - Prefix[FreeCode] = OldCode; /* build the tables */ - Suffix[FreeCode] = FinChar; - OldCode = InCode; - - FreeCode++; /* move pointer */ - if (FreeCode >= CurMaxCode) { - if (CurCodeSize < BITS) { - CurCodeSize++; - CurMaxCode *= 2; - } - } - } - CurCode = ReadCode(); - } - return 0; -} diff --git a/graf2d/win32gdk/src/gifencode.c b/graf2d/win32gdk/src/gifencode.c deleted file mode 100644 index 2bb7a437f6f4b..0000000000000 --- a/graf2d/win32gdk/src/gifencode.c +++ /dev/null @@ -1,306 +0,0 @@ -/* @(#)root/win32gdk:$Id$ */ -/* Author: E.Chernyaev 19/01/94*/ -#include -#include -#include - -#ifdef __STDC__ -#define ARGS(alist) alist -#else -#define ARGS(alist) () -#endif - -#define BITS 12 /* largest code size */ -#define THELIMIT 4096 /* NEVER generate this */ -#define HSIZE 5003 /* hash table size */ -#define SHIFT 4 /* shift for hashing */ - -#define put_byte(A) (*put_b)((byte)(A)); Nbyte++ - -typedef unsigned char byte; - -static long HashTab [HSIZE]; /* hash table */ -static int CodeTab [HSIZE]; /* code table */ - -static int BitsPixel, /* number of bits per pixel */ - IniCodeSize, /* initial number of bits per code */ - CurCodeSize, /* current number of bits per code */ - CurMaxCode, /* maximum code, given CurCodeSize */ - ClearCode, /* reset code */ - EOFCode, /* end of file code */ - FreeCode; /* first unused entry */ - -static long Nbyte; -static void (*put_b) ARGS((byte)); - -static void output ARGS((int)); -static void char_init(); -static void char_out ARGS((int)); -static void char_flush(); -static void put_short ARGS((int)); - -/*********************************************************************** - * * - * Name: GIFencode Date: 02.10.92 * - * Author: E.Chernyaev (IHEP/Protvino) Revised: * - * * - * Function: GIF compression of the image * - * * - * Input: Width - image width (must be >= 8) * - * Height - image height (must be >= 8) * - * Ncol - number of colors * - * R[] - red components * - * G[] - green components * - * B[] - blue components * - * ScLine[] - array for scan line (byte per pixel) * - * get_scline - user routine to read scan line: * - * get_scline(y, Width, ScLine) * - * pb - user routine for "put_byte": pb(b) * - * * - * Return: size of GIF * - * * - ***********************************************************************/ -long GIFencode(Width, Height, Ncol, R, G, B, ScLine, get_scline, pb) - int Width, Height, Ncol; - byte R[], G[], B[], ScLine[]; - void (*get_scline) ARGS((int, int, byte *)), (*pb) ARGS((byte)); -{ - long CodeK; - int ncol, i, x, y, disp, Code, K; - - /* C H E C K P A R A M E T E R S */ - - Code = 0; - if (Width <= 0 || Width > 4096 || Height <= 0 || Height > 4096) { - fprintf(stderr, - "\nGIFencode: incorrect image size: %d x %d\n", Width, Height); - return 0; - } - - if (Ncol <= 0 || Ncol > 256) { - fprintf(stderr,"\nGIFencode: wrong number of colors: %d\n", Ncol); - return 0; - } - - /* I N I T I A L I S A T I O N */ - - put_b = pb; - Nbyte = 0; - char_init(); /* initialise "char_..." routines */ - - /* F I N D # O F B I T S P E R P I X E L */ - - BitsPixel = 1; - if (Ncol > 2) BitsPixel = 2; - if (Ncol > 4) BitsPixel = 3; - if (Ncol > 8) BitsPixel = 4; - if (Ncol > 16) BitsPixel = 5; - if (Ncol > 32) BitsPixel = 6; - if (Ncol > 64) BitsPixel = 7; - if (Ncol > 128) BitsPixel = 8; - - ncol = 1 << BitsPixel; - IniCodeSize = BitsPixel; - if (BitsPixel <= 1) IniCodeSize = 2; - - /* W R I T E H E A D E R */ - - put_byte('G'); /* magic number: GIF87a */ - put_byte('I'); - put_byte('F'); - put_byte('8'); - put_byte('7'); - put_byte('a'); - - put_short(Width); /* screen size */ - put_short(Height); - - K = 0x80; /* yes, there is a color map */ - K |= (8-1)<<4; /* OR in the color resolution */ - K |= (BitsPixel - 1); /* OR in the # of bits per pixel */ - put_byte(K); - - put_byte(0); /* background color */ - put_byte(0); /* future expansion byte */ - - for (i=0; i 0) /* try again */ - goto PROBE; - -NOMATCH: - output(Code); /* full code not found */ - Code = K; - - if (FreeCode < THELIMIT) { - CodeTab[i] = FreeCode++; /* code -> hashtable */ - HashTab[i] = CodeK; - } - else - output(ClearCode); - } - } - /* O U T P U T T H E R E S T */ - - output(Code); - output(EOFCode); - put_byte(0); /* zero-length packet (EOF) */ - put_byte(';'); /* GIF file terminator */ - - return (Nbyte); -} - -static unsigned long cur_accum; -static int cur_bits; -static int a_count; -static char accum[256]; -static unsigned long masks[] = { 0x0000, - 0x0001, 0x0003, 0x0007, 0x000F, - 0x001F, 0x003F, 0x007F, 0x00FF, - 0x01FF, 0x03FF, 0x07FF, 0x0FFF, - 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; - -/*************************************************************** - * * - * Name: output Date: 02.10.92 * - * * - * Function: output GIF code * - * * - * Input: code - GIF code * - * * - ***************************************************************/ -static void output(code) - int code; -{ - /* O U T P U T C O D E */ - - cur_accum &= masks[cur_bits]; - if (cur_bits > 0) - cur_accum |= ((long)code << cur_bits); - else - cur_accum = code; - cur_bits += CurCodeSize; - while( cur_bits >= 8 ) { - char_out( (unsigned int) (cur_accum & 0xFF) ); - cur_accum >>= 8; - cur_bits -= 8; - } - - /* R E S E T */ - - if (code == ClearCode ) { - memset((char *) HashTab, -1, sizeof(HashTab)); - FreeCode = ClearCode + 2; - CurCodeSize = IniCodeSize; - CurMaxCode = (1 << (IniCodeSize)) - 1; - } - - /* I N C R E A S E C O D E S I Z E */ - - if (FreeCode > CurMaxCode ) { - CurCodeSize++; - if ( CurCodeSize == BITS ) - CurMaxCode = THELIMIT; - else - CurMaxCode = (1 << (CurCodeSize)) - 1; - } - - /* E N D O F F I L E : write the rest of the buffer */ - - if( code == EOFCode ) { - while( cur_bits > 0 ) { - char_out( (unsigned int)(cur_accum & 0xff) ); - cur_accum >>= 8; - cur_bits -= 8; - } - char_flush(); - } -} - -static void char_init() -{ - a_count = 0; - cur_accum = 0; - cur_bits = 0; -} - -static void char_out(c) - int c; -{ - accum[a_count++] = c; - if (a_count >= 254) - char_flush(); -} - -static void char_flush() -{ - int i; - - if (a_count == 0) return; - put_byte(a_count); - for (i=0; i>8) & 0xFF); -} diff --git a/graf2d/win32gdk/src/gifquantize.c b/graf2d/win32gdk/src/gifquantize.c deleted file mode 100644 index c1c8b175ed48b..0000000000000 --- a/graf2d/win32gdk/src/gifquantize.c +++ /dev/null @@ -1,301 +0,0 @@ -/* @(#)root/win32gdk:$Id$ */ -/* Author: Fons Rademakers 04/11/98*/ -/***************************************************************************** -* Module to quantize high resolution image into lower one. You may want to * -* peek into the following article this code is based on: * -* "Color Image Quantization for frame buffer Display", by Paul Heckbert * -* SIGGRAPH 1982 page 297-307. * -*****************************************************************************/ - -#include -#include - -typedef unsigned char byte; -typedef struct GifColorType { - byte Red, Green, Blue; -} GifColorType; - -#define ABS(x) ((x) > 0 ? (x) : (-(x))) - -#define GIF_ERROR 0 -#define GIF_OK 1 - -/* The colors are stripped to 5 bits per primary color */ -#define COLOR_ARRAY_SIZE 32768 -#define BITS_PER_PRIM_COLOR 5 -#define MAX_PRIM_COLOR 0x1f - - -static int SortRGBAxis; - -typedef struct QuantizedColorType { - byte RGB[3]; - byte NewColorIndex; - long Count; - struct QuantizedColorType *Pnext; -} QuantizedColorType; - -typedef struct NewColorMapType { - byte RGBMin[3], RGBWidth[3]; - unsigned int NumEntries; /* # of QuantizedColorType in linked list below. */ - long Count; /* Total number of pixels in all the entries. */ - QuantizedColorType *QuantizedColors; -} NewColorMapType; - -static int SubdivColorMap(NewColorMapType *NewColorSubdiv, - unsigned int ColorMapSize, - unsigned int *NewColorMapSize); -static int SortCmpRtn(const void *Entry1, const void *Entry2); - - -/****************************************************************************** -* Quantize high resolution image into lower one. Input image consists of a * -* 2D array for each of the RGB colors with size Width by Height. There is no * -* Color map for the input. Output is a quantized image with 2D array of * -* indexes into the output color map. * -* Note input image can be 24 bits at the most (8 for red/green/blue) and * -* the output has 256 colors at the most (256 entries in the color map.). * -* ColorMapSize specifies size of color map up to 256 and will be updated to * -* real size before returning. * -* Also non of the parameter are allocated by this routine. * -* This function returns GIF_OK if successful, GIF_ERROR otherwise. * -******************************************************************************/ -int GIFquantize(unsigned int Width, unsigned int Height, int *ColorMapSize, - byte *RedInput, byte *GreenInput, byte *BlueInput, - byte *OutputBuffer, GifColorType *OutputColorMap) -{ - unsigned int Index, NumOfEntries, newsize; - int i, j, MaxRGBError[3]; - int NewColorMapSize; - long Red, Green, Blue; - NewColorMapType NewColorSubdiv[256]; - QuantizedColorType *ColorArrayEntries, *QuantizedColor; - - if ((ColorArrayEntries = (QuantizedColorType *) - malloc(sizeof(QuantizedColorType) * COLOR_ARRAY_SIZE)) == NULL) { - fprintf(stderr, "QuantizeBuffer: not enough memory\n"); - return GIF_ERROR; - } - - for (i = 0; i < COLOR_ARRAY_SIZE; i++) { - ColorArrayEntries[i].RGB[0]= i >> (2 * BITS_PER_PRIM_COLOR); - ColorArrayEntries[i].RGB[1] = (i >> BITS_PER_PRIM_COLOR) & MAX_PRIM_COLOR; - ColorArrayEntries[i].RGB[2] = i & MAX_PRIM_COLOR; - ColorArrayEntries[i].Count = 0; - } - - /* Sample the colors and their distribution: */ - for (i = 0; i < (int)(Width * Height); i++) { - Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) - << (2 * BITS_PER_PRIM_COLOR)) + - ((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) - << BITS_PER_PRIM_COLOR) + - (BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR)); - ColorArrayEntries[Index].Count++; - } - - /* Put all the colors in the first entry of the color map, and call the */ - /* recursive subdivision process. */ - for (i = 0; i < 256; i++) { - NewColorSubdiv[i].QuantizedColors = NULL; - NewColorSubdiv[i].Count = NewColorSubdiv[i].NumEntries = 0; - for (j = 0; j < 3; j++) { - NewColorSubdiv[i].RGBMin[j] = 0; - NewColorSubdiv[i].RGBWidth[j] = 255; - } - } - - /* Find the non empty entries in the color table and chain them: */ - for (i = 0; i < COLOR_ARRAY_SIZE; i++) - if (ColorArrayEntries[i].Count > 0) break; - QuantizedColor = NewColorSubdiv[0].QuantizedColors = &ColorArrayEntries[i]; - NumOfEntries = 1; - while (++i < COLOR_ARRAY_SIZE) - if (ColorArrayEntries[i].Count > 0) { - QuantizedColor -> Pnext = &ColorArrayEntries[i]; - QuantizedColor = &ColorArrayEntries[i]; - NumOfEntries++; - } - QuantizedColor -> Pnext = NULL; - - NewColorSubdiv[0].NumEntries = NumOfEntries;/* Different sampled colors. */ - NewColorSubdiv[0].Count = ((long) Width) * Height; /* Pixels. */ - newsize = 1; - if (SubdivColorMap(NewColorSubdiv, *ColorMapSize, &newsize) != GIF_OK) { - free((char *) ColorArrayEntries); - return GIF_ERROR; - } - NewColorMapSize = (int)newsize; - if (NewColorMapSize < *ColorMapSize) { - /* And clear rest of color map: */ - for (i = NewColorMapSize; i < *ColorMapSize; i++) - OutputColorMap[i].Red = - OutputColorMap[i].Green = - OutputColorMap[i].Blue = 0; - } - - /* Average the colors in each entry to be the color to be used in the */ - /* output color map, and plug it into the output color map itself. */ - for (i = 0; i < NewColorMapSize; i++) { - if ((j = NewColorSubdiv[i].NumEntries) > 0) { - QuantizedColor = NewColorSubdiv[i].QuantizedColors; - Red = Green = Blue = 0; - while (QuantizedColor) { - QuantizedColor -> NewColorIndex = i; - Red += QuantizedColor -> RGB[0]; - Green += QuantizedColor -> RGB[1]; - Blue += QuantizedColor -> RGB[2]; - QuantizedColor = QuantizedColor -> Pnext; - } - OutputColorMap[i].Red = (byte)((Red << (8 - BITS_PER_PRIM_COLOR)) / j); - OutputColorMap[i].Green = (byte)((Green << (8 - BITS_PER_PRIM_COLOR)) / j); - OutputColorMap[i].Blue= (byte)((Blue << (8 - BITS_PER_PRIM_COLOR)) / j); - } - else - fprintf(stderr, "Null entry in quantized color map - thats weird."); - } - - /* Finally scan the input buffer again and put the mapped index in the */ - /* output buffer. */ - MaxRGBError[0] = MaxRGBError[1] = MaxRGBError[2] = 0; - for (i = 0; i < (int)(Width * Height); i++) { - Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) - << (2 * BITS_PER_PRIM_COLOR)) + - ((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) - << BITS_PER_PRIM_COLOR) + - (BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR)); - Index = ColorArrayEntries[Index].NewColorIndex; - OutputBuffer[i] = Index; - if (MaxRGBError[0] < ABS(OutputColorMap[Index].Red - RedInput[i])) - MaxRGBError[0] = ABS(OutputColorMap[Index].Red - RedInput[i]); - if (MaxRGBError[1] < ABS(OutputColorMap[Index].Green - GreenInput[i])) - MaxRGBError[1] = ABS(OutputColorMap[Index].Green - GreenInput[i]); - if (MaxRGBError[2] < ABS(OutputColorMap[Index].Blue - BlueInput[i])) - MaxRGBError[2] = ABS(OutputColorMap[Index].Blue - BlueInput[i]); - } - -#ifdef DEBUG - fprintf(stderr, - "Quantization L(0) errors: Red = %d, Green = %d, Blue = %d.\n", - MaxRGBError[0], MaxRGBError[1], MaxRGBError[2]); -#endif /* DEBUG */ - - free((char *) ColorArrayEntries); - - *ColorMapSize = NewColorMapSize; - - return GIF_OK; -} - -/****************************************************************************** -* Routine to subdivide the RGB space recursively using median cut in each * -* axes alternatingly until ColorMapSize different cubes exists. * -* The biggest cube in one dimension is subdivide unless it has only one entry.* -* Returns GIF_ERROR if failed, otherwise GIF_OK. * -******************************************************************************/ -static int SubdivColorMap(NewColorMapType *NewColorSubdiv, - unsigned int ColorMapSize, - unsigned int *NewColorMapSize) -{ - int MaxSize; - unsigned int i, j, Index = 0, NumEntries, MinColor, MaxColor; - long Sum, Count; - QuantizedColorType *QuantizedColor, **SortArray; - - while (ColorMapSize > *NewColorMapSize) { - /* Find candidate for subdivision: */ - MaxSize = -1; - for (i = 0; i < *NewColorMapSize; i++) { - for (j = 0; j < 3; j++) { - if (((int) NewColorSubdiv[i].RGBWidth[j]) > MaxSize && - NewColorSubdiv[i].NumEntries > 1) { - MaxSize = NewColorSubdiv[i].RGBWidth[j]; - Index = i; - SortRGBAxis = j; - } - } - } - - if (MaxSize == -1) - return GIF_OK; - - /* Split the entry Index into two along the axis SortRGBAxis: */ - - /* Sort all elements in that entry along the given axis and split at */ - /* the median. */ - if ((SortArray = (QuantizedColorType **) - malloc(sizeof(QuantizedColorType *) * - NewColorSubdiv[Index].NumEntries)) == NULL) - return GIF_ERROR; - for (j = 0, QuantizedColor = NewColorSubdiv[Index].QuantizedColors; - j < NewColorSubdiv[Index].NumEntries && QuantizedColor != NULL; - j++, QuantizedColor = QuantizedColor -> Pnext) - SortArray[j] = QuantizedColor; - qsort(SortArray, NewColorSubdiv[Index].NumEntries, - sizeof(QuantizedColorType *), SortCmpRtn); - - /* Relink the sorted list into one: */ - for (j = 0; j < NewColorSubdiv[Index].NumEntries - 1; j++) - SortArray[j] -> Pnext = SortArray[j + 1]; - SortArray[NewColorSubdiv[Index].NumEntries - 1] -> Pnext = NULL; - NewColorSubdiv[Index].QuantizedColors = QuantizedColor = SortArray[0]; - free((char *) SortArray); - - /* Now simply add the Counts until we have half of the Count: */ - Sum = NewColorSubdiv[Index].Count / 2 - QuantizedColor -> Count; - NumEntries = 1; - Count = QuantizedColor -> Count; - while ((Sum -= QuantizedColor -> Pnext -> Count) >= 0 && - QuantizedColor -> Pnext != NULL && - QuantizedColor -> Pnext -> Pnext != NULL) { - QuantizedColor = QuantizedColor -> Pnext; - NumEntries++; - Count += QuantizedColor -> Count; - } - /* Save the values of the last color of the first half, and first */ - /* of the second half so we can update the Bounding Boxes later. */ - /* Also as the colors are quantized and the BBoxes are full 0..255, */ - /* they need to be rescaled. */ - MaxColor = QuantizedColor -> RGB[SortRGBAxis];/* Max. of first half. */ - MinColor = QuantizedColor -> Pnext -> RGB[SortRGBAxis];/* of second. */ - MaxColor <<= (8 - BITS_PER_PRIM_COLOR); - MinColor <<= (8 - BITS_PER_PRIM_COLOR); - - /* Partition right here: */ - NewColorSubdiv[*NewColorMapSize].QuantizedColors = - QuantizedColor -> Pnext; - QuantizedColor -> Pnext = NULL; - NewColorSubdiv[*NewColorMapSize].Count = Count; - NewColorSubdiv[Index].Count -= Count; - NewColorSubdiv[*NewColorMapSize].NumEntries = - NewColorSubdiv[Index].NumEntries - NumEntries; - NewColorSubdiv[Index].NumEntries = NumEntries; - for (j = 0; j < 3; j++) { - NewColorSubdiv[*NewColorMapSize].RGBMin[j] = - NewColorSubdiv[Index].RGBMin[j]; - NewColorSubdiv[*NewColorMapSize].RGBWidth[j] = - NewColorSubdiv[Index].RGBWidth[j]; - } - NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] = - NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] + - NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] - - MinColor; - NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] = MinColor; - - NewColorSubdiv[Index].RGBWidth[SortRGBAxis] = - MaxColor - NewColorSubdiv[Index].RGBMin[SortRGBAxis]; - - (*NewColorMapSize)++; - } - - return GIF_OK; -} - -/****************************************************************************** -* Routine called by qsort to compare to entries. * -******************************************************************************/ -static int SortCmpRtn(const void *Entry1, const void *Entry2) -{ - return (* ((QuantizedColorType **) Entry1)) -> RGB[SortRGBAxis] - - (* ((QuantizedColorType **) Entry2)) -> RGB[SortRGBAxis]; -} diff --git a/graf2d/x11/CMakeLists.txt b/graf2d/x11/CMakeLists.txt index 68620e97cab03..987277c3c16e4 100644 --- a/graf2d/x11/CMakeLists.txt +++ b/graf2d/x11/CMakeLists.txt @@ -13,9 +13,8 @@ ROOT_STANDARD_LIBRARY_PACKAGE(GX11 HEADERS TGX11.h SOURCES - src/gifdecode.c - src/gifencode.c - src/gifquantize.c + ../gifencode/gifdecode.cxx + ../gifencode/gifencode.cxx src/GX11Gui.cxx src/Rotated.cxx src/TGX11.cxx @@ -34,6 +33,8 @@ ROOT_STANDARD_LIBRARY_PACKAGE(GX11 ) target_include_directories(GX11 PRIVATE ${X11_INCLUDE_DIR}) +target_include_directories(GX11 PRIVATE ../gifencode) + if(AIX) target_include_directories(GX11 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/inc) diff --git a/graf2d/x11/inc/TGX11.h b/graf2d/x11/inc/TGX11.h index 4646efa97d19e..f3c8af94f29e1 100644 --- a/graf2d/x11/inc/TGX11.h +++ b/graf2d/x11/inc/TGX11.h @@ -79,7 +79,6 @@ friend struct XWindow_t; UChar_t *image, Drawable_t id); void SetColor(XWindow_t *ctxt, void *gc, Int_t ci); void SetInput(Int_t inp); - void ImgPickPalette(RXImage *image, Int_t &ncol, Int_t *&R, Int_t *&G, Int_t *&B); //---- Private methods used for GUI ---- void MapGCValues(GCValues_t &gval, ULong_t &xmask, RXGCValues &xgval, Bool_t tox = kTRUE); @@ -235,6 +234,8 @@ friend struct XWindow_t; void UpdateWindowW(WinContext_t wctxt, Int_t mode) override; void SetOpacityW(WinContext_t wctxt, Int_t percent) override; void CopyPixmapW(WinContext_t wctxt, Int_t wid, Int_t xpos, Int_t ypos) override; + Int_t WriteGIFW(WinContext_t wctxt, const char *name) override; + void DrawBoxW(WinContext_t wctxt, Int_t x1, Int_t y1, Int_t x2, Int_t y2, EBoxMode mode) override; void DrawFillAreaW(WinContext_t wctxt, Int_t n, TPoint *xy) override; diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index 3efc79be47e34..d0e67b47b32a9 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -62,6 +62,9 @@ by Olivier Couet (package X11INT). # include #endif +#include "gifencode.h" +#include "gifdecode.h" + extern float XRotVersion(char*, int); extern void XRotSetMagnification(float); extern void XRotSetBoundingBoxPad(int); @@ -2800,160 +2803,129 @@ void TGX11::WritePixmap(int wid, unsigned int w, unsigned int h, char *pxname) XWriteBitmapFile((Display*)fDisplay, pxname, gTws->fDrawing, wval, hval, -1, -1); } +//////////////////////////////////////////////////////////////////////////////// +/// Helper class to extract pixel information from XImage for store in the GIF -// -// Functions for GIFencode() -// +class TX11GifEncode : public TGifEncode { + private: + XImage *fXimage = nullptr; + protected: + void get_scline(int y, int width, unsigned char *buf) override + { + for (int x = 0; x < width; x++) { + ULong_t pixel = XGetPixel(fXimage, x, y); + buf[x] = 0; -static FILE *gOut; // output unit used WriteGIF and PutByte -static XImage *gXimage = nullptr; // image used in WriteGIF and GetPixel + auto iter = std::find(orgcolors.begin(), orgcolors.end(), pixel); + if (iter != orgcolors.end()) { + auto idx = iter - orgcolors.begin(); + if (idx < 256) + buf[x] = (unsigned char) idx; + } + } + } + public: + std::vector orgcolors; // all unique pixels + + TX11GifEncode(XImage *image) : fXimage(image) {} +}; -extern "C" { - int GIFquantize(UInt_t width, UInt_t height, Int_t *ncol, Byte_t *red, Byte_t *green, - Byte_t *blue, Byte_t *outputBuf, Byte_t *outputCmap); - long GIFencode(int Width, int Height, Int_t Ncol, Byte_t R[], Byte_t G[], Byte_t B[], Byte_t ScLine[], - void (*get_scline) (int, int, Byte_t *), void (*pb)(Byte_t)); - int GIFdecode(Byte_t *gifArr, Byte_t *pixArr, int *Width, int *Height, int *Ncols, Byte_t *R, Byte_t *G, Byte_t *B); - int GIFinfo(Byte_t *gifArr, int *Width, int *Height, int *Ncols); -} //////////////////////////////////////////////////////////////////////////////// -/// Get pixels in line y and put in array scline. +/// Writes the current window into GIF file. Returns 1 in case of success, +/// 0 otherwise. -static void GetPixel(int y, int width, Byte_t *scline) +Int_t TGX11::WriteGIF(char *name) { - for (int i = 0; i < width; i++) - scline[i] = Byte_t(XGetPixel(gXimage, i, y)); + return WriteGIFW((WinContext_t) gCws, name); } //////////////////////////////////////////////////////////////////////////////// -/// Put byte b in output stream. +/// Writes the specified window into GIF file. Returns 1 in case of success, +/// 0 otherwise. -static void PutByte(Byte_t b) +Int_t TGX11::WriteGIFW(WinContext_t wctxt, const char *name) { - if (ferror(gOut) == 0) fputc(b, gOut); -} + auto ctxt = (XWindow_t *) wctxt; -//////////////////////////////////////////////////////////////////////////////// -/// Returns in R G B the ncol colors of the palette used by the image. -/// The image pixels are changed to index values in these R G B arrays. -/// This produces a colormap with only the used colors (so even on displays -/// with more than 8 planes we will be able to create GIF's when the image -/// contains no more than 256 different colors). If it does contain more -/// colors we will have to use GIFquantize to reduce the number of colors. -/// The R G B arrays must be deleted by the caller. + XImage *image = XGetImage((Display*)fDisplay, ctxt->fDrawing, 0, 0, + ctxt->fWidth, ctxt->fHeight, + AllPlanes, ZPixmap); -void TGX11::ImgPickPalette(RXImage *image, Int_t &ncol, Int_t *&R, Int_t *&G, Int_t *&B) -{ - std::vector orgcolors; + if (!image) { + Error("WriteGIFW", "Cannot create image for writing GIF. Try in batch mode."); + return 0; + } + + /// Collect R G B colors of the palette used by the image. + /// The image pixels are changed to index values in these R G B arrays. + /// This produces a colormap with only the used colors (so even on displays + /// with more than 8 planes we will be able to create GIF's when the image + /// contains no more than 256 different colors). If it does contain more + /// colors we will have to use GIFquantize to reduce the number of colors. + + TX11GifEncode gif(image); // collect different image colors - for (UInt_t x = 0; x < gCws->fWidth; x++) { - for (UInt_t y = 0; y < gCws->fHeight; y++) { + for (UInt_t x = 0; x < ctxt->fWidth; x++) { + for (UInt_t y = 0; y < ctxt->fHeight; y++) { ULong_t pixel = XGetPixel(image, x, y); - if (std::find(orgcolors.begin(), orgcolors.end(), pixel) == orgcolors.end()) - orgcolors.emplace_back(pixel); + if (std::find(gif.orgcolors.begin(), gif.orgcolors.end(), pixel) == gif.orgcolors.end()) + gif.orgcolors.emplace_back(pixel); } } + auto ncolors = gif.orgcolors.size(); + + if (ncolors > 256) { + Error("WriteGIFW", "Cannot create GIF of image containing more than 256 colors. Try in batch mode."); + XDestroyImage(image); + return 0; + } + // get RGB values belonging to pixels - std::vector xcol(orgcolors.size()); + std::vector xcol(ncolors); - for (size_t i = 0; i < orgcolors.size(); i++) { - xcol[i].pixel = orgcolors[i]; + for (std::size_t i = 0; i < ncolors; i++) { + xcol[i].pixel = gif.orgcolors[i]; xcol[i].red = xcol[i].green = xcol[i].blue = 0; xcol[i].flags = DoRed | DoGreen | DoBlue; } - QueryColors(fColormap, xcol.data(), orgcolors.size()); - // create RGB arrays and store RGB's for each color and set number of colors - // (space must be delete by caller) - R = new Int_t[orgcolors.size()]; - G = new Int_t[orgcolors.size()]; - B = new Int_t[orgcolors.size()]; + QueryColors(fColormap, xcol.data(), ncolors); - for (size_t i = 0; i < orgcolors.size(); i++) { - R[i] = xcol[i].red; - G[i] = xcol[i].green; - B[i] = xcol[i].blue; + UShort_t maxcol = 0; + for (std::size_t i = 0; i < ncolors; i++) { + maxcol = TMath::Max(maxcol, xcol[i].red); + maxcol = TMath::Max(maxcol, xcol[i].green); + maxcol = TMath::Max(maxcol, xcol[i].blue); } - ncol = (Int_t) orgcolors.size(); + if (maxcol == 0) + maxcol = 255; - // update image with indices (pixels) into the new RGB colormap - for (UInt_t x = 0; x < gCws->fWidth; x++) { - for (UInt_t y = 0; y < gCws->fHeight; y++) { - ULong_t pixel = XGetPixel(image, x, y); - auto iter = std::find(orgcolors.begin(), orgcolors.end(), pixel); - if (iter != orgcolors.end()) { - auto idx = iter - orgcolors.begin(); - XPutPixel(image, x, y, idx); - } - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// Writes the current window into GIF file. Returns 1 in case of success, -/// 0 otherwise. + std::vector r(ncolors), b(ncolors), g(ncolors); -Int_t TGX11::WriteGIF(char *name) -{ - Byte_t scline[2000], r[256], b[256], g[256]; - Int_t *red, *green, *blue; - Int_t ncol, maxcol, i; - - if (gXimage) { - XDestroyImage(gXimage); - gXimage = nullptr; + for (std::size_t i = 0; i < ncolors; i++) { + r[i] = (unsigned char) (xcol[i].red * 255 / maxcol); + g[i] = (unsigned char) (xcol[i].green * 255 / maxcol); + b[i] = (unsigned char) (xcol[i].blue * 255 / maxcol); } - gXimage = XGetImage((Display*)fDisplay, gCws->fDrawing, 0, 0, - gCws->fWidth, gCws->fHeight, - AllPlanes, ZPixmap); - - ImgPickPalette((RXImage*)gXimage, ncol, red, green, blue); - - if (ncol > 256) { - //GIFquantize(...); - Error("WriteGIF", "Cannot create GIF of image containing more than 256 colors. Try in batch mode."); - delete [] red; - delete [] green; - delete [] blue; - return 0; - } + Int_t ret = 0; - maxcol = 0; - for (i = 0; i < ncol; i++) { - if (maxcol < red[i] ) maxcol = red[i]; - if (maxcol < green[i] ) maxcol = green[i]; - if (maxcol < blue[i] ) maxcol = blue[i]; - r[i] = 0; - g[i] = 0; - b[i] = 0; - } - if (maxcol != 0) { - for (i = 0; i < ncol; i++) { - r[i] = red[i] * 255/maxcol; - g[i] = green[i] * 255/maxcol; - b[i] = blue[i] * 255/maxcol; - } + if (gif.OpenFile(name)) { + auto len = gif.GIFencode(ctxt->fWidth, ctxt->fHeight, ncolors, r.data(), g.data(), b.data()); + if (len > 0) + ret = 1; + gif.CloseFile(); + } else { + Error("WriteGIFW", "cannot write file: %s", name); } - gOut = fopen(name, "w+"); + // cleanup image at the end + XDestroyImage(image); - if (gOut) { - GIFencode(gCws->fWidth, gCws->fHeight, - ncol, r, g, b, scline, ::GetPixel, PutByte); - fclose(gOut); - i = 1; - } else { - Error("WriteGIF","cannot write file: %s",name); - i = 0; - } - delete [] red; - delete [] green; - delete [] blue; - return i; + return ret; } //////////////////////////////////////////////////////////////////////////////// @@ -3033,14 +3005,13 @@ void TGX11::PutImage(Int_t offset,Int_t itran,Int_t x0,Int_t y0,Int_t nx,Int_t n Pixmap_t TGX11::ReadGIF(int x0, int y0, const char *file, Window_t id) { - FILE *fd; Seek_t filesize = 0; unsigned char *gifArr, *pixArr, red[256], green[256], blue[256], *j1, *j2, icol; int i, j, k, width, height, ncolor, irep, offset; float rr, gg, bb; Pixmap_t pic = 0; - fd = fopen(file, "r"); + FILE *fd = fopen(file, "r"); if (!fd) { Error("ReadGIF", "unable to open GIF file"); return pic; @@ -3071,7 +3042,7 @@ Pixmap_t TGX11::ReadGIF(int x0, int y0, const char *file, Window_t id) } fclose(fd); - irep = GIFinfo(gifArr, &width, &height, &ncolor); + irep = TGifDecode::GIFinfo(gifArr, &width, &height, &ncolor); if (irep != 0) { free(gifArr); return pic; @@ -3083,7 +3054,9 @@ Pixmap_t TGX11::ReadGIF(int x0, int y0, const char *file, Window_t id) return pic; } - irep = GIFdecode(gifArr, pixArr, &width, &height, &ncolor, red, green, blue); + TGifDecode gif; + + irep = gif.GIFdecode(gifArr, pixArr, &width, &height, &ncolor, red, green, blue); if (irep != 0) { free(gifArr); free(pixArr); @@ -3111,7 +3084,8 @@ Pixmap_t TGX11::ReadGIF(int x0, int y0, const char *file, Window_t id) icol = *j1; *j1++ = *j2; *j2++ = icol; } } - if (id) pic = CreatePixmap(id, width, height); + if (id) + pic = CreatePixmap(id, width, height); PutImage(offset,-1,x0,y0,width,height,0,0,width-1,height-1,pixArr,pic); free(gifArr); @@ -3119,7 +3093,8 @@ Pixmap_t TGX11::ReadGIF(int x0, int y0, const char *file, Window_t id) if (pic) return pic; - else if (gCws->fDrawing) + + if (gCws->fDrawing) return (Pixmap_t)gCws->fDrawing; return 0; } diff --git a/graf2d/x11/src/gifquantize.c b/graf2d/x11/src/gifquantize.c deleted file mode 100644 index beb1585fe885f..0000000000000 --- a/graf2d/x11/src/gifquantize.c +++ /dev/null @@ -1,302 +0,0 @@ -/* @(#)root/x11:$Id$ */ -/* Author: Fons Rademakers 04/11/98*/ -/***************************************************************************** -* Module to quantize high resolution image into lower one. You may want to * -* peek into the following article this code is based on: * -* "Color Image Quantization for frame buffer Display", by Paul Heckbert * -* SIGGRAPH 1982 page 297-307. * -*****************************************************************************/ - -#include -#include - -typedef unsigned char byte; -typedef struct GifColorType { - byte Red, Green, Blue; -} GifColorType; - -#define ABS(x) ((x) > 0 ? (x) : (-(x))) - -#define GIF_ERROR 0 -#define GIF_OK 1 - -/* The colors are stripped to 5 bits per primary color */ -#define COLOR_ARRAY_SIZE 32768 -#define BITS_PER_PRIM_COLOR 5 -#define MAX_PRIM_COLOR 0x1f - - -static int SortRGBAxis; - -typedef struct QuantizedColorType { - byte RGB[3]; - byte NewColorIndex; - long Count; - struct QuantizedColorType *Pnext; -} QuantizedColorType; - -typedef struct NewColorMapType { - byte RGBMin[3], RGBWidth[3]; - unsigned int NumEntries; /* # of QuantizedColorType in linked list below. */ - long Count; /* Total number of pixels in all the entries. */ - QuantizedColorType *QuantizedColors; -} NewColorMapType; - -static int SubdivColorMap(NewColorMapType *NewColorSubdiv, - unsigned int ColorMapSize, - unsigned int *NewColorMapSize); -static int SortCmpRtn(const void *Entry1, const void *Entry2); - - -/****************************************************************************** -* Quantize high resolution image into lower one. Input image consists of a * -* 2D array for each of the RGB colors with size Width by Height. There is no * -* Color map for the input. Output is a quantized image with 2D array of * -* indexes into the output color map. * -* Note input image can be 24 bits at the most (8 for red/green/blue) and * -* the output has 256 colors at the most (256 entries in the color map.). * -* ColorMapSize specifies size of color map up to 256 and will be updated to * -* real size before returning. * -* Also non of the parameter are allocated by this routine. * -* This function returns GIF_OK if successful, GIF_ERROR otherwise. * -******************************************************************************/ -int GIFquantize(unsigned int Width, unsigned int Height, int *ColorMapSize, - byte *RedInput, byte *GreenInput, byte *BlueInput, - byte *OutputBuffer, GifColorType *OutputColorMap) -{ - unsigned int Index, NumOfEntries, newsize; - int i, j, MaxRGBError[3]; - int NewColorMapSize; - long Red, Green, Blue; - NewColorMapType NewColorSubdiv[256]; - QuantizedColorType *ColorArrayEntries, *QuantizedColor; - - if ((ColorArrayEntries = (QuantizedColorType *) - malloc(sizeof(QuantizedColorType) * COLOR_ARRAY_SIZE)) == NULL) { - fprintf(stderr, "QuantizeBuffer: not enough memory\n"); - return GIF_ERROR; - } - - for (i = 0; i < COLOR_ARRAY_SIZE; i++) { - ColorArrayEntries[i].RGB[0]= i >> (2 * BITS_PER_PRIM_COLOR); - ColorArrayEntries[i].RGB[1] = (i >> BITS_PER_PRIM_COLOR) & MAX_PRIM_COLOR; - ColorArrayEntries[i].RGB[2] = i & MAX_PRIM_COLOR; - ColorArrayEntries[i].Count = 0; - } - - /* Sample the colors and their distribution: */ - for (i = 0; i < (int)(Width * Height); i++) { - Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) - << (2 * BITS_PER_PRIM_COLOR)) + - ((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) - << BITS_PER_PRIM_COLOR) + - (BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR)); - ColorArrayEntries[Index].Count++; - } - - /* Put all the colors in the first entry of the color map, and call the */ - /* recursive subdivision process. */ - for (i = 0; i < 256; i++) { - NewColorSubdiv[i].QuantizedColors = NULL; - NewColorSubdiv[i].Count = NewColorSubdiv[i].NumEntries = 0; - for (j = 0; j < 3; j++) { - NewColorSubdiv[i].RGBMin[j] = 0; - NewColorSubdiv[i].RGBWidth[j] = 255; - } - } - - /* Find the non empty entries in the color table and chain them: */ - for (i = 0; i < COLOR_ARRAY_SIZE; i++) - if (ColorArrayEntries[i].Count > 0) break; - QuantizedColor = NewColorSubdiv[0].QuantizedColors = &ColorArrayEntries[i]; - NumOfEntries = 1; - while (++i < COLOR_ARRAY_SIZE) - if (ColorArrayEntries[i].Count > 0) { - QuantizedColor -> Pnext = &ColorArrayEntries[i]; - QuantizedColor = &ColorArrayEntries[i]; - NumOfEntries++; - } - QuantizedColor -> Pnext = NULL; - - NewColorSubdiv[0].NumEntries = NumOfEntries;/* Different sampled colors. */ - NewColorSubdiv[0].Count = ((long) Width) * Height; /* Pixels. */ - newsize = 1; - if (SubdivColorMap(NewColorSubdiv, *ColorMapSize, &newsize) != GIF_OK) { - free((char *) ColorArrayEntries); - return GIF_ERROR; - } - NewColorMapSize = (int)newsize; - if (NewColorMapSize < *ColorMapSize) { - /* And clear rest of color map: */ - for (i = NewColorMapSize; i < *ColorMapSize; i++) - OutputColorMap[i].Red = - OutputColorMap[i].Green = - OutputColorMap[i].Blue = 0; - } - - /* Average the colors in each entry to be the color to be used in the */ - /* output color map, and plug it into the output color map itself. */ - for (i = 0; i < NewColorMapSize; i++) { - if ((j = NewColorSubdiv[i].NumEntries) > 0) { - QuantizedColor = NewColorSubdiv[i].QuantizedColors; - Red = Green = Blue = 0; - while (QuantizedColor) { - QuantizedColor -> NewColorIndex = i; - Red += QuantizedColor -> RGB[0]; - Green += QuantizedColor -> RGB[1]; - Blue += QuantizedColor -> RGB[2]; - QuantizedColor = QuantizedColor -> Pnext; - } - OutputColorMap[i].Red = (Red << (8 - BITS_PER_PRIM_COLOR)) / j; - OutputColorMap[i].Green = (Green << (8 - BITS_PER_PRIM_COLOR)) / j; - OutputColorMap[i].Blue= (Blue << (8 - BITS_PER_PRIM_COLOR)) / j; - } - else - fprintf(stderr, "Null entry in quantized color map - thats weird."); - } - - /* Finally scan the input buffer again and put the mapped index in the */ - /* output buffer. */ - MaxRGBError[0] = MaxRGBError[1] = MaxRGBError[2] = 0; - for (i = 0; i < (int)(Width * Height); i++) { - Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) - << (2 * BITS_PER_PRIM_COLOR)) + - ((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) - << BITS_PER_PRIM_COLOR) + - (BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR)); - Index = ColorArrayEntries[Index].NewColorIndex; - OutputBuffer[i] = Index; - if (MaxRGBError[0] < ABS(OutputColorMap[Index].Red - RedInput[i])) - MaxRGBError[0] = ABS(OutputColorMap[Index].Red - RedInput[i]); - if (MaxRGBError[1] < ABS(OutputColorMap[Index].Green - GreenInput[i])) - MaxRGBError[1] = ABS(OutputColorMap[Index].Green - GreenInput[i]); - if (MaxRGBError[2] < ABS(OutputColorMap[Index].Blue - BlueInput[i])) - MaxRGBError[2] = ABS(OutputColorMap[Index].Blue - BlueInput[i]); - } - -#ifdef DEBUG - fprintf(stderr, - "Quantization L(0) errors: Red = %d, Green = %d, Blue = %d.\n", - MaxRGBError[0], MaxRGBError[1], MaxRGBError[2]); -#endif /* DEBUG */ - - free((char *) ColorArrayEntries); - - *ColorMapSize = NewColorMapSize; - - return GIF_OK; -} - -/****************************************************************************** -* Routine to subdivide the RGB space recursively using median cut in each * -* axes alternatingly until ColorMapSize different cubes exists. * -* The biggest cube in one dimension is subdivide unless it has only one entry.* -* Returns GIF_ERROR if failed, otherwise GIF_OK. * -******************************************************************************/ -static int SubdivColorMap(NewColorMapType *NewColorSubdiv, - unsigned int ColorMapSize, - unsigned int *NewColorMapSize) -{ - int MaxSize; - unsigned int i, j, Index = 0, NumEntries, MinColor, MaxColor; - long Sum, Count; - QuantizedColorType *QuantizedColor, **SortArray; - - while (ColorMapSize > *NewColorMapSize) { - /* Find candidate for subdivision: */ - MaxSize = -1; - for (i = 0; i < *NewColorMapSize; i++) { - for (j = 0; j < 3; j++) { - if (((int) NewColorSubdiv[i].RGBWidth[j]) > MaxSize && - NewColorSubdiv[i].NumEntries > 1) { - MaxSize = NewColorSubdiv[i].RGBWidth[j]; - Index = i; - SortRGBAxis = j; - } - } - } - - if (MaxSize == -1) - return GIF_OK; - - /* Split the entry Index into two along the axis SortRGBAxis: */ - - /* Sort all elements in that entry along the given axis and split at */ - /* the median. */ - if ((SortArray = (QuantizedColorType **) - malloc(sizeof(QuantizedColorType *) * - NewColorSubdiv[Index].NumEntries)) == NULL) - return GIF_ERROR; - for (j = 0, QuantizedColor = NewColorSubdiv[Index].QuantizedColors; - j < NewColorSubdiv[Index].NumEntries && QuantizedColor != NULL; - j++, QuantizedColor = QuantizedColor -> Pnext) - SortArray[j] = QuantizedColor; - qsort(SortArray, NewColorSubdiv[Index].NumEntries, - sizeof(QuantizedColorType *), SortCmpRtn); - - /* Relink the sorted list into one: */ - for (j = 0; j < NewColorSubdiv[Index].NumEntries - 1; j++) - SortArray[j] -> Pnext = SortArray[j + 1]; - SortArray[NewColorSubdiv[Index].NumEntries - 1] -> Pnext = NULL; - NewColorSubdiv[Index].QuantizedColors = QuantizedColor = SortArray[0]; - free((char *) SortArray); - - /* Now simply add the Counts until we have half of the Count: */ - Sum = NewColorSubdiv[Index].Count / 2 - QuantizedColor -> Count; - NumEntries = 1; - Count = QuantizedColor -> Count; - while (QuantizedColor -> Pnext != NULL && - QuantizedColor -> Pnext -> Pnext != NULL && - (Sum -= QuantizedColor -> Pnext -> Count) >= 0) { - QuantizedColor = QuantizedColor -> Pnext; - NumEntries++; - Count += QuantizedColor -> Count; - } - /* Save the values of the last color of the first half, and first */ - /* of the second half so we can update the Bounding Boxes later. */ - /* Also as the colors are quantized and the BBoxes are full 0..255, */ - /* they need to be rescaled. */ - MaxColor = QuantizedColor -> RGB[SortRGBAxis];/* Max. of first half. */ - if (QuantizedColor -> Pnext) MinColor = QuantizedColor -> Pnext -> RGB[SortRGBAxis];/* of second. */ - else MinColor = 0; - MaxColor <<= (8 - BITS_PER_PRIM_COLOR); - MinColor <<= (8 - BITS_PER_PRIM_COLOR); - - /* Partition right here: */ - NewColorSubdiv[*NewColorMapSize].QuantizedColors = - QuantizedColor -> Pnext; - QuantizedColor -> Pnext = NULL; - NewColorSubdiv[*NewColorMapSize].Count = Count; - NewColorSubdiv[Index].Count -= Count; - NewColorSubdiv[*NewColorMapSize].NumEntries = - NewColorSubdiv[Index].NumEntries - NumEntries; - NewColorSubdiv[Index].NumEntries = NumEntries; - for (j = 0; j < 3; j++) { - NewColorSubdiv[*NewColorMapSize].RGBMin[j] = - NewColorSubdiv[Index].RGBMin[j]; - NewColorSubdiv[*NewColorMapSize].RGBWidth[j] = - NewColorSubdiv[Index].RGBWidth[j]; - } - NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] = - NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] + - NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] - - MinColor; - NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] = MinColor; - - NewColorSubdiv[Index].RGBWidth[SortRGBAxis] = - MaxColor - NewColorSubdiv[Index].RGBMin[SortRGBAxis]; - - (*NewColorMapSize)++; - } - - return GIF_OK; -} - -/****************************************************************************** -* Routine called by qsort to compare to entries. * -******************************************************************************/ -static int SortCmpRtn(const void *Entry1, const void *Entry2) -{ - return (* ((QuantizedColorType **) Entry1)) -> RGB[SortRGBAxis] - - (* ((QuantizedColorType **) Entry2)) -> RGB[SortRGBAxis]; -}