通通WPF随笔(3)——艺术二维码素材生成器
最近公司让我开发一个条形码的生成控件,花了半天时间搞定觉得不过瘾,什么年代了该用二维码了吧。于是wiki了一下二维码的资料。
比较常见的就是QR码(Quick Response)即快速识别码,为了验证“快速”,我特地和条形码做了一次比较:经过我测试条形码的code 128编码方式可以表示数字、字母、和符号,而且长度也可以很长。当我用“我查查”进行识别测试时发现,当长度达到20个字符时就很难识别出来了,速度也比较慢,也许是软件的原因吧。但二维码不同,其中包括了汉字等乱七八糟的一大堆东西,同样可以秒识。
看了各种外国设计师的艺术二维码设计让我一发不可收拾。先来欣赏一下国外大师的设计吧:







这里选了几张个人比较喜欢,比较有代表性的。
1.总体思路
这是一张普通的二维码:

我们可以把它看作由很多
正方形组成的矩阵,每一个正方形就是矩阵中的一个节点。那3个大方框和右下角的小方框是用来定位二维码的方向位置的。
先排除颜色贴图不管,那些艺术二维码的区别无非就是节点的形状不同而已,有方的、圆的、还有在方的边缘做了平滑处理的。如果能用这些节点生成最基本的黑白原型,用PS加上颜色和贴图简直就是轻而易举。所以我做了这个一个快速原型工具,如下图:

通过修改左边的参数就可以实现各种效果:
改变节点大小

使用随机节点大小和随机颜色

圆形节点

圆形随机大小、随机颜色

自定义形状节点

生成各种素材,经过PS的拼装处理,基本可以实现任何效果了。
(有些比较难识别,是因为比较难找到作为位置定位的那几个方框,所以还得PS处理时,要把那几个方框做得明显些)
关于方形边缘平滑处理效果,由于用PS比较容易实现,就懒得研究代码了,录制个PS动作更快些。如下:

这个是女朋友生日那天临时设计的。
2.详细设计
关于二维码的生成这里我用了一个开源项目QrCode.Net(http://qrcodenet.codeplex.com/)其实这个工程里面已经自带了WPF的控件,可以生成最基本的正方形节点二维码,且有一个属性是Path的材质,这样生成普通的二维码已经方便了,但是不能满足我们多样化的需求。
所以,我只用到了他生成一个二维数组来表示二维码的算法,二维数组的元素只有0和1,其中0表示没有黑块,1表示有,这样只要根据自定义路径的大小计算出每个块的位置,用代码布局一下就出来了。
我自己写了一个可以用任意形状路径填充节点的类,并增加随机节点大小和随机颜色功能,而且修复了它的一些Bug,这样即满足了多样化的需求,而且整个二维码都是用路径来表示,换句话说就是矢量图,这样就可以生成任意大小的图片,满足各种用途。
原本的这个开源项目可以导出.eps矢量格式,可供Adobe Illustrator 使用,而Adobe Illustrator的标准格式.AI,可以被Expression Design 4导入,Expression Design 4又可以转换为XAML文件,也就是说这么多软件都可以用来加工我们的二维码原型,这样就增加了设计的可能性。但是当我看完它转换的实现源码时,我愣住了,完全由作者自己写的代码,只是在做字符串的拼接,形成.eps的格式,而且只考虑到了直线路径...所以我就只能将矢量图输出为位图来保存(这里保存为.png格式,因为png是无损压缩格式,作为中介不错)通过PS加工,好在分辨率基本可以满足大部分需求了。为什么Expression Design 4不能导入XAML格式啊....
由于代码比较多,思路我上面已经说明了,只是编码的问题了,这里我就贴出源码,感兴趣的可以自己研究一下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Gma.QrCodeNet.Encoding;
using Gma.QrCodeNet.Encoding.Windows.Render;
using System.Windows;
using System.Windows.Controls; namespace QRCodeFactory
{
static class PathRender
{
/// <summary>
/// 以矩形来填充矩阵点
/// </summary>
/// <param name="QrMatrix">算出来的矩阵</param>
/// <param name="xScale">isRandom?随机取值的最小值:每个点的宽度</param>
/// <param name="yScale">isRandom?随机取值的最大值:每个点的高度</param>
/// <param name="isRandom">是否随机大小</param>
/// <returns>返回路径填充材质</returns>
public static StreamGeometry DrawRectGeometry(BitMatrix QrMatrix, double xScale, double yScale, bool isRandom)
{
int width = QrMatrix == null ? : QrMatrix.Width; StreamGeometry qrCodeStream = new StreamGeometry();
qrCodeStream.FillRule = FillRule.EvenOdd; if (QrMatrix == null)
return qrCodeStream; using (StreamGeometryContext qrCodeCtx = qrCodeStream.Open())
{
for (int y = ; y < width; y++)
{
for (int x = ; x < width; x++)
{
if (QrMatrix[x, y])
{
if (isRandom)
qrCodeCtx.DrawRectGeometry(x, y, (double)(new Random(x + y + Environment.TickCount).Next((int)(xScale * ), (int)(yScale * ))) / , (double)(new Random(x + y + Environment.TickCount).Next((int)(xScale * ), (int)(yScale * ))) / );
else
qrCodeCtx.DrawRectGeometry(x, y, xScale, yScale);
}
}
}
} qrCodeStream.Freeze(); return qrCodeStream;
} /// <summary>
/// 以圆点来填充矩阵点
/// </summary>
/// <param name="QrMatrix">算出来的矩阵</param>
/// <param name="xScale">isRandom?随机取值的最小值:每个点的宽度</param>
/// <param name="yScale">isRandom?随机取值的最大值:每个点的高度</param>
/// <param name="isRandom">是否随机大小</param>
/// <returns>返回路径填充材质</returns>
public static StreamGeometry DrawEllipseGeometry(BitMatrix QrMatrix, double xScale, double yScale, bool isRandom)
{
int width = QrMatrix == null ? : QrMatrix.Width; StreamGeometry qrCodeStream = new StreamGeometry();
qrCodeStream.FillRule = FillRule.EvenOdd; if (QrMatrix == null)
return qrCodeStream; using (StreamGeometryContext qrCodeCtx = qrCodeStream.Open())
{
for (int y = ; y < width; y++)
{
for (int x = ; x < width; x++)
{
if (QrMatrix[x, y])
{
if (isRandom)
qrCodeCtx.DrawEllipseGeometry(x, y, (double)(new Random(x + y + Environment.TickCount).Next((int)(xScale * ), (int)(yScale * ))) / , (double)(new Random(x + y + Environment.TickCount).Next((int)(xScale * ), (int)(yScale * ))) / );
else
qrCodeCtx.DrawEllipseGeometry(x, y, xScale, yScale);
}
}
}
} qrCodeStream.Freeze(); return qrCodeStream;
} /// <summary>
/// 以自定义图形来填充矩阵点
/// </summary>
/// <param name="QrMatrix">算出来的矩阵</param>
/// <param name="xScale">isRandom?随机取值的最小值:每个点的宽度</param>
/// <param name="yScale">isRandom?随机取值的最大值:每个点的高度</param>
/// <param name="isRandomSize">是否随机大小</param>
/// <returns>返回路径填充材质</returns>
public static void DrawCustomGeometry(BitMatrix QrMatrix, ref Grid drawGrid, Path pathGeo, double xScale, double yScale, bool isRandomSize,bool isRandomColor)
{
int width = QrMatrix == null ? : QrMatrix.Width;
drawGrid.Width = drawGrid.Height = width * pathGeo.Width;
for (int y = ; y < width; y++)
{
for (int x = ; x < width; x++)
{
if (QrMatrix[x, y])
{
Path newPath = new Path();//创建一个路径,代表一点
newPath.StrokeThickness = ;
newPath.Stretch = Stretch.UniformToFill;//填充方式s
newPath.HorizontalAlignment = HorizontalAlignment.Left;
newPath.VerticalAlignment = VerticalAlignment.Top;
newPath.Data = pathGeo.Data;
newPath.RenderTransformOrigin = new Point(0.5, 0.5);
TranslateTransform newTTF = new TranslateTransform(x * pathGeo.Width, y * pathGeo.Height);
newPath.RenderTransform = newTTF;
if (isRandomSize)//如果随机大小
{
newPath.Width = newPath.Height = pathGeo.Width * (double)(new Random(x + y + Environment.TickCount).Next((int)(xScale * ), (int)(yScale * ))) / ;
}
else
{
newPath.Width = pathGeo.Width * xScale;
newPath.Height = pathGeo.Height * yScale;
}
if (isRandomColor)//如果随机颜色
newPath.Fill = new SolidColorBrush(GetRandomColor());
else
newPath.Fill = Brushes.Black; drawGrid.Children.Add(newPath);
}
}
} } internal static void DrawRectGeometry(this StreamGeometryContext ctx, double X, double Y, double Width, double Height)
{
ctx.BeginFigure(new Point(X, Y),true, true);
ctx.LineTo(new Point(X, Y + Height), true, true);
ctx.LineTo(new Point(X + Width, Y + Height), true, true);
ctx.LineTo(new Point(X + Width, Y), true, true);
} internal static void DrawEllipseGeometry(this StreamGeometryContext ctx, double X, double Y, double Width, double Height)
{
X = X * ;
Y = Y * ;
Height = Height * ;
Width = Width * ; ctx.BeginFigure(new Point(X, Y + Height / ), true, true);
ctx.ArcTo(new Point(X + Width, Y + Height / ), new Size(Width / , Height / ), , false, SweepDirection.Clockwise, true, true);
ctx.ArcTo(new Point(X, Y + Height / ), new Size(Width / , Height / ), , false, SweepDirection.Clockwise, true, true); } public static Color GetRandomColor()
{
Random randomNum_1 = new Random(Guid.NewGuid().GetHashCode());
System.Threading.Thread.Sleep(randomNum_1.Next());
int int_Red = randomNum_1.Next(); Random randomNum_2 = new Random((int)DateTime.Now.Ticks);
int int_Green = randomNum_2.Next(); Random randomNum_3 = new Random(Guid.NewGuid().GetHashCode()); int int_Blue = randomNum_3.Next();
int_Blue = (int_Red + int_Green > ) ? int_Red + int_Green - : int_Blue;
int_Blue = (int_Blue > ) ? : int_Blue; return GetDarkerColor(Color.FromArgb(Convert.ToByte(),Convert.ToByte(int_Red), Convert.ToByte(int_Green), Convert.ToByte(int_Blue)));
} //获取加深颜色
public static Color GetDarkerColor(Color color)
{
const int max = ;
int increase = new Random(Guid.NewGuid().GetHashCode()).Next(, ); //还可以根据需要调整此处的值 int r = Math.Abs(Math.Min(color.R - increase, max));
int g = Math.Abs(Math.Min(color.G - increase, max));
int b = Math.Abs(Math.Min(color.B - increase, max)); return Color.FromArgb(Convert.ToByte(), Convert.ToByte(r), Convert.ToByte(g), Convert.ToByte(b));
}
}
}
下面欣赏一下我心血来潮时设计的:



下载地址:http://files.cnblogs.com/tong-tong/TTQRCodeFactory.zip
后记
自从本人淘宝女装店倒闭以后就一直不甘心,本来想开家店卖下二维码的设计赚点饭钱,结果事太多了,愣是没有时间来装修店铺...各位博友如果有二维码的设计需求的话也可以找我哦,价格公道,只收饭钱~~~~
通通WPF随笔(3)——艺术二维码素材生成器的更多相关文章
- 分享:Java 开发精美艺术二维码
博客地址:https://ainyi.com/58 Java 开发精美艺术二维码 看到网络上各种各样的二维码层出不穷,好像很炫酷的样子,一时兴起,我也要制作这种炫酷二维码效果 例如: 根据以往例子 根 ...
- Java生成艺术二维码也可以很简单
原文点击: Quick-Media Java生成艺术二维码也可以很简单 现在二维码可以说非常常见了,当然我们见得多的一般是白底黑块,有的再中间加一个 logo,或者将二维码嵌在一张特定的背景中(比如微 ...
- C# WPF使用ZXing生成二维码ImageSource
介绍: 如果需要实在WPF窗体程序中现类似如下的二维码图片生成功能,可以通过本文的方法实现 添加步骤: 1.在http://zxingnet.codeplex.com/站点上下载ZXing .Net的 ...
- 【C#/WPF】.Net生成二维码QRCode的工具
先马 http://qrcodenet.codeplex.com/ 使用该工具WPF生成二维码的简单例子: 前台XAML准备一个Image控件显示二维码. string qrcodeStr = &qu ...
- WPF调用zxing生成二维码
1.登录http://zxingnet.codeplex.com/,下载对应.net版本的zxing库 2.引入zxing.dll 3.新建界面控件 using System; using Syste ...
- WPF 使用QRCoder生成二维码
vs中使用Nuget获取QRCoder 窗体中添加按钮和Iage <Window x:Class="QRCoderTest.MainWindow" xmlns="h ...
- Python-炫酷二维码
一.环境 首先是安装python环境,如果没有安装python环境看此处 二.myqr myqr 其实是一个 python 的脚本,可以生产二维码图片,作者也对python脚本进行了打包,在 ...
- python库myqr生成二维码
python中有一个好玩的库,不仅可以生成各种花色的二维码,还可以生成动态二维码. MyQR是一个能够生成自定义二维码的第三方库,可以根据需要生成普通二维码.带图片的艺术二维码,也可以生成动态二维码 ...
- 使用Python第三方库生成二维码
本文主要介绍两个可用于生成二维码的Python第三方库:MyQR和qrcode. MyQR的使用: 安装: pip install MyQR 导入: from MyQR import myqr imp ...
随机推荐
- POST提交数据时四种常见的数据格式
最近项目部署到新环境tomcat+mysql,想看看项目部署成功没有,就用soupui调对应接口开测试,soupui使用比较简单,给上接口地址,入参xml报文,把入参的media Type设置为app ...
- [Compose] 11. Use Task for Asynchronous Actions
We refactor a standard node callback style workflow into a composed task-based workflow. For example ...
- html5-5 HTML5表单元素和内嵌框架
html5-5 HTML5表单元素和内嵌框架 一.总结 一句话总结:单选框和多选框选的时候外面加label就可以实现选后面文字也可以选中了 1.html5如何实现文件上传? 必须加上enctype ...
- [CSS] Nest a grid within a grid
A grid item can also be a grid container! Let’s see how to specify a grid within a grid.
- wait()、notify()、notifyAll()与线程通信方式总结
1.通过wait().notify().notifyAll()进行线程通信 线程通信的目标是使线程间能够互相发送信号.另一方面,线程通信使线程能够等待其他线程的信号.例如,线程B可以等待线程A的一个信 ...
- show binlog events 命令查看某个binlog日志内容
mysql> show binlog events [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count]; 选项解析: IN 'l ...
- Python 库的使用 —— dis
dis:Disassembler of Python byte code into mnemonics. Java.Python.Ruby 1.9 这些语言均使用了栈机器型的 VM.因为是基于栈的实现 ...
- ACCESS通过一个连接写入的数据,还有一个连接却读取不出来
近期在用c#实现一个数据导入的功能,将一个ACCESS数据库中的数据导入到还有一个ACCESS的数据库中,然后显示出来,可是导入成功了.却显示不出来. 经过研究认为应该是缓存的原因,因为我写入数据和读 ...
- Eclipse迅速执行:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
问题叙述性说明: Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 问题原因: 程序中对 ...
- POJ3280 Cheapest Palindrome 【DP】
Cheapest Palindrome Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 6013 Accepted: 29 ...