Esempio n. 1
0
def _cairo_surface_write_to_bmp(img: cairo.ImageSurface) -> bytes:

    data = bytes(img.get_data())
    return (
        b"BM"
        + struct.pack(
            "<ihhiiiihhiiiiii",
            54 + len(data),  # size of BMP file
            0,  # unused
            0,  # unused
            54,  # pixel array offset
            40,  # DIB header
            img.get_width(),  # width
            img.get_height(),  # height
            1,  # planes
            32,  # BPP
            0,  # no compression
            len(data),  # size of the raw bitmap data
            2835,  # 72DPI H
            2835,  # 72DPI V
            0,  # palette
            0,  # all colors are important
        )
        + data
    )
    def renegerate_overlay_buffer(self):
        image = ImageSurface(cairo.FORMAT_ARGB32, self.video_width, self.video_height)
        context = Context(image)
        text = "Foo bar 123"
        font = pango.FontDescription('sans normal 22')
        text_offset = [6, 6]

        textOverflowed = False
        if text:
            pcContext = pangocairo.CairoContext(context)
            pangoLayout = pcContext.create_layout()
            font = pango.FontDescription('sans normal 22')
            pangoLayout.set_font_description(font)
    
            context.move_to(text_offset[0]+2, text_offset[1]+2)
            pangoLayout.set_markup('<span foreground="black" >%s</span>' % text)
            pcContext.show_layout(pangoLayout)
            context.move_to(text_offset[0], text_offset[1])
            pangoLayout.set_markup('<span foreground="white" >%s</span>' % text)
            pcContext.show_layout(pangoLayout)
    
            textWidth, textHeight = pangoLayout.get_pixel_size()
        
        self.overlay_buffer = image.get_data()
        print "overlay_buffer size: %d" % len(self.overlay_buffer)
Esempio n. 3
0
def _surface_to_array(surface: cairo.ImageSurface) -> np.ndarray:
    """convert surface to array"""

    # NOTE! The format of the array is PREMULTIPLIED ALPHA, not RGBA!
    res = np.ndarray(
        (surface.get_height(), surface.get_width(),
         4),  # do height and width work here???
        dtype=np.uint8,
        buffer=surface.get_data())
    res = res[:, :, [2, 1, 0, 3]]  # swap RGB order like OpenCV
    return res
Esempio n. 4
0
def _tonumpy(surface: cairo.ImageSurface):
    np_image = np.ndarray(
        shape=(surface.get_height(), surface.get_width(), 4),
        dtype=np.uint8,
        buffer=surface.get_data(),
        strides=(surface.get_width() * 4, 4, 1)
    )
    np_image = np_image[:, :, :-1]
    np_image = np_image[:, :, ::-1]
    np_image = np_image.copy()
    return np_image
Esempio n. 5
0
def motionblur(target: cairo.ImageSurface, t: float, draw: Callable, look_ahead: float, n: int):
    w = target.get_width()
    h = target.get_width()
    frames = []
    for tt in np.linspace(0, look_ahead, n):
        frame = np.zeros((w * h * 4,), dtype=np.uint8)
        surface = cairo.ImageSurface.create_for_data(memoryview(frame), cairo.Format.RGB24, w, h)
        draw(surface, t + tt)
        #frames.append(degamma(frame))
        frames.append(frame)

    avg = np.average(np.stack(frames), axis=0).astype(np.uint8)
    #avg = gamma(np.average(np.stack(frames), axis=0)).astype(np.uint8)
    data = target.get_data()
    for i in range(len(data)):
        data[i] = avg[i]
Esempio n. 6
0
def draw_triangle(target: cairo.ImageSurface, triangle, attributes,
                  texture: Texture):
    # drop z coordinate
    p0, p1, p2 = [p[:2] for p in triangle]

    # compute area
    area = edge(p0, p1, p2)

    if area == 0:
        return

    width, height = resolution(target)
    xmin = int(max(min(p0[0], p1[0], p2[0]), 0))
    xmax = int(min(max(p0[0], p1[0], p2[0]), width))
    ymin = int(max(min(p0[1], p1[1], p2[1]), 0))
    ymax = int(min(max(p0[1], p1[1], p2[1]), height))

    x, y = np.meshgrid(range(xmin, xmax), range(ymin, ymax), indexing='xy')
    p = np.vstack([x.ravel(), y.ravel()]).T
    # Barycentric coordinates are calculated as the areas of the three sub-triangles divided
    # by the area of the whole triangle.
    barycentric = np.vstack(
        [edge(p1, p2, p), edge(p2, p0, p),
         edge(p0, p1, p)]).T / area

    # Find all indices of rows where all columns are positive
    is_inside = np.all(barycentric >= 0, axis=-1)

    # Compute indices of all points inside triangle
    stride = np.array([4, target.get_stride()])
    indices = np.dot(p[is_inside], stride)

    # Interpolate vertex attributes
    attrs = np.dot(barycentric[is_inside], attributes)

    # Fill pixels
    data = target.get_data()
    for index, (u, v) in zip(indices, attrs):
        r, g, b = texture(u, v)
        data[index + 0] = r
        data[index + 1] = g
        data[index + 2] = b
Esempio n. 7
0
    def draw(self, target: cairo.ImageSurface):
        saved = self.positions, self.t

        n = 4
        lookahead = 0.2
        dt = lookahead / n

        targets = []
        for _ in range(n):
            image = cairo.ImageSurface(cairo.Format.RGB24, target.get_width(),
                                       target.get_height())
            self.draw_frame(image)
            targets.append(image)
            self.step(dt)

        data = target.get_data()
        for i in range(len(data)):
            data[i] = int(sum(img.get_data()[i] for img in targets) / n)

        self.positions, self.t = saved
Esempio n. 8
0
    def _scale_down(self, handle, ratio):
        xsize, ysize = self.size
        if ratio >= 1.0:
            # Convert
            surface = ImageSurface(FORMAT_ARGB32, xsize, ysize)
            ctx = Context(surface)
        else:
            # Scale
            xsize, ysize = int(xsize * ratio), int(ysize * ratio)
            surface = ImageSurface(FORMAT_ARGB32, xsize, ysize)
            ctx = Context(surface)
            ctx.scale(ratio, ratio)

        # Render
        handle.render_cairo(ctx)

        # Transform to a PIL image for further manipulation
        size = (xsize, ysize)
        im = frombuffer('RGBA', size, surface.get_data(), 'raw', 'BGRA', 0, 1)
        surface.finish()

        return im, xsize, ysize
Esempio n. 9
0
    def _scale_down(self, handle, ratio):
        xsize, ysize = self.size
        if ratio >= 1.0:
            # Convert
            surface = ImageSurface(FORMAT_ARGB32, xsize, ysize)
            ctx = Context(surface)
        else:
            # Scale
            xsize, ysize = int(xsize * ratio), int(ysize * ratio)
            surface = ImageSurface(FORMAT_ARGB32, xsize, ysize)
            ctx = Context(surface)
            ctx.scale(ratio, ratio)

        # Render
        handle.render_cairo(ctx)

        # Transform to a PIL image for further manipulation
        size = (xsize, ysize)
        im = frombuffer('RGBA', size, surface.get_data(), 'raw', 'BGRA', 0, 1)
        surface.finish()

        return im, xsize, ysize
     L = make_label('Hello', './Vera.ttf', size, angle=angle)
 except NotImplementedError:
     raise SystemExit("For python 3.x, you need pycairo >= 1.11+ (from https://github.com/pygobject/pycairo)")
 h = L.get_height()
 w = L.get_width()
 if h < H and w < W:
     x0 = W//2 + (random.uniform()-.1)*50
     y0 = H//2 + (random.uniform()-.1)*50
     for dx,dy in spiral():
         c = .25+.75*random.random()
         x = int(x0+dx)
         y = int(y0+dy)
         checked = False
         I.flush()
         if not (x <= w//2 or y <= h//2 or x >= (W-w//2) or y >= (H-h//2)):
             ndI = ndarray(shape=(h,w), buffer=I.get_data(), dtype=ubyte, order='C',
                           offset=(x-w//2) + I.get_stride() * (y-h//2),
                           strides=[I.get_stride(), 1])
             ndL = ndarray(shape=(h,w), buffer=L.get_data(), dtype=ubyte, order='C',
                           strides=[L.get_stride(), 1])
             if ((ndI * ndL).sum() == 0):
                checked = True
         new_region = RectangleInt(x-w//2, y-h//2, w, h)
         if  (checked or ( drawn_regions.contains_rectangle(new_region) == REGION_OVERLAP_OUT )):
             ctxI.set_source_surface(L, 0, 0)
             pattern = ctxI.get_source()
             scalematrix = Matrix()
             scalematrix.scale(1.0,1.0)
             scalematrix.translate(w//2 - x, h//2 - y)
             pattern.set_matrix(scalematrix)
             ctxI.set_source_rgba(c,c,c,c)
Esempio n. 11
0
def generateOverlay(text, font, showFlumotion, showCC, showXiph, width,
                    height):
    """Generate an transparent image with text + logotypes rendered on top
    of it suitable for mixing into a video stream
    @param text: text to put in the top left corner
    @type text: str
    @param font: font description used to render the text
    @type: str
    @param showFlumotion: if we should show the flumotion logo
    @type showFlumotion: bool
    @param showCC: if we should show the Creative Common logo
    @type showCC: bool
    @param showXiph: if we should show the xiph logo
    @type showXiph: bool
    @param width: width of the image to generate
    @type width: int
    @param height: height of the image to generate
    @type height: int
    @returns: raw image and if images or if text overflowed
    @rtype: 3 sized tuple of string and 2 booleans
    """
    from cairo import ImageSurface
    from cairo import Context

    image = ImageSurface(cairo.FORMAT_ARGB32, width, height)
    context = Context(image)

    subImages = []
    if showXiph:
        subImages.append(os.path.join(configure.imagedir, '36x36', 'xiph.png'))
    if showCC:
        subImages.append(os.path.join(configure.imagedir, '36x36', 'cc.png'))
    if showFlumotion:
        subImages.append(
            os.path.join(configure.imagedir, '36x36', 'fluendo.png'))

    imagesOverflowed = False

    offsetX = BORDER
    for subPath in subImages:
        sub = ImageSurface.create_from_png(subPath)
        subX = sub.get_width()
        subY = sub.get_height()
        offsetY = height - subY - BORDER
        context.set_source_surface(sub, offsetX, offsetY)
        context.paint()
        if (offsetX + subX) > width:
            imagesOverflowed = True
        offsetX += subX + BORDER

    textOverflowed = False
    if text:
        pcContext = pangocairo.CairoContext(context)
        pangoLayout = pcContext.create_layout()
        if font is not None:
            font = pango.FontDescription(font)
            if not font.get_family() or \
               not font.get_family().lower() in [family.get_name().lower()
                    for family in pangoLayout.get_context().list_families()]:
                font.set_family(FONT)
            if font.get_size() == 0:
                font.set_size(FONT_SIZE)
        else:
            font = pango.FontDescription('%s %s' % (FONT, FONT_PROPS))
        pangoLayout.set_font_description(font)

        context.move_to(TEXT_XOFFSET + 2, TEXT_YOFFSET + 2)
        pangoLayout.set_markup('<span foreground="black" >%s</span>' % text)
        pcContext.show_layout(pangoLayout)
        context.move_to(TEXT_XOFFSET, TEXT_YOFFSET)
        pangoLayout.set_markup('<span foreground="white" >%s</span>' % text)
        pcContext.show_layout(pangoLayout)

        textWidth, textHeight = pangoLayout.get_pixel_size()
        if textWidth > width:
            textOverflowed = True

    if cairo.version < '1.2.6':
        buf = image.get_data_as_rgba()
    else:
        buf = image.get_data()

    return buf, imagesOverflowed, textOverflowed
Esempio n. 12
0
# Google's NotoColorEmoji only accept size 109 to get 136x128 bitmaps
face.set_char_size( 160*64 )
face.load_char('😀', freetype.FT_LOAD_COLOR)

bitmap = face.glyph.bitmap
width = face.glyph.bitmap.width
rows = face.glyph.bitmap.rows

# The line below depends on this assumption. Check.
if ( face.glyph.bitmap.pitch != width * 4 ):
    raise RuntimeError('pitch != width * 4 for color bitmap: Please report this.')
bitmap = np.array(bitmap.buffer, dtype=np.uint8).reshape((bitmap.rows,bitmap.width,4))

I = ImageSurface(FORMAT_ARGB32, width, rows)
try:
    ndI = np.ndarray(shape=(rows,width), buffer=I.get_data(),
                     dtype=np.uint32, order='C',
                     strides=[I.get_stride(), 4])
except NotImplementedError:
    raise SystemExit("For python 3.x, you need pycairo >= 1.11+ (from https://github.com/pygobject/pycairo)")

# Although both are 32-bit, cairo is host-order while
# freetype is small endian.
ndI[:,:] = bitmap[:,:,3] * 2**24 + bitmap[:,:,2] * 2**16 + bitmap[:,:,1] * 2**8 + bitmap[:,:,0]
I.mark_dirty()

surface = ImageSurface(FORMAT_ARGB32, 2*width, rows)
ctx = Context(surface)

ctx.set_source_surface(I, 0, 0)
ctx.paint()
Esempio n. 13
0
                  strides=[pitch, 3])
    ndG = ndarray(shape=(rows, width),
                  buffer=copybuffer,
                  dtype=ubyte,
                  order='C',
                  offset=1,
                  strides=[pitch, 3])
    ndB = ndarray(shape=(rows, width),
                  buffer=copybuffer,
                  dtype=ubyte,
                  order='C',
                  offset=2,
                  strides=[pitch, 3])
    try:
        ndI = ndarray(shape=(rows, width),
                      buffer=I.get_data(),
                      dtype=uint32,
                      order='C',
                      strides=[I.get_stride(), 4])
    except NotImplementedError:
        raise SystemExit(
            "For python 3.x, you need pycairo >= 1.11+ (from https://github.com/pygobject/pycairo)"
        )
    # 255 * 2**24 = opaque
    ndI[:, :] = 255 * 2**24 + ndR[:, :] * 2**16 + ndG[:, :] * 2**8 + ndB[:, :]
    I.mark_dirty()

    surface = ImageSurface(FORMAT_ARGB32, 800, 600)
    ctx = Context(surface)

    ctx.set_source_surface(I, 0, 0)
Esempio n. 14
0
def generateOverlay(text,
                    font,
                    showFlumotion,
                    showCC,
                    showXiph,
                    width, height):
    """Generate an transparent image with text + logotypes rendered on top
    of it suitable for mixing into a video stream
    @param text: text to put in the top left corner
    @type text: str
    @param font: font description used to render the text
    @type: str
    @param showFlumotion: if we should show the flumotion logo
    @type showFlumotion: bool
    @param showCC: if we should show the Creative Common logo
    @type showCC: bool
    @param showXiph: if we should show the xiph logo
    @type showXiph: bool
    @param width: width of the image to generate
    @type width: int
    @param height: height of the image to generate
    @type height: int
    @returns: raw image and if images or if text overflowed
    @rtype: 3 sized tuple of string and 2 booleans
    """
    from cairo import ImageSurface
    from cairo import Context

    image = ImageSurface(cairo.FORMAT_ARGB32, width, height)
    context = Context(image)

    subImages = []
    if showXiph:
        subImages.append(os.path.join(configure.imagedir, '36x36', 'xiph.png'))
    if showCC:
        subImages.append(os.path.join(configure.imagedir, '36x36', 'cc.png'))
    if showFlumotion:
        subImages.append(os.path.join(configure.imagedir, '36x36',
                                      'fluendo.png'))

    imagesOverflowed = False

    offsetX = BORDER
    for subPath in subImages:
        sub = ImageSurface.create_from_png(subPath)
        subX = sub.get_width()
        subY = sub.get_height()
        offsetY = height - subY - BORDER
        context.set_source_surface(sub, offsetX, offsetY)
        context.paint()
        if (offsetX + subX) > width:
            imagesOverflowed = True
        offsetX += subX + BORDER

    textOverflowed = False
    if text:
        pcContext = pangocairo.CairoContext(context)
        pangoLayout = pcContext.create_layout()
        if font is not None:
            font = pango.FontDescription(font)
            if not font.get_family() or \
               not font.get_family().lower() in [family.get_name().lower()
                    for family in pangoLayout.get_context().list_families()]:
                font.set_family(FONT)
            if font.get_size() == 0:
                font.set_size(FONT_SIZE)
        else:
            font = pango.FontDescription('%s %s' % (FONT, FONT_PROPS))
        pangoLayout.set_font_description(font)

        context.move_to(TEXT_XOFFSET+2, TEXT_YOFFSET+2)
        pangoLayout.set_markup('<span foreground="black" >%s</span>' % text)
        pcContext.show_layout(pangoLayout)
        context.move_to(TEXT_XOFFSET, TEXT_YOFFSET)
        pangoLayout.set_markup('<span foreground="white" >%s</span>' % text)
        pcContext.show_layout(pangoLayout)

        textWidth, textHeight = pangoLayout.get_pixel_size()
        if textWidth > width:
            textOverflowed = True

    if cairo.version < '1.2.6':
        buf = image.get_data_as_rgba()
    else:
        buf = image.get_data()

    return buf, imagesOverflowed, textOverflowed
Esempio n. 15
0
# Google's NotoColorEmoji only accept size 109 to get 136x128 bitmaps
face.set_char_size( 160*64 )
face.load_char('😀', freetype.FT_LOAD_COLOR)

bitmap = face.glyph.bitmap
width = face.glyph.bitmap.width
rows = face.glyph.bitmap.rows

# The line below depends on this assumption. Check.
if ( face.glyph.bitmap.pitch != width * 4 ):
    raise RuntimeError('pitch != width * 4 for color bitmap: Please report this.')
bitmap = np.array(bitmap.buffer, dtype=np.uint8).reshape((bitmap.rows,bitmap.width,4))

I = ImageSurface(FORMAT_ARGB32, width, rows)
try:
    ndI = np.ndarray(shape=(rows,width), buffer=I.get_data(),
                     dtype=np.uint32, order='C',
                     strides=[I.get_stride(), 4])
except NotImplementedError:
    raise SystemExit("For python 3.x, you need pycairo >= 1.11+ (from https://github.com/pygobject/pycairo)")

# Although both are 32-bit, cairo is host-order while
# freetype is small endian.
ndI[:,:] = bitmap[:,:,3] * 2**24 + bitmap[:,:,2] * 2**16 + bitmap[:,:,1] * 2**8 + bitmap[:,:,0]
# ndI[...] = (bitmap*(1,2**8,2**16,2**24)).sum(axis=-1)


I.mark_dirty()

surface = ImageSurface(FORMAT_ARGB32, 2*width, rows)
ctx = Context(surface)