コード例 #1
0
ファイル: gui.py プロジェクト: rudresh2319/Xpra
def get_CG_imagewrapper(rect=None):
    from xpra.codecs.image_wrapper import ImageWrapper
    assert CG, "cannot capture without Quartz.CoreGraphics"
    if rect is None:
        x = 0
        y = 0
        region = CG.CGRectInfinite
    else:
        x, y, w, h = rect
        region = CG.CGRectMake(x, y, roundup(w, 2), roundup(h, 2))
    image = CG.CGWindowListCreateImage(
        region, CG.kCGWindowListOptionOnScreenOnly, CG.kCGNullWindowID,
        CG.kCGWindowImageNominalResolution)  #CG.kCGWindowImageDefault)
    width = CG.CGImageGetWidth(image)
    height = CG.CGImageGetHeight(image)
    bpc = CG.CGImageGetBitsPerComponent(image)
    bpp = CG.CGImageGetBitsPerPixel(image)
    rowstride = CG.CGImageGetBytesPerRow(image)
    alpha = CG.CGImageGetAlphaInfo(image)
    alpha_str = ALPHA.get(alpha, alpha)
    log(
        "get_CG_imagewrapper(..) image size: %sx%s, bpc=%s, bpp=%s, rowstride=%s, alpha=%s",
        width, height, bpc, bpp, rowstride, alpha_str)
    prov = CG.CGImageGetDataProvider(image)
    argb = CG.CGDataProviderCopyData(prov)
    return ImageWrapper(x, y, width, height, argb, "BGRX", 24, rowstride)
コード例 #2
0
ファイル: codec_checks.py プロジェクト: chewi/xpra
def make_test_image(pixel_format, w, h):
    from xpra.codecs.image_wrapper import ImageWrapper
    from xpra.codecs.codec_constants import get_subsampling_divs
    #import time
    #start = monotonic()
    if pixel_format.startswith("YUV") or pixel_format.startswith(
            "GBRP") or pixel_format == "NV12":
        divs = get_subsampling_divs(pixel_format)
        try:
            depth = int(pixel_format.split("P")[1])  #ie: YUV444P10 -> 10
        except (IndexError, ValueError):
            depth = 8
        Bpp = roundup(depth, 8) // 8
        nplanes = len(divs)
        ydiv = divs[0]  #always (1, 1)
        y = makebuf(w // ydiv[0] * h // ydiv[1] * Bpp)
        udiv = divs[1]
        u = makebuf(w // udiv[0] * h // udiv[1] * Bpp)
        planes = [y, u]
        strides = [w // ydiv[0] * Bpp, w // udiv[0] * Bpp]
        if nplanes == 3:
            vdiv = divs[2]
            v = makebuf(w // vdiv[0] * h // vdiv[1] * Bpp)
            planes.append(v)
            strides.append(w // vdiv[0] * Bpp)
        image = ImageWrapper(0,
                             0,
                             w,
                             h,
                             planes,
                             pixel_format,
                             32,
                             strides,
                             planes=nplanes,
                             thread_safe=True)
        #l = len(y)+len(u)+len(v)
    elif pixel_format in ("RGB", "BGR", "RGBX", "BGRX", "XRGB", "BGRA", "RGBA",
                          "r210", "BGR48"):
        if pixel_format == "BGR48":
            stride = w * 6
        else:
            stride = w * len(pixel_format)
        rgb_data = makebuf(stride * h)
        image = ImageWrapper(0,
                             0,
                             w,
                             h,
                             rgb_data,
                             pixel_format,
                             32,
                             stride,
                             planes=ImageWrapper.PACKED,
                             thread_safe=True)
        #l = len(rgb_data)
    else:
        raise Exception("don't know how to create a %s image" % pixel_format)
    #log("make_test_image%30s took %3ims for %6iMBytes",
    #    (pixel_format, w, h), 1000*(monotonic()-start), l//1024//1024)
    return image
コード例 #3
0
def init_client_mmap(mmap_group=None,
                     socket_filename=None,
                     size=128 * 1024 * 1024,
                     filename=None):
    """
        Initializes an mmap area, writes the token in it and returns:
            (success flag, mmap_area, mmap_size, temp_file, mmap_filename)
        The caller must keep hold of temp_file to ensure it does not get deleted!
        This is used by the client.
    """
    def rerr():
        return False, False, None, 0, None, None

    log("init_mmap%s", (mmap_group, socket_filename, size, filename))
    mmap_filename = filename
    mmap_temp_file = None
    delete = True

    def validate_size(size):
        assert size >= 64 * 1024 * 1024, "mmap size is too small: %sB (minimum is 64MB)" % std_unit(
            size)
        assert size <= 4 * 1024 * 1024 * 1024, "mmap is too big: %sB (maximum is 4GB)" % std_unit(
            size)

    try:
        import mmap
        unit = max(4096, mmap.PAGESIZE)
        #add 8 bytes for the mmap area control header zone:
        mmap_size = roundup(size + 8, unit)
        if WIN32:
            validate_size(mmap_size)
            if not filename:
                from xpra.net.crypto import get_hex_uuid
                filename = "xpra-%s" % get_hex_uuid()
            mmap_filename = filename
            mmap_area = mmap.mmap(0, mmap_size, filename)
            #not a real file:
            delete = False
            mmap_temp_file = None
        else:
            assert POSIX
            if filename:
                if os.path.exists(filename):
                    fd = os.open(filename, os.O_EXCL | os.O_RDWR)
                    mmap_size = os.path.getsize(mmap_filename)
                    validate_size(mmap_size)
                    #mmap_size = 4*1024*1024    #size restriction needed with ivshmem
                    delete = False
                    log.info("Using existing mmap file '%s': %sMB",
                             mmap_filename, mmap_size // 1024 // 1024)
                else:
                    validate_size(mmap_size)
                    import errno
                    flags = os.O_CREAT | os.O_EXCL | os.O_RDWR
                    try:
                        fd = os.open(filename, flags)
                        mmap_temp_file = None  #os.fdopen(fd, 'w')
                        mmap_filename = filename
                    except OSError as e:
                        if e.errno == errno.EEXIST:
                            log.error(
                                "Error: the mmap file '%s' already exists",
                                filename)
                            return rerr()
                        raise
            else:
                validate_size(mmap_size)
                import tempfile
                from xpra.platform.paths import get_mmap_dir
                mmap_dir = get_mmap_dir()
                subs = os.environ.copy()
                subs.update({
                    "UID": os.getuid(),
                    "GID": os.getgid(),
                    "PID": os.getpid(),
                })
                mmap_dir = shellsub(mmap_dir, subs)
                if mmap_dir and not os.path.exists(mmap_dir):
                    os.mkdir(mmap_dir, 0o700)
                if not mmap_dir or not os.path.exists(mmap_dir):
                    raise Exception("mmap directory %s does not exist!" %
                                    mmap_dir)
                #create the mmap file, the mkstemp that is called via NamedTemporaryFile ensures
                #that the file is readable and writable only by the creating user ID
                try:
                    temp = tempfile.NamedTemporaryFile(prefix="xpra.",
                                                       suffix=".mmap",
                                                       dir=mmap_dir)
                except OSError as e:
                    log.error("Error: cannot create mmap file:")
                    log.error(" %s", e)
                    return rerr()
                #keep a reference to it so it does not disappear!
                mmap_temp_file = temp
                mmap_filename = temp.name
                fd = temp.file.fileno()
            #set the group permissions and gid if the mmap-group option is specified
            if mmap_group and type(socket_filename) == str and os.path.exists(
                    socket_filename):
                from stat import S_IRUSR, S_IWUSR, S_IRGRP, S_IWGRP
                s = os.stat(socket_filename)
                os.fchown(fd, -1, s.st_gid)
                os.fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
            log("using mmap file %s, fd=%s, size=%s", mmap_filename, fd,
                mmap_size)
            os.lseek(fd, mmap_size - 1, os.SEEK_SET)
            assert os.write(fd, b'\x00')
            os.lseek(fd, 0, os.SEEK_SET)
            mmap_area = mmap.mmap(fd, length=mmap_size)
        return True, delete, mmap_area, mmap_size, mmap_temp_file, mmap_filename
    except Exception as e:
        log("failed to setup mmap: %s", e, exc_info=True)
        log.error("Error: mmap setup failed:")
        log.error(" %s", e)
        clean_mmap(mmap_filename)
        return rerr()
コード例 #4
0
 def get_image(self, x=0, y=0, width=0, height=0):
     start = time.time()
     metrics = get_virtualscreenmetrics()
     if self.metrics is None or self.metrics != metrics:
         #new metrics, start from scratch:
         self.metrics = metrics
         self.clean()
     log("get_image%s metrics=%s", (x, y, width, height), metrics)
     dx, dy, dw, dh = metrics
     if width == 0:
         width = dw
     if height == 0:
         height = dh
     #clamp rectangle requested to the virtual desktop size:
     if x < dx:
         width -= x - dx
         x = dx
     if y < dy:
         height -= y - dy
         y = dy
     if width > dw:
         width = dw
     if height > dh:
         height = dh
     if not self.dc:
         self.wnd = GetDesktopWindow()
         self.dc = GetWindowDC(self.wnd)
         assert self.dc, "failed to get a drawing context from the desktop window %s" % self.wnd
         self.bit_depth = GetDeviceCaps(self.dc, win32con.BITSPIXEL)
         self.memdc = CreateCompatibleDC(self.dc)
         assert self.memdc, "failed to get a compatible drawing context from %s" % self.dc
     bitmap = CreateCompatibleBitmap(self.dc, width, height)
     assert bitmap, "failed to get a compatible bitmap from %s" % self.dc
     r = SelectObject(self.memdc, bitmap)
     if r == 0:
         log.error("Error: cannot select bitmap object")
         return None
     select_time = time.time()
     log("get_image up to SelectObject (%s) took %ims",
         REGION_CONSTS.get(r, r), (select_time - start) * 1000)
     try:
         if BitBlt(self.memdc, 0, 0, width, height, self.dc, x, y,
                   win32con.SRCCOPY) == 0:
             e = ctypes.get_last_error()
             #rate limit the error message:
             now = time.time()
             if now - self.bitblt_err_time > 10:
                 log.error("Error: failed to blit the screen, error %i", e)
                 self.bitblt_err_time = now
             return None
     except Exception as e:
         log("BitBlt error", exc_info=True)
         log.error("Error: cannot capture screen")
         log.error(" %s", e)
         return None
     bitblt_time = time.time()
     log("get_image BitBlt took %ims", (bitblt_time - select_time) * 1000)
     rowstride = roundup(width * self.bit_depth // 8, 2)
     buf_size = rowstride * height
     pixels = ctypes.create_string_buffer(b"", buf_size)
     log("GetBitmapBits(%#x, %#x, %#x)", bitmap, buf_size,
         ctypes.addressof(pixels))
     r = GetBitmapBits(bitmap, buf_size, ctypes.byref(pixels))
     if r == 0:
         log.error("Error: failed to copy screen bitmap data")
         return None
     if r != buf_size:
         log.warn(
             "Warning: truncating pixel buffer, got %i bytes but expected %i",
             r, buf_size)
         pixels = pixels[:r]
     log("get_image GetBitmapBits took %ims",
         (time.time() - bitblt_time) * 1000)
     DeleteObject(bitmap)
     assert pixels, "no pixels returned from GetBitmapBits"
     if self.bit_depth == 32:
         rgb_format = "BGRX"
     elif self.bit_depth == 30:
         rgb_format = "r210"
     elif self.bit_depth == 24:
         rgb_format = "BGR"
     elif self.bit_depth == 16:
         rgb_format = "BGR565"
     elif self.bit_depth == 8:
         rgb_format = "RLE8"
     else:
         raise Exception("unsupported bit depth: %s" % self.bit_depth)
     bpp = self.bit_depth // 8
     v = ImageWrapper(0,
                      0,
                      width,
                      height,
                      pixels,
                      rgb_format,
                      self.bit_depth,
                      rowstride,
                      bpp,
                      planes=ImageWrapper.PACKED,
                      thread_safe=True)
     if self.bit_depth == 8:
         count = GetSystemPaletteEntries(self.dc, 0, 0, None)
         log("palette size: %s", count)
         palette = []
         if count > 0:
             buf = (PALETTEENTRY * count)()
             r = GetSystemPaletteEntries(self.dc, 0, count,
                                         ctypes.byref(buf))
             #we expect 16-bit values, so bit-shift them:
             for p in buf:
                 palette.append(
                     (p.peRed << 8, p.peGreen << 8, p.peBlue << 8))
         v.set_palette(palette)
     log("get_image%s=%s took %ims", (x, y, width, height), v,
         (time.time() - start) * 1000)
     return v
コード例 #5
0
 def may_restride(self):
     newstride = roundup(self.width*self.bytesperpixel, 4)
     if self.rowstride>newstride:
         return self.restride(newstride)
     return False
コード例 #6
0
check_devices()

print("pycuda import")
from pycuda import driver  #@UnresolvedImport

cuda_device = driver.Device(0)
print("cuda_device=%s" % cuda_device)
cuda_context = cuda_device.make_context(flags=driver.ctx_flags.SCHED_AUTO
                                        | driver.ctx_flags.MAP_HOST)
try:
    print("cuda_context=%s" % cuda_context)

    BGRA2NV12 = get_CUDA_function(0, "BGRA_to_NV12")
    print("BGRA2NV12=%s" % BGRA2NV12)

    w = roundup(512, 32)
    h = roundup(512, 32)

    log("w=%s, h=%s", w, h)

    cudaInputBuffer, inputPitch = driver.mem_alloc_pitch(w, h * 3 / 2, 16)
    log("CUDA Input Buffer=%s, pitch=%s", hex(int(cudaInputBuffer)),
        inputPitch)
    #allocate CUDA NV12 buffer (on device):
    cudaNV12Buffer, NV12Pitch = driver.mem_alloc_pitch(w, h * 3 / 2, 16)
    log("CUDA NV12 Buffer=%s, pitch=%s", hex(int(cudaNV12Buffer)), NV12Pitch)

    #host buffers:
    inputBuffer = driver.pagelocked_zeros(inputPitch * h * 3 / 2,
                                          dtype=numpy.byte)
    log("inputBuffer=%s", inputBuffer)
コード例 #7
0
ファイル: clipboard.py プロジェクト: frostbane/xpra
        def got_clipboard_lock():
            if COMPRESSED_IMAGES:
                fmt_name = LPCSTR(img_format.upper().encode("latin1") +
                                  b"\0")  #ie: "PNG"
                fmt = RegisterClipboardFormatA(fmt_name)
                if fmt:
                    data_handle = GetClipboardData(fmt)
                    if data_handle:
                        size = GlobalSize(data_handle)
                        data = GlobalLock(data_handle)
                        log("GetClipboardData(%s)=%#x size=%s, data=%#x",
                            img_format.upper(), data_handle, size, data)
                        if data and size:
                            try:
                                cdata = (c_char * size).from_address(data)
                            finally:
                                GlobalUnlock(data)
                            got_image(bytes(cdata), False)
                            return True

            data_handle = GetClipboardData(win32con.CF_DIBV5)
            log("CF_BITMAP=%s", data_handle)
            data = GlobalLock(data_handle)
            if not data:
                log("failed to lock data handle %#x (may try again)",
                    data_handle)
                return False
            try:
                header = cast(data, PBITMAPV5HEADER).contents
                offset = header.bV5Size + header.bV5ClrUsed * 4
                w, h = header.bV5Width, abs(header.bV5Height)
                bits = header.bV5BitCount
                log(
                    "offset=%s, width=%i, height=%i, compression=%s", offset,
                    w, h,
                    BI_FORMATS.get(header.bV5Compression,
                                   header.bV5Compression))
                log("planes=%i, bitcount=%i", header.bV5Planes, bits)
                log("colorspace=%s",
                    COLOR_PROFILES.get(header.bV5CSType, header.bV5CSType))
                #if header.bV5Compression in (BI_JPEG, BI_PNG):
                #    pass
                if header.bV5Compression != BI_RGB:
                    errback(
                        "cannot handle %s compression yet" % BI_FORMATS.get(
                            header.bV5Compression, header.bV5Compression))
                    return True
                if bits == 24:
                    save_format = "RGB"
                    rgb_format = "BGR"
                    stride = roundup(w * 3, 4)
                elif bits == 32:
                    save_format = "RGBA"
                    rgb_format = "BGRA"
                    stride = w * 4
                else:
                    errback(
                        "cannot handle image data with %i bits per pixel yet" %
                        bits)
                    return True
                img_size = stride * h
                rgb_data = (c_char * img_size).from_address(data + offset)
                from PIL import Image, ImageOps
                img = Image.frombytes(save_format, (w, h), rgb_data, "raw",
                                      rgb_format, stride, 1)
                if header.bV5Height > 0:
                    img = ImageOps.flip(img)
                buf = BytesIO()
                img.save(buf, format=save_format)
                data = buf.getvalue()
                buf.close()
                got_image(data, True)
                return True
            finally:
                GlobalUnlock(data)
コード例 #8
0
def init_client_mmap(mmap_group=None, socket_filename=None, size=128*1024*1024, filename=None):
    """
        Initializes an mmap area, writes the token in it and returns:
            (success flag, mmap_area, mmap_size, temp_file, mmap_filename)
        The caller must keep hold of temp_file to ensure it does not get deleted!
        This is used by the client.
    """
    def rerr():
        return False, False, None, 0, None, None
    log("init_mmap%s", (mmap_group, socket_filename, size, filename))
    mmap_filename = filename
    mmap_temp_file = None
    delete = True
    def validate_size(size : int):
        assert size>=64*1024*1024, "mmap size is too small: %sB (minimum is 64MB)" % std_unit(size)
        assert size<=4*1024*1024*1024, "mmap is too big: %sB (maximum is 4GB)" % std_unit(size)
    try:
        import mmap
        unit = max(4096, mmap.PAGESIZE)
        #add 8 bytes for the mmap area control header zone:
        mmap_size = roundup(size + 8, unit)
        if WIN32:
            validate_size(mmap_size)
            if not filename:
                from xpra.os_util import get_hex_uuid
                filename = "xpra-%s" % get_hex_uuid()
            mmap_filename = filename
            mmap_area = mmap.mmap(0, mmap_size, filename)
            #not a real file:
            delete = False
        else:
            assert POSIX
            if filename:
                if os.path.exists(filename):
                    fd = os.open(filename, os.O_EXCL | os.O_RDWR)
                    mmap_size = os.path.getsize(mmap_filename)
                    validate_size(mmap_size)
                    #mmap_size = 4*1024*1024    #size restriction needed with ivshmem
                    delete = False
                    log.info("Using existing mmap file '%s': %sMB", mmap_filename, mmap_size//1024//1024)
                else:
                    validate_size(mmap_size)
                    flags = os.O_CREAT | os.O_EXCL | os.O_RDWR
                    try:
                        fd = os.open(filename, flags)
                        mmap_temp_file = None   #os.fdopen(fd, 'w')
                        mmap_filename = filename
                    except FileExistsError:
                        log.error("Error: the mmap file '%s' already exists", filename)
                        return rerr()
            else:
                validate_size(mmap_size)
                import tempfile
                from xpra.platform.paths import get_mmap_dir
                mmap_dir = get_mmap_dir()
                subs = os.environ.copy()
                subs.update({
                    "UID"               : os.getuid(),
                    "GID"               : os.getgid(),
                    "PID"               : os.getpid(),
                    })
                mmap_dir = shellsub(mmap_dir, subs)
                if mmap_dir and not os.path.exists(mmap_dir):
                    os.mkdir(mmap_dir, 0o700)
                if not mmap_dir or not os.path.exists(mmap_dir):
                    raise Exception("mmap directory %s does not exist!" % mmap_dir)
                #create the mmap file, the mkstemp that is called via NamedTemporaryFile ensures
                #that the file is readable and writable only by the creating user ID
                try:
                    temp = tempfile.NamedTemporaryFile(prefix="xpra.", suffix=".mmap", dir=mmap_dir)
                except OSError as e:
                    log.error("Error: cannot create mmap file:")
                    log.error(" %s", e)
                    return rerr()
                #keep a reference to it so it does not disappear!
                mmap_temp_file = temp
                mmap_filename = temp.name
                fd = temp.file.fileno()
            #set the group permissions and gid if the mmap-group option is specified
            mmap_group = (mmap_group or "")
            if POSIX and mmap_group and mmap_group not in FALSE_OPTIONS:
                group_id = None
                if mmap_group=="SOCKET":
                    group_id = get_socket_group(socket_filename)
                elif mmap_group.lower()=="auto":
                    group_id = xpra_group()
                    if not group_id and socket_filename:
                        group_id = get_socket_group(socket_filename)
                elif mmap_group.lower() in TRUE_OPTIONS:
                    log.info("parsing legacy mmap-group value '%s' as 'auto'", mmap_group)
                    log.info(" please update your configuration")
                    group_id = xpra_group() or get_socket_group(socket_filename)
                else:
                    group_id = get_group_id(mmap_group)
                if group_id>0:
                    log("setting mmap file %s to group id=%i", mmap_filename, group_id)
                    try:
                        os.fchown(fd, -1, group_id)
                    except OSError as e:
                        log("fchown(%i, %i, %i) on %s", fd, -1, group_id, mmap_filename, exc_info=True)
                        log.error("Error: failed to change group ownership of mmap file to '%s':", mmap_group)
                        log.error(" %s", e)
                    from stat import S_IRUSR,S_IWUSR,S_IRGRP,S_IWGRP
                    os.fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
            log("using mmap file %s, fd=%s, size=%s", mmap_filename, fd, mmap_size)
            os.lseek(fd, mmap_size-1, os.SEEK_SET)
            assert os.write(fd, b'\x00')
            os.lseek(fd, 0, os.SEEK_SET)
            mmap_area = mmap.mmap(fd, length=mmap_size)
        return True, delete, mmap_area, mmap_size, mmap_temp_file, mmap_filename
    except Exception as e:
        log("failed to setup mmap: %s", e, exc_info=True)
        log.error("Error: mmap setup failed:")
        log.error(" %s", e)
        if delete:
            if mmap_temp_file:
                try:
                    mmap_temp_file.close()
                except OSError:
                    log("%s()", mmap_temp_file.close, exc_info=True)
                    log.error(" failed to remove the mmap temp file: %s", e)
            else:
                clean_mmap(mmap_filename)
        return rerr()
コード例 #9
0
 def get_image(self, x=0, y=0, width=0, height=0):
     start = time.time()
     x, y, width, height = self.get_capture_coords(x, y, width, height)
     if not self.dc:
         self.wnd = GetDesktopWindow()
         if not self.wnd:
             log.error("Error: cannot access the desktop window")
             log.error(" capturing the screen is not possible")
             return None
         self.dc = GetWindowDC(self.wnd)
         if not self.dc:
             log.error("Error: cannot get a drawing context")
             log.error(" capturing the screen is not possible")
             log.error(" desktop window=%#x", self.wnd)
             return None
         self.bit_depth = GetDeviceCaps(self.dc, win32con.BITSPIXEL)
         self.memdc = CreateCompatibleDC(self.dc)
         assert self.memdc, "failed to get a compatible drawing context from %s" % self.dc
     bitmap = CreateCompatibleBitmap(self.dc, width, height)
     if not bitmap:
         log.error("Error: failed to get a compatible bitmap")
         log.error(" from drawing context %#x with size %ix%i", self.dc,
                   width, height)
         self.clean_dc()
         return None
     r = SelectObject(self.memdc, bitmap)
     if not r:
         log.error("Error: cannot select bitmap object")
         return None
     select_time = time.time()
     log("get_image up to SelectObject (%s) took %ims",
         REGION_CONSTS.get(r, r), (select_time - start) * 1000)
     try:
         if BitBlt(self.memdc, 0, 0, width, height, self.dc, x, y,
                   win32con.SRCCOPY) == 0:
             e = ctypes.get_last_error()
             #rate limit the error message:
             now = time.time()
             if now - self.bitblt_err_time > 10:
                 log.error("Error: failed to blit the screen, error %i", e)
                 self.bitblt_err_time = now
             return None
     except Exception as e:
         log("BitBlt error", exc_info=True)
         log.error("Error: cannot capture screen with BitBlt")
         log.error(" %s", e)
         self.clean_dc()
         return None
     bitblt_time = time.time()
     log("get_image BitBlt took %ims", (bitblt_time - select_time) * 1000)
     rowstride = roundup(width * self.bit_depth // 8, 2)
     buf_size = rowstride * height
     pixels = ctypes.create_string_buffer(b"", buf_size)
     log("GetBitmapBits(%#x, %#x, %#x)", bitmap, buf_size,
         ctypes.addressof(pixels))
     r = GetBitmapBits(bitmap, buf_size, ctypes.byref(pixels))
     if not r:
         log.error("Error: failed to copy screen bitmap data")
         self.clean_dc()
         return None
     if r != buf_size:
         log.warn(
             "Warning: truncating pixel buffer, got %i bytes but expected %i",
             r, buf_size)
         pixels = pixels[:r]
     log("get_image GetBitmapBits took %ims",
         (time.time() - bitblt_time) * 1000)
     DeleteObject(bitmap)
     assert pixels, "no pixels returned from GetBitmapBits"
     rgb_format = RGB_FORMATS.get(self.bit_depth)
     if not rgb_format:
         raise Exception("unsupported bit depth: %s" % self.bit_depth)
     bpp = self.bit_depth // 8
     v = ImageWrapper(0,
                      0,
                      width,
                      height,
                      pixels,
                      rgb_format,
                      self.bit_depth,
                      rowstride,
                      bpp,
                      planes=ImageWrapper.PACKED,
                      thread_safe=True)
     if self.bit_depth == 8:
         palette = get_palette(self.dc)
         v.set_palette(palette)
     log("get_image%s=%s took %ims", (x, y, width, height), v,
         (time.time() - start) * 1000)
     return v