Search code examples
multithreadingleadtools-sdk

(Leadtools) Rastercodecs.load is thread safe?


I want to convert a PDF to images. I am using Leadtools and to increase the speed, I am using multi-threading in the following way.

string multiPagePDF = @"Manual.pdf";
string destFileName = @"output\Manual";
Task.Factory.StartNew(() =>
{
    using (RasterCodecs codecs = new RasterCodecs())
    {
        CodecsImageInfo info = codecs.GetInformation(multiPagePDF, true);
        ParallelOptions po = new ParallelOptions();
        po.MaxDegreeOfParallelism = 5;
        Parallel.For(1, multiPagePDF.TotalPages+1, po, i =>
        {
            RasterImage image = codecs.Load(multiPagePDF, i);
            codecs.Save(image, destFileName + i + ".png", RasterImageFormat.Png, 0);
         });  
    }       
});

Is this a thread-safe manner? Will it result in unexpected output? I tried this a few times and there were instances when a specific page appeared twice in the output images.

Solution

According to Leadtools online chat support (which is very helpful btw), Rastercodecs.load is NOT thread safe and the above code would result in unexpected output (in my case, Page 1 occurred twice in the output set of images). The solution is to define codecs variable within the Parallel.For so that each iteration separately accesses its own RasterCodecs.


Solution

  • Amyn, As you found out, the correct way to use the RasterCodecs object in this case is this:

    Task.Factory.StartNew(() =>
    {
       using (RasterCodecs codecs = new RasterCodecs())
       {
          CodecsImageInfo info = codecs.GetInformation(multiPagePDF, true);
          ParallelOptions po = new ParallelOptions();
          po.MaxDegreeOfParallelism = 5;
          Parallel.For(1, info.TotalPages + 1, po, i =>
          {
             using(RasterCodecs codecs2 = new RasterCodecs()) {
               RasterImage image = codecs2.Load(multiPagePDF, i);
               codecs2.Save(image, destFileName + i + ".png", RasterImageFormat.Png, 0);
             }
          });
       }
    });
    

    This gives you the same speed benefits when running on a multi-core processor without causing any conflicts between concurrent threads.

    The LEADTOOLS RasterCodecs.Load() and RasterCodecs.Save() methods are thread-safe. The reason behind creating multiple instances of the RasterCodecs class is because this class internally uses structures that hold many different loading & saving options for files. Using these structures (where these options are changed) across multiple threads can cause unpredictable results. One such property in the loading options structure is the page number. For this reason, using separate instances of this class is recommended.