Размер текста Qt в пунктах - PullRequest
0 голосов
/ 27 апреля 2018

Я пытаюсь напечатать документ счета на А4 в миллиметрах вместо единиц измерения по умолчанию. За исключением того, что при изменении единиц измерения на миллиметры размер текста в печатном документе больше не совпадает с размером, например, в Word или Adobe Illustrator. Я пытался преобразовать размер точки в соответствующий размер в пикселях, но у них были проблемы.

QFont :: SetPixelSize принимает только целое число, поэтому, если вычисления упадут ниже 1, оно будет равно 0

font.setPixelSize((9.0 * 72.0) / printer.resolution());

И другой метод сделал текст правильного размера по вертикали, но есть некоторые артефакты:

int phys_w = printer.width();
font.setPointSizeF((9.0 / phys_w) * 210.0);

enter image description here
Где вы можете увидеть необычно большие промежутки между некоторыми персонажами. (Возможно, есть некоторая проблема точности в Qt его коде рисования текста?)


Вот минимальный пример, показывающий проблемы:

QPrinter printer(QPrinter::HighResolution);
printer.setPageSize(QPrinter::A4);
printer.setOrientation(QPrinter::Portrait);
printer.setFullPage(true);
printer.setPageMargins(QMarginsF(0, 0, 0, 0));

printer.setOutputFormat(QPrinter::PdfFormat);
printer.setOutputFileName("invoice.pdf");

QPainter painter(&printer);

auto page_size = printer.pageRect(QPrinter::Unit::Millimeter);
painter.setWindow(page_size.toRect());

QFont font = painter.font();

// Either this
font.setPixelSize((9.0 * 72.0) / printer.resolution());

// or this
int phys_w = printer.width();
font.setPointSizeF((9.0 / phys_w) * 210.0);

painter.setFont(font);
painter.drawText(35, 46, "John Doe");

Как определить положение в миллиметрах (или любой произвольной единице) и сделать размер текста точным (или некоторый правильный пересчет)?

Это на Qt 5.10.0 и Windows 10.

EDIT В итоге я решил увеличить масштаб в 10 раз (десятые доли миллиметра), что исправило проблемы с кернингом, видимые для setPointSizeF. Теперь последняя проблема, которую я имею со шкалой, связана с установкой ширины линии и других фигур (QPen :: setWidth), и я не могу найти вычисление, так что это в миллиметрах.

EDIT В конце концов, ширина линии не нуждается в каких-либо перерасчетах. Окончательный код ниже:

QPrinter printer(QPrinter::HighResolution);
printer.setPageSize(QPrinter::A4);
printer.setOrientation(QPrinter::Portrait);
printer.setFullPage(true);
printer.setPageMargins(QMarginsF(0, 0, 0, 0));

printer.setOutputFormat(QPrinter::NativeFormat);

QPainter painter(&printer);
painter.setWindow(0, 0, 2100, 2970);
painter.setViewport(0, 0, printer.width(), printer.height());

QFont font(fontFamily, 0, weight, italic);
font.setPointSizeF(static_cast<float>(pixelSize) / printer.width() * 2100);

Ответы [ 2 ]

0 голосов
/ 06 мая 2018

Проводя подробные наблюдения (печатая длинное предложение), можно заметить, что эти пробелы между символами напрямую связаны с самими символами, широкие символы и заглавные буквы поглощают этот пробел (J, s, r, c), а узкие символы оставляют больше разрыв (i, l, t) .. это просто сказать, что это не случайное поведение.

В общем, это известно как кернинг хорошо объяснено здесь . Чтобы минимизировать это, Qt устанавливает кернинг QFont в значение true (по умолчанию) QFont Kerning ... но проблема в том, что кернинг сильно зависит от используемого шрифта и пикселя, и включенный кернинг Qt иногда не действует, как в этот пост , вероятно, потому что установка Кернинг в true

(Будет применен кернинг между соседними символами. Обратите внимание, что OpenType GPOS основанный кернинг в настоящее время не поддерживается QRawFont :: LayoutFlags

Это означает, что некоторый шрифт Ascent / Descent все равно будет вызывать ограничение на управление зазором. Ниже рассматриваются два решения, первое из которых по-прежнему придерживается шрифта по умолчанию для рисования, но вы можете растянуть символов, чтобы обеспечить разумную игру:

font.setStretch(70); // value is experimental 

enter image description here

Я не думаю, что это надежное решение, если только оно не ограничено использованием определенного шрифта, хотя сам шрифт не важен для печати счетов, второй привлекательный подход - найти лучший шрифт, который соответствует требования: хорошо отображать с заданным разрешением / с небольшими потерями при рисовании в PDF (из Qt) / и, что наиболее важно, эффективно для кернинга! « MS Gothic » (ttf), например, хорошо работает для такой настройки, вот как она работает (без растяжения)

painter.setFont(QFont("MS Gothic"));
QFont font = painter.font();
int phys_w = printer.width();
font.setPointSizeF((9.0 / phys_w) * 210.0);
//font.setStretch(70);
painter.setFont(font);

enter image description here

Хорошая вещь при выборе подходящего шрифта состоит в том, что возможен больший контроль (особенно для печати счетов-фактур, где мало места).

Например, та же банка может быть напечатана с меньшим пространством на , уменьшая расстояние между буквами :

font.setLetterSpacing(QFont::PercentageSpacing,65); // 65% gap of default

enter image description here

И можно пойти даже на меньший размер шрифта без потери визуального оформления.


делимся ниже некоторыми работами, пытаясь выяснить, как печать шрифта малого размера влияет на разрыв между буквами. идея состоит в том, чтобы нарисовать каждый символ отдельно внутри QRect и одновременно нарисовать эквивалентный QRectF в той же области.

Чтобы увидеть, когда размер шрифта большой, QRectF нарисованы рядом друг с другом, так что также каждый символ ... в то время как при уменьшении размера шрифта смежные QRectF будут сильно перекрываться, и промежутки между символами начинают становиться неупорядоченными.

QPen pen=painter.pen();
pen.setWidth(0.1);
painter.setPen(pen);
QString td("John Doe");
auto spacer = font.pointSizeF(); // font size used to set width of QRect of each character.
spacer *=30.0; // large Rect width.
auto b = 35.0;

for (int i=0; i < td.length() ;i++ )
{
    QRectF rectf(b+=spacer,47.0,4.0,4.0);
    QRect rect(b, 47.0,4.0,4.0);
    QString ch = td.at(i);
    //painter.drawText(b+=spacer,46,ch);
    painter.drawText(rect,Qt::AlignCenter,ch);
    painter.drawRect(rectf);
}
painter.end();

Результат для большого размера шрифта:

enter image description here

Следующее перекрытие QRectF:

spacer *=10.0;

Результат: буквы получают меньше пробелов, а широкие смежные символы - узкие.

enter image description here

0 голосов
/ 04 мая 2018

Я думаю, что вы делите, где вы должны размножаться, и наоборот. Взгляните на единицы, написанные явно:

9 точек * (1 дюйм / 72 точки) * (printer.res пикселей / дюйм)

, умножая единицы, числитель получает (точки * дюйм * пиксели), знаменатель получает (точки * дюйм). Отмените одинаковые единицы, и вы получите пиксели в числителе. Поэтому расчет должен быть:

font.setPixelSize(9.0 / 72.0 * printer.resolution());

Для вашей второй проблемы,

QPen::setWidthF(w*printer.resolution()/25.4);

где w - желаемая ширина в мм.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...