Импорт Form XObject из SVG

THotPDF.ImportSVGFormXObject разбирает SVG один раз и регистрирует один переиспользуемый PDF Form XObject, а THPDFPage.DrawSVGFormXObject размещает его в любом размере и опционально создаёт link-аннотации страниц

Объявление

function ImportSVGFormXObject(const Input: TBytes): AnsiString; overload;
function ImportSVGFormXObject(
  const Input: TBytes;
  out Statistics: THPDFSVGImportStatistics
): AnsiString; overload;

procedure DrawSVGFormXObject(
  const FormName: AnsiString;
  X, Y, W, H: Single;
  AddLinks: Boolean = True
);

Векторный профиль

Границы текста и заливки

Текст поддерживает сплошную заливку, варианты bold и italic, размер шрифта, трансформации, якорение, opacity и геометрическое отсечение; градиентная заливка текста жёстко отклоняется, а каждый узел text или tspan остаётся независимо позиционируемым прогоном, а не полноценным движком вёрстки текстового потока SVG

Импорт текста документов сохраняет выбранное начертание bold и italic через учитывающие стиль проверки глифов и резервную вёрстку, хранит измеренные границы краски и отклоняет действительно неразрешённые глифы

UTF-8-текст и XML-ссылки на символы в шестнадцатеричном или десятичном виде сохраняют одинаковые скаляры Unicode в Delphi и FPC, включая дополнительные скаляры в UTF-16 surrogate-парах

Автономная перегрузка HPDFBuildSVGFormData без text builder использует измеренные ширины Base 14 — Helvetica, Times и Courier — и отклоняет символы вне WinAnsi вместо подстановки вопросительных знаков; перегрузка с THPDFSVGTextRunBuilder принимает переданные вызывающим встроенные текстовые формы и метрики

Градиенты сохраняют ограниченную аппроксимацию векторными полосами; прозрачные ресурсы требуют PDF 1.4 и отклоняются строгим профилем PDF/A-1

Стили штрихов

stroke-dasharray, stroke-dashoffset и stroke-miterlimit работают через presentation attributes, встроенный CSS, inline-стили и наследование, включая группы и экземпляры use только на фрагменты

Dash-массивы принимают числа, разделённые запятыми или пробелами, и поддерживаемые длины; проценты считаются от нормализованной диагонали viewport, вычисляемой как sqrt((viewWidth * viewWidth + viewHeight * viewHeight) / 2)

Массивы нечётной длины повторяются до шаблона чётной длины, каждый подпуть перезапускает шаблон, а положительные и отрицательные смещения заворачиваются по полному шаблону; none и массивы из одних нулей дают сплошные штрихи

Рисуемые штрихи нулевой длины сохраняют marks с round или square caps; обычные сплошные штрихи, pattern градиентных штрихов, клипы, mask и изолированные группы opacity используют одни и те же настройки штриха

Miter limit по умолчанию равен 4; значения SVG 2 от 0 до 1 принимаются и используют bevel-соединения там, где miter превысил бы лимит, при этом границы градиентных и transparency-ресурсов сохраняют острые соединения в рамках выбранного лимита

Нативный рендеринг использует ограниченную dash-геометрию, чтобы сохранить смещения, дробные длины и массивы длиннее лимита GDI-пера, с адаптивным упрощением кривых и непрерывными рисуемыми соединениями через границы сегментов

Калибровка штрихов через pathLength остаётся за пределами профиля; фигуры, сочетающие несплошной dash-массив с pathLength, жёстко отклоняются, а не молча используют некалиброванные длины

Семантика штрихов следует модели штрихов SVG 2 в пределах бюджетов парсера и рендерера, описанных ниже

Конфигурация шейпинга текста

Встроенный SVG-текст использует настройки импортирующего документа ShapingFeatures, AutoShapeArabic, AutoShapeSyriac, AutoShapeNko, AutoShapeAdlam и AutoShapeHanifiRohingya, а также его выборы GSUB-скрипта и языка и fallback-цепочки шрифтов

Эти настройки применяются и при измерении ширин, и при генерации text appearance без изменения конфигурации вызывающего; шейпинг остаётся opt-in и требует шрифт с нужными глифами и таблицами OpenType

Каждое сгенерированное text appearance принимает не более 256 различных выборов шрифтов для шейпинга и 64 MiB суммарных сырых данных шрифтов; неподдерживаемые данные шрифта или превышенный лимит атомарно срывают импорт

Opacity объектов и групп

opacity применяется один раз к полному закрашенному результату своего узла и не наследуется потомками; fill-opacity и stroke-opacity сохраняют свои отдельные унаследованные значения заливки

Два перекрывающихся непрозрачных красных прямоугольника внутри <g opacity="0.5"> остаются одинаково полупрозрачными в перекрытии, а два независимо полупрозрачных прямоугольника в перекрытии становятся темнее

Вложенные группы компонуются по порядку: две объемлющие opacity 0.5 дают эффективные 0.25 поверх непрозрачного потомка, а явная opacity 1 у потомка не переопределяет объемлющую группу

Корневые узлы SVG, контейнеры, ссылки, ссылки на фрагменты, текст, изображения и фигуры идут одним путём opacity объектов; ссылки use только на фрагменты сохраняют стили и экземпляра, и ссылаемого узла

Alpha fill и stroke остаются независимыми, в том числе в их перекрытии внутри полупрозрачного объекта, а alpha градиентных stop комбинируется с alpha соответствующей заливки до композитинга объекта

Эффекты clip и mask принадлежат своему узлу, а не наследуются как настройки заливки потомков; геометрия ссылок остаётся с учётом размещения, а границы изолированных Form консервативно удерживают трансформированные штрихи и caps

Импортер сохраняет векторные операторы, встроенные текстовые Form, ресурсы изображений, pattern и mask внутри изолированных групп; он не сплющивает весь SVG в bitmap

Поддерживаемое поведение следует модели opacity объектов и групп SVG; прочие ограничения этой страницы на текст, градиенты и геометрию продолжают действовать

Безопасность и бюджеты

Импортер принимает обычный или gzip-сжатый SVG до 8 MiB и ограничивает развёрнутый ввод 32 MiB, суммарные операторы main, pattern, mask и group — 16 MiB, узлы — 4,096, вложенность — 64 уровнями, правила CSS — 256, а значения path — 100,000

Встроенные изображения принимают только строгие Base64 payload data:image/png;base64, и data:image/jpeg;base64, — не более 128 изображений, 16,384 пикселей по измерению и 16,777,216 декодированных пикселей на все изображения; размеры проверяются до нативного декодирования

Текст ограничен 128 прогонами и 65,536 единицами UTF-16 на прогон, а pattern градиентных штрихов, mask и изолированные группы opacity — 128 ресурсами каждого типа; рекурсивные ссылки mask жёстко отклоняются

Dash-массивы содержат не более 64 исходных записей до развёртывания нечётных массивов; положительные записи должны быть не меньше 0.000001 user units, отдельные длины и нормализованный цикл не должны превышать 1,000,000,000, абсолютные смещения — 1,000,000,000, а miter limit должен оставаться в диапазоне от 0 до 1,000,000

Реальные вложенные transparency-эффекты ограничены восемью уровнями, чтобы совпадать с нативным рендерером, независимо от лимита глубины дерева SVG; обычные вложенные контейнеры без transparency-эффектов эту квоту не расходуют

Границы transparency-эффектов должны быть конечными, и каждая координата должна оставаться в пределах абсолютного значения 1,000,000,000; импорты за рамками этого ограниченного координатного профиля отклоняются до регистрации групп или mask

Неудавшиеся импорты откатывают сгенерированные объекты, встроенные текстовые Form, записи реестра и состояние версии и device-цветов, так что вызывающий может переиспользовать тот же документ и сохранить объемлющую graph transaction

Скрипты, event handler'ы, DTD, foreignObject, неподдерживаемые data media types, JavaScript-URL и внешние URL заливки или ресурсов изображений жёстко отклоняются

Ссылки на фрагменты вроде url(#gradient), url(#clip) и href="#symbol" остаются внутри разобранного документа и никогда не приводят к доступу к файлам или сети

Статистика

THPDFSVGImportStatistics сообщает узлы, правила CSS, gradient, gradient stroke, mask, изображения, ссылки, text run, изолированные группы opacity через GroupCount и суммарные байты сгенерированных операторов main, pattern, mask и group

HPDFBuildSVGFormData открывает ограниченный парсер отдельно — через THPDFSVGFormData и THPDFSVGLinkInfo — для тех, кому нужно содержимое Form, собственные размеры, ресурсы opacity, payload изображений, потоки pattern и mask, имена текстовых ресурсов или метаданные ссылок до регистрации; Groups предоставляет потоки операторов изолированных групп и консервативные границы Form

Пример

Document.BeginDoc;
FormName := Document.ImportSVGFormXObject(SVGBytes, Statistics);
if FormName = '' then
  raise Exception.Create('SVG import failed');

Document.CurrentPage.DrawSVGFormXObject(
  FormName,
  36,
  72,
  240,
  120,
  True
);

Document.CurrentPage.DrawSVGFormXObject(
  FormName,
  320,
  72,
  120,
  60,
  False
);

См. также: THotPDF.ImportSVGFormXObject, THPDFPage.DrawSVGFormXObject, HTML5 Paged-Media Import