bmp-resize-python/main.py

265 lines
8.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from math import floor
from tqdm import tqdm
################## 数据输入 Start ##################
# 输入数据
# img = input("请输入图片路径:")
# new_width = int(input("请输入新宽度(px)"))
# new_height = int(input("请输入新高度(px)"))
# print("模式 0 直接缩放")
# print("模式 1 高斯模糊缩放")
# mode = int(input("请输入模式:"))
img = 'imgs/1/2x1.bmp'
new_width = 512
new_height = 512
mode = 0
if (mode != 1):
mode = 0
################## 数据输入 End ##################
################## 文件读入 Start ##################
# 读入图片
with open(img, 'rb') as f:
imgBytes = f.read()
for _ in tqdm(range(len(imgBytes)), "读入文件中"):
pass
################## 文件读入 End ##################
# 十六进制转十进制
def byteSize(begin, length):
size = 0
for i in range(length):
size += imgBytes[i + begin] * 16**(2 * i)
return size
# 十进制转十六进制
def sizeByte(size, length):
b = []
while (size):
b.append(size // 16**((length - len(b) - 1) * 2))
size %= 16**((length - len(b)) * 2)
b.extend([0] * (length - len(b)))
return b[::-1]
################## 文件头处理 Start ##################
# 位图文件头
# 检验文件头是否为 BM
if (imgBytes[0] != 66 or imgBytes[1] != 77):
print("当前文件非 BMP 格式")
exit()
fileSize = byteSize(2, 4) #文件头中的文件大小
dataStart = byteSize(10, 4) #文件头中的数据开始字节
# bmp 文件头
headerSize = byteSize(14, 4) #该头结构的大小40字节
width = byteSize(18, 4) #位图宽度,单位为像素(有符号整数)
height = byteSize(22, 4) #位图高度,单位为像素(有符号整数)
nbplan = byteSize(26, 2) #色彩平面数只有1为有效值
bpp = byteSize(28, 2) #每个像素所占位数即图像的色深。典型值为1、4、8、16、24和32
compression = byteSize(30, 4) #所使用的压缩方法,可取值见下表。
imageSize = byteSize(34, 4) #图像大小。指原始位图数据的大小(详见后文),与文件大小不是同一个概念。
wppm = byteSize(38, 4) #图像的横向分辨率,单位为像素每米(有符号整数)
hppm = byteSize(42, 4) #图像的纵向分辨率,单位为像素每米(有符号整数)
colorsNum = byteSize(46, 4) #调色板的颜色数为0时表示颜色数为默认的2^色深个
icolorsNum = byteSize(50, 4) #重要颜色数为0时表示所有颜色都是重要的通常不使用本项
colorsBoard = imgBytes[54:dataStart] #调色板
colors = []
i = 0
while (i < len(colorsBoard)):
colors.append({
'r': colorsBoard[i],
'g': colorsBoard[i + 1],
'b': colorsBoard[i + 2],
'a': colorsBoard[i + 3],
})
i += 4
################## 文件头处理 End ##################
################## 像素点读入 Start ##################
# 变量预处理
pixels = []
for i in range(height):
pixels.append([])
rowLength = floor(width * bpp / 8)
while (rowLength % 4 != 0 or rowLength == 0):
rowLength += 1
# 计算像素点
i = dataStart
for currentRow in tqdm(range(height), "读入像素点中"):
currentCol = 0
while (currentCol < width * (bpp // 8)):
if (bpp == 32):
pixels[currentRow].append({
'r':
imgBytes[dataStart + currentRow * rowLength + currentCol],
'g':
imgBytes[dataStart + currentRow * rowLength + currentCol + 1],
'b':
imgBytes[dataStart + currentRow * rowLength + currentCol + 2],
'a':
imgBytes[dataStart + currentRow * rowLength + currentCol + 3]
})
currentCol += bpp // 8
else:
pixels[currentRow].append({
'r':
imgBytes[dataStart + currentRow * rowLength + currentCol],
'g':
imgBytes[dataStart + currentRow * rowLength + currentCol + 1],
'b':
imgBytes[dataStart + currentRow * rowLength + currentCol + 2]
})
currentCol += bpp // 8
# 读入图片为像素数组完成
# 缩放图片
# 变量预处理
scale_w = new_width / width
scale_h = new_height / height
newpixels = []
for i in range(new_height):
newpixels.append([])
# 计算新像素
for currentRow in tqdm(range(new_height), "计算新像素点中"):
for currentCol in range(new_width):
ori_row = floor(currentRow / scale_h)
ori_col = floor(currentCol // scale_w)
newpixels[currentRow].append(pixels[ori_row][ori_col])
# 处理新文件
newimgArray = [66, 77]
rowLength = new_width
rowLength *= bpp // 8
while (rowLength % 4 != 0):
rowLength += 1
# 新文件头
new_fileSize = 54 + rowLength * new_height #文件头中的文件大小
newimgArray.extend(sizeByte(new_fileSize, 4))
newimgArray.extend(sizeByte(0, 4))
new_dataStart = dataStart
newimgArray.extend(sizeByte(new_dataStart, 4))
# 新 bmp 文件头
new_headerSize = headerSize
newimgArray.extend(sizeByte(headerSize, 4))
new_width_b = sizeByte(new_width, 4)
newimgArray.extend(new_width_b)
new_height_b = sizeByte(new_height, 4)
newimgArray.extend(new_height_b)
new_nbplan = nbplan
newimgArray.extend(sizeByte(new_nbplan, 2))
new_bpp = bpp
newimgArray.extend(sizeByte(bpp, 2))
new_compression = compression
newimgArray.extend(sizeByte(new_compression, 4))
new_imageSize = rowLength * new_height
newimgArray.extend(sizeByte(new_imageSize, 4))
# 调色板不做处理
newimgArray.extend(sizeByte(0, new_headerSize + 14 - len(newimgArray)))
def flur(row, col):
if (row - 1 < 0):
row = new_height + 1
if (row + 1 >= new_height):
row = 0
if (col - 1 < 0):
col = new_width + 1
if (col + 1 >= new_width):
col = 0
p = [0.0947416, 0.118318, 0.147761]
r = floor(newpixels[row - 1][col - 1]['r'] * p[0] +
newpixels[row - 1][col + 1]['r'] * p[0] +
newpixels[row + 1][col - 1]['r'] * p[0] +
newpixels[row + 1][col + 1]['r'] * p[0] +
newpixels[row][col + 1]['r'] * p[1] +
newpixels[row][col - 1]['r'] * p[1] +
newpixels[row - 1][col]['r'] * p[1] +
newpixels[row + 1][col]['r'] * p[1] +
newpixels[row][col]['r'] * p[2])
g = floor(newpixels[row - 1][col - 1]['g'] * p[0] +
newpixels[row - 1][col + 1]['g'] * p[0] +
newpixels[row + 1][col - 1]['g'] * p[0] +
newpixels[row + 1][col + 1]['g'] * p[0] +
newpixels[row][col + 1]['g'] * p[1] +
newpixels[row][col - 1]['g'] * p[1] +
newpixels[row - 1][col]['g'] * p[1] +
newpixels[row + 1][col]['g'] * p[1] +
newpixels[row][col]['g'] * p[2])
b = floor(newpixels[row - 1][col - 1]['b'] * p[0] +
newpixels[row - 1][col + 1]['b'] * p[0] +
newpixels[row + 1][col - 1]['b'] * p[0] +
newpixels[row + 1][col + 1]['b'] * p[0] +
newpixels[row][col + 1]['b'] * p[1] +
newpixels[row][col - 1]['b'] * p[1] +
newpixels[row - 1][col]['b'] * p[1] +
newpixels[row + 1][col]['b'] * p[1] +
newpixels[row][col]['b'] * p[2])
if (new_bpp // 8 == 3):
return [r, g, b]
else:
a = floor(newpixels[row - 1][col - 1]['a'] * p[0] +
newpixels[row - 1][col + 1]['a'] * p[0] +
newpixels[row + 1][col - 1]['a'] * p[0] +
newpixels[row + 1][col + 1]['a'] * p[0] +
newpixels[row][col + 1]['a'] * p[1] +
newpixels[row][col - 1]['a'] * p[1] +
newpixels[row - 1][col]['a'] * p[1] +
newpixels[row + 1][col]['a'] * p[1] +
newpixels[row][col]['a'] * p[2])
return [r, g, b, a]
for i in tqdm(range(len(newpixels)), "将像素点格式化中"):
row = newpixels[i]
for col in range(len(row)):
if (mode == 0):
if (new_bpp // 8 == 3):
pixel = [
newpixels[i][col]['r'], newpixels[i][col]['g'],
newpixels[i][col]['b']
]
else:
pixel = [
newpixels[i][col]['r'], newpixels[i][col]['g'],
newpixels[i][col]['b'], newpixels[i][col]['a']
]
newimgArray.extend(pixel)
elif (mode == 1):
newimgArray.extend(flur(i, col))
newimgArray.extend(sizeByte(0, rowLength - len(row) * (new_bpp // 8)))
# 写入新的文件
newimgBytes = bytes(newimgArray)
with open(img[:-4] + "_new" + img[-4:], 'wb') as f:
f.write(newimgBytes)
for _ in tqdm(range(len(newimgBytes)), "写出图片中"):
pass