diff options
Diffstat (limited to 'gerber/render')
-rw-r--r-- | gerber/render/cairo_backend.py | 95 | ||||
-rw-r--r-- | gerber/render/render.py | 10 | ||||
-rw-r--r-- | gerber/render/theme.py | 17 |
3 files changed, 65 insertions, 57 deletions
diff --git a/gerber/render/cairo_backend.py b/gerber/render/cairo_backend.py index a3ee3fa..0cb230b 100644 --- a/gerber/render/cairo_backend.py +++ b/gerber/render/cairo_backend.py @@ -24,7 +24,8 @@ from operator import mul, div import math
import tempfile
-from .render import GerberContext
+from .render import GerberContext, RenderSettings
+from .theme import THEMES
from ..primitives import *
try:
@@ -44,6 +45,15 @@ class GerberCairoContext(GerberContext): self.mask_ctx = None
self.origin_in_inch = None
self.size_in_inch = None
+ self._xform_matrix = None
+
+ @property
+ def origin_in_pixels(self):
+ return tuple(map(mul, self.origin_in_inch, self.scale)) if self.origin_in_inch is not None else (0.0, 0.0)
+
+ @property
+ def size_in_pixels(self):
+ return tuple(map(mul, self.size_in_inch, self.scale)) if self.size_in_inch is not None else (0.0, 0.0)
def set_bounds(self, bounds, new_surface=False):
origin_in_inch = (bounds[0][0], bounds[1][0])
@@ -63,34 +73,55 @@ class GerberCairoContext(GerberContext): self.mask_ctx.set_fill_rule(cairo.FILL_RULE_EVEN_ODD)
self.mask_ctx.scale(1, -1)
self.mask_ctx.translate(-(origin_in_inch[0] * self.scale[0]), (-origin_in_inch[1]*self.scale[0]) - size_in_pixels[1])
+ self._xform_matrix = cairo.Matrix(xx=1.0, yy=-1.0, x0=-self.origin_in_pixels[0], y0=self.size_in_pixels[1] + self.origin_in_pixels[1])
- def render_layers(self, layers, filename):
+ def render_layers(self, layers, filename, theme=THEMES['default']):
""" Render a set of layers
"""
self.set_bounds(layers[0].bounds, True)
self._paint_background(True)
for layer in layers:
- self._render_layer(layer)
+ self._render_layer(layer, theme)
self.dump(filename)
- @property
- def origin_in_pixels(self):
- return tuple(map(mul, self.origin_in_inch, self.scale)) if self.origin_in_inch is not None else (0.0, 0.0)
+ def dump(self, filename):
+ """ Save image as `filename`
+ """
+ if filename and filename.lower().endswith(".svg"):
+ self.surface.finish()
+ self.surface_buffer.flush()
+ with open(filename, "w") as f:
+ self.surface_buffer.seek(0)
+ f.write(self.surface_buffer.read())
+ f.flush()
+ else:
+ return self.surface.write_to_png(filename)
- @property
- def size_in_pixels(self):
- return tuple(map(mul, self.size_in_inch, self.scale)) if self.size_in_inch is not None else (0.0, 0.0)
+ def dump_str(self):
+ """ Return a string containing the rendered image.
+ """
+ fobj = StringIO()
+ self.surface.write_to_png(fobj)
+ return fobj.getvalue()
- def _render_layer(self, layer):
- self.color = layer.settings.color
- self.alpha = layer.settings.alpha
- self.invert = layer.settings.invert
- if layer.settings.mirror:
+ def dump_svg_str(self):
+ """ Return a string containg the rendered SVG.
+ """
+ self.surface.finish()
+ self.surface_buffer.flush()
+ return self.surface_buffer.read()
+
+ def _render_layer(self, layer, theme=THEMES['default']):
+ settings = theme.get(layer.layer_class, RenderSettings())
+ self.color = settings.color
+ self.alpha = settings.alpha
+ self.invert = settings.invert
+ if settings.mirror:
raise Warning('mirrored layers aren\'t supported yet...')
if self.invert:
self._clear_mask()
- for p in layer.primitives:
- self.render(p)
+ for prim in layer.primitives:
+ self.render(prim)
if self.invert:
self._render_mask()
@@ -298,10 +329,11 @@ class GerberCairoContext(GerberContext): def _render_test_record(self, primitive, color):
position = tuple(map(add, primitive.position, self.origin_in_inch))
+ self.ctx.set_operator(cairo.OPERATOR_OVER)
self.ctx.select_font_face('monospace', cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
self.ctx.set_font_size(13)
self._render_circle(Circle(position, 0.015), color)
- self.ctx.set_source_rgb(*color)
+ self.ctx.set_source_rgba(*color, alpha=self.alpha)
self.ctx.set_operator(cairo.OPERATOR_OVER if primitive.level_polarity == "dark" else cairo.OPERATOR_CLEAR)
self.ctx.move_to(*[self.scale[0] * (coord + 0.015) for coord in position])
self.ctx.scale(1, -1)
@@ -316,8 +348,7 @@ class GerberCairoContext(GerberContext): def _render_mask(self): self.ctx.set_operator(cairo.OPERATOR_OVER)
ptn = cairo.SurfacePattern(self.mask)
- ptn.set_matrix(cairo.Matrix(xx=1.0, yy=-1.0, x0=-self.origin_in_pixels[0],
- y0=self.size_in_pixels[1] + self.origin_in_pixels[1]))
+ ptn.set_matrix(self._xform_matrix)
self.ctx.set_source(ptn)
self.ctx.paint()
@@ -326,28 +357,4 @@ class GerberCairoContext(GerberContext): self.bg = True self.ctx.set_source_rgba(self.background_color[0], self.background_color[1], self.background_color[2], alpha=1.0) self.ctx.paint()
-
- def dump(self, filename):
- if filename and filename.lower().endswith(".svg"):
- self.surface.finish()
- self.surface_buffer.flush()
- with open(filename, "w") as f:
- self.surface_buffer.seek(0)
- f.write(self.surface_buffer.read())
- f.flush()
- else:
- return self.surface.write_to_png(filename)
-
- def dump_str(self):
- """ Return a string containing the rendered image.
- """
- fobj = StringIO()
- self.surface.write_to_png(fobj)
- return fobj.getvalue()
-
- def dump_svg_str(self):
- """ Return a string containg the rendered SVG.
- """
- self.surface.finish()
- self.surface_buffer.flush()
- return self.surface_buffer.read()
+ diff --git a/gerber/render/render.py b/gerber/render/render.py index cb65a8d..f521c44 100644 --- a/gerber/render/render.py +++ b/gerber/render/render.py @@ -214,8 +214,10 @@ class GerberContext(object): pass -class Renderable(object): - def __init__(self, settings=None): - self.settings = settings - self.primitives = [] +class RenderSettings(object): + def __init__(self, color=(0.0, 0.0, 0.0), alpha=1.0, invert=False, mirror=False): + self.color = color + self.alpha = alpha + self.invert = invert + self.mirror = mirror diff --git a/gerber/render/theme.py b/gerber/render/theme.py index 5978831..e538df8 100644 --- a/gerber/render/theme.py +++ b/gerber/render/theme.py @@ -16,6 +16,8 @@ # limitations under the License. +from .render import RenderSettings + COLORS = { 'black': (0.0, 0.0, 0.0), 'white': (1.0, 1.0, 1.0), @@ -33,14 +35,6 @@ COLORS = { } -class RenderSettings(object): - def __init__(self, color, alpha=1.0, invert=False, mirror=False): - self.color = color - self.alpha = alpha - self.invert = invert - self.mirror = mirror - - class Theme(object): def __init__(self, name=None, **kwargs): self.name = 'Default' if name is None else name @@ -57,8 +51,13 @@ class Theme(object): def __getitem__(self, key): return getattr(self, key) + def get(self, key, noneval=None): + val = getattr(self, key) + return val if val is not None else noneval + + THEMES = { - 'Default': Theme(), + 'default': Theme(), 'OSH Park': Theme(name='OSH Park', top=RenderSettings(COLORS['enig copper']), bottom=RenderSettings(COLORS['enig copper']), |