Wednesday, January 4, 2012

Using ManualResetEvent to Wait

This one time, at band camp, I was using a PDF library from third-party to generate PNG thumbnails of the pages. The library was set up in such a way that thumbnail generation was forked to a separate thread with only an event handler to notify when rendering was complete.

Since this code was going to serve the thumbnail file from a web server, I needed to file to be ready before delivering the web response. I had to wait until the event fired--a sort of "re-synchronization" or "de-asynchronization", if you will.

Enter the ManualResetEvent. With some blogger help, I was able to put together the following:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;

// http://code.google.com/p/pdfviewer-win32
using PDFLibNet;

namespace InSite.Portal.Helpers
{
    public class PdfHelper
    {
        PDFWrapper _pdf;

        public PdfHelper(string sourceFilePath)
        {
            _pdf = new PDFWrapper();
            _pdf.LoadPDF(sourceFilePath);
        }
       
        public void SavePageAsImage(string destFilePath, int page)
        {
            SavePageAsImage(destFilePath, page, ImageFormat.Png);
        }
        
        public void SavePageAsImage(string destFilePath, int page, ImageFormat format)
        {
            ManualResetEvent _mre = new ManualResetEvent(false);
            var renderPageThumbnailFinished = new RenderNotifyFinishedHandler((i, s) => { _mre.Set(); });

            var pg = _pdf.Pages[page];
            pg.RenderThumbnailFinished += renderPageThumbnailFinished;
            var h = Convert.ToInt32(pg.Height); // get height
            var w = Convert.ToInt32(pg.Width);  // get width
            var bmp = pg.LoadThumbnail(w, h);   // call thumbnail render
            _mre.WaitOne(30 * 1000, true);      // wait until render complete (30 sec timeout)
            bmp.Save(destFilePath, format);     // save completed image
            pg.RenderThumbnailFinished -= renderPageThumbnailFinished;
        }

        public int PageCount
        {
            get
            {
                return _pdf.PageCount;
            }
        }
    }
}

Crude? Elegant? Either way, it gets the job done.

No comments:

Post a Comment