使用图像而非瓷砖填充纹理笔刷 [英] Fill texture brush using image, not tile

查看:155
本文介绍了使用图像而非瓷砖填充纹理笔刷的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用特定图像的纹理笔刷,可以使纹理像这样显示:

Image image = new Bitmap("Untitled.png");
for (int i = 0; i < points.Count; i++)
{
    using (TextureBrush tbr = new TextureBrush(image))
    {
          tbr.RotateTransform(i * 4);
          var p = PointToClient(Cursor.Position);
          tbr.Transform = new Matrix(
          75.0f / 640.0f,
          0.0f,
          0.0f,
          75.0f / 480.0f,
          0.0f,
          0.0f);
          e.Graphics.FillEllipse(tbr, p.X - 50, p.Y - 50, 100, 100);
          Pen p3 = new Pen(tbr);
          e.Graphics.DrawEllipse(Pens.DeepSkyBlue, p.X - 50, p.Y - 50, 100, 100);
    }
}

这是它正在使用的图像:

结果是这样的:

我希望图像填充圆圈,使其看起来像这样(编辑后的图像):

任何帮助将不胜感激.

解决方案

您需要使用正确的数字进行缩放.

如果您要使尺寸=宽*高像素的图像填充直径的圆,则应像这样缩放:

 int diameter = 100;
 Image image = new Bitmap(yourImage);
 float scaleX = 1f * diameter / image.Size.Width;
 float scaleY = 1f * diameter / image.Size.Height;

不过请注意,您的TextureBrush将始终显示根据图片制作的平铺.这对于您的原始问题,尤其是在旋转尾部的图像以消除任何伪像时.

但是这里可能根本不是您想要的.

如果要使图像跟随鼠标,则需要绘制图像.

这里是一个示例,该示例使用复选框在平铺绘图之间切换.动画仅使用一帧:

    for (int i = 0; i < points.Count; i++)
    {
        using (TextureBrush tbr = new TextureBrush(image))
        {
            tbr.RotateTransform(i * 4);   // optional
            var p = PointToClient(Cursor.Position);
            tbr.Transform = new Matrix(
                scaleX,
                0.0f,
                0.0f,
                scaleY,
                0.0f,
                0.0f);
            // any tile mode will work, though not all the same way
            tbr.WrapMode = WrapMode.TileFlipXY;
            if (cbx_tileFunny.Checked)
                e.Graphics.FillEllipse(tbr, p.X - diameter/2, 
                                            p.Y - diameter/2, diameter, diameter);
            else
            {
               ((Bitmap)image).SetResolution(e.Graphics.DpiX, e.Graphics.DpiY);   // (**)
                e.Graphics.ScaleTransform(scaleX, scaleY);
                e.Graphics.DrawImage( image, (p.X - diameter/2) / scaleX,
                                             (p.Y - diameter/2 ) / scaleY);
                e.Graphics.ResetTransform();

            }
                /// ? Pen p3 = new Pen(tbr);
                e.Graphics.DrawEllipse(Pens.DeepSkyBlue, p.X - diameter/2,
                                       p.Y - diameter/2, diameter, diameter);
        }
    }

如果图像的dpi设置与屏幕不同,请注意此处(**)所需的额外缩放比例.

另外:虽然通常快速创建和处置钢笔和画笔是一个好主意,但是如果在创建画笔和/或图像时花了很大的精力来缓存它们,甚至是一系列,这似乎是更可取的,imo./p>

I have a texture brush that uses a certain image to make the texture to be displayed like this:

Image image = new Bitmap("Untitled.png");
for (int i = 0; i < points.Count; i++)
{
    using (TextureBrush tbr = new TextureBrush(image))
    {
          tbr.RotateTransform(i * 4);
          var p = PointToClient(Cursor.Position);
          tbr.Transform = new Matrix(
          75.0f / 640.0f,
          0.0f,
          0.0f,
          75.0f / 480.0f,
          0.0f,
          0.0f);
          e.Graphics.FillEllipse(tbr, p.X - 50, p.Y - 50, 100, 100);
          Pen p3 = new Pen(tbr);
          e.Graphics.DrawEllipse(Pens.DeepSkyBlue, p.X - 50, p.Y - 50, 100, 100);
    }
}

and here's the image it is using:

This is how it turns out:

I want the image to fill the circle so that it looks like this(edited image):

Any Help would be appreciated.

解决方案

You need to scale using the correct numbers.

If you want an image with a size = width * height pixels to fill a circle of diameter you should scale like this:

 int diameter = 100;
 Image image = new Bitmap(yourImage);
 float scaleX = 1f * diameter / image.Size.Width;
 float scaleY = 1f * diameter / image.Size.Height;

Note however that your TextureBrush will always reveal a tiling made from your image. This seemed ok for your original question, especially when rotating the images in the tail to get rid of any artifacts.

But here it may simply not be what you want.

If you want the image to follow the mouse you need to draw it.

Here is an example, that uses a checkbox to switch between tiling and drawing. The animation uses only one frame:

    for (int i = 0; i < points.Count; i++)
    {
        using (TextureBrush tbr = new TextureBrush(image))
        {
            tbr.RotateTransform(i * 4);   // optional
            var p = PointToClient(Cursor.Position);
            tbr.Transform = new Matrix(
                scaleX,
                0.0f,
                0.0f,
                scaleY,
                0.0f,
                0.0f);
            // any tile mode will work, though not all the same way
            tbr.WrapMode = WrapMode.TileFlipXY;
            if (cbx_tileFunny.Checked)
                e.Graphics.FillEllipse(tbr, p.X - diameter/2, 
                                            p.Y - diameter/2, diameter, diameter);
            else
            {
               ((Bitmap)image).SetResolution(e.Graphics.DpiX, e.Graphics.DpiY);   // (**)
                e.Graphics.ScaleTransform(scaleX, scaleY);
                e.Graphics.DrawImage( image, (p.X - diameter/2) / scaleX,
                                             (p.Y - diameter/2 ) / scaleY);
                e.Graphics.ResetTransform();

            }
                /// ? Pen p3 = new Pen(tbr);
                e.Graphics.DrawEllipse(Pens.DeepSkyBlue, p.X - diameter/2,
                                       p.Y - diameter/2, diameter, diameter);
        }
    }

Do note the extra scaling needed here (**) if the image has a different dpi setting than your screen.

Also: While it is usually a good idea to create and dispose Pens and Brushes quickly, when so much effort is put into creating the Brush and/or Image caching them or even a series of them seems rather preferrable, imo.

这篇关于使用图像而非瓷砖填充纹理笔刷的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆