C#水印生成

水印的生成,起初我只是把它看成一个图片合成的简单过程,充其量也就是再加个追加文字。一开始,我写了一个demo,其实功能而言基本和后面重写的这个没有太大差异,但是因为目的性极强,完全忽略了代码上的可靠性,当时甚至更多的只是关注如何实现透明度的控制。   不过当功能的实现这个槛过了以后,我就反过来关注起给图片加水印的另外一些细节,比如水印的组成,位置等与水印本身同样重要的部分。   从选择水印图片、文字以及位置到最终生成,这个操作过程其实不过就是几次点击。而在生成水印图片之前,操作的部分没有严格的顺序,既不存在先选择位置,还是先选择水印内容的前后之分,代码的执行都在点击了“保存”以后才真正开始,因此,为了将水印相关的各个部分的耦合性降到最低,我作了以下考虑。   由于水印的部分可以是文字,可以是图片,不管怎么样,我们把它看做水印的CONTENT;另外,不管是什么类型的CONTENT,都有一个具体的位置信息。而我们在操作水印生成的过程的时候,选择位置和水印图片或文字的时候都是独立不相约束的,所以就有了最初的两个独立的对象:   ·位置对象 ·水印对象    1.位置         原来我考虑的水印位置只有根据ContentAlignment定位以及平铺的形式,但是后来同事提了个建议说是否可以自己定义水印出现的位置,所以就有了AlignedPosition与CustomedPosition的两个WatermarkPosition的子类。   从上面的图可以看出,AlignedPosition有两个子类:SingleAlignedPosition、RepeatAlignedPosition。这两个类就是之前我提到的以ContentAlignment定位的和以平铺形式分布的水印位置对象。   另外,由于平铺的水印的位置不止一个,所以这里引入了一个IMultiPosition。   代码:   WatermarkPosition.cs  
复制C#代码保存代码
public abstract class WatermarkPosition
{
    protected float _x;
    protected float _y;

    public abstract RectangleF GetPosition(Size imageSize, Size watermarkSize);
}
AlignedPosition.cs  
复制C#代码保存代码
public abstract class AlignedPosition : WatermarkPosition 
{ 
    protected float _offsetX; 
    protected float _offsetY; 
 
    #region Cstr 
    public AlignedPosition() 
     { 
        this._offsetX = -1.0f; 
        this._offsetY = -1.0f; 
     } 
     #endregion 
 
    public override RectangleF GetPosition(Size imageSize, Size watermarkSize) 
     { 
        if (this._offsetX == -1.0f && this._offsetY == -1.0f) 
         { 
            float tWidht = (float)imageSize.Width; 
            float tHeight = (float)imageSize.Height; 
 
            this._offsetX = tWidht * 0.05f; 
            this._offsetY = tHeight * 0.05f; 
         } 
 
        return this.GetRectangle(imageSize, watermarkSize); 
     } 
 
    protected abstract RectangleF GetRectangle(Size imageSize, Size watermarkSize); 
}
SingleAlignedPosition.cs  
复制C#代码保存代码
public class SingleAlignedPosition : AlignedPosition
{
    private ContentAlignment _alignment;

     #region Cstr
    public SingleAlignedPosition()
         : base()
     {
        this._alignment = ContentAlignment.TopLeft;
     }

    public SingleAlignedPosition(ContentAlignment alignment)
         : base()
     {
        this._alignment = alignment;
     }

    public SingleAlignedPosition(ContentAlignment alignment, int offset)
     {
        this._alignment = alignment;

        this._offsetX = (float) offset;
        this._offsetY = (float) offset;
     }
     #endregion

    protected override RectangleF GetRectangle(Size imageSize, Size watermarkSize)
     {
        float x, y;

        float tWidth = (float) imageSize.Width;
        float tHeight = (float) imageSize.Height;
        float width = (float) watermarkSize.Width;
        float height = (float) watermarkSize.Height;

        switch (this._alignment)
         {
        case ContentAlignment.TopLeft:         // 左上 
             x = this._offsetX;
             y = this._offsetY;
            break;
        case ContentAlignment.TopCenter:     // 上中 
             x = (tWidth - width) / 2;
             y = this._offsetY;
            break;
        case ContentAlignment.TopRight:         // 右上 
             x = tWidth - width - this._offsetX;
             y = this._offsetY;
            break;
        case ContentAlignment.MiddleLeft:     // 左中: 
             x = this._offsetX;
             y = (tHeight - tHeight) / 2;
            break;
        case ContentAlignment.MiddleCenter:     // 正中央 
             x = (tWidth - width) / 2;
             y = (tHeight - height) / 2;
            break;
        case ContentAlignment.MiddleRight:     // 右中 
             x = tWidth - width - this._offsetX;
             y = (tHeight - height) / 2;
            break;
        case ContentAlignment.BottomLeft:     // 左下 
             x = this._offsetX;
             y = tHeight - height - this._offsetY;
            break;
        case ContentAlignment.BottomCenter:     // 左中 
             x = (imageSize.Width - width) / 2;
             y = tHeight - height - this._offsetY;
            break;
        default:     // 默认右下 
             x = tWidth - width - this._offsetX;
             y = tHeight - height - this._offsetY;
            break;
         }

        return new RectangleF(x, y, width, height);
     }
}
RepeatAlignedPosition.cs  
复制C#代码保存代码
public class RepeatAlignedPosition : AlignedPosition, IMultiPosition
{
    private float _currentX = 0.0f;
    private float _currentY = 0.0f;
    private bool _moveFlag = true;

     #region Cstr
    public RepeatAlignedPosition()
         : base()
     {
     }

    public RepeatAlignedPosition(int offset)
     {
        this._offsetX = offset;
        this._offsetY = offset;
     }
     #endregion

    protected override RectangleF GetRectangle(Size imageSize, Size watermarkSize)
     {
        if (!this._moveFlag)
         {
            throw new InvalidOperationException("请确认所有位置是否都已输出,否则必须调用MoveNext才能取得位置对象");
         }
        else
         {
            this._currentX += this._offsetX;
            this._currentY += this._offsetY;

            this._moveFlag = false;

            return new RectangleF(this._currentX, this._currentY, (float) watermarkSize.Width, (float) watermarkSize.Height);

            //this.MoveNext(imageSize, watermarkSize); 
         }
     }

     #region IMultiPosition 成员
     RectangleF[] Jingstudio.WatermarkMaker.Watermark.IMultiPosition.GetPositions(Size imageSize, Size watermarkSize)
     {
        float tWidth = (float) imageSize.Width;
        float tHeight = (float) imageSize.Height;
        float width = (float) watermarkSize.Width;
        float height = (float) watermarkSize.Height;

        int x = (int) Math.Ceiling(tWidth / (width + this._offsetX));
        int y = (int) Math.Ceiling(tHeight / (height + this._offsetY));

         RectangleF[] positions = new RectangleF[x * y];

        int index = 0;
        for (int i = 0; i < x; i++)
         {
            for (int j = 0; j < y; j++)
             {
                 PointF p = new PointF((float) i * (width + this._offsetX), (float) j * (height + this._offsetY));
                 positions[index] = new RectangleF(p, watermarkSize);
                 index++;
             }
         }

        return positions;
     }

    public bool MoveNext(Size imageSize, Size watermarkSize)
     {
        float tWidth = (float) imageSize.Width;
        float tHeight = (float) imageSize.Height;
        float width = (float) watermarkSize.Width;
        float height = (float) watermarkSize.Height;
        float x, y;
         x = 0;
         y = 0;

         x = this._currentX + this._offsetX + width;

        if (x >= tWidth)
         {
             x = this._offsetX;
             y = this._currentY + this._offsetY + height;
         }

        if (y >= tHeight)
         {
            return false;
         }
        else
         {
            this._currentX = x;
            this._currentY = y;
            this._moveFlag = true;
            return true;
         }
     }
     #endregion
}
CustomedPosition.cs  
复制C#代码保存代码
public class CustomedPosition : WatermarkPosition 
{ 
      #region Cstr 
    public CustomedPosition() 
     { 
        this._x = -1; 
        this._y = -1; 
     } 
 
    public CustomedPosition(PointF point) 
     { 
        this._x = point.X; 
        this._y = point.Y; 
     } 
     #endregion 
 
    public override RectangleF GetPosition(Size imageSize, Size watermarkSize) 
     { 
        float width = (float)watermarkSize.Width; 
        float height = (float)watermarkSize.Height; 
 
        if (this._x == -1 && this._y == -1) 
         { 
            float tWidth = (float)imageSize.Width; 
            float tHeight = (float)imageSize.Height; 
 
            this._x = (tWidth - width)/2; 
            this._y = (tHeight - height)/2; 
         } 
 
        return new RectangleF (this._x, this._y, width, height); 
     } 
}
2.水印 前文讲了水印位置的基本思路以及代码,接下来就是水印的实体类了。前面讲了我把水印的组成分为水印位置与水印内容两个对象,但是,实现的时候,界限就不是那么明显。 我提供了一个Watermark的实体类,而它只是作为一个抽象的实体,由于水印包括了图片与文字两种形式,所以由此类衍生出ImageWatermark与TextWatermark两个子类。由这两个类来实现具体的水印内容的区分。  ImageWatermark拥有一个内嵌类(Nested Class)ImageProperties,表示水印的图片信息。 TextWatermark拥有一个内嵌类TextProperties,表示水印文字的属性。 Watermark对象提供了对这两个具体的水印内容的聚合。 这里有个问题,是把水印内容建一个抽象类,然后衍生不同的水印内容(图片、文字)好呢,还是以我这样的设计好。我个人觉得,我这么做是为了从水印(Watermark)的角度去区别对象——即可以直接从ImageWatermark和TextWatermark来区分是何种水印方式,而不是再从其内容来区分。这个对后面的水印生成类的定义应该是有帮助的。 另外,Watermark也提供了对之前的Position的聚合
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值