Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Catalog · How the catalog works

Random project

PasWmfToSvg

View on GitHub

Anyone may press Interesting, signed in or not. It helps others find this project.

Member rating

No ratings yet.

Sign in to rate this project.

README

PasWmfToSvg

Перевод метафайлов Windows (EMF и WMF) в SVG на чистом Object Pascal. Работает без GDI, Java и внешних программ на Windows, Linux, macOS, Android и iOS (Delphi 10.3 и новее, проверено на Delphi 13).

Записи метафайла разбираются напрямую и повторяются так, как их рисует сама Windows. Отсюда ровный размер, полупиксельные сдвиги, исключённые правые и нижние края, штрихи перьев, узоры штриховки и фон текста как в GDI. Результат сверяется по пикселям с рисованием Windows (см. «Проверка»).

Использование

pascal
uses
  PasWmfToSvg;

var
  Info: TMfInfo;
  Svg: string;
begin
  Svg := MetafileToSvg(TFile.ReadAllBytes('picture.emf'), Info);   // EMF или WMF - определяется по заголовку
  TFile.WriteAllBytes('picture.svg', TEncoding.UTF8.GetBytes(Svg));
  Writeln(Info.Format, ' ', Info.Width, 'x', Info.Height, ', пропущено записей: ', Info.Skipped);
end;
  • MetafileToSvg(Data) / MetafileToSvg(Data, Info, Metrics). Неверные данные — исключение EMetafileToSvg.
  • TMfInfo: формат (EMF, WMF, WMF+EMF), размер картинки в пикселях, число записей, пропущенные записи и их типы.
  • Метрики шрифтов (IMfFontMetrics) нужны для базовой линии текста и ширины строки (фон, выравнивание):
    • по умолчанию — встроенные таблицы 14 распространённых шрифтов (PasWmfToSvg.FontTables.inc, измерены в GDI Windows); незнакомый шрифт берётся по семейству;
    • в Windows достаточно добавить в uses модуль PasWmfToSvg.Gdi — метрики будет давать сама Windows;
    • можно передать свой поставщик.
  • Потокобезопасно: у каждого вызова своё состояние.

Что поддерживается

EMF WMF
фигуры многоугольники, ломаные (и составные), отрезки, прямоугольники, эллипсы, скруглённые прямоугольники, дуги, хорды, секторы, кривые Безье то же без кривых Безье, плюс SETPIXEL
перья косметические и геометрические, штрихи (промежутки цветом фона при непрозрачном фоне), концы и стыки косметические и геометрические, штрихи
кисти сплошные, штриховка HS_* (фон при непрозрачном фоне), DIB-узор, начало узора сплошные, штриховка, DIB-узор
текст EXTTEXTOUTW: выравнивание, фон, ETO_OPAQUE, межсимвольные расстояния, наклон, полужирный, курсив, подчёркивание TEXTOUT, EXTTEXTOUT (однобайтовый текст — по набору символов шрифта)
картинки BITBLT, STRETCHBLT, STRETCHDIBITS, SETDIBITSTODEVICE, ALPHABLEND (альфа), PATBLT; DIB 1/4/8/16/24/32 бита DIBBITBLT, DIBSTRETCHBLT, STRETCHDIB, SETDIBTODEV, PATBLT
координаты режимы отображения, окно и область вывода, мировое преобразование, SAVEDC/RESTOREDC окно, режимы отображения, SAVEDC/RESTOREDC
  • Размер SVG — рамка картинки: у EMF это rclFrame в пикселях эталонного устройства, у WMF — рамка размещаемого заголовка при 96 точках на дюйм. Координаты — пиксели этого размера, точка GDI — центр пикселя. Масштаб SVG к картинке — ровно 1. Картинки и DIB-узоры встраиваются как PNG (data:).
  • В WMF, который Windows сделала из EMF (GetWinMetaFileBits), исходный EMF вложен комментариями. Его и рисует преобразователь, как это делает сама Windows.
  • Не поддерживаются и пропускаются: пути (BEGINPATH …), отсечение, регионы, растровые операции кроме копирования, EMF+ (двойные метафайлы рисуются их EMF-частью), картинки устройства (Bitmap16), сжатые DIB (RLE, JPEG, PNG).

Проверка

Сверка с рисованием Windows по пикселям (на Windows, нужны Delphi, Python 3 и Edge или Chrome):

pascal
python Tools\build.py Tools\MfSvgCheck.dpr --output build
build\MfSvgCheck.exe --make-samples build\samples              :: ?????????????????????????? ?????????????????? ???????? ???????????????????????? ??????????????
build\MfSvgCheck.exe build\samples --out build\check           :: SVG ?? ???????????????? GDI ?????????????? ??????????????????
python Tools\edge_compare.py --check build\check --worst 10    :: SVG ???????????? ??????????????, ?????????????????? ?? GDI
  • MfSvgCheck для папки .emf/.wmf сохраняет SVG, картинку GDI и manifest.json. Ключи: --wmf — каждый EMF переводится в WMF; --wmf-pure — то же без вложенного EMF, проверка самих записей WMF; --builtin-metrics; --no-gdi --no-svg — только разбор.
  • edge_compare.py считает долю «несовпавших» пикселей (разница канала больше 96) от закрашенных в GDI и пишет report.json. Худшие файлы сохраняются как worst_*.png: GDI | SVG | разница | другой SVG (--old).
  • Samples/ — синтетические метафайлы этой проверки (EMF и WMF без вложенного EMF).
  • Сборка ядра под другие платформы без их SDK: python Tools\build.py Source\PasWmfToSvg.pas --platform linux64 (а также win64, osx64, osxarm64, android64, iosarm64).

Результат на 68 144 реальных EMF (чертежи оконных конструкций из программы расчёта):

что итог
разбор всех файлов ошибок 0, пропущенных записей 0; 0,5 мс на файл, SVG в среднем 3,7 КБ
сверка с GDI в Edge, 2 059 случайных и самые большие несовпавших пикселей: медиана 1,0 %, p95 3,1 %, p99 6,6 %; сдвиг 0 у всех. Прежний конвертер (wmf2svg, Java): медиана 12,6 %, p95 88 %
те же файлы как WMF с вложенным EMF как EMF
те же файлы как WMF без вложенного EMF медиана 3,2 %, p95 13 % (Windows округляет масштабированные координаты по-своему)

Остаток разницы — сглаживание: браузер сглаживает наклонные линии и буквы, GDI — нет.

Инструменты

  • Tools/MfToSvg.dpr — перевод из командной строки: MfToSvg <метафайл> [<файл.svg>] [--builtin-metrics].
  • Tools/MeasureFonts.dpr (Windows) — заново измеряет таблицы шрифтов и узоров штриховки в Source/PasWmfToSvg.FontTables.inc.
  • Tools/build.py — сборка компилятором Delphi из командной строки.

Лицензия

MIT, см. LICENSE. Таблицы шрифтов — измеренные числа (ширины символов и высоты), без самих шрифтов.