Leadtools Send comments on this topic. | Back to Introduction - All Topics | Help Version 16.5.9.25
RasterPaintCallbacks Class
See Also  Members   Example 
Leadtools Namespace : RasterPaintCallbacks Class



The RasterPaintCallbacks class is used to implement custom painting. The RasterImage.PaintCallbacks property contains a list of such classes.

Syntax

Visual Basic (Declaration) 
Public Class RasterPaintCallbacks 
Visual Basic (Usage)Copy Code
Dim instance As RasterPaintCallbacks
C# 
public class RasterPaintCallbacks 
C++/CLI 
public ref class RasterPaintCallbacks 

Example

This C++ example will show the use of the RasterImage.PaintCallbacks property to implement custom callbacks.

For a full example source project that works with Barco Display devices, please contact Technical Support.

C#Copy Code
/* Use GlobalAlloc instead of malloc to avoid some known errors  
   ("The string binding is invalid") when an application written in C++/CLI exits, 
   These errors were supposed to be solved in Visual Studio 2005,  
   but we have encountered them during development. 
 
   So we switched to using GlobalAlloc in order to avoid complicating the code  
   unnecessarily with workarounds for these Microsoft compiler problems. 
*/ 
 
/***************** Macros ********************/ 
#define ALLOC(SIZE)           GlobalAllocPtr(GMEM_MOVEABLE, SIZE) 
#define FREE(PTR)             GlobalFreePtr(PTR) 
#define REALLOC(PTR, NEWSIZE) GlobalReAllocPtr(PTR, NEWSIZE, GMEM_MOVEABLE) 
 
#define DIB_WIDTH_BYTES(pixels) ((((pixels) + 31) & ~31) > > 3) 
#define SAFE_FREE(PTR) { if(PTR) { FREE(PTR); (PTR) = NULL; } } 
#define GET_HIGHBIT(IMAGE, HIGHBIT) ((HIGHBIT) == -1 ? (IMAGE)->BitsPerPixel - 1 : (HIGHBIT)) 
 
/* Hardcoded define that tells whether the LUT should be applied by the hardware or not. 
   We are leaving it here to show you how you can choose whether to pay attention to the lookup table or not */ 
#define IGNORELUT  TRUE 
 
namespace GrayCallbacks 

   // This class will convert a grayscale bitmap to a 16-bit image which has the 
   // image data in the low 12 bits. 
   // 
   // This type of image data can be be useful in painting to advanced  
   // medical display adapters that can display more than 256 shades of gray. 
   // 
   // One example of such display can be found at www.barco.com 
   //  
   // This example will also show you how to implement your own function 
   // for converting the image data. The built-in conversion function is capable of 
   // performing this conversion, but we are implementing it as an example. 
   public ref class MyRasterPaintCallbacks : public IDisposable 
   { 
      public: MyRasterPaintCallbacks(); 
      public: ~MyRasterPaintCallbacks(); 
      public: !MyRasterPaintCallbacks(); 
 
      // return a RasterPaintCallbacks class 
      public: Leadtools::RasterPaintCallbacks^ _rasterPaintCallbacks; 
      public: Leadtools::RasterPaintCallbacks^ GetRasterPaintCallbacks() 
      { 
         return _rasterPaintCallbacks; 
      }; 
 
      // member variables needed for the painting operations. These are volatile and change for each paint call 
      unsigned char        *_LocalConvertBuffer; 
      unsigned int         _LocalConvertBufferSize; 
 
      // callbacks 
      public: Object^ IsCompatibleDCCallback(RasterImage^ image, array<Object^>^ Params); 
      public: Object^ GetDibInfoCallback(RasterImage^ image, array<Object^>^ Params); 
      public: Object^ ConvertLineCallback(RasterImage^ image, array<Object^>^ Params); 
      public: Object^ StretchDIBitsCallback(RasterImage^ image, array<Object^>^ Params); 
      public: Object^ PrePaintCallback(RasterImage^ image, array<Object^>^ Params); 
 
      // internal functions 
      private: unsigned char *AllocateConvertBuffer(unsigned int uBytes); 
   }; 
 
   MyRasterPaintCallbacks::MyRasterPaintCallbacks() 
   { 
      _rasterPaintCallbacks = gcnew RasterPaintCallbacks(); 
 
      PaintCallbackDelegate ^f; 
       
      f = gcnew PaintCallbackDelegate(this, &MyRasterPaintCallbacks::IsCompatibleDCCallback); 
      _rasterPaintCallbacks->SetCallback(RasterImagePaintCallbackFunction::IsCompatibleDCCallback, f); 
 
      f = gcnew PaintCallbackDelegate(this, &MyRasterPaintCallbacks::GetDibInfoCallback); 
      _rasterPaintCallbacks->SetCallback(RasterImagePaintCallbackFunction::GetDibInfoCallback, f); 
 
      f = gcnew PaintCallbackDelegate(this, &MyRasterPaintCallbacks::ConvertLineCallback); 
      _rasterPaintCallbacks->SetCallback(RasterImagePaintCallbackFunction::ConvertLineCallback, f); 
 
      f = gcnew PaintCallbackDelegate(this, &MyRasterPaintCallbacks::StretchDIBitsCallback); 
      _rasterPaintCallbacks->SetCallback(RasterImagePaintCallbackFunction::StretchDIBitsCallback, f); 
 
      f = gcnew PaintCallbackDelegate(this, &MyRasterPaintCallbacks::PrePaintCallback); 
      _rasterPaintCallbacks->SetCallback(RasterImagePaintCallbackFunction::PrePaintCallback, f); 
   } 
 
   // destructor - might not get called all the time 
   MyRasterPaintCallbacks::~MyRasterPaintCallbacks() 
   { 
      this->!MyRasterPaintCallbacks(); 
   } 
 
   // finalizer - will always be called at some point 
   MyRasterPaintCallbacks::!MyRasterPaintCallbacks() 
   { 
      SAFE_FREE(_LocalConvertBuffer); 
   } 
 
   /* This function tells LEADTOOLS whether the HDC is for a comaptible display device.  
      If the display is not a compatible, the normal paint functions are used instead of my paint functions. 
      Since my advanced device is useful for rendering 12-bits of grayscale data, we will lie and say the  
      device is not compatible if the image is not 12/16-bit grayscale. 
 
      Parameters: 
         Param0: HDC hdc 
   */ 
   Object^ MyRasterPaintCallbacks::IsCompatibleDCCallback(RasterImage^ image, array<Object^>^ Params) 
   { 
      // we will reject images that are not grayscale because the regular GDI paint works for them 
      if((image->BitsPerPixel != 12 && image->BitsPerPixel != 16 && image->BitsPerPixel != 32) || image->Order != RasterByteOrder::Gray) 
         return false; 
 
      // also reject images that do not require at least 9-bits for painting 
      unsigned int uRequiredBits = GET_HIGHBIT(image, image->HighBit) - image->LowBit + 1; 
 
      if(uRequiredBits <= 8) 
      { 
         // Console.Error.WriteLine("The image has only {0} bits, so I can use the regular paint functions", uRequiredBits); 
         return false; 
      } 
 
      // You should always receive one parameter (HDC) 
      if(Params->Length != 1) 
         return false; 
 
      IntPtr hdcPtr = (IntPtr)Params[0]; 
      HDC   hdc = (HDC)hdcPtr.ToPointer(); 
      // you need to replace this call to a check that determines whether this DC is compatible 
      if(!IsMyDevice(hdc)) 
         return false; 
 
      /* Get information about your device here */ 
 
      return true; 
   } 
 
   /* This function tells LEADTOOLS how the data expected by my displays looks like. 
      I will convert the data to 16-bits per pixel, with the image data in the low 12 bits. 
       
      Parameters: 
         Param0: HDC hdc 
         Param1: unsigned int uWidth; 
 
      Returns 
         RasterPaintDibInfo 
   */ 
   Object^ MyRasterPaintCallbacks::GetDibInfoCallback(RasterImage^ image, array<Object^>^ Params) 
   { 
      if(Params->Length != 2 || image == nullptr) 
      { 
         throw gcnew RasterException(RasterExceptionCode::InvalidParameter); 
         return nullptr; 
      } 
      UInt32 uWidth = (UInt32)Params[1]; 
      RasterPaintDibInfo^ pDibInfo = gcnew RasterPaintDibInfo; 
      if(pDibInfo == nullptr) 
      { 
         throw gcnew RasterException(RasterExceptionCode::NoMemory); 
         return nullptr; 
      } 
 
      pDibInfo->Default(); 
      pDibInfo->BitsPerPixel = 16;          // paint using 16-bit data, although there are only 12 significant bits 
      pDibInfo->PlaneCount = 1;             // One plane 
      pDibInfo->BytesPerLine = DIB_WIDTH_BYTES(uWidth * 16);   // bytes per line is a multiple of 4 bytes 
      // assume my display device expects the image data to be top-down, unlike the regular GDI 
      pDibInfo->ViewPerspective = RasterViewPerspective::TopLeft; 
      pDibInfo->Order = RasterByteOrder::Gray;         // gray bitmap 
 
      // indicate that the data should be in the low 12 bits 
      pDibInfo->Flags = RasterPaintDibInfoFlags::LowHighBitValid; 
      pDibInfo->LowBit = 0; 
      pDibInfo->HighBit = 11; 
 
      if(IGNORELUT) 
         pDibInfo->Flags |= RasterPaintDibInfoFlags::IgnoreLut; // Ignore the LUT during conversion if I use hardware LUT 
 
      return pDibInfo; 
   } 
 
   // allocate a convert buffer of at least nBytes 
   unsigned char *MyRasterPaintCallbacks::AllocateConvertBuffer(unsigned int uBytes) 
   { 
      if(_LocalConvertBufferSize < uBytes) 
      { 
         unsigned char *pBuffer = (unsigned char *)REALLOC(_LocalConvertBuffer, uBytes); 
         if(!pBuffer) 
            return pBuffer; 
         _LocalConvertBuffer = pBuffer; 
         _LocalConvertBufferSize = uBytes; 
      } 
      return _LocalConvertBuffer; 
   } 
 
   /* callback function for converting data  
 
      Parameters: 
         Param0:  L_UCHAR* pOutScan    = Buffer to be filled with the output data. The first bytes correspond to pixel 'nLeft' in the input buffer 
         Param1:  L_UCHAR* pInScan     = Buffer containing the data for a row. Data starts at pixel 0 and might have to be truncated 
         Param2:  int nLeft          = Offset of the first pixel that should be converted. (Number of pixels from pInScan that should be skipped before doing the conversion) 
         Param3:  int nRight         = Offset of the first pixel that should NOT be converted. nRight - 1 is the last pixel that should be converted 
         Param4:  RasterPaintDibInfo^ pDibInfo = structure describing the output image. This was filled by the GetDibInfoCallback delegate (GetDibInfoCallback in our case) 
   */ 
   Object^ MyRasterPaintCallbacks::ConvertLineCallback(RasterImage^ image, array<Object^>^ Params) 
   { 
      if(Params->Length != 5) 
         return RasterExceptionCode::InvalidParameter; 
 
      unsigned char *pOutScan = (unsigned char*)((safe_cast<IntPtr>(Params[0])).ToPointer()); 
      unsigned char *pInScan = (unsigned char*)((safe_cast<IntPtr>(Params[1])).ToPointer()); 
      int nLeft = (int)Params[2]; 
      int nRight = (int)Params[3]; 
      RasterPaintDibInfo^ pDibInfo = safe_cast<RasterPaintDibInfo^>(Params[4]); 
      if(image == nullptr || pDibInfo == nullptr) 
         return RasterExceptionCode::NullPointer; 
 
      // allocate a larger buffer, just in case we need to round nLeft and nRight to a multiple of 2 
      unsigned char *pConvertBuffer = AllocateConvertBuffer(((nRight - nLeft + 2) * max(image->BitsPerPixel, 16) + 7) / 8); 
      if(pConvertBuffer == NULL) 
         return RasterExceptionCode::NoMemory; 
 
      int nLeftPixel = nLeft; 
      int nRightPixel = nRight; 
      if(image->BitsPerPixel == 12) 
      { 
         nLeftPixel &= ~1; // round down to multiple of 2 
         nRightPixel = (nRightPixel + 1) & ~1; 
         if(nRightPixel > image->Width) 
            nRightPixel--; 
      } 
      int nRightOffset = (nRightPixel * image->BitsPerPixel + 7) >> 3; 
      int nLeftOffset = (nLeftPixel * image->BitsPerPixel) >> 3; 
      // copy all pixels to convert buffer 
      CopyMemory(pConvertBuffer, pInScan + nLeftOffset, nRightOffset - nLeftOffset); 
 
      // convert to full 16-bit gray range 
      RasterBufferConverter::Convert(IntPtr(pConvertBuffer), nRightPixel - nLeftPixel, image->BitsPerPixel, 16, image->Order, RasterByteOrder::Gray,  
                           (pDibInfo->Flags & RasterPaintDibInfoFlags::IgnoreLut) == RasterPaintDibInfoFlags::None ? image->GetLookupTable() : nullptr, nullptr, 
                           (pDibInfo->Flags & RasterPaintDibInfoFlags::IgnoreLut) == RasterPaintDibInfoFlags::None ? image->GetLookupTable16() : nullptr, nullptr, 
                           image->PaintLowBit, image->PaintHighBit, 0, RasterConvertBufferFlags::SourceUseBits); 
 
      // convert the 16-bit buffer to pDibInfo->uLowBit..pDibInfo->uHighBit (if necessary) 
      if(pDibInfo->LowBit != 0 || pDibInfo->HighBit != 15) 
         RasterBufferConverter::Convert(IntPtr(pConvertBuffer), nRightPixel - nLeftPixel, 16, 16, RasterByteOrder::Gray, RasterByteOrder::Gray,  
                           nullptr, nullptr,  
                           pDibInfo->LowBit, pDibInfo->HighBit, 0, RasterConvertBufferFlags::DestinationUseBits); 
 
      // copy the data to the output buffer 
      CopyMemory(pOutScan, pConvertBuffer + (nLeft - nLeftPixel) * 2, (nRight - nLeft) * 2); 
 
      return RasterExceptionCode::Success; 
   } 
 
   /* callback function for implementing StretchDIBits. See the documentation for StretchDIBits for more info. 
 
      Parameters: 
         Param0:  HDC hdc 
         Param1:  int nXDest 
         Param2:  int nYDest 
         Param3:  int nDestWidth 
         Param4:  int nDestHeight 
         Param5:  int nXSrc 
         Param6:  int nYSrc 
         Param7:  int nSrcWidth 
         Param8:  int nSrcHeight 
         Param9:  const L_VOID* lpvBits = pointer to the DIB data (unmanaged) 
         Param10: const BITMAPINFO* lpbmi = pointer to the BITMAPINFO structure (unmanaged) 
         Param11: unsigned int fuColorUse 
         Param12: unsigned int32 ulROP3Code 
   */ 
   Object^ MyRasterPaintCallbacks::StretchDIBitsCallback(RasterImage^ image, array<Object^>^ Params) 
   { 
      if(Params->Length != 13) 
         return RasterExceptionCode::InvalidParameter; 
 
      // allocate it, since I can't put it on the stack 
      HDC                  hdc = (HDC)safe_cast<IntPtr>(Params[0]).ToPointer(); 
      int                  nXDest = (int)Params[1]; 
      int                  nYDest = (int)Params[2]; 
      int                  nDestWidth = (int)Params[3]; 
      int                  nDestHeight = (int)Params[4]; 
      int                  nXSrc = (int)Params[5]; 
      int                  nYSrc = (int)Params[6]; 
      int                  nSrcWidth = (int)Params[7]; 
      int                  nSrcHeight = (int)Params[8]; 
      const VOID*          lpvBits = (safe_cast<IntPtr>(Params[9])).ToPointer(); 
      const BITMAPINFO*    lpbmi = (BITMAPINFO *)(safe_cast<IntPtr>(Params[10])).ToPointer(); 
      unsigned int         fuColorUse = (unsigned int)Params[11]; 
      unsigned long        ulROP3Code = (unsigned int)Params[12]; 
 
      // replace this with a call to your device's StretchDIBits equivalent 
      return CallMyStretchDiBits( hdc, nXDest, nYDest, nDestWidth, nDestHeight, nXSrc, nYSrc, nSrcWidth, nSrcHeight 
                           lpvBits, lpbmi, fuColorUse, ulROP3Code); 
   } 
 
   /* callback function preparing the paint 
 
      Parameters: 
         Param0:  HDC hdc 
         Param1:  LPRECT prcDestClip 
   */ 
   Object^ MyRasterPaintCallbacks::PrePaintCallback(RasterImage^ image, array<Object^>^ Params) 
   { 
      if(Params->Length != 2) 
         return RasterExceptionCode::InvalidParameter; 
 
      HDC hdc = (HDC)(safe_cast<IntPtr>(Params[0])).ToPointer(); 
      LPRECT prcDestClip = (LPRECT)(safe_cast<IntPtr>(Params[1])).ToPointer(); 
 
      /* Do any initialization needed by your device */ 
 
      return RasterExceptionCode::Success; 
   } 
}

Remarks

The RasterPaintCallbacks class can contain one or more custom paint callbacks.

The callbacks are used to

  • Check whether the display adapter is compatible
  • Get information about the data expected by the display adapter
  • Do the actual painting
  • Initialize before and cleanup after the paint

Typically, you would create a class for each display adapter you want to support and add them all to the RasterImage.PaintCallbacks list. The reason for needing a list is this: the computer running the application might have more than one monitor and more than one display adapter. The user can drag the window from one monitor to another so you should populate the RasterImage.PaintCallbacks list with all the custom paint objects compatible with the display adapters in the system. Or you can just add all the display adapters you can support since the overhead for having unnecessary callbacks in the list is low.

Whenever the RasterImage object needs to paint, it searches through the RasterImage.PaintCallbacks list until it finds a compatible RasterPaintCallbacks object. If the list is empty or there is no compatible RasterPaintCallbacks object, the default paint functions are used.

Inheritance Hierarchy

System.Object
   Leadtools.RasterPaintCallbacks

Requirements

Target Platforms: Microsoft .NET Framework 3.0, Windows XP, Windows Server 2003 family, Windows Server 2008 family

See Also