←Select platform

FilterHeartbeat Event

Summary

Event for tracking and aborting long-running operations.

Syntax
C#
C++/CLI
Python
public event EventHandler<CodecsFilterHeartbeatEventArgs> FilterHeartbeat 
public:  
   event EventHandler<CodecsFilterHeartbeatEventArgs^>^ FilterHeartbeat 
def FilterHeartbeat(sender,e): # sender: RasterCodecs e: CodecsFilterHeartbeatEventArgs 
Event Data
Parameter Type Description
sender object The source of the event
e CodecsFilterHeartbeatEventArgs The event data
Remarks

The RasterCodecs class contains the LoadImage event. It is used to monitor the progress of loading images by calling Load or LoadSvg. The LoadImage event is quite suitable for raster images: the filter (PNG or TIF, for instance), can parse the image file structure quickly and start to send one or more scanlines to the event quickly. Consequently, LoadImage events will start to occur shortly after Load/LoadSvg is called. The application can use LoadImage to show a progress bar to allow the user to monitor and potentially abort the load operation.

The LoadImage event does not work well with complex document file formats such as DOCX and XSLX. Their complex structure requires significantly more time to parse the file structure. The first scanline generated and sent to the LoadImage event may not occur until well after Load/LoadSvg was called. The amount of time required for loading depends on the source file itself. For a very complex document file such as a very large XLSX spreadsheet with thousands or millions of rows, the time can be many seconds or even minutes. Moreover, file structure parsing usually occurs by calling GetInformation (whether called directly by the user, or internally by Load/LoadSvg), none of which invoke the LoadImage event at all.

For complex documents, using the LoadImage event to allow the user to abort long load operations is not feasible: the event will occur at the very end of the operation after all the necessary data has been parsed. A significant amount of time could have elapsed since the original Load/LoadSvg was called. Instead, the application can use the FilterHeartbeat event to monitor and abort very long operations. The FilterHeartbeat event occurs at the beginning of GetInformation, and then again periodically during this function and Load/LoadSvg, allowing the user to abort the current operation if desired.

The FilterHeartbeat event will fire with an instance of CodecsFilterHeartbeatEventArgs, and when CodecsFilterHeartbeatEventArgs.Abort is set to true, RasterCodecs will abort the current operation as follows:

In other words, aborting a filter operation does not throw an exception. Instead, the application should check the returned object as described above to detect when the user aborted.

Some applications require all load operations that take more than a certain time to be aborted (for instance, a web server using LEADTOOLS to load and return images in a web method). This server may require that no operation running within the web method can take more than 2 seconds. When this occurs, the operation should be aborted, and the work delegated to a dedicated thread or process outside of the web service worker thread.

FilterHeartbeat can be used to install an event that tracks the time and aborts all operations taking more than the allocated time. Or, the RasterCodecs.Options.Timeout property can be used to set a global timeout interval for all get information and load operations in a RasterCodecs object. This class uses FilterHeartbeat internally to install a handler that can take care of aborting long-running operations automatically.

Currently filter heartbeat and timeout is only supported for the following file formats:

  • DOCX/DOC
  • RTF
  • TXT
  • XLSX/XLS
Example
C#
Java
using Leadtools; 
using Leadtools.Codecs; 
using Leadtools.ImageProcessing; 
using Leadtools.ImageProcessing.Color; 
using Leadtools.Svg; 
 
 
// Call this method with a very large and complex XLSX document and a timeout in seconds value 
// Returns true on success and false if aborted 
// For each page, the image is loaded and passed to the processImage action 
public bool FilterHeartbeatExample(string inputFileName, int timeoutSeconds, Action<RasterImage, int> processImage) 
{ 
   using (var rasterCodecs = new RasterCodecs()) 
   { 
      // This is the start time, we will reset this value 
      // anytime we start an operation 
      DateTime startOperationTime = DateTime.Now; 
 
      // Create a heartbeat handler 
      EventHandler<CodecsFilterHeartbeatEventArgs> heartbeatHandler = (sender, e) => 
      { 
         // Abort if it has been more than timeoutSeconds since last operation 
         TimeSpan timeSpan = DateTime.Now - startOperationTime; 
         if (timeSpan.TotalSeconds > timeoutSeconds) 
         { 
            e.Abort = true; 
         } 
      }; 
 
      // Install the heartbeat handler 
      rasterCodecs.FilterHeartbeat += heartbeatHandler; 
 
      // First, get information on the file to get the number of pages 
      RasterImageFormat format; 
      int pageCount = 0; 
 
      // Reset the start time 
      startOperationTime = DateTime.Now; 
      using (CodecsImageInfo imageInfo = rasterCodecs.GetInformation(inputFileName, true)) 
      { 
         // If GetInformationt took more than timeoutSeconds then we aborted the operation 
         // inside heartbeatHandler and GetInformation will return RasterImageFormat.Unknown 
         format = imageInfo.Format; 
         if (format != RasterImageFormat.Unknown) 
            pageCount = imageInfo.TotalPages; 
      } 
 
      // Did we abort? 
      if (format == RasterImageFormat.Unknown) 
      { 
         // Yes, fail 
         rasterCodecs.FilterHeartbeat -= heartbeatHandler; 
         return false; 
      } 
 
      // Now load all the pages 
 
      for (int pageNumber = 1; pageNumber <= pageCount; pageNumber++) 
      { 
         // Reset the start time 
         startOperationTime = DateTime.Now; 
         RasterImage image = rasterCodecs.Load(inputFileName, pageNumber); 
         // If Load took more than timeoutSeconds then we aborted the operation 
         // inside heartbeatHandler and Load will return null 
 
         // Did we abort? 
         if (image == null) 
         { 
            // Yes, fail 
            rasterCodecs.FilterHeartbeat -= heartbeatHandler; 
            return false; 
         } 
 
         // Process the image and then delete it 
         processImage(image, pageNumber); 
         image.Dispose(); 
      } 
 
      rasterCodecs.FilterHeartbeat -= heartbeatHandler; 
 
      // We successfully loaded and processed all the pages from the file 
      return true; 
   } 
} 
 
import java.io.*; 
import java.net.*; 
import java.nio.file.Paths; 
import java.util.*; 
import java.time.Instant; 
import java.time.Duration; 
 
import org.junit.*; 
import org.junit.runner.JUnitCore; 
import org.junit.runner.Result; 
import org.junit.runner.notification.Failure; 
import static org.junit.Assert.*; 
 
import leadtools.*; 
import leadtools.codecs.*; 
import leadtools.codecs.RasterCodecs.FeedCallbackThunk; 
import leadtools.drawing.internal.*; 
import leadtools.imageprocessing.*; 
import leadtools.imageprocessing.color.ChangeIntensityCommand; 
import leadtools.svg.*; 
 
 
Instant start; 
int timeoutSeconds; 
 
public void filterHeartbeatExample() throws InterruptedException { 
   final String LEAD_VARS_IMAGES_DIR = "C:\\LEADTOOLS23\\Resources\\Images"; 
   String inputFileName = combine(LEAD_VARS_IMAGES_DIR, "large_sheet_5k.xlsx"); 
   RasterCodecs rasterCodecs = new RasterCodecs(); 
 
   Calendar.getInstance(); 
   start = Instant.now(); 
   timeoutSeconds = 20; 
 
   // Create a heartbeat handler 
   // Install the heartbeat handler 
   rasterCodecs.addFilterHeartbeatListener(heartbeatHandler); 
 
   // First, get information on the file to get the number of pages 
   RasterImageFormat format; 
   int pageCount = 0; 
 
   Calendar.getInstance(); 
   CodecsImageInfo imageInfo = rasterCodecs.getInformation(inputFileName, true); 
 
   // If GetInformation took more than timeoutSeconds then we aborted the 
   // operation 
   // inside heartbeatHandler and GetInformation will return 
   // RasterImageFormat.Unknown 
   format = imageInfo.getFormat(); 
   if (format != RasterImageFormat.UNKNOWN) { 
      pageCount = imageInfo.getTotalPages(); 
   } 
 
   // Did we abort? 
   if (format == RasterImageFormat.UNKNOWN) { 
      // Yes, fail 
      rasterCodecs.addFilterHeartbeatListener(heartbeatHandler); 
      return; 
   } 
 
   // Now load all the pages 
   for (int pageNumber = 1; pageNumber <= pageCount; pageNumber++) { 
      // Reset the start time 
      start = Instant.now(); 
      RasterImage image = rasterCodecs.load(inputFileName, pageNumber); 
      // If Load took more than timeoutSeconds then we aborted the operation 
      // inside heartbeatHandler and Load will return null 
 
      // Did we abort? 
      if (image == null) { 
         // Yes, fail 
         rasterCodecs.addFilterHeartbeatListener(heartbeatHandler); 
         return; 
      } 
 
      // Process the image and then delete it 
      processImage(image, pageNumber); 
      image.dispose(); 
   } 
 
   rasterCodecs.addFilterHeartbeatListener(heartbeatHandler); 
 
   // We successfully loaded and processed all the pages from the file 
   return; 
} 
 
CodecsFilterHeartbeatListener heartbeatHandler = new CodecsFilterHeartbeatListener() { 
 
   public void onHeartbeat(CodecsFilterHeartbeatEvent e) { 
      // Abort if it has been more than timeoutSeconds since last operation 
      Instant end = Instant.now(); 
      Duration timeElapsed = Duration.between(start, end); 
      if (timeElapsed.getSeconds() > timeoutSeconds) { 
         e.setAbort(true); 
      } 
   } 
 
}; 
Requirements

Target Platforms

Help Version 23.0.2024.2.29
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2024 LEAD Technologies, Inc. All Rights Reserved.

Leadtools.Codecs Assembly
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2023 LEAD Technologies, Inc. All Rights Reserved.