コード例 #1
0
ファイル: core.py プロジェクト: MengYing/BibTexParser
def join(lst1, lst2, separator=None):
    ret = []
    ret.extend(List.from_maybe(lst1))
    ret.extend(List.from_maybe(lst2))

    use_comma = __parse_separator(separator, default_from=lst1)
    return List(ret, use_comma=use_comma)
コード例 #2
0
ファイル: core.py プロジェクト: PhilipGarnero/pyScss
def join(lst1, lst2, separator=String.unquoted('auto')):
    expect_type(separator, String)

    ret = []
    ret.extend(List.from_maybe(lst1))
    ret.extend(List.from_maybe(lst2))

    if separator.value == 'comma':
        use_comma = True
    elif separator.value == 'space':
        use_comma = False
    elif separator.value == 'auto':
        # The Sass docs are slightly misleading here, but the algorithm is: use
        # the delimiter from the first list that has at least 2 items, or
        # default to spaces.
        if len(lst1) > 1:
            use_comma = lst1.use_comma
        elif len(lst2) > 1:
            use_comma = lst2.use_comma
        else:
            use_comma = False
    else:
        raise ValueError("separator for join() must be comma, space, or auto")

    return List(ret, use_comma=use_comma)
コード例 #3
0
ファイル: helpers.py プロジェクト: Foued123/qooxdoo
def reject(lst, *values):
    """Removes the given values from the list"""
    lst = List.from_maybe(lst)
    values = frozenset(List.from_maybe_starargs(values))

    ret = []
    for item in lst:
        if item not in values:
            ret.append(item)
    return List(ret, use_comma=lst.use_comma)
コード例 #4
0
ファイル: core.py プロジェクト: magical/pyScss
def quote(*args):
    arg = List.from_maybe_starargs(args).maybe()

    if isinstance(arg, StringValue):
        return StringValue(arg.value, quotes='"')
    else:
        return StringValue(arg.render(), quotes='"')
コード例 #5
0
ファイル: gradients.py プロジェクト: yacobell/pyScss
def grad_color_stops(*args):
    args = List.from_maybe_starargs(args)
    color_stops = __color_stops(True, *args)
    ret = ', '.join([
        'color-stop(%s, %s)' % (s.render(), c.render()) for s, c in color_stops
    ])
    return String.unquoted(ret)
コード例 #6
0
def enumerate_(prefix, frm, through, separator='-'):
    separator = String.unquoted(separator).value
    try:
        frm = int(getattr(frm, 'value', frm))
    except ValueError:
        frm = 1
    try:
        through = int(getattr(through, 'value', through))
    except ValueError:
        through = frm
    if frm > through:
        # DEVIATION: allow reversed enumerations (and ranges as range() uses enumerate, like '@for .. from .. through')
        frm, through = through, frm
        rev = reversed
    else:
        rev = lambda x: x

    ret = []
    for i in rev(range(frm, through + 1)):
        if prefix and prefix.value:
            ret.append(
                String.unquoted(prefix.value + separator + six.text_type(i)))
        else:
            ret.append(Number(i))

    return List(ret, use_comma=True)
コード例 #7
0
ファイル: core.py プロジェクト: PhilipGarnero/pyScss
def append(lst, val, separator="space"):
    ret = []
    ret.extend(List.from_maybe(lst))
    ret.append(val)

    use_comma = __parse_separator(separator, default_from=lst)
    return List(ret, use_comma=use_comma)
コード例 #8
0
ファイル: helpers.py プロジェクト: hblanks/pyScss
def _font_files(args, inline):
    args = List.from_maybe_starargs(args)
    n = 0
    params = [[], []]
    for arg in args:
        if isinstance(arg, List):
            if len(arg) == 2:
                if n % 2 == 1:
                    params[1].append(None)
                    n += 1
                params[0].append(arg[0])
                params[1].append(arg[1])
                n += 2
            else:
                for arg2 in arg:
                    params[n % 2].append(arg2)
                    n += 1
        else:
            params[n % 2].append(arg)
            n += 1
    len0 = len(params[0])
    len1 = len(params[1])
    if len1 < len0:
        params[1] += [None] * (len0 - len1)
    elif len0 < len1:
        params[0] += [None] * (len1 - len0)
    fonts = []
    for font, format in zip(params[0], params[1]):
        if format:
            fonts.append('%s format("%s")' % (_font_url(font, inline=inline), String.unquoted(format).value))
        else:
            fonts.append(_font_url(font, inline=inline))
    return List(fonts)
コード例 #9
0
ファイル: core.py プロジェクト: magical/pyScss
def unquote(*args):
    arg = List.from_maybe_starargs(args).maybe()

    if isinstance(arg, StringValue):
        return StringValue(arg.value, quotes=None)
    else:
        return StringValue(arg.render(), quotes=None)
コード例 #10
0
def test_reference_operations():
    """Test the example expressions in the reference document:

    http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#operations
    """
    # TODO: break this into its own file and add the entire reference guide

    # Need to build the calculator manually to get at its namespace, and need
    # to use calculate() instead of evaluate_expression() so interpolation
    # works
    ns = CoreExtension.namespace.derive()
    calc = Calculator(ns).calculate

    # Simple example
    assert calc('1in + 8pt') == Number(1.1111111111111112, "in")

    # Division
    ns.set_variable('$width', Number(1000, "px"))
    ns.set_variable('$font-size', Number(12, "px"))
    ns.set_variable('$line-height', Number(30, "px"))
    assert calc('10px/8px') == String('10px / 8px')  # plain CSS; no division
    assert calc('$width/2') == Number(500,
                                      "px")  # uses a variable; does division
    assert calc('(500px/2)') == Number(250, "px")  # uses parens; does division
    assert calc('5px + 8px/2px') == Number(9, "px")  # uses +; does division
    # TODO, again: Ruby Sass correctly renders this without spaces
    assert calc('#{$font-size}/#{$line-height}') == String('12px / 30px')
    # uses #{}; does no division

    # Color operations
    ns.set_variable('$translucent-red', Color.from_rgb(1, 0, 0, 0.5))
    ns.set_variable('$green', Color.from_name('lime'))
    assert calc('#010203 + #040506') == Color.from_hex('#050709')
    assert calc('#010203 * 2') == Color.from_hex('#020406')
    assert calc(
        'rgba(255, 0, 0, 0.75) + rgba(0, 255, 0, 0.75)') == Color.from_rgb(
            1, 1, 0, 0.75)
    assert calc('opacify($translucent-red, 0.3)') == Color.from_rgb(
        1, 0, 0, 0.8)
    assert calc('transparentize($translucent-red, 0.25)') == Color.from_rgb(
        1, 0, 0, 0.25)
    assert calc(
        "progid:DXImageTransform.Microsoft.gradient(enabled='false', startColorstr='#{ie-hex-str($green)}', endColorstr='#{ie-hex-str($translucent-red)}')"
    ).render(
    ) == "progid:DXImageTransform.Microsoft.gradient(enabled='false', startColorstr='#FF00FF00', endColorstr='#80FF0000')"

    # String operations
    ns.set_variable('$value', Null())
    assert_strict_string_eq(calc('e + -resize'), String('e-resize',
                                                        quotes=None))
    assert_strict_string_eq(calc('"Foo " + Bar'), String('Foo Bar',
                                                         quotes='"'))
    assert_strict_string_eq(calc('sans- + "serif"'),
                            String('sans-serif', quotes=None))
    assert calc('3px + 4px auto') == List(
        [Number(7, "px"), String('auto', quotes=None)])
    assert_strict_string_eq(calc('"I ate #{5 + 10} pies!"'),
                            String('I ate 15 pies!', quotes='"'))
    assert_strict_string_eq(calc('"I ate #{$value} pies!"'),
                            String('I ate  pies!', quotes='"'))
コード例 #11
0
ファイル: core.py プロジェクト: PhilipGarnero/pyScss
def quote(*args):
    arg = List.from_maybe_starargs(args).maybe()

    if isinstance(arg, String):
        return String(arg.value, quotes='"')
    else:
        return String(arg.render(), quotes='"')
コード例 #12
0
ファイル: extra.py プロジェクト: Rehy0810/database
def background_noise(density=None, opacity=None, size=None, monochrome=False, intensity=(), color=None, background=None, inline=False):
    if not Image:
        raise Exception("Images manipulation require PIL")

    density = [Number(v).value for v in List.from_maybe(density)]
    intensity = [Number(v).value for v in List.from_maybe(intensity)]
    color = [Color(v).value for v in List.from_maybe(color) if v]
    opacity = [Number(v).value for v in List.from_maybe(opacity)]

    size = int(Number(size).value) if size else 0
    if size < 1 or size > 512:
        size = 200

    monochrome = bool(monochrome)

    background = Color(background).value if background else None

    new_image = Image.new(
        mode='RGBA',
        size=(size, size)
    )

    pixdata = new_image.load()
    _image_noise(pixdata, size, density, intensity, color, opacity, monochrome)

    if not inline:
        key = (size, density, intensity, color, opacity, monochrome)
        asset_file = 'noise-%s%sx%s' % ('mono-' if monochrome else '', size, size)
        # asset_file += '-[%s][%s]' % ('-'.join(to_str(s).replace('.', '_') for s in density or []), '-'.join(to_str(s).replace('.', '_') for s in opacity or []))
        asset_file += '-' + base64.urlsafe_b64encode(hashlib.md5(repr(key)).digest()).rstrip('=').replace('-', '_')
        asset_file += '.png'
        asset_path = os.path.join(config.ASSETS_ROOT or os.path.join(config.STATIC_ROOT, 'assets'), asset_file)
        try:
            new_image.save(asset_path)
        except IOError:
            log.exception("Error while saving image")
            inline = True  # Retry inline version
        url = '%s%s' % (config.ASSETS_URL, asset_file)
    if inline:
        output = six.BytesIO()
        new_image.save(output, format='PNG')
        contents = output.getvalue()
        output.close()
        url = 'data:image/png;base64,' + base64.b64encode(contents)

    inline = 'url("%s")' % escape(url)
    return String.unquoted(inline)
コード例 #13
0
ファイル: gradients.py プロジェクト: 4teamwork/pyScss
def _get_gradient_color_stops(args):
    color_stops = []
    for arg in args:
        for a in List.from_maybe(arg):
            if _is_color(a):
                color_stops.append(arg)
                break
    return color_stops or None
コード例 #14
0
def _get_gradient_color_stops(args):
    color_stops = []
    for arg in args:
        for a in List.from_maybe(arg):
            if isinstance(a, Color):
                color_stops.append(arg)
                break
    return color_stops or None
コード例 #15
0
def test_parse(calc):
    # Tests for some general parsing.

    assert calc('foo !important bar') == List([
        String('foo'),
        String('!important'),
        String('bar'),
    ])
コード例 #16
0
def _get_gradient_color_stops(args):
    color_stops = []
    for arg in args:
        for a in List.from_maybe(arg):
            if _is_color(a):
                color_stops.append(arg)
                break
    return color_stops or None
コード例 #17
0
ファイル: gradients.py プロジェクト: Foued123/qooxdoo
def _get_gradient_color_stops(args):
    color_stops = []
    for arg in args:
        for a in List.from_maybe(arg):
            if isinstance(a, Color):
                color_stops.append(arg)
                break
    return color_stops or None
コード例 #18
0
    def evaluate(self, calculator, divide=False):
        # TODO bake this into the context and options "dicts", plus library
        func_name = normalize_var(self.func_name)

        argspec_node = self.argspec

        # Turn the pairs of arg tuples into *args and **kwargs
        # TODO unclear whether this is correct -- how does arg, kwarg, arg
        # work?
        args, kwargs = argspec_node.evaluate_call_args(calculator)
        argspec_len = len(args) + len(kwargs)

        # Translate variable names to Python identifiers
        # TODO what about duplicate kw names?  should this happen in argspec?
        # how does that affect mixins?
        kwargs = dict((key.lstrip('$').replace('-', '_'), value)
                      for key, value in kwargs.items())

        # TODO merge this with the library
        funct = None
        try:
            funct = calculator.namespace.function(func_name, argspec_len)
            # @functions take a ns as first arg.  TODO: Python functions possibly
            # should too
            if getattr(funct, '__name__', None) == '__call':
                funct = partial(funct, calculator.namespace)
        except KeyError:
            try:
                # DEVIATION: Fall back to single parameter
                funct = calculator.namespace.function(func_name, 1)
                args = [List(args, use_comma=True)]
            except KeyError:
                if not is_builtin_css_function(func_name):
                    log.error("Function not found: %s:%s",
                              func_name,
                              argspec_len,
                              extra={'stack': True})

        if funct:
            ret = funct(*args, **kwargs)
            if not isinstance(ret, Value):
                raise TypeError("Expected Sass type as return value, got %r" %
                                (ret, ))
            return ret

        # No matching function found, so render the computed values as a CSS
        # function call.  Slurpy arguments are expanded and named arguments are
        # unsupported.
        if kwargs:
            raise TypeError(
                "The CSS function %s doesn't support keyword arguments." %
                (func_name, ))

        # TODO another candidate for a "function call" sass type
        rendered_args = [arg.render() for arg in args]

        return String(u"%s(%s)" % (func_name, u", ".join(rendered_args)),
                      quotes=None)
コード例 #19
0
ファイル: test_gradients.py プロジェクト: ziotoie00/pyScss
def test_linear_gradient():
    # Set up some values
    to = String.unquoted('to')
    bottom = String.unquoted('bottom')
    left = String.unquoted('left')

    red = Color.from_name('red')
    blue = Color.from_name('blue')

    start = Number(0, "%")
    middle = Number(50, "%")
    end = Number(100, "%")

    assert (linear_gradient(left, List((red, start)), List(
        (blue, middle))) == String('linear-gradient(left, red, blue 50%)'))

    assert (linear_gradient(List((to, bottom)), blue, List(
        (red, end))) == String('linear-gradient(to bottom, blue, red)'))
コード例 #20
0
ファイル: fonts.py プロジェクト: coinpayee/pyScss
def glyphs(sheet, remove_suffix=False):
    sheet = sheet.render()
    font_sheet = font_sheets.get(sheet, {})
    return List([
        String.unquoted(f) for f in sorted(
            set(
                f.rsplit('-', 1)[0] if remove_suffix else f for f in font_sheet
                if not f.startswith('*')))
    ])
コード例 #21
0
ファイル: gradients.py プロジェクト: Foued123/qooxdoo
def linear_gradient(*args):
    args = List.from_maybe_starargs(args)

    position_and_angle = _get_gradient_position_and_angle(args)
    color_stops = _get_gradient_color_stops(args)
    if color_stops is None:
        raise Exception('No color stops provided to linear-gradient function')
    color_stops = __color_stops(False, *color_stops)

    args = [
        position(position_and_angle) if position_and_angle is not None else None,
    ]
    args.extend(_render_standard_color_stops(color_stops))

    to__s = 'linear-gradient(' + ', '.join(to_str(a) for a in args or [] if a is not None) + ')'
    ret = String.unquoted(to__s)

    def to__css2():
        return String.unquoted('')
    ret.to__css2 = to__css2

    def to__moz():
        return String.unquoted('-moz-' + to__s)
    ret.to__moz = to__moz

    def to__pie():
        return String.unquoted('-pie-' + to__s)
    ret.to__pie = to__pie

    def to__ms():
        return String.unquoted('-ms-' + to__s)
    ret.to__ms = to__ms

    def to__o():
        return String.unquoted('-o-' + to__s)
    ret.to__o = to__o

    def to__webkit():
        return String.unquoted('-webkit-' + to__s)
    ret.to__webkit = to__webkit

    def to__owg():
        args = [
            'linear',
            position(position_and_angle or None),
            opposite_position(position_and_angle or None),
        ]
        args.extend('color-stop(%s, %s)' % (s.render(), c.render()) for s, c in color_stops)
        ret = '-webkit-gradient(' + ', '.join(to_str(a) for a in args if a is not None) + ')'
        return String.unquoted(ret)
    ret.to__owg = to__owg

    def to__svg():
        return linear_svg_gradient(color_stops, position_and_angle or 'top')
    ret.to__svg = to__svg

    return ret
コード例 #22
0
def linear_gradient(*args):
    args = List.from_maybe_starargs(args)

    position_and_angle = _get_gradient_position_and_angle(args)
    color_stops = _get_gradient_color_stops(args)
    if color_stops is None:
        raise Exception('No color stops provided to linear-gradient function')
    color_stops = __color_stops(False, *color_stops)

    args = [
        position(position_and_angle) if position_and_angle is not None else None,
    ]
    args.extend(_render_standard_color_stops(color_stops))

    to__s = 'linear-gradient(' + ', '.join(to_str(a) for a in args or [] if a is not None) + ')'
    ret = String.unquoted(to__s)

    def to__css2():
        return String.unquoted('')
    ret.to__css2 = to__css2

    def to__moz():
        return String.unquoted('-moz-' + to__s)
    ret.to__moz = to__moz

    def to__pie():
        return String.unquoted('-pie-' + to__s)
    ret.to__pie = to__pie

    def to__ms():
        return String.unquoted('-ms-' + to__s)
    ret.to__ms = to__ms

    def to__o():
        return String.unquoted('-o-' + to__s)
    ret.to__o = to__o

    def to__webkit():
        return String.unquoted('-webkit-' + to__s)
    ret.to__webkit = to__webkit

    def to__owg():
        args = [
            'linear',
            position(position_and_angle or None),
            opposite_position(position_and_angle or None),
        ]
        args.extend('color-stop(%s, %s)' % (s.render(), c.render()) for s, c in color_stops)
        ret = '-webkit-gradient(' + ', '.join(to_str(a) for a in args if a is not None) + ')'
        return String.unquoted(ret)
    ret.to__owg = to__owg

    def to__svg():
        return linear_svg_gradient(color_stops, position_and_angle or 'top')
    ret.to__svg = to__svg

    return ret
コード例 #23
0
def sprites(map, remove_suffix=False):
    map = map.render()
    sprite_map = sprite_maps.get(map, {})
    return List([
        String.unquoted(s) for s in sorted(
            set(
                s.rsplit('-', 1)[0] if remove_suffix else s for s in sprite_map
                if not s.startswith('*')))
    ])
コード例 #24
0
ファイル: helpers.py プロジェクト: return42/pyScss
def nest(*arguments):
    if isinstance(arguments[0], List):
        lst = arguments[0]
    elif isinstance(arguments[0], String):
        lst = arguments[0].value.split(',')
    else:
        raise TypeError("Expected list or string, got %r" % (arguments[0], ))

    ret = []
    for s in lst:
        if isinstance(s, String):
            s = s.value
        elif isinstance(s, six.string_types):
            s = s
        else:
            raise TypeError("Expected string, got %r" % (s, ))

        s = s.strip()
        if not s:
            continue

        ret.append(s)

    for arg in arguments[1:]:
        if isinstance(arg, List):
            lst = arg
        elif isinstance(arg, String):
            lst = arg.value.split(',')
        else:
            raise TypeError("Expected list or string, got %r" % (arg, ))

        new_ret = []
        for s in lst:
            if isinstance(s, String):
                s = s.value
            elif isinstance(s, six.string_types):
                s = s
            else:
                raise TypeError("Expected string, got %r" % (s, ))

            s = s.strip()
            if not s:
                continue

            for r in ret:
                if '&' in s:
                    new_ret.append(s.replace('&', r))
                else:
                    if not r or r[-1] in ('.', ':', '#'):
                        new_ret.append(r + s)
                    else:
                        new_ret.append(r + ' ' + s)
        ret = new_ret

    ret = [String.unquoted(s) for s in sorted(set(ret))]
    return List(ret, use_comma=True)
コード例 #25
0
ファイル: helpers.py プロジェクト: return42/pyScss
def prefix(prefix, *args):
    to_fnct_str = 'to_' + to_str(prefix).replace('-', '_')
    args = list(args)
    for i, arg in enumerate(args):
        if isinstance(arg, List):
            _value = []
            for iarg in arg:
                to_fnct = getattr(iarg, to_fnct_str, None)
                if to_fnct:
                    _value.append(to_fnct())
                else:
                    _value.append(iarg)
            args[i] = List(_value)
        else:
            to_fnct = getattr(arg, to_fnct_str, None)
            if to_fnct:
                args[i] = to_fnct()

    return List.maybe_new(args, use_comma=True)
コード例 #26
0
ファイル: helpers.py プロジェクト: Foued123/qooxdoo
def first_value_of(*args):
    if len(args) == 1 and isinstance(args[0], String):
        first = args[0].value.split()[0]
        return type(args[0])(first)

    args = List.from_maybe_starargs(args)
    if len(args):
        return args[0]
    else:
        return Null()
コード例 #27
0
ファイル: helpers.py プロジェクト: return42/pyScss
def first_value_of(*args):
    if len(args) == 1 and isinstance(args[0], String):
        first = args[0].value.split()[0]
        return type(args[0])(first)

    args = List.from_maybe_starargs(args)
    if len(args):
        return args[0]
    else:
        return Null()
コード例 #28
0
ファイル: helpers.py プロジェクト: return42/pyScss
def compact(*args):
    """Returns a new list after removing any non-true values"""
    use_comma = True
    if len(args) == 1 and isinstance(args[0], List):
        use_comma = args[0].use_comma
        args = args[0]

    return List(
        [arg for arg in args if arg],
        use_comma=use_comma,
    )
コード例 #29
0
ファイル: gradients.py プロジェクト: Rehy0810/database
def radial_gradient(*args):
    args = List.from_maybe_starargs(args)

    position_and_angle = _get_gradient_position_and_angle(args)
    shape_and_size = _get_gradient_shape_and_size(args)
    color_stops = _get_gradient_color_stops(args)
    if color_stops is None:
        raise Exception('No color stops provided to radial-gradient function')
    color_stops = __color_stops(False, *color_stops)

    args = [
        position(position_and_angle) if position_and_angle is not None else None,
        shape_and_size if shape_and_size is not None else None,
    ]
    args.extend(_render_standard_color_stops(color_stops))

    to__s = 'radial-gradient(' + ', '.join(to_str(a) for a in args or [] if a is not None) + ')'
    ret = String.unquoted(to__s)

    def to__css2():
        return String.unquoted('')
    ret.to__css2 = to__css2

    def to__moz():
        return String.unquoted('-moz-' + to__s)
    ret.to__moz = to__moz

    def to__pie():
        log.warn("PIE does not support radial-gradient.")
        return String.unquoted('-pie-radial-gradient(unsupported)')
    ret.to__pie = to__pie

    def to__webkit():
        return String.unquoted('-webkit-' + to__s)
    ret.to__webkit = to__webkit

    def to__owg():
        args = [
            'radial',
            grad_point(position_and_angle) if position_and_angle is not None else 'center',
            '0',
            grad_point(position_and_angle) if position_and_angle is not None else 'center',
            __grad_end_position(True, color_stops),
        ]
        args.extend('color-stop(%s, %s)' % (s.render(), c.render()) for s, c in color_stops)
        ret = '-webkit-gradient(' + ', '.join(to_str(a) for a in args or [] if a is not None) + ')'
        return String.unquoted(ret)
    ret.to__owg = to__owg

    def to__svg():
        return radial_svg_gradient(color_stops, position_and_angle or 'center')
    ret.to__svg = to__svg

    return ret
コード例 #30
0
ファイル: gradients.py プロジェクト: Foued123/qooxdoo
def radial_gradient(*args):
    args = List.from_maybe_starargs(args)

    position_and_angle = _get_gradient_position_and_angle(args)
    shape_and_size = _get_gradient_shape_and_size(args)
    color_stops = _get_gradient_color_stops(args)
    if color_stops is None:
        raise Exception('No color stops provided to radial-gradient function')
    color_stops = __color_stops(False, *color_stops)

    args = [
        position(position_and_angle) if position_and_angle is not None else None,
        shape_and_size if shape_and_size is not None else None,
    ]
    args.extend(_render_standard_color_stops(color_stops))

    to__s = 'radial-gradient(' + ', '.join(to_str(a) for a in args or [] if a is not None) + ')'
    ret = String.unquoted(to__s)

    def to__css2():
        return String.unquoted('')
    ret.to__css2 = to__css2

    def to__moz():
        return String.unquoted('-moz-' + to__s)
    ret.to__moz = to__moz

    def to__pie():
        log.warn("PIE does not support radial-gradient.")
        return String.unquoted('-pie-radial-gradient(unsupported)')
    ret.to__pie = to__pie

    def to__webkit():
        return String.unquoted('-webkit-' + to__s)
    ret.to__webkit = to__webkit

    def to__owg():
        args = [
            'radial',
            grad_point(position_and_angle) if position_and_angle is not None else 'center',
            '0',
            grad_point(position_and_angle) if position_and_angle is not None else 'center',
            __grad_end_position(True, color_stops),
        ]
        args.extend('color-stop(%s, %s)' % (s.render(), c.render()) for s, c in color_stops)
        ret = '-webkit-gradient(' + ', '.join(to_str(a) for a in args or [] if a is not None) + ')'
        return String.unquoted(ret)
    ret.to__owg = to__owg

    def to__svg():
        return radial_svg_gradient(color_stops, position_and_angle or 'center')
    ret.to__svg = to__svg

    return ret
コード例 #31
0
ファイル: helpers.py プロジェクト: return42/pyScss
def _position(opposite, positions):
    if positions is None:
        positions = DEFAULT_POSITION
    else:
        positions = List.from_maybe(positions)

    ret = []
    for pos in positions:
        if isinstance(pos, (String, six.string_types)):
            pos_value = getattr(pos, 'value', pos)
            if pos_value in OPPOSITE_POSITIONS:
                if opposite:
                    ret.append(OPPOSITE_POSITIONS[pos_value])
                else:
                    ret.append(pos)
                continue
            elif pos_value == 'to':
                # Gradient syntax keyword; leave alone
                ret.append(pos)
                continue

        elif isinstance(pos, Number):
            if pos.is_simple_unit('%'):
                if opposite:
                    ret.append(Number(100 - pos.value, '%'))
                else:
                    ret.append(pos)
                continue
            elif pos.is_simple_unit('deg'):
                # TODO support other angle types?
                if opposite:
                    ret.append(Number((pos.value + 180) % 360, 'deg'))
                else:
                    ret.append(pos)
                continue

        if opposite:
            log.warn("Can't find opposite for position %r" % (pos, ))
        ret.append(pos)

    return List(ret, use_comma=False).maybe()
コード例 #32
0
def append(lst, val, separator=String.unquoted('auto')):
    expect_type(separator, String)

    ret = []
    ret.extend(List.from_maybe(lst))
    ret.append(val)

    separator = separator.value
    if separator == 'comma':
        use_comma = True
    elif separator == 'space':
        use_comma = False
    elif separator == 'auto':
        if len(lst) < 2:
            use_comma = False
        else:
            use_comma = lst.use_comma
    else:
        raise ValueError('Separator must be auto, comma, or space')

    return List(ret, use_comma=use_comma)
コード例 #33
0
ファイル: sprites.py プロジェクト: 571451370/devstack_mitaka
def sprite_position(map, sprite, offset_x=None, offset_y=None):
    """
    Returns the position for the original image in the sprite.
    This is suitable for use as a value to background-position.
    """
    map = map.render()
    sprite_maps = _get_cache('sprite_maps')
    sprite_map = sprite_maps.get(map)
    sprite_name = String.unquoted(sprite).value
    sprite = sprite_map and sprite_map.get(sprite_name)
    if not sprite_map:
        log.error("No sprite map found: %s", map, extra={'stack': True})
    elif not sprite:
        log.error("No sprite found: %s in %s",
                  sprite_name,
                  sprite_map['*n*'],
                  extra={'stack': True})
    if sprite:
        x = None
        if offset_x is not None and not isinstance(offset_x, Number):
            x = offset_x
        if not x or x.value not in ('left', 'right', 'center'):
            if x:
                offset_x = None
            x = Number(offset_x or 0, 'px')
            if not x.value or (x.value <= -1
                               or x.value >= 1) and not x.is_simple_unit('%'):
                x -= Number(sprite[2], 'px')
        y = None
        if offset_y is not None and not isinstance(offset_y, Number):
            y = offset_y
        if not y or y.value not in ('top', 'bottom', 'center'):
            if y:
                offset_y = None
            y = Number(offset_y or 0, 'px')
            if not y.value or (y.value <= -1
                               or y.value >= 1) and not y.is_simple_unit('%'):
                y -= Number(sprite[3], 'px')
        return List([x, y])
    return List([Number(0), Number(0)])
コード例 #34
0
ファイル: test_expression.py プロジェクト: ziotoie00/pyScss
def test_parse_bang_important(calc):
    # The !important flag is treated as part of a spaced list.
    assert calc('40px !important') == List([
        Number(40, 'px'),
        String.unquoted('!important'),
    ],
                                           use_comma=False)

    # And is allowed anywhere in the string.
    assert calc('foo !important bar') == List([
        String('foo'),
        String('!important'),
        String('bar'),
    ],
                                              use_comma=False)

    # And may have space before the !.
    assert calc('40px ! important') == List([
        Number(40, 'px'),
        String.unquoted('!important'),
    ],
                                            use_comma=False)
コード例 #35
0
    def evaluate(self, calculator, divide=False):
        items = [item.evaluate(calculator, divide=divide) for item in self.items]

        # Whether this is a "plain" literal matters for null removal: nulls are
        # left alone if this is a completely vanilla CSS property
        literal = True
        if divide:
            # TODO sort of overloading "divide" here...  rename i think
            literal = False
        elif not all(isinstance(item, Literal) for item in self.items):
            literal = False

        return List(items, use_comma=self.comma, literal=literal)
コード例 #36
0
def linear_svg_gradient(*args):
    args = List.from_maybe_starargs(args)
    color_stops = args
    start = None
    if isinstance(args[-1], (StringValue, NumberValue, six.string_types)):
        start = args[-1]
        color_stops = args[:-1]
    color_stops = __color_stops(False, *color_stops)
    x1, y1 = zip(*grad_point(start).items())[1]
    x2, y2 = zip(*grad_point(opposite_position(start)).items())[1]
    svg = _linear_svg(color_stops, x1, y1, x2, y2)
    url = 'data:' + 'image/svg+xml' + ';base64,' + base64.b64encode(svg)
    inline = 'url("%s")' % escape(url)
    return StringValue(inline)
コード例 #37
0
def radial_svg_gradient(*args):
    args = List.from_maybe_starargs(args)
    color_stops = args
    center = None
    if isinstance(args[-1], (String, Number)):
        center = args[-1]
        color_stops = args[:-1]
    color_stops = __color_stops(False, *color_stops)
    cx, cy = grad_point(center)
    r = __grad_end_position(True, color_stops)
    svg = __radial_svg(color_stops, cx, cy, r)
    url = 'data:' + 'image/svg+xml' + ';base64,' + base64.b64encode(svg)
    inline = 'url("%s")' % escape(url)
    return String.unquoted(inline)
コード例 #38
0
def grad_point(*p):
    pos = set()
    hrz = vrt = Number(0.5, '%')
    for _p in p:
        pos.update(String.unquoted(_p).value.split())
    if 'left' in pos:
        hrz = Number(0, '%')
    elif 'right' in pos:
        hrz = Number(1, '%')
    if 'top' in pos:
        vrt = Number(0, '%')
    elif 'bottom' in pos:
        vrt = Number(1, '%')
    return List([v for v in (hrz, vrt) if v is not None])
コード例 #39
0
def linear_svg_gradient(*args):
    args = List.from_maybe_starargs(args)
    color_stops = args
    start = None
    if isinstance(args[-1], (String, Number)):
        start = args[-1]
        color_stops = args[:-1]
    color_stops = __color_stops(False, *color_stops)
    x1, y1 = grad_point(start)
    x2, y2 = grad_point(opposite_position(start))
    svg = _linear_svg(color_stops, x1, y1, x2, y2)
    url = 'data:' + 'image/svg+xml' + ';base64,' + base64.b64encode(svg)
    inline = 'url("%s")' % escape(url)
    return String.unquoted(inline)
コード例 #40
0
ファイル: gradients.py プロジェクト: Foued123/qooxdoo
def linear_svg_gradient(*args):
    args = List.from_maybe_starargs(args)
    color_stops = args
    start = None
    if isinstance(args[-1], (String, Number, six.string_types)):
        start = args[-1]
        color_stops = args[:-1]
    color_stops = __color_stops(False, *color_stops)
    x1, y1 = zip(*grad_point(start).items())[1]
    x2, y2 = zip(*grad_point(opposite_position(start)).items())[1]
    svg = _linear_svg(color_stops, x1, y1, x2, y2)
    url = 'data:' + 'image/svg+xml' + ';base64,' + base64.b64encode(svg)
    inline = 'url("%s")' % escape(url)
    return String.unquoted(inline)
コード例 #41
0
ファイル: gradients.py プロジェクト: Foued123/qooxdoo
def radial_svg_gradient(*args):
    args = List.from_maybe_starargs(args)
    color_stops = args
    center = None
    if isinstance(args[-1], (String, Number, six.string_types)):
        center = args[-1]
        color_stops = args[:-1]
    color_stops = __color_stops(False, *color_stops)
    cx, cy = zip(*grad_point(center).items())[1]
    r = __grad_end_position(True, color_stops)
    svg = __radial_svg(color_stops, cx, cy, r)
    url = 'data:' + 'image/svg+xml' + ';base64,' + base64.b64encode(svg)
    inline = 'url("%s")' % escape(url)
    return String.unquoted(inline)
コード例 #42
0
def _position(opposite, positions):
    if positions is None:
        positions = DEFAULT_POSITION
    else:
        positions = List.from_maybe(positions)

    ret = []
    for pos in positions:
        if isinstance(pos, (StringValue, six.string_types)):
            pos_value = getattr(pos, 'value', pos)
            if pos_value in OPPOSITE_POSITIONS:
                if opposite:
                    ret.append(OPPOSITE_POSITIONS[pos_value])
                else:
                    ret.append(pos)
                continue

        elif isinstance(pos, NumberValue):
            if pos.unit == '%':
                if opposite:
                    ret.append(NumberValue(100 - pos.value, '%'))
                else:
                    ret.append(pos)
                continue
            elif pos.unit == 'deg':
                # TODO support other angle types?
                if opposite:
                    ret.append(NumberValue((pos.value + 180) % 360, 'deg'))
                else:
                    ret.append(pos)
                continue

        log.warn("Can't find opposite for position %r" % (pos, ))
        ret.append(pos)

    return List(ret, use_comma=False).maybe()
コード例 #43
0
ファイル: helpers.py プロジェクト: Foued123/qooxdoo
def prefix(prefix, *args):
    to_fnct_str = 'to_' + to_str(prefix).replace('-', '_')
    args = list(args)
    for i, arg in enumerate(args):
        if isinstance(arg, List):
            _value = []
            for iarg in arg:
                to_fnct = getattr(iarg, to_fnct_str, None)
                if to_fnct:
                    _value.append(to_fnct())
                else:
                    _value.append(iarg)
            args[i] = List(_value)
        else:
            to_fnct = getattr(arg, to_fnct_str, None)
            if to_fnct:
                args[i] = to_fnct()

    return List.maybe_new(args, use_comma=True)
コード例 #44
0
ファイル: extra.py プロジェクト: incidunt/pyScss
def background_brushed(density=None, intensity=None, color=None, opacity=None, size=None, monochrome=False, direction=(), spread=(), background=None, inline=False):
    if not Image:
        raise Exception("Images manipulation require PIL")

    density = [Number(v).value for v in List.from_maybe(density)]
    intensity = [Number(v).value for v in List.from_maybe(intensity)]
    color = [Color(v).value for v in List.from_maybe(color) if v]
    opacity = [Number(v).value for v in List.from_maybe(opacity)]

    size = int(Number(size).value) if size else -1
    if size < 0 or size > 512:
        size = 200

    monochrome = bool(monochrome)

    direction = [Number(v).value for v in List.from_maybe(direction)]
    spread = [Number(v).value for v in List.from_maybe(spread)]

    background = Color(background).value if background else None

    new_image = Image.new(
        mode='RGBA',
        size=(size, size)
    )

    pixdata = new_image.load()
    _image_brushed(pixdata, size, density, intensity, color, opacity, monochrome, direction, spread, background)

    if not inline:
        key = (size, density, intensity, color, opacity, monochrome, direction, spread, background)
        asset_file = 'brushed-%s%sx%s' % ('mono-' if monochrome else '', size, size)
        # asset_file += '-[%s][%s][%s]' % ('-'.join(to_str(s).replace('.', '_') for s in density or []), '-'.join(to_str(s).replace('.', '_') for s in opacity or []), '-'.join(to_str(s).replace('.', '_') for s in direction or []))
        asset_file += '-' + make_filename_hash(key)
        asset_file += '.png'
        asset_path = os.path.join(config.ASSETS_ROOT or os.path.join(config.STATIC_ROOT, 'assets'), asset_file)
        try:
            new_image.save(asset_path)
        except IOError:
            log.exception("Error while saving image")
            inline = True  # Retry inline version
        url = '%s%s' % (config.ASSETS_URL, asset_file)
    if inline:
        output = six.BytesIO()
        new_image.save(output, format='PNG')
        contents = output.getvalue()
        output.close()
        url = make_data_url('image/png', contents)

    inline = 'url("%s")' % escape(url)
    return String.unquoted(inline)
コード例 #45
0
ファイル: helpers.py プロジェクト: Foued123/qooxdoo
def _position(opposite, positions):
    if positions is None:
        positions = DEFAULT_POSITION
    else:
        positions = List.from_maybe(positions)

    ret = []
    for pos in positions:
        if isinstance(pos, (String, six.string_types)):
            pos_value = getattr(pos, 'value', pos)
            if pos_value in OPPOSITE_POSITIONS:
                if opposite:
                    ret.append(OPPOSITE_POSITIONS[pos_value])
                else:
                    ret.append(pos)
                continue
            elif pos_value == 'to':
                # Gradient syntax keyword; leave alone
                ret.append(pos)
                continue

        elif isinstance(pos, Number):
            if pos.is_simple_unit('%'):
                if opposite:
                    ret.append(Number(100 - pos.value, '%'))
                else:
                    ret.append(pos)
                continue
            elif pos.is_simple_unit('deg'):
                # TODO support other angle types?
                if opposite:
                    ret.append(Number((pos.value + 180) % 360, 'deg'))
                else:
                    ret.append(pos)
                continue

        if opposite:
            log.warn("Can't find opposite for position %r" % (pos,))
        ret.append(pos)

    return List(ret, use_comma=False).maybe()
コード例 #46
0
ファイル: core.py プロジェクト: 4teamwork/pyScss
def append(lst, val, separator=String.unquoted('auto')):
    expect_type(separator, String)

    ret = []
    ret.extend(List.from_maybe(lst))
    ret.append(val)

    separator = separator.value
    if separator == 'comma':
        use_comma = True
    elif separator == 'space':
        use_comma = False
    elif separator == 'auto':
        if len(lst) < 2:
            use_comma = False
        else:
            use_comma = lst.use_comma
    else:
        raise ValueError('Separator must be auto, comma, or space')

    return List(ret, use_comma=use_comma)
コード例 #47
0
ファイル: helpers.py プロジェクト: return42/pyScss
def headers(frm=None, to=None):
    if frm and to is None:
        if isinstance(frm, String) and frm.value.lower() == 'all':
            frm = 1
            to = 6
        else:
            try:
                to = int(getattr(frm, 'value', frm))
            except ValueError:
                to = 6
            frm = 1
    else:
        try:
            frm = 1 if frm is None else int(getattr(frm, 'value', frm))
        except ValueError:
            frm = 1
        try:
            to = 6 if to is None else int(getattr(to, 'value', to))
        except ValueError:
            to = 6
    ret = [String.unquoted('h' + six.text_type(i)) for i in range(frm, to + 1)]
    return List(ret, use_comma=True)
コード例 #48
0
ファイル: gradients.py プロジェクト: Foued123/qooxdoo
def grad_color_stops(*args):
    args = List.from_maybe_starargs(args)
    color_stops = __color_stops(True, *args)
    ret = ', '.join(['color-stop(%s, %s)' % (s.render(), c.render()) for s, c in color_stops])
    return String.unquoted(ret)
コード例 #49
0
ファイル: sprites.py プロジェクト: jrcartee/pyScss
def sprite_map(g, **kwargs):
    """
    Generates a sprite map from the files matching the glob pattern.
    Uses the keyword-style arguments passed in to control the placement.

    $direction - Sprite map layout. Can be `vertical` (default), `horizontal`, `diagonal` or `smart`.

    $position - For `horizontal` and `vertical` directions, the position of the sprite. (defaults to `0`)
    $<sprite>-position - Position of a given sprite.

    $padding, $spacing - Adds paddings to sprites (top, right, bottom, left). (defaults to `0, 0, 0, 0`)
    $<sprite>-padding, $<sprite>-spacing - Padding for a given sprite.

    $dst-color - Together with `$src-color`, forms a map of source colors to be converted to destiny colors (same index of `$src-color` changed to `$dst-color`).
    $<sprite>-dst-color - Destiny colors for a given sprite. (defaults to `$dst-color`)

    $src-color - Selects source colors to be converted to the corresponding destiny colors. (defaults to `black`)
    $<sprite>-dst-color - Source colors for a given sprite. (defaults to `$src-color`)

    $collapse - Collapses every image in the sprite map to a fixed size (`x` and `y`).
    $collapse-x  - Collapses a size for `x`.
    $collapse-y  - Collapses a size for `y`.
    """
    if not Image:
        raise Exception("Images manipulation require PIL")

    sprite_maps = _get_cache('sprite_maps')

    now_time = time.time()

    globs = String(g, quotes=None).value
    globs = sorted(g.strip() for g in globs.split(','))

    _k_ = ','.join(globs)

    files = None
    rfiles = None
    tfiles = None
    map_name = None

    if _k_ in sprite_maps:
        sprite_maps[_k_]['*'] = now_time
    else:
        files = []
        rfiles = []
        tfiles = []
        for _glob in globs:
            if '..' not in _glob:  # Protect against going to prohibited places...
                if callable(config.STATIC_ROOT):
                    _glob_path = _glob
                    _rfiles = _files = sorted(config.STATIC_ROOT(_glob))
                else:
                    _glob_path = os.path.join(config.STATIC_ROOT, _glob)
                    _files = glob.glob(_glob_path)
                    _files = sorted((f, None) for f in _files)
                    _rfiles = [(rf[len(config.STATIC_ROOT):], s) for rf, s in _files]
                if _files:
                    files.extend(_files)
                    rfiles.extend(_rfiles)
                    base_name = os.path.normpath(os.path.dirname(_glob)).replace('\\', '_').replace('/', '_')
                    _map_name, _, _map_type = base_name.partition('.')
                    if _map_type:
                        _map_type += '-'
                    if not map_name:
                        map_name = _map_name
                    tfiles.extend([_map_type] * len(_files))
                else:
                    glob_path = _glob_path

    if files is not None:
        if not files:
            log.error("Nothing found at '%s'", glob_path)
            return String.unquoted('')

        key = [f for (f, s) in files] + [repr(kwargs), config.ASSETS_URL]
        key = map_name + '-' + make_filename_hash(key)
        asset_file = key + '.png'
        ASSETS_ROOT = _assets_root()
        asset_path = os.path.join(ASSETS_ROOT, asset_file)
        cache_path = os.path.join(config.CACHE_ROOT or ASSETS_ROOT, asset_file + '.cache')

        inline = Boolean(kwargs.get('inline', False))

        sprite_map = None
        asset = None
        file_asset = None
        inline_asset = None
        if os.path.exists(asset_path) or inline:
            try:
                save_time, file_asset, inline_asset, sprite_map, sizes = pickle.load(open(cache_path))
                if file_asset:
                    sprite_maps[file_asset.render()] = sprite_map
                if inline_asset:
                    sprite_maps[inline_asset.render()] = sprite_map
                if inline:
                    asset = inline_asset
                else:
                    asset = file_asset
            except:
                pass

            if sprite_map:
                for file_, storage in files:
                    _time = getmtime(file_, storage)
                    if save_time < _time:
                        if _time > now_time:
                            log.warning("File '%s' has a date in the future (cache ignored)" % file_)
                        sprite_map = None  # Invalidate cached sprite map
                        break

        if sprite_map is None or asset is None:
            cache_buster = Boolean(kwargs.get('cache_buster', True))
            direction = String.unquoted(kwargs.get('direction', config.SPRTE_MAP_DIRECTION)).value
            repeat = String.unquoted(kwargs.get('repeat', 'no-repeat')).value
            collapse = kwargs.get('collapse', Number(0))
            if isinstance(collapse, List):
                collapse_x = int(Number(collapse[0]).value)
                collapse_y = int(Number(collapse[-1]).value)
            else:
                collapse_x = collapse_y = int(Number(collapse).value)
            if 'collapse_x' in kwargs:
                collapse_x = int(Number(kwargs['collapse_x']).value)
            if 'collapse_y' in kwargs:
                collapse_y = int(Number(kwargs['collapse_y']).value)

            position = Number(kwargs.get('position', 0))
            if not position.is_simple_unit('%') and position.value > 1:
                position = position.value / 100.0
            else:
                position = position.value
            if position < 0:
                position = 0.0
            elif position > 1:
                position = 1.0

            padding = kwargs.get('padding', kwargs.get('spacing', Number(0)))
            padding = [int(Number(v).value) for v in List.from_maybe(padding)]
            padding = (padding * 4)[:4]

            dst_colors = kwargs.get('dst_color')
            dst_colors = [list(Color(v).value[:3]) for v in List.from_maybe(dst_colors) if v]
            src_colors = kwargs.get('src_color', Color.from_name('black'))
            src_colors = [tuple(Color(v).value[:3]) for v in List.from_maybe(src_colors)]
            len_colors = max(len(dst_colors), len(src_colors))
            dst_colors = (dst_colors * len_colors)[:len_colors]
            src_colors = (src_colors * len_colors)[:len_colors]

            def images(f=lambda x: x):
                for file_, storage in f(files):
                    if storage is not None:
                        _file = storage.open(file_)
                    else:
                        _file = file_
                    _image = Image.open(_file)
                    yield _image

            names = tuple(os.path.splitext(os.path.basename(file_))[0] for file_, storage in files)
            tnames = tuple(tfiles[i] + n for i, n in enumerate(names))

            has_dst_colors = False
            all_dst_colors = []
            all_src_colors = []
            all_positions = []
            all_paddings = []

            for name in names:
                name = name.replace('-', '_')

                _position = kwargs.get(name + '_position')
                if _position is None:
                    _position = position
                else:
                    _position = Number(_position)
                    if not _position.is_simple_unit('%') and _position.value > 1:
                        _position = _position.value / 100.0
                    else:
                        _position = _position.value
                    if _position < 0:
                        _position = 0.0
                    elif _position > 1:
                        _position = 1.0
                all_positions.append(_position)

                _padding = kwargs.get(name + '_padding', kwargs.get(name + '_spacing'))
                if _padding is None:
                    _padding = padding
                else:
                    _padding = [int(Number(v).value) for v in List.from_maybe(_padding)]
                    _padding = (_padding * 4)[:4]
                all_paddings.append(_padding)

                _dst_colors = kwargs.get(name + '_dst_color')
                if _dst_colors is None:
                    _dst_colors = dst_colors
                    if dst_colors:
                        has_dst_colors = True
                else:
                    has_dst_colors = True
                    _dst_colors = [list(Color(v).value[:3]) for v in List.from_maybe(_dst_colors) if v]
                _src_colors = kwargs.get(name + '_src_color', Color.from_name('black'))
                if _src_colors is None:
                    _src_colors = src_colors
                else:
                    _src_colors = [tuple(Color(v).value[:3]) for v in List.from_maybe(_src_colors)]
                _len_colors = max(len(_dst_colors), len(_src_colors))
                _dst_colors = (_dst_colors * _len_colors)[:_len_colors]
                _src_colors = (_src_colors * _len_colors)[:_len_colors]
                all_dst_colors.append(_dst_colors)
                all_src_colors.append(_src_colors)

            sizes = tuple((collapse_x or i.size[0], collapse_y or i.size[1]) for i in images())

            if direction == 'horizontal':
                layout = HorizontalSpritesLayout(sizes, all_paddings, position=all_positions)
            elif direction == 'vertical':
                layout = VerticalSpritesLayout(sizes, all_paddings, position=all_positions)
            elif direction == 'diagonal':
                layout = DiagonalSpritesLayout(sizes, all_paddings)
            elif direction == 'smart':
                layout = PackedSpritesLayout(sizes, all_paddings)
            else:
                raise Exception("Invalid direction %r" % (direction,))
            layout_positions = list(layout)

            new_image = Image.new(
                mode='RGBA',
                size=(layout.width, layout.height),
                color=(0, 0, 0, 0)
            )

            useless_dst_color = has_dst_colors

            offsets_x = []
            offsets_y = []
            for i, image in enumerate(images()):
                x, y, width, height, cssx, cssy, cssw, cssh = layout_positions[i]
                iwidth, iheight = image.size

                if has_dst_colors:
                    pixdata = image.load()
                    for _y in xrange(iheight):
                        for _x in xrange(iwidth):
                            pixel = pixdata[_x, _y]
                            a = pixel[3] if len(pixel) == 4 else 255
                            if a:
                                rgb = pixel[:3]
                                for j, dst_color in enumerate(all_dst_colors[i]):
                                    if rgb == all_src_colors[i][j]:
                                        new_color = tuple([int(c) for c in dst_color] + [a])
                                        if pixel != new_color:
                                            pixdata[_x, _y] = new_color
                                            useless_dst_color = False
                                        break

                if iwidth != width or iheight != height:
                    cy = 0
                    while cy < iheight:
                        cx = 0
                        while cx < iwidth:
                            new_image = alpha_composite(new_image, image, (x, y), (cx, cy, cx + width, cy + height))
                            cx += width
                        cy += height
                else:
                    new_image.paste(image, (x, y))
                offsets_x.append(cssx)
                offsets_y.append(cssy)

            if useless_dst_color:
                log.warning("Useless use of $dst-color in sprite map for files at '%s' (never used for)" % glob_path)

            filetime = int(now_time)

            if not inline:
                try:
                    new_image.save(asset_path)
                    url = '%s%s' % (config.ASSETS_URL, asset_file)
                    if cache_buster:
                        url += '?_=%s' % filetime
                except IOError:
                    log.exception("Error while saving image")
                    inline = True
            if inline:
                output = six.BytesIO()
                new_image.save(output, format='PNG')
                contents = output.getvalue()
                output.close()
                mime_type = 'image/png'
                url = make_data_url(mime_type, contents)

            url = 'url(%s)' % escape(url)
            if inline:
                asset = inline_asset = List([String.unquoted(url), String.unquoted(repeat)])
            else:
                asset = file_asset = List([String.unquoted(url), String.unquoted(repeat)])

            # Add the new object:
            sprite_map = dict(zip(tnames, zip(sizes, rfiles, offsets_x, offsets_y)))
            sprite_map['*'] = now_time
            sprite_map['*f*'] = asset_file
            sprite_map['*k*'] = key
            sprite_map['*n*'] = map_name
            sprite_map['*t*'] = filetime

            sizes = zip(files, sizes)
            cache_tmp = tempfile.NamedTemporaryFile(delete=False, dir=ASSETS_ROOT)
            pickle.dump((now_time, file_asset, inline_asset, sprite_map, sizes), cache_tmp)
            cache_tmp.close()
            if sys.platform == 'win32' and os.path.isfile(cache_path):
                # on windows, cannot rename a file to a path that matches
                # an existing file, we have to remove it first
                os.remove(cache_path)
            os.rename(cache_tmp.name, cache_path)

            # Use the sorted list to remove older elements (keep only 500 objects):
            if len(sprite_maps) > MAX_SPRITE_MAPS:
                for a in sorted(sprite_maps, key=lambda a: sprite_maps[a]['*'], reverse=True)[KEEP_SPRITE_MAPS:]:
                    del sprite_maps[a]
                log.warning("Exceeded maximum number of sprite maps (%s)" % MAX_SPRITE_MAPS)
            sprite_maps[asset.render()] = sprite_map
        image_size_cache = _get_cache('image_size_cache')
        for file_, size in sizes:
            image_size_cache[file_] = size
    # TODO this sometimes returns an empty list, or is never assigned to
    return asset
コード例 #50
0
ファイル: images.py プロジェクト: balagopalraj/clearlinux
def _image_url(
    path,
    only_path=False,
    cache_buster=True,
    dst_color=None,
    src_color=None,
    inline=False,
    mime_type=None,
    spacing=None,
    collapse_x=None,
    collapse_y=None,
):
    """
    src_color - a list of or a single color to be replaced by each corresponding dst_color colors
    spacing - spaces to be added to the image
    collapse_x, collapse_y - collapsable (layered) image of the given size (x, y)
    """
    if inline or dst_color or spacing:
        if not Image:
            raise Exception("Images manipulation require PIL")
    filepath = String.unquoted(path).value
    fileext = os.path.splitext(filepath)[1].lstrip(".").lower()
    if mime_type:
        mime_type = String.unquoted(mime_type).value
    if not mime_type:
        mime_type = mimetypes.guess_type(filepath)[0]
    if not mime_type:
        mime_type = "image/%s" % fileext
    path = None
    IMAGES_ROOT = _images_root()
    if callable(IMAGES_ROOT):
        try:
            _file, _storage = list(IMAGES_ROOT(filepath))[0]
            d_obj = _storage.modified_time(_file)
            filetime = int(time.mktime(d_obj.timetuple()))
            if inline or dst_color or spacing:
                path = _storage.open(_file)
        except:
            filetime = "NA"
    else:
        _path = os.path.join(IMAGES_ROOT.rstrip("/"), filepath.strip("/"))
        if os.path.exists(_path):
            filetime = int(os.path.getmtime(_path))
            if inline or dst_color or spacing:
                path = open(_path, "rb")
        else:
            filetime = "NA"

    BASE_URL = config.IMAGES_URL or config.STATIC_URL
    if path:
        dst_colors = [list(Color(v).value[:3]) for v in List.from_maybe(dst_color) if v]

        src_color = Color.from_name("black") if src_color is None else src_color
        src_colors = [tuple(Color(v).value[:3]) for v in List.from_maybe(src_color)]

        len_colors = max(len(dst_colors), len(src_colors))
        dst_colors = (dst_colors * len_colors)[:len_colors]
        src_colors = (src_colors * len_colors)[:len_colors]

        spacing = Number(0) if spacing is None else spacing
        spacing = [int(Number(v).value) for v in List.from_maybe(spacing)]
        spacing = (spacing * 4)[:4]

        file_name, file_ext = os.path.splitext(os.path.normpath(filepath).replace("\\", "_").replace("/", "_"))
        key = (filetime, src_color, dst_color, spacing)
        key = file_name + "-" + base64.urlsafe_b64encode(hashlib.md5(repr(key)).digest()).rstrip("=").replace("-", "_")
        asset_file = key + file_ext
        ASSETS_ROOT = config.ASSETS_ROOT or os.path.join(config.STATIC_ROOT, "assets")
        asset_path = os.path.join(ASSETS_ROOT, asset_file)

        if os.path.exists(asset_path):
            filepath = asset_file
            BASE_URL = config.ASSETS_URL
            if inline:
                path = open(asset_path, "rb")
                url = "data:" + mime_type + ";base64," + base64.b64encode(path.read())
            else:
                url = "%s%s" % (BASE_URL, filepath)
                if cache_buster:
                    filetime = int(os.path.getmtime(asset_path))
                    url = add_cache_buster(url, filetime)
        else:
            simply_process = False
            image = None

            if fileext in ("cur",):
                simply_process = True
            else:
                try:
                    image = Image.open(path)
                except IOError:
                    if not collapse_x and not collapse_y and not dst_colors:
                        simply_process = True

            if simply_process:
                if inline:
                    url = "data:" + mime_type + ";base64," + base64.b64encode(path.read())
                else:
                    url = "%s%s" % (BASE_URL, filepath)
                    if cache_buster:
                        filetime = int(os.path.getmtime(asset_path))
                        url = add_cache_buster(url, filetime)
            else:
                width, height = collapse_x or image.size[0], collapse_y or image.size[1]
                new_image = Image.new(
                    mode="RGBA",
                    size=(width + spacing[1] + spacing[3], height + spacing[0] + spacing[2]),
                    color=(0, 0, 0, 0),
                )
                for i, dst_color in enumerate(dst_colors):
                    src_color = src_colors[i]
                    pixdata = image.load()
                    for _y in xrange(image.size[1]):
                        for _x in xrange(image.size[0]):
                            pixel = pixdata[_x, _y]
                            if pixel[:3] == src_color:
                                pixdata[_x, _y] = tuple(
                                    [int(c) for c in dst_color] + [pixel[3] if len(pixel) == 4 else 255]
                                )
                iwidth, iheight = image.size
                if iwidth != width or iheight != height:
                    cy = 0
                    while cy < iheight:
                        cx = 0
                        while cx < iwidth:
                            cropped_image = image.crop((cx, cy, cx + width, cy + height))
                            new_image.paste(cropped_image, (int(spacing[3]), int(spacing[0])), cropped_image)
                            cx += width
                        cy += height
                else:
                    new_image.paste(image, (int(spacing[3]), int(spacing[0])))

                if not inline:
                    try:
                        new_image.save(asset_path)
                        filepath = asset_file
                        BASE_URL = config.ASSETS_URL
                        if cache_buster:
                            filetime = int(os.path.getmtime(asset_path))
                    except IOError:
                        log.exception("Error while saving image")
                        inline = True  # Retry inline version
                    url = os.path.join(config.ASSETS_URL.rstrip("/"), asset_file.lstrip("/"))
                    if cache_buster:
                        url = add_cache_buster(url, filetime)
                if inline:
                    output = six.BytesIO()
                    new_image.save(output, format="PNG")
                    contents = output.getvalue()
                    output.close()
                    url = "data:" + mime_type + ";base64," + base64.b64encode(contents)
    else:
        url = os.path.join(BASE_URL.rstrip("/"), filepath.lstrip("/"))
        if cache_buster and filetime != "NA":
            url = add_cache_buster(url, filetime)

    if not only_path:
        url = "url(%s)" % escape(url)
    return String.unquoted(url)
コード例 #51
0
ファイル: gradients.py プロジェクト: Foued123/qooxdoo
def color_stops_in_percentages(*args):
    args = List.from_maybe_starargs(args)
    color_stops = __color_stops(True, *args)
    ret = ', '.join(['%s %s' % (c.render(), s.render()) for s, c in color_stops])
    return String.unquoted(ret)
コード例 #52
0
ファイル: gradients.py プロジェクト: Foued123/qooxdoo
def __color_stops(percentages, *args):
    if len(args) == 1:
        if isinstance(args[0], (list, tuple, List)):
            list(args[0])
        elif isinstance(args[0], (String, six.string_types)):
            color_stops = []
            colors = split_params(getattr(args[0], 'value', args[0]))
            for color in colors:
                color = color.strip()
                if color.startswith('color-stop('):
                    s, c = split_params(color[11:].rstrip(')'))
                    s = s.strip()
                    c = c.strip()
                else:
                    c, s = color.split()
                color_stops.append((to_float(s), c))
            return color_stops

    colors = []
    stops = []
    prev_color = False
    for c in args:
        for c in List.from_maybe(c):
            if isinstance(c, Color):
                if prev_color:
                    stops.append(None)
                colors.append(c)
                prev_color = True
            elif isinstance(c, Number):
                stops.append(c)
                prev_color = False

    if prev_color:
        stops.append(None)
    stops = stops[:len(colors)]
    if stops[0] is None:
        stops[0] = Number(0, '%')
    if stops[-1] is None:
        stops[-1] = Number(100, '%')

    maxable_stops = [s for s in stops if s and not s.is_simple_unit('%')]
    if maxable_stops:
        max_stops = max(maxable_stops)
    else:
        max_stops = None

    stops = [_s / max_stops if _s and not _s.is_simple_unit('%') else _s for _s in stops]

    init = 0
    start = None
    for i, s in enumerate(stops + [1.0]):
        if s is None:
            if start is None:
                start = i
            end = i
        else:
            final = s
            if start is not None:
                stride = (final - init) / Number(end - start + 1 + (1 if i < len(stops) else 0))
                for j in range(start, end + 1):
                    stops[j] = init + stride * Number(j - start + 1)
            init = final
            start = None

    if not max_stops or percentages:
        pass
    else:
        stops = [s if s.is_simple_unit('%') else s * max_stops for s in stops]

    return list(zip(stops, colors))
コード例 #53
0
ファイル: helpers.py プロジェクト: Foued123/qooxdoo
def prefixed(prefix, *args):
    to_fnct_str = 'to_' + to_str(prefix).replace('-', '_')
    for arg in List.from_maybe_starargs(args):
        if hasattr(arg, to_fnct_str):
            return Boolean(True)
    return Boolean(False)
コード例 #54
0
ファイル: images.py プロジェクト: asfaltboy/pyScss
def _image_url(path, only_path=False, cache_buster=True, dst_color=None, src_color=None, inline=False, mime_type=None, spacing=None, collapse_x=None, collapse_y=None):
    """
    src_color - a list of or a single color to be replaced by each corresponding dst_color colors
    spacing - spaces to be added to the image
    collapse_x, collapse_y - collapsable (layered) image of the given size (x, y)
    """
    if inline or dst_color or spacing:
        if not Image:
            raise Exception("Images manipulation require PIL")
    filepath = String.unquoted(path).value
    fileext = os.path.splitext(filepath)[1].lstrip('.').lower()
    if mime_type:
        mime_type = String.unquoted(mime_type).value
    if not mime_type:
        mime_type = mimetypes.guess_type(filepath)[0]
    if not mime_type:
        mime_type = 'image/%s' % fileext
    path = None
    IMAGES_ROOT = _images_root()
    if callable(IMAGES_ROOT):
        try:
            _file, _storage = list(IMAGES_ROOT(filepath))[0]
        except IndexError:
            filetime = None
        else:
            filetime = getmtime(_file, _storage)
        if filetime is None:
            filetime = 'NA'
        elif inline or dst_color or spacing:
            path = _storage.open(_file)
    else:
        _path = os.path.join(IMAGES_ROOT.rstrip(os.sep), filepath.strip('\\/'))
        filetime = getmtime(_path)
        if filetime is None:
            filetime = 'NA'
        elif inline or dst_color or spacing:
            path = open(_path, 'rb')

    BASE_URL = config.IMAGES_URL or config.STATIC_URL
    if path:
        dst_colors = [list(Color(v).value[:3]) for v in List.from_maybe(dst_color) if v]

        src_color = Color.from_name('black') if src_color is None else src_color
        src_colors = [tuple(Color(v).value[:3]) for v in List.from_maybe(src_color)]

        len_colors = max(len(dst_colors), len(src_colors))
        dst_colors = (dst_colors * len_colors)[:len_colors]
        src_colors = (src_colors * len_colors)[:len_colors]

        spacing = Number(0) if spacing is None else spacing
        spacing = [int(Number(v).value) for v in List.from_maybe(spacing)]
        spacing = (spacing * 4)[:4]

        file_name, file_ext = os.path.splitext(os.path.normpath(filepath).replace(os.sep, '_'))
        key = (filetime, src_color, dst_color, spacing)
        asset_file = file_name + '-' + make_filename_hash(key) + file_ext
        ASSETS_ROOT = config.ASSETS_ROOT or os.path.join(config.STATIC_ROOT, 'assets')
        asset_path = os.path.join(ASSETS_ROOT, asset_file)

        if os.path.exists(asset_path):
            filepath = asset_file
            BASE_URL = config.ASSETS_URL
            if inline:
                path = open(asset_path, 'rb')
                url = make_data_url(mime_type, path.read())
            else:
                url = '%s%s' % (BASE_URL, filepath)
                if cache_buster:
                    filetime = getmtime(asset_path)
                    url = add_cache_buster(url, filetime)
        else:
            simply_process = False
            image = None

            if fileext in ('cur',):
                simply_process = True
            else:
                try:
                    image = Image.open(path)
                except IOError:
                    if not collapse_x and not collapse_y and not dst_colors:
                        simply_process = True

            if simply_process:
                if inline:
                    url = make_data_url(mime_type, path.read())
                else:
                    url = '%s%s' % (BASE_URL, filepath)
                    if cache_buster:
                        filetime = getmtime(asset_path)
                        url = add_cache_buster(url, filetime)
            else:
                width, height = collapse_x or image.size[0], collapse_y or image.size[1]
                new_image = Image.new(
                    mode='RGBA',
                    size=(width + spacing[1] + spacing[3], height + spacing[0] + spacing[2]),
                    color=(0, 0, 0, 0)
                )
                for i, dst_color in enumerate(dst_colors):
                    src_color = src_colors[i]
                    pixdata = image.load()
                    for _y in xrange(image.size[1]):
                        for _x in xrange(image.size[0]):
                            pixel = pixdata[_x, _y]
                            if pixel[:3] == src_color:
                                pixdata[_x, _y] = tuple([int(c) for c in dst_color] + [pixel[3] if len(pixel) == 4 else 255])
                iwidth, iheight = image.size
                if iwidth != width or iheight != height:
                    cy = 0
                    while cy < iheight:
                        cx = 0
                        while cx < iwidth:
                            cropped_image = image.crop((cx, cy, cx + width, cy + height))
                            new_image.paste(cropped_image, (int(spacing[3]), int(spacing[0])), cropped_image)
                            cx += width
                        cy += height
                else:
                    new_image.paste(image, (int(spacing[3]), int(spacing[0])))

                if not inline:
                    try:
                        new_image.save(asset_path)
                        filepath = asset_file
                        BASE_URL = config.ASSETS_URL
                        if cache_buster:
                            filetime = getmtime(asset_path)
                    except IOError:
                        log.exception("Error while saving image")
                        inline = True  # Retry inline version
                    url = os.path.join(config.ASSETS_URL.rstrip(os.sep), asset_file.lstrip(os.sep))
                    if cache_buster:
                        url = add_cache_buster(url, filetime)
                if inline:
                    output = six.BytesIO()
                    new_image.save(output, format='PNG')
                    contents = output.getvalue()
                    output.close()
                    url = make_data_url(mime_type, contents)
    else:
        url = os.path.join(BASE_URL.rstrip('/'), filepath.lstrip('\\/'))
        if cache_buster and filetime != 'NA':
            url = add_cache_buster(url, filetime)

    if not os.sep == '/':
        url = url.replace(os.sep, '/')

    if only_path:
        return String.unquoted(url)
    else:
        return Url.unquoted(url)
コード例 #55
0
ファイル: gradients.py プロジェクト: 4teamwork/pyScss
def radial_gradient(*args):
    args = List.from_maybe_starargs(args)

    try:
        # Do a rough check for standard syntax first -- `shape at position`
        at_position = list(args[0]).index(String('at'))
    except (IndexError, ValueError):
        shape_and_size = _get_gradient_shape_and_size(args)
        position_and_angle = _get_gradient_position_and_angle(args)
    else:
        shape_and_size = List.maybe_new(args[0][:at_position])
        position_and_angle = List.maybe_new(args[0][at_position + 1:])

    color_stops = _get_gradient_color_stops(args)
    if color_stops is None:
        raise Exception('No color stops provided to radial-gradient function')
    color_stops = __color_stops(False, *color_stops)

    if position_and_angle:
        rendered_position = position(position_and_angle)
    else:
        rendered_position = None
    rendered_color_stops = _render_standard_color_stops(color_stops)

    args = []
    if shape_and_size and rendered_position:
        args.append(List([shape_and_size, String.unquoted('at'), rendered_position], use_comma=False))
    elif rendered_position:
        args.append(rendered_position)
    elif shape_and_size:
        args.append(shape_and_size)
    args.extend(rendered_color_stops)

    legacy_args = []
    if rendered_position:
        legacy_args.append(rendered_position)
    if shape_and_size:
        legacy_args.append(shape_and_size)
    legacy_args.extend(rendered_color_stops)

    ret = String.unquoted(
        'radial-gradient(' + ', '.join(a.render() for a in args) + ')')

    legacy_ret = 'radial-gradient(' + ', '.join(a.render() for a in legacy_args) + ')'

    def to__css2():
        return String.unquoted('')
    ret.to__css2 = to__css2

    def to__moz():
        return String.unquoted('-moz-' + legacy_ret)
    ret.to__moz = to__moz

    def to__pie():
        log.warn("PIE does not support radial-gradient.")
        return String.unquoted('-pie-radial-gradient(unsupported)')
    ret.to__pie = to__pie

    def to__webkit():
        return String.unquoted('-webkit-' + legacy_ret)
    ret.to__webkit = to__webkit

    def to__owg():
        args = [
            'radial',
            grad_point(*position_and_angle) if position_and_angle is not None else 'center',
            '0',
            grad_point(*position_and_angle) if position_and_angle is not None else 'center',
            __grad_end_position(True, color_stops),
        ]
        args.extend('color-stop(%s, %s)' % (s.render(), c.render()) for s, c in color_stops)
        ret = '-webkit-gradient(' + ', '.join(to_str(a) for a in args or [] if a is not None) + ')'
        return String.unquoted(ret)
    ret.to__owg = to__owg

    def to__svg():
        return radial_svg_gradient(*(list(color_stops) + list(position_and_angle or [String('center')])))
    ret.to__svg = to__svg

    return ret
コード例 #56
0
ファイル: images.py プロジェクト: magical/pyScss
def _image_url(path, only_path=False, cache_buster=True, dst_color=None, src_color=None, inline=False, mime_type=None, spacing=None, collapse_x=None, collapse_y=None):
    """
    src_color - a list of or a single color to be replaced by each corresponding dst_color colors
    spacing - spaces to be added to the image
    collapse_x, collapse_y - collapsable (layered) image of the given size (x, y)
    """
    if inline or dst_color or spacing:
        if not Image:
            raise Exception("Images manipulation require PIL")
    filepath = StringValue(path).value
    mime_type = inline and (StringValue(mime_type).value or mimetypes.guess_type(filepath)[0])
    path = None
    if callable(config.STATIC_ROOT):
        try:
            _file, _storage = list(config.STATIC_ROOT(filepath))[0]
            d_obj = _storage.modified_time(_file)
            filetime = int(time.mktime(d_obj.timetuple()))
            if inline or dst_color or spacing:
                path = _storage.open(_file)
        except:
            filetime = 'NA'
    else:
        _path = os.path.join(config.STATIC_ROOT, filepath.strip('/'))
        if os.path.exists(_path):
            filetime = int(os.path.getmtime(_path))
            if inline or dst_color or spacing:
                path = open(_path, 'rb')
        else:
            filetime = 'NA'
    BASE_URL = config.STATIC_URL
    if path:
        dst_colors = [list(ColorValue(v).value[:3]) for v in List.from_maybe(dst_color) if v]

        src_colors = src_color
        src_colors = [tuple(ColorValue(v).value[:3]) if v else (0, 0, 0) for v in List.from_maybe(src_color)]

        len_colors = max(len(dst_colors), len(src_colors))
        dst_colors = (dst_colors * len_colors)[:len_colors]
        src_colors = (src_colors * len_colors)[:len_colors]

        spacing = [int(NumberValue(v).value) if v else 0 for v in List.from_maybe(spacing)]
        spacing = (spacing * 4)[:4]

        file_name, file_ext = os.path.splitext(os.path.normpath(filepath).replace('\\', '_').replace('/', '_'))
        key = (filetime, src_color, dst_color, spacing)
        key = file_name + '-' + base64.urlsafe_b64encode(hashlib.md5(repr(key)).digest()).rstrip('=').replace('-', '_')
        asset_file = key + file_ext
        ASSETS_ROOT = config.ASSETS_ROOT or os.path.join(config.STATIC_ROOT, 'assets')
        asset_path = os.path.join(ASSETS_ROOT, asset_file)

        if os.path.exists(asset_path):
            filepath = asset_file
            BASE_URL = config.ASSETS_URL
            if inline:
                path = open(asset_path, 'rb')
                url = 'data:' + mime_type + ';base64,' + base64.b64encode(path.read())
            else:
                url = '%s%s' % (BASE_URL, filepath)
                if cache_buster:
                    filetime = int(os.path.getmtime(asset_path))
                    url = add_cache_buster(url, filetime)
        else:
            image = Image.open(path)
            width, height = collapse_x or image.size[0], collapse_y or image.size[1]
            new_image = Image.new(
                mode='RGBA',
                size=(width + spacing[1] + spacing[3], height + spacing[0] + spacing[2]),
                color=(0, 0, 0, 0)
            )
            for i, dst_color in enumerate(dst_colors):
                src_color = src_colors[i]
                pixdata = image.load()
                for _y in xrange(image.size[1]):
                    for _x in xrange(image.size[0]):
                        pixel = pixdata[_x, _y]
                        if pixel[:3] == src_color:
                            pixdata[_x, _y] = tuple([int(c) for c in dst_color] + [pixel[3] if len(pixel) == 4 else 255])
            iwidth, iheight = image.size
            if iwidth != width or iheight != height:
                cy = 0
                while cy < iheight:
                    cx = 0
                    while cx < iwidth:
                        cropped_image = image.crop((cx, cy, cx + width, cy + height))
                        new_image.paste(cropped_image, (int(spacing[3]), int(spacing[0])), cropped_image)
                        cx += width
                    cy += height
            else:
                new_image.paste(image, (int(spacing[3]), int(spacing[0])))

            if not inline:
                try:
                    new_image.save(asset_path)
                    filepath = asset_file
                    BASE_URL = config.ASSETS_URL
                    if cache_buster:
                        filetime = int(os.path.getmtime(asset_path))
                except IOError:
                    log.exception("Error while saving image")
                    inline = True  # Retry inline version
                url = '%s%s' % (config.ASSETS_URL, asset_file)
                if cache_buster:
                    url = add_cache_buster(url, filetime)
            if inline:
                output = six.BytesIO()
                new_image.save(output, format='PNG')
                contents = output.getvalue()
                output.close()
                url = 'data:' + mime_type + ';base64,' + base64.b64encode(contents)
    else:
        url = '%s%s' % (BASE_URL, filepath)
        if cache_buster:
            url = add_cache_buster(url, filetime)

    if not only_path:
        url = 'url("%s")' % escape(url)
    return StringValue(url)
コード例 #57
0
ファイル: sprites.py プロジェクト: magical/pyScss
def sprite_map(g, **kwargs):
    """
    Generates a sprite map from the files matching the glob pattern.
    Uses the keyword-style arguments passed in to control the placement.

    $direction - Sprite map layout. Can be `vertical` (default), `horizontal`, `diagonal` or `smart`.

    $position - For `horizontal` and `vertical` directions, the position of the sprite. (defaults to `0`)
    $<sprite>-position - Position of a given sprite.

    $padding, $spacing - Adds paddings to sprites (top, right, bottom, left). (defaults to `0, 0, 0, 0`)
    $<sprite>-padding, $<sprite>-spacing - Padding for a given sprite.

    $dst-color - Together with `$src-color`, forms a map of source colors to be converted to destiny colors (same index of `$src-color` changed to `$dst-color`).
    $<sprite>-dst-color - Destiny colors for a given sprite. (defaults to `$dst-color`)

    $src-color - Selects source colors to be converted to the corresponding destiny colors. (defaults to `black`)
    $<sprite>-dst-color - Source colors for a given sprite. (defaults to `$src-color`)

    $collapse - Collapses every image in the sprite map to a fixed size (`x` and `y`).
    $collapse-x  - Collapses a size for `x`.
    $collapse-y  - Collapses a size for `y`.
    """
    if not Image:
        raise Exception("Images manipulation require PIL")

    now_time = time.time()

    g = StringValue(g).value

    if g in sprite_maps:
        sprite_maps[glob]['*'] = now_time
    elif '..' not in g:  # Protect against going to prohibited places...
        if callable(config.STATIC_ROOT):
            glob_path = g
            rfiles = files = sorted(config.STATIC_ROOT(g))
        else:
            glob_path = os.path.join(config.STATIC_ROOT, g)
            files = glob.glob(glob_path)
            files = sorted((f, None) for f in files)
            rfiles = [(rf[len(config.STATIC_ROOT):], s) for rf, s in files]

        if not files:
            log.error("Nothing found at '%s'", glob_path)
            return StringValue(None)

        map_name = os.path.normpath(os.path.dirname(g)).replace('\\', '_').replace('/', '_')
        key = list(zip(*files)[0]) + [repr(kwargs), config.ASSETS_URL]
        key = map_name + '-' + base64.urlsafe_b64encode(hashlib.md5(repr(key)).digest()).rstrip('=').replace('-', '_')
        asset_file = key + '.png'
        ASSETS_ROOT = config.ASSETS_ROOT or os.path.join(config.STATIC_ROOT, 'assets')
        asset_path = os.path.join(ASSETS_ROOT, asset_file)
        cache_path = os.path.join(config.CACHE_ROOT or ASSETS_ROOT, asset_file + '.cache')

        sprite_map = None
        if os.path.exists(asset_path):
            try:
                save_time, asset, sprite_map, sizes = pickle.load(open(cache_path))
                sprite_maps[asset] = sprite_map
            except:
                pass

            if sprite_map:
                for file_, storage in files:
                    if storage is not None:
                        d_obj = storage.modified_time(file_)
                        _time = time.mktime(d_obj.timetuple())
                    else:
                        _time = os.path.getmtime(file_)
                    if save_time < _time:
                        if _time > now_time:
                            log.warning("File '%s' has a date in the future (cache ignored)" % file_)
                        sprite_map = None  # Invalidate cached sprite map
                        break

        if sprite_map is None:
            direction = StringValue(kwargs.get('direction', config.SPRTE_MAP_DIRECTION)).value
            repeat = StringValue(kwargs.get('repeat', 'no-repeat')).value
            collapse = kwargs.get('collapse') or 0
            if isinstance(collapse, List):
                collapse_x = int(NumberValue(collapse[0]).value)
                collapse_y = int(NumberValue(collapse[-1]).value)
            else:
                collapse_x = collapse_y = int(NumberValue(collapse).value)
            if 'collapse_x' in kwargs:
                collapse_x = int(NumberValue(kwargs['collapse_x']).value)
            if 'collapse_y' in kwargs:
                collapse_y = int(NumberValue(kwargs['collapse_y']).value)

            position = kwargs.get('position', 0)
            position = NumberValue(position)
            if position.unit != '%' and position.value > 1:
                position = position.value / 100.0
            else:
                position = position.value
            if position < 0:
                position = 0.0
            elif position > 1:
                position = 1.0

            padding = kwargs.get('padding', kwargs.get('spacing', 0))
            padding = [int(NumberValue(v).value) for v in List.from_maybe(padding)]
            padding = (padding * 4)[:4]

            dst_colors = kwargs.get('dst_color')
            dst_colors = [list(ColorValue(v).value[:3]) for v in List.from_maybe(dst_colors) if v]
            src_colors = kwargs.get('src_color')
            src_colors = [tuple(ColorValue(v).value[:3]) if v else (0, 0, 0) for v in List.from_maybe(src_colors)]
            len_colors = max(len(dst_colors), len(src_colors))
            dst_colors = (dst_colors * len_colors)[:len_colors]
            src_colors = (src_colors * len_colors)[:len_colors]

            def images(f=lambda x: x):
                for file_, storage in f(files):
                    if storage is not None:
                        _file = storage.open(file_)
                    else:
                        _file = file_
                    _image = Image.open(_file)
                    yield _image

            names = tuple(os.path.splitext(os.path.basename(file_))[0] for file_, storage in files)

            has_dst_colors = False
            all_dst_colors = []
            all_src_colors = []
            all_positions = []
            all_paddings = []

            for name in names:
                name = name.replace('-', '_')

                _position = kwargs.get(name + '_position')
                if _position is None:
                    _position = position
                else:
                    _position = NumberValue(_position)
                    if _position.unit != '%' and _position.value > 1:
                        _position = _position.value / 100.0
                    else:
                        _position = _position.value
                    if _position < 0:
                        _position = 0.0
                    elif _position > 1:
                        _position = 1.0
                all_positions.append(_position)

                _padding = kwargs.get(name + '_padding', kwargs.get(name + '_spacing'))
                if _padding is None:
                    _padding = padding
                else:
                    _padding = [int(NumberValue(v).value) for v in List.from_maybe(_padding)]
                    _padding = (_padding * 4)[:4]
                all_paddings.append(_padding)

                _dst_colors = kwargs.get(name + '_dst_color')
                if _dst_colors is None:
                    _dst_colors = dst_colors
                    if dst_colors:
                        has_dst_colors = True
                else:
                    has_dst_colors = True
                    _dst_colors = [list(ColorValue(v).value[:3]) for v in List.from_maybe(_dst_colors) if v]
                _src_colors = kwargs.get(name + '_src_color')
                if _src_colors is None:
                    _src_colors = src_colors
                else:
                    _src_colors = [tuple(ColorValue(v).value[:3]) if v else (0, 0, 0) for v in List.from_maybe(_src_colors)]
                _len_colors = max(len(_dst_colors), len(_src_colors))
                _dst_colors = (_dst_colors * _len_colors)[:_len_colors]
                _src_colors = (_src_colors * _len_colors)[:_len_colors]
                all_dst_colors.append(_dst_colors)
                all_src_colors.append(_src_colors)

            sizes = tuple((collapse_x or i.size[0], collapse_y or i.size[1]) for i in images())

            if direction == 'horizontal':
                layout = HorizontalSpritesLayout(sizes, all_paddings, position=all_positions)
            elif direction == 'vertical':
                layout = VerticalSpritesLayout(sizes, all_paddings, position=all_positions)
            elif direction == 'diagonal':
                layout = DiagonalSpritesLayout(sizes, all_paddings)
            elif direction == 'smart':
                layout = PackedSpritesLayout(sizes, all_paddings)
            else:
                raise Exception("Invalid direction %r" % (direction,))
            layout_positions = list(layout)

            new_image = Image.new(
                mode='RGBA',
                size=(layout.width, layout.height),
                color=(0, 0, 0, 0)
            )

            useless_dst_color = has_dst_colors

            offsets_x = []
            offsets_y = []
            for i, image in enumerate(images()):
                x, y, width, height, cssx, cssy, cssw, cssh = layout_positions[i]
                iwidth, iheight = image.size

                if has_dst_colors:
                    pixdata = image.load()
                    for _y in xrange(iheight):
                        for _x in xrange(iwidth):
                            pixel = pixdata[_x, _y]
                            a = pixel[3] if len(pixel) == 4 else 255
                            if a:
                                rgb = pixel[:3]
                                for j, dst_color in enumerate(all_dst_colors[i]):
                                    if rgb == all_src_colors[i][j]:
                                        new_color = tuple([int(c) for c in dst_color] + [a])
                                        if pixel != new_color:
                                            pixdata[_x, _y] = new_color
                                            useless_dst_color = False
                                        break

                if iwidth != width or iheight != height:
                    cy = 0
                    while cy < iheight:
                        cx = 0
                        while cx < iwidth:
                            new_image = alpha_composite(new_image, image, (x, y), (cx, cy, cx + width, cy + height))
                            cx += width
                        cy += height
                else:
                    new_image.paste(image, (x, y))
                offsets_x.append(cssx)
                offsets_y.append(cssy)

            if useless_dst_color:
                log.warning("Useless use of $dst-color in sprite map for files at '%s' (never used for)" % glob_path)

            try:
                new_image.save(asset_path)
            except IOError:
                log.exception("Error while saving image")

            filetime = int(now_time)
            url = '%s%s?_=%s' % (config.ASSETS_URL, asset_file, filetime)
            asset = 'url("%s") %s' % (escape(url), repeat)

            # Add the new object:
            sprite_map = dict(zip(names, zip(sizes, rfiles, offsets_x, offsets_y)))
            sprite_map['*'] = now_time
            sprite_map['*f*'] = asset_file
            sprite_map['*k*'] = key
            sprite_map['*n*'] = map_name
            sprite_map['*t*'] = filetime

            cache_tmp = tempfile.NamedTemporaryFile(delete=False, dir=ASSETS_ROOT)
            pickle.dump((now_time, asset, sprite_map, zip(files, sizes)), cache_tmp)
            cache_tmp.close()
            os.rename(cache_tmp.name, cache_path)

            # Use the sorted list to remove older elements (keep only 500 objects):
            if len(sprite_maps) > MAX_SPRITE_MAPS:
                for a in sorted(sprite_maps, key=lambda a: sprite_maps[a]['*'], reverse=True)[KEEP_SPRITE_MAPS:]:
                    del sprite_maps[a]
                log.warning("Exceeded maximum number of sprite maps (%s)" % MAX_SPRITE_MAPS)
            sprite_maps[asset] = sprite_map
        for file_, size in sizes:
            _image_size_cache[file_] = size
    ret = StringValue(asset)
    return ret
コード例 #58
0
ファイル: helpers.py プロジェクト: Foued123/qooxdoo
def dash_compass_list(*args):
    return List.from_maybe_starargs(args)