TiffBitmapEncoder: сделать асинхронное растровое кодирование

Проблема: как сохранить / сжать растровые изображения (несколько из них сложены в tiff файл) асинхронно по отношению к основному потоку?

Мои настройки: (синхронное и медленное рабочее решение: когда выполняется сжатие, поток остается на несколько секунд. Я не могу себе этого позволить.)

 ...in the body of a window class 

private void afunction(){ 
     //called with a given frequency and updating this.colorBitmap
     ...
     this.colorBitmap = something;          
     savePictureStackTiff();
}

private int stack_pict_count = 0;
private int PICT_PER_FILE = 45;        
private TiffBitmapEncoder encoder;        

private string savePictureStackTiff()
{
      initializeTiffEncoder();
      //make a local copy of the image I want to put in the tiff binder
      WriteableBitmap localCopy = new WriteableBitmap(this.colorBitmap);    

      encoder.Frames.Add(BitmapFrame.Create(localCopy));  

      stack_pict_count++;
      if (stack_pict_count % PICT_PER_FILE == 0) 
      //Once I have enough files stacked I ask for compression
      {              
          stack_pict_count = 0;
          pict_metadata = "";            
          try
          {
              using (FileStream fs = new FileStream(path, FileMode.Create))
              {
                  encoder.Save(fs); //<<<== LINE WHICH I'D LIKE TO BE RUN ASYNC
              }                    
           }
           catch (IOException)
           {}               
        }
 }

 private void initializeTiffEncoder()
 {
    if (stack_pict_count == 0)
    {                
        encoder = new TiffBitmapEncoder();
        encoder.Compression = TiffCompressOption.Zip;                
    }
 }

То, что я пытался: я хотел бы сжатие (вызов encoder.save(fs)) должен выполняться в другом потоке, чем основной.

Я пытался позвонить encoder.save(fs) в BackgroundWorker который превентивно копирует кодировщик в локальную версию (хотя не уверен, что он работал), а затем выполняет вызов. Я получаю сообщение об ошибке типа "Вызывающий поток не может получить доступ к этому объекту, потому что другой поток владеет им".

Если я использую Dispatcher.Invoke (при условии, что я делаю это правильно) выполнение снова становится очень медленным.

Я совершил глупую ошибку?


РЕДАКТИРОВАТЬ: (работа в соответствии с предложениями @meilke и @user7116)

Теперь я перенес распределение и исполнение компрессора в BackgroundWorker, Хотя сейчас colorBitmap который передается, принадлежит другому потоку. Я пытался freeze это, но это не выглядит достаточно; Я все еще получаю "Вызывающий поток не может получить доступ к этому объекту, потому что другой поток владеет им".

        tiffCompressorWorker = new BackgroundWorker();
        tiffCompressorWorker.DoWork += (s, a) =>
        {

            initializeTiffEncoder();
            WriteableBitmap localCopy = new WriteableBitmap((WriteableBitmap)a.Argument);
            localCopy.Freeze();
            encoder.Frames.Add(BitmapFrame.Create(localCopy));

            stack_pict_count++;
            if (stack_pict_count % PICT_PER_FILE == 0)
            {
                stack_pict_count = 0;                    
                try
                {
                    using (FileStream fs = new FileStream(path, FileMode.Create))
                    {
                        saving_encoder.Save(fs);
                    }
                }
                catch (IOException)
                {
                    ..
                }
            }            
        };

2 ответа

Вы должны поместить всю операцию TIFF в фоновый рабочий. А затем передать копию входного изображения в качестве аргумента RunWorkerAsync, Вот ссылка на одно из многих доступных в сети решений о том, как это сделать: Копирование из BitmapSource в WritableBitmap. Поместите этот код в вспомогательный метод и используйте его для копирования изображения перед сохранением его на диск.

Я не информатик, но я нашел этот пост, в котором говорится:

WriteableBitmap наследует DispatcherObject и должен быть доступен только в потоке диспетчера, которому он принадлежит.

И мне кажется, что вы выходите за пределы разрешений DispatcherObject.

Другие вопросы по тегам