近期规划遇到一个需求,项目中所用颜色需要使用潘通色卡上的颜色,他们给我一套某宝购买的色卡集(共计2625个潘通色)以作参考,长这样
在与公司纺织专业的同事沟通过后,了解到他们为了工作方便,还有一个扫码枪,扫一下色卡或布料,就能得到色块信息,神奇~
通过数小时的研究,总结出色卡上的关键信息有
类型 | 含义 |
---|---|
Color Nr. | 潘通色号 |
Name | 颜色名字 |
Book | 在哪本色卡集 |
Page | 在哪一页 |
Row | 在哪一行 |
Hex Code | 16进制颜色值 (未印制在色卡上) |
RGB | 10进制颜色值 (未印制在色卡上) |
参考的网站:
在潘通·国际上看到有FIND A PANTONE COLOR,如果我猜得没错的话,这个可以查找官方提供的潘通色注册免费账号(不要钱的就是香)通过一番摸索,终于在Color选项找到了查找潘通色的入口设置到对应选项 FHI Paper TPG右侧设置竟还能设置色块布局(这个设计很友好嘛)看到上面结果的时候,我的内心狂喜,心想这需求很简单嘛,马上搞定。
BUT!很快我就发现,潘通官网在这里设置了障碍。F12查看网页源代码,并没有发现关于任何关于色块的html代码,卒~好消息是无意间点击色块,在弹出框中选择GET PHYSICAL SAMPLE,发现一个可以根据色号查询色号信息的接口(https://www.pantone.com/connect/)
国际网找不到,那么就在潘通·中国上找寻PANTONE色彩查找TPG但只搜到了2310个结果,与色卡上的2625还差315个潘通色。
不过,有比没有强,先把搜索到的内容格式化存储到文本。F12查看网页源代码,找到色块所在DOM,复制元素到txt文档。
将字符串赋值到js文件中的一个变量分析html代码,提取关键信息data-color-code、data-hex-code、style:background-color,这里用正则表达式最方便了
<script>
const colorCodeRegx = /(data-color-code)=[^\s][^"]+/gi;
const hexCodeRegx = /(data-hex-code)=[^\s>]+/gi;
const colorRegx = /]*style=\"([^">]+)\"[^>]*>/ig;
const listOfColorCode = str.match(colorCodeRegx);
const listOfHexCode = str.match(hexCodeRegx);
const listOfColor = str.match(colorRegx);
const listOfResult = listOfColor.map((item, index) => {
return {
color_code: listOfColorCode[index].match(/(?<=data-color-code\=").+/ig)[0],
hex_code: listOfHexCode[index].match(/(?<=data-hex-code\=").+[^"]/ig)[0],
rgb: item.match(/(?<=rgb\().+(?=\);")/ig)[0]
}
});
console.log(JSON.stringify(listOfResult));
</script>
将匹配后的格式化文本粘贴到txt文档。接下来就是考虑新增的那315个色号怎么整了。。。
3. 探索Torso
继续搜索,一番操作后,发现一个神奇的网站Torso,竟然可以下载潘通色卡的目录PDF。最最神奇的是该目录包含2020年完整的2625个色号,以及新增哪些色号(绿色标注)。
二、分析现有资料
1. 我有什么?
2310个色号信息(来源:潘通·中国)、2625个色号的目录(来源:Torso)、色号查询接口(来源:潘通·国际)
2. 我能做什么?
将已有的2310个色号信息添加到对应目录中;对于新增的315个色号,可以通过色号查询接口按照色号进行查询。
三、工程实施
1. 格式化2310个数据信息
public struct PantoneInfo
{
public string color_code;
public string hex_code;
public string rgb;
}
PantoneInfo[] pantoneInfos;
public void ReadTPGColor()
{
using (FileStream fs = new FileStream("TPGColor2310.txt", FileMode.Open, FileAccess.Read))
{
StreamReader reader = new StreamReader(fs, Encoding.UTF8);
pantoneInfos = JsonConvert.DeserializeObject<PantoneInfo[]>(reader.ReadLine().Trim());
reader.Close();
fs.Close();
}
}
2. 根据色号查询信息
void GetColorFromRequest(string ColorNr, ref string hex_code, ref string rgb)
{
try
{
WebRequest request = WebRequest.Create("https://www.pantone.com/connect/" + ColorNr);
WebResponse response = request.GetResponse();
Stream receiveStream = response.GetResponseStream();
StreamReader reader = new StreamReader(receiveStream, Encoding.UTF8);
//获取网页源代码
string html = reader.ReadToEnd();
reader.Close();
receiveStream.Close();
response.Close();
int resultIndex = html.IndexOf("window.pageDataJson = ");
int startIndex = html.IndexOf("{", resultIndex);
int endIndex = html.IndexOf("};", startIndex);
string jsonStr = html.Substring(startIndex, endIndex - startIndex + 1);
JObject jsonData = JsonConvert.DeserializeObject(jsonStr) as JObject;
JObject colorJsonData = JsonConvert.DeserializeObject(jsonData["color"].ToString()) as JObject;
JObject hexJsonData = JsonConvert.DeserializeObject(colorJsonData["hex"].ToString()) as JObject;
JObject rgbJsonData = JsonConvert.DeserializeObject(colorJsonData["rgb"].ToString()) as JObject;
hex_code = hexJsonData["HTML"].ToString();
rgb = $"{rgbJsonData["Red"]},{rgbJsonData["Green"]},{rgbJsonData["Blue"]}";
}
catch (Exception e)
{
CLog.LogLine(CLog.LogType.Log, "");
CLog.LogLine(CLog.LogType.Error, $"[ERROR] Get Nr.{ColorNr} Failed! -- {e.Message}");
hex_code = "";
rgb = "";
}
}
3. 数据化目录pdf
将在Torso上下载的pdf文档中的信息复制到txt文档,分析文本格式,读取已有的2310个色号信息,数据化目录
public struct PantoneInfoWithPageRow
{
public string nr;
public string name;
public int book;
public int page;
public int row;
public string hexCode;
public string rgb;
}
List<PantoneInfoWithPageRow> pantoneInfoWithPageRows = new List<PantoneInfoWithPageRow>(2625);
List<PantoneInfoWithPageRow> sorted;
public void FormatOriginTxt()
{
string lineStr = "";
using (FileStream readFS = new FileStream("PantoneColor.txt", FileMode.Open, FileAccess.Read))
{
StreamReader reader = new StreamReader(readFS, Encoding.UTF8);
string ColorNr, Name, Book, Page, Row, HexCode = "", RGB = "", Update;
int arrLen, index;
string[] lineArray;
string[] nameArray;
CLog.LogLine(CLog.LogType.Log, $"-------------------------------------------------------");
while (reader.Peek() != -1)
{
ColorNr = Name = Book = Page = Row = HexCode = RGB = Update = "";
arrLen = index = -1;
lineArray = nameArray = null;
lineStr = reader.ReadLine().Trim();
if (!string.IsNullOrEmpty(lineStr))
{
lineArray = lineStr.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
arrLen = lineArray.Length;
ColorNr = lineStr.Substring(0, 19);
ClearCurrentConsoleLine();
CLog.Log(CLog.LogType.Log, $"Processing ColorNr: {ColorNr}");
nameArray = new string[arrLen - 10];
for (int i = 0; i < arrLen - 10; i++)
{
nameArray[i] = lineArray[i + 3];
}
Name = CombineStringWithUpperFirst(" ", nameArray);
Book = lineArray[arrLen - 7];
Page = lineArray[arrLen - 6].Substring(2, 3);
Row = lineArray[arrLen - 5];
//1.New Color 2.No Change 3.New Page
Update = CombineStringWithUpperFirst(" ", lineArray[arrLen - 2], lineArray[arrLen - 1]);
//根据Update的值判断如何对hexCode和rgb赋值
if (Update.Equals("New Color"))
{
//把色号传入查询接口
GetColorFromRequest(ColorNr.Substring(8, 11), ref HexCode, ref RGB);
}
else
{
//根据色号取值
index = FindColorInfoWithNr(ColorNr);
if (index == -1)
{
HexCode = "";
RGB = "";
}
else
{
HexCode = pantoneInfos[index].hex_code;
RGB = pantoneInfos[index].rgb;
}
}
pantoneInfoWithPageRows.Add(new PantoneInfoWithPageRow()
{
nr = ColorNr,
name = Name,
book = int.Parse(Book),
page = int.Parse(Page),
row = int.Parse(Row),
hexCode = HexCode,
rgb = RGB
});
}
}
//关闭文件流
reader.Close();
readFS.Close();
CLog.LogLine(CLog.LogType.Log, "");
CLog.LogLine(CLog.LogType.Log, "-------------------------------------------------------");
}
}
//根据色号在已有的2310个色号中查找信息
int FindColorInfoWithNr(string name)
{
for (int i = 0; i < pantoneInfos.Length; i++)
{
if (name.Contains(pantoneInfos[i].color_code))
{
return i;
}
}
return -1;
}
//连接字符串 “New”、“Color” --> “New Color”
string CombineStringWithUpperFirst(string combineChar, params string[] str)
{
if (str.Length == 0)
{
return "";
}
string tmp = "";
for (int i = 0; i < str.Length - 1; i++)
{
tmp += ToUpperFirst(str[i]) + combineChar;
}
tmp += ToUpperFirst(str[str.Length - 1]);
return tmp;
}
//首字母大写
unsafe string ToUpperFirst(string str)
{
if (str == null) return null;
string ret = string.Copy(str);
fixed (char* ptr = ret)
{
*ptr = char.ToUpper(*ptr);
}
return ret;
}
4. 对数据化的色号目录进行排序(Book、Page、Row均由大到小)
List<PantoneInfoWithPageRow> sorted;
public void PageSort()
{
int index = -1;
int book = 2;
int page = 200;
int row = 7;
int count = pantoneInfoWithPageRows.Count;
sorted = new List<PantoneInfoWithPageRow>();
for (int i = 0; i < count; i++)
{
ClearCurrentConsoleLine();
CLog.Log(CLog.LogType.Log, $"Processing Book: {book} Page: {page} Row: {row}");
while (true)
{
index = FindPageRowWithBook(book, page, row);
if (index == -1)
{
row--;
if (row == 0)
{
row = 7;
page--;
if (page == 0)
{
page = 200;
row = 7;
book--;
if (book == 0)
{
break;
}
}
}
}
else
{
break;
}
}
if (index != -1)
{
sorted.Add(pantoneInfoWithPageRows[index]);
row--;
if (row == 0)
{
row = 7;
page--;
if (page == 0)
{
row = 7;
page = 200;
book--;
if (book == 0)
{
break;
}
}
}
}
}
CLog.LogLine(CLog.LogType.Log, "");
}
5. 逆序后输出最终文档
public void WriteSortedFile()
{
using (FileStream writeFS = new FileStream("PantoneColorFormatPageRow.txt", FileMode.Create, FileAccess.Write))
{
StreamWriter writer = new StreamWriter(writeFS, Encoding.UTF8);
writer.WriteLine(string.Format("{0,-13}{1,-25}{2,-20}{3,-10}{4,-10}{5,-10}{6,-10}{7,-10}", "Number", "Color Nr.", "Name", "Book", "Page", "Row", "Hex Code", "RGB"));
int count = sorted.Count;
sorted.Reverse();
for (int i = 0; i < count; i++)
{
writer.WriteLine(string.Format("No.{0,-10:D4}{1,-25}{2,-20}{3,-10}{3}.{4,-8:D3}{5,-10}{6,-10}{7,-10}",
i + 1,
sorted[i].nr,
sorted[i].name,
sorted[i].book,
sorted[i].page,
sorted[i].row,
sorted[i].hexCode,
sorted[i].rgb.Replace(" ", "")));
}
writer.Flush();
writer.Close();
writeFS.Close();
CLog.LogLine(CLog.LogType.Log, "Write Over! Press Any Key To Continue!");
}
}
总结
遇到新需求还是不能太掉以轻心,应多收集资料,将资料汇总后,找到之前的关系,合理利用。