GDI+: как нарисовать линию длиной один дюйм на любом устройстве, на котором она нарисована?

Мне нужно нарисовать линию длиной один дюйм на любом устройстве, имеющем ссылку Graphics на него. Мне нужно, чтобы он был длиной в дюйм независимо от того, на что установлено Transform. Предположим, что коэффициент масштабирования преобразования задается как scale как в горизонтальном, так и в вертикальном направлениях.

Некоторый код С++/CLI:

g->DrawLine(Pens::Black, 50.0f, 50.0f, 50.0f + oneInchEquivalent / scale, 50.0f);

Теперь это было совсем не сложно! Теперь все, что нам нужно сделать, это вычислить oneInchEquivalent.

g->DpiX дает мне расстояние, которое выглядит как один дюйм на экране, но не на принтере. Кажется, что на принтерах рисование линии из 100 единиц с g->PageUnit, установленным на GraphicsUnit::Display, даст мне линию длиной в один дюйм. Но мне действительно нужно, чтобы это работало независимо от настройки PageUnit. На самом деле, изменение PageUnit изменит ширину пера!!

Редактировать: я предварительно принял единственный ответ здесь, так как он довольно близок к тому, что я ищу.


person Agnel Kurian    schedule 27.08.2009    source источник
comment
Я обновил свой ответ сейчас с образцом печати   -  person Fredrik Mörk    schedule 27.08.2009


Ответы (1)


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

Установка для свойства PageUnit объекта Graphics значения GraphicsUnit.Pixel и умножение координат на значения DpiX и DpiY отобразит ожидаемый результат как на устройствах отображения, так и на устройствах печати.

private static void DrawInchLine(Graphics g, Color color, Point start, Point end)
{
    GraphicsUnit originalUnit = g.PageUnit;
    g.PageUnit = GraphicsUnit.Pixel;
    using (Pen pen = new Pen(color, 1))
    {
        g.DrawLine(pen,
            start.X * g.DpiX,
            start.Y * g.DpiY,
            end.X * g.DpiX,
            end.Y * g.DpiY);
    }
    g.PageUnit = originalUnit;
}

Вы можете нарисовать его на форме (или в каком-либо элементе управления):

using (Graphics g = this.CreateGraphics())
{
    Point start = new Point(1, 1);
    Point end = new Point(2, 1);
    DrawInchLine(g, Color.Black, start, end);
}

...или отправить вывод на принтер:

PrintDialog dialog = new PrintDialog();
if (dialog.ShowDialog() == DialogResult.OK)
{
    PrintDocument pd = new PrintDocument();
    pd.PrinterSettings = dialog.PrinterSettings;
    pd.PrintPage += (psender, pe) =>
    {
        Point start = new Point(1, 1);
        Point end = new Point(2, 1);
        DrawInchLine(pe.Graphics, Color.Black, start, end);
        pe.HasMorePages = false;
    };

    pd.Print();
}

Однако это зависит от установки PageUnit.

person Fredrik Mörk    schedule 27.08.2009
comment
Вы можете попробовать CutePDF для эмулятора принтера. Вы можете увидеть различия там. - person Agnel Kurian; 27.08.2009
comment
Я только что понял, что у меня здесь стоит принтер; пытался печатать на нем; вышел ровно на один дюйм. Будет обновляться с кодом. - person Fredrik Mörk; 27.08.2009
comment
Спасибо, Фредрик, но мне нужно сделать это, используя только Math, не меняя настройки PageUnit. Изменение PageUnit повлияет на ширину пера. Смотрите последнюю часть моего вопроса. - person Agnel Kurian; 27.08.2009
comment
Ах, пропустил эту часть... К сожалению, я не вижу простого решения, кроме использования Pixel в качестве базовой единицы для всех рисунков и масштабирования его на целевое устройство с использованием DpiX и DpiY. - person Fredrik Mörk; 27.08.2009