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.