这个小软件用来把一张像素很低的二维码图片变成像素很高,而且大小很小的二维码图片。
使用之前需要提前处理小尺寸的二维码图片,不能留边缘,像这样:
只要能确保这张图片被划分成37x37份之后,生成的37x37个采样点,能够准确地落到每一个小方块上就行了。
ch01.py
import os
from PIL import Image, ImageDraw
from const import *
from ch02 import *
from datetime import datetime as datet
import errno
aa = r'D:\0003\1122.jpg'
class CHHUI:
def __init__(self, path_full):
self.path_full = path_full
# 初始化二维列表,用于存储颜色信息
self.list_ks = [[] for _ in range(37)]
self.dict_ks = [{} for _ in range(37)]
# 打开图片
def open_tu(self):
print('001')
# 获取当前工作目录
self.workpath = os.getcwd()
print(f'当前脚本工作目录为:{self.workpath}\n')
# 分离目录和文件名
self.mulu, self.full_filename = os.path.split(self.path_full)
print(f"mulu:{self.mulu}")
# 分离文件名和扩展名
self.filename, self.extension = os.path.splitext(self.full_filename)
print(f"文件名:{self.filename}")
print(f"扩展名:{self.extension}")
self.original_image = Image.open(self.path_full)
print('成功打开图片\n')
# 初始化操作图片
def initial_tu(self):
print('002')
# 转换为灰度图像,以减少计算
self.gray_image = self.original_image.convert('L')
# 图片的尺寸
width, height = self.gray_image.size
print(f'原图宽高:[{width}, {height}]')
# 确定间隔,赋值覆盖
self.aa = width / 37 # 单位小方块的长度
self.aaa = self.aa/2 # 采样点的偏移量(使落到中心)
self.bb = height / 37
self.bbb = self.bb/2
print(f'采样点水平间隔:{self.aa}\n垂直间隔:{self.bb}')
print('\n图片已转为灰度图像,采样点已完成初始化\n')
# 开始对图片采样
def cai_tu(self):
print('003')
color = '-'
# 遍历图片的每个像素
for iy in range(37): # 0-36
for ix in range(37): # 0-36
# 确定采样点
xy = ((self.aaa+ix*self.aa),(self.bbb+iy*self.bb))
# .getpixel()方法需要传入一个规范书写的元组,如果传入不带括弧的元祖则会被视为传入了多个位置参数!
pixel_value = self.gray_image.getpixel(xy) # 从指定像素获取灰度值
# 灰度值小于230则为黑色
if pixel_value < YYY:
color = 1
else:
color = 0
self.list_ks[iy].append(color)
x = xy[0]
y = xy[1]
self.dict_ks[iy][ix] = (x, y, pixel_value, color)
print('已完成37x37个采样点的遍历\n')
# 打开一个txt文件用于记录采样数据
def write_tu(self):
print('004')
# 定义你想要创建的目录的路径
directory_path = os.path.join(self.workpath, 'work')
# 使用os.makedirs()创建目录
try:
os.makedirs(directory_path)
print(f"目录 '{directory_path}' 已成功创建。")
except OSError as e:
if e.errno == errno.EEXIST: # 如果目录已存在,则忽略这个错误
print(f"目录 '{directory_path}' 已存在。")
else:
print(f"在创建目录时发生错误: {e}")
# 创建一个 datetime 对象
now = datet.now()
# 使用 strftime 方法将 datetime 对象格式化为字符串
formatted_date = str(now.strftime("%Y-%m-%d %H-%M-%S"))
print(formatted_date)
Txt_1 = os.path.join(directory_path, f'{formatted_date}_c3.txt')
with open(Txt_1, 'w') as file:
for row in self.list_ks:
file.write(' '.join(map(str, row)) + '\n')
# ' '.join将每行的整数列表转换为由空格分隔的字符串, map(str, row) 将整数列表转换为字符串列表
Txt_2 = os.path.join(directory_path, f'{formatted_date}_xx3.txt') # os.path.join(self.mulu, 'x3.txt')
with open(Txt_2, 'w') as file2:
ii = 0
for i in range(37):
for j in range(37):
ii = self.dict_ks[i][j]
# print(ii)
iii = str(ii)
file2.write(f'{i}, {j}, {iii}\n') # 写入文件并添加换行符
print('写完了\n')
def draw_new(self):
print('005')
img_width = BLOCK_SIZE * 37 + BORDER * 2
img_height = BLOCK_SIZE * 37 + BORDER * 2
# 创建一张空白图片,背景色为白色
self.image = Image.new('RGBA', (img_width, img_height),color=(255, 255, 255, 0))
# 创建一个可以在给定图片上绘图的对象
self.draw = ImageDraw.Draw(self.image)
print(f'将要绘制尺寸{BORDER*2 + BLOCK_SIZE*37}像素的方形图片(含{BORDER}像素的出血边)')
inf = str(MODE)
# 解读快速指令,选择模式
if inf[1] == '1':
if inf[0] == '1':
self.fill_color1 = (0, 0, 0, 255) # 黑色-黑色
print('黑色为黑色')
else:
self.fill_color1 = (255, 255, 255, 255) # 白色
print('黑色为白色')
else:
self.fill_color1 = (0, 0, 0, 0) # 黑色-透明
print('黑色为透明')
if inf[3] == '1':
if inf[2] == '0':
self.fill_color0 = (255, 255, 255, 255) # 原色
print('白色为白色')
else:
self.fill_color0 = (0, 0, 0, 255) # 反相
print('白色为黑色')
else:
self.fill_color0 = (255, 255, 255, 0) # 透明
print('白色为透明')
# 遍历列表并绘制矩形
for j in range(37):
for i in range(37):
if self.list_ks[j][i] == 1: # 识别为黑色矩形
# 绘制矩形,根据左上角坐标和右下角坐标
self.draw.rectangle([(BORDER+i*BLOCK_SIZE,BORDER+j*BLOCK_SIZE), (BORDER+(1+i)*BLOCK_SIZE, BORDER+(1+j)*BLOCK_SIZE)], fill=self.fill_color1)
elif self.list_ks[j][i] == 0: # 识别为白色矩形
# 绘制矩形,根据左上角坐标和右下角坐标
self.draw.rectangle([(BORDER+i*BLOCK_SIZE,BORDER+j*BLOCK_SIZE), (BORDER+(1+i)*BLOCK_SIZE, BORDER+(1+j)*BLOCK_SIZE)], fill=self.fill_color0)
else:
print('画手犯病了')
# print(f'{j},{i},{fill_color}')
fill_fu = (0, 0, 0, 255)
# 先画一个矩形做背景板
self.draw.rectangle([(BORDER+BLOCK_SIZE*14,BORDER+BLOCK_SIZE*14), (BORDER+BLOCK_SIZE*(14+9),BORDER+BLOCK_SIZE*(14+9))], fill=fill_fu)
# 先对原始的logo形状参数列表“缩放”,以确保尺寸适合新图像
self.xy = scale_list(WX_LOGO_XY)
print(self.xy)
# 绘制logo
for u in range(7):
self.draw.ellipse(self.xy[u], fill= (0, 0, 0, WX_LOGO_AP[u]))
for u in range(7,9):
self.draw.polygon(self.xy[u], fill= (0, 0, 0, WX_LOGO_AP[u]))
print('画完了\n')
def save_new(self):
print('006')
# 保存图片
self.image.save(rf'{self.mulu}\{self.filename}-1.5.png')
print(f'图像已保存至\n{self.mulu}\{self.filename}-1.5.png\n')
def work(self):
self.open_tu()
self.initial_tu()
self.cai_tu()
self.write_tu()
self.draw_new()
self.save_new()
cc3 = r'D:\BaiduSyncdisk\Pythonxx\重绘二维码\洛阳店-二维码.jpg'
if __name__ == '__main__':
print('\n---2024.7.1---\n')
aa = CHHUI(PATH_CC[2])
aa.work()
print('---end---')
ch02.py
from const import *
SCALE = (BLOCK_SIZE*6) / 1000
OFFSET = (BORDER+BLOCK_SIZE*15.5)
def scale_list(input_list):
print(f"中心logo需要缩放{SCALE}倍\n从{OFFSET}开始")
# 初始化一个新的列表来存储结果
result = []
ii = 0
# 遍历输入列表中的每个元素
for item in input_list:
ii += 1
# 检查元素是否是列表
if isinstance(item, list):
# 如果是列表,则创建一个新的列表,并遍历原始列表中的每个元组(这是由于我们事先知道它的结构)
new_item = []
for iuu in item:
new_iuu = tuple(round(iu * SCALE + OFFSET) for iu in iuu)
new_item.append(new_iuu)
# 将新的列表添加到结果列表中
result.append(new_item)
elif isinstance(item, tuple):
# 如果是元组,则创建一个新的元组,并遍历原始元组中的每个元素
new_item = tuple(round(num * SCALE + OFFSET) for num in item)
# 将新的元组添加到结果列表中
result.append(new_item)
# 每个一级元素会依次被追加到结果中,它们的顺序不会混乱
return result
if __name__ == '__main__':
# 调用函数并打印结果
scaled_WX_LOGO_XY = scale_list(WX_LOGO_XY)
print('---运算完成---\n')
print(scaled_WX_LOGO_XY)
print('\n---end---')
const.py
BLOCK_SIZE = 40 # 单位尺寸
BORDER = 0 # 出血边
YYY = 200
PATH_CC = [
r'重绘二维码\海特店1080.jpg',
r'D:\BaiduSyncdisk\Pythonxx\重绘二维码\海特店1080.jpg',
r'..\..\..\BaiduSyncdisk\Pythonxx\重绘二维码\洛阳店.png',
r'\BaiduSyncdisk\Pythonxx\重绘二维码\海特店1080.jpg'
]
PATH_CCC = [
r'重绘二维码\海特店1080.jpg',
r'D:\BaiduSyncdisk\Pythonxx\重绘二维码\海特店1080.jpg',
r'..\..\..\BaiduSyncdisk\Pythonxx\重绘二维码\洛阳店.png',
r'\BaiduSyncdisk\Pythonxx\重绘二维码\海特店1080.jpg'
]
# .. 表示上一级目录。这是一个特殊的路径元素,用于导航到当前目录的父目录。
# \ 是路径分隔符,用于分隔目录和文件名。
MODE = 1100
# 手动选择的模式,可以用于反转黑白、增加透明区域等
# 原始的logo坐标列表
WX_LOGO_XY = [
(0,92,715,692),
(376,338,974,896),
(399,358,1000,870),
(187,240,283,336),
(434,240,530,336),
(566,496,647,577),
(760,496,841,577),
[(143,628), (107,738), (240,670)],
[(796,847), (874,814), (902,906)],
]
WX_LOGO_AP = [
0,
255,
0,
255,
255,
255,
255,
0,
0,
]
'''
WX_LOGO_AP = [
255,
0,
255,
0,
0,
0,
0,
255,
255,
]
'''
if __name__ == "__main__":
print([i for i in range(10)])
print(PATH_CCC[2])
import os
print(f'当前脚本工作目录为:{os.getcwd()}\n')
relative_path = PATH_CCC[2]
if os.path.exists(relative_path):
print("文件存在")
else:
print("文件不存在")
摸鱼写的,基本功能是完整的,鸡肋功能是不少的。
使用PS的魔棒和图层蒙版可以直接完成这个任务,但是会出现像素级别的误差。使用Illustrator可以没有像素级别的误差,但是效率很低,很费眼睛。
刚实现基础功能的时候,只写了一百多行。但是最后封装的时候突然多了很多想法,多增加了好几个功能,封装完之后总共三个脚本: