鱼遇于池,池涸,相濡以沫,相鞠以湿,不若相忘于海。

while (alive) {
  object state = working & fighting & enjoying & living thanksgiving;
}
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Watermark Maker Classes I: Brief Intro, WatermarkPosition

Posted on 2005-07-27 21:36  alittlefish  阅读(1205)  评论(3编辑  收藏  举报

水印的生成,起初我只是把它看成一个图片合成的简单过程,充其量也就是再加个追加文字。一开始,我写了一个demo,其实功能而言基本和后面重写的这个没有太大差异,但是因为目的性极强,完全忽略了代码上的可靠性,当时甚至更多的只是关注如何实现透明度的控制。

不过当功能的实现这个槛过了以后,我就反过来关注起给图片加水印的另外一些细节,比如水印的组成,位置等与水印本身同样重要的部分。

从选择水印图片、文字以及位置到最终生成,这个操作过程其实不过就是几次点击。而在生成水印图片之前,操作的部分没有严格的顺序,既不存在先选择位置,还是先选择水印内容的前后之分,代码的执行都在点击了“保存”以后才真正开始,因此,为了将水印相关的各个部分的耦合性降到最低,我作了以下考虑。

由于水印的部分可以是文字,可以是图片,不管怎么样,我们把它看做水印的CONTENT;另外,不管是什么类型的CONTENT,都有一个具体的位置信息。而我们在操作水印生成的过程的时候,选择位置和水印图片或文字的时候都是独立不相约束的,所以就有了最初的两个独立的对象:

    ·位置对象
    ·水印对象

1.位置
    原来我考虑的水印位置只有根据ContentAlignment定位以及平铺的形式,但是后来同事提了个建议说是否可以自己定义水印出现的位置,所以就有了AlignedPosition与CustomedPosition的两个WatermarkPosition的子类。



从上面的图可以看出,AlignedPosition有两个子类:SingleAlignedPosition、RepeatAlignedPosition。这两个类就是之前我提到的以ContentAlignment定位的和以平铺形式分布的水印位置对象。

另外,由于平铺的水印的位置不止一个,所以这里引入了一个IMultiPosition。

代码:

WatermarkPosition.cs
1public 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
 1public abstract class AlignedPosition : WatermarkPosition
 2{
 3    protected float _offsetX;
 4    protected float _offsetY;
 5
 6    #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
 1public class SingleAlignedPosition : AlignedPosition
 2{
 3    private ContentAlignment _alignment;
 4
 5    #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
 1public class RepeatAlignedPosition : AlignedPosition, IMultiPosition
 2{
 3    private float _currentX = 0.0f;
 4    private float _currentY = 0.0f;
 5    private bool _moveFlag = true;
 6
 7    #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    #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
 1public class CustomedPosition : WatermarkPosition
 2{
 3    #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}

下篇:水印类