VectSharp  2.2.1
A light library for C# vector graphics
MaskFilter.cs
1 /*
2  VectSharp - A light library for C# vector graphics.
3  Copyright (C) 2020-2022 Giorgio Bianchini
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, version 3.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU Lesser General Public License for more details.
13 
14  You should have received a copy of the GNU Lesser General Public License
15  along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17 
18 using System;
19 using System.Threading.Tasks;
20 
21 namespace VectSharp.Filters
22 {
23  /// <summary>
24  /// Represents a filter that uses the luminance of an image to mask another image.
25  /// </summary>
27  {
28  /// <inheritdoc/>
29  public Point TopLeftMargin => new Point(0, 0);
30  /// <inheritdoc/>
31  public Point BottomRightMargin => new Point(0, 0);
32 
33  /// <summary>
34  /// The image that is used to mask the input image.
35  /// </summary>
36  public Graphics Mask => this.RasterisableParameter;
37 
38  /// <summary>
39  /// Creates a new <see cref="MaskFilter"/> with the specified mask image.
40  /// </summary>
41  /// <param name="mask">The image that is used to mask the input image.</param>
42  public MaskFilter(Graphics mask) : base(mask) { }
43 
44  /// <inheritdoc/>
45  public RasterImage Filter(RasterImage image, Rectangle bounds, double scale)
46  {
47  RasterImage mask = this.GetCachedRasterisation(scale);
48 
49  IntPtr tbrData = System.Runtime.InteropServices.Marshal.AllocHGlobal(image.Width * image.Height * 4);
50  GC.AddMemoryPressure(image.Width * image.Height * 4);
51 
52  int width = image.Width;
53  int height = image.Height;
54 
55  int pixelSizeInput = image.HasAlpha ? 4 : 3;
56  int strideInput = image.Width * pixelSizeInput;
57 
58  int pixelSizeOutput = 4;
59  int strideOutput = image.Width * pixelSizeOutput;
60 
61  int pixelSizeMask = 4;
62  int strideMask = mask.Width * pixelSizeMask;
63 
64  int maskWidth = mask.Width;
65  int maskHeight = mask.Height;
66 
67  int threads = Math.Min(8, Environment.ProcessorCount);
68 
69  unsafe
70  {
71  byte* input = (byte*)image.ImageDataAddress;
72  byte* maskBytes = (byte*)mask.ImageDataAddress;
73  byte* output = (byte*)tbrData;
74 
75  Action<int> yLoop;
76 
77  if (image.HasAlpha)
78  {
79  yLoop = (y) =>
80  {
81  for (int x = 0; x < width; x++)
82  {
83  int maskX = (int)Math.Round((bounds.Location.X + (x + 0.5) * bounds.Size.Width / width - CachedBounds.Location.X) / CachedBounds.Size.Width * maskWidth);
84  int maskY = (int)Math.Round((bounds.Location.Y + (y + 0.5) * bounds.Size.Height / height - CachedBounds.Location.Y) / CachedBounds.Size.Height * maskHeight);
85 
86  double weight = 0;
87 
88  if (maskX >= 0 && maskX < maskWidth && maskY >= 0 && maskY < maskHeight)
89  {
90  weight = (maskBytes[maskY * strideMask + maskX * pixelSizeMask] * 0.2126 + maskBytes[maskY * strideMask + maskX * pixelSizeMask + 1] * 0.7152 + maskBytes[maskY * strideMask + maskX * pixelSizeMask + 2] * 0.0722) / 255.0;
91 
92  if (mask.HasAlpha)
93  {
94  weight *= maskBytes[maskY * strideMask + maskX * pixelSizeMask + 3] / 255.0;
95  }
96  }
97 
98  if (weight > 0)
99  {
100  output[y * strideOutput + x * 4] = input[y * strideInput + x * 4];
101  output[y * strideOutput + x * 4 + 1] = input[y * strideInput + x * 4 + 1];
102  output[y * strideOutput + x * 4 + 2] = input[y * strideInput + x * 4 + 2];
103  output[y * strideOutput + x * 4 + 3] = (byte)Math.Round(input[y * strideInput + x * 4 + 3] * weight);
104  }
105  else
106  {
107  output[y * strideOutput + x * 4] = 0;
108  output[y * strideOutput + x * 4 + 1] = 0;
109  output[y * strideOutput + x * 4 + 2] = 0;
110  output[y * strideOutput + x * 4 + 3] = 0;
111  }
112  }
113  };
114  }
115  else
116  {
117  yLoop = (y) =>
118  {
119  for (int x = 0; x < width; x++)
120  {
121  int maskX = (int)Math.Round((bounds.Location.X + (x + 0.5) * bounds.Size.Width / width - CachedBounds.Location.X) / CachedBounds.Size.Width * maskWidth);
122  int maskY = (int)Math.Round((bounds.Location.Y + (y + 0.5) * bounds.Size.Height / height - CachedBounds.Location.Y) / CachedBounds.Size.Height * maskHeight);
123 
124  double weight = 0;
125 
126  if (maskX >= 0 && maskX < maskWidth && maskY >= 0 && maskY < maskHeight)
127  {
128  weight = (maskBytes[maskY * strideMask + maskX * pixelSizeMask] * 0.2126 + maskBytes[maskY * strideMask + maskX * pixelSizeMask + 1] * 0.7152 + maskBytes[maskY * strideMask + maskX * pixelSizeMask + 2] * 0.0722);
129 
130  if (mask.HasAlpha)
131  {
132  weight *= maskBytes[maskY * strideMask + maskX * pixelSizeMask + 3] / 255.0;
133  }
134  }
135 
136  if (weight > 0)
137  {
138  output[y * strideOutput + x * 4] = input[y * strideInput + x * 3];
139  output[y * strideOutput + x * 4 + 1] = input[y * strideInput + x * 3 + 1];
140  output[y * strideOutput + x * 4 + 2] = input[y * strideInput + x * 3 + 2];
141  output[y * strideOutput + x * 4 + 3] = (byte)Math.Round(weight);
142  }
143  else
144  {
145  output[y * strideOutput + x * 4] = 0;
146  output[y * strideOutput + x * 4 + 1] = 0;
147  output[y * strideOutput + x * 4 + 2] = 0;
148  output[y * strideOutput + x * 4 + 3] = 0;
149  }
150  }
151  };
152  }
153 
154  if (threads == 1)
155  {
156  for (int y = 0; y < height; y++)
157  {
158  yLoop(y);
159  }
160  }
161  else
162  {
163  ParallelOptions options = new ParallelOptions() { MaxDegreeOfParallelism = threads };
164 
165  Parallel.For(0, height, options, yLoop);
166  }
167 
168  }
169 
170  DisposableIntPtr disp = new DisposableIntPtr(tbrData);
171 
172  return new RasterImage(ref disp, width, height, image.HasAlpha, image.Interpolate);
173 
174  }
175  }
176 }
VectSharp.Rectangle
Represents a rectangle.
Definition: Point.cs:173
VectSharp.Filters.MaskFilter.MaskFilter
MaskFilter(Graphics mask)
Creates a new MaskFilter with the specified mask image.
Definition: MaskFilter.cs:42
VectSharp.Filters.MaskFilter.Mask
Graphics Mask
The image that is used to mask the input image.
Definition: MaskFilter.cs:36
VectSharp.RasterImage
Represents a raster image, created from raw pixel data. Consider using the derived classes included i...
Definition: RasterImage.cs:99
VectSharp.DisposableIntPtr
An IDisposable wrapper around an IntPtr that frees the allocated memory when it is disposed.
Definition: RasterImage.cs:54
VectSharp.RasterImage.Width
int Width
The width in pixels of the image.
Definition: RasterImage.cs:123
VectSharp.Size.Height
double Height
Height of the object.
Definition: Point.cs:155
VectSharp.RasterImage.Interpolate
bool Interpolate
Determines whether the image should be interpolated when it is resized.
Definition: RasterImage.cs:133
VectSharp.Graphics
Represents an abstract drawing surface.
Definition: Graphics.cs:262
VectSharp.Rectangle.Size
Size Size
The size of the rectangle.
Definition: Point.cs:187
VectSharp.RasterImage.HasAlpha
bool HasAlpha
Determines whether the image has an alpha channel.
Definition: RasterImage.cs:118
VectSharp.Filters.FilterWithRasterisableParameter
Represents a filter with a parameter that needs to be rasterised at the same resolution as the subjec...
Definition: Filters.cs:87
VectSharp.Point.X
double X
Horizontal (x) coordinate, measured to the right of the origin.
Definition: Point.cs:32
VectSharp.RasterImage.Height
int Height
The height in pixels of the image.
Definition: RasterImage.cs:128
VectSharp.Filters.MaskFilter.BottomRightMargin
Point BottomRightMargin
Definition: MaskFilter.cs:31
VectSharp.Filters
Definition: BoxBlurFilter.cs:22
VectSharp.Filters.MaskFilter
Represents a filter that uses the luminance of an image to mask another image.
Definition: MaskFilter.cs:27
VectSharp.Rectangle.Location
Point Location
The top-left corner of the rectangle.
Definition: Point.cs:182
VectSharp.Size.Width
double Width
Width of the object.
Definition: Point.cs:150
VectSharp.Filters.IFilterWithLocation
Represents a filter whose results depend on the position of the subject image on the graphics surface...
Definition: Filters.cs:56
VectSharp.RasterImage.ImageDataAddress
IntPtr ImageDataAddress
The memory address of the image pixel data.
Definition: RasterImage.cs:103
VectSharp.Point
Represents a point relative to an origin in the top-left corner.
Definition: Point.cs:28
VectSharp.Filters.MaskFilter.TopLeftMargin
Point TopLeftMargin
Definition: MaskFilter.cs:29
VectSharp.Filters.MaskFilter.Filter
RasterImage Filter(RasterImage image, Rectangle bounds, double scale)
Applies the filter to a RasterImage.
Definition: MaskFilter.cs:45
VectSharp.Point.Y
double Y
Vertical (y) coordinate, measured to the bottom of the origin.
Definition: Point.cs:37