private static void CreateThumbnail(BlockingCollection <BitmapWithFilePath> inputQueue, BlockingCollection <BitmapWithFilePath> outputQueue, CancellationTokenSource cts)
        {
            CancellationToken token = cts.Token;

            try
            {
                foreach (var input in inputQueue.GetConsumingEnumerable(token))
                {
                    if (token.IsCancellationRequested)
                    {
                        break;
                    }

                    var result    = ImageProcessor.ResizeToThumbnail(input.Image);
                    var outputObj = new BitmapWithFilePath()
                    {
                        FilePath = input.FilePath,
                        Image    = result
                    };
                    outputQueue.Add(outputObj, token);
                }
            }
            catch (Exception ex)
            {
                if (!(ex is OperationCanceledException))
                {
                    cts.Cancel();
                    throw;
                }
            }
            finally
            {
                outputQueue.CompleteAdding();
            }
        }
        private static void RemoveBackground(BlockingCollection <BitmapWithFilePath> inputQueue, Bitmap background_bm, BlockingCollection <BitmapWithFilePath>[] outputQueues, CancellationTokenSource cts)
        {
            CancellationToken token = cts.Token;

            try
            {
                foreach (var input in inputQueue.GetConsumingEnumerable(token))
                {
                    if (token.IsCancellationRequested)
                    {
                        break;
                    }

                    lock (input.Image)
                    {
                        lock (background_bm)
                        {
                            var result = ImageProcessor.RemoveBackground(input.Image, background_bm);
                            for (int i = 0; i < outputQueues.Length; i++)
                            {
                                if (token.IsCancellationRequested)
                                {
                                    break;
                                }

                                var outputObj = new BitmapWithFilePath()
                                {
                                    FilePath = input.FilePath,
                                    Image    = (Bitmap)result.Clone()
                                };
                                outputQueues[i].Add(outputObj, token);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                if (!(ex is OperationCanceledException))
                {
                    cts.Cancel();
                    throw;
                }
            }
            finally
            {
                foreach (var outputQueue in outputQueues)
                {
                    outputQueue.CompleteAdding();
                }
            }
        }
        private static void LoadImages(string InputDirectory, BlockingCollection <BitmapWithFilePath> outputQueue, CancellationTokenSource cts)
        {
            CancellationToken token = cts.Token;

            try
            {
                foreach (string filePath in Directory.GetFiles(InputDirectory))
                {
                    if (token.IsCancellationRequested)
                    {
                        break;
                    }

                    if (Path.GetExtension(filePath) == ".bmp")
                    {
                        Bitmap bm = ImageProcessor.LoadFileAsImage(filePath);

                        var outputObj = new BitmapWithFilePath()
                        {
                            FilePath = filePath,
                            Image    = bm
                        };
                        outputQueue.Add(outputObj, token);
                    }
                }
            }
            catch (Exception ex)
            {
                if (!(ex is OperationCanceledException))
                {
                    cts.Cancel();
                    throw;
                }
            }
            finally
            {
                outputQueue.CompleteAdding();
            }
        }