maposmatic-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Maposmatic-dev] [PATCH] Draw utils refactoring


From: Étienne Loks
Subject: [Maposmatic-dev] [PATCH] Draw utils refactoring
Date: Sun, 1 Apr 2012 01:06:56 +0200

---
 ocitysmap2/draw_utils.py                      |  105 ++++++++++++++++++++++---
 ocitysmap2/layoutlib/abstract_renderer.py     |   60 +++-----------
 ocitysmap2/layoutlib/multi_page_renderer.py   |  100 +++++------------------
 ocitysmap2/layoutlib/single_page_renderers.py |    5 +-
 4 files changed, 133 insertions(+), 137 deletions(-)

diff --git a/ocitysmap2/draw_utils.py b/ocitysmap2/draw_utils.py
index e7b1a04..c5bb750 100644
--- a/ocitysmap2/draw_utils.py
+++ b/ocitysmap2/draw_utils.py
@@ -1,13 +1,14 @@
 # -*- coding: utf-8 -*-
 
 # ocitysmap, city map and street index generator from OpenStreetMap data
-# Copyright (C) 2010  David Decotigny
-# Copyright (C) 2010  Frédéric Lehobey
-# Copyright (C) 2010  Pierre Mauduit
-# Copyright (C) 2010  David Mentré
-# Copyright (C) 2010  Maxime Petazzoni
-# Copyright (C) 2010  Thomas Petazzoni
-# Copyright (C) 2010  Gaël Utard
+# Copyright (C) 2012  David Decotigny
+# Copyright (C) 2012  Frédéric Lehobey
+# Copyright (C) 2012  Pierre Mauduit
+# Copyright (C) 2012  David Mentré
+# Copyright (C) 2012  Maxime Petazzoni
+# Copyright (C) 2012  Thomas Petazzoni
+# Copyright (C) 2012  Gaël Utard
+# Copyright (C) 2012  Étienne Loks
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Affero General Public License as
@@ -24,8 +25,8 @@
 
 import cairo
 import pango
+import pangocairo
 import ocitysmap2.layoutlib.commons as commons
-from ocitysmap2.layoutlib.abstract_renderer import Renderer
 
 def draw_text(ctx, pc, layout, fascent, fheight,
               baseline_x, baseline_y, text, pango_alignment):
@@ -54,7 +55,6 @@ def draw_text(ctx, pc, layout, fascent, fheight,
     pc.show_layout(layout)
     return width, height
 
-
 def draw_text_left(ctx, pc, layout, fascent, fheight,
                     baseline_x, baseline_y, text):
     """Draws the given text left aligned into the provided Cairo
@@ -126,6 +126,22 @@ def draw_text_right(ctx, pc, layout, fascent, fheight,
             baseline_y,
             baseline_x + layout_width)
 
+def draw_simpletext_center(ctx, text, x, y):
+    """
+    Draw the given text centered at x,y.
+
+    Args:
+       ctx (cairo.Context): The cairo context to use to draw.
+       text (str): the text to draw.
+       x,y (numbers): Location of the center (cairo units).
+    """
+    ctx.save()
+    xb, yb, tw, th, xa, ya = ctx.text_extents(text)
+    ctx.move_to(x - tw/2.0 - xb, y - yb/2.0)
+    ctx.show_text(text)
+    ctx.stroke()
+    ctx.restore()
+
 def draw_dotted_line(ctx, line_width, baseline_x, baseline_y, length):
     ctx.set_line_width(line_width)
     ctx.set_dash([line_width, line_width*2])
@@ -133,6 +149,74 @@ def draw_dotted_line(ctx, line_width, baseline_x, 
baseline_y, length):
     ctx.rel_line_to(length, 0)
     ctx.stroke()
 
+def adjust_font_size(layout, fd, constraint_x, constraint_y):
+    """
+    Grow the given font description (20% by 20%) until it fits in
+    designated area and then draw it.
+
+    Args:
+       layout (pango.Layout): The text block parameters.
+       fd (pango.FontDescriptor): The font object.
+       constraint_x/constraint_y (numbers): The area we want to
+           write into (cairo units).
+    """
+    while (layout.get_size()[0] / pango.SCALE < constraint_x and
+           layout.get_size()[1] / pango.SCALE < constraint_y):
+        fd.set_size(int(fd.get_size()*1.2))
+        layout.set_font_description(fd)
+    fd.set_size(int(fd.get_size()/1.2))
+    layout.set_font_description(fd)
+
+def draw_text_adjusted(ctx, text, x, y, width, height, max_char_number=None,
+                       text_color=(0, 0, 0, 1), align=pango.ALIGN_CENTER):
+    """
+    Draw a text adjusted to a maximum character number
+
+    Args:
+       ctx (cairo.Context): The cairo context to use to draw.
+       text (str): the text to draw.
+       x/y (numbers): The position on the canvas.
+       width/height (numbers): The area we want to
+           write into (cairo units).
+       max_char_number (number): If set a maximum character number.
+    """
+    pc = pangocairo.CairoContext(ctx)
+    layout = pc.create_layout()
+    layout.set_width(int(0.7 * width * pango.SCALE))
+    layout.set_alignment(align)
+    fd = pango.FontDescription("Georgia Bold")
+    fd.set_size(pango.SCALE)
+    layout.set_font_description(fd)
+
+    if max_char_number:
+        # adjust size with the max character number
+        layout.set_text('0'*max_char_number)
+        adjust_font_size(layout, fd, 0.7*width, 0.8*height)
+
+    # set the real text
+    layout.set_text(text)
+    if not max_char_number:
+        adjust_font_size(layout, fd, 0.7*width, 0.8*height)
+
+    # draw
+    text_x, text_y, text_w, text_h = layout.get_extents()[1]
+    ctx.save()
+    ctx.set_source_rgba(*text_color)
+    if align == pango.ALIGN_CENTER:
+        x = x - (text_w/2.0)/pango.SCALE - text_x/pango.SCALE
+        y = y - (text_h/2.0)/pango.SCALE - text_y/pango.SCALE
+    else:
+        y = y - (text_h/2.0)/pango.SCALE - text_y/pango.SCALE
+    ctx.translate(x, y)
+
+    if align == pango.ALIGN_LEFT:
+        # Hack to workaround what appears to be a Cairo bug: without
+        # drawing a rectangle here, the translation above is not taken
+        # into account for rendering the text.
+        ctx.rectangle(0, 0, 0, 0)
+    pc.show_layout(layout)
+    ctx.restore()
+
 def render_page_number(ctx, page_number,
                        usable_area_width_pt, usable_area_height_pt, margin_pt,
                        transparent_background = True):
@@ -160,5 +244,6 @@ def render_page_number(ctx, page_number,
     x_offset = commons.convert_pt_to_dots(margin_pt)/2
     y_offset = commons.convert_pt_to_dots(margin_pt)/2
     ctx.translate(x_offset, y_offset)
-    Renderer._draw_centered_text(ctx, unicode(page_number), 0, 0)
+    draw_simpletext_center(ctx, unicode(page_number), 0, 0)
     ctx.restore()
+
diff --git a/ocitysmap2/layoutlib/abstract_renderer.py 
b/ocitysmap2/layoutlib/abstract_renderer.py
index 11aed7d..bf587c0 100644
--- a/ocitysmap2/layoutlib/abstract_renderer.py
+++ b/ocitysmap2/layoutlib/abstract_renderer.py
@@ -1,13 +1,14 @@
 # -*- coding: utf-8 -*-
 
 # ocitysmap, city map and street index generator from OpenStreetMap data
-# Copyright (C) 2010  David Decotigny
-# Copyright (C) 2010  Frédéric Lehobey
-# Copyright (C) 2010  Pierre Mauduit
-# Copyright (C) 2010  David Mentré
-# Copyright (C) 2010  Maxime Petazzoni
-# Copyright (C) 2010  Thomas Petazzoni
-# Copyright (C) 2010  Gaël Utard
+# Copyright (C) 2012  David Decotigny
+# Copyright (C) 2012  Frédéric Lehobey
+# Copyright (C) 2012  Pierre Mauduit
+# Copyright (C) 2012  David Mentré
+# Copyright (C) 2012  Maxime Petazzoni
+# Copyright (C) 2012  Thomas Petazzoni
+# Copyright (C) 2012  Gaël Utard
+# Copyright (C) 2012  Étienne Loks
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Affero General Public License as
@@ -37,6 +38,7 @@ from ocitysmap2.maplib.map_canvas import MapCanvas
 from ocitysmap2.maplib.grid import Grid
 import commons
 from ocitysmap2 import maplib
+from ocitysmap2 import draw_utils
 import shapely.wkt
 
 import logging
@@ -84,42 +86,6 @@ class Renderer:
                 commons.convert_mm_to_pt(self.rc.paper_height_mm)
 
     @staticmethod
-    def _draw_centered_text(ctx, text, x, y):
-        """
-        Draw the given text centered at x,y.
-
-        Args:
-           ctx (cairo.Context): The cairo context to use to draw.
-           text (str): the text to draw.
-           x,y (numbers): Location of the center (cairo units).
-        """
-        ctx.save()
-        xb, yb, tw, th, xa, ya = ctx.text_extents(text)
-        ctx.move_to(x - tw/2.0 - xb, y - yb/2.0)
-        ctx.show_text(text)
-        ctx.stroke()
-        ctx.restore()
-
-    @staticmethod
-    def _adjust_font_size(layout, fd, constraint_x, constraint_y):
-        """
-        Grow the given font description (20% by 20%) until it fits in
-        designated area and then draw it.
-
-        Args:
-           layout (pango.Layout): The text block parameters.
-           fd (pango.FontDescriptor): The font object.
-           constraint_x/constraint_y (numbers): The area we want to
-               write into (cairo units).
-        """
-        while (layout.get_size()[0] / pango.SCALE < constraint_x and
-               layout.get_size()[1] / pango.SCALE < constraint_y):
-            fd.set_size(int(fd.get_size()*1.2))
-            layout.set_font_description(fd)
-        fd.set_size(int(fd.get_size()/1.2))
-        layout.set_font_description(fd)
-
-    @staticmethod
     def _get_osm_logo(ctx, height):
         """
         Read the OSM logo file and rescale it to fit within height.
@@ -193,9 +159,9 @@ class Renderer:
             else:
                 continue
 
-            Renderer._draw_centered_text(ctx, label,
+            draw_utils.draw_simpletext_center(ctx, label,
                                          x, grid_legend_margin_dots/2.0)
-            Renderer._draw_centered_text(ctx, label,
+            draw_utils.draw_simpletext_center(ctx, label,
                                          x, map_area_height_dots -
                                          grid_legend_margin_dots/2.0)
 
@@ -209,9 +175,9 @@ class Renderer:
             else:
                 continue
 
-            Renderer._draw_centered_text(ctx, label,
+            draw_utils.draw_simpletext_center(ctx, label,
                                          grid_legend_margin_dots/2.0, y)
-            Renderer._draw_centered_text(ctx, label,
+            draw_utils.draw_simpletext_center(ctx, label,
                                          map_area_width_dots -
                                          grid_legend_margin_dots/2.0, y)
 
diff --git a/ocitysmap2/layoutlib/multi_page_renderer.py 
b/ocitysmap2/layoutlib/multi_page_renderer.py
index 9446a7b..30141a2 100644
--- a/ocitysmap2/layoutlib/multi_page_renderer.py
+++ b/ocitysmap2/layoutlib/multi_page_renderer.py
@@ -49,12 +49,11 @@ import ocitysmap2
 import commons
 import shapely.wkt
 from ocitysmap2 import maplib
+from ocitysmap2 import draw_utils
 
 from indexlib.commons import IndexCategory
-import draw_utils
 
 LOG = logging.getLogger('ocitysmap')
-PAGE_STR = " - Page %(page_number)d"
 
 class MultiPageRenderer(Renderer):
     """
@@ -423,26 +422,8 @@ class MultiPageRenderer(Renderer):
         ctx.set_source_rgb(.80,.80,.80)
         ctx.rectangle(0, 0, blue_w, blue_h)
         ctx.fill()
-
-        # Prepare the title text layout
-        pc = pangocairo.CairoContext(ctx)
-        layout = pc.create_layout()
-        layout.set_width(int(0.7 * w * pango.SCALE))
-        layout.set_alignment(pango.ALIGN_CENTER)
-        fd = pango.FontDescription("Georgia Bold")
-        fd.set_size(pango.SCALE)
-        layout.set_font_description(fd)
-        layout.set_text(self.rc.title)
-        self._adjust_font_size(layout, fd, 0.7 * blue_w, 0.8 * blue_h)
-
-        # Draw the title
-        text_x, text_y, text_w, text_h = layout.get_extents()[1]
-        ctx.save()
-        ctx.set_source_rgb(0, 0, 0)
-        ctx.translate((blue_w / 2) - (text_w / 2.0) / pango.SCALE - text_x / 
pango.SCALE,
-                      (blue_h / 2) - (text_h / 2.0) / pango.SCALE - text_y / 
pango.SCALE)
-        pc.show_layout(layout)
-        ctx.restore()
+        draw_utils.draw_text_adjusted(ctx, self.rc.title, blue_w/2, blue_h/2,
+                 blue_w, blue_h)
 
     def _render_front_page_map(self, ctx, dpi, w, h):
         # We will render the map slightly below the title
@@ -506,29 +487,9 @@ class MultiPageRenderer(Renderer):
         finally:
             locale.setlocale(locale.LC_TIME, prev_locale)
 
-        # Render the text
-        pc = pangocairo.CairoContext(ctx)
-        layout = pc.create_layout()
-        layout.set_width(int(footer_w * 0.7) * pango.SCALE)
-        layout.set_alignment(pango.ALIGN_LEFT)
-        fd = pango.FontDescription("Georgia Bold")
-        fd.set_size(pango.SCALE)
-        layout.set_font_description(fd)
-        layout.set_text(notice)
-        self._adjust_font_size(layout, fd, footer_w * 0.7, footer_h * 0.8)
-
-        text_x, text_y, text_w, text_h = layout.get_extents()[1]
-        ctx.save()
-        ctx.set_source_rgb(0,0,0)
-        ctx.translate(Renderer.PRINT_SAFE_MARGIN_PT,
-                      (footer_h / 2) - (text_h / 2.0 / pango.SCALE))
-        # Hack to workaround what appears to be a Cairo bug: without
-        # drawing a rectangle here, the translation above is not taken
-        # into account for rendering the text.
-        ctx.rectangle(0, 0, 0, 0)
-        pc.show_layout(layout)
-        ctx.restore()
-
+        draw_utils.draw_text_adjusted(ctx, notice,
+                Renderer.PRINT_SAFE_MARGIN_PT, footer_h/2, footer_w,
+                footer_h, align=pango.ALIGN_LEFT)
         ctx.restore()
 
     def _render_front_page(self, ctx, cairo_surface, dpi, osm_date):
@@ -571,7 +532,7 @@ class MultiPageRenderer(Renderer):
         w = self._usable_area_width_pt
         h = self._usable_area_height_pt
         ctx.set_source_rgb(.6,.6,.6)
-        Renderer._draw_centered_text(ctx, _('This page is intentionally left '\
+        draw_utils.draw_simpletext_center(ctx, _('This page is intentionally 
left '\
                                             'blank.'), w/2.0, 0.95*h)
         draw_utils.render_page_number(ctx, 2,
                                       self._usable_area_width_pt,
@@ -598,7 +559,8 @@ class MultiPageRenderer(Renderer):
 
         cairo_surface.show_page()
 
-    def _draw_arrow(self, ctx, cairo_surface, number, reverse_text=False):
+    def _draw_arrow(self, ctx, cairo_surface, number, max_digit_number,
+                    reverse_text=False):
         arrow_edge = self.grayed_margin_pt*.6
         ctx.save()
         ctx.set_source_rgb(0, 0, 0)
@@ -616,10 +578,11 @@ class MultiPageRenderer(Renderer):
         if reverse_text:
             ctx.rotate(math.pi)
         ctx.set_source_rgb(1, 1, 1)
-        Renderer._draw_centered_text(ctx, unicode(number), 0, 0)
+        draw_utils.draw_simpletext_center(ctx, unicode(number), 0, 0)
         ctx.restore()
 
-    def _render_neighbour_arrows(self, ctx, cairo_surface, map_number):
+    def _render_neighbour_arrows(self, ctx, cairo_surface, map_number,
+                                 max_digit_number):
         nb_previous_pages = 4
         current_line, current_col = None, None
         for line_nb in xrange(self.nb_pages_height):
@@ -640,7 +603,7 @@ class MultiPageRenderer(Renderer):
                 ctx.translate(self._usable_area_width_pt/2,
                     commons.convert_pt_to_dots(self.grayed_margin_pt)/2)
                 self._draw_arrow(ctx, cairo_surface,
-                                 north_arrow + nb_previous_pages)
+                              north_arrow + nb_previous_pages, 
max_digit_number)
                 ctx.restore()
                 break
 
@@ -654,7 +617,8 @@ class MultiPageRenderer(Renderer):
                       - commons.convert_pt_to_dots(self.grayed_margin_pt)/2)
                 ctx.rotate(math.pi)
                 self._draw_arrow(ctx, cairo_surface,
-                             south_arrow + nb_previous_pages, 
reverse_text=True)
+                      south_arrow + nb_previous_pages, max_digit_number,
+                      reverse_text=True)
                 ctx.restore()
                 break
 
@@ -668,7 +632,7 @@ class MultiPageRenderer(Renderer):
                     self._usable_area_height_pt/2)
                 ctx.rotate(-math.pi/2)
                 self._draw_arrow(ctx, cairo_surface,
-                                 west_arrow + nb_previous_pages)
+                               west_arrow + nb_previous_pages, 
max_digit_number)
                 ctx.restore()
                 break
 
@@ -683,7 +647,7 @@ class MultiPageRenderer(Renderer):
                     self._usable_area_height_pt/2)
                 ctx.rotate(math.pi/2)
                 self._draw_arrow(ctx, cairo_surface,
-                                 east_arrow + nb_previous_pages)
+                               east_arrow + nb_previous_pages, 
max_digit_number)
                 ctx.restore()
                 break
 
@@ -726,7 +690,8 @@ class MultiPageRenderer(Renderer):
                                           self._usable_area_height_pt,
                                           self.grayed_margin_pt,
                                           transparent_background = True)
-            self._render_neighbour_arrows(ctx, cairo_surface, map_number)
+            self._render_neighbour_arrows(ctx, cairo_surface, map_number,
+                                          len(unicode(len(self.pages)+4)))
 
             cairo_surface.show_page()
         ctx.restore()
@@ -812,29 +777,8 @@ class MultiPageRenderer(Renderer):
                                                          )/coord_delta_x
                 h = area_height_dots*(p_top_right.y - p_bottom_right.y
                                                          )/coord_delta_y
-            # Prepare the number text layout
-            pc = pangocairo.CairoContext(ctx)
-            layout = pc.create_layout()
-            layout.set_width(int(0.7 * w * pango.SCALE))
-            layout.set_alignment(pango.ALIGN_CENTER)
-            fd = pango.FontDescription("Georgia Bold")
-            fd.set_size(pango.SCALE)
-            layout.set_font_description(fd)
-
-            # adjust size with the last page number
-            layout.set_text('0'*len(unicode(len(overview_grid._pages_bbox)+3)))
-            cls._adjust_font_size(layout, fd, 0.65 * w, 0.8 * h)
-
-            # set the real text
-            layout.set_text(unicode(idx+4))
-
-            # draw
-            text_x, text_y, text_w, text_h = layout.get_extents()[1]
-            ctx.save()
-            ctx.set_source_rgba(0, 0, 0, 0.6)
-            ctx.translate(x - (text_w/2.0)/pango.SCALE - text_x/pango.SCALE,
-                          y - (text_h/2.0)/pango.SCALE - text_y/pango.SCALE)
-            pc.show_layout(layout)
-            ctx.restore()
+            draw_utils.draw_text_adjusted(ctx, unicode(idx+4), x, y, w, h,
+                 
max_char_number=len(unicode(len(overview_grid._pages_bbox)+3)),
+                 text_color=(0, 0, 0, 0.6))
 
         ctx.restore()
diff --git a/ocitysmap2/layoutlib/single_page_renderers.py 
b/ocitysmap2/layoutlib/single_page_renderers.py
index e76c98e..edb7bee 100644
--- a/ocitysmap2/layoutlib/single_page_renderers.py
+++ b/ocitysmap2/layoutlib/single_page_renderers.py
@@ -42,6 +42,7 @@ import logging
 
 from indexlib.indexer import StreetIndex
 from indexlib.commons import IndexDoesNotFitError, IndexEmptyError
+import draw_utils
 
 LOG = logging.getLogger('ocitysmap')
 
@@ -262,7 +263,7 @@ class SinglePageRenderer(Renderer):
         fd.set_size(pango.SCALE)
         layout.set_font_description(fd)
         layout.set_text(self.rc.title)
-        self._adjust_font_size(layout, fd, layout.get_width(), 0.8*h_dots)
+        draw_utils.adjust_font_size(layout, fd, layout.get_width(), 0.8*h_dots)
 
         # Draw the title
         ctx.save()
@@ -320,7 +321,7 @@ class SinglePageRenderer(Renderer):
         layout = pc.create_layout()
         layout.set_font_description(fd)
         layout.set_text(notice)
-        self._adjust_font_size(layout, fd, w_dots, h_dots)
+        draw_utils.adjust_font_size(layout, fd, w_dots, h_dots)
         pc.show_layout(layout)
         ctx.restore()
 
-- 
1.7.9.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]