通过二维码传输少量文本

2017-06-08  本文已影响0人  laxe

有时候想通过图片传递一些信息,比如公司电脑上一些自己的文档,拍照的话还得自己重新整理出来,要是能将文档转成二维码,用手机扫出来,多方便,本文对此进行一些尝试。

二维码能传输的信息量是很少的,直接将文档内容转成二维码很不现实,先对文档进行压缩再传输比较可行,先用WinRAR对原文件进行压缩。
然后需要将rar转换成可打印字符,一个汉字的二维码比两个ascii字符的二维码复杂,这里考虑将rar转成可打印的ascii字符。标准ascii里有95个可打印字符,那就选64个,可表示6个比特位。

rar文件 可打印字符
6个比特位 一个字符
24个比特位/3个字节 4个字符

所以,rar文件的字节数和可打印字符的字节数之比是3:4。

将rar文件转换为可打印字符的代码:

// encode.c
//input: src.rar output: dest.txt
#include <stdio.h>
#include <string.h>

unsigned char table[]=
{
    '0','1','2','3','4','5','6','7','8','9','<','>',
    'A','B','C','D','E','F','G','H','I','J','K','L','M',
    'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
    'a','b','c','d','e','f','g','h','i','j','k','l','m',
    'n','o','p','q','r','s','t','u','v','w','x','y','z'
};

// 当到达文件尾不足3个字符时, 末尾补0, 最多会有2个空字符, 对rar文件无影响
int read3chars(FILE *fin, unsigned char *re)
{
    int t;
    unsigned char buf[3];
    memset(buf, 0, 3*sizeof(unsigned char));

    t = fgetc(fin);
    if(t == EOF) return 1;
    buf[0] = t;
    t = fgetc(fin);
    if(t == EOF) goto last;
    buf[1] = t;
    t = fgetc(fin);
    if(t == EOF) goto last;
    buf[2] = t;

last:
    unsigned char a = (buf[0]&0xFC)>>2;
    unsigned char b = (buf[0]&0x03)<<4 | (buf[1]&0xF0)>>4;
    unsigned char c = (buf[1]&0x0F)<<2 | buf[2]>>6;
    unsigned char d = buf[2]&0x3F;
    re[0] = table[a];
    re[1] = table[b];
    re[2] = table[c];
    re[3] = table[d];

    return 0;
}

int main()
{
    FILE *fin = fopen("src.rar", "rb");
    if(fin == NULL)
    {
        puts("cann't open src.rar!");
        getchar();
        return -1;
    }
    FILE *fout = fopen("dest.txt", "w");
    for(;;)
    {
        unsigned char buf[4];
        int ret = read3chars(fin, buf);
        if(ret == 1) break;
        fputc(buf[0], fout);
        fputc(buf[1], fout);
        fputc(buf[2], fout);
        fputc(buf[3], fout);
    }
    fclose(fin);
    fclose(fout);
    return 0;
}

将生成的字符分批次通过二维码扫描工具传输。
也可以直接改上面的main函数:

int main()
{
    FILE *fin = fopen("src.rar", "rb");
    if(fin == NULL)
    {
        puts("cann't open src.rar!");
        getchar();
        return -1;
    }
    char dest[] = "A.txt";
    FILE *fout = fopen(dest, "w");
    for(int i=1;;++i)
    {
        unsigned char buf[4];
        int ret = read3chars(fin, buf);
        if(ret == 1) break;
        fputc(buf[0], fout);
        fputc(buf[1], fout);
        fputc(buf[2], fout);
        fputc(buf[3], fout);
        if(i == 256)
        {
            i = 0;
            fclose(fout);
            ++dest[0];
            fout = fopen(dest, "w");
        }
    }
    fclose(fin);
    fclose(fout);
    return 0;
}

将扫码得到的字符组合在一起,放到txt文件里,然后执行以下的程序。这里并没有对BOM字符进行处理,仅仅是和上面的程序一起进行测试。

// decode.cpp
// input: dest.txt output: dest.rar
#include <cstdio>
#include <hash_map>

char table[]=
{
    '0','1','2','3','4','5','6','7','8','9','<','>',
    'A','B','C','D','E','F','G','H','I','J','K','L','M',
    'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
    'a','b','c','d','e','f','g','h','i','j','k','l','m',
    'n','o','p','q','r','s','t','u','v','w','x','y','z'
};
__gnu_cxx::hash_map<unsigned char, unsigned char> retable;

// 一定是4字节的整数倍
int read4chars(FILE *fin, unsigned char *ret)
{
    unsigned char buf[4];
    int t = fgetc(fin);
    if(t == EOF) return -1;
    buf[0] = t;
    buf[1] = fgetc(fin);
    buf[2] = fgetc(fin);
    buf[3] = fgetc(fin);

    unsigned char a = retable[buf[0]];
    unsigned char b = retable[buf[1]];
    unsigned char c = retable[buf[2]];
    unsigned char d = retable[buf[3]];
    ret[0] = a<<2 | b>>4;
    ret[1] = b<<4 | c>>2;
    ret[2] = c<<6 | d;

    return 0;
}

int main()
{
    for(unsigned char i=0; i<64; ++i)
        retable.insert(std::make_pair(table[i], i));

    FILE *fin = fopen("dest.txt", "r");
    if(fin == NULL)
    {
        puts("cann't open dest.txt!");
        getchar();
        return -1;
    }
    FILE *fout = fopen("dest.rar", "wb");
    for(;;)
    {
        unsigned char buf[3];
        int res = read4chars(fin, buf);
        if(res == -1) break;
        fputc(buf[0], fout);
        fputc(buf[1], fout);
        fputc(buf[2], fout);
    }

    fclose(fin);
    fclose(fout);
    return 0;
}

这和Base64编码的原理是一样的。

上一篇下一篇

猜你喜欢

热点阅读