FileFormatException при сериализации FixedDocument

При сериализации FixedDocument в XPS я иногда получаю сообщение FileFormatException о том, что формат шрифта (как я полагаю) не соответствует ожидаемой спецификации формата файла (см. исключение ниже).

Загадочная часть:

  • Исключение будет происходить только время от времени
  • Это произойдет только для определенных комбинаций FontFamily/Style/Weight (пользовательский интерфейс Segoe, выделенный курсивом и жирным шрифтом, кажется, вызывает это)

Кто-нибудь знает, почему это происходит (и особенно почему это происходит не постоянно, а только через непредсказуемые промежутки времени)?

Следующий минимальный воспроизводимый пример вызовет исключение примерно от 4 до 5 раз за запуск (на моем компьютере с Windows 10 это происходит с .NET 4, 4.6.1 и т. д.):

private void TestXpsSerialization(object a)
{
    for (int i = 0; i < 400; ++i)
    {
        TextBlock block = new TextBlock
        {
            Text = "Test",
            FontFamily = new FontFamily("Segoe UI"),
            FontStyle = FontStyles.Italic,
            FontWeight = FontWeights.Bold,
            Background = null,
            FontSize = 12
        };
        FixedDocument fixedDoc = new FixedDocument();

        PageContent pageContent = new PageContent();
        FixedPage fixedPage = new FixedPage();
        fixedPage.Children.Add(block);
        ((IAddChild) pageContent).AddChild(fixedPage);
        fixedDoc.Pages.Add(pageContent);
        using (MemoryStream documentStream = new MemoryStream())
        {
            string inMemoryPackageName = string.Format("memorystream://{0}.xps", Guid.NewGuid());
            Uri packageUri = new Uri(inMemoryPackageName);
            using (Package package = Package.Open(documentStream, FileMode.CreateNew))
            {
                MemoryStream resultStream = new MemoryStream();
                PackageStore.AddPackage(packageUri, package);
                using (XpsDocument xpsd =
                new XpsDocument(package, CompressionOption.Maximum, inMemoryPackageName))
                {
                    XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(xpsd);
                    writer.Write(fixedDoc);
                    package.Flush();

                    using (MemoryStream outputStream = new MemoryStream())
                    {
                        SerializerWriter serializerWriter =
                        new XpsSerializerFactory().CreateSerializerWriter(outputStream);

                        bool success = true;
                        try
                        {
                            serializerWriter.Write(xpsd.GetFixedDocumentSequence());
                        }
                        catch (Exception e)
                        {
                            success = false;
                            Debug.WriteLine(e);
                        }
                        if (success)
                        {
                            outputStream.Seek(0, SeekOrigin.Begin);
                            outputStream.CopyTo(resultStream);
                        }
                    }
                }
                PackageStore.RemovePackage(packageUri);
                Debug.WriteLine(resultStream.Length);
            }
        }
    }
}

Возникает следующее исключение (извините за немецкий):

Ausnahme ausgelöst: "System.IO.FileFormatException" in PresentationCore.dll
System.IO.FileFormatException: Die Datei "pack://memorystream:,,62db450e-87fe-4246-a727-15ab02c5c55e.xps,/Resources/34890974-3e2d-4baf-9003-24c3375636b0.ODTTF" entspricht nicht der erwarteten Dateiformatspezifikation.
   bei MS.Internal.TrueTypeSubsetter.ComputeSubset(Void* fontData, Int32 fileSize, Uri sourceUri, Int32 directoryOffset, UInt16[] glyphArray)
   bei MS.Internal.FontFace.TrueTypeFontDriver.ComputeFontSubset(ICollection`1 glyphs)
   bei System.Windows.Media.GlyphTypeface.ComputeSubset(ICollection`1 glyphs)
   bei System.Windows.Xps.Serialization.FEMCacheItem.SubSetFont(ICollection`1 glyphs, Stream stream)
   bei System.Windows.Xps.Serialization.FEMCacheItem.Commit()
   bei System.Windows.Xps.Serialization.XpsFontSubsetter.CommitFontSubsetsSignal(FontSubsetterCommitPolicies signal)
   bei System.Windows.Xps.Serialization.XpsFontSerializationService.SignalCommit(Type type)
   bei System.Windows.Xps.Serialization.XpsSerializationManager.ReleaseXmlWriter(Type writerType)
   bei System.Windows.Xps.Serialization.DocumentSequenceSerializer.set_XmlWriter(XmlWriter value)
   bei System.Windows.Xps.Serialization.DocumentSequenceSerializer.PersistObjectData(SerializableObjectContext serializableObjectContext)
   bei System.Windows.Xps.Serialization.ReachSerializer.SerializeObject(Object serializedObject)
   bei System.Windows.Xps.Serialization.XpsSerializationManager.SaveAsXaml(Object serializedObject)
   bei System.Windows.Xps.XpsDocumentWriter.SaveAsXaml(Object serializedObject, Boolean isSync)
   bei System.Windows.Xps.XpsDocumentWriter.Write(FixedDocumentSequence fixedDocumentSequence)
   bei System.Windows.Xps.Serialization.XpsSerializerWriter.Write(FixedDocumentSequence fixedDocumentSequence)

Первую строку можно перевести так:

"System.IO.FileFormatException" in PresentationCore.dll
System.IO.FileFormatException: "pack://memorystream:,,62db450e-87fe-4246-a727-15ab02c5c55e.xps,/Resources/34890974-3e2d-4baf-9003-24c3375636b0.ODTTF" file does not conform to the expected file format specification.

person Daniel    schedule 29.08.2017    source источник
comment
Вы установили для параметра культуры в своем xaml немецкий язык? то есть xml:lang="de-DE".   -  person XAMlMAX    schedule 29.08.2017
comment
@XAMlMAX спасибо за предложение, я не совсем уверен, как это поможет, но, тем не менее, безуспешно пробовал.   -  person Daniel    schedule 29.08.2017
comment
Я могу воспроизвести. И если я уберу FontStyle = FontStyles.Italic, то все заработает... мне кажется, это баг (вы не единственный: questarter.com/q/), вы должны сообщить об этом в Microsoft Connect connect.microsoft.com   -  person Simon Mourier    schedule 01.09.2017
comment
@SimonMourier да, это действительно похоже на ошибку ... Я подожду некоторое время, прежде чем сообщать, на всякий случай, если кто-нибудь увидит, что именно не так (или у него есть хороший обходной путь, в настоящее время я думаю, я просто буду повторять процесс, пока он не работает, что, очевидно, не очень приятное исправление).   -  person Daniel    schedule 01.09.2017
comment
@Daniel похож на this свяжитесь со службой поддержки ms и спросите их, они быстро   -  person Ferus7    schedule 06.09.2017
comment
Внутри XPS представляет собой zip-архив с фиксированными документами, содержащий все необходимое для представления документов. Он внутренне пытается упаковать ваши шрифты в виде потока памяти в zip-архив xps. Вы не можете запаковать свой шрифт в архив XPS. Шрифт может быть размыт. Проверьте приведенный ниже URL-адрес и загрузите код в конце ссылки, похоже, это очень старая ссылка. Возможно, упомянутое решение может решить вашу проблему. blogs.microsoft.co .il/tamir/2008/04/17/   -  person Amit Kumar Singh    schedule 07.09.2017
comment
@Amit Большое спасибо, это действительно кажется возможным решением этой проблемы. В настоящее время я не могу проверить, будет ли это работать, но я должен сказать: это действительно довольно сложное исправление... тем более, что оно хочет, чтобы я сохранял шрифты на диск (вероятно, довольно медленно), а затем использовал замену Regex в XML-документ (ну, это выглядит уродливо)... В любом случае, поскольку проблема не является детерминированной, я по-прежнему предполагаю, что инфраструктура .NET плохо справляется с этой ситуацией. В любом случае большое спасибо за ссылку и предложения.   -  person Daniel    schedule 07.09.2017
comment
эта строка в вашем примере -> MemoryStream resultStream = new MemoryStream(); почему это не заключено в оператор using, как остальные используемые потоки памяти?   -  person Aaron. S    schedule 11.09.2017
comment
@Aaron.S хорошо, вы правы, MemoryStreams также следует утилизировать. Однако в настоящее время удаление их не имеет эффекта. В любом случае, я не понимаю, как это будет иметь отношение к моей проблеме...   -  person Daniel    schedule 12.09.2017
comment
@SimonMourier Почему вы связали эту статью (questarter.com/q/). questarter — это нелегальный сайт, скопировавший содержимое SE.   -  person I am the Most Stupid Person    schedule 15.09.2017


Ответы (1)


Исходный код в вопросе

Комментарии в исходном коде, похоже, указывают на то, что это вызывает собственный код. Драйверу шрифта требуется доступ к объявленному шрифту. Не все шрифты поддерживают все варианты. Вы должны убедиться, что выбранное вами семейство шрифтов установлено и поддерживает курсив.

Если API поддерживает эту опцию, попробуйте указать конкретный шрифт (а не семейство), который, как вы уже подтвердили, установлен и поддерживает выбранные вами варианты.

Удачи!

person N-ate    schedule 28.11.2017