/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/baserenderer.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/UI/baserenderer.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

trunk/thuban/Thuban/UI/baserenderer.py revision 1554 by bh, Wed Aug 6 17:24:30 2003 UTC branches/WIP-pyshapelib-bramz/Thuban/UI/baserenderer.py revision 2755 by dpinte, Thu Apr 12 09:21:58 2007 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH  # Copyright (c) 2001, 2002, 2003, 2004 by Intevation GmbH
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4  # Jonathan Coles <[email protected]>  # Jonathan Coles <[email protected]>
# Line 14  be tested reasonably easily and it could Line 14  be tested reasonably easily and it could
14  renderers.  renderers.
15  """  """
16    
17    from __future__ import generators
18    
19  __version__ = "$Revision$"  __version__ = "$Revision$"
20  # $Source$  # $Source$
21  # $Id$  # $Id$
22    
23    import sys
24  import traceback  import traceback
25    
26  from Thuban.Model.layer import Layer, RasterLayer  from Thuban.Model.layer import Layer, RasterLayer
# Line 27  from Thuban.Model.label import ALIGN_CEN Line 30  from Thuban.Model.label import ALIGN_CEN
30    
31  import Thuban.Model.resource  import Thuban.Model.resource
32    
 if Thuban.Model.resource.has_gdal_support():  
     from gdalwarp import ProjectRasterFile  
33    
34    
35    #
36    #       Renderer Extensions
37    #
38    # The renderer extensions provide a way to render layer types defined in
39    # Thuban extensions. The renderer extensions are stored as a list with
40    # (layer_class, draw_function) pairs. If the renderer has to draw a
41    # non-builtin layer type, i.e. a layer that is not a subclass of Layer
42    # or RasterLayer, it iterates through that list, tests whether the layer
43    # to be drawn is an instance of layer_class and if so calls
44    # draw_function with the renderer and the layer as arguments. Since
45    # drawing is done incrementally, the draw_function should return an
46    # iterable. The easiest way is to simply implement the draw_function as
47    # a generator and to yield in suitable places, or to return the empty
48    # tuple.
49    #
50    # New renderer extensions should be added with add_renderer_extension().
51    # If necessary the extensions list can be reset with
52    # init_renderer_extensions().
53    
54    _renderer_extensions = []
55    
56    def add_renderer_extension(layer_class, function):
57        """Add a renderer extension for the layer class layer_class
58    
59        When an instance of layer_class is to be drawn by the renderer the
60        renderer will call function with the renderer and the layer_class
61        instance as arguments. Since drawing is done incrementally, the
62        function should return an iterable. The easiest way is to simply
63        implement the draw_function as a generator and to yield True in
64        suitable places, or to return the empty tuple if it's not possible
65        to do the rendering incrementally.
66        """
67        _renderer_extensions.append((layer_class, function))
68    
69    def init_renderer_extensions():
70        """(Re)initialize the list of renderer extensions
71    
72        Calling this function outside of the test suite is probably not
73        useful.
74        """
75        del _renderer_extensions[:]
76    
77    def proj_params_to_str(proj):
78        "Build a string suitable for GDAL describing the given projection"
79        str = ""
80        if proj is not None:
81            for p in proj.GetAllParameters():
82                str += "+" + p + " "
83        return str
84    
85    #
86    #       Base Renderer
87    #
88    
89  class BaseRenderer:  class BaseRenderer:
90    
91      """Basic Renderer Infrastructure for Thuban Maps      """Basic Renderer Infrastructure for Thuban Maps
# Line 49  class BaseRenderer: Line 104  class BaseRenderer:
104      TRANSPARENT_PEN = None      TRANSPARENT_PEN = None
105      TRANSPARENT_BRUSH = None      TRANSPARENT_BRUSH = None
106    
107      def __init__(self, dc, scale, offset, resolution = 72.0,      def __init__(self, dc, map, scale, offset, region = None,
108                   honor_visibility = None):                   resolution = 72.0, honor_visibility = None):
109          """Inititalize the renderer.          """Inititalize the renderer.
110    
111          dc -- the device context to render on.          dc -- the device context to render on.
# Line 58  class BaseRenderer: Line 113  class BaseRenderer:
113          scale, offset -- the scale factor and translation to convert          scale, offset -- the scale factor and translation to convert
114                  between projected coordinates and the DC coordinates                  between projected coordinates and the DC coordinates
115    
116            region -- The region to draw as a (x, y, width, height) tuple in
117                      the map's coordinate system. Default is None meaning
118                      to draw everything.
119    
120          resolution -- the assumed resolution of the DC. Used to convert          resolution -- the assumed resolution of the DC. Used to convert
121                  absolute lengths like font sizes to DC coordinates. The                  absolute lengths like font sizes to DC coordinates. The
122                  defauult is 72.0                  default is 72.0. If given, this parameter must be
123                    provided as a keyword argument.
124    
125          honor_visibility -- boolean. If true, honor the visibility flag          honor_visibility -- boolean. If true, honor the visibility flag
126                  of the layers, otherwise draw all layers. If None (the                  of the layers, otherwise draw all layers. If None (the
127                  default), use the renderer's default.                  default), use the renderer's default. If given, this
128                    parameter must be provided as a keyword argument.
129          """          """
130          # resolution in pixel/inch          # resolution in pixel/inch
   
131          self.dc = dc          self.dc = dc
132            self.map = map
133          self.scale = scale          self.scale = scale
134          self.offset = offset          self.offset = offset
135            self.region = region
136          if honor_visibility is not None:          if honor_visibility is not None:
137              self.honor_visibility = honor_visibility              self.honor_visibility = honor_visibility
138          # store the resolution in pixel/point because it's more useful          # store the resolution in pixel/point because it's more useful
# Line 85  class BaseRenderer: Line 147  class BaseRenderer:
147          """          """
148          raise NotImplementedError          raise NotImplementedError
149    
150      def render_map(self, map):      def render_map(self):
151          """Render the map onto the DC the renderer was instantiated with          """Render the map onto the DC.
152    
153            Both map and DC are the ones the renderer was instantiated with.
154    
155            This method is just a front-end for render_map_incrementally
156            which does all rendering in one go. It also calls the dc's
157            BeginDrawing and EndDrawing methods before and after calling
158            render_map_incrementally.
159            """
160    
161            self.dc.BeginDrawing()
162            try:
163                for cont in self.render_map_incrementally():
164                    pass
165            finally:
166                self.dc.EndDrawing()
167    
168        def render_map_incrementally(self):
169            """Render the map incrementally.
170    
171            Return an iterator whose next method should be called until it
172            returns False. After returning False it will raise StopIteration
173            so that you could also use it in a for loop (implementation
174            detail: this method is implemented as a generator).
175    
176          Iterate through all layers and draw them. Layers containing          Iterate through all layers and draw them. Layers containing
177          vector data are drawn with the draw_shape_layer method, raster          vector data are drawn with the draw_shape_layer method, raster
# Line 97  class BaseRenderer: Line 182  class BaseRenderer:
182          that methods especially in derived classes have access to the          that methods especially in derived classes have access to the
183          map if necessary.          map if necessary.
184          """          """
         # Some method have to have access to the map so we store it in  
         # self.map.  
         self.map = map  
   
         # Whether the raster layer has already been drawn. See below for  
         # the optimization this is used for  
         seenRaster = True  
   
         self.dc.BeginDrawing()  
185    
186          try:          for layer in self.map.Layers():
187              #              # if honor_visibility is true, only draw visible layers,
188              # This is only a good optimization if there is only one              # otherwise draw all layers
189              # raster layer and the image covers the entire window (as              if not self.honor_visibility or layer.Visible():
190              # it currently does). We note if there is a raster layer                  if isinstance(layer, Layer):
191              # and only begin drawing layers once we have drawn it.                      for i in self.draw_shape_layer_incrementally(layer):
192              # That way we avoid drawing layers that won't be seen.                          yield True
193              #                  elif isinstance(layer, RasterLayer):
194              if Thuban.Model.resource.has_gdal_support():                      self.draw_raster_layer(layer)
195                  for layer in map.Layers():                      yield True
196                      if isinstance(layer, RasterLayer) and layer.Visible():                  else:
197                          seenRaster = False                      # look it up in the renderer extensions
198                          break                      for cls, func in _renderer_extensions:
199                            if isinstance(layer, cls):
200              for layer in map.Layers():                              for i in func(self, layer):
201                  # if honor_visibility is true, only draw visible layers,                                  yield True
202                  # otherwise draw all layers                              break
203                  if not self.honor_visibility or layer.Visible():                      else:
204                      if isinstance(layer, Layer) and seenRaster:                          # No renderer found. Print a message about it
205                          self.draw_shape_layer(layer)                          print >>sys.stderr, ("Drawing layer %r not supported"
206                      elif isinstance(layer, RasterLayer) \                                               % layer)
207                          and Thuban.Model.resource.has_gdal_support():              yield True
                         self.draw_raster_layer(layer)  
                         seenRaster = True  
208    
209              self.draw_label_layer(map.LabelLayer())          self.draw_label_layer(self.map.LabelLayer())
210          finally:          yield False
             self.dc.EndDrawing()  
211    
212      def draw_shape_layer(self, layer):      def draw_shape_layer_incrementally(self, layer):
213          """Draw the shape layer layer onto the map.          """Draw the shape layer layer onto the map incrementally.
214    
215          Automatically called by render_map. Iterate through all shapes          This method is a generator which yields True after every 500
216          as indicated by self.layer_ids() and draw them, using low-level          shapes.
         renderers returned by self.low_level_renderer().  
217          """          """
218          scale = self.scale          scale = self.scale
219          offx, offy = self.offset          offx, offy = self.offset
# Line 159  class BaseRenderer: Line 231  class BaseRenderer:
231          defaultGroup = lc.GetDefaultGroup()          defaultGroup = lc.GetDefaultGroup()
232          table = layer.ShapeStore().Table()          table = layer.ShapeStore().Table()
233    
234            if lc.GetNumGroups() == 0:
235                # There's only the default group, so we can pretend that
236                # there is no field to classifiy on which makes things
237                # faster since we don't need the attribute information at
238                # all.
239                field = None
240    
241          # Determine which render function to use.          # Determine which render function to use.
242          draw_func, draw_func_param = self.low_level_renderer(layer)          useraw, draw_func, draw_func_param = self.low_level_renderer(layer)
243    
244            #
245          # Iterate through all shapes that have to be drawn.          # Iterate through all shapes that have to be drawn.
246          for i in self.layer_ids(layer):          #
247    
248            # Count the shapes drawn so that we can yield every few hundred
249            # shapes
250            count = 0
251    
252            # Cache the tools (pens and brushes) for the classification
253            # groups. This is a mapping from the group's ids to the a tuple
254            # (pen, brush)
255            tool_cache = {}
256    
257            for shape in self.layer_shapes(layer):
258                count += 1
259              if field is None:              if field is None:
260                  group = defaultGroup                  group = defaultGroup
261              else:              else:
262                  record = table.ReadRowAsDict(i)                  value = table.ReadValue(shape.ShapeID(), field)
263                  assert record is not None                  group = lc.FindGroup(value)
                 group = lc.FindGroup(record[field])  
264    
265              if not group.IsVisible():              if not group.IsVisible():
266                  continue                  continue
267    
268              # don't recreate new objects if they are the same as before              try:
269              if group is not old_group:                  pen, brush = tool_cache[id(group)]
270                  old_group = group              except KeyError:
271                    pen, brush = tool_cache[id(group)] \
272                  prop = group.GetProperties()                               = self.tools_for_property(group.GetProperties())
   
                 if prop != old_prop:  
                     pen, brush = self.tools_for_property(prop)  
273    
274              draw_func(draw_func_param, i, pen, brush)              if useraw:
275                    data = shape.RawData()
276                else:
277                    data = shape.Points()
278                if draw_func == self.draw_point_shape:
279                     draw_func(draw_func_param, data, pen, brush,
280                               size = group.GetProperties().GetSize())
281                else:
282                     draw_func(draw_func_param, data, pen, brush)
283                if count % 500 == 0:
284                    yield True
285    
286      def layer_ids(self, layer):      def layer_shapes(self, layer):
287          """Return the shape ids of the given layer that have to be drawn.          """Return an iterable over the shapes to be drawn from the given layer.
288    
289          The default implementation simply returns all ids in the layer.          The default implementation simply returns all ids in the layer.
290          Override in derived classes to be more precise.          Override in derived classes to be more precise.
291          """          """
292          return range(layer.NumShapes())          return layer.ShapeStore().AllShapes()
293    
294      def low_level_renderer(self, layer):      def low_level_renderer(self, layer):
295          """Return the low-level renderer for the layer for draw_shape_layer          """Return the low-level renderer for the layer for draw_shape_layer
296    
297          The low level renderer to be returned by this method is a tuple          The low level renderer to be returned by this method is a tuple
298          (func, param) where func is a callable object and param is          (useraw, func, param) where useraw is a boolean indicating
299          passed as the first parameter to func. The draw_shape_layer          whether the function uses the raw shape data, func is a callable
300          method will call func like this:          object and param is passed as the first parameter to func. The
301            draw_shape_layer method will call func like this:
302              func(param, rawshape, pen, brush)  
303                func(param, shapedata, pen, brush)
304          where rawshape is currently the shapeid. pen and brush are the  
305          pen and brush to use to draw the shape on the dc.          where shapedata is the return value of the RawData method of the
306            shape object if useraw is true or the return value of the Points
307            method if it's false. pen and brush are the pen and brush to use
308            to draw the shape on the dc.
309    
310          The default implementation returns one of          The default implementation returns one of
311          self.draw_polygon_shape, self.draw_arc_shape or          self.draw_polygon_shape, self.draw_arc_shape or
312          self.draw_point_shape as func and layer as param. Derived          self.draw_point_shape as func and layer as param. None of the
313          classes can override this method to return more efficient low          method use the raw shape data. Derived classes can override this
314          level renderers.          method to return more efficient low level renderers.
315          """          """
316          shapetype = layer.ShapeType()          shapetype = layer.ShapeType()
317          if shapetype == SHAPETYPE_POINT:          if shapetype == SHAPETYPE_POINT:
# Line 220  class BaseRenderer: Line 320  class BaseRenderer:
320              func = self.draw_arc_shape              func = self.draw_arc_shape
321          else:          else:
322              func = self.draw_polygon_shape              func = self.draw_polygon_shape
323          return func, layer          return False, func, layer
324    
325      def make_point(self, x, y):      def make_point(self, x, y):
326          """Convert (x, y) to a point object.          """Convert (x, y) to a point object.
# Line 229  class BaseRenderer: Line 329  class BaseRenderer:
329          """          """
330          raise NotImplementedError          raise NotImplementedError
331    
332      def projected_points(self, layer, shapeid):      def projected_points(self, layer, points):
333          """Return the projected coordinates of shape shapeid in layer.          """Return the projected coordinates of the points taken from layer.
334    
335          Read the shape from the layer through its Shape method and          Transform all the points in the list of lists of coordinate
336          transform all the points in the list of lists of coordinate          pairs in points.
         pairs returned by the shape's Points method.  
337    
338          The transformation applies the inverse of the layer's projection          The transformation applies the inverse of the layer's projection
339          if any, then the map's projection if any and finally applies          if any, then the map's projection if any and finally applies
# Line 253  class BaseRenderer: Line 352  class BaseRenderer:
352              inverse = proj.Inverse              inverse = proj.Inverse
353          else:          else:
354              inverse = None              inverse = None
355          shape = layer.Shape(shapeid)          result = []
         points = []  
356          scale = self.scale          scale = self.scale
357          offx, offy = self.offset          offx, offy = self.offset
358          make_point = self.make_point          make_point = self.make_point
359          for part in shape.Points():  
360              points.append([])          for part in points:
361                result.append([])
362              for x, y in part:              for x, y in part:
363                  if inverse:                  if inverse:
364                      x, y = inverse(x, y)                      x, y = inverse(x, y)
365                  if forward:                  if forward:
366                      x, y = forward(x, y)                      x, y = forward(x, y)
367                  points[-1].append(make_point(x * scale + offx,                  result[-1].append(make_point(x * scale + offx,
368                                               -y * scale + offy))                                               -y * scale + offy))
369          return points          return result
370    
371      def draw_polygon_shape(self, layer, index, pen, brush):      def draw_polygon_shape(self, layer, points, pen, brush):
372          """Draw a polygon shape with the given brush and pen          """Draw a polygon shape from layer with the given brush and pen
373    
374          The shape is indicated by its id (index) and the layer. The          The shape is given by points argument which is a the return
375          coordinates in the DC's coordinate system are determined with          value of the shape's Points() method. The coordinates in the
376            DC's coordinate system are determined with
377          self.projected_points.          self.projected_points.
378    
379            For a description of the algorithm look in wxproj.cpp.
380          """          """
381          points = self.projected_points(layer, index)          points = self.projected_points(layer, points)
382    
383          if brush is not self.TRANSPARENT_BRUSH:          if brush is not self.TRANSPARENT_BRUSH:
384              polygon = []              polygon = []
385              for part in points:              for part in points:
386                  polygon.extend(part)                  polygon.extend(part)
387    
388                # missing back vertices for correct filling.
389              insert_index = len(polygon)              insert_index = len(polygon)
390              for part in points[:-1]:              for part in points[:-1]:
391                  polygon.insert(insert_index, part[0])                  polygon.insert(insert_index, part[0])
# Line 298  class BaseRenderer: Line 401  class BaseRenderer:
401              for part in points:              for part in points:
402                  self.dc.DrawLines(part)                  self.dc.DrawLines(part)
403    
404      def draw_arc_shape(self, layer, index, pen, brush):      def draw_arc_shape(self, layer, points, pen, brush):
405          """Draw an arc shape with the given brush and pen          """Draw an arc shape from layer with the given brush and pen
406    
407          The shape is indicated by its id (index) and the layer. The          The shape is given by points argument which is a the return
408          coordinates in the DC's coordinate system are determined with          value of the shape's Points() method. The coordinates in the
409            DC's coordinate system are determined with
410          self.projected_points.          self.projected_points.
411          """          """
412          points = self.projected_points(layer, index)          points = self.projected_points(layer, points)
413          self.dc.SetBrush(brush)          self.dc.SetBrush(brush)
414          self.dc.SetPen(pen)          self.dc.SetPen(pen)
415          for part in points:          for part in points:
416              self.dc.DrawLines(part)              self.dc.DrawLines(part)
417    
418      def draw_point_shape(self, layer, index, pen, brush):      def draw_point_shape(self, layer, points, pen, brush, size = 5):
419          """Draw a point shape with the given brush and pen          """Draw a point shape from layer with the given brush and pen
420    
421          The shape is indicated by its id (index) and the layer. The          The shape is given by points argument which is a the return
422          coordinates in the DC's coordinate system are determined with          value of the shape's Points() method. The coordinates in the
423            DC's coordinate system are determined with
424          self.projected_points.          self.projected_points.
425    
426          The point is drawn as a circle centered on the point.          The point is drawn as a circle centered on the point.
427          """          """
428          points = self.projected_points(layer, index)          points = self.projected_points(layer, points)
429          if not points:          if not points:
430              return              return
431    
432          radius = self.resolution * 5          radius = int(round(self.resolution * size))
433          self.dc.SetBrush(brush)          self.dc.SetBrush(brush)
434          self.dc.SetPen(pen)          self.dc.SetPen(pen)
435          for part in points:          for part in points:
# Line 335  class BaseRenderer: Line 440  class BaseRenderer:
440      def draw_raster_layer(self, layer):      def draw_raster_layer(self, layer):
441          """Draw the raster layer          """Draw the raster layer
442    
443          This implementation does the projection and scaling of the data          This implementation uses self.projected_raster_layer() to project
444          as required by the layer's and map's projections and the scale          and scale the data as required by the layer's and map's projections
445          and offset of the renderer and then hands the transformed data          and the scale and offset of the renderer and then hands the transformed
446          to self.draw_raster_data() which has to be implemented in          data to self.draw_raster_data() which has to be implemented in
447          derived classes.          derived classes.
448          """          """
449          offx, offy = self.offset          offx, offy = self.offset
450          width, height = self.dc.GetSizeTuple()          width, height = self.dc.GetSizeTuple()
451    
452          in_proj = ""          in_proj  = proj_params_to_str(layer.GetProjection())
453          proj = layer.GetProjection()          out_proj = proj_params_to_str(self.map.GetProjection())
         if proj is not None:  
             for p in proj.GetAllParameters():  
                 in_proj += "+" + p + " "  
454    
455          out_proj = ""          # True  -- warp the image to the size of the whole screen
456          proj = self.map.GetProjection()          # False -- only use the bound box of the layer (currently inaccurate)
457          if proj is not None:          if True:
458              for p in proj.GetAllParameters():          #if False:
459                  out_proj += "+" + p + " "              pmin = [0,height]
460                pmax = [width, 0]
461            else:
462                bb = layer.LatLongBoundingBox()
463                bb = [[[bb[0], bb[1]], [bb[2], bb[3]],],]
464                pmin, pmax = self.projected_points(layer, bb)[0]
465    
466          xmin = (0 - offx) / self.scale          #print bb
467          ymin = (offy - height) / self.scale          #print pmin, pmax
         xmax = (width - offx) / self.scale  
         ymax = (offy - 0) / self.scale  
468    
469          try:          fmin = [max(0, min(pmin[0], pmax[0])) - offx,
470              data = ProjectRasterFile(layer.GetImageFilename(),                  offy - min(height, max(pmin[1], pmax[1]))]
                                      in_proj, out_proj,  
                                      (xmin, ymin, xmax, ymax), "",  
                                      (width, height))  
         except (IOError, AttributeError, ValueError):  
             # Why does this catch AttributeError and ValueError?  
             # FIXME: The exception should be communicated to the user  
             # better.  
             traceback.print_exc()  
         else:  
             self.draw_raster_data(data)  
471    
472      def draw_raster_data(self, data):          fmax = [min(width, max(pmin[0], pmax[0])) - offx,
473          """Draw the raster image in data onto the DC                  offy - max(0, min(pmin[1], pmax[1]))]
474    
475          The raster image data is a string holding the data in BMP          xmin = fmin[0]/self.scale
476          format. The data is exactly the size of the dc and covers it          ymin = fmin[1]/self.scale
477          completely.          xmax = fmax[0]/self.scale
478            ymax = fmax[1]/self.scale
479    
480            width  = int(min(width,  round(fmax[0] - fmin[0] + 1)))
481            height = int(min(height, round(fmax[1] - fmin[1] + 1)))
482    
483            options = 0
484            options = options | layer.MaskType()
485    
486            img_data = self.projected_raster_layer(layer, in_proj, out_proj,
487                        (xmin,ymin,xmax,ymax), [0,0], (width, height), options)
488    
489            if img_data is not None:
490                data = (width, height, img_data)
491                self.draw_raster_data(fmin[0]+offx, offy-fmax[1],
492                                      data, format="RAW", opacity=layer.Opacity())
493                data = None
494    
495        def projected_raster_layer(self, layer, srcProj, dstProj, extents,
496                                   resolution, dimensions, options):
497            """Return the projected raster image associated with the layer.
498    
499            The returned value will be a tuple of the form
500    
501                (image_data, mask_data, alpha_data)
502    
503            suitable for the data parameter to draw_raster_data.
504    
505            The return value may be None if raster projections are not supported.
506    
507            srcProj     --  a string describing the source projection
508            dstProj     --  a string describing the destination projection
509            extents     --  a tuple of the region to project in map coordinates
510            resolution  --  (currently not used, defaults to [0,0])
511            dimensions  --  a tuple (width, height) for the output image
512            options     --  bit-wise options to pass to the renderer
513    
514            the currently supported values for options are
515    
516                OPTS_MASK        = 1  -- generate a mask
517                OPTS_ALPHA       = 2  -- generate an alpha channel
518                OPTS_INVERT_MASK = 4  -- invert the values in the mask
519                                         (if generated)
520    
521          This method has to be implemented by derived classes.          This method has to be implemented by derived classes.
522          """          """
523    
524            raise NotImplementedError
525    
526        def draw_raster_data(self, x, y, data, format="BMP", opacity=1.0):
527            """Draw a raster image held in data onto the DC with the top
528            left corner at (x,y)
529    
530            The raster image data is a tuple of the form
531                (width, height, (image_data, mask_data, alpha_data))
532            
533            holding the image width, height, image data, mask data, and alpha data.
534            mask_data may be None if a mask should not be used. alpha_data may
535            also be None. If both are not None mask overrides alpha. If
536            format is 'RAW' the data will be RGB values and the mask
537            will be in XMB format. Otherwise, both kinds
538            of data are assumed to be in the format specified in format.
539    
540            The format parameter is a string with the name of the format.
541            The following format names should be used:
542    
543              'RAW'  -- an array of RGB values (len=3*width*height)
544              'PNG'  -- Portable Network Graphic (transparency supported)
545              'BMP'  -- Windows Bitmap
546              'TIFF' -- Tagged Image File Format
547              'GIF'  -- GIF Image
548              'JPEG' -- JPEG Image
549    
550            The default format is 'BMP'.
551    
552            This method has to be implemented by derived classes. The
553            implementation in the derived class should try to support at
554            least the formats specified above and may support more.
555            """
556          raise NotImplementedError          raise NotImplementedError
557    
558      def label_font(self):      def label_font(self):
# Line 411  class BaseRenderer: Line 581  class BaseRenderer:
581              text = label.text              text = label.text
582              if forward:              if forward:
583                  x, y = forward(x, y)                  x, y = forward(x, y)
584              x = x * scale + offx              x = int(round(x * scale + offx))
585              y = -y * scale + offy              y = int(round(-y * scale + offy))
586              width, height = self.dc.GetTextExtent(text)              width, height = self.dc.GetTextExtent(text)
587              if label.halign == ALIGN_LEFT:              if label.halign == ALIGN_LEFT:
588                  # nothing to be done                  # nothing to be done

Legend:
Removed from v.1554  
changed lines
  Added in v.2755

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26