如何使用 PDF 图元绘制填充和未填充的圆圈?

问题描述 投票:0回答:3

在 PostScript 上绘制圆圈很容易,令我惊讶的是 PDF 显然没有继承这些相同的基元。有很多商业图书馆可以做到这一点,但它不应该比这更简单吗?

还有一些使用贝塞尔曲线的技巧,但你不会得到一个完美的圆,你必须在连接线段中绘制它们。我不需要完美的圆形,只要它看起来接近完美即可。

我这样做是作为 PDF-EasyPDF Perl 模块的补充,但该语言不是我需要帮助的部分。

perl pdf
3个回答
5
投票

情况总是如此。 PDF 的基元中没有圆,只有贝塞尔曲线。 PDF 成像模型是根据 PostScript 成像模型构建的,该模型本身仅使用 arc/arcto 图元提供圆形,而这些图元本身是根据贝塞尔曲线实现的。

奇怪的是,我被要求在我正在处理的一些生成 PDF 的测试代码中完成这个确切的任务。 我是这样做的:

    private void DrawEllipse(PdfGraphics g, double xrad, double yrad)
    {
        const double magic = 0.551784;
        double xmagic = xrad * magic;
        double ymagic = yrad * magic;
        g.MoveTo(-xrad, 0);
        g.CurveTo(-xrad, ymagic, -xmagic, yrad, 0, yrad);
        g.CurveTo(xmagic, yrad, xrad, ymagic, xrad, 0);
        g.CurveTo(xrad, -ymagic, xmagic, -yrad, 0, -yrad);
        g.CurveTo(-xmagic, -yrad, -xrad, -ymagic, -xrad, 0);
    }

    private void DrawCircle(PdfGraphics g, double radius)
    {
        DrawEllipse(g, radius, radius);
    }

假设

PdfGraphics
是一个发出PDF命令的类,那么
g.MoveTo(x, y)
将在内容流中变成“x y m”。 我从 Don Lancaster 的精彩解释(当然是 PDF)中获取了我的数学和神奇数字。 这假设圆或椭圆将在原点绘制。 要将其移动到其他位置,请先进行平移变换或修改代码以在所需原点中减去添加。 此代码给出的最坏情况误差约为 1/1250(约 0.08%),平均值为 1/2500(约 0.04%)。


4
投票

这里的其他两个答案都是完美的,但我只想为实心填充(因此没有笔画)的特定情况添加一个小技巧。

只需绘制一条零长度线,线宽为圆的直径,但将“线帽”设置为

rounded

对于椭圆、圆弧、线段和许多其他相关形状来说,这显然不是一个很好的解决方案......但它是一个很酷的技巧。


4
投票

plinth的答案与我最终发现的相同。有很多棘手的数学可以简化为一个神奇的常数,并将任务细分为四个独立的贝塞尔曲线。 我需要在原始 PDF 命令中执行此操作,但过程是相同的。

  • 移至第一条曲线的起点。这是圆心减去半径,无论您喜欢什么方向。

  • 找出曲线的末端(此代码中的

    $x3
    $y3
    值)。下标来自大多数人使用的贝塞尔曲线控制点标签。

  • 找出控制点。这就是

    $magic
    值出现的地方。

  • 完成一个部分后,进行下一个部分。四段没有什么特别之处,只是它在笛卡尔坐标系中只需加法和减法就可以很好地工作。

  • 如果您想要填充,请以

    f
    结束以绘制刚刚创建的路径的内部。

我可以做一些重构,但是当我使用它时,更容易看到我通过单独的代码块得到了正确的标志。这是我添加到 PDF::EasyPDF:

的子例程
sub make_magic_circle
    {
    my( $pdf, # PDF::EasyPDF object
        $center,
        $r   # radius
        ) = @_;

    my( $xc, $yc ) = $center->xy;
    
    my $magic = $r * 0.552;
    my( $x0p, $y0p ) = ( $xc - $r, $yc );
    $pdf->{stream} .= "$x0p $y0p m\n";
    
    {
    ( $x0p, $y0p ) = ( $xc - $r, $yc );
    my( $x1, $y1 ) = ( $x0p,               $y0p + $magic );
    my( $x2, $y2 ) = ( $x0p + $r - $magic, $y0p + $r     );
    my( $x3, $y3 ) = ( $x0p + $r,          $y0p + $r     );
    $pdf->{stream} .= "$x1 $y1 $x2 $y2 $x3 $y3 c\n";
    }
    
    {
    ( $x0p, $y0p ) = ( $xc, $yc + $r );
    my( $x1, $y1 ) = ( $x0p + $magic, $y0p               );
    my( $x2, $y2 ) = ( $x0p + $r,     $y0p - $r + $magic );
    my( $x3, $y3 ) = ( $x0p + $r,     $y0p - $r          );
    $pdf->{stream} .= "$x1 $y1 $x2 $y2 $x3 $y3 c\n";
    }
    
    {
    ( $x0p, $y0p ) = ( $xc + $r, $yc );
    my( $x1, $y1 ) = ( $x0p,               $y0p - $magic );
    my( $x2, $y2 ) = ( $x0p - $r + $magic, $y0p - $r     );
    my( $x3, $y3 ) = ( $x0p - $r,          $y0p - $r     );
    $pdf->{stream} .= "$x1 $y1 $x2 $y2 $x3 $y3 c\n";
    }
    
    {
    ( $x0p, $y0p ) = ( $xc, $yc - $r );
    my( $x1, $y1 ) = ( $x0p - $magic,  $y0p               );
    my( $x2, $y2 ) = ( $x0p - $r,      $y0p + $r - $magic );
    my( $x3, $y3 ) = ( $x0p - $r,      $y0p + $r          );
    $pdf->{stream} .= "$x1 $y1 $x2 $y2 $x3 $y3 c\n";
    }
    
    $pdf->{stream} .= "f\n";
    }
© www.soinside.com 2019 - 2024. All rights reserved.