Пример #1
0
 def nasty_rgb_via_png_paint(self, cairo_format, has_alpha, img_data, x, y, width, height, rowstride, rgb_format):
     log.warn("nasty_rgb_via_png_paint%s",
              (cairo_format, has_alpha, len(img_data), x, y, width, height, rowstride, rgb_format))
     #PIL fallback
     from PIL import Image
     if has_alpha:
         oformat = "RGBA"
     else:
         oformat = "RGB"
     #use frombytes rather than frombuffer to be compatible with python3 new-style buffers
     #this is slower, but since this codepath is already dreadfully slow, we don't care
     bdata = strtobytes(memoryview_to_bytes(img_data))
     src_format = rgb_format.replace("X", "A")
     try:
         img = Image.frombytes(oformat, (width,height), bdata, "raw", src_format, rowstride, 1)
     except ValueError as e:
         log("PIL Image frombytes:", exc_info=True)
         raise Exception("failed to parse raw %s data as %s to %s: %s" % (rgb_format, src_format, oformat, e))
     #This is insane, the code below should work, but it doesn't:
     # img_data = bytearray(img.tostring('raw', oformat, 0, 1))
     # pixbuf = pixbuf_new_from_data(img_data, COLORSPACE_RGB, True, 8, width, height, rowstride)
     # success = self.cairo_paint_pixbuf(pixbuf, x, y)
     #So we still rountrip via PNG:
     png = BytesIOClass()
     img.save(png, format="PNG")
     reader = BytesIOClass(png.getvalue())
     png.close()
     img = cairo.ImageSurface.create_from_png(reader)
     self.cairo_paint_surface(img, x, y)
     return True
Пример #2
0
def load_icon_from_file(filename):
    if filename.endswith("xpm"):
        try:
            from xpra.gtk_common.gobject_compat import import_pixbufloader
            from xpra.gtk_common.gtk_util import pixbuf_save_to_memory
            data = load_binary_file(filename)
            loader = import_pixbufloader()()
            loader.write(data)
            loader.close()
            pixbuf = loader.get_pixbuf()
            pngicondata = pixbuf_save_to_memory(pixbuf, "png")
            return pngicondata, "png"
        except Exception as e:
            log("pixbuf error loading %s", filename, exc_info=True)
            log.error("Error loading '%s':", filename)
            log.error(" %s", e)
        #try PIL:
        from PIL import Image
        try:
            img = Image.open(filename)
        except Exception as e:
            log("Image.open(%s)", filename, exc_info=True)
            log.error("Error loading '%s':", filename)
            log.error(" %s", e)
            return None
        buf = BytesIOClass()
        img.save(buf, "PNG")
        pngicondata = buf.getvalue()
        buf.close()
        return pngicondata, "png"
    icondata = load_binary_file(filename)
    if not icondata:
        return None
    log("got icon data from '%s': %i bytes", filename, len(icondata))
    return icondata, os.path.splitext(filename)[1].rstrip(".")
Пример #3
0
 def do_send_cursor(self, delay):
     self.cursor_timer = None
     cd = self.get_cursor_data_cb()
     if cd and cd[0]:
         cursor_data = list(cd[0])
         cursor_sizes = cd[1]
         #skip first two fields (if present) as those are coordinates:
         if self.last_cursor_sent and self.last_cursor_sent[
                 2:9] == cursor_data[2:9]:
             cursorlog(
                 "do_send_cursor(..) cursor identical to the last one we sent, nothing to do"
             )
             return
         self.last_cursor_sent = cursor_data[:9]
         w, h, _xhot, _yhot, serial, pixels, name = cursor_data[2:9]
         #compress pixels if needed:
         encoding = None
         if pixels is not None:
             #convert bytearray to string:
             cpixels = strtobytes(pixels)
             if "png" in self.cursor_encodings:
                 from xpra.codecs.loader import get_codec
                 PIL = get_codec("PIL")
                 assert PIL
                 cursorlog(
                     "do_send_cursor() loading %i bytes of cursor pixel data for %ix%i cursor named '%s'",
                     len(cpixels), w, h, name)
                 img = PIL.Image.frombytes("RGBA", (w, h), cpixels, "raw",
                                           "BGRA", w * 4, 1)
                 buf = BytesIOClass()
                 img.save(buf, "PNG")
                 pngdata = buf.getvalue()
                 buf.close()
                 cpixels = Compressed("png cursor",
                                      pngdata,
                                      can_inline=True)
                 encoding = "png"
                 if SAVE_CURSORS:
                     with open("raw-cursor-%#x.png" % serial, "wb") as f:
                         f.write(pngdata)
             elif len(cpixels) >= 256 and ("raw" in self.cursor_encodings
                                           or not self.cursor_encodings):
                 cpixels = self.compressed_wrapper("cursor", pixels)
                 cursorlog("do_send_cursor(..) pixels=%s ", cpixels)
                 encoding = "raw"
             cursor_data[7] = cpixels
         cursorlog(
             "do_send_cursor(..) %sx%s %s cursor name='%s', serial=%#x with delay=%s (cursor_encodings=%s)",
             w, h, (encoding or "empty"), name, serial, delay,
             self.cursor_encodings)
         args = list(cursor_data[:9]) + [cursor_sizes[0]] + list(
             cursor_sizes[1])
         if self.cursor_encodings and encoding:
             args = [encoding] + args
     else:
         cursorlog("do_send_cursor(..) sending empty cursor with delay=%s",
                   delay)
         args = [""]
         self.last_cursor_sent = None
     self.send_more("cursor", *args)
Пример #4
0
def image_data(img):
    buf = BytesIOClass()
    img.save(buf, "png")
    data = buf.getvalue()
    buf.close()
    w,h = img.size
    return ("png", w, h, data)
Пример #5
0
 def nasty_rgb_via_png_paint(self, cairo_format, has_alpha, img_data, x, y, width, height, rowstride, rgb_format):
     log("nasty_rgb_via_png_paint%s", (cairo_format, has_alpha, len(img_data), x, y, width, height, rowstride, rgb_format))
     #PIL fallback
     PIL = get_codec("PIL")
     if has_alpha:
         oformat = "RGBA"
     else:
         oformat = "RGB"
     #use frombytes rather than frombuffer to be compatible with python3 new-style buffers
     #this is slower, but since this codepath is already dreadfully slow, we don't care
     bdata = strtobytes(memoryview_to_bytes(img_data))
     try:
         img = PIL.Image.frombytes(oformat, (width,height), bdata, "raw", rgb_format.replace("X", "A"), rowstride, 1)
     except ValueError as e:
         raise Exception("failed to parse raw %s data to %s: %s" % (rgb_format, oformat, e))
     #This is insane, the code below should work, but it doesn't:
     # img_data = bytearray(img.tostring('raw', oformat, 0, 1))
     # pixbuf = pixbuf_new_from_data(img_data, COLORSPACE_RGB, True, 8, width, height, rowstride)
     # success = self.cairo_paint_pixbuf(pixbuf, x, y)
     #So we still rountrip via PNG:
     png = BytesIOClass()
     img.save(png, format="PNG")
     reader = BytesIOClass(png.getvalue())
     png.close()
     img = cairo.ImageSurface.create_from_png(reader)
     self.cairo_paint_surface(img, x, y)
     return True
Пример #6
0
 def nasty_rgb_via_png_paint(self, cairo_format, has_alpha, img_data, x, y,
                             width, height, rowstride, rgb_format):
     log("nasty_rgb_via_png_paint%s",
         (cairo_format, has_alpha, len(img_data), x, y, width, height,
          rowstride, rgb_format))
     #PIL fallback
     PIL = get_codec("PIL")
     if has_alpha:
         oformat = "RGBA"
     else:
         oformat = "RGB"
     #use frombytes rather than frombuffer to be compatible with python3 new-style buffers
     #this is slower, but since this codepath is already dreadfully slow, we don't care
     bdata = strtobytes(memoryview_to_bytes(img_data))
     img = PIL.Image.frombytes(oformat, (width, height), bdata, "raw",
                               rgb_format, rowstride, 1)
     #This is insane, the code below should work, but it doesn't:
     # img_data = bytearray(img.tostring('raw', oformat, 0, 1))
     # pixbuf = pixbuf_new_from_data(img_data, COLORSPACE_RGB, True, 8, width, height, rowstride)
     # success = self.cairo_paint_pixbuf(pixbuf, x, y)
     #So we still rountrip via PNG:
     png = BytesIOClass()
     img.save(png, format="PNG")
     reader = BytesIOClass(png.getvalue())
     png.close()
     img = cairo.ImageSurface.create_from_png(reader)
     self.cairo_paint_surface(img, x, y)
     return True
Пример #7
0
 def paint_pil_image(self, pil_image, width, height, rowstride, options,
                     callbacks):
     buf = BytesIOClass()
     pil_image.save(buf, format="PNG")
     png_data = buf.getvalue()
     buf.close()
     self.idle_add(self.paint_png, png_data, 0, 0, width, height, rowstride,
                   options, callbacks)
Пример #8
0
 def send_webcam_frame(self):
     if not self.webcam_lock.acquire(False):
         return False
     log("send_webcam_frame() webcam_device=%s", self.webcam_device)
     try:
         assert self.webcam_device_no>=0, "device number is not set"
         assert self.webcam_device, "no webcam device to capture from"
         from xpra.codecs.pillow.encode import get_encodings
         client_webcam_encodings = get_encodings()
         common_encodings = list(set(self.server_webcam_encodings).intersection(client_webcam_encodings))
         log("common encodings (server=%s, client=%s): %s",
             csv(self.server_encodings), csv(client_webcam_encodings), csv(common_encodings))
         if not common_encodings:
             log.error("Error: cannot send webcam image, no common formats")
             log.error(" the server supports: %s", csv(self.server_webcam_encodings))
             log.error(" the client supports: %s", csv(client_webcam_encodings))
             self.stop_sending_webcam()
             return False
         preferred_order = ["jpeg", "png", "png/L", "png/P", "webp"]
         formats = [x for x in preferred_order if x in common_encodings] + common_encodings
         encoding = formats[0]
         start = monotonic_time()
         import cv2
         ret, frame = self.webcam_device.read()
         assert ret, "capture failed"
         assert frame.ndim==3, "invalid frame data"
         h, w, Bpp = frame.shape
         assert Bpp==3 and frame.size==w*h*Bpp
         rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
         end = monotonic_time()
         log("webcam frame capture took %ims", (end-start)*1000)
         start = monotonic_time()
         from PIL import Image
         image = Image.fromarray(rgb)
         buf = BytesIOClass()
         image.save(buf, format=encoding)
         data = buf.getvalue()
         buf.close()
         end = monotonic_time()
         log("webcam frame compression to %s took %ims", encoding, (end-start)*1000)
         frame_no = self.webcam_frame_no
         self.webcam_frame_no += 1
         self.send("webcam-frame", self.webcam_device_no, frame_no, encoding,
                   w, h, compression.Compressed(encoding, data))
         self.cancel_webcam_check_ack_timer()
         self.webcam_ack_check_timer = self.timeout_add(10*1000, self.webcam_check_acks)
         return True
     except Exception as e:
         log.error("webcam frame %i failed", self.webcam_frame_no, exc_info=True)
         log.error("Error sending webcam frame: %s", e)
         self.stop_sending_webcam()
         summary = "Webcam forwarding has failed"
         body = "The system encountered the following error:\n" + \
             ("%s\n" % e)
         self.may_notify(XPRA_WEBCAM_NOTIFICATION_ID, summary, body, expire_timeout=10*1000, icon_name="webcam")
         return False
     finally:
         self.webcam_lock.release()
Пример #9
0
    def _do_paint_rgb(self, cairo_format, has_alpha, img_data, x, y, width,
                      height, rowstride, options):
        """ must be called from UI thread """
        log("cairo._do_paint_rgb(%s, %s, %s bytes,%s,%s,%s,%s,%s,%s)",
            cairo_format, has_alpha, len(img_data), x, y, width, height,
            rowstride, options)
        rgb_format = options.strget("rgb_format", "RGB")
        if _memoryview and isinstance(img_data, _memoryview):
            #Pixbuf cannot use the memoryview directly:
            img_data = img_data.tobytes()
        #"cairo.ImageSurface.create_for_data" is not implemented in GTK3! ARGH!
        # http://cairographics.org/documentation/pycairo/3/reference/surfaces.html#cairo.ImageSurface.create_for_data
        # "Not yet available in Python 3"
        #
        #It is available in the cffi cairo bindings, which can be used instead of pycairo
        # but then we can't use it from the draw callbacks:
        # https://mail.gnome.org/archives/python-hackers-list/2011-December/msg00004.html
        # "PyGObject just lacks the glue code that allows it to pass the statically-wrapped
        # cairo.Pattern to introspected methods"

        if not is_gtk3() and rgb_format in ("ARGB", "XRGB"):
            #the pixel format is also what cairo expects
            #maybe we should also check that the stride is acceptable for cairo?
            #cairo_stride = cairo.ImageSurface.format_stride_for_width(cairo_format, width)
            #log("cairo_stride=%s, stride=%s", cairo_stride, rowstride)
            img_surface = cairo.ImageSurface.create_for_data(
                img_data, cairo_format, width, height, rowstride)
            return self.cairo_paint_surface(img_surface, x, y)

        if not is_gtk3() and rgb_format in ("RGBA", "RGBX"):
            #with GTK2, we can use a pixbuf from RGB(A) pixels
            if rgb_format == "RGBA":
                #we have to unpremultiply for pixbuf!
                img_data = self.unpremultiply(img_data)
            pixbuf = pixbuf_new_from_data(img_data, COLORSPACE_RGB, has_alpha,
                                          8, width, height, rowstride)
            return self.cairo_paint_pixbuf(pixbuf, x, y)

        #PIL fallback
        PIL = get_codec("PIL")
        if has_alpha:
            oformat = "RGBA"
        else:
            oformat = "RGB"
        img = PIL.Image.frombuffer(oformat, (width, height), img_data, "raw",
                                   rgb_format, rowstride, 1)
        #This is insane, the code below should work, but it doesn't:
        # img_data = bytearray(img.tostring('raw', oformat, 0, 1))
        # pixbuf = pixbuf_new_from_data(img_data, COLORSPACE_RGB, True, 8, width, height, rowstride)
        # success = self.cairo_paint_pixbuf(pixbuf, x, y)
        #So we still rountrip via PNG:
        png = BytesIOClass()
        img.save(png, format="PNG")
        reader = BytesIOClass(png.getvalue())
        png.close()
        img = cairo.ImageSurface.create_from_png(reader)
        return self.cairo_paint_surface(img, x, y)
Пример #10
0
    def test_webcam(self):
        if not POSIX or OSX:
            get_util_logger().info("webcam test skipped: %s not supported yet",
                                   sys.platform)
            return
        from xpra.platform.xposix.webcam import get_virtual_video_devices, check_virtual_dir
        if not check_virtual_dir():
            get_util_logger().info(
                "webcam test skipped: no virtual video device directory")
            return
        devices = get_virtual_video_devices()
        if not devices:
            get_util_logger().info(
                "webcam test skipped: no virtual video devices found")
            return
        from xpra.server.source.webcam_mixin import WebcamMixin
        server = AdHocStruct()
        wm = WebcamMixin()
        server.webcam_enabled = True
        server.webcam_device = None
        server.webcam_encodings = ["png", "jpeg"]
        wm.init_from(None, server)
        wm.init_state()
        wm.hello_sent = True
        packets = []

        def send(*args):
            packets.append(args)

        #wm.send = send
        wm.send_async = send
        try:
            assert wm.get_info()
            device_id = 0
            w, h = 640, 480
            assert wm.start_virtual_webcam(device_id, w, h)
            assert wm.get_info().get("webcam", {}).get("active-devices",
                                                       0) == 1
            assert len(packets) == 1  #ack sent
            frame_no = 0
            encoding = "png"
            buf = BytesIOClass()
            from PIL import Image
            image = Image.new('RGB', size=(w, h), color=(155, 0, 0))
            image.save(buf, 'jpeg')
            data = buf.getvalue()
            buf.close()
            wm.process_webcam_frame(device_id, frame_no, encoding, w, h, data)
            assert len(packets) == 2  #ack sent
            wm.stop_virtual_webcam(device_id)
        finally:
            wm.cleanup()
Пример #11
0
 def take_screenshot(self):
     x, y, w, h = get_virtualscreenmetrics()
     image = self.get_image(x, y, w, h)
     if not image:
         return None
     assert image.get_width()==w and image.get_height()==h
     assert image.get_pixel_format()=="BGRX"
     img = Image.frombuffer("RGB", (w, h), image.get_pixels(), "raw", "BGRX", 0, 1)
     out = BytesIOClass()
     img.save(out, format="PNG")
     screenshot = (img.width, img.height, "png", img.width*3, out.getvalue())
     out.close()
     return screenshot
Пример #12
0
    def _do_paint_rgb(self, cairo_format, has_alpha, img_data, x, y, width, height, rowstride, options):
        """ must be called from UI thread """
        log("cairo._do_paint_rgb(%s, %s, %s bytes,%s,%s,%s,%s,%s,%s)", cairo_format, has_alpha, len(img_data), x, y, width, height, rowstride, options)
        rgb_format = options.strget("rgb_format", "RGB")
        if _memoryview and isinstance(img_data, _memoryview):
            #Pixbuf cannot use the memoryview directly:
            img_data = img_data.tobytes()
        #"cairo.ImageSurface.create_for_data" is not implemented in GTK3! ARGH!
        # http://cairographics.org/documentation/pycairo/3/reference/surfaces.html#cairo.ImageSurface.create_for_data
        # "Not yet available in Python 3"
        #
        #It is available in the cffi cairo bindings, which can be used instead of pycairo
        # but then we can't use it from the draw callbacks:
        # https://mail.gnome.org/archives/python-hackers-list/2011-December/msg00004.html
        # "PyGObject just lacks the glue code that allows it to pass the statically-wrapped
        # cairo.Pattern to introspected methods"

        if not is_gtk3() and rgb_format in ("ARGB", "XRGB"):
            #the pixel format is also what cairo expects
            #maybe we should also check that the stride is acceptable for cairo?
            #cairo_stride = cairo.ImageSurface.format_stride_for_width(cairo_format, width)
            #log("cairo_stride=%s, stride=%s", cairo_stride, rowstride)
            img_surface = cairo.ImageSurface.create_for_data(img_data, cairo_format, width, height, rowstride)
            return self.cairo_paint_surface(img_surface, x, y)

        if not is_gtk3() and rgb_format in ("RGBA", "RGBX"):
            #with GTK2, we can use a pixbuf from RGB(A) pixels
            if rgb_format=="RGBA":
                #we have to unpremultiply for pixbuf!
                img_data = self.unpremultiply(img_data)
            pixbuf = pixbuf_new_from_data(img_data, COLORSPACE_RGB, has_alpha, 8, width, height, rowstride)
            return self.cairo_paint_pixbuf(pixbuf, x, y)

        #PIL fallback
        PIL = get_codec("PIL")
        if has_alpha:
            oformat = "RGBA"
        else:
            oformat = "RGB"
        img = PIL.Image.frombuffer(oformat, (width,height), img_data, "raw", rgb_format, rowstride, 1)
        #This is insane, the code below should work, but it doesn't:
        # img_data = bytearray(img.tostring('raw', oformat, 0, 1))
        # pixbuf = pixbuf_new_from_data(img_data, COLORSPACE_RGB, True, 8, width, height, rowstride)
        # success = self.cairo_paint_pixbuf(pixbuf, x, y)
        #So we still rountrip via PNG:
        png = BytesIOClass()
        img.save(png, format="PNG")
        reader = BytesIOClass(png.getvalue())
        png.close()
        img = cairo.ImageSurface.create_from_png(reader)
        return self.cairo_paint_surface(img, x, y)
Пример #13
0
 def do_paint_rgb24(self, img_data, x, y, width, height, rowstride, options, callbacks):
     """ must be called from UI thread """
     if DRAW_DEBUG:
         log.info("cairo_paint_rgb24(..,%s,%s,%s,%s,%s,%s,%s)", x, y, width, height, rowstride, options, callbacks)
     if self._backing is None:
         fire_paint_callbacks(callbacks, False)
         return  False
     assert PIL, "cannot paint without PIL!"
     if rowstride==0:
         rowstride = width * 3
     im = PIL.Image.frombuffer("RGB", (width, height), img_data, "raw", "RGB", rowstride)
     buf = BytesIOClass()
     im.save(buf, "PNG")
     data = buf.getvalue()
     buf.close()
     img_data = BytesIOClass(data)
     self.do_paint_png(img_data, x, y, width, height, rowstride, options, callbacks)
     return  False
Пример #14
0
 def get_notification_icon(self, icon_string):
     #the string may be:
     # * a path which we will load using pillow
     # * a name we lookup in the current them
     if not icon_string:
         return ()
     img = None
     from PIL import Image
     if os.path.isabs(icon_string):
         if os.path.exists(icon_string) and os.path.isfile(icon_string):
             img = Image.open(icon_string)
             w, h = img.size
     else:
         #try to find it in the theme:
         theme = gtk.icon_theme_get_default()
         if theme:
             try:
                 icon = theme.load_icon(icon_string, gtk.ICON_SIZE_BUTTON,
                                        0)
             except Exception as e:
                 notifylog(
                     "failed to load icon '%s' from default theme: %s",
                     icon_string, e)
             else:
                 data = icon.get_pixels()
                 w = icon.get_width()
                 h = icon.get_height()
                 rowstride = icon.get_rowstride()
                 mode = "RGB"
                 if icon.get_has_alpha():
                     mode = "RGBA"
                 img = Image.frombytes(mode, (w, h), data, "raw", mode,
                                       rowstride)
     if img:
         if w > 256 or h > 256:
             img = img.resize((256, 256), Image.ANTIALIAS)
             w = h = 256
         buf = BytesIOClass()
         img.save(buf, "PNG")
         cpixels = buf.getvalue()
         buf.close()
         return "png", w, h, cpixels
     return ()
Пример #15
0
 def do_paint_rgb24(self, img_data, x, y, width, height, rowstride, options, callbacks):
     """ must be called from UI thread """
     if DRAW_DEBUG:
         log.info("cairo_paint_rgb24(..,%s,%s,%s,%s,%s,%s,%s)", x, y, width, height, rowstride, options, callbacks)
     if self._backing is None:
         fire_paint_callbacks(callbacks, False)
         return  False
     PIL = get_codec("PIL")
     assert PIL, "cannot paint without PIL!"
     if rowstride==0:
         rowstride = width * 3
     im = PIL.Image.frombuffer("RGB", (width, height), img_data, "raw", "RGB", rowstride)
     buf = BytesIOClass()
     im.save(buf, "PNG")
     data = buf.getvalue()
     buf.close()
     img_data = BytesIOClass(data)
     self.do_paint_png(img_data, x, y, width, height, rowstride, options, callbacks)
     return  False
Пример #16
0
    def test_webcam(self):
        if not POSIX or OSX:
            return
        from xpra.platform.xposix.webcam import get_virtual_video_devices, check_virtual_dir
        if not check_virtual_dir():
            return
        devices = get_virtual_video_devices()
        if not devices:
            return
        from xpra.server.source.webcam_mixin import WebcamMixin
        wm = WebcamMixin(True, None, ["png", "jpeg"])
        wm.init_state()
        wm.hello_sent = True
        packets = []

        def send(*args):
            packets.append(args)

        #wm.send = send
        wm.send_async = send
        try:
            assert wm.get_info()
            device_id = 0
            w, h = 640, 480
            assert wm.start_virtual_webcam(device_id, w, h)
            assert wm.get_info().get("webcam", {}).get("active-devices",
                                                       0) == 1
            assert len(packets) == 1  #ack sent
            frame_no = 0
            encoding = "png"
            buf = BytesIOClass()
            from PIL import Image
            image = Image.new('RGB', size=(w, h), color=(155, 0, 0))
            image.save(buf, 'jpeg')
            data = buf.getvalue()
            buf.close()
            wm.process_webcam_frame(device_id, frame_no, encoding, w, h, data)
            assert len(packets) == 2  #ack sent
            wm.stop_virtual_webcam(device_id)
        finally:
            wm.cleanup()
Пример #17
0
 def command_callback(hwnd, cid):
     if cid == 1024:
         from xpra.platform.win32.win32_balloon import notify
         from xpra.os_util import BytesIOClass
         try:
             from PIL import Image  #@UnresolvedImport
             img = Image.open("icons\\printer.png")
             buf = BytesIOClass()
             img.save(buf, "PNG")
             data = buf.getvalue()
             buf.close()
             icon = (b"png", img.size[0], img.size[1], data)
         except Exception as e:
             print("could not find icon: %s" % (e, ))
             icon = None
         else:
             pass
         notify(hwnd, 0, "hello", "world", timeout=1000, icon=icon)
     elif cid == 1025:
         print("Goodbye")
         DestroyWindow(hwnd)
     else:
         print("OnCommand for ID=%s" % cid)
Пример #18
0
def encode(coding, image, quality, speed, supports_transparency):
    pixel_format = image.get_pixel_format()
    w = image.get_width()
    h = image.get_height()
    rgb = {
           "XRGB"   : "RGB",
           "BGRX"   : "RGB",
           "RGBA"   : "RGBA",
           "BGRA"   : "RGBA",
           }.get(pixel_format, pixel_format)
    bpp = 32
    #remove transparency if it cannot be handled:
    try:
        pixels = image.get_pixels()
        assert pixels, "failed to get pixels from %s" % image
        #PIL cannot use the memoryview directly:
        if type(pixels)!=_buffer:
            pixels = memoryview_to_bytes(pixels)
        #it is safe to use frombuffer() here since the convert()
        #calls below will not convert and modify the data in place
        #and we save the compressed data then discard the image
        im = PIL.Image.frombuffer(rgb, (w, h), pixels, "raw", pixel_format, image.get_rowstride())
        if coding.startswith("png") and not supports_transparency and rgb=="RGBA":
            im = im.convert("RGB")
            rgb = "RGB"
            bpp = 24
    except Exception:
        log.error("PIL_encode%s converting %s pixels from %s to %s failed", (w, h, coding, "%s bytes" % image.get_size(), pixel_format, image.get_rowstride()), type(pixels), pixel_format, rgb, exc_info=True)
        raise
    buf = BytesIOClass()
    client_options = {}
    #only optimize with Pillow>=2.2 and when speed is zero
    if coding in ("jpeg", "webp"):
        q = int(min(99, max(1, quality)))
        kwargs = im.info
        kwargs["quality"] = q
        client_options["quality"] = q
        if coding=="jpeg" and PIL_can_optimize and speed<70:
            #(optimizing jpeg is pretty cheap and worth doing)
            kwargs["optimize"] = True
            client_options["optimize"] = True
        im.save(buf, coding.upper(), **kwargs)
    else:
        assert coding in ("png", "png/P", "png/L"), "unsupported png encoding: %s" % coding
        if coding in ("png/L", "png/P") and supports_transparency and rgb=="RGBA":
            #grab alpha channel (the last one):
            #we use the last channel because we know it is RGBA,
            #otherwise we should do: alpha_index= image.getbands().index('A')
            alpha = im.split()[-1]
            #convert to simple on or off mask:
            #set all pixel values below 128 to 255, and the rest to 0
            def mask_value(a):
                if a<=128:
                    return 255
                return 0
            mask = PIL.Image.eval(alpha, mask_value)
        else:
            #no transparency
            mask = None
        if coding=="png/L":
            im = im.convert("L", palette=PIL.Image.ADAPTIVE, colors=255)
            bpp = 8
        elif coding=="png/P":
            #I wanted to use the "better" adaptive method,
            #but this does NOT work (produces a black image instead):
            #im.convert("P", palette=Image.ADAPTIVE)
            im = im.convert("P", palette=PIL.Image.WEB, colors=255)
            bpp = 8
        if mask:
            # paste the alpha mask to the color of index 255
            im.paste(255, mask)
        kwargs = im.info
        if mask is not None:
            client_options["transparency"] = 255
            kwargs["transparency"] = 255
        if PIL_can_optimize and speed==0:
            #optimizing png is very rarely worth doing
            kwargs["optimize"] = True
            client_options["optimize"] = True
        #level can range from 0 to 9, but anything above 5 is way too slow for small gains:
        #76-100   -> 1
        #51-76    -> 2
        #etc
        level = max(1, min(5, (125-speed)//25))
        kwargs["compress_level"] = level
        client_options["compress_level"] = level
        #default is good enough, no need to override, other options:
        #DEFAULT_STRATEGY, FILTERED, HUFFMAN_ONLY, RLE, FIXED
        #kwargs["compress_type"] = PIL.Image.DEFAULT_STRATEGY
        im.save(buf, "PNG", **kwargs)
    log("sending %sx%s %s as %s, mode=%s, options=%s", w, h, pixel_format, coding, im.mode, kwargs)
    data = buf.getvalue()
    buf.close()
    return coding, compression.Compressed(coding, data), client_options, image.get_width(), image.get_height(), 0, bpp
Пример #19
0
    def compress_and_send_window_icon(self):
        #this runs in the work queue
        self.send_window_icon_timer = 0
        idata = self.window_icon_data
        if not idata:
            return
        w, h, pixel_format, pixel_data = idata
        log("compress_and_send_window_icon() %ix%i in %s format, %i bytes", w, h, pixel_format, len(pixel_data))
        assert pixel_format in ("BGRA", "RGBA", "png"), "invalid window icon format %s" % pixel_format
        if pixel_format=="BGRA":
            #BGRA data is always unpremultiplied
            #(that's what we get from NetWMIcons)
            from xpra.codecs.argb.argb import premultiply_argb  #@UnresolvedImport
            pixel_data = premultiply_argb(pixel_data)

        max_w, max_h = self.window_icon_max_size
        #use png if supported and if "premult_argb32" is not supported by the client (ie: html5)
        #or if we must downscale it (bigger than what the client is willing to deal with),
        #or if we want to save window icons
        must_scale = w>max_w or h>max_h
        use_png = self.has_png and (must_scale or not self.has_premult or w*h>=MAX_ARGB_PIXELS)
        log("compress_and_send_window_icon: %sx%s (max-size=%s, standard-size=%s), sending as png=%s, pixel_format=%s",
            w, h, self.window_icon_max_size, self.window_icon_size, use_png, pixel_format)
        must_convert = (use_png and pixel_format!="png") or (pixel_format=="png" and not use_png) or (pixel_format=="BGRA" and not self.has_premult)
        log(" must convert=%s, must scale=%s", must_convert, must_scale)

        image = None
        if must_scale or must_convert or SAVE_WINDOW_ICONS:
            #we're going to need a PIL Image:
            if pixel_format=="png":
                image = Image.open(BytesIOClass(pixel_data))
            else:
                #note: little endian makes this confusing.. RGBA for pillow is BGRA in memory
                if pixel_format=="RGBA":
                    src_format = "BGRA"
                else:
                    src_format = "RGBA"
                image = Image.frombuffer("RGBA", (w,h), memoryview_to_bytes(pixel_data), "raw", src_format, 0, 1)
            if must_scale:
                #scale the icon down to the size the client wants
                #(we should scale + paste to preserve the aspect ratio, meh)
                icon_w, icon_h = self.window_icon_size
                if float(w)/icon_w>=float(h)/icon_h:
                    rh = min(max_h, h*icon_w//w)
                    rw = icon_w
                else:
                    rw = min(max_w, w*icon_h//h)
                    rh = icon_h
                log("scaling window icon down to %sx%s", rw, rh)
                image = image.resize((rw, rh), Image.ANTIALIAS)
            if SAVE_WINDOW_ICONS:
                filename = "server-window-%i-icon-%i.png" % (self.wid, int(monotonic_time()))
                image.save(filename, 'PNG')
                log("server window icon saved to %s", filename)

        if use_png:
            if image:
                #image got converted or scaled, get the new pixel data:
                output = BytesIOClass()
                image.save(output, "png")
                pixel_data = output.getvalue()
                output.close()
                w, h = image.size
            wrapper = compression.Compressed("png", pixel_data)
        else:
            if image:
                pixel_data = image.tobytes("raw", "RGBA")
            wrapper = self.compressed_wrapper("premult_argb32", memoryview_to_bytes(pixel_data))
        packet = ("window-icon", self.wid, w, h, wrapper.datatype, wrapper)
        log("queuing window icon update: %s", packet)
        self.queue_packet(packet, wait_for_more=True)
Пример #20
0
def encode(coding, image, quality, speed, supports_transparency):
    log("pillow.encode%s", (coding, image, quality, speed, supports_transparency))
    pixel_format = bytestostr(image.get_pixel_format())
    palette = None
    w = image.get_width()
    h = image.get_height()
    rgb = {
        "RLE8"  : "P",
        "XRGB"  : "RGB",
        "BGRX"  : "RGB",
        "RGBX"  : "RGB",
        "RGBA"  : "RGBA",
        "BGRA"  : "RGBA",
        "BGR"   : "RGB",
        }.get(pixel_format, pixel_format)
    bpp = 32
    #remove transparency if it cannot be handled,
    #and deal with non 24-bit formats:
    try:
        pixels = image.get_pixels()
        assert pixels, "failed to get pixels from %s" % image
        if pixel_format=="r210":
            from xpra.codecs.argb.argb import r210_to_rgba, r210_to_rgb #@UnresolvedImport
            if supports_transparency:
                pixels = r210_to_rgba(pixels)
                pixel_format = "RGBA"
                rgb = "RGBA"
            else:
                image.set_rowstride(image.get_rowstride()*3//4)
                pixels = r210_to_rgb(pixels)
                pixel_format = "RGB"
                rgb = "RGB"
                bpp = 24
        elif pixel_format=="BGR565":
            from xpra.codecs.argb.argb import bgr565_to_rgbx, bgr565_to_rgb    #@UnresolvedImport
            if supports_transparency:
                image.set_rowstride(image.get_rowstride()*2)
                pixels = bgr565_to_rgbx(pixels)
                pixel_format = "RGBA"
                rgb = "RGBA"
            else:
                image.set_rowstride(image.get_rowstride()*3//2)
                pixels = bgr565_to_rgb(pixels)
                pixel_format = "RGB"
                rgb = "RGB"
                bpp = 24
        elif pixel_format=="RLE8":
            pixel_format = "P"
            palette = []
            #pillow requires 8 bit palette values,
            #but we get 16-bit values from the image wrapper (X11 palettes are 16-bit):
            for r, g, b in image.get_palette():
                palette.append((r>>8) & 0xFF)
                palette.append((g>>8) & 0xFF)
                palette.append((b>>8) & 0xFF)
            bpp = 8
        #PIL cannot use the memoryview directly:
        if isinstance(pixels, memoryview):
            pixels = pixels.tobytes()
        #it is safe to use frombuffer() here since the convert()
        #calls below will not convert and modify the data in place
        #and we save the compressed data then discard the image
        im = Image.frombuffer(rgb, (w, h), pixels, "raw", pixel_format, image.get_rowstride(), 1)
        if palette:
            im.putpalette(palette)
            im.palette = ImagePalette.ImagePalette("RGB", palette = palette, size = len(palette))
        if coding.startswith("png") and not supports_transparency and rgb=="RGBA":
            im = im.convert("RGB")
            rgb = "RGB"
            bpp = 24
    except Exception:
        log.error("PIL_encode%s converting %s pixels from %s to %s failed", (w, h, coding, "%s bytes" % image.get_size(), pixel_format, image.get_rowstride()), type(pixels), pixel_format, rgb, exc_info=True)
        raise
    client_options = {}
    if coding in ("jpeg", "webp", "jpeg2000"):
        #newer versions of pillow require explicit conversion to non-alpha:
        if pixel_format.find("A")>=0:
            im = im.convert("RGB")
        q = int(min(100, max(1, quality)))
        kwargs = im.info
        kwargs["quality"] = q
        client_options["quality"] = q
        if coding=="jpeg2000":
            kwargs["quality_mode"] = "rates"    #other option: "dB"
            kwargs["quality_layers"] = max(1, (100-q)*5)
        elif coding=="jpeg" and speed<50:
            #(optimizing jpeg is pretty cheap and worth doing)
            kwargs["optimize"] = True
            client_options["optimize"] = True
        elif coding=="webp" and q>=100:
            kwargs["lossless"] = 1
        pil_fmt = coding.upper()
    else:
        assert coding in ("png", "png/P", "png/L"), "unsupported encoding: %s" % coding
        if coding in ("png/L", "png/P") and supports_transparency and rgb=="RGBA":
            #grab alpha channel (the last one):
            #we use the last channel because we know it is RGBA,
            #otherwise we should do: alpha_index= image.getbands().index('A')
            alpha = im.split()[-1]
            #convert to simple on or off mask:
            #set all pixel values below 128 to 255, and the rest to 0
            def mask_value(a):
                if a<=128:
                    return 255
                return 0
            mask = Image.eval(alpha, mask_value)
        else:
            #no transparency
            mask = None
        if coding=="png/L":
            im = im.convert("L", palette=Image.ADAPTIVE, colors=255)
            bpp = 8
        elif coding=="png/P":
            #convert to 255 indexed colour if:
            # * we're not in palette mode yet (source is >8bpp)
            # * we need space for the mask (256 -> 255)
            if palette is None or mask:
                #I wanted to use the "better" adaptive method,
                #but this does NOT work (produces a black image instead):
                #im.convert("P", palette=Image.ADAPTIVE)
                im = im.convert("P", palette=Image.WEB, colors=255)
            bpp = 8
        kwargs = im.info
        if mask:
            # paste the alpha mask to the color of index 255
            im.paste(255, mask)
            client_options["transparency"] = 255
            kwargs["transparency"] = 255
        if speed==0:
            #optimizing png is very rarely worth doing
            kwargs["optimize"] = True
            client_options["optimize"] = True
        #level can range from 0 to 9, but anything above 5 is way too slow for small gains:
        #76-100   -> 1
        #51-76    -> 2
        #etc
        level = max(1, min(5, (125-speed)//25))
        kwargs["compress_level"] = level
        #no need to expose to the client:
        #client_options["compress_level"] = level
        #default is good enough, no need to override, other options:
        #DEFAULT_STRATEGY, FILTERED, HUFFMAN_ONLY, RLE, FIXED
        #kwargs["compress_type"] = Image.DEFAULT_STRATEGY
        pil_fmt = "PNG"
    buf = BytesIOClass()
    im.save(buf, pil_fmt, **kwargs)
    if SAVE_TO_FILE:
        filename = "./%s.%s" % (time.time(), pil_fmt)
        im.save(filename, pil_fmt)
        log.info("saved %s to %s", coding, filename)
    log("sending %sx%s %s as %s, mode=%s, options=%s", w, h, pixel_format, coding, im.mode, kwargs)
    data = buf.getvalue()
    buf.close()
    return coding, Compressed(coding, data), client_options, image.get_width(), image.get_height(), 0, bpp
Пример #21
0
 def compress_and_send_window_icon(self):
     #this runs in the work queue
     self.send_window_icon_timer = 0
     idata = self.window_icon_data
     if not idata:
         return
     pixel_data, pixel_format, stride, w, h = idata
     PIL = get_codec("PIL")
     max_w, max_h = self.window_icon_max_size
     if stride != w * 4:
         #re-stride it (I don't think this ever fires?)
         pixel_data = b"".join(pixel_data[stride * y:stride * y + w * 4]
                               for y in range(h))
         stride = w * 4
     #use png if supported and if "premult_argb32" is not supported by the client (ie: html5)
     #or if we must downscale it (bigger than what the client is willing to deal with),
     #or if we want to save window icons
     has_png = PIL and PNG_ICONS and ("png" in self.window_icon_encodings)
     has_premult = ARGB_ICONS and "premult_argb32" in self.window_icon_encodings
     use_png = has_png and (SAVE_WINDOW_ICONS or w > max_w or h > max_h
                            or w * h >= 1024 or (not has_premult) or
                            (pixel_format != "BGRA"))
     log(
         "compress_and_send_window_icon: %sx%s (max-size=%s, standard-size=%s), sending as png=%s, has_png=%s, has_premult=%s, pixel_format=%s",
         w, h, self.window_icon_max_size, self.window_icon_size, use_png,
         has_png, has_premult, pixel_format)
     if use_png:
         img = PIL.Image.frombuffer("RGBA", (w, h), pixel_data, "raw",
                                    pixel_format, 0, 1)
         if w > max_w or h > max_h:
             #scale the icon down to the size the client wants
             icon_w, icon_h = self.window_icon_size
             if float(w) / icon_w >= float(h) / icon_h:
                 h = min(max_h, h * icon_w // w)
                 w = icon_w
             else:
                 w = min(max_w, w * icon_h // h)
                 h = icon_h
             log("scaling window icon down to %sx%s", w, h)
             img = img.resize((w, h), PIL.Image.ANTIALIAS)
         output = BytesIOClass()
         img.save(output, 'PNG')
         compressed_data = output.getvalue()
         output.close()
         wrapper = compression.Compressed("png", compressed_data)
         if SAVE_WINDOW_ICONS:
             filename = "server-window-%i-icon-%i.png" % (
                 self.wid, int(monotonic_time()))
             img.save(filename, 'PNG')
             log("server window icon saved to %s", filename)
     elif ("premult_argb32"
           in self.window_icon_encodings) and pixel_format == "BGRA":
         wrapper = self.compressed_wrapper("premult_argb32",
                                           str(pixel_data))
     else:
         log("cannot send window icon, supported encodings: %s",
             self.window_icon_encodings)
         return
     assert wrapper.datatype in (
         "premult_argb32",
         "png"), "invalid wrapper datatype %s" % wrapper.datatype
     packet = ("window-icon", self.wid, w, h, wrapper.datatype, wrapper)
     log("queuing window icon update: %s", packet)
     self.queue_packet(packet, wait_for_more=True)
Пример #22
0
 def paint_pil_image(self, pil_image, width, height, rowstride, options, callbacks):
     buf = BytesIOClass()
     pil_image.save(buf, format="PNG")
     png_data = buf.getvalue()
     buf.close()
     self.idle_add(self.paint_png, png_data, 0, 0, width, height, rowstride, options, callbacks)