VectSharp  2.2.1
A light library for C# vector graphics
ColourMatrixFilter.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 colour transformation matrix.
25  /// </summary>
26  public class ColourMatrix
27  {
28  /// <summary>
29  /// The coefficient relating the R component of the output colour to the R component of the input colour.
30  /// </summary>
31  public double R1 { get; set; }
32 
33  /// <summary>
34  /// The coefficient relating the R component of the output colour to the G component of the input colour.
35  /// </summary>
36  public double R2 { get; set; }
37 
38  /// <summary>
39  /// The coefficient relating the R component of the output colour to the B component of the input colour.
40  /// </summary>
41  public double R3 { get; set; }
42 
43  /// <summary>
44  /// The coefficient relating the R component of the output colour to the A component of the input colour.
45  /// </summary>
46  public double R4 { get; set; }
47 
48  /// <summary>
49  /// The bias (translation) applied to the R component of the output colour.
50  /// </summary>
51  public double R5 { get; set; }
52 
53  /// <summary>
54  /// The coefficient relating the G component of the output colour to the R component of the input colour.
55  /// </summary>
56  public double G1 { get; set; }
57 
58  /// <summary>
59  /// The coefficient relating the G component of the output colour to the G component of the input colour.
60  /// </summary>
61  public double G2 { get; set; }
62 
63  /// <summary>
64  /// The coefficient relating the G component of the output colour to the B component of the input colour.
65  /// </summary>
66  public double G3 { get; set; }
67 
68  /// <summary>
69  /// The coefficient relating the G component of the output colour to the A component of the input colour.
70  /// </summary>
71  public double G4 { get; set; }
72 
73  /// <summary>
74  /// The bias (translation) applied to the R component of the output colour.
75  /// </summary>
76  public double G5 { get; set; }
77 
78  /// <summary>
79  /// The coefficient relating the B component of the output colour to the R component of the input colour.
80  /// </summary>
81  public double B1 { get; set; }
82 
83  /// <summary>
84  /// The coefficient relating the B component of the output colour to the G component of the input colour.
85  /// </summary>
86  public double B2 { get; set; }
87 
88  /// <summary>
89  /// The coefficient relating the B component of the output colour to the B component of the input colour.
90  /// </summary>
91  public double B3 { get; set; }
92 
93  /// <summary>
94  /// The coefficient relating the B component of the output colour to the A component of the input colour.
95  /// </summary>
96  public double B4 { get; set; }
97 
98  /// <summary>
99  /// The bias (translation) applied to the B component of the output colour.
100  /// </summary>
101  public double B5 { get; set; }
102 
103  /// <summary>
104  /// The coefficient relating the A component of the output colour to the R component of the input colour.
105  /// </summary>
106  public double A1 { get; set; }
107 
108  /// <summary>
109  /// The coefficient relating the A component of the output colour to the G component of the input colour.
110  /// </summary>
111  public double A2 { get; set; }
112 
113  /// <summary>
114  /// The coefficient relating the A component of the output colour to the B component of the input colour.
115  /// </summary>
116  public double A3 { get; set; }
117 
118  /// <summary>
119  /// The coefficient relating the A component of the output colour to the A component of the input colour.
120  /// </summary>
121  public double A4 { get; set; }
122 
123  /// <summary>
124  /// The bias (translation) applied to the A component of the output colour.
125  /// </summary>
126  public double A5 { get; set; }
127 
128  /// <summary>
129  /// Gets or sets the requested element of the matrix. Elements of the last row of the matrix can be read, but not set.
130  /// </summary>
131  /// <param name="y">The row of the matrix.</param>
132  /// <param name="x">The column of the matrix.</param>
133  /// <returns>The requested element of the matrix.</returns>
134  /// <exception cref="ArgumentOutOfRangeException">An attempt has been made to access an element out of the bounds of the matrix.</exception>
135  public double this[int y, int x]
136  {
137  get
138  {
139  switch (y)
140  {
141  case 0:
142  switch (x)
143  {
144  case 0:
145  return R1;
146  case 1:
147  return R2;
148  case 2:
149  return R3;
150  case 3:
151  return R4;
152  case 4:
153  return R5;
154  default:
155  throw new ArgumentOutOfRangeException(nameof(x), x, "Coordinate out of range!");
156  }
157 
158  case 1:
159  switch (x)
160  {
161  case 0:
162  return G1;
163  case 1:
164  return G2;
165  case 2:
166  return G3;
167  case 3:
168  return G4;
169  case 4:
170  return G5;
171  default:
172  throw new ArgumentOutOfRangeException(nameof(x), x, "Coordinate out of range!");
173  }
174 
175  case 2:
176  switch (x)
177  {
178  case 0:
179  return B1;
180  case 1:
181  return B2;
182  case 2:
183  return B3;
184  case 3:
185  return B4;
186  case 4:
187  return B5;
188  default:
189  throw new ArgumentOutOfRangeException(nameof(x), x, "Coordinate out of range!");
190  }
191 
192  case 3:
193  switch (x)
194  {
195  case 0:
196  return A1;
197  case 1:
198  return A2;
199  case 2:
200  return A3;
201  case 3:
202  return A4;
203  case 4:
204  return A5;
205  default:
206  throw new ArgumentOutOfRangeException(nameof(x), x, "Coordinate out of range!");
207  }
208 
209  case 4:
210  switch (x)
211  {
212  case 0:
213  return 0;
214  case 1:
215  return 0;
216  case 2:
217  return 0;
218  case 3:
219  return 0;
220  case 4:
221  return 1;
222  default:
223  throw new ArgumentOutOfRangeException(nameof(x), x, "Coordinate out of range!");
224  }
225 
226  default:
227  throw new ArgumentOutOfRangeException(nameof(y), y, "Coordinate out of range!");
228  }
229  }
230 
231  private set
232  {
233  switch (y)
234  {
235  case 0:
236  switch (x)
237  {
238  case 0:
239  R1 = value;
240  break;
241  case 1:
242  R2 = value;
243  break;
244  case 2:
245  R3 = value;
246  break;
247  case 3:
248  R4 = value;
249  break;
250  case 4:
251  R5 = value;
252  break;
253  default:
254  throw new ArgumentOutOfRangeException(nameof(x), x, "Coordinate out of range!");
255  }
256  break;
257 
258  case 1:
259  switch (x)
260  {
261  case 0:
262  G1 = value;
263  break;
264  case 1:
265  G2 = value;
266  break;
267  case 2:
268  G3 = value;
269  break;
270  case 3:
271  G4 = value;
272  break;
273  case 4:
274  G5 = value;
275  break;
276  default:
277  throw new ArgumentOutOfRangeException(nameof(x), x, "Coordinate out of range!");
278  }
279  break;
280 
281  case 2:
282  switch (x)
283  {
284  case 0:
285  B1 = value;
286  break;
287  case 1:
288  B2 = value;
289  break;
290  case 2:
291  B3 = value;
292  break;
293  case 3:
294  B4 = value;
295  break;
296  case 4:
297  B5 = value;
298  break;
299  default:
300  throw new ArgumentOutOfRangeException(nameof(x), x, "Coordinate out of range!");
301  }
302  break;
303 
304  case 3:
305  switch (x)
306  {
307  case 0:
308  A1 = value;
309  break;
310  case 1:
311  A2 = value;
312  break;
313  case 2:
314  A3 = value;
315  break;
316  case 3:
317  A4 = value;
318  break;
319  case 4:
320  A5 = value;
321  break;
322  default:
323  throw new ArgumentOutOfRangeException(nameof(x), x, "Coordinate out of range!");
324  }
325  break;
326 
327  default:
328  throw new ArgumentOutOfRangeException(nameof(y), y, "Coordinate out of range!");
329  }
330  }
331  }
332 
333  /// <summary>
334  /// A <see cref="ColourMatrix"/> that whose output colour is always the same as the input colour.
335  /// </summary>
336  public static ColourMatrix Identity = new ColourMatrix(new double[,] { { 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0 }, { 0, 0, 1, 0, 0 }, { 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 1 } });
337 
338  /// <summary>
339  /// A <see cref="ColourMatrix"/> that transforms every colour in a shade of grey with approximately the same luminance.
340  /// </summary>
341  public static ColourMatrix GreyScale = new ColourMatrix(new double[,] { { 0.2126, 0.7152, 0.0722, 0, 0 }, { 0.2126, 0.7152, 0.0722, 0, 0 }, { 0.2126, 0.7152, 0.0722, 0, 0 }, { 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 1 } });
342 
343  /// <summary>
344  /// A <see cref="ColourMatrix"/> producing a "pastel" (desaturation) effect.
345  /// </summary>
346  public static ColourMatrix Pastel = new ColourMatrix(new double[,] { { 0.75, 0.25, 0.25, 0, 0 }, { 0.25, 0.75, 0.25, 0, 0 }, { 0.25, 0.25, 0.75, 0, 0 }, { 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 1 } });
347 
348  /// <summary>
349  /// A <see cref="ColourMatrix"/> that inverts every colour, leaving the alpha component intact.
350  /// </summary>
351  public static ColourMatrix Inversion = new ColourMatrix(new double[,] { { -1, 0, 0, 0, 1 }, { 0, -1, 0, 0, 1 }, { 0, 0, -1, 0, 1 }, { 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 1 } });
352 
353  /// <summary>
354  /// A <see cref="ColourMatrix"/> that inverts the alpha component, leaving the other components intact.
355  /// </summary>
356  public static ColourMatrix AlphaInversion = new ColourMatrix(new double[,] { { 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0 }, { 0, 0, 1, 0, 0 }, { 0, 0, 0, -1, 1 }, { 0, 0, 0, 0, 1 } });
357 
358  /// <summary>
359  /// A <see cref="ColourMatrix"/> that shifts every colour component by an amount corresponding to the inverted alpha value. The alpha component is left intact.
360  /// </summary>
361  public static ColourMatrix InvertedAlphaShift = new ColourMatrix(new double[,] { { 1, 0, 0, -1, 1 }, { 0, 1, 0, -1, 1 }, { 0, 0, 1, -1, 1 }, { 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 1 } });
362 
363  /// <summary>
364  /// Creates a <see cref="ColourMatrix"/> that turns every colour to which it is applied into the specified <paramref name="colour"/>.
365  /// </summary>
366  /// <param name="colour">The colour that will be produced by the <see cref="ColourMatrix"/>.</param>
367  /// <param name="useAlpha">If this is <see langword="true"/>, all output pixels will have the same alpha value as the supplied <paramref name="colour"/>. If this is false, the alpha value of the input pixels is preserved.</param>
368  /// <returns>A <see cref="ColourMatrix"/> that turns every colour to which it is applied into the specified <paramref name="colour"/>.</returns>
369  public static ColourMatrix ToColour(Colour colour, bool useAlpha = false)
370  {
371  if (!useAlpha)
372  {
373  return new ColourMatrix(new double[,] { { 0, 0, 0, 0, colour.R }, { 0, 0, 0, 0, colour.G }, { 0, 0, 0, 0, colour.B }, { 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 1 } });
374  }
375  else
376  {
377  return new ColourMatrix(new double[,] { { 0, 0, 0, 0, colour.R }, { 0, 0, 0, 0, colour.G }, { 0, 0, 0, 0, colour.B }, { 0, 0, 0, 0, colour.A }, { 0, 0, 0, 0, 1 } });
378  }
379  }
380 
381  /// <summary>
382  /// Creates a <see cref="ColourMatrix"/> that turns every colour to which it is applied into a shade of the specified <paramref name="colour"/>. The brightness of the output colour depends on the luminance of the input colour.
383  /// </summary>
384  /// <param name="colour">The colour whose shades will be produced by the <see cref="ColourMatrix"/>.</param>
385  /// <param name="useAlpha">If this is <see langword="true"/>, the transformation will also be applied to the alpha channel. If this is false, the alpha value of the input pixels is preserved.</param>
386  /// <returns>A <see cref="ColourMatrix"/> that turns every colour to which it is applied into a shade of the specified <paramref name="colour"/>.</returns>
387  public static ColourMatrix LuminanceToColour(Colour colour, bool useAlpha = false)
388  {
389  if (!useAlpha)
390  {
391  return new ColourMatrix(new double[,] { { 0.2126 * colour.R, 0.7152 * colour.R, 0.0722 * colour.R, 0, 0 }, { 0.2126 * colour.G, 0.7152 * colour.G, 0.0722 * colour.G, 0, 0 }, { 0.2126 * colour.B, 0.7152 * colour.B, 0.0722 * colour.B, 0, 0 }, { 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 1 } });
392  }
393  else
394  {
395  return new ColourMatrix(new double[,] { { 0.2126 * colour.R, 0.7152 * colour.R, 0.0722 * colour.R, 0, 0 }, { 0.2126 * colour.G, 0.7152 * colour.G, 0.0722 * colour.G, 0, 0 }, { 0.2126 * colour.B, 0.7152 * colour.B, 0.0722 * colour.B, 0, 0 }, { 0.2126 * colour.A, 0.7152 * colour.A, 0.0722 * colour.A, 0, 0 }, { 0, 0, 0, 0, 1 } });
396  }
397  }
398 
399  /// <summary>
400  /// Creates a <see cref="ColourMatrix"/> that transforms the alpha value of the colour it is applied to into a value depending on the luminance of the input colour.
401  /// </summary>
402  /// <param name="preserveColour">If this is <see langword="true"/>, the values of the red, green and blue components of the input colour are preserved in the output colour. If this is false, the output colour will always be black.</param>
403  /// <returns>A <see cref="ColourMatrix"/> that transforms the alpha value of the colour it is applied to into a value depending on the luminance of the input colour.</returns>
404  public static ColourMatrix LuminanceToAlpha(bool preserveColour = false)
405  {
406  if (!preserveColour)
407  {
408  return new ColourMatrix(new double[,] { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0.2126, 0.7152, 0.0722, 0, 0 }, { 0, 0, 0, 0, 1 } });
409  }
410  else
411  {
412  return new ColourMatrix(new double[,] { { 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0 }, { 0, 0, 1, 0, 0 }, { 0.2126, 0.7152, 0.0722, 0, 0 }, { 0, 0, 0, 0, 1 } });
413  }
414  }
415 
416  /// <summary>
417  /// Creates a new <see cref="ColourMatrix"/> whose alpha coefficients are multiplied by the specified value.
418  /// </summary>
419  /// <param name="alpha">The value that will be used to multiply all the alpha coefficients of the <see cref="ColourMatrix"/>.</param>
420  /// <returns>A new <see cref="ColourMatrix"/> whose alpha coefficients have been multiplied by the specified value.</returns>
421  public ColourMatrix WithAlpha(double alpha)
422  {
423  return new ColourMatrix(new double[,] { { R1, R2, R3, R4, R5 }, { G1, G2, G3, G4, G5 }, { B1, B2, B3, B4, B5 }, { A1 * alpha, A2 * alpha, A3 * alpha, A4 * alpha, A5 * alpha }, { 0, 0, 0, 0, 1 } });
424  }
425 
426  /// <summary>
427  /// Concatenates two matrices. The resulting <see cref="ColourMatrix"/> is equivalent to first applying <paramref name="matrix2"/>, and then <paramref name="matrix1"/>.
428  /// </summary>
429  /// <param name="matrix1">The matrix that acts second.</param>
430  /// <param name="matrix2">The matrix that acts first.</param>
431  /// <returns>A <see cref="ColourMatrix"/> equivalent to first applying <paramref name="matrix2"/>, and then <paramref name="matrix1"/>.</returns>
432  public static ColourMatrix operator *(ColourMatrix matrix1, ColourMatrix matrix2)
433  {
434  double[,] tbr = new double[5, 5];
435 
436  for (int i = 0; i < 5; i++)
437  {
438  for (int j = 0; j < 5; j++)
439  {
440  for (int k = 0; k < 5; k++)
441  {
442  tbr[i, j] += matrix1[i, k] * matrix2[k, j];
443  }
444  }
445  }
446 
447  return new ColourMatrix(tbr);
448  }
449 
450  /// <summary>
451  /// Creates a new <see cref="ColourMatrix"/> with the specified coefficients.
452  /// </summary>
453  /// <param name="matrix">The coefficients of the <see cref="ColourMatrix"/>.</param>
454  public ColourMatrix(double[,] matrix)
455  {
456  for (int i = 0; i < 4; i++)
457  {
458  for (int j = 0; j < 5; j++)
459  {
460  this[i, j] = matrix[i, j];
461  }
462  }
463  }
464 
465  /// <summary>
466  /// Applies the <see cref="ColourMatrix"/> to the specified <see cref="Colour"/>.
467  /// </summary>
468  /// <param name="colour">The <see cref="Colour"/> to which the <see cref="ColourMatrix"/> should be applied.</param>
469  /// <returns>The result of applying the <see cref="ColourMatrix"/> to the specified colour.</returns>
470  public Colour Apply(Colour colour)
471  {
472  double[] col = new double[] { colour.R, colour.G, colour.B, colour.A, 1 };
473 
474  double[] tbr = new double[5];
475 
476  for (int i = 0; i < tbr.Length; i++)
477  {
478  for (int j = 0; j < tbr.Length; j++)
479  {
480  tbr[i] += this[i, j] * col[j];
481  }
482  }
483 
484  return Colour.FromRgba(tbr[0], tbr[1], tbr[2], tbr[3]);
485  }
486 
487  /// <summary>
488  /// Applies the <see cref="ColourMatrix"/> to the specified colour, represented as four bytes, and stores the resulting colour in the
489  /// same variables as the original RGBA values.
490  /// </summary>
491  /// <param name="R">The R component of the input colour. After this method returns, this will contain the R component of the output colour.</param>
492  /// <param name="G">The G component of the input colour. After this method returns, this will contain the G component of the output colour.</param>
493  /// <param name="B">The B component of the input colour. After this method returns, this will contain the B component of the output colour.</param>
494  /// <param name="A">The A component of the input colour. After this method returns, this will contain the A component of the output colour.</param>
495  public void Apply(ref byte R, ref byte G, ref byte B, ref byte A)
496  {
497  byte r = (byte)Math.Min(255, Math.Max(0, Math.Round(R * this.R1 + G * this.R2 + B * this.R3 + A * this.R4 + this.R5 * 255)));
498  byte g = (byte)Math.Min(255, Math.Max(0, Math.Round(R * this.G1 + G * this.G2 + B * this.G3 + A * this.G4 + this.G5 * 255)));
499  byte b = (byte)Math.Min(255, Math.Max(0, Math.Round(R * this.B1 + G * this.B2 + B * this.B3 + A * this.B4 + this.B5 * 255)));
500  byte a = (byte)Math.Min(255, Math.Max(0, Math.Round(R * this.A1 + G * this.A2 + B * this.A3 + A * this.A4 + this.A5 * 255)));
501 
502  R = r;
503  G = g;
504  B = b;
505  A = a;
506  }
507 
508  /// <summary>
509  /// Applies the <see cref="ColourMatrix"/> to the specified colour, represented as three bytes, and stores the resulting colour in the
510  /// same variables as the original RGB values.
511  /// </summary>
512  /// <param name="R">The R component of the input colour. After this method returns, this will contain the R component of the output colour.</param>
513  /// <param name="G">The G component of the input colour. After this method returns, this will contain the G component of the output colour.</param>
514  /// <param name="B">The B component of the input colour. After this method returns, this will contain the B component of the output colour.</param>
515  public void Apply(ref byte R, ref byte G, ref byte B)
516  {
517  byte r = (byte)Math.Min(255, Math.Max(0, Math.Round(R * this.R1 + G * this.R2 + B * this.R3 + 255 * this.R4 + this.R5 * 255)));
518  byte g = (byte)Math.Min(255, Math.Max(0, Math.Round(R * this.G1 + G * this.G2 + B * this.G3 + 255 * this.G4 + this.G5 * 255)));
519  byte b = (byte)Math.Min(255, Math.Max(0, Math.Round(R * this.B1 + G * this.B2 + B * this.B3 + 255 * this.B4 + this.B5 * 255)));
520 
521  R = r;
522  G = g;
523  B = b;
524  }
525 
526  /// <summary>
527  /// Applies the <see cref="ColourMatrix"/> to the specified colour, represented as four bytes, and stores the resulting colour in the
528  /// specified output bytes.
529  /// </summary>
530  /// <param name="R">The R component of the input colour.</param>
531  /// <param name="G">The G component of the input colour.</param>
532  /// <param name="B">The B component of the input colour.</param>
533  /// <param name="A">The A component of the input colour.</param>
534  /// <param name="r">After this method returns, this will contain the R component of the output colour.</param>
535  /// <param name="g">After this method returns, this will contain the G component of the output colour.</param>
536  /// <param name="b">After this method returns, this will contain the B component of the output colour.</param>
537  /// <param name="a">After this method returns, this will contain the A component of the output colour.</param>
538  public void Apply(byte R, byte G, byte B, byte A, out byte r, out byte g, out byte b, out byte a)
539  {
540  r = (byte)Math.Min(255, Math.Max(0, Math.Round(R * this.R1 + G * this.R2 + B * this.R3 + A * this.R4 + this.R5 * 255)));
541  g = (byte)Math.Min(255, Math.Max(0, Math.Round(R * this.G1 + G * this.G2 + B * this.G3 + A * this.G4 + this.G5 * 255)));
542  b = (byte)Math.Min(255, Math.Max(0, Math.Round(R * this.B1 + G * this.B2 + B * this.B3 + A * this.B4 + this.B5 * 255)));
543  a = (byte)Math.Min(255, Math.Max(0, Math.Round(R * this.A1 + G * this.A2 + B * this.A3 + A * this.A4 + this.A5 * 255)));
544  }
545 
546  /// <summary>
547  /// Applies the <see cref="ColourMatrix"/> to the specified colour, represented as three bytes, and stores the resulting colour in the
548  /// specified output bytes.
549  /// </summary>
550  /// <param name="R">The R component of the input colour.</param>
551  /// <param name="G">The G component of the input colour.</param>
552  /// <param name="B">The B component of the input colour.</param>
553  /// <param name="r">After this method returns, this will contain the R component of the output colour.</param>
554  /// <param name="g">After this method returns, this will contain the G component of the output colour.</param>
555  /// <param name="b">After this method returns, this will contain the B component of the output colour.</param>
556  public void Apply(byte R, byte G, byte B, out byte r, out byte g, out byte b)
557  {
558  r = (byte)Math.Min(255, Math.Max(0, Math.Round(R * this.R1 + G * this.R2 + B * this.R3 + 255 * this.R4 + this.R5 * 255)));
559  g = (byte)Math.Min(255, Math.Max(0, Math.Round(R * this.G1 + G * this.G2 + B * this.G3 + 255 * this.G4 + this.G5 * 255)));
560  b = (byte)Math.Min(255, Math.Max(0, Math.Round(R * this.B1 + G * this.B2 + B * this.B3 + 255 * this.B4 + this.B5 * 255)));
561  }
562  }
563 
564  /// <summary>
565  /// Represents a filter that applies a <see cref="Filters.ColourMatrix"/> to the colours of the image.
566  /// </summary>
568  {
569  /// <summary>
570  /// The <see cref="Filters.ColourMatrix"/> that is applied by this filter.
571  /// </summary>
572  public ColourMatrix ColourMatrix { get; }
573 
574  /// <inheritdoc/>
575  public Point TopLeftMargin { get; } = new Point();
576 
577  /// <inheritdoc/>
578  public Point BottomRightMargin { get; } = new Point();
579 
580  /// <summary>
581  /// Creates a new <see cref="ColourMatrixFilter"/> with the specified <see cref="Filters.ColourMatrix"/>.
582  /// </summary>
583  /// <param name="colorMatrix">The <see cref="Filters.ColourMatrix"/> that will be applied by the filter.</param>
584  public ColourMatrixFilter(ColourMatrix colorMatrix)
585  {
586  this.ColourMatrix = colorMatrix;
587  }
588 
589  /// <inheritdoc/>
590  public RasterImage Filter(RasterImage image, double scale)
591  {
592  IntPtr tbrData = System.Runtime.InteropServices.Marshal.AllocHGlobal(image.Width * image.Height * (image.HasAlpha ? 4 : 3));
593  GC.AddMemoryPressure(image.Width * image.Height * (image.HasAlpha ? 4 : 3));
594 
595  int width = image.Width;
596  int height = image.Height;
597 
598  int pixelSize = image.HasAlpha ? 4 : 3;
599  int stride = image.Width * pixelSize;
600 
601  int threads = Math.Min(8, Environment.ProcessorCount);
602 
603  unsafe
604  {
605  byte* input = (byte*)image.ImageDataAddress;
606  byte* output = (byte*)tbrData;
607 
608  Action<int> yLoop;
609 
610  if (image.HasAlpha)
611  {
612  yLoop = (y) =>
613  {
614  for (int x = 0; x < width; x++)
615  {
616  this.ColourMatrix.Apply(input[y * stride + x * 4], input[y * stride + x * 4 + 1], input[y * stride + x * 4 + 2], input[y * stride + x * 4 + 3], out output[y * stride + x * 4], out output[y * stride + x * 4 + 1], out output[y * stride + x * 4 + 2], out output[y * stride + x * 4 + 3]);
617  }
618  };
619  }
620  else
621  {
622  yLoop = (y) =>
623  {
624  for (int x = 0; x < width; x++)
625  {
626  this.ColourMatrix.Apply(input[y * stride + x * 4], input[y * stride + x * 4 + 1], input[y * stride + x * 4 + 2], out output[y * stride + x * 4], out output[y * stride + x * 4 + 1], out output[y * stride + x * 4 + 2]);
627  }
628  };
629  }
630 
631  if (threads == 1)
632  {
633  for (int y = 0; y < height; y++)
634  {
635  yLoop(y);
636  }
637  }
638  else
639  {
640  ParallelOptions options = new ParallelOptions() { MaxDegreeOfParallelism = threads };
641 
642  Parallel.For(0, height, options, yLoop);
643  }
644 
645  }
646 
647  DisposableIntPtr disp = new DisposableIntPtr(tbrData);
648 
649  return new RasterImage(ref disp, width, height, image.HasAlpha, image.Interpolate);
650  }
651  }
652 }
VectSharp.Filters.ColourMatrix.B4
double B4
The coefficient relating the B component of the output colour to the A component of the input colour.
Definition: ColourMatrixFilter.cs:96
VectSharp.Filters.ColourMatrix
Represents a colour transformation matrix.
Definition: ColourMatrixFilter.cs:27
VectSharp.Filters.ColourMatrix.Apply
void Apply(ref byte R, ref byte G, ref byte B)
Applies the ColourMatrix to the specified colour, represented as three bytes, and stores the resultin...
Definition: ColourMatrixFilter.cs:515
VectSharp.Colour
Represents an RGB colour.
Definition: Colour.cs:26
VectSharp.Filters.ColourMatrix.A1
double A1
The coefficient relating the A component of the output colour to the R component of the input colour.
Definition: ColourMatrixFilter.cs:106
VectSharp.Filters.ColourMatrix.Inversion
static ColourMatrix Inversion
A ColourMatrix that inverts every colour, leaving the alpha component intact.
Definition: ColourMatrixFilter.cs:351
VectSharp.Filters.ColourMatrix.G3
double G3
The coefficient relating the G component of the output colour to the B component of the input colour.
Definition: ColourMatrixFilter.cs:66
VectSharp.Filters.ColourMatrix.Apply
Colour Apply(Colour colour)
Applies the ColourMatrix to the specified Colour.
Definition: ColourMatrixFilter.cs:470
VectSharp.RasterImage
Represents a raster image, created from raw pixel data. Consider using the derived classes included i...
Definition: RasterImage.cs:99
VectSharp.Colour.R
double R
Red component of the colour. Range: [0, 1].
Definition: Colour.cs:30
VectSharp.Filters.ColourMatrix.A5
double A5
The bias (translation) applied to the A component of the output colour.
Definition: ColourMatrixFilter.cs:126
VectSharp.Filters.ColourMatrix.operator*
static ColourMatrix operator*(ColourMatrix matrix1, ColourMatrix matrix2)
Concatenates two matrices. The resulting ColourMatrix is equivalent to first applying matrix2 ,...
Definition: ColourMatrixFilter.cs:432
VectSharp.DisposableIntPtr
An IDisposable wrapper around an IntPtr that frees the allocated memory when it is disposed.
Definition: RasterImage.cs:54
VectSharp.Filters.ColourMatrix.LuminanceToAlpha
static ColourMatrix LuminanceToAlpha(bool preserveColour=false)
Creates a ColourMatrix that transforms the alpha value of the colour it is applied to into a value de...
Definition: ColourMatrixFilter.cs:404
VectSharp.Filters.ColourMatrixFilter
Represents a filter that applies a Filters.ColourMatrix to the colours of the image.
Definition: ColourMatrixFilter.cs:568
VectSharp.Filters.ColourMatrix.A3
double A3
The coefficient relating the A component of the output colour to the B component of the input colour.
Definition: ColourMatrixFilter.cs:116
VectSharp.Filters.ColourMatrix.Apply
void Apply(byte R, byte G, byte B, byte A, out byte r, out byte g, out byte b, out byte a)
Applies the ColourMatrix to the specified colour, represented as four bytes, and stores the resulting...
Definition: ColourMatrixFilter.cs:538
VectSharp.RasterImage.Width
int Width
The width in pixels of the image.
Definition: RasterImage.cs:123
VectSharp.Filters.ColourMatrix.R2
double R2
The coefficient relating the R component of the output colour to the G component of the input colour.
Definition: ColourMatrixFilter.cs:36
VectSharp.Colour.A
double A
Alpha component of the colour. Range: [0, 1].
Definition: Colour.cs:45
VectSharp.Filters.ColourMatrix.G4
double G4
The coefficient relating the G component of the output colour to the A component of the input colour.
Definition: ColourMatrixFilter.cs:71
VectSharp.Filters.ColourMatrix.G2
double G2
The coefficient relating the G component of the output colour to the G component of the input colour.
Definition: ColourMatrixFilter.cs:61
VectSharp.Filters.ColourMatrix.WithAlpha
ColourMatrix WithAlpha(double alpha)
Creates a new ColourMatrix whose alpha coefficients are multiplied by the specified value.
Definition: ColourMatrixFilter.cs:421
VectSharp.RasterImage.Interpolate
bool Interpolate
Determines whether the image should be interpolated when it is resized.
Definition: RasterImage.cs:133
VectSharp.Filters.ColourMatrixFilter.BottomRightMargin
Point BottomRightMargin
Definition: ColourMatrixFilter.cs:578
VectSharp.Filters.ColourMatrix.A2
double A2
The coefficient relating the A component of the output colour to the G component of the input colour.
Definition: ColourMatrixFilter.cs:111
VectSharp.Filters.ColourMatrix.R1
double R1
The coefficient relating the R component of the output colour to the R component of the input colour.
Definition: ColourMatrixFilter.cs:31
VectSharp.Filters.ColourMatrix.AlphaInversion
static ColourMatrix AlphaInversion
A ColourMatrix that inverts the alpha component, leaving the other components intact.
Definition: ColourMatrixFilter.cs:356
VectSharp.Filters.ColourMatrix.GreyScale
static ColourMatrix GreyScale
A ColourMatrix that transforms every colour in a shade of grey with approximately the same luminance.
Definition: ColourMatrixFilter.cs:341
VectSharp.RasterImage.HasAlpha
bool HasAlpha
Determines whether the image has an alpha channel.
Definition: RasterImage.cs:118
VectSharp.Filters.ColourMatrix.InvertedAlphaShift
static ColourMatrix InvertedAlphaShift
A ColourMatrix that shifts every colour component by an amount corresponding to the inverted alpha va...
Definition: ColourMatrixFilter.cs:361
VectSharp.Filters.ColourMatrix.B5
double B5
The bias (translation) applied to the B component of the output colour.
Definition: ColourMatrixFilter.cs:101
VectSharp.Filters.ColourMatrix.G5
double G5
The bias (translation) applied to the R component of the output colour.
Definition: ColourMatrixFilter.cs:76
VectSharp.Filters.ColourMatrix.ToColour
static ColourMatrix ToColour(Colour colour, bool useAlpha=false)
Creates a ColourMatrix that turns every colour to which it is applied into the specified colour .
Definition: ColourMatrixFilter.cs:369
VectSharp.Filters.ColourMatrix.B3
double B3
The coefficient relating the B component of the output colour to the B component of the input colour.
Definition: ColourMatrixFilter.cs:91
VectSharp.Filters.ColourMatrix.Identity
static ColourMatrix Identity
A ColourMatrix that whose output colour is always the same as the input colour.
Definition: ColourMatrixFilter.cs:336
VectSharp.Filters.ColourMatrixFilter.TopLeftMargin
Point TopLeftMargin
Definition: ColourMatrixFilter.cs:575
VectSharp.Filters.ColourMatrix.R4
double R4
The coefficient relating the R component of the output colour to the A component of the input colour.
Definition: ColourMatrixFilter.cs:46
VectSharp.Colour.B
double B
Blue component of the colour. Range: [0, 1].
Definition: Colour.cs:40
VectSharp.Filters.ColourMatrix.R5
double R5
The bias (translation) applied to the R component of the output colour.
Definition: ColourMatrixFilter.cs:51
VectSharp.RasterImage.Height
int Height
The height in pixels of the image.
Definition: RasterImage.cs:128
VectSharp.Filters.ColourMatrix.Apply
void Apply(ref byte R, ref byte G, ref byte B, ref byte A)
Applies the ColourMatrix to the specified colour, represented as four bytes, and stores the resulting...
Definition: ColourMatrixFilter.cs:495
VectSharp.Filters
Definition: BoxBlurFilter.cs:22
VectSharp.Filters.ColourMatrix.R3
double R3
The coefficient relating the R component of the output colour to the B component of the input colour.
Definition: ColourMatrixFilter.cs:41
VectSharp.Filters.ILocationInvariantFilter
Represents a filter that can be applied to an image regardless of its location on the graphics surfac...
Definition: Filters.cs:42
VectSharp.Filters.ColourMatrix.G1
double G1
The coefficient relating the G component of the output colour to the R component of the input colour.
Definition: ColourMatrixFilter.cs:56
VectSharp.Filters.ColourMatrix.Apply
void Apply(byte R, byte G, byte B, out byte r, out byte g, out byte b)
Applies the ColourMatrix to the specified colour, represented as three bytes, and stores the resultin...
Definition: ColourMatrixFilter.cs:556
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.ColourMatrix.LuminanceToColour
static ColourMatrix LuminanceToColour(Colour colour, bool useAlpha=false)
Creates a ColourMatrix that turns every colour to which it is applied into a shade of the specified c...
Definition: ColourMatrixFilter.cs:387
VectSharp.Filters.ColourMatrix.ColourMatrix
ColourMatrix(double[,] matrix)
Creates a new ColourMatrix with the specified coefficients.
Definition: ColourMatrixFilter.cs:454
VectSharp.Filters.ColourMatrix.B1
double B1
The coefficient relating the B component of the output colour to the R component of the input colour.
Definition: ColourMatrixFilter.cs:81
VectSharp.Filters.ColourMatrixFilter.Filter
RasterImage Filter(RasterImage image, double scale)
Applies the filter to a RasterImage.
Definition: ColourMatrixFilter.cs:590
VectSharp.Filters.ColourMatrix.B2
double B2
The coefficient relating the B component of the output colour to the G component of the input colour.
Definition: ColourMatrixFilter.cs:86
VectSharp.Filters.ColourMatrix.Pastel
static ColourMatrix Pastel
A ColourMatrix producing a "pastel" (desaturation) effect.
Definition: ColourMatrixFilter.cs:346
VectSharp.Filters.ColourMatrixFilter.ColourMatrixFilter
ColourMatrixFilter(ColourMatrix colorMatrix)
Creates a new ColourMatrixFilter with the specified Filters.ColourMatrix.
Definition: ColourMatrixFilter.cs:584
VectSharp.Colour.G
double G
Green component of the colour. Range: [0, 1].
Definition: Colour.cs:35
VectSharp.Filters.ColourMatrix.A4
double A4
The coefficient relating the A component of the output colour to the A component of the input colour.
Definition: ColourMatrixFilter.cs:121
VectSharp.Colour.FromRgba
static Colour FromRgba(double r, double g, double b, double a)
Create a new colour from RGBA (red, green, blue and alpha) values.
Definition: Colour.cs:99