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

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

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

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

    ·位置对象 
    ·水印对象 

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

继续讲讲我的水印制作工具的思路_Math

从上面的图可以看出,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    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 

1public 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 

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    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 

1public 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}