C#水印图片的生成 - 教你如何用C#程序生成水印图片
2009-12-01 00:09
471 查看
Watermark Maker Classes I: Brief Intro, WatermarkP
水印的生成,起初我只是把它看成一个图片合成的简单过程,充其量也就是再加个追加文字。一开始,我写了一个demo,其实功能而言基本和后面重写的这个没有太大差异,但是因为目的性极强,完全忽略了代码上的可靠性,当时甚至更多的只是关注如何实现透明度的控制。
不过当功能的实现这个槛过了以后,我就反过来关注起给图片加水印的另外一些细节,比如水印的组成,位置等与水印本身同样重要的部分。
从选择水印图片、文字以及位置到最终生成,这个操作过程其实不过就是几次点击。而在生成水印图片之前,操作的部分没有严格的顺序,既不存在先选择位置,还是先选择水印内容的前后之分,代码的执行都在点击了“保存”以后才真正开始,因此,为了将水印相关的各个部分的耦合性降到最低,我作了以下考虑。
由于水印的部分可以是文字,可以是图片,不管怎么样,我们把它看做水印的CONTENT;另外,不管是什么类型的CONTENT,都有一个具体的位置信息。而我们在操作水印生成的过程的时候,选择位置和水印图片或文字的时候都是独立不相约束的,所以就有了最初的两个独立的对象:
·位置对象
·水印对象
1.位置
原来我考虑的水印位置只有根据ContentAlignment定位以及平铺的形式,但是后来同事提了个建议说是否可以自己定义水印出现的位置,所以就有了AlignedPosition与CustomedPosition的两个WatermarkPosition的子类。
从上面的图可以看出,AlignedPosition有两个子类:SingleAlignedPosition、RepeatAlignedPosition。这两个类就是之前我提到的以ContentAlignment定位的和以平铺形式分布的水印位置对象。
另外,由于平铺的水印的位置不止一个,所以这里引入了一个IMultiPosition。
代码:
WatermarkPosition.cs
复制C#代码保存代码
AlignedPosition.cs
复制C#代码保存代码
SingleAlignedPosition.cs
复制C#代码保存代码
RepeatAlignedPosition.cs
复制C#代码保存代码
CustomedPosition.cs
复制C#代码保存代码
2.水印
前文讲了水印位置的基本思路以及代码,接下来就是水印的实体类了。前面讲了我把水印的组成分为水印位置与水印内容两个对象,但是,实现的时候,界限就不是那么明显。
我提供了一个Watermark的实体类,而它只是作为一个抽象的实体,由于水印包括了图片与文字两种形式,所以由此类衍生出ImageWatermark与TextWatermark两个子类。由这两个类来实现具体的水印内容的区分。
ImageWatermark拥有一个内嵌类(Nested Class)ImageProperties,表示水印的图片信息。
TextWatermark拥有一个内嵌类TextProperties,表示水印文字的属性。
Watermark对象提供了对这两个具体的水印内容的聚合。
这里有个问题,是把水印内容建一个抽象类,然后衍生不同的水印内容(图片、文字)好呢,还是以我这样的设计好。我个人觉得,我这么做是为了从水印(Watermark)的角度去区别对象——即可以直接从ImageWatermark和TextWatermark来区分是何种水印方式,而不是再从其内容来区分。这个对后面的水印生成类的定义应该是有帮助的。
另外,Watermark也提供了对之前的Position的聚合
水印的生成,起初我只是把它看成一个图片合成的简单过程,充其量也就是再加个追加文字。一开始,我写了一个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的聚合
相关文章推荐
- 一个c#上传的程序,可以生成缩略图也可以自由添加水印效果
- [原创]超强C#图片上传,加水印,自动生成缩略图源代码
- 使用ASP.net(C#)批量上传图片并自动生成缩略图,文字水印图,图片水印图
- 一个c#上传的程序,可以生成缩略图也可以自由添加水印效果
- c# 添加图片水印,可以指定水印位置+生成缩略图
- 使用ASP.net(C#)批量上传图片并自动生成缩略图,文字水印图,图片水印图
- C#的图片处理类,加水印及生成缩略图
- 一个c#上传的程序,可以生成缩略图也可以自由添加水印效果
- c# 添加图片水印,可以指定水印位置+生成缩略图
- c# 添加图片水印,可以指定水印位置+生成缩略图
- 图片 缩略 和 水印 以及 C#获取当前程序运行路径的方法集合
- C#如何实现图片的随机生成与显示(转载)
- 向Word中插入图片,C#编写的生成缩略图程序
- 使用ASP.net(C#)批量上传图片并自动生成缩略图,文字水印图,图片水印图
- c# 添加图片水印,可以指定水印位置+生成缩略图
- C#如何生成release版本的程序,生成debug版本的程序
- C#(.net)水印图片的生成
- c# 添加图片水印,可以指定水印位置+生成缩略图
- .net c# gif动画如何添加图片水印实现思路及代码
- .net c# gif动画如何添加图片水印