python 拆解ico格式

1.图片转ico(转自https://blog.csdn.net/c_boy_lu/article/details/49816039,我也没用过这个)

# -*- coding: utf-8 -*-
import os,sys
from PIL import Image
 
image_size = [512,256,144,140,128,120,108,100,88,72,48,32,28]
def create_icon():
     for size in image_size:
          '''pri_image = Image.open("icon.png")
          pri_image.thumbnail((size,size))
          image_name = "icon_%d.png"%(size)
          pri_image.save(image_name)'''
          pri_image = Image.open("icon.png")
          pri_image.resize((size,size),Image.ANTIALIAS ).save("icom_%d.png"%(size))
if __name__ == "__main__":
     create_icon()

我自己

#Python3.7
import PIL.Image as Image

img=Image.open("1.png")
img.resize(32,32).save("1.ico")

2.网上找不到ico的编码,我们来了解一下编码

所以网上找了个ico文件

读取字节码

ico=open("2_calendar_16px_11084_easyicon.net.ico","rb")
size=10#比特块大小
line=ico.read(size)#读
while(line):
    print(line)
    line=ico.read(size)#读下一行

发现不好看,转换byte为int

ico=open("2_calendar_16px_11084_easyicon.net.ico","rb")
size=1#比特块大小
line=ico.read(size)#读
while(line):
    print(int.from_bytes(line,byteorder='big'),end="")
    print(" ",end="")
    line=ico.read(size)#读下一行

统计一下byte个数

ico=open("2_calendar_16px_11084_easyicon.net.ico","rb")
size=1#比特块大小
line=ico.read(size)#读
bytes=0
while(line):
    #print(int.from_bytes(line,byteorder='big'),end="")
    bytes+=1
    #print(" ",end="")
    line=ico.read(size)#读下一行
print(bytes)

结果1150个

而图片信息

16*16=256,而ico带透明通道,所以是rgba编码,256*4=1024。1150-1024=126,估计126是文件头

ico=open("2_calendar_16px_11084_easyicon.net.ico","rb")
size=4#比特块大小
line=ico.read(126)#读头
print([ i for i in line])
line=ico.read(size)
pixel=0
while(line):
    print([ i for i in line])
    pixel+=1
    line=ico.read(size)#读下一行
print(pixel)

一般像这样的点阵图都是顺序的

对应关系:

意味着我错了,在第一个255往前16*4+1才是图片数据的头

ico=open("2_calendar_16px_11084_easyicon.net.ico","rb")
size=4#比特块大小
line=ico.read(61)#读图片头
print([ i for i in line])
#读取图片数据段
line=ico.read(size)
pixel=0
while(line):
    print([ i for i in line])
    pixel+=1
    if (pixel==256):
        break
    line=ico.read(size)#读下一行
#读取图片尾
print([ i for i in ico.read(65)])#显示剩下的

这样就把数据段抽出来了

后来查了下Python\Python37\Lib\site-packages\PIL的转换源代码

Image.py.save()调用了一个ext = os.path.splitext(filename)[1].lower()获取文件扩展名

IcoImagePlugin.py._save()

_MAGIC = b"\0\0\1\0"


def _save(im, fp, filename):
    fp.write(_MAGIC)  # (2+2)
    sizes = im.encoderinfo.get("sizes",
                               [(16, 16), (24, 24), (32, 32), (48, 48),
                                (64, 64), (128, 128), (256, 256)])
    width, height = im.size
    sizes = filter(lambda x: False if (x[0] > width or x[1] > height or
                                       x[0] > 256 or x[1] > 256) else True,
                   sizes)
    sizes = list(sizes)
    fp.write(struct.pack("<H", len(sizes)))  # idCount(2)
    offset = fp.tell() + len(sizes)*16
    for size in sizes:
        width, height = size
        # 0 means 256
        fp.write(struct.pack("B", width if width < 256 else 0))  # bWidth(1)
        fp.write(struct.pack("B", height if height < 256 else 0))  # bHeight(1)
        fp.write(b"\0")  # bColorCount(1)
        fp.write(b"\0")  # bReserved(1)
        fp.write(b"\0\0")  # wPlanes(2)
        fp.write(struct.pack("<H", 32))  # wBitCount(2)

        image_io = BytesIO()
        tmp = im.copy()
        tmp.thumbnail(size, Image.LANCZOS)
        tmp.save(image_io, "png")
        image_io.seek(0)
        image_bytes = image_io.read()
        bytes_len = len(image_bytes)
        fp.write(struct.pack("<I", bytes_len))  # dwBytesInRes(4)
        fp.write(struct.pack("<I", offset))  # dwImageOffset(4)
        current = fp.tell()
        fp.seek(offset)
        fp.write(image_bytes)
        offset = offset + bytes_len
        fp.seek(current)

 

真像大白!!!

再后来事情就变得迷离了,突然想到windows图标是ico,那么写windows用的是C,C++,那么,帖文档啥也不说了,果然文档最简单。

https://blog.csdn.net/jinzhuojun/article/details/8007586 博客

https://msdn.microsoft.com/en-us/library/ms997538.aspx 微软

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值