def render(self, cairo_surface, dpi, osm_date): ctx = cairo.Context(cairo_surface) self._render_front_page(ctx, cairo_surface, dpi, osm_date) self._render_blank_page(ctx, cairo_surface, dpi) ctx.save() # Prepare to draw the map at the right location ctx.translate( commons.convert_pt_to_dots(Renderer.PRINT_SAFE_MARGIN_PT), commons.convert_pt_to_dots(Renderer.PRINT_SAFE_MARGIN_PT)) self._render_overview_page(ctx, cairo_surface, dpi) for map_number, (canvas, grid) in enumerate(self.pages): rendered_map = canvas.get_rendered_map() LOG.debug('Mapnik scale: 1/%f' % rendered_map.scale_denominator()) LOG.debug('Actual scale: 1/%f' % canvas.get_actual_scale()) mapnik.render(rendered_map, ctx) # Place the vertical and horizontal square labels ctx.save() ctx.translate(commons.convert_pt_to_dots(self.grayed_margin_pt), commons.convert_pt_to_dots(self.grayed_margin_pt)) self._draw_labels(ctx, grid, commons.convert_pt_to_dots(self._usable_area_width_pt) \ - 2 * commons.convert_pt_to_dots(self.grayed_margin_pt), commons.convert_pt_to_dots(self._usable_area_height_pt) \ - 2 * commons.convert_pt_to_dots(self.grayed_margin_pt), commons.convert_pt_to_dots(self._grid_legend_margin_pt)) ctx.restore() # Render the page number draw_utils.render_page_number(ctx, map_number+4, self._usable_area_width_pt, self._usable_area_height_pt, self.grayed_margin_pt, transparent_background = True) self._render_neighbour_arrows(ctx, cairo_surface, map_number, len(unicode(len(self.pages)+4))) cairo_surface.show_page() ctx.restore() mpsir = MultiPageStreetIndexRenderer(self.rc.i18n, ctx, cairo_surface, self.index_categories, (Renderer.PRINT_SAFE_MARGIN_PT, Renderer.PRINT_SAFE_MARGIN_PT, self._usable_area_width_pt, self._usable_area_height_pt), map_number+5) mpsir.render() cairo_surface.flush()
def render(self, cairo_surface, dpi, osm_date): ctx = cairo.Context(cairo_surface) self._render_front_page(ctx, cairo_surface, dpi, osm_date) self._render_blank_page(ctx, cairo_surface, dpi) ctx.save() # Prepare to draw the map at the right location ctx.translate( commons.convert_pt_to_dots(Renderer.PRINT_SAFE_MARGIN_PT), commons.convert_pt_to_dots(Renderer.PRINT_SAFE_MARGIN_PT)) self._render_overview_page(ctx, cairo_surface, dpi) for map_number, (canvas, grid) in enumerate(self.pages): rendered_map = canvas.get_rendered_map() LOG.debug('Mapnik scale: 1/%f' % rendered_map.scale_denominator()) LOG.debug('Actual scale: 1/%f' % canvas.get_actual_scale()) mapnik.render(rendered_map, ctx) # Place the vertical and horizontal square labels ctx.save() ctx.translate(commons.convert_pt_to_dots(self.grayed_margin_pt), commons.convert_pt_to_dots(self.grayed_margin_pt)) self._draw_labels(ctx, grid, commons.convert_pt_to_dots(self._usable_area_width_pt) \ - 2 * commons.convert_pt_to_dots(self.grayed_margin_pt), commons.convert_pt_to_dots(self._usable_area_height_pt) \ - 2 * commons.convert_pt_to_dots(self.grayed_margin_pt), commons.convert_pt_to_dots(self._grid_legend_margin_pt)) ctx.restore() # Render the page number draw_utils.render_page_number(ctx, map_number + 4, self._usable_area_width_pt, self._usable_area_height_pt, self.grayed_margin_pt, transparent_background=True) self._render_neighbour_arrows(ctx, cairo_surface, map_number, len(unicode(len(self.pages) + 4))) cairo_surface.show_page() ctx.restore() mpsir = MultiPageStreetIndexRenderer( self.rc.i18n, ctx, cairo_surface, self.index_categories, (Renderer.PRINT_SAFE_MARGIN_PT, Renderer.PRINT_SAFE_MARGIN_PT, self._usable_area_width_pt, self._usable_area_height_pt), map_number + 5) mpsir.render() cairo_surface.flush()
def _render_overview_page(self, ctx, cairo_surface, dpi): rendered_map = self.overview_canvas.get_rendered_map() mapnik.render(rendered_map, ctx) # draw pages numbers self._draw_overview_labels(ctx, self.overview_canvas, self.overview_grid, commons.convert_pt_to_dots(self._usable_area_width_pt), commons.convert_pt_to_dots(self._usable_area_height_pt)) # Render the page number draw_utils.render_page_number(ctx, 3, self._usable_area_width_pt, self._usable_area_height_pt, self.grayed_margin_pt, transparent_background = True) cairo_surface.show_page()
def _render_overview_page(self, ctx, cairo_surface, dpi): rendered_map = self.overview_canvas.get_rendered_map() mapnik.render(rendered_map, ctx) # draw pages numbers self._draw_overview_labels( ctx, self.overview_canvas, self.overview_grid, commons.convert_pt_to_dots(self._usable_area_width_pt), commons.convert_pt_to_dots(self._usable_area_height_pt)) # Render the page number draw_utils.render_page_number(ctx, 3, self._usable_area_width_pt, self._usable_area_height_pt, self.grayed_margin_pt, transparent_background=True) cairo_surface.show_page()
def _render_blank_page(self, ctx, cairo_surface, dpi): """ Render a blank page with a nice "intentionally blank" notice """ ctx.save() ctx.translate( commons.convert_pt_to_dots(Renderer.PRINT_SAFE_MARGIN_PT), commons.convert_pt_to_dots(Renderer.PRINT_SAFE_MARGIN_PT)) # footer notice w = self._usable_area_width_pt h = self._usable_area_height_pt ctx.set_source_rgb(.6,.6,.6) 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, self._usable_area_height_pt, self.grayed_margin_pt, transparent_background=False) cairo_surface.show_page() ctx.restore()
def _render_blank_page(self, ctx, cairo_surface, dpi): """ Render a blank page with a nice "intentionally blank" notice """ ctx.save() ctx.translate( commons.convert_pt_to_dots(Renderer.PRINT_SAFE_MARGIN_PT), commons.convert_pt_to_dots(Renderer.PRINT_SAFE_MARGIN_PT)) # footer notice w = self._usable_area_width_pt h = self._usable_area_height_pt ctx.set_source_rgb(.6, .6, .6) 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, self._usable_area_height_pt, self.grayed_margin_pt, transparent_background=False) cairo_surface.show_page() ctx.restore()
def render(self, cairo_surface, dpi, osm_date): """Renders the map, the index and all other visual map features on the given Cairo surface. Args: cairo_surface (Cairo.Surface): the destination Cairo device. dpi (int): dots per inch of the device. """ LOG.info( "SinglePageRenderer rendering on %dx%dmm paper at %d dpi." % (self.rc.paper_width_mm, self.rc.paper_height_mm, dpi) ) # First determine some useful drawing parameters safe_margin_dots = commons.convert_pt_to_dots(Renderer.PRINT_SAFE_MARGIN_PT, dpi) usable_area_width_dots = commons.convert_pt_to_dots(self._usable_area_width_pt, dpi) usable_area_height_dots = commons.convert_pt_to_dots(self._usable_area_height_pt, dpi) title_margin_dots = commons.convert_pt_to_dots(self._title_margin_pt, dpi) copyright_margin_dots = commons.convert_pt_to_dots(self._copyright_margin_pt, dpi) map_coords_dots = map(lambda l: commons.convert_pt_to_dots(l, dpi), self._map_coords) ctx = cairo.Context(cairo_surface) # Set a white background ctx.save() ctx.set_source_rgb(1, 1, 1) ctx.rectangle( 0, 0, commons.convert_pt_to_dots(self.paper_width_pt, dpi), commons.convert_pt_to_dots(self.paper_height_pt, dpi), ) ctx.fill() ctx.restore() ## ## Draw the map, scaled to fit the designated area ## ctx.save() # prevent map background from filling the full canvas ctx.rectangle(map_coords_dots[0], map_coords_dots[1], map_coords_dots[2], map_coords_dots[3]) ctx.clip() # Prepare to draw the map at the right location ctx.translate(map_coords_dots[0], map_coords_dots[1]) # Draw the rescaled Map ctx.save() scale_factor = dpi / 72 rendered_map = self._map_canvas.get_rendered_map() LOG.debug("Map:") LOG.debug("Mapnik scale: 1/%f" % rendered_map.scale_denominator()) LOG.debug("Actual scale: 1/%f" % self._map_canvas.get_actual_scale()) mapnik.render(rendered_map, ctx, scale_factor, 0, 0) ctx.restore() # Draw the rescaled Overlay if self.rc.overlay: LOG.debug("Overlay:") ctx.save() scale_factor = dpi / 72 rendered_overlay = self._overlay_canvas.get_rendered_map() mapnik.render(rendered_overlay, ctx, scale_factor, 0, 0) ctx.restore() # Draw a rectangle around the map ctx.rectangle(0, 0, map_coords_dots[2], map_coords_dots[3]) ctx.stroke() # Place the vertical and horizontal square labels self._draw_labels( ctx, self.grid, map_coords_dots[2], map_coords_dots[3], commons.convert_pt_to_dots(self._grid_legend_margin_pt, dpi), ) ctx.restore() ## ## Draw the title ## ctx.save() ctx.translate(safe_margin_dots, safe_margin_dots) self._draw_title(ctx, usable_area_width_dots, title_margin_dots, "Georgia Bold") ctx.restore() ## ## Draw the index, when applicable ## if self._index_renderer and self._index_area: ctx.save() # NEVER use ctx.scale() here because otherwise pango will # choose different dont metrics which may be incompatible # with what has been computed by __init__(), which may # require more columns than expected ! Instead, we have # to trick pangocairo into believing it is rendering to a # device with the same default resolution, but with a # cairo resolution matching the 'dpi' specified # resolution. See # index::render::StreetIndexRenederer::render() and # comments within. self._index_renderer.render(ctx, self._index_area, dpi) ctx.restore() # Also draw a rectangle ctx.save() ctx.rectangle( commons.convert_pt_to_dots(self._index_area.x, dpi), commons.convert_pt_to_dots(self._index_area.y, dpi), commons.convert_pt_to_dots(self._index_area.w, dpi), commons.convert_pt_to_dots(self._index_area.h, dpi), ) ctx.stroke() ctx.restore() ## ## Draw the copyright notice ## ctx.save() # Move to the right position ctx.translate( safe_margin_dots, (safe_margin_dots + title_margin_dots + usable_area_height_dots + copyright_margin_dots / 4.0), ) # Draw the copyright notice self._draw_copyright_notice(ctx, usable_area_width_dots, copyright_margin_dots, osm_date=osm_date) ctx.restore() # Draw compass rose # TODO: proper positioning/scaling, move to abstract renderer ctx.save() ctx.translate(50, title_margin_dots + 50) ctx.scale(0.33, 0.33) compass_path = os.path.abspath( os.path.join(os.path.dirname(__file__), "..", "..", "images", "compass-rose.svg") ) svg = rsvg.Handle(compass_path) svg.render_cairo(ctx) ctx.restore() # TODO: map scale cairo_surface.flush()
def render(self, cairo_surface, dpi, osm_date): """Renders the map, the index and all other visual map features on the given Cairo surface. Args: cairo_surface (Cairo.Surface): the destination Cairo device. dpi (int): dots per inch of the device. """ LOG.info('SinglePageRenderer rendering on %dx%dmm paper at %d dpi.' % (self.rc.paper_width_mm, self.rc.paper_height_mm, dpi)) # First determine some useful drawing parameters safe_margin_dots \ = commons.convert_pt_to_dots(Renderer.PRINT_SAFE_MARGIN_PT, dpi) usable_area_width_dots \ = commons.convert_pt_to_dots(self._usable_area_width_pt, dpi) usable_area_height_dots \ = commons.convert_pt_to_dots(self._usable_area_height_pt, dpi) title_margin_dots \ = commons.convert_pt_to_dots(self._title_margin_pt, dpi) copyright_margin_dots \ = commons.convert_pt_to_dots(self._copyright_margin_pt, dpi) map_coords_dots = map(lambda l: commons.convert_pt_to_dots(l, dpi), self._map_coords) ctx = cairo.Context(cairo_surface) # Set a white background ctx.save() ctx.set_source_rgb(1, 1, 1) ctx.rectangle(0, 0, commons.convert_pt_to_dots(self.paper_width_pt, dpi), commons.convert_pt_to_dots(self.paper_height_pt, dpi)) ctx.fill() ctx.restore() ## ## Draw the index, when applicable ## if self._index_renderer and self._index_area: ctx.save() # NEVER use ctx.scale() here because otherwise pango will # choose different dont metrics which may be incompatible # with what has been computed by __init__(), which may # require more columns than expected ! Instead, we have # to trick pangocairo into believing it is rendering to a # device with the same default resolution, but with a # cairo resolution matching the 'dpi' specified # resolution. See # index::render::StreetIndexRenederer::render() and # comments within. self._index_renderer.render(ctx, self._index_area, dpi) ctx.restore() # Also draw a rectangle ctx.save() ctx.rectangle(commons.convert_pt_to_dots(self._index_area.x, dpi), commons.convert_pt_to_dots(self._index_area.y, dpi), commons.convert_pt_to_dots(self._index_area.w, dpi), commons.convert_pt_to_dots(self._index_area.h, dpi)) ctx.stroke() ctx.restore() ## ## Draw the map, scaled to fit the designated area ## ctx.save() # Prepare to draw the map at the right location ctx.translate(map_coords_dots[0], map_coords_dots[1]) # Draw the rescaled Map ctx.save() rendered_map = self._map_canvas.get_rendered_map() LOG.debug('Mapnik scale: 1/%f' % rendered_map.scale_denominator()) LOG.debug('Actual scale: 1/%f' % self._map_canvas.get_actual_scale()) mapnik.render(rendered_map, ctx) ctx.restore() # Draw a rectangle around the map ctx.rectangle(0, 0, map_coords_dots[2], map_coords_dots[3]) ctx.stroke() # Place the vertical and horizontal square labels self._draw_labels(ctx, self.grid, map_coords_dots[2], map_coords_dots[3], commons.convert_pt_to_dots(self._grid_legend_margin_pt, dpi)) ctx.restore() ## ## Draw the title ## ctx.save() ctx.translate(safe_margin_dots, safe_margin_dots) self._draw_title(ctx, usable_area_width_dots, title_margin_dots, 'Georgia Bold') ctx.restore() ## ## Draw the copyright notice ## ctx.save() # Move to the right position ctx.translate(safe_margin_dots, ( safe_margin_dots + title_margin_dots + usable_area_height_dots + copyright_margin_dots/4. ) ) # Draw the copyright notice self._draw_copyright_notice(ctx, usable_area_width_dots, copyright_margin_dots, osm_date=osm_date) ctx.restore() # TODO: map scale # TODO: compass rose cairo_surface.flush()
def render(self, cairo_surface, dpi): """Renders the map, the index and all other visual map features on the given Cairo surface. Args: cairo_surface (Cairo.Surface): the destination Cairo device. dpi (int): dots per inch of the device. """ LOG.info('SinglePageRenderer rendering on %dx%dmm paper at %d dpi.' % (self.rc.paper_width_mm, self.rc.paper_height_mm, dpi)) # First determine some useful drawing parameters safe_margin_dots \ = commons.convert_pt_to_dots(Renderer.PRINT_SAFE_MARGIN_PT, dpi) usable_area_width_dots \ = commons.convert_pt_to_dots(self._usable_area_width_pt, dpi) usable_area_height_dots \ = commons.convert_pt_to_dots(self._usable_area_height_pt, dpi) title_margin_dots \ = commons.convert_pt_to_dots(self._title_margin_pt, dpi) copyright_margin_dots \ = commons.convert_pt_to_dots(self._copyright_margin_pt, dpi) map_coords_dots = map(lambda l: commons.convert_pt_to_dots(l, dpi), self._map_coords) ctx = cairo.Context(cairo_surface) ## ## Draw the index, when applicable ## if self._index_renderer and self._index_area: ctx.save() # NEVER use ctx.scale() here because otherwise pango will # choose different dont metrics which may be incompatible # with what has been computed by __init__(), which may # require more columns than expected ! Instead, we have # to trick pangocairo into believing it is rendering to a # device with the same default resolution, but with a # cairo resolution matching the 'dpi' specified # resolution. See # index::render::StreetIndexRenederer::render() and # comments within. self._index_renderer.render(ctx, self._index_area, dpi) ctx.restore() # Also draw a rectangle ctx.save() ctx.rectangle(commons.convert_pt_to_dots(self._index_area.x, dpi), commons.convert_pt_to_dots(self._index_area.y, dpi), commons.convert_pt_to_dots(self._index_area.w, dpi), commons.convert_pt_to_dots(self._index_area.h, dpi)) ctx.stroke() ctx.restore() ## ## Draw the map, scaled to fit the designated area ## ctx.save() # Prepare to draw the map at the right location ctx.translate(map_coords_dots[0], map_coords_dots[1]) # Draw the rescaled Map ctx.save() rendered_map = self._map_canvas.get_rendered_map() ctx.scale(map_coords_dots[2] / rendered_map.width, map_coords_dots[3] / rendered_map.height) mapnik.render(rendered_map, ctx) ctx.restore() # Draw a rectangle around the map ctx.rectangle(0, 0, map_coords_dots[2], map_coords_dots[3]) ctx.stroke() # Place the vertical and horizontal square labels self._draw_labels(ctx, self.grid, map_coords_dots[2], map_coords_dots[3], commons.convert_pt_to_dots(self._grid_legend_margin_pt, dpi)) ctx.restore() ## ## Draw the title ## ctx.save() ctx.translate(safe_margin_dots, safe_margin_dots) self._draw_title(ctx, usable_area_width_dots, title_margin_dots, 'Georgia Bold') ctx.restore() ## ## Draw the copyright notice ## ctx.save() # Move to the right position ctx.translate(safe_margin_dots, ( safe_margin_dots + title_margin_dots + usable_area_height_dots + copyright_margin_dots/4. ) ) # Draw the copyright notice self._draw_copyright_notice(ctx, usable_area_width_dots, copyright_margin_dots) ctx.restore() # TODO: map scale # TODO: compass rose cairo_surface.flush()
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): if map_number in self.page_disposition[line_nb]: current_line = line_nb current_col = self.page_disposition[line_nb].index(map_number) break if current_line == None: # page not referenced return # north arrow for line_nb in reversed(xrange(current_line)): if self.page_disposition[line_nb][current_col] != None: north_arrow = self.page_disposition[line_nb][current_col] ctx.save() 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, max_digit_number) ctx.restore() break # south arrow for line_nb in xrange(current_line + 1, self.nb_pages_height): if self.page_disposition[line_nb][current_col] != None: south_arrow = self.page_disposition[line_nb][current_col] ctx.save() ctx.translate(self._usable_area_width_pt/2, self._usable_area_height_pt \ - 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, max_digit_number, reverse_text=True) ctx.restore() break # west arrow for col_nb in reversed(xrange(0, current_col)): if self.page_disposition[current_line][col_nb] != None: west_arrow = self.page_disposition[current_line][col_nb] ctx.save() ctx.translate( commons.convert_pt_to_dots(self.grayed_margin_pt) / 2, self._usable_area_height_pt / 2) ctx.rotate(-math.pi / 2) self._draw_arrow(ctx, cairo_surface, west_arrow + nb_previous_pages, max_digit_number) ctx.restore() break # east arrow for col_nb in xrange(current_col + 1, self.nb_pages_width): if self.page_disposition[current_line][col_nb] != None: east_arrow = self.page_disposition[current_line][col_nb] ctx.save() ctx.translate( self._usable_area_width_pt \ - commons.convert_pt_to_dots(self.grayed_margin_pt)/2, self._usable_area_height_pt/2) ctx.rotate(math.pi / 2) self._draw_arrow(ctx, cairo_surface, east_arrow + nb_previous_pages, max_digit_number) ctx.restore() break
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): if map_number in self.page_disposition[line_nb]: current_line = line_nb current_col = self.page_disposition[line_nb].index( map_number) break if current_line == None: # page not referenced return # north arrow for line_nb in reversed(xrange(current_line)): if self.page_disposition[line_nb][current_col] != None: north_arrow = self.page_disposition[line_nb][current_col] ctx.save() 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, max_digit_number) ctx.restore() break # south arrow for line_nb in xrange(current_line + 1, self.nb_pages_height): if self.page_disposition[line_nb][current_col] != None: south_arrow = self.page_disposition[line_nb][current_col] ctx.save() ctx.translate(self._usable_area_width_pt/2, self._usable_area_height_pt \ - 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, max_digit_number, reverse_text=True) ctx.restore() break # west arrow for col_nb in reversed(xrange(0, current_col)): if self.page_disposition[current_line][col_nb] != None: west_arrow = self.page_disposition[current_line][col_nb] ctx.save() ctx.translate( commons.convert_pt_to_dots(self.grayed_margin_pt)/2, self._usable_area_height_pt/2) ctx.rotate(-math.pi/2) self._draw_arrow(ctx, cairo_surface, west_arrow + nb_previous_pages, max_digit_number) ctx.restore() break # east arrow for col_nb in xrange(current_col + 1, self.nb_pages_width): if self.page_disposition[current_line][col_nb] != None: east_arrow = self.page_disposition[current_line][col_nb] ctx.save() ctx.translate( self._usable_area_width_pt \ - commons.convert_pt_to_dots(self.grayed_margin_pt)/2, self._usable_area_height_pt/2) ctx.rotate(math.pi/2) self._draw_arrow(ctx, cairo_surface, east_arrow + nb_previous_pages, max_digit_number) ctx.restore() break