水印的生成,起初我只是把它看成一个图片合成的简单过程,充其量也就是再加个追加文字。一开始,我写了一个demo,其实功能而言基本和后面重写的这个没有太大差异,但是因为目的性极强,完全忽略了代码上的可靠性,当时甚至更多的只是关注如何实现透明度的控制。
不过当功能的实现这个槛过了以后,我就反过来关注起给图片加水印的另外一些细节,比如水印的组成,位置等与水印本身同样重要的部分。
从选择水印图片、文字以及位置到最终生成,这个操作过程其实不过就是几次点击。而在生成水印图片之前,操作的部分没有严格的顺序,既不存在先选择位置,还是先选择水印内容的前后之分,代码的执行都在点击了“保存”以后才真正开始,因此,为了将水印相关的各个部分的耦合性降到最低,我作了以下考虑。
由于水印的部分可以是文字,可以是图片,不管怎么样,我们把它看做水印的CONTENT;另外,不管是什么类型的CONTENT,都有一个具体的位置信息。而我们在操作水印生成的过程的时候,选择位置和水印图片或文字的时候都是独立不相约束的,所以就有了最初的两个独立的对象:
·位置对象
·水印对象
1.位置
原来我考虑的水印位置只有根据ContentAlignment定位以及平铺的形式,但是后来同事提了个建议说是否可以自己定义水印出现的位置,所以就有了AlignedPosition与CustomedPosition的两个WatermarkPosition的子类。
从上面的图可以看出,AlignedPosition有两个子类:SingleAlignedPosition、RepeatAlignedPosition。这两个类就是之前我提到的以ContentAlignment定位的和以平铺形式分布的水印位置对象。
另外,由于平铺的水印的位置不止一个,所以这里引入了一个IMultiPosition。
代码:
WatermarkPosition.cs
1
public abstract class WatermarkPosition
2![]()
![]()
{
3
protected float _x;
4
protected float _y;
5
6
public abstract RectangleF GetPosition(Size imageSize, Size watermarkSize);
7
} AlignedPosition.cs
1
public abstract class AlignedPosition : WatermarkPosition
2![]()
![]()
{
3
protected float _offsetX;
4
protected float _offsetY;
5
6![]()
Cstr#region Cstr
7
public AlignedPosition()
8![]()
{
9
this._offsetX = -1.0f;
10
this._offsetY = -1.0f;
11
}
12
#endregion
13
14
public override RectangleF GetPosition(Size imageSize, Size watermarkSize)
15![]()
{
16
if (this._offsetX == -1.0f && this._offsetY == -1.0f)
17![]()
{
18
float tWidht = (float)imageSize.Width;
19
float tHeight = (float)imageSize.Height;
20
21
this._offsetX = tWidht * 0.05f;
22
this._offsetY = tHeight * 0.05f;
23
}
24
25
return this.GetRectangle(imageSize, watermarkSize);
26
}
27
28
protected abstract RectangleF GetRectangle(Size imageSize, Size watermarkSize);
29
} SingleAlignedPosition.cs
1
public class SingleAlignedPosition : AlignedPosition
2![]()
![]()
{
3
private ContentAlignment _alignment;
4
5![]()
Cstr#region Cstr
6
public SingleAlignedPosition() : base()
7![]()
{
8
this._alignment = ContentAlignment.TopLeft;
9
}
10
11
public SingleAlignedPosition(ContentAlignment alignment) : base()
12![]()
{
13
this._alignment = alignment;
14
}
15
16
public SingleAlignedPosition(ContentAlignment alignment, int offset)
17![]()
{
18
this._alignment = alignment;
19
20
this._offsetX = (float)offset;
21
this._offsetY = (float)offset;
22
}
23
#endregion
24
25
protected override RectangleF GetRectangle(Size imageSize, Size watermarkSize)
26![]()
{
27
float x, y;
28
29
float tWidth = (float)imageSize.Width;
30
float tHeight = (float)imageSize.Height;
31
float width = (float)watermarkSize.Width;
32
float height = (float)watermarkSize.Height;
33
34
switch(this._alignment)
35![]()
{
36
case ContentAlignment.TopLeft: // 左上
37
x = this._offsetX;
38
y = this._offsetY;
39
break;
40
case ContentAlignment.TopCenter: // 上中
41
x = (tWidth - width)/2;
42
y = this._offsetY;
43
break;
44
case ContentAlignment.TopRight: // 右上
45
x = tWidth - width - this._offsetX;
46
y = this._offsetY;
47
break;
48
case ContentAlignment.MiddleLeft: // 左中:
49
x = this._offsetX;
50
y = (tHeight - tHeight)/2;
51
break;
52
case ContentAlignment.MiddleCenter: // 正中央
53
x = (tWidth - width)/2;
54
y = (tHeight - height)/2;
55
break;
56
case ContentAlignment.MiddleRight: // 右中
57
x = tWidth - width - this._offsetX;
58
y = (tHeight - height)/2;
59
break;
60
case ContentAlignment.BottomLeft: // 左下
61
x = this._offsetX;
62
y = tHeight - height - this._offsetY;
63
break;
64
case ContentAlignment.BottomCenter: // 左中
65
x = (imageSize.Width - width)/2;
66
y = tHeight - height - this._offsetY;
67
break;
68
default: // 默认右下
69
x = tWidth - width - this._offsetX;
70
y = tHeight - height - this._offsetY;
71
break;
72
}
73
74
return new RectangleF(x, y, width, height);
75
}
76
} RepeatAlignedPosition.cs
1
public class RepeatAlignedPosition : AlignedPosition, IMultiPosition
2![]()
![]()
{
3
private float _currentX = 0.0f;
4
private float _currentY = 0.0f;
5
private bool _moveFlag = true;
6
7![]()
Cstr#region Cstr
8
public RepeatAlignedPosition() : base()
9![]()
{
10
}
11
12
public RepeatAlignedPosition(int offset)
13![]()
{
14
this._offsetX = offset;
15
this._offsetY = offset;
16
}
17
#endregion
18
19
protected override RectangleF GetRectangle(Size imageSize, Size watermarkSize)
20![]()
{
21
if (!this._moveFlag)
22![]()
{
23
throw new InvalidOperationException("请确认所有位置是否都已输出,否则必须调用MoveNext才能取得位置对象");
24
}
25
else
26![]()
{
27
this._currentX += this._offsetX;
28
this._currentY += this._offsetY;
29
30
this._moveFlag = false;
31
32
return new RectangleF(this._currentX, this._currentY, (float)watermarkSize.Width, (float)watermarkSize.Height);
33
34
//this.MoveNext(imageSize, watermarkSize);
35
}
36
}
37
38![]()
IMultiPosition 成员#region IMultiPosition 成员
39
RectangleF[] Jingstudio.WatermarkMaker.Watermark.IMultiPosition.GetPositions(Size imageSize, Size watermarkSize)
40![]()
{
41
float tWidth = (float)imageSize.Width;
42
float tHeight = (float)imageSize.Height;
43
float width = (float)watermarkSize.Width;
44
float height = (float)watermarkSize.Height;
45
46
int x = (int)Math.Ceiling(tWidth / (width + this._offsetX));
47
int y = (int)Math.Ceiling(tHeight / (height + this._offsetY));
48
49
RectangleF[] positions = new RectangleF[x*y];
50
51
int index = 0;
52
for (int i=0; i<x; i++)
53![]()
{
54
for (int j=0; j<y; j++)
55![]()
{
56
PointF p = new PointF( (float)i * (width + this._offsetX), (float)j * (height + this._offsetY) );
57
positions[index] = new RectangleF(p, watermarkSize);
58
index ++;
59
}
60
}
61
62
return positions;
63
}
64
65
public bool MoveNext(Size imageSize, Size watermarkSize)
66![]()
{
67
float tWidth = (float)imageSize.Width;
68
float tHeight = (float)imageSize.Height;
69
float width = (float)watermarkSize.Width;
70
float height = (float)watermarkSize.Height;
71
float x, y;
72
x = 0; y = 0;
73
74
x = this._currentX + this._offsetX + width;
75
76
if (x >= tWidth)
77![]()
{
78
x = this._offsetX;
79
y = this._currentY + this._offsetY + height;
80
}
81
82
if (y >= tHeight)
83![]()
{
84
return false;
85
}
86
else
87![]()
{
88
this._currentX = x;
89
this._currentY = y;
90
this._moveFlag = true;
91
return true;
92
}
93
}
94
#endregion
95
} CustomedPosition.cs
1
public class CustomedPosition : WatermarkPosition
2![]()
![]()
{
3![]()
Cstr#region Cstr
4
public CustomedPosition()
5![]()
{
6
this._x = -1;
7
this._y = -1;
8
}
9
10
public CustomedPosition(PointF point)
11![]()
{
12
this._x = point.X;
13
this._y = point.Y;
14
}
15
#endregion
16
17
public override RectangleF GetPosition(Size imageSize, Size watermarkSize)
18![]()
{
19
float width = (float)watermarkSize.Width;
20
float height = (float)watermarkSize.Height;
21
22
if (this._x == -1 && this._y == -1)
23![]()
{
24
float tWidth = (float)imageSize.Width;
25
float tHeight = (float)imageSize.Height;
26
27
this._x = (tWidth - width)/2;
28
this._y = (tHeight - height)/2;
29
}
30
31
return new RectangleF (this._x, this._y, width, height);
32
}
33
} 下篇:
水印类