介绍

根据豆瓣的标签分类,分成文学流行文化生活经管科技六个大类,大类下包括若干标签。
每个大类整理成一个单独Excle文件,里面的一个工作表对应保存一个标签的全部书,按照书的评分从高到低排序。
表格里保存的信息包括评分评价人数作者出版社信息

简介豆瓣链接以及封面图文件名(封面图的合集也会在下面放出,有兴趣的可以下)

多个标签(以文学大类为例)

下载地址

注:如果不能下载的话,请在其他浏览器中打开并重试。

文学大类


直接下载
网盘下载
●════════════════════●

流行大类


直接下载
网盘下载
●════════════════════●

文化大类


直接下载
网盘下载
●════════════════════●

生活大类


直接下载
网盘下载
●════════════════════●

经管大类


直接下载
网盘下载
●════════════════════●

科技大类


直接下载
网盘下载
●════════════════════●

封面图合集


网盘下载

前言

最近看了下这方面的资料,顺便也做个整理记录,就先以用得较广泛的ETC1纹理压缩开个头,着重讲下是如何把ETC数据还原成RGB图像数据。
主要是基于这篇资料的翻译和理解,如有错漏之处,还望斧正。

介绍

Ericsson Texture Compression (ETC)是由 Khronos 支持的开放标准,在移动平台中广泛采用。它是一种为感知质量设计的有损算法,其依据是人眼对亮度改变的反应要高于色度改变。对于24位的RGB数据,提供6倍的压缩率。最大的弊端是不支持Alpha通道的存储,不过在后续的ETC2中也得到了支持。 维基百科

原理

ETC的压缩纹理以4x4的像素块为单位的方式描述出来。如果纹理在任意方向小于4个像素,那么只有位于左上角的像素块才是可用的。

    单个像素块
 ---- ---- ---- ---- 
|a   |e   |i   |m   |
|    |    |    |    |
 ---- ---- ---- ---- 
|b   |f   |j   |n   |
|    |    |    |    |
 ---- ---- ---- ---- 
|c   |g   |k   |o   |
|    |    |    |    |
 ---- ---- ---- ---- 
|d   |h   |l   |p   |
|    |    |    |    |
 ---- ---- ---- ---- 

一个4x4的像素块的数据用64bit的数据来表示。4x4的块被分成两个子块,垂直分(2x4)或者水平分(4x2),每一个子块有一组基础颜色(分别是RGB444/RGB444或RGB555/RGB333格式)、亮度索引、像素索引。
每个像素的颜色等于所属子块基础颜色加上索引指向的亮度修正。

        垂直分块

 子块 1     子块 2
 ---- ---- ---- ----
|a    e   |i    m   |
|         |         |
|         |         |
|b    f   |j    n   |
|         |         |
|         |         |
|c    g   |k    o   |
|         |         |
|         |         |
|d    h   |l    p   |
|         |         |
 ---- ---- ---- ----

        水平分块

 ---- ---- ---- ----
|a    e    i    m   |
|                   |
|                   | 子块 1
|b    f    j    n   |
|                   |
 -------------------
|c    g    k    o   |
|                   |
|                   | 子块 2
|d    h    l    p   |
|                   |
 ---- ---- ---- ----

下面讲下这64bit的数据是存放和使用的

子块基础颜色计算

2个子块的基础颜色根据32-63bit的数据而决定。ETC1里有两种模式:individual模式differential模式
这两种模式决定了子块存储的颜色是以RGB444/RGB444(individual模式)还是RGB555/RGB333(differential模式)格式存储颜色的数据,由bit 33(称为 diffbit)的值来决定,值为0时是individual模式,为1时是differential模式。

 32bit到63bit,当 diffbit = 0时的布局

 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48
 -----------------------------------------------
| base col1 | base col2 | base col1 | base col2 |
| R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)|
 -----------------------------------------------
 47 46 45 44 43 42 41 40 39 38 37 36 35 34  33  32
 ---------------------------------------------------
| base col1 | base col2 | table  | table  |diff|flip|
| B1 (4bits)| B2 (4bits)| cw 1   | cw 2   |bit |bit |
 ---------------------------------------------------

 32bit到63bit,当 diffbit = 1时的布局

 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 
 -----------------------------------------------
| base col1    | dcol 2 | base col1    | dcol 2 |
| R1' (5 bits) | dR2    | G1' (5 bits) | dG2    |
 -----------------------------------------------

 47 46 45 44 43 42 41 40 39 38 37 36 35 34  33  32 
 ---------------------------------------------------
| base col 1   | dcol 2 | table  | table  |diff|flip|
| B1' (5 bits) | dB2    | cw 1   | cw 2   |bit |bit |
 ---------------------------------------------------
  • Individual模式
    每个子块以RGB444/RGB444方式存储,将4bit颜色扩充为8bit,高4位和低4位相同
    举例:子块1存储的RGB数据是R1=14=1110b,G1=3=0011b,B1=8=1000b
    那么还原后的子块1基础RGB为R1=11101110b=238,G1=00110011b=51,B1=10001000b=136
    子块2同理

    base col subblock1 = extend_4to8bits(R1, G1, B1)
    base col subblock2 = extend_4to8bits(R2, G2, B2)

  • Differential模式
    子块1以RGB555,子块2以RGB333方式存储,子块1的颜色是以5bit的高3位作为扩充为8位之后的低3位
    举例:子块1存储的RGB数据是R1=28=11100b,G1=4=00100b,B1=3=00011b
    那么还原后的子块1基础RGB为R1=11100111b=231,G1=00100001b=33,B1=00011000b=24
    子块2计算时,先要通过和子块1存储的RGB叠加。把RGB333转为RGB555,然后再扩充为RGB888
    原有RGB333可看作是带符号位的,所以取值范围是[-4, 3]
    举例:和上面一样有R1’=28,的dR2=100b=-4,R1’+dR2=24=11000b,转成8bit则为,R2=11000110=198,G2B2同理

    base col subblock1 = extend_5to8bits(R1’, G1’, B1’)
    base col subblock2 = extend_5to8bits(R1’+dR2, G1’+dG2, B1’+dG2)

分块方式

分块方式根据bit 32来决定(称为flipbit),flipbit=0为垂直分(2x4),flipbit=1为水平分(4x2)。

像素RGB的最终确定

通过上面的步骤可以得出两个分块的基础颜色,然后需要确定每个像素的修正值,和基础颜色进行叠加,最后限定在[0, 255]内。

  • 亮度修正表
    亮度修正表定义了8组修正的值(固定不变的),每组包含4个值,具体的像素采用哪个修正值还需要通过修正结果映射表(下面会说到)来决定。
    继续引用上面表格,37bit到39bit这3bit存储的是子块1的亮度修正表索引,34bit到36bit是存了子块2的亮度修正表索引。
    举例:37bit到39bit的值为010b=2,则得到修正值为{-17,-5,5,17}
codewords modifier value1 modifier value2 modifier value3 modifier value4
0 -8 -2 2 8
1 -17 -5 5 17
2 -29 -9 9 29
3 -42 -13 13 42
4 -60 -18 18 60
5 -80 -24 24 80
6 -106 -33 33 106
7 -183 -47 47 183
  • 修正结果映射表
    0bit到31bit之间是记录4x4个像素采用的索引值,每个像素由2bit(msb和lsb)决定。
    0-15bit之间的值为lsb(least significant bit),16-31bit之间的值为msb(most significant bit),第一个像素对应0bit和16bit,第二个像素对应1bit和17bit…如此类推。
    msb和lsb可以称为像素下标位。
    上面已经根据亮度索引从亮度修正表里面得出了四个值,现在可以通过得到的msb和lsb,在修正结果映射表里面得到一个最终的修正值。
msb lsb 最后的修正值
1 1 modifier value1
1 0 modifier value2
0 0 modifier value3
0 1 modifier value4
  • 最终结果计算举例
    算出像素所在子块的基础色为(231, 8, 16),亮度修正索引为010b=2,对应值为{-29, -9, 9, 29},像素下标位为01b=1,所以取得修正值为29,叠加后得到(260, 37, 45),修正在[0, 255],所以最终结果是(255, 37, 45)

实现是利用C#的Process来执行外部程序,然后借助cmd来调用TortoiseProc(或者svn)命令行来进行svn操作
不过cmd命令行中对输入有长度限制,XP或更高版本命令行最大长度为8191个字符
如果超出限度的话,就需要将命令中的部分参数存成文本,然后再调用。

具体使用例子如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Collections.Generic;

public class Test
{
private void TestFunction()
{

string tmpFilePath = "C:\\SvnCommit.tmp";
List<string> commitFiles = new List<string>();
//commitFiles.Add(@"c:/commitFile1.txt");
//commitFiles.Add(@"c:/commitFile2.txt");
using (var s = File.Create(tmpFilePath))
{
using (var sw = new StreamWriter(s, new UnicodeEncoding(false, false)))
{
for (int i = 0, count = commitFiles.Count; i < count; ++i)
{
sw.Write(commitFiles[i] + '\n');
}
}
}

Execute("TortoiseProc /command:commit /pathfile:\"" + tmpFilePath + "\"", true);
}

public void Execute(string cmd, bool createNoWindow)
{

Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c " + cmd;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = createNoWindow;
p.Start();
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import requests
import json
from bs4 import BeautifulSoup


class JianShuItem(object):

def __init__(self, title, content):
super(JianShuItem, self).__init__()
self.title = title
self.content = content

def toObj(self):
obj = {}
obj["title"] = self.title
obj["content"] = self.content
return obj

def console(self):
print(self.title)
for c in self.content:
print(self.content[c])
print("=========================")


class JianShuCrawler(object):

def __init__(self):
super(JianShuCrawler, self).__init__()
self.stories = []

def loadPageItems(self, pageIndex):
url = 'http://www.jianshu.com/collections/38/notes?order_by=added_at&page=' + \
str(pageIndex)
response = requests.get(url)
soup = BeautifulSoup(response.text, "html.parser")
titles = soup.find_all('h4', class_="title")
for t in titles:
item = JianShuItem(t.select("a")[0].get_text(),
self.getDetail(t.select("a")[0]["href"]))
item.console()
self.stories.append(item.toObj())

def getDetail(self, url):
contentUrl = 'http://www.jianshu.com' + url
response = requests.get(contentUrl)
soup = BeautifulSoup(response.text, "html.parser")
content = soup.find('div', attrs={"class": "show-content"})
detailContent = content.select("p")
contentArr = {}
index = 0
for c in detailContent:
contentArr[index] = c.get_text()
index += 1
return contentArr

def start(self):
for i in range(10):
self.loadPageItems(i)
self.save()

def save(self):
jsonStr = json.dumps(self.stories)
print(jsonStr)
with open('data.txt', 'wt') as f:
f.write(jsonStr)

crawler = JianShuCrawler()
crawler.start()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using System;

// Reference:
// https://github.com/MattRix/UnityDecompiled/blob/master/UnityEngine/UnityEngine/Mathf.cs
// https://github.com/MattRix/UnityDecompiled/blob/master/UnityEngine/UnityEngineInternal/MathfInternal.cs
public class Test
{
public struct MathfInternal
{
public static volatile float FloatMinNormal = 1.17549435E-38f;
public static volatile float FloatMinDenormal = 1.401298E-45f;
public static bool IsFlushToZeroEnabled = MathfInternal.FloatMinDenormal == 0f;
}

public readonly float Epsilon = (!MathfInternal.IsFlushToZeroEnabled) ? MathfInternal.FloatMinDenormal : MathfInternal.FloatMinNormal;

public void TestFunc ()
{

float total = 1f;
float num = 0f;

for (int i = 0; i < 10; ++i)
{
num += 0.1f;
}

Console.WriteLine(num == total); // Print "False"
Console.WriteLine(Approximately(num, total)); // Print "True"
}

private bool Approximately (float a, float b)
{

return Math.Abs (b - a) < Math.Max (1E-06f * Math.Max (Math.Abs (a), Math.Abs (b)), Epsilon * 8f);
}
}

祝大家元宵节快乐 (′▽`〃)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/env python
# encoding: utf-8
import platform

a = "Hello"
b = "World"
print("%s %s!Python" % (a, b))
# 输出当前的python版本
print(platform.python_version())

'''
代码解析

Line1:使用环境配置的python解析器
指定用2.7的可以改为:#! python2.7
指定用3.*的可以改为:#! python3

Line2:指定编码为UTF-8,python3默认则为utf-8,可以不加

Line3:导入要使用的库

Line5-6:定义变量a为字符串"Hello",b变量为"Python"

Line7:输出,python3中print改为函数,%为格式化字符,+为连接字符串

Line8:单行注释用#

Line9:输出当前python版本

Line11-31:多行注释用三个单(双)引号
'''

MSYS2是什么

MSYS2 (Minimal SYStem 2) 是一个MSYS的独立改写版本,主要用于shell 命令行开发环境。 同时它也是一个在Cygwin (POSIX 兼容性层) 和MinGW-w64(从”MinGW-生成”)基础上产生的,追求更好的互操作性的Windows 软件。


中文乱码问题

在默认安装完后,会存在中文乱码的问题,通过下面提到的方法可以解决。

1. 设置字符编码

点击MSYS2窗口的左上角,打开Options,设置为UTF-8

2. 处理运行Win上命令的乱码

这样设置后,运行Win的命令还是会出现乱码(比如ping,ipconfig等)

现象

1
2
3
4
5
6
7
8
9
10
11
12
$ ping google.com

▒▒▒▒ Ping google.com [216.58.221.142] ▒▒▒▒ 32 ▒ֽڵ▒▒▒▒▒:
▒▒▒▒ 216.58.221.142 ▒Ļظ▒: ▒ֽ▒=32 ʱ▒▒=9ms TTL=48
▒▒▒▒ 216.58.221.142 ▒Ļظ▒: ▒ֽ▒=32 ʱ▒▒=10ms TTL=48
▒▒▒▒ 216.58.221.142 ▒Ļظ▒: ▒ֽ▒=32 ʱ▒▒=10ms TTL=48
▒▒▒▒ 216.58.221.142 ▒Ļظ▒: ▒ֽ▒=32 ʱ▒▒=9ms TTL=48

216.58.221.142 ▒▒ Ping ͳ▒▒▒▒Ϣ:
▒▒▒ݰ▒: ▒ѷ▒▒▒ = 4▒▒▒ѽ▒▒▒ = 4▒▒▒▒ʧ = 0 (0% ▒▒ʧ)▒▒
▒▒▒▒▒г̵Ĺ▒▒▒ʱ▒▒(▒Ժ▒▒▒Ϊ▒▒λ):
▒▒▒ = 9ms▒▒▒ = 10ms▒▒ƽ▒▒ = 9ms

解决方案

新建/usr/bin/win

1
2
#!/bin/bash
$@ |iconv -f gbk -t utf-8

新建/etc/profile.d/alias.sh

1
2
3
4
5
6
7
8
alias ls="/bin/ls --color=tty --show-control-chars"
alias grep="/bin/grep --color"
alias ll="/bin/ls --color=tty --show-control-chars -l"

alias ping="/bin/win ping"
alias netstat="/bin/win netstat"
alias nslookup="/bin/win nslookup"
alias ipconfig="/bin/win ipconfig"

效果:

1
2
3
4
5
6
7
8
9
10
11
12
$ ping google.com

正在 Ping google.com [216.58.221.46] 具有 32 字节的数据:
来自 216.58.221.46 的回复: 字节=32 时间=8ms TTL=48
来自 216.58.221.46 的回复: 字节=32 时间=9ms TTL=48
来自 216.58.221.46 的回复: 字节=32 时间=9ms TTL=48
来自 216.58.221.46 的回复: 字节=32 时间=9ms TTL=48

216.58.221.46 的 Ping 统计信息:
数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
最短 = 8ms,最长 = 9ms,平均 = 8ms

如何使用七牛图床

关于图床

图床,就是用来存放图片的空间,同时允许外链到其他网站。
将图片放到图床然后在博客里引用主要有一下几点好处:

  • 减少博客空间的访问流量
  • 便于管理图片
  • 加快网页访问速度
  • 方便对图片进行二次加工,如:加水印,调整图片尺寸等等

关于七牛

考虑访问速度,优先选择国内图床。
查找了下相关资料,发现有不少的人推荐使用七牛,使用稳定,并且免费用户也能有一定流量。
还能处理图片,例如加水印、放盗链等。

有哪些适合开发人员的图床?

如何使用

1.注册

进入七牛的注册界面,填写信息后通过邮件激活就完成注册了。
注册成功后成为体验用户

体验用户免费额度:
储存空间1GB、每月下载流量1GB、创建1个空间

2.上传图片

注册成功后,在首页先新建空间

点击“内容管理”——点击“上传”

由于没有目录结构,为避免图片重名,建议使用 自定义前缀


上传成功后,可以在这里看到外链地址。

3.图片加工

为了防止图片被盗用以及标识图片的个人信息,一般会对图片进行加水印处理

点击“数据处理”——点击“新建图片样式”

输入图片样式名称(后面会用到),然后进行水印设置(支持文字水印、图片水印)

除了水印之外,还可以对图片的尺寸,质量进行修正处理。感兴趣的可以试试

使用处理后的图片

在原有的图片外链后加上样式分隔符(默认为“-”)和样式名称,就可以得到水印图片了。例如:

使用处理后的图片,访问链接: http://domain/a.png-default