<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Misc on chai2010 的博客</title>
    <link>https://chai2010.cn/categories/misc/</link>
    <description>Recent content in Misc on chai2010 的博客</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>zh-CN</language>
    <lastBuildDate>Wed, 15 Nov 2017 00:00:00 +0000</lastBuildDate>
    
        <atom:link href="https://chai2010.cn/categories/misc/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>用ASCII画图</title>
      <link>https://chai2010.cn/post/misc/ascii-draw/</link>
      <pubDate>Wed, 15 Nov 2017 00:00:00 +0000</pubDate>
      
      <guid>https://chai2010.cn/post/misc/ascii-draw/</guid>
      
        <description>

&lt;p&gt;作为一个严肃的码农，用ASCII画图是一门艺术。&lt;/p&gt;

&lt;h2 id=&#34;monodraw-https-monodraw-helftone-com-ascii-画图界的ps&#34;&gt;&lt;a href=&#34;https://monodraw.helftone.com/&#34;&gt;MonoDraw&lt;/a&gt; - ASCII 画图界的PS&lt;/h2&gt;

&lt;p&gt;当然，我们并不是要像用小刀刻硬盘那样一个一个字符来画图，在ASCII画图领用也有类似PhotoShop那样的软件，那就是大名鼎鼎的 MonoDraw ！&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://chai2010.cn/images/ascii-draw-01.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;要注意的是这个软件只有 macOS 版本，而且是收费软件(100+RMB)。&lt;/p&gt;

&lt;p&gt;比如我们用 &lt;a href=&#34;https://monodraw.helftone.com/&#34;&gt;MonoDraw&lt;/a&gt;  画一个 iPhone, 然后在窗口显示一个文本:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://chai2010.cn/images/ascii-draw-02.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;ditaa-http-ditaa-sourceforge-net-ascii-图像打印机&#34;&gt;&lt;a href=&#34;http://ditaa.sourceforge.net/&#34;&gt;Ditaa&lt;/a&gt; - ASCII 图像打印机&lt;/h2&gt;

&lt;p&gt;Ditaa 是 Java 写的一个开源小工具，它可以将ASCII码图打印为漂亮的png格式图片。&lt;/p&gt;

&lt;p&gt;比如有以下样式的ASCII码图：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://chai2010.cn/images/ascii-draw-03.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;渲染后的效果是这样的:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://chai2010.cn/images/ascii-draw-04.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;这里是打包好的 Docker 镜像(也有很多例子)： &lt;a href=&#34;https://github.com/chai2010/ditaa-docker&#34;&gt;https://github.com/chai2010/ditaa-docker&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;其它工具&#34;&gt;其它工具&lt;/h2&gt;

&lt;p&gt;还有很多其它知名度很高小工具，这里只是简单列举几个：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.graphviz.org/&#34;&gt;Graphviz&lt;/a&gt;: 通过自定义的DOT语言脚本描述图形，然后渲染为图像文件&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://plantuml.com/&#34;&gt;PlantUML&lt;/a&gt;: 通过自定义的脚本语言描述UML图，然后渲染为图像文件&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.gnuplot.info/&#34;&gt;Gnuplot&lt;/a&gt;: 一个生成图标的小工具(它和GNU项目没关系)&lt;/li&gt;
&lt;/ul&gt;
</description>
      
    </item>
    
    <item>
      <title>TIFF6.0格式简介</title>
      <link>https://chai2010.cn/post/misc/tiff-spec/</link>
      <pubDate>Mon, 02 Sep 2013 00:00:00 +0000</pubDate>
      
      <guid>https://chai2010.cn/post/misc/tiff-spec/</guid>
      
        <description>

&lt;!-- TIFF格式简介 --&gt;

&lt;!-- 作者: chai2010 chaishushan{AT}gmail.com (整理) --&gt;

&lt;p&gt;&lt;em&gt;作者: chai2010 (chaishushan{AT}gmail.com) (整理)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;标签图像文件格式(Tagged Image File Format, 简写为TIFF)是一种主要用来存储包括照片和艺术图在内的图像的文件格式. 它最初由Aldus公司与微软公司一起为PostScript打印开发.&lt;/p&gt;

&lt;p&gt;TIFF最初的设计目的是为了1980年代中期桌面扫描仪厂商达成一个公用的扫描图像文件格式, 而不是每个厂商使用自己专有的格式. 在刚开始的时候, TIFF只是一个二值图像格式, 因为当时的桌面扫描仪只能处理这种格式. 随着扫描仪的功能愈来愈强大, 并且桌面计算机的磁盘空间越来越大, TIFF逐渐支持灰阶图像和彩色图像.&lt;/p&gt;

&lt;p&gt;目前最新的 &lt;a href=&#34;http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf&#34;&gt;TIFF6.0规范&lt;/a&gt; 在1992年公布.&lt;/p&gt;

&lt;h2 id=&#34;结构概述&#34;&gt;结构概述&lt;/h2&gt;

&lt;p&gt;TIFF文件以&lt;code&gt;.tif&lt;/code&gt;或&lt;code&gt;.tiff&lt;/code&gt;为扩展名. 其数据格式是一种3级体系结构, 从高到低依次为: 文件头IFH(Image File Header), 一个或多个称为IFD(Image File Directory)的包含标记指针的目录和数据. 一个文件中可以包含多个IFD, 每个IFD对应一个图像.&lt;/p&gt;

&lt;p&gt;图像头(IFH)/图像目录(IFD)/标签入口(IFDEntry)的逻辑结构如下:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;+------------------------------------------------------------------------------+
|                           TIFF Structure                                     |
|  IFH                                                                         |
| +------------------+                                                         |
| | II/MM            |                                                         |
| +------------------+                                                         |
| | 42               |      IFD                                                |
| +------------------+    +------------------+                                 |
| | Next IFD Address |---&amp;gt;| IFD Entry Num    |                                 |
| +------------------+    +------------------+                                 |
|                         | IFD Entry 1      |                                 |
|                         +------------------+                                 |
|                         | IFD Entry 2      |                                 |
|                         +------------------+                                 |
|                         |                  |      IFD                        |
|                         +------------------+    +------------------+         |
|     IFD Entry           | Next IFD Address |---&amp;gt;| IFD Entry Num    |         |
|    +---------+           +------------------+   +------------------+         |
|    | Tag     |                                  | IFD Entry 1      |         |
|    +---------+                                  +------------------+         |
|    | Type    |                                  | IFD Entry 2      |         |
|    +---------+                                  +------------------+         |
|    | Count   |                                  |                  |         |
|    +---------+                                  +------------------+         |
|    | Offset  |---&amp;gt;Value                         | Next IFD Address |---&amp;gt;NULL |
|    +---------+                                  +------------------+         |
|                                                                              |
+------------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;其中, TIFF中的版本号为42, 包含生命宇宙以及任何事情的终极答案(这也说明了TIFF格式为何这么强大).
文件中的数据指针(offset)最大对应4个字节, 因此一个文件不能超过4GB.
如果需要大于4GB的图像支持, 可以参考基于TIFF的变种格式 &lt;a href=&#34;http://www.awaresystems.be/imaging/tiff/bigtiff.html&#34;&gt;BigTiff&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;图像基本信息&#34;&gt;图像基本信息&lt;/h2&gt;

&lt;p&gt;基本信息为图像的大小, 图像的颜色模型(黑白图像/灰度图像/调色板图像/真彩色 等),
每个像素的大小和单位等信息.&lt;/p&gt;

&lt;p&gt;每个图像必须包含的标签有(含压缩类型):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ImageWidth 256 SHORT or LONG
ImageLength 257 SHORT or LONG
XResolution 282 RATIONAL
YResolution 283 RATIONAL
ResolutionUnit 128 SHORT 1, 2 or 3
Compression 259 SHORT 1, 2 or 32773
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;其中颜色模型由几个标签组合判断:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;PhotometricInterpretation 262 106 SHORT 0/1/2/3
BitsPerSample 258 SHORT 4 or 8
SamplesPerPixel 277 SHORT default(1)
ColorMap 320 SHORT 3 * (2**BitsPerSample)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;色彩模型&#34;&gt;色彩模型&lt;/h2&gt;

&lt;p&gt;TIFF基础部分定义了4种色彩模型(这里不讨论掩码图像和扩展色彩模型),
主要有: 二值图像, 灰度图像, 调色板图像, 真彩色图像.&lt;/p&gt;

&lt;h3 id=&#34;二值图像&#34;&gt;二值图像&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;如果没有 BitsPerSample 则为二值图&lt;/li&gt;
&lt;li&gt;颜色模型 PhotometricInterpretation 必须为 0(0为白色) 或 1(1为白色)&lt;/li&gt;
&lt;li&gt;压缩类型 Compression 1, 2 or 32773, 支持 Huffman 编码&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&#34;灰度图像&#34;&gt;灰度图像&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;有 BitsPerSample, 且 PhotometricInterpretation 为 0 或 1&lt;/li&gt;
&lt;li&gt;压缩类型 Compression 1 or 32773, 不支持 Huffman 编码&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&#34;调色板图像&#34;&gt;调色板图像&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;PhotometricInterpretation 为 3&lt;/li&gt;
&lt;li&gt;必需包含 ColorMap&lt;/li&gt;
&lt;li&gt;BitsPerSample 为 4 或 8&lt;/li&gt;
&lt;li&gt;Compression 为 1 or 32773, 不支持 Huffman 编码&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&#34;真彩色图像&#34;&gt;真彩色图像&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;PhotometricInterpretation 为 2&lt;/li&gt;
&lt;li&gt;必须含 SamplesPerPixel 波段数信息, 值为 3&lt;/li&gt;
&lt;li&gt;BitsPerSample 必须为 8,8,8&lt;/li&gt;
&lt;li&gt;Compression 为 1 or 32773, 不支持 Huffman 编码&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&#34;其他模型&#34;&gt;其他模型&lt;/h3&gt;

&lt;p&gt;TIFF 的扩展特性中还包含 CMYK 和 YCbCr 等其他色彩模型.
详细信息请参考TIFF6.0规范.&lt;/p&gt;

&lt;h2 id=&#34;条带和分片&#34;&gt;条带和分片&lt;/h2&gt;

&lt;p&gt;其中数据的组织方式有条带和分片两种, 默认为条带方式存储.&lt;/p&gt;

&lt;p&gt;条带图像必要的标签有:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;RowsPerStrip 278 SHORT or LONG
StripOffsets 273 SHORT or LONG
StripByteCounts 279 SHORT or LONG
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;其中 &lt;code&gt;RowsPerStrip&lt;/code&gt; 缺省值为 &lt;code&gt;2^32-1&lt;/code&gt;, 图像将只有1个条带.
如果条带数据不足的话, 末尾并不需要数据填充.&lt;/p&gt;

&lt;p&gt;分片图像必要的标签有:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;TileWidth 322 SHORT or LONG
TileLength 323 SHORT or LONG
TileOffsets 324 SHORT or LONG
TileByteCounts 325 SHORT or LONG
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;每个片的大小必须是16的倍数, 每个片的长和宽可以不同.
如果片数据不足的话, 需要填充(填充数据没有要求).&lt;/p&gt;

&lt;h2 id=&#34;位平面&#34;&gt;位平面&lt;/h2&gt;

&lt;p&gt;位平面由 &lt;code&gt;PlanarConfiguration&lt;/code&gt; 标签确定, 缺省时为1表示按像素组织(比如RGBRGB).
当 &lt;code&gt;PlanarConfiguration&lt;/code&gt; 为2时, 为按通道存储(比如RRGGBB).&lt;/p&gt;

&lt;p&gt;当只有1个通道时(&lt;code&gt;SamplesPerPixel&lt;/code&gt;), 位平面信息可以忽略.&lt;/p&gt;

&lt;h2 id=&#34;压缩方式&#34;&gt;压缩方式&lt;/h2&gt;

&lt;p&gt;压缩方式由 &lt;code&gt;Compression&lt;/code&gt; 标签确定.&lt;/p&gt;

&lt;p&gt;基本算法:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;1 = No compression
2 = CCITT modified Huffman RLE
32773 = PackBits compression, aka Macintosh RLE
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;扩展特性:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;3 = CCITT Group 3 fax encoding
4 = CCITT Group 4 fax encoding
5 = LZW
6 = JPEG (&#39;old-style&#39; JPEG, later overriden in Technote2)
7 = JPEG (&#39;new-style&#39; JPEG)
8 = Deflate (&#39;Adobe-style&#39;)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;常见标签&#34;&gt;常见标签&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;ImageDescription 270 ASCII

CellLength 265 SHORT
CellWidth 264 SHORT

Software 305 ASCII
DateTime 306 ASCII
Artist 315 ASCII
HostComputer 316 ASCII

Copyright 33432 ASCII
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;空闲空间&#34;&gt;空闲空间&lt;/h2&gt;

&lt;p&gt;当创建或更新TIFF文件时, 文件中会有一些空闲的空间(类似malloc/free导致的内存碎片).
TIFF规范中有 &lt;code&gt;FreeByteCounts&lt;/code&gt; 和 &lt;code&gt;FreeOffsets&lt;/code&gt; 两个标签用于记录文件中的空闲空间.&lt;/p&gt;

&lt;p&gt;但是由于不同标签之间的弱引用关系, &lt;code&gt;FreeByteCounts&lt;/code&gt; 和 &lt;code&gt;FreeOffsets&lt;/code&gt; 记录的信息
可能并不可靠. 因此, 并不能完全依赖这个信息.&lt;/p&gt;

&lt;h2 id=&#34;忽略特性&#34;&gt;忽略特性&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;文件中含多个图像(多IFD)&lt;/li&gt;
&lt;li&gt;扩展的压缩算法&lt;/li&gt;
&lt;li&gt;扩展的色彩模型&lt;/li&gt;
&lt;li&gt;多通道数大于4&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;文件实例&#34;&gt;文件实例&lt;/h2&gt;

&lt;p&gt;这是一个二值图像的片段(来自TIFF6.0规范文档):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Header:
0000 Byte Order                  4D4D
0002 42                          002A
0004 1st IFD offset              00000014

IFD:
0014 Number of Directory Entries 000C
0016 NewSubfileType              00FE 0004 00000001 00000000
0022 ImageWidth                  0100 0004 00000001 000007D0
002E ImageLength                 0101 0004 00000001 00000BB8
003A Compression                 0103 0003 00000001 8005 0000
0046 PhotometricInterpretation   0106 0003 00000001 0001 0000
0052 StripOffsets                0111 0004 000000BC 000000B6
005E RowsPerStrip                0116 0004 00000001 00000010
006A StripByteCounts             0117 0003 000000BC 000003A6
0076 XResolution                 011A 0005 00000001 00000696
0082 YResolution                 011B 0005 00000001 0000069E
008E Software                    0131 0002 0000000E 000006A6
009A DateTime                    0132 0002 00000014 000006B6
00A6 Next IFD offset             00000000

Values longer than 4 bytes:
00B6 StripOffsets                Offset0, Offset1, ... Offset187
03A6 StripByteCounts             Count0, Count1, ... Count187
0696 XResolution                 0000012C 00000001
069E YResolution                 0000012C 00000001
06A6 Software                    “PageMaker 4.0”
06B6 DateTime                    “1988:02:18 13:59:59”

Image Data:
00000700                         Compressed data for strip 10
xxxxxxxx                         Compressed data for strip 179
xxxxxxxx                         Compressed data for strip 53
xxxxxxxx                         Compressed data for strip 160
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;参考信息&#34;&gt;参考信息&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf&#34;&gt;http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.awaresystems.be/imaging/tiff.html&#34;&gt;http://www.awaresystems.be/imaging/tiff.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.libtiff.org/tools.html&#34;&gt;http://www.libtiff.org/tools.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      
    </item>
    
    <item>
      <title>ASCII码中大小写字母转换</title>
      <link>https://chai2010.cn/post/misc/ascii-upper-lower/</link>
      <pubDate>Mon, 06 May 2013 00:00:00 +0000</pubDate>
      
      <guid>https://chai2010.cn/post/misc/ascii-upper-lower/</guid>
      
        <description>&lt;p&gt;ASCII中消息字母比大写字母大32, 比如: &amp;lsquo;a&amp;rsquo;对应97, &amp;lsquo;A&amp;rsquo;对应65(97-32=65).&lt;/p&gt;

&lt;p&gt;ASCII中大小写字母都是排列有序的, 一般在转换大小写字母时都会基于这个特性.&lt;/p&gt;

&lt;p&gt;下边是&lt;ctypes.h&gt;中转换函数的一种实现:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;int tolower(int c) {return ( c -&#39;A&#39;+&#39;a&#39;);}
int toupper(int c) {return ( c -&#39;a&#39;+&#39;A&#39;);}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;其实&lt;code&gt;&#39;a&#39;-&#39;A&#39;&lt;/code&gt;对应的32刚好是2的幂, 二进制表示为: &lt;code&gt;00010 0000&lt;/code&gt;.
ASCII中大小写字母转换只是将32的二进制中唯一的bit为1的数置0或置1.
置0对应减32转换为大写字母, 置1对应加32转换为小写字母.&lt;/p&gt;

&lt;p&gt;我们可以用位运算重新实现上面的函数:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;int tolower(int c) {return (c ^ 32);}
int toupper(int c) {return (c ^ 32);}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;继续观察可以发现32刚好对应ASCII中的空格&amp;rsquo; &amp;lsquo;, 因此代码调整为:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;int tolower(int c) {return (c ^ &#39; &#39;);}
int toupper(int c) {return (c ^ &#39; &#39;);}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;在转换单个字母时这样就可以了: &lt;code&gt;c ^= &#39; &#39;&lt;/code&gt;.&lt;/p&gt;
</description>
      
    </item>
    
    <item>
      <title>VC2010下Qt5的中文乱码问题</title>
      <link>https://chai2010.cn/post/misc/qt5-i18n/</link>
      <pubDate>Thu, 04 Apr 2013 00:00:00 +0000</pubDate>
      
      <guid>https://chai2010.cn/post/misc/qt5-i18n/</guid>
      
        <description>&lt;p&gt;要搞清楚这个问题，先要弄明白编码。但是编码问题实在太复杂，这里肯定讲不开。&lt;/p&gt;

&lt;p&gt;我先找一个例子，比如：&amp;rdquo;中文&amp;rdquo; 的 Unicode 码点/UTF8编码/GBK 分别是多少。&lt;/p&gt;

&lt;p&gt;先去这个网站，输入 &amp;ldquo;中文&amp;rdquo; 查询对应的 Unicode 码点/UTF8编码：&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://www.mytju.com/classcode/tools/encode_utf8.asp&#34;&gt;http://www.mytju.com/classcode/tools/encode_utf8.asp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unicode的码点分别是(十进制)：中(20013)，文(25991)。
对应的UTF8编码分别(16进制): 中(E4B8AD)，文(E69687)。&lt;/p&gt;

&lt;p&gt;然后再去下面这个网站，输入 &amp;ldquo;中文&amp;rdquo; 查询对应的 GBK 编码：
&lt;a href=&#34;http://www.mytju.com/classcode/tools/encode_gb2312.asp&#34;&gt;http://www.mytju.com/classcode/tools/encode_gb2312.asp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GBK编码16进制(GBK内码)分别是：中(D6D0)，文(CEC4)。&lt;/p&gt;

&lt;p&gt;现在已经知道了&amp;rdquo;中文&amp;rdquo;的UTF8和GBK编码的具体值。
我们再看看VC2010是怎么处理的。&lt;/p&gt;

&lt;h2 id=&#34;1-先看-无-bom-的-utf8-编码的代码-utf8-no-bom-cpp&#34;&gt;1. 先看 无 BOM 的 UTF8 编码的代码 (utf8_no_bom.cpp)&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;// utf8 no bom
// 文件中包含不能在当前代码页（936）中表示的字符
#include &amp;lt;stdio.h&amp;gt;

int main() {
    const char* str = &amp;quot;中文&amp;quot;;
    for(int i = 0; i &amp;lt; sizeof(str); ++i) {
        printf(&amp;quot;0x%x &amp;quot;, str[i]&amp;amp;0xFF);
    }
    return 0;
    // Output:
    // 0xe4 0xb8 0xad 0xe6
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;输出是：0xe4 0xb8 0xad 0xe6。
感觉好像是对的。&lt;/p&gt;

&lt;p&gt;但是，先别急：VC编译时输出了一条警告信息：
utf8_no_bom.cpp : warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。
请将该文件保存为 Unicode 格式以防止数据丢失。&lt;/p&gt;

&lt;p&gt;潜台词就是，你这个代码有GBK不能表示的字符，请用Unicode方式保存。
VC根本就没把 代码(utf8_no_bom.cpp) 当作UTF8，VC只是把它作为GBK处理罢了。&lt;/p&gt;

&lt;p&gt;那为什么又输出了正确的结果呢？&lt;/p&gt;

&lt;p&gt;因为 VC 把 (utf8_no_bom.cpp) 当作 GBK，而编译时也要转换为本地编码(也是GBK)。
因此，UTF8编码的 &amp;ldquo;中文&amp;rdquo;，被VC当作编码为 &amp;ldquo;0xe4 0xb8 0xad 0xe6&amp;rdquo; 的其他中文处理了。
VC已经不知道 &amp;ldquo;0xe4 0xb8 0xad 0xe6&amp;rdquo; 是对应 &amp;ldquo;中文&amp;rdquo; 字面值了。&lt;/p&gt;

&lt;p&gt;但是在GBK(实际是无BOM的UTF8)转GBK的过程中，发现了一些UTF8编码的字符并不是
GBK能表达的合理方式，因此就出现了那个C4819编译警告。&lt;/p&gt;

&lt;h2 id=&#34;2-再看带bom的utf8是怎么处理的-utf8-with-bom-cpp&#34;&gt;2. 再看带BOM的UTF8是怎么处理的 (utf8_with_bom.cpp)&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;// utf8 with bom
#include &amp;lt;stdio.h&amp;gt;

int main() {
    const char* str = &amp;quot;中文&amp;quot;;
    for(int i = 0; i &amp;lt; sizeof(str); ++i) {
        printf(&amp;quot;0x%x &amp;quot;, str[i]&amp;amp;0xFF);
    }
    return 0;
    // Output:
    // 0xd6 0xd0 0xce 0xc4
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;编译没有警告，但是输出有问题：0xd6 0xd0 0xce 0xc4。&lt;/p&gt;

&lt;p&gt;源文件明明是 UTF8 编码的格式&amp;rdquo;0xe4 0xb8 0xad 0xe6&amp;rdquo;，
怎么变成了 &amp;ldquo;0xd6 0xd0 0xce 0xc4&amp;rdquo; (这个是GBK编码)？&lt;/p&gt;

&lt;p&gt;这就是VC私下干的好事：它自作聪明的将UTF8源代码转换为GBK处理了！&lt;/p&gt;

&lt;p&gt;VC为何要做这样蠢事？&lt;/p&gt;

&lt;p&gt;原因是为了兼容老的VC版本。
因为以前的VC不能处理UTF8，都是用本地编码处理的。&lt;/p&gt;

&lt;h2 id=&#34;3-在看看真的gbk是怎么处理的-gbk-cpp&#34;&gt;3. 在看看真的GBK是怎么处理的 (gbk.cpp)&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;// gbk
#include &amp;lt;stdio.h&amp;gt;

int main() {
    const char* str = &amp;quot;中文&amp;quot;;
    for(int i = 0; i &amp;lt; sizeof(str); ++i) {
        printf(&amp;quot;0x%x &amp;quot;, str[i]&amp;amp;0xFF);
    }
    return 0;
    // Output:
    // 0xd6 0xd0 0xce 0xc4
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;没有编译错误，输出也和源代码一致：&amp;rdquo;0xd6 0xd0 0xce 0xc4&amp;rdquo;。&lt;/p&gt;

&lt;p&gt;因为源文件就是GBK，cl在编译时GBK转化为GBK，没有改变字符串。&lt;/p&gt;

&lt;p&gt;只是，现在很多人不想用GBK了（因为只能在中国地区用，不能表示全球字符）。&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;到这里，可以初步小结一下：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;VC编辑器和VC编译器是2个概念，VC编辑器支持UTF8并不能表示VC编译器也支持UTF8&lt;/li&gt;
&lt;li&gt;VC编辑器从2008?开始支持带BOM的UTF8(不带BOM的暂时没戏，因为会本地编码冲突)&lt;/li&gt;
&lt;li&gt;VC编译器从2010开始重要可以支持UTF8了(虽然支持方式很不优雅)&lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;

&lt;h2 id=&#34;4-看看vc2010是怎么处理带bom的utf8的-utf8-with-bom-2010-cpp&#34;&gt;4. 看看VC2010是怎么处理带BOM的UTF8的 (utf8_with_bom_2010.cpp)&lt;/h2&gt;

&lt;p&gt;VC2010重要增加了UTF8的编译支持(&lt;code&gt;#pragma execution_character_set(&amp;quot;utf-8&amp;quot;)&lt;/code&gt;),
具体查看:&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/2f328917-4e99-40be-adfa-35cc17c9cdec&#34;&gt;http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/2f328917-4e99-40be-adfa-35cc17c9cdec&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// utf8 with bom (VC2010), 这句是重点！
#pragma execution_character_set(&amp;quot;utf-8&amp;quot;)

#include &amp;lt;stdio.h&amp;gt;

int main() {
    const char* str = &amp;quot;中文&amp;quot;;
    for(int i = 0; i &amp;lt; sizeof(str); ++i) {
        printf(&amp;quot;0x%x &amp;quot;, str[i]&amp;amp;0xFF);
    }
    return 0;
    // Output:
    // 0xe4 0xb8 0xad 0xe6
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;没有编译错误，输出也和源代码一致：&amp;rdquo;0xe4 0xb8 0xad 0xe6&amp;rdquo;。&lt;/p&gt;

&lt;p&gt;UTF8编码，UTF8输出。完美!&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&#34;回到-qt5-的中文输出问题&#34;&gt;回到 Qt5 的中文输出问题。&lt;/h1&gt;

&lt;p&gt;Qt默认支持 VS2010/MinGW/Gcc 等编译器，而它们现在都已经真正支持UTF8了。&lt;/p&gt;

&lt;p&gt;当然，VS2010 对UTF8的支持会入侵代码(&lt;code&gt;#pragma execution_character_set(&amp;quot;utf-8&amp;quot;)&lt;/code&gt;)。&lt;/p&gt;

&lt;p&gt;看看Qt官方论坛别人是怎么说的：
&lt;a href=&#34;http://qt-project.org/forums/viewthread/17617&#34;&gt;http://qt-project.org/forums/viewthread/17617&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Nothing special need to do, it will works by default.
If the exec-charset of your your compiler is UTF-8.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;简单的说，从Qt5开始，源代码就是默认UTF8编码的。&lt;/p&gt;

&lt;p&gt;当然，VC2010编辑器对带BOM的UTF8也是认识，只可惜VC2010编译器根本承认它是UTF8！&lt;/p&gt;

&lt;p&gt;在继续看官方论坛的回复：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can write a simple example like this&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  #include &amp;lt;QApplication&amp;gt;
  #include &amp;lt;QLabel&amp;gt;

  #if _MSC_VER &amp;gt;= 1600
  #pragma execution_character_set(&amp;quot;utf-8&amp;quot;)
  #endif

  int main(int argc, char *argv[])
  {
      QApplication a(argc, argv);
      QLabel label(&amp;quot;ąśćółęńżź&amp;quot;);
      label.show();

      return a.exec();
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If other people can reproduce your problem, you can file a bug.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;教完整的解决方案(增加了Qt4/Qt5和非VC环境的判断):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// Coding: UTF-8(BOM)
#if defined(_MSC_VER) &amp;amp;&amp;amp; (_MSC_VER &amp;gt;= 1600)
# pragma execution_character_set(&amp;quot;utf-8&amp;quot;)
#endif

#include &amp;lt;QApplication&amp;gt;
#include &amp;lt;QTextCodec&amp;gt;
#include &amp;lt;QLabel&amp;gt;

int main(int argc, char* argv[])
{
    QApplication app(argc, argv);

#if QT_VERSION &amp;lt; QT_VERSION_CHECK(5,0,0)
#if defined(_MSC_VER) &amp;amp;&amp;amp; (_MSC_VER &amp;lt; 1600)
    QTextCodec::setCodecForTr(QTextCodec::codecForName(&amp;quot;GB18030-0&amp;quot;));
#else
    QTextCodec::setCodecForTr(QTextCodec::codecForName(&amp;quot;UTF-8&amp;quot;));
#endif
#endif

    QLabel *label = new QLabel(QObject::tr(&amp;quot;你好！&amp;quot;));
    label-&amp;gt;show();

    return app.exec();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;有以下几种类型(源代码必须是带BOM的UTF8):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Qt5+/VC2010+: 包含了 &lt;code&gt;# pragma execution_character_set(&amp;quot;utf-8&amp;quot;)&lt;/code&gt; 已经支持中文&lt;/li&gt;
&lt;li&gt;Qt5/VC2008-: 这个暂时误解(我还没找到方法)&lt;/li&gt;
&lt;li&gt;Qt4+/VC2008-: 采用以前老的方式, 指定代码为 &amp;ldquo;GB18030-0&amp;rdquo; 编码&lt;/li&gt;
&lt;li&gt;Qt4/Qt5/Linux: 只要是默认的UTF8环境, 应该都没问题&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;其实这个问题不是Qt特有的, 追根溯源还是C/C++和编译器的问题.&lt;/p&gt;

&lt;p&gt;即使是支持UTF16的Java也同样难逃此问题.&lt;/p&gt;

&lt;p&gt;不过还好, &lt;a href=&#34;http://golang.org&#34;&gt;Go语言&lt;/a&gt; 算是彻底了解决了这个问题.
以后转向 &lt;a href=&#34;http://golang.org&#34;&gt;Go语言&lt;/a&gt; 了 !&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>PwdGen - 用Go语言实现的密码生成工具</title>
      <link>https://chai2010.cn/post/misc/pwdgen/</link>
      <pubDate>Wed, 27 Mar 2013 00:00:00 +0000</pubDate>
      
      <guid>https://chai2010.cn/post/misc/pwdgen/</guid>
      
        <description>&lt;p&gt;针对CSDN等各大网站私自保存密码的问题, 尝试用Go语言 写了个密码生成工具.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://bitbucket.org/chai2010/pwdgen/wiki/Home&#34;&gt;pwdgen&lt;/a&gt; 是 password generator 的缩写, 支持生成&lt;a href=&#34;http://keepass.info/&#34;&gt;KeePass&lt;/a&gt;格式.&lt;/p&gt;

&lt;p&gt;下面是生成算法和实现的代码:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// base58(sha512(md5hex(encrypt_key+encrypt_salt)+site_id+site_salt)[0:16]
func pwdgen(site_id, site_salt, encrypt_key, encrypt_salt string) string {
    md5 := md5.New()
    md5.Write([]byte(encrypt_key + encrypt_salt))
    md5Hex := fmt.Sprintf(&amp;quot;%x&amp;quot;, md5.Sum(nil))

    sha := sha512.New()
    sha.Write([]byte(md5Hex + site_id + site_salt))
    shaSum := sha.Sum(nil)

    pwd := base58.EncodeBase58(shaSum)[0:16]
    return string(pwd)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;完整的程序请访问: &lt;a href=&#34;https://bitbucket.org/chai2010/pwdgen/wiki/Home&#34;&gt;https://bitbucket.org/chai2010/pwdgen/wiki/Home&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;在线文档请访问:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://godoc.org/bitbucket.org/chai2010/pwdgen&#34;&gt;http://godoc.org/bitbucket.org/chai2010/pwdgen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://godoc.org/bitbucket.org/chai2010/pwdgen/base58&#34;&gt;http://godoc.org/bitbucket.org/chai2010/pwdgen/base58&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://godoc.org/bitbucket.org/chai2010/pwdgen/ini&#34;&gt;http://godoc.org/bitbucket.org/chai2010/pwdgen/ini&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      
    </item>
    
  </channel>
</rss>