Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
240 views
in Technique[技术] by (71.8m points)

python - Image.frombuffer with 16-bit image data

If my windows is in 32-bit color depth mode, then the following code gets a nice PIL Image from a window:

def image_grab_native(window):
    hwnd = win32gui.GetDesktopWindow()

    left, top, right, bot = get_rect(window)
    w = right - left
    h = bot - top

    hwndDC = win32gui.GetWindowDC(hwnd)
    mfcDC  = win32ui.CreateDCFromHandle(hwndDC)
    saveDC = mfcDC.CreateCompatibleDC()

    saveBitMap = win32ui.CreateBitmap()
    saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)

    saveDC.SelectObject(saveBitMap)
    saveDC.BitBlt((0, 0), (w, h),  mfcDC,  (left, top),  win32con.SRCCOPY)

    bmpinfo = saveBitMap.GetInfo()
    bmpstr = saveBitMap.GetBitmapBits(True)

    im = Image.frombuffer(
        'RGB',
        (bmpinfo['bmWidth'], bmpinfo['bmHeight']),
        bmpstr, 'raw', 'BGRX', 0, 1)

    win32gui.DeleteObject(saveBitMap.GetHandle())
    saveDC.DeleteDC()
    mfcDC.DeleteDC()
    win32gui.ReleaseDC(hwnd, hwndDC)

    return im

However, when running in 16-bit mode, I get the error:

>>> image_grab_native(win)
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    image_grab_native(win)
  File "C:claudiuumhunterfinderbotezpokerutilswin32.py", line 204, in image_grab_native
    bmpstr, 'raw', 'BGRX', 0, 1)
  File "c:python25libsite-packagesPILImage.py", line 1808, in frombuffer
    return apply(fromstring, (mode, size, data, decoder_name, args))
  File "c:python25libsite-packagesPILImage.py", line 1747, in fromstring
    im.fromstring(data, decoder_name, args)
  File "c:python25libsite-packagesPILImage.py", line 575, in fromstring
    raise ValueError("not enough image data")
ValueError: not enough image data

How should I form the frombuffer call to work in 16-bit mode? Also how can I make this function work in any bit depth mode, instead of say having to pass it as a parameter?

UPDATE: From this question I learned I must use "BGR;16" instead of "BGRX" for the 2nd mode parameter. It takes a correct picture, either specifying stride or not. The problem is that the pixel values are slightly off on some values:

x   y native           ImageGrab
280 0  (213, 210, 205) (214, 211, 206)
280 20 (156, 153, 156) (156, 154, 156)
280 40 (213, 210, 205) (214, 211, 206)
300 0  (213, 210, 205) (214, 211, 206)

just a sample of values taken from the same window. the screenshots look identical to the naked eye, but i have to do some pixel manipulation.. also the reason I want to use the native approach at all is that it's a bit faster and it behaves better when running inside virtual machines with dual monitors.. (yes pretty randomly complicated I know).

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

For the stride parameter, you need to give the row size in bytes. Your pixels are 16 bits each so you might naively assume stride = 2*bmpinfo['bmWidth']; unfortunately Windows adds padding to make the stride an even multiple of 32 bits. That means you'll have to round it to the next highest multiple of 4: stride = (stride + 3) / 4) * 4.

The documentation doesn't mention a 16-bit raw format so you'll have to check the Unpack.c module to see what's available.

The final thing you'll notice is that Windows likes to make its bitmaps upside down.

Edit: Your final little problem is easily explained - the conversion from 16 bit to 24 bit is not precisely defined, and an off-by-one difference between two different conversions is perfectly normal. It wouldn't be hard to adjust the data after you've converted it, as I'm sure the differences are constant based on the value.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...