Постараюсь максимально ёмко уместить свой вопрос. Пока писал этот вопрос понял, что можно было написать короче. Вся суть в двух последних предложениях.
Идея: хранить FlowDocument(xaml файл) и картинки(они хранятся в папке media) в одном zip архиве. И в теории все неплохо.
Проблема: тяжело сделать Source у BitmapImage, так как нет Uri до файла, который находится в архиве
Допустим мы вставили картинку в RichTextBox. И когда мы ее вставили, то UriSource и BaseUri картинки выглядит так (внимание на pack://payload:):
<?xml version="1.0"?>
<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
NumberSubstitution.CultureSource="User" AllowDrop="True" PagePadding="5,0,5,0">
<BlockUIContainer TextAlignment="Justify">
<Image Height="400" Width="600">
<Image.Source>
<BitmapImage CacheOption="OnLoad" UriSource="./Image1.bmp"
BaseUri="pack://payload:,,wpf1,/Xaml/Document.xaml"/>
</Image.Source>
</Image>
</BlockUIContainer>
</FlowDocument>
Всю эту радость надо сохранить. Как это делаю я:
ищу картинки в FlowDocument (Найти картинки в FlowDocument)
сохраняю их в папке media
меняю Source картинки на null, и в Tag картинки записываю путь относительно Кусок кода (без создания папок):
private void Save_Executed(object sender, ExecutedRoutedEventArgs e)
{
\\omitted
string richTextBoxFlowDocument = xamlWriter.Save(rtbEditor.Document);
//Копия FlowDocument
FlowDocument rtbDocumentCopy = (FlowDocument)XamlReader.Parse(richTextBoxFlowDocument);
//Находим все картинки в RichTextBox
List<Image> images = FindImages(rtbDocumentCopy).ToList();
foreach (var image in images)
{
\\Omitted
BitmapEncoder encoder = new PngBitmapEncoder();
//Делаем BitmapImage из image source
var imageToSave = image.Source as BitmapImage;
encoder.Frames.Add(BitmapFrame.Create(imageToSave));
//Сохраняем картинку
using (var fileStream = new FileStream(pathToMediaPlusNewFile, FileMode.Create))
{
encoder.Save(fileStream);
}
//Записываем в Tag место картинки относительно flowdocument,
image.Tag = nameofMediaFolder + "/" + eligibleMediaFileName;
//Если source не указан, то всем плевать
image.Source = null;
}
richTextBoxFlowDocument = XamlWriter.Save(rtbDocumentCopy);
File.WriteAllText(nameOfXamlRelativePath, richTextBoxFlowDocument, Encoding.UTF8);
//Зипуем папку
ZipFile.CreateFromDirectory(cardGUIDFolderRelativePath, cardGUIDFolderRelativePath + ".zip");
//Удаляем папку и все содержимое
Directory.Delete(cardGUIDFolderRelativePath, true);
}
На этом этапе все хорошо, если у всех Image есть правильные Uri из которых можно сделать картинку.
Теперь это нужно открыть и заново сохранять. Одной из моих попыток было сделать List<MemoryStream>
в каждый поток запихнуть по картинке, которую прочитаю из zip и потом из потока их и сохранять. Но сразу признаюсь, что в Stream я плохо разобрался.
Открываем:
List<MemoryStream> memoryStreams = new List<MemoryStream>();
private void Open_Executed(object sender, ExecutedRoutedEventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
if (dlg.ShowDialog() == true)
{
//Открываем zip файл. UserData\<GUID>
using (FileStream fullCardZipFile = File.Open(dlg.FileName, FileMode.Open, FileAccess.ReadWrite))
{
//Смотрим zip c ZipArchive
using (ZipArchive archive = new ZipArchive(fullCardZipFile, ZipArchiveMode.Update))
{
//Получаем entry для нашего xaml.
ZipArchiveEntry xamlFileEntry = archive.GetEntry(nameOfXamlCardDefault);
//Открываем наш xaml
using (Stream xamlFileStreamInZip = xamlFileEntry.Open())
{
rtbEditor.Document = XamlReader.Load(xamlFileStreamInZip) as FlowDocument;
//Ищем картинки
List<Image> images = FindImages(rtbEditor.Document).ToList();
foreach (var image in images)
{
var imageFileEntry = archive.GetEntry(image.Tag.ToString());
var bitmap = new BitmapImage();
using (Stream imageFileStream = imageFileEntry.Open())
{
//Инициализирую MemoryStream
var memoryStream = new MemoryStream();
imageFileStream.CopyTo(memoryStream);
memoryStreams.Add(memoryStream);
//Делаю картинку
bitmap.BeginInit();
bitmap.StreamSource = memoryStreams.Last();
bitmap.CacheOption = BitmapCacheOption.OnDemand;
bitmap.EndInit();
image.Source = bitmap;
}
}
}
}
}
}
return;
}
И в RichTextBox Document получается такое:
<?xml version="1.0"?>
<FlowDocument xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
NumberSubstitution.CultureSource="User" AllowDrop="True"
PagePadding="5,0,5,0">
<Paragraph>
<Image Tag="Media/image0.png">
<Image.Source>
<BitmapImage CacheOption="OnDemand" BaseUri="{x:Null}"/>
</Image.Source>
</Image>
<Image Tag="Media/image1.png">
<Image.Source>
<BitmapImage CacheOption="OnDemand" BaseUri="{x:Null}"/>
</Image.Source>
</Image>
</Paragraph>
</FlowDocument>
И такое чудо уже не сохранить, так как нет нормального Source у BitmapImage. InvalidOperationException: Необходимо задать свойство "UriSource" или "StreamSource".
Что я делал:
Это все работало, но я хочу сохранять картинку в MemoryStream и когда сохраняю в zip-файл, из MemoryStream картинку и доставать, также как это делает сама программа с чудо pack://payload:,,. Как это сделать?
Виртуальный выделенный сервер (VDS) становится отличным выбором
Клиент записывает в сокет последовательно значения Uint, Uint, Short
Какой самый надёжный метод определения системных процессов в системе?
Есть zip файл, в котором хранится FlowDocument (Cardxaml) и папка с изображениями (Media)
Есть код, который переводит все в двоичный кодТеперь мне нужно задать числу 1 - черный цвет, а 0 - белый цвет