On Thu, 2006-11-09 at 12:31 -0500, Erik Blankinship wrote:
> Thanks, that sample code is very helpful for making the transition
> from cairo text rendering to cairo+pango text rendering.
> 
> Are there python examples for pango font metrics?
> When just using cairo's font rendering, I would make calls such as 
> x_bearing, y_bearing, width, height, x_advance, y_advance =
> ctx.text_extents( "how do i measure this in pango?" )

layout.get_pixel_extents() is probably what you are looking for.  It
returns to "rectangles", first one is ink, the second one is logical.
Each rectangle is a list of four numbers: x, y, width, height.

To be more like the cairo API, and if you are dealing with one line of
text, you can get to the line object:

  layout.get_line(0)

and do the get_pixel_extents() on the line.  the difference is that for
the layout, the origin is top-left, for the line, it's at the
baseline-left, which is like what cairo's text API uses.

With the extents, you can easily convert to bearings and advances:

  x_bearing = extents[0][0] (or pango.LBEARING(extents[0]))
  y_bearing = extents[0][1]
  width     = extents[0][2]
  height    = extents[0][3]
  x_advance = extents[1][2]
  y_advance = 0


Actually if you let me know what your usecase is, I can recommend what
exactly you should use.  It's a bit too easy to confuse ink and logical
extents.  Attaching another pygtk example that demonstrates ink and
logical extents for layout, lines, runs, and clusters.  You need a very
recent Pango or it will crash. :)

behdad


> How do I measure these attributes in pango?
> 
> Thanks
> Erik
> 
> On 11/9/06, Behdad Esfahbod <[EMAIL PROTECTED]> wrote:
>         On Mon, 2006-11-06 at 21:08 -0500, Erik Blankinship wrote:
>         > Thanks for the warning about cairo's font rendering.
>         >
>         > Could you please send a reference to how to use pangocairo
>         with
>         > pycairo?  I think that would be helpful for everyone on this
>         list who 
>         > might use text in their application.
>         
>         Attaching a complete test case.  If you can find your way in
>         the
>         example, the better, otherwise some explanation follows that
>         may be
>         helpful mapping the C APIs to the pygtk ones. 
>         
>         
>         In the C API, there are three objects of interest:
>         
>           cairo_t
>           PangoContext
>           PangoLayout
>         
>         You can get a cairo_t for your widget using
>         
>                 gdk_cairo_create (widget->window)
>         
>         You can also get a PangoContext using
>         
>                 gtk_widget_get_pango_context (widget)
>         
>         You can create a PangoLayout either using a PangoContext:
>         
>                 pango_layout_new (pangocontext)
>         
>         or get it directly from the widget: 
>         
>                 gtk_widget_create_pango_layout (widget)
>         
>         There's also a third way, which is to create one using a
>         cairo_t:
>         
>                 pango_cairo_create_layout (cr)
>         
>         
>         Of these, you should avoid the last one if possible, because
>         that 
>         doesn't derive font and other properties from the widget
>         style.
>         
>         
>         In pygtk, there is a convenience class hierarchy that doesn't
>         really map
>         to the C api, so it's worth mentioning to reduce confusion:
>         
>         There is the cairo.Context object which is a cairo_t.
>         
>         Then there is a pangocairo.CairoContext object which is a
>         descendant of
>         cairo.Context, with additional methods mapping to the
>         functions like
>         pango_cairo_create_layout() and
>         pango_cairo_show_layout()...  It 
>         actually makes sense, since those are functions taking a
>         cairo_t as
>         their first argument, so they can be thought of as extended
>         cairo_t
>         methods.
>         
>         Then there is gtk.gdk.CairoContext that derives from
>         pangocairo.CairoContext and extends that with some gdk
>         methods, namely
>         set_source_color and set_source_pixbuf.  Those too map to
>         gkd_cairo_*()
>         functions that take a cairo_t as their first argument.
>         
>         Now the cool part is that widget.window.cairo_create ()
>         returns a
>         gtk.gdk.CairoContext, so you can do a show_layout() on it
>         directly,
>         without having to create a pangocairo.CairoContext out of it.
>         
>         The only thing to note is to not use the
>         widget.window.cairo_create ()
>         context to create a PangoLayout directly (create_layout()) and
>         use
>         widget.get_pango_context() instead, for reasons stated above.
>         
>         behdad
>         
>         
>         > Erik
>         >
>         > On 11/6/06, Behdad Esfahbod < [EMAIL PROTECTED]> wrote:
>         >         On Fri, 2006-11-03 at 17:27 -0500, Erik Blankinship
>         wrote:
>         >         > Hello
>         >         >
>         >         > If I want to use the system font in my cairo
>         context, where 
>         >         do I find
>         >         > the font file to load in?
>         >
>         >         NEVER EVER use cairo's text rendering capabilities
>         to render
>         >         any text.
>         >         Not in olpc at least.  Use pangocairo ALL THE TIME. 
>         >
>         >         And for families, like others suggested, use
>         "sans-serif",
>         >         "serif", and
>         >         "monospace".
>         >
>         >
>         >         > Thanks,
>         >         > Erik 
>         >
>         >         --
>         >         behdad
>         >         http://behdad.org/
>         >
>         >
>         >
>         --
>         behdad
>         http://behdad.org/
>         
>         
> 
-- 
behdad
http://behdad.org/
#!/usr/bin/env python2.4
# -*- coding:utf8 -*-
from __future__ import division

import sys
import cairo
import pygtk
pygtk.require('2.0')
import gtk
import gtk.gdk
import pango
import gobject

class ExtentDemo(gtk.Widget):
    def __init__(self, text="""Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor.\n\tسلامی چو بوی خوشِ آشنایی... بر آن ملّتِ دیرام‌دام دیرام..."""):
        gtk.Widget.__init__(self)
        self.text = "foo"
        self.text = text
        self.modes = [
            (1, 0),  # Logical, Ink?
            ('line', 'run', 'cluster', 'char'),
            (pango.ALIGN_LEFT, pango.ALIGN_CENTER, pango.ALIGN_RIGHT),
        ]
        self.current_modes = [0, 0, 0]
        self.mode_num = 1

	self.x_margin = 5
	self.y_margin = 5
	self.x_offset = 0
	self.y_offset = 25
	self.font_size = 36

    def do_realize(self):
        self.set_flags(self.flags() | gtk.REALIZED)

        self.window = gtk.gdk.Window(
            self.get_parent_window(),
            width=self.allocation.width,
            height=self.allocation.height,
            window_type=gtk.gdk.WINDOW_CHILD,
            wclass=gtk.gdk.INPUT_OUTPUT,
            event_mask=self.get_events() | gtk.gdk.EXPOSURE_MASK)

        self.window.set_user_data(self)

        self.style.attach(self.window)

        self.style.set_background(self.window, gtk.STATE_NORMAL)
        self.window.move_resize(*self.allocation)

    def do_unrealize(self):
        self.window.destroy()

    def do_size_request(self, requisition):

	width = 800

	layout = self.get_layout(self.get_pango_context())
	layout.set_width (pango.SCALE * (width     - (self.x_offset + 2 * self.x_margin)))
	height = layout.get_pixel_extents ()[1][3] + (self.y_offset + 2 * self.y_margin)

        requisition.width  = width
        requisition.height = height

    def do_expose_event(self, event):
        context = self.window.cairo_create()
        context.rectangle(event.area.x, event.area.y,
                          event.area.width, event.area.height)
        context.clip()
        pangocontext = self.get_pango_context()

        self.draw(context, pangocontext)

        return False


    def get_layout (self, pangocontext):
        font = pango.FontDescription()
        font.set_family("sans")
        font.set_size(self.font_size * pango.SCALE)

        layout = pango.Layout(pangocontext)
        layout.set_font_description(font)
        layout.set_text(self.text)

	return layout

    def draw(self, context, pangocontext):

    	context.set_source_rgb (1, 1, 1)
	context.paint()
    	context.set_source_rgb (0, 0, 0)

	context.translate (self.x_margin, self.y_margin)

        extentindex, name, align = (self.modes[i][j] for i,j in
                                    enumerate(self.current_modes))

        labellayout = pango.Layout(pangocontext)
        labellayout.set_text(self.mode_name())
        context.move_to(0, 0)
        context.show_layout(labellayout)


	context.translate (self.x_offset, self.y_offset)

	layout = self.get_layout (pangocontext)
        width  = self.allocation.width  - (self.x_offset + 2 * self.x_margin)
        layout.set_width(width * pango.SCALE)
        layout.set_alignment(align)

        context.move_to(0, 0)
        context.show_layout(layout)

        context.set_source_rgba(1, 0, 0, 0.5)
    	context.set_line_width (2)
        x, y, width, height = layout.get_pixel_extents()[extentindex]
        context.rectangle(x-1, y-1, width+2, height+2)
        context.stroke()

        context.set_source_rgba(0, 1, 0, 0.7)
    	context.set_line_width (1)

        li = layout.get_iter()

        while True:
	    if self.modes[1][self.current_modes[1]] == 'char':
                extents = getattr(li, 'get_%s_extents' % name)()
	    else:
                extents = getattr(li, 'get_%s_extents' % name)()[extentindex]
            x, y, width, height = self._descale(extents)
            context.rectangle(x+.5, y+.5, width-1, height-1)
            context.stroke()

            if not getattr(li, 'next_%s' % name)():
                break

    def mode_name(self):
        extentindex, name, align = self.current_modes

        return '%i: %s %s %s' % (self.mode_num,
                                 ('left', 'center', 'right')[align],
                                 self.modes[1][name],
                                 ('logical', 'ink')[extentindex],
        )

    def cycle_mode(self):
        i = 0
        self.mode_num += 1
        for i in range(len(self.modes)):
            self.current_modes[i] += 1
            if self.current_modes[i] < len(self.modes[i]):
                break
            self.current_modes[i] = 0
        else:
            self.mode_num = 1
	
	# char only has logical extents
	if self.modes[1][self.current_modes[1]] == 'char' and self.current_modes[0] > 0:
	    self.mode_num -= 1
	    self.cycle_mode()
        self.queue_draw()

    def key_press_event(self, widget, event):
        if event.string == ' ':
            self.cycle_mode()
        elif event.string == 'q':
            gtk.main_quit()

    def _descale(self, rect):
        return (i / pango.SCALE for i in rect)

    def run(self):
        window = gtk.Window()
        window.add(self)
        window.connect("destroy", gtk.main_quit)
        window.connect("key-press-event", self.key_press_event)
        window.show_all()

        gtk.main()

gobject.type_register(ExtentDemo)


def main():
    if len (sys.argv) > 2:
        ed = ExtentDemo(sys.argv[2])
    else:
        ed = ExtentDemo()
    if len (sys.argv) > 1:
	mode = int(sys.argv[1])
	while mode > 1:
	    mode -= 1
	    ed.cycle_mode()
    ed.run()

if __name__ == "__main__":
    main()

Attachment: signature.asc
Description: This is a digitally signed message part

_______________________________________________
Sugar mailing list
[email protected]
http://mailman.laptop.org/mailman/listinfo/sugar

Reply via email to