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()
signature.asc
Description: This is a digitally signed message part
_______________________________________________ Sugar mailing list [email protected] http://mailman.laptop.org/mailman/listinfo/sugar
