Peter Ward avatar Peter Ward committed 43d5375

Rip out the single slide text rendering stuff and put it into shinypress.
Still needs to be tidied up.

Comments (0)

Files changed (5)

shinypress/render.py

     :type scaling_mode: shinypress.render.ScalingMode
     """
     pass
-
-def render_text(ctx, text, size, **todo_fill_in_these_kwargs):
-    """
-    Render some text onto the given Cairo context.
-
-    :param ctx: a Cairo context
-    :param text: the text to be rendered
-    :type text: unicode
-    :param size: the dimensions of the text box
-    :type size: a (width, height) tuple
-    """
-    pass

shinypress/text/single.py

+from functools import partial
+
+from gi.repository import Pango
+from gi.repository import PangoCairo
+
+def get_box_cost(actual_size, target_size):
+    aw, ah = actual_size
+    tw, th = target_size
+    if aw > tw or ah > th:
+        return float('inf')
+    height_penalty = 1 - (float(ah) / th) ** 4
+    width_penalty = 1 - (float(aw) / tw) ** 2
+    return (width_penalty + height_penalty) / 2.0
+
+def layout_text(ctx, text, target_size, size):
+    font = Pango.FontDescription()
+    font.set_family('Droid Sans')
+    font.set_size(size * Pango.SCALE)
+
+    layout = PangoCairo.create_layout(ctx)
+    layout.set_font_description(font)
+    layout.set_justify(True)
+    layout.set_text(text, -1)
+    layout.set_width(target_size[0] * Pango.SCALE)
+    layout.set_spacing(size * 0.2 * Pango.SCALE)
+
+    actual_size = layout.get_pixel_size()
+    cost = get_box_cost(actual_size, target_size)
+
+    return cost, layout
+
+def generate_sizes(min_size, max_size, scale):
+    if not 0 < scale < 1:
+        scale = 1.0 / scale
+    assert 0 < scale < 1
+
+    sizes = []
+    # generate the minor scale
+    size = min_size
+    while size < max_size:
+        sizes.append(size)
+        size /= scale
+    # generate the major scale
+    size = max_size
+    while size > min_size:
+        sizes.append(size)
+        size *= scale
+
+    return sorted(set(sizes))
+
+def minimise(sizes, fn):
+    """Find the maximum size with the lowest cost."""
+    best_cost = float('inf')
+    best = None
+
+    while len(sizes) > 1:
+        # find the middle element
+        i = len(sizes) // 2
+        size = sizes[i]
+        cost, layout = fn(size)
+
+        # if this beat our current best, we should only try sizes larger than
+        # this one.
+        if cost <= best_cost:
+            best_cost = cost
+            best = (size, layout)
+            sizes = sizes[i + 1:]
+        # otherwise, this sizes and anything larger is bad
+        else:
+            sizes = sizes[:i]
+
+    return best_cost, best
+
+def render_text(
+    ctx, text, size,
+    min_font_size, max_font_size, factor,
+):
+    """
+    Render text on a Cairo context.
+
+    This method takes a minimum and maximum font size, and scales both by
+    ``factor`` in order to determine the range of font sizes that should be
+    tried.
+
+    The font size which produces the lowest cost according to layout_text will
+    be used.
+
+    :param ctx: the Cairo context to draw on
+    :param text: the text to draw
+    :type text: unicode
+    :param size: the dimensions of the text box
+    :type size: a (width, height) tuple
+    :param min_font_size: minimum font size, in points
+    :param max_font_size: maximum font size, in points
+    :param factor: amount to scale by
+    :type factor: float
+    """
+    fn = partial(layout_text, ctx, text, size)
+    sizes = generate_sizes(min_font_size, max_font_size, factor)
+
+    cost, (size, layout) = minimise(sizes, fn)
+    PangoCairo.show_layout(ctx, layout)

slide-breaking/main.py

-from functools import partial
+import cairo
 
-import cairo
-from gi.repository import PangoCairo
-
-from text.single import generate_sizes, layout_text
-from utils import minimise
+from text.single import render_text
 
 TEXT = open('sample.txt', 'rU').read()
 
 surf = cairo.PDFSurface('blah.pdf', WIDTH, HEIGHT)
 ctx = cairo.Context(surf)
 
-fn = partial(layout_text, ctx, TEXT, (WIDTH, HEIGHT))
-sizes = generate_sizes(18, 48, 1.25)
-
-score, (size, layout) = minimise(sizes, fn)
-PangoCairo.show_layout(ctx, layout)
+render_text(ctx, TEXT, (WIDTH, HEIGHT), 18, 48, 1.25)
 surf.show_page()

slide-breaking/text/single.py

-from gi.repository import Pango
-from gi.repository import PangoCairo
-
-def score_box(actual_size, target_size):
-    aw, ah = actual_size
-    tw, th = target_size
-    if aw > tw or ah > th:
-        return float('inf')
-    height_penalty = 1 - (float(ah) / th) ** 4
-    width_penalty = 1 - (float(aw) / tw) ** 2
-    return (width_penalty + height_penalty) / 2.0
-
-def layout_text(ctx, text, target_size, size):
-    font = Pango.FontDescription()
-    font.set_family('Droid Sans')
-    font.set_size(size * Pango.SCALE)
-
-    layout = PangoCairo.create_layout(ctx)
-    layout.set_font_description(font)
-    layout.set_justify(True)
-    layout.set_text(text, -1)
-    layout.set_width(target_size[0] * Pango.SCALE)
-    layout.set_spacing(size * 0.2 * Pango.SCALE)
-
-    actual_size = layout.get_pixel_size()
-    score = score_box(actual_size, target_size)
-
-    return score, layout
-
-def generate_sizes(min_size, max_size, scale):
-    if not 0 < scale < 1:
-        scale = 1.0 / scale
-    assert 0 < scale < 1
-
-    sizes = []
-    # generate the minor scale
-    size = min_size
-    while size < max_size:
-        sizes.append(size)
-        size /= scale
-    # generate the major scale
-    size = max_size
-    while size > min_size:
-        sizes.append(size)
-        size *= scale
-
-    return sorted(set(sizes))

slide-breaking/utils.py

-def minimise(sizes, fn):
-    """Find the maximum size with the lowest score."""
-    best_score = float('inf')
-    best = None
-
-    while len(sizes) > 1:
-        # find the middle element
-        i = len(sizes) // 2
-        size = sizes[i]
-        score, layout = fn(size)
-
-        # if this beat our current best, we should only try sizes larger than
-        # this one.
-        if score <= best_score:
-            best_score = score
-            best = (size, layout)
-            sizes = sizes[i + 1:]
-        # otherwise, this sizes and anything larger is bad
-        else:
-            sizes = sizes[:i]
-
-    return best_score, best
-
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.