📄 effect.extend.cs
字号:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
namespace PhotoSprite.ImageProcessing
{
partial class Effect
{
/************************************************************
*
* 剪纸、铅笔画、素描、连环画
* 碧绿、棕褐、渲染
* 冰冻、熔铸
* 暗调、对调、怪调
*
************************************************************/
/// <summary>
/// 剪纸
/// </summary>
/// <param name="b">位图流</param>
/// <param name="threshold">阈值[0, 255]</param>
/// <param name="bgColor">背景色</param>
/// <param name="fgColor">前景色</param>
/// <returns></returns>
public Bitmap PaperCut(Bitmap b, byte threshold, Color bgColor, Color fgColor)
{
GrayProcessing gp = new GrayProcessing();
// 对图像按指定阈值进行二值化
byte[,] GrayArray = gp.BinaryArray(b, threshold);
// 对图像进行上色
return gp.BinaryImage(GrayArray, bgColor, fgColor);
} // end of PaperCut
/// <summary>
/// 铅笔画
/// </summary>
/// <param name="b">位图流</param>
/// <param name="threshold">颜色阈值[0, 100]</param>
/// <returns></returns>
public Bitmap Pencil(Bitmap b, int threshold)
{
if (threshold < 0) threshold = 0;
if (threshold > 100) threshold = 100;
int width = b.Width;
int height = b.Height;
Bitmap dstImage = new Bitmap(width, height);
BitmapData srcData = b.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
BitmapData dstData = dstImage.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
// 图像实际处理区域
// 图像最外围一圈不处理
int rectTop = 1;
int rectBottom = height - 1;
int rectLeft = 1;
int rectRight = width - 1;
unsafe
{
byte* src = (byte*)srcData.Scan0;
byte* dst = (byte*)dstData.Scan0;
int stride = srcData.Stride;
int offset = stride - width * BPP;
// 源图像周围八点指针
byte* nw; byte* n; byte* ne;
byte* w; byte* e;
byte* sw; byte* s; byte* se;
int R, G, B;
// 移向第一行
src += stride;
dst += stride;
for (int y = rectTop; y < rectBottom; y++)
{
// 移向每行第 1 列
src += BPP;
dst += BPP;
for (int x = rectLeft; x < rectRight; x++)
{
// 取周围八个点的颜色值
nw = src - stride - BPP; // (x-1, y-1)
n = src - stride; // (x , y-1)
ne = src - stride + BPP; // (x+1, y-1)
w = src - BPP; // (x-1, y)
e = src + BPP; // (x+1, y)
sw = src + stride - BPP; // (x-1, y+1)
s = src + stride; // (x , y+1)
se = src + stride + BPP; // (x+1, y+1)
// 计算当前像素点与周围八点平均值的差
R = nw[2] + n[2] + ne[2] + w[2] + e[2] + sw[2] + s[2] + se[2];
R = src[2] - R / 8;
G = nw[1] + n[1] + ne[1] + w[1] + e[1] + sw[1] + s[1] + se[1];
G = src[1] - G / 8;
B = nw[0] + n[0] + ne[0] + w[0] + e[0] + sw[0] + s[0] + se[0];
B = src[0] - B / 8;
// 取差值的绝对值
if (R < 0) R = -R;
if (G < 0) G = -G;
if (B < 0) B = -B;
// 如果差值大于指定阈值,则在当前位置描点
if (R >= threshold || G >= threshold || B >= threshold)
{
dst[0] = dst[1] = dst[2] = 0;
}
else
{
dst[0] = dst[1] = dst[2] = 255;
}
dst[3] = src[3]; // A
// 向后移一像素
src += BPP;
dst += BPP;
} // x
// 移向下一行
// 这里得注意要多移 1 列,因最右列不必处理
src += offset + BPP;
dst += offset + BPP;
} // y
}
b.UnlockBits(srcData);
dstImage.UnlockBits(dstData);
b.Dispose();
return dstImage;
} // end of Pencil
/// <summary>
/// 素描
/// </summary>
/// <param name="b">位图流</param>
/// <param name="threshold">颜色阈值[0, 100]</param>
/// <returns></returns>
public Bitmap Sketch(Bitmap b, int threshold)
{
if (threshold < 0) threshold = 0;
if (threshold > 100) threshold = 100;
// 先求灰度
GrayProcessing gp = new GrayProcessing();
b = gp.Gray(b, GrayProcessing.GrayMethod.WeightAveraging);
int width = b.Width;
int height = b.Height;
BitmapData srcData = b.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
// 图像实际处理区域
int rectTop = 0;
int rectBottom = height - 1;
int rectLeft = 0;
int rectRight = width - 1;
unsafe
{
byte* dst = (byte*)srcData.Scan0;
// 取当前像素点右下角像素
byte* src = dst + srcData.Stride + BPP;
int offset = srcData.Stride - width * BPP;
int diff;
for (int y = rectTop; y < rectBottom; y++)
{
for (int x = rectLeft; x < rectRight; x++)
{
// 计算相邻两点的灰度差
diff = dst[0] - src[0];
if (diff < 0)
diff = -diff;
// 如果灰度差大于指定阈值,则颜色跳变严重,需描下轮廓,
// 即把该点置为黑色,否则置为白色
if (diff >= threshold)
dst[0] = dst[1] = dst[2] = 0;
else
dst[0] = dst[1] = dst[2] = 255;
// 向后移一像素
src += BPP;
dst += BPP;
} // x
// 移向下一行
// 这里得注意要多移 1 列,因最右列不必处理
src += offset + BPP;
dst += offset + BPP;
} // y
}
b.UnlockBits(srcData);
return b;
} // end of Sketch
/// <summary>
/// 连环画
/// </summary>
/// <param name="b">位图流</param>
/// <returns></returns>
public Bitmap Comic(Bitmap b)
{
int width = b.Width;
int height = b.Height;
BitmapData data = b.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
byte* p = (byte*)data.Scan0;
int offset = data.Stride - width * BPP;
int R, G, B, pixel;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
R = p[2];
G = p[1];
B = p[0];
// R = |g – b + g + r| * r / 256;
pixel = G - B + G + R;
if (pixel < 0) pixel = -pixel;
pixel = pixel * R / 256;
if (pixel > 255) pixel = 255;
p[2] = (byte)pixel;
// G = |b – g + b + r| * r / 256;
pixel = B - G + B + R;
if (pixel < 0) pixel = -pixel;
pixel = pixel * R / 256;
if (pixel > 255) pixel = 255;
p[1] = (byte)pixel;
// B = |b – g + b + r| * g / 256;
pixel = B - G + B + R;
if (pixel < 0) pixel = -pixel;
pixel = pixel * G / 256;
if (pixel > 255) pixel = 255;
p[0] = (byte)pixel;
p += BPP;
} // x
p += offset;
} // y
}
b.UnlockBits(data);
// 对图像进行灰度化
GrayProcessing gp = new GrayProcessing();
return gp.Gray(b, GrayProcessing.GrayMethod.WeightAveraging);
} // end of Comic
/// <summary>
/// 碧绿
/// </summary>
/// <param name="b">位图流</param>
/// <returns></returns>
public Bitmap Aqua(Bitmap b)
{
int width = b.Width;
int height = b.Height;
BitmapData data = b.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
byte* p = (byte*)data.Scan0;
int offset = data.Stride - width * BPP;
int R, G, B, pixel;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// R = (g - b) * (g - b) / 128;
// G = (r - b) * (r - b) / 128;
// B = (r - g) * (r - g) / 128;
R = p[2];
G = p[1];
B = p[0];
pixel = (G - B) * (G - B) / 128;
if (pixel > 255) pixel = 255;
p[2] = (byte)pixel;
pixel = (R - B) * (R - B) / 128;
if (pixel > 255) pixel = 255;
p[1] = (byte)pixel;
pixel = (R - G) * (R - G) / 128;
if (pixel > 255) pixel = 255;
p[0] = (byte)pixel;
p += BPP;
} // x
p += offset;
} // y
}
b.UnlockBits(data);
return b;
} // end of Aqua
/// <summary>
/// 棕褐色、旧相片
/// </summary>
/// <param name="b">位图流</param>
/// <returns></returns>
public Bitmap Sepia(Bitmap b)
{
int width = b.Width;
int height = b.Height;
BitmapData data = b.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
byte* p = (byte*)data.Scan0;
int offset = data.Stride - width * BPP;
int R, G, B;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// R = 0.393 * r + 0.769 * g + 0.189 * b;
// G = 0.349 * r + 0.686 * g + 0.168 * b;
// B = 0.272 * r + 0.534 * g + 0.131 * b;
R = (25756 * p[2] + 50397 * p[1] + 12386 * p[0]) >> 16;
G = (22872 * p[2] + 44958 * p[1] + 11010 * p[0]) >> 16;
B = (17826 * p[2] + 34996 * p[1] + 8585 * p[0]) >> 16;
if (R < 0) R = 0;
if (R > 255) R = 255;
if (G < 0) G = 0;
if (G > 255) G = 255;
if (B < 0) B = 0;
if (B > 255) B = 255;
p[2] = (byte)R;
p[1] = (byte)G;
p[0] = (byte)B;
p += BPP;
} // x
p += offset;
} // y
}
b.UnlockBits(data);
return b;
} // end of Sepia
/// <summary>
/// 颜色渲染
/// </summary>
/// <param name="b">位图流</param>
/// <param name="red">红色分量[0, 255]</param>
/// <param name="green">绿色分量[0, 255]</param>
/// <param name="blue">蓝色分量[0, 255]</param>
/// <returns></returns>
public Bitmap Colorize(Bitmap b, int red, int green, int blue)
{
if (red < 0) red = 0;
if (red > 255) red = 255;
if (green < 0) green = 0;
if (green > 255) green = 255;
if (blue < 0) blue = 0;
if (blue > 255) blue = 255;
// 灰度化
GrayProcessing gp = new GrayProcessing();
b = gp.Gray(b, GrayProcessing.GrayMethod.WeightAveraging);
int width = b.Width;
int height = b.Height;
BitmapData data = b.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
byte* p = (byte*)data.Scan0;
int offset = data.Stride - width * BPP;
int R, G, B;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
R = p[2] * red / 255;
G = p[1] * green / 255;
B = p[0] * blue / 255;
p[2] = (byte)R;
p[1] = (byte)G;
p[0] = (byte)B;
p += BPP;
} // x
p += offset;
} // y
}
b.UnlockBits(data);
return b;
} // end of Colorize
/// <summary>
/// 冰冻
/// </summary>
/// <param name="b">位图流</param>
/// <returns></returns>
public Bitmap Ice(Bitmap b)
{
int width = b.Width;
int height = b.Height;
BitmapData data = b.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
byte* p = (byte*)data.Scan0;
int offset = data.Stride - width * BPP;
int R, G, B, pixel;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
R = p[2];
G = p[1];
B = p[0];
// R = |r - g - b| * 3 / 2;
pixel = R - G - B;
pixel = pixel * 3 / 2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -