2016-03-06 91 views
0

我在剪贴板中有截图。如何将图像保存到没有PIL的剪贴板中?

我已经使用win32clipboard.GetClipboardData(win32con.CF_DIB)来获取一个字符串,并将该字符串写入一个.bmp文件,但它不能被图片查看器打开。

因此,没有PIL(和其他图像第三部分库),如何将剪贴板中的图像写入本地?

+1

你有任何*码*,做了吗?如果是这样,不会**包括它**帮助我们回答你? – Tersosauros

+0

**“将剪贴板中的图像写入本地”是什么意思? – martineau

+0

@martineau这意味着我在剪贴板中有截图,我想将它保存在文件中。 – Kingname

回答

1

您的简单方法的主要问题是写入文件的字符串缺少.bmp文件标头,这是一个BITMAPFILEHEADER结构。

为了创建文件头,必须解码由GetClipboardData()调用返回的字符串中的至少一些信息。对于CF_DIB剪贴板格式,字符串中数据的第一部分将是BITMAPINFOHEADER

这个头结构是一个非常普遍的,因为有许多不同类型的DIB,每个组件和压缩类型都有不同的风格。幸运的是,用于截图的那个非常简单 - 未压缩的RGBA像素。

这一事实使事情变得容易得多,因为另有决定把在BITMAPFILEHEADERbfOffBits字段中的值会被这样的事实,在大多数其它情况下也就是跟随BITMAPINFOHEADER和开始的可变大小的色表很复杂像素阵列。

下面是处理这种情况的示例代码(仅):

import ctypes 
from ctypes.wintypes import * 
import win32clipboard 
from win32con import * 
import sys 

class BITMAPFILEHEADER(ctypes.Structure): 
    _pack_ = 1 # structure field byte alignment 
    _fields_ = [ 
     ('bfType', WORD), # file type ("BM") 
     ('bfSize', DWORD), # file size in bytes 
     ('bfReserved1', WORD), # must be zero 
     ('bfReserved2', WORD), # must be zero 
     ('bfOffBits', DWORD), # byte offset to the pixel array 
    ] 
SIZEOF_BITMAPFILEHEADER = ctypes.sizeof(BITMAPFILEHEADER) 

class BITMAPINFOHEADER(ctypes.Structure): 
    _pack_ = 1 # structure field byte alignment 
    _fields_ = [ 
     ('biSize', DWORD), 
     ('biWidth', LONG), 
     ('biHeight', LONG), 
     ('biPLanes', WORD), 
     ('biBitCount', WORD), 
     ('biCompression', DWORD), 
     ('biSizeImage', DWORD), 
     ('biXPelsPerMeter', LONG), 
     ('biYPelsPerMeter', LONG), 
     ('biClrUsed', DWORD), 
     ('biClrImportant', DWORD) 
    ] 
SIZEOF_BITMAPINFOHEADER = ctypes.sizeof(BITMAPINFOHEADER) 

win32clipboard.OpenClipboard() 
try: 
    if win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_DIB): 
     data = win32clipboard.GetClipboardData(win32clipboard.CF_DIB) 
    else: 
     print('clipboard does not contain an image in DIB format') 
     sys.exit(1) 
finally: 
    win32clipboard.CloseClipboard() 

bmih = BITMAPINFOHEADER() 
ctypes.memmove(ctypes.pointer(bmih), data, SIZEOF_BITMAPINFOHEADER) 

if bmih.biCompression != BI_BITFIELDS: # RGBA? 
    print('insupported compression type {}'.format(bmih.biCompression)) 
    sys.exit(1) 

bmfh = BITMAPFILEHEADER() 
ctypes.memset(ctypes.pointer(bmfh), 0, SIZEOF_BITMAPFILEHEADER) # zero structure 
bmfh.bfType = ord('B') | (ord('M') << 8) 
bmfh.bfSize = SIZEOF_BITMAPFILEHEADER + len(data) # file size 
SIZEOF_COLORTABLE = 0 
bmfh.bfOffBits = SIZEOF_BITMAPFILEHEADER + SIZEOF_BITMAPINFOHEADER + SIZEOF_COLORTABLE 

bmp_filename = 'clipboard.bmp' 
with open(bmp_filename, 'wb') as bmp_file: 
    bmp_file.write(bmfh) 
    bmp_file.write(data) 

print('file "{}" created from clipboard image'.format(bmp_filename)) 
+0

你是一个高手!谢谢,这是我想要的。顺便说一句,我想将这个答案翻译成中文,并发布到我的博客,所以我想获得您的许可,请允许我这样做。 – Kingname

+0

不客气。是的,请随时在您的博客中使用它 - 确保使用我刚发布的更新版本,我试图改进解释(无需更改代码)。 – martineau

+0

好的,非常感谢 – Kingname

相关问题