压缩位图失败(Python 实现)
Posted
技术标签:
【中文标题】压缩位图失败(Python 实现)【英文标题】:Compressing bitmap fails (Python implementation) 【发布时间】:2018-08-25 15:40:39 【问题描述】:我有一个使用位图存储图像的应用程序。目前这些被存储为未压缩的位图,但由于颜色的数量几乎总是 https://en.wikipedia.org/wiki/BMP_file_format 的***条目的帮助下,我尝试在 Python 中实现一个压缩程序 - 如下所示。这成功读取了输入bmp并输出了一个较小的bmp,但是生成的bmp不可读,所以我一定做错了什么。在 Windows 资源管理器中,文件的属性包括“位深度:32”,这显然不是意图 - 但我很确定我得到了正确的位深度和压缩的标题信息。如果我能找到一个用于检查的压缩位图示例,那将有所帮助,但无法找到一个。这种格式是不是普遍不支持,还是我做错了什么?
import math
def rgb(r,g,b):
return hex(256*256*256+r*256*256+g*256+b)[3:9]
def read_bmp(path):
bm=
with open(path,"rb") as f:
byte=f.read(54)
header_size=byte[14]+byte[15]*256
if header_size!=40: return None
bm['w']=w=byte[18]+byte[19]*256
bm['h']=byte[22]+byte[23]*256
bm['color_depth']=byte[28]
bm['compression']=byte[30]
bm['im_size']=byte[34]+byte[35]*256+byte[36]*256*256
if bm['compression']!=0:
ct=f.read(4*bm['color_depth'])
color_table=[]
for i in range(0,bm['color_depth']):
color_table.append((ct[i*4],ct[i*4+1],ct[i*4+2]))
if bm['color_depth']==24:
bmp=f.read(bm['im_size'])
row_size=bm['im_size']//bm['h']
col=
pixel=[]
for y in range(0,bm['h']):
s=""
row=[]
for x in range(0,w):
row.append((bmp[y*row_size+x*3],bmp[y*row_size+x*3+1],bmp[y*row_size+x*3+2]))
color=rgb(bmp[y*row_size+x*3],bmp[y*row_size+x*3+1],bmp[y*row_size+x*3+2])
if color in col:
col[color]+=1
else:
col[color]=1
pixel.append(row)
bm['pix']=pixel
bm['color_count']=len(col)
return bm
def putint(b,p,i):
b[p]=i & 255
b[p+1]=(i>>8)&255
if i>65535:
b[p+2]=(i>>16)&255
b[p+3]=(i>>24)&255
def write_compressed_bmp(bm,path):
pix=bm['pix']
col=[]
color_index=[]
for row in pix:
rowindex=[]
for color in row:
if not color in col: col.append(color)
rowindex.append(col.index(color))
color_index.append(rowindex)
print(col)
if len(col)>16: return
with open(path,"wb") as f:
row_size=math.ceil(bm['w']/8)*4
image_size=row_size*bm['h']
file_len=54+64+image_size
header=bytearray(54)
header[0]=ord('B')
header[1]=ord('M')
putint(header,2,file_len)
putint(header,10,54+64)
putint(header,14,40)
putint(header,18,bm['w'])
putint(header,22,bm['h'])
putint(header,26,1)
putint(header,28,4)
putint(header,34,image_size)
f.write(header)
color_map=bytearray(64)
for i in range(0,len(col)):
color_map[i*4]=col[i][0]
color_map[i*4+1]=col[i][1]
color_map[i*4+2]=col[i][2]
f.write(color_map)
for row in pix:
row_bytes=bytearray(row_size)
i=0
for color in row:
ci=col.index(color)
if i&1:
row_bytes[i>>1]|=ci
else:
row_bytes[i>>1]|=ci<<4
i+=1
f.write(row_bytes)
bm=read_bmp("bitmap.bmp")
if bm['color_count']<=16:
write_compressed_bmp(bm,"bitmap2.bmp")
【问题讨论】:
在阅读更多内容后,我意识到我设置的“压缩方法”=2 (BI_RLE4) 值用于运行长度编码,我不使用它。唯一有意义的其他可能值是 0(无压缩),但这会导致尝试打开文件时出现“不兼容的位图格式”错误。 【参考方案1】:我发现了问题所在——我忘记了 Python 中的 range() 方法将比最大期望值大一作为其第二个参数,因此写入的行数太少。解决这个问题,并将“压缩”位保留为 0 解决了问题 - 我相应地编辑了上面的代码。如果没问题,我会留在这里供其他人使用。
【讨论】:
以上是关于压缩位图失败(Python 实现)的主要内容,如果未能解决你的问题,请参考以下文章
Java之大数据位图法(无重复排序,重复排序,去重复排序,数据压缩)