📄 photopropchanger.cs
字号:
using System;
using System.Drawing;
using System.Drawing.Imaging;
namespace VirtualPhotoOrganizer.Photo
{
/// <summary>
/// allows us to change brightness, contrast, saturation, grayscale, sepia and gamma
/// </summary>
internal class PhotoPropChanger
{
#region constants
// grayscale values defined by the NTSC
private const Single GRAYRED = 0.3086F;
private const Single GRAYGREEN = 0.6094F;
private const Single GRAYBLUE = 0.082F;
// sepia consts
private const Single SEPIARED = 0.2F;
private const Single SEPIAGREEN = 0.14F;
private const Single SEPIABLUE = 0.08F;
#endregion
public PhotoPropChanger() { }
#region public methods
/// <summary>
/// Adjusts the brightness of the image according to the specified value
/// </summary>
public void AdjustBrightness(Bitmap image, int percent) {
DrawImage(image, GetBrightnessMatrix(percent));
}
/// <summary>
/// Adjusts the contrast of the image according to the specified value
/// </summary>
public void AdjustContrast(Bitmap image, int percent) {
DrawImage(image, GetContrastMatrix(percent));
}
/// <summary>
/// Adjusts the saturation of the image according to the specified value
/// </summary>
public void AdjustSaturation(Bitmap image, int percent) {
DrawImage(image, GetSaturationMatrix(percent));
}
/// <summary>
/// Converts the specified image to grayscale
/// </summary>
public void ConvertToGrayscale(Bitmap image) {
DrawImage(image, GetGrayscaleMatrix());
}
/// <summary>
/// Converts the image to sepia
/// </summary>
public void ConvertToSepia(Bitmap image) {
DrawImage(image, GetSepiaMatrix());
}
/// <summary>
/// Adjusts the image using the specified matrix
/// </summary>
public void AdjustUsingCustomMatrix(Bitmap image, Single[][] matrix) {
DrawImage(image, matrix);
}
/// <summary>
/// Adjusts the image using the specified attributes
/// </summary>
public void AdjustUsingCustomAttributes(Bitmap image, ImageAttributes attrib) {
DrawImage(image, attrib);
}
/// <summary>
/// Adjusts the gamma value of the image according to the specified value
/// </summary>
public void AdjustGamma(Bitmap image, int percent) {
// setup attributes with gamma value
ImageAttributes attrib = new ImageAttributes();
attrib.SetGamma(GetGamma(percent));
// update the image
DrawImage(image, attrib);
attrib.Dispose();
}
#endregion
#region helper methods
/// <summary>
/// Returns the matrix for the specified brightness value
/// </summary>
public Single[][] GetBrightnessMatrix(int percent) {
/*set brightness by setting the offset row in the matrix
* values can range from -1.0 (black) to 1.0 (white)
* map the percent to use 60% of the full range (-0.6 to 0.6)*/
Single v = 0.006F * percent;
// setup the matrix
Single[][] matrix =
{
new Single[] {1, 0, 0, 0, 0},
new Single[] {0, 1, 0, 0, 0},
new Single[] {0, 0, 1, 0, 0},
new Single[] {0, 0, 0, 1, 0},
new Single[] {v, v, v, 0, 1}
};
// return the matrix
return matrix;
}
/// <summary>
/// Returns the matrix for the specified contrast
/// </summary>
public Single[][] GetContrastMatrix(int percent) {
// get contrast by settings the scale and offset at the same time
// calculate the scale
Single v;
if (percent > 0) {
// may range from 0.0 (no change) to 3.8 (high contrast)
v = 0.0195F * percent;
v *= v;
} else // negative value, -1.0 is gray and 0.0 is no change
v = 0.009F * percent;
Single scale = 1 + v;
Single offset = v / 2;
// setup the matrix;
Single[][] matrix =
{
new Single[] {scale, 0, 0, 0, 0},
new Single[] {0, scale, 0, 0, 0},
new Single[] {0, 0, scale, 0, 0},
new Single[] {0, 0, 0, 1, 0},
new Single[] {-offset, -offset, -offset, 0, 1}
};
return matrix;
}
/// <summary>
/// Returns the matrix for the specified saturation
/// </summary>
public Single[][] GetSaturationMatrix(int percent) {
/* set the saturation by scaling the red, green and blue values
* a value of 0 is grayscale, 1.0 is the orginial (no change) and
* above 2.0 starts to look unnatural*/
// calculate the scaling offset to apply to the red, green and blue colors
Single v;
if (percent > 0)
v = 1.0F + (0.015F * percent); // range from 1 (no change) to 2.5 (a lot of saturation)
else
v = 1.0F - (0.0075F * -percent); // range from 0.25 (almost grayscale) to 1 (no change)
Single red = (1.0F - v) * GRAYRED;
Single green = (1.0F - v) * GRAYGREEN;
Single blue = (1.0F - v) * GRAYBLUE;
// setup matrix
Single[][] matrix =
{
new Single[] {red + v, red, red, 0, 0},
new Single[] {green, green + v, green, 0, 0},
new Single[] {blue, blue, blue + v, 0, 0},
new Single[] {0, 0, 0, 1, 0},
new Single[] {0, 0, 0, 0, 1}
};
return matrix;
}
/// <summary>
/// Returns the matrix for grayscale
/// </summary>
/// <returns></returns>
public Single[][] GetGrayscaleMatrix() {
// set the luminosity of the colors using grayscale weighting
Single[][] matrix =
{
new Single[] {GRAYRED, GRAYRED, GRAYRED, 0, 0},
new Single[] {GRAYGREEN, GRAYGREEN, GRAYGREEN, 0, 0},
new Single[] {GRAYBLUE, GRAYBLUE, GRAYBLUE, 0, 0},
new Single[] {0, 0, 0, 1, 0},
new Single[] {0, 0, 0, 0, 1}
};
return matrix;
}
/// <summary>
/// Returns the matrix for sepia
/// </summary>
public Single[][] GetSepiaMatrix() {
/*sepia looks better if you first darken the image, the matrix values
* (combination of brightness and sepia) could be hard coded,
* but are left in code to make it easy to modify*/
Single[][] brightness = GetBrightnessMatrix(-25);
/*setup the matrix - sepia is grayscale with a slight offset in the red,
* green and blue colors*/
Single[][] sepia =
{
new Single[] {GRAYRED, GRAYRED, GRAYRED, 0, 0},
new Single[] {GRAYGREEN, GRAYGREEN, GRAYGREEN, 0, 0},
new Single[] {GRAYBLUE, GRAYBLUE, GRAYBLUE, 0, 0},
new Single[] {0, 0, 0, 1, 0},
new Single[] {SEPIARED, SEPIAGREEN, SEPIABLUE, 0, 1}
};
return sepia;
}
/// <summary>
/// Returns a combination of the tow specified matrices, while still maintaining the order information
/// </summary>
public Single[][] CombineMatrices(Single[][] m1, Single[][] m2) {
// create a new empty matrix
Single[][] matrix =
{
new Single[] {0, 0, 0, 0, 0},
new Single[] {0, 0, 0, 0, 0},
new Single[] {0, 0, 0, 0, 0},
new Single[] {0, 0, 0, 0, 0},
new Single[] {0, 0, 0, 0, 0}
};
// combine the two matrices
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
matrix[j][i] =
m1[j][0] * m2[0][i] +
m1[j][1] * m2[1][i] +
m1[j][2] * m2[2][i] +
m1[j][3] * m2[3][i] +
m1[j][4] * m2[4][i];
}
}
return matrix;
}
/// <summary>
/// Returns the gamma value for the specified percent value
/// </summary>
public Single GetGamma(int percent) {
// the gamma value can range from 0.1 (bright) to 5.0 (dark)
// we'll only allow the range of 0.15 to 3.5, since the other values don't make much sense
Single v;
if (percent > 0)
v = 1.0F - (0.0085F * percent); // range from 1.0 (no change) to 0.15 (brighter)
else
v = 1.0F + (0.025F * -percent); // range from 3.5 (darker) to 1.0 (no change)
return v;
}
private void DrawImage(Bitmap image, ImageAttributes attrib) {
// create the required graphics object from our image
Graphics g = Graphics.FromImage(image);
// draw the image using the specified attributes
Rectangle destRect = new Rectangle(0, 0, image.Width, image.Height);
g.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attrib);
// dispose the graphics object
g.Dispose();
}
/// <summary>
/// Draw an image using the specified matrix
/// </summary>
private void DrawImage(Bitmap image, Single[][] matrix) {
// create a new attributes class with the specified matrix
ColorMatrix cm = new ColorMatrix(matrix);
ImageAttributes attrib = new ImageAttributes();
attrib.SetColorMatrix(cm);
// draw the image and dispose the attrib object
DrawImage(image, attrib);
attrib.Dispose();
}
#endregion
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -