65.9K
CodeProject 正在变化。 阅读更多。
Home

图像蒙版:现在支持矢量路径

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.61/5 (6投票s)

2017年4月2日

CPOL

2分钟阅读

viewsIcon

7362

downloadIcon

176

蒙版图像和指定软蒙版

引言

我将讨论在揭示解决方案并讨论它之前,你可以掩盖图像的其他方法,因为在PDF中掩盖图像有很多种方法,所以这比你想象的要有趣。如果你搜索PDF规范(就像我现在做的),你会发现基本上有两个部分讨论了蒙版:第8.9.6节 蒙版图像和第11.6.5节 指定软蒙版,但两者都没有讨论使用矢量路径进行蒙版。

背景

软蒙版是透明度章节的一部分,有两种形式:图像和字典。如果你熟悉RGBA图像,图像软蒙版本质上是将Alpha(透明度)通道从RGB图像中分离出来,并使其在父图像XObject中独立存在。这本质上是DLE处理包含RGBA图像的PNG文件的方式。另一方面,软蒙版字典是扩展图形状态的一部分,虽然它们包含一个透明度组表单XObject,其中可以包含矢量路径,但这并不是将矢量路径用于图像蒙版的理想机制。

蒙版图像有三种形式;模版蒙版、显式蒙版和色彩键蒙版。显式蒙版类似于图像软蒙版,除了alpha通道像素只能完全开启或完全关闭,因此没有透明度的程度。色彩键蒙版有点像GIF文件中透明度的工作方式,其中一种索引颜色被指定为透明颜色,但使用色彩键蒙版,你可以为图像的每个颜色分量指定一个范围;如果所有分量值都落在这些范围内,则该像素将被蒙版(或不被蒙版,具体取决于Decode参数,但这就是想法)。模版蒙版类似于显式蒙版,除了你已经丢弃了主图像,并且正在蒙版已经存在的背景。

使用代码

这些变体都不允许使用矢量路径,那么如何使用矢量路径进行蒙版呢?蒙版是正确的概念,但在这个例子中用词不当,因为要用矢量路径蒙版图像,你只需将剪切路径应用于图像。或者至少,这就是理论,我需要一些代码来证明它。我决定使用以下代码创建的17点星形来剪切此图像:

                    var center = new Point(pageRect.Left+pageRect.Width/2,pageRect.Bottom+pageRect.Height/2); 

                    var smallDim = Math.Min(img2.BoundingBox.Width,img2.BoundingBox.Height);

                    var cPath = createStar(center,smallDim/2,smallDim/3, 17);

        static Path createStar(Point Center, double r1, double r2, int rays)

        {

            var starPath = new Path();

            Point start = new Point(Center.H+ r1 *Math.Cos(0), Center.V+r1*Math.Sin(0));

            starPath.MoveTo(start);

            double angle =2*Math.PI/rays;

            var halfAngle = angle /2.0;

            for(int i=0; i < rays; i++)

            {

                var theta1 = (i * angle) + halfAngle;

                var theta2 = theta1 + halfAngle;

                var Point1 = new Point(Center.H + r2 * Math.Cos(theta1), Center.V + r2 * Math.Sin(theta1));

                var Point2 = new Point(Center.H + r1 * Math.Cos(theta2), Center.V + r1 * Math.Sin(theta2));

                starPath.AddLine(Point1);

                starPath.AddLine(Point2);

            }

            starPath.ClosePath();



            return starPath;

        }

结果是

然而,我的邻居挑战我将剪切反转过来,或者有效地从外到内(!)。

       // Challenge #2: use the inverse of the Path as the mask for an image

                    var page3 = doc.CreatePage(Document.LastPage, pageRect);

                    var img3 = newimage.Clone();



                    // Solved by surrounding the Path with a Rect around the image.

                    var clipPath2 = new Path();

                    clipPath2.AddRect(new Point(72,72), img3.BoundingBox.Width, img3.BoundingBox.Height);

                    AppendStar(ref clipPath2, center, smallDim / 2, smallDim / 3, 17);

                    Clip clip2 = new Clip();

                    clip2.AddElement(clipPath2);

                    img3.Clip = clip2;

                    page3.Content.AddElement(img3);

                    page3.UpdateContent();

将星形附加到现有的剪切路径,其中包含围绕整个图像的矩形,需要对创建星形的方式进行轻微的修改

static void AppendStar(ref Path existingPath, Point Center, double r1, double r2, int rays)

        {

            

            Point start = new Point(Center.H + r1 * Math.Cos(0), Center.V + r1 * Math.Sin(0));

            existingPath.MoveTo(start);

            double angle = 2 * Math.PI / rays;

            var halfAngle = angle / 2.0;

            for (int i = 0; i < rays; i++)

            {

                var theta1 = (i * angle) + halfAngle;

                var theta2 = theta1 + halfAngle;

                var Point1 = new Point(Center.H + r2 * Math.Cos(theta1), Center.V + r2 * Math.Sin(theta1));

                var Point2 = new Point(Center.H + r1 * Math.Cos(theta2), Center.V + r1 * Math.Sin(theta2));

                existingPath.AddLine(Point1);

                existingPath.AddLine(Point2);

            }

            existingPath.ClosePath();

        }

这次结果是

任务完成:使用矢量路径蒙版的图像。

© . All rights reserved.