vdi-cloud/tools/xwd2png.py
宋一鸣 7fdcb53dd9 清理:移除 RDP 遗留资料并纳管产品文档与运维工具
变更详情:清理 RDP 遗留文档与临时文件,纳管产品文档与运维工具脚本
2026-10-29 17:44:25 +08:00

85 lines
2.7 KiB
Python

#!/usr/bin/env python3
"""Convert an XWD dump (from xwd) into a PNG, without external image libraries.
Usage: xwd -root -silent | python3 xwd2png.py out.png
"""
import struct
import sys
import zlib
def read_header(data):
fields = struct.unpack(">25I", data[:100])
names = [
"header_size", "file_version", "pixmap_format", "pixmap_depth",
"pixmap_width", "pixmap_height", "xoffset", "byte_order",
"bitmap_unit", "bitmap_bit_order", "bitmap_pad", "bits_per_pixel",
"bytes_per_line", "visual_class", "red_mask", "green_mask",
"blue_mask", "bits_per_rgb", "colormap_entries", "ncolors",
"window_width", "window_height", "window_x", "window_y",
"window_bdrwidth",
]
return dict(zip(names, fields))
def write_png(path, width, height, rgb_rows):
raw = b"".join(b"\x00" + row for row in rgb_rows)
def chunk(tag, payload):
return (struct.pack(">I", len(payload)) + tag + payload +
struct.pack(">I", zlib.crc32(tag + payload) & 0xFFFFFFFF))
header = struct.pack(">IIBBBBB", width, height, 8, 2, 0, 0, 0)
png = (b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", header) +
chunk(b"IDAT", zlib.compress(raw, 6)) + chunk(b"IEND", b""))
with open(path, "wb") as handle:
handle.write(png)
def main():
out_path = sys.argv[1] if len(sys.argv) > 1 else "out.png"
data = sys.stdin.buffer.read()
head = read_header(data)
width = head["pixmap_width"]
height = head["pixmap_height"]
bpp = head["bits_per_pixel"]
stride = head["bytes_per_line"]
offset = head["header_size"] + head["ncolors"] * 12
pixels = data[offset:]
if bpp == 32:
rows = []
for y in range(height):
line = pixels[y * stride:y * stride + width * 4]
out = bytearray(width * 3)
for x in range(width):
src = x * 4
dst = x * 3
out[dst] = line[src + 2]
out[dst + 1] = line[src + 1]
out[dst + 2] = line[src]
rows.append(bytes(out))
elif bpp == 24:
rows = []
for y in range(height):
line = pixels[y * stride:y * stride + width * 3]
out = bytearray(width * 3)
for x in range(width):
src = x * 3
dst = x * 3
out[dst] = line[src + 2]
out[dst + 1] = line[src + 1]
out[dst + 2] = line[src]
rows.append(bytes(out))
else:
sys.stderr.write("unsupported bits_per_pixel=%s\n" % bpp)
return 2
write_png(out_path, width, height, rows)
print("%s %dx%d" % (out_path, width, height))
return 0
if __name__ == "__main__":
sys.exit(main())