锯齿形边框和填充色 [英] Zigzag border and fill color

查看:80
本文介绍了锯齿形边框和填充色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个曲折的路径,我旋转它来制作一个曲折的边框,像这样.由于使用了旋转",因此每条锯齿形线都具有不同的路径属性,因此我无法填写颜色.如何使用d3.js填充这些路径的颜色

I have a zigzag path, I rotated it to make a zigzag border like this. Because of using Rotate, each zigzag line is in a different path attribute so I can`t fill in the color. How can I fill in the color insde these pathes using d3.js

<svg height="2100" width="4000">
  <path d="M150 250 L190 260 L230 240 L270 260 L310 240 L350 260 L390 240" stroke="red" stroke-width="2" fill = "none"/>
  <path d="M150 250 L190 260 L230 240 L270 260 L310 240 L350 260 L390 240" stroke="red" stroke-width="2" fill = "none" transform="rotate(-60 150 250)"/>
  <path d="M150 250 L190 260 L230 240 L270 260 L310 240 L350 260 L390 240" stroke="red" stroke-width="2" fill = "none" transform="rotate(60 390 240)"/>

推荐答案

您在这里.

<?xml version="1.0" ?>
<svg baseProfile="full" height="558px" version="1.1" viewBox="725.88 614.7492934009083 288.24 267.65531628991823" width="600px" xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs/>
  <path d="M 750.0,850.0 L 790.0,860.0 L 830.0,840.0 L 870.0,860.0 L 910.0,840.0 L 950.0,860.0 L 990.0,840.0 M 750.0,850.0 L 778.6602540378444,820.3589838486225 L 781.3397459621556,775.717967697245 L 818.6602540378444,751.0769515458674 L 821.3397459621556,706.4359353944899 L 858.6602540378444,681.7949192431123 L 861.3397459621556,637.1539030917348 L 872.6794919243112,676.7949192431124 L 910.0,701.4359353944899 L 912.6794919243112,746.0769515458675 L 950.0,770.7179676972451 L 952.6794919243112,815.3589838486225 L 990.0,840.0000000000002" fill="#ffaec9" stroke="red" stroke-width="1"/>
</svg>

我不确定您是否要了解如何生成此图像.

I am not sure whether are you want to understand how to generate this image.

我使用Python,并尝试绘制每个路径.

I use Python, and try to draw each path.

首先,您需要找到已经进行旋转的新点.

At first, you need to find the new points that is do the rotate already.

最后,您应该移动路径.

Finally, you should shift the path.

  1. 曲线[0]不需要移动.
  2. 曲线 1 应该移至曲线[0].开始
  3. 然后,曲线[2]应该移到曲线 1 .end
  1. curve[0] doesn't need to shift.
  2. curve1 should shift to curve[0].start
  3. then, curve[2] should shift to curve1.end

代码如下. (但我删除了转换方法,因为该代码太丑陋了,但是我相信只是一个概念,您可以自己尝试一下.)

The code is as follows. (but I delete how to shift because that code is too ugly, but I believe that just a concept you can try by yourself.)

from svgpathtools import svg2paths  # you need ``pip install svgpathtools``
from svgpathtools.path import Path as CombinePath
from svgpathtools import Line, Path, wsvg
from pathlib import Path
import numpy as np
import cv2
from math import sin, cos, radians
from typing import Tuple, List

TEST_SVG = Path('test2.svg')


class COLOR:
    """
    CV2: BGR
    """
    __slots__ = ()
    BLACK = (0, 0, 0)
    AZURE = (255, 127, 0)
    WHITE = (255, 255, 255)
    BLUE = (255, 0, 0)
    GREEN = (0, 255, 0)
    RED = (0, 0, 255)
    PURPLE = (255, 0, 255)
    YELLOW = (0, 255, 255)


def scale_image(img: np.ndarray, scale_percent: int):
    width = int(img.shape[1] * scale_percent / 100)
    height = int(img.shape[0] * scale_percent / 100)
    dim = (width, height)
    return cv2.resize(img, dim, interpolation=cv2.INTER_AREA)


def show_img(show_or_not: bool, scale_percent=50):
    def wrap(function):
        def job(*arg, **options):
            np_img = function(*arg, **options)
            if show_or_not:
                cv2.namedWindow('demo', cv2.WINDOW_NORMAL)  # can resize
                cv2.imshow('demo', scale_image(np_img, scale_percent))
                cv2.waitKey(0)
            return np_img
        return job
    return wrap


def svg_translate(array: np.ndarray,
                  co, si,
                  n_si, co2,
                  x_shift, y_shift):
    matrix = np.array([[co, n_si, x_shift],
                       [si, co2, y_shift],
                       [0, 0, 1]])
    result = matrix @ array  # rotate
    return result


@show_img(show_or_not=True, scale_percent=50)
def draw_line(np_img: np.ndarray, history_list: list, line: Line,
              degree=0, x_shift=0, y_shift=0):
    degree = radians(degree)
    list_point: List[Tuple[float, float]] = []
    for point in (line.start, line.end):
        x, y = point.real, point.imag
        x, y, _ = svg_translate(np.array([[x], [y], [1]]),
                                cos(degree), sin(degree),
                                -sin(degree), cos(degree),
                                x_shift, y_shift)
        list_point.append((x, y))

    (x_start, y_start), (x_end, y_end) = pt_start, pt_end = list_point

    np_img = cv2.line(np_img, pt_start, pt_end, COLOR.BLUE, thickness=1)
    history_list.append(Line(complex(x_start, y_start), complex(x_end, y_end)))
    return np_img


def main():
    path_list, data_list = svg2paths(str(Path(TEST_SVG)))
    np_img = np.ones((2000, 2000, 3), dtype=np.uint8) * 255  # background with white color

    history_list = []
    for idx, (cur_path, dict_data) in enumerate(zip(path_list, data_list)):
        transform = dict_data.get('transform')
        degree, x_shift, y_shift = 0, 0, 0
        if transform:
            degree, x_shift, y_shift = [int(_) for _ in transform.translate(str.maketrans({'(': '', ')': ''})).replace('rotate', '').split()]

        for cur_idx, curve in enumerate(cur_path):
            np_img = draw_line(np_img, history_list, curve, degree, x_shift, y_shift) if isinstance(curve, Line) else None

    wsvg(CombinePath(*history_list), filename=f'result.svg',
         attributes=[dict(fill="#ffaec9", stroke="red", stroke_width=1)],
         openinbrowser=True  # default is False,
         )


if __name__ == '__main__':
    main()


解决方案2: Potrace

对不起,我不擅长d3.js语言.即使我现在学习d3.js,我也可能很快无法回答您...


Solution2: Potrace

Sorry, I am not good at the d3.js language. Even if I learn d3.js now, I might not be able to answer you soon...

但是我可以为您提供另一种解决方案,您可以尝试使用 potrace .

But I can provide you another solution, you can try with the potrace.

这是脚本(再次是Python,但是它只是通过该脚本运行Potrace)

here is the scrips (Python again but it just runs Potrace by this scrips)

from pathlib import Path
from subprocess import Popen
import cv2
import sys
import numpy as np
from typing import Tuple

POTRACE_EXE_PATH = Path(r'X:\...\potrace-1.16.win64\potrace.exe')  # download: http://potrace.sourceforge.net/#downloading


def scale_image(img: np.ndarray, scale_percent):
    width = int(img.shape[1] * scale_percent / 100)
    height = int(img.shape[0] * scale_percent / 100)
    dim = (width, height)
    return cv2.resize(img, dim, interpolation=cv2.INTER_AREA)


def morph_open_image(img: np.ndarray, kernel_shape: Tuple[int, int] = (5, 5)):
    """
    fill all the small hole, the result as much as possible to the same as the original image.

    .. note:: please remove the isolated noise first before you use this function.
    """
    return cv2.morphologyEx(img, cv2.MORPH_OPEN, cv2.getStructuringElement(cv2.MORPH_RECT, kernel_shape))


def init_potrace_exe(exe_path: Path, ansi_codepage='cp950'):  # decorator

    assert exe_path.exists(), f'FileNotFoundError: exe_path:{exe_path}'

    exe_path = str(exe_path.resolve())

    def run_fun(fun):
        def job(*args, **options):
            options['potrace_exe'] = exe_path
            options['ansi_codepage'] = ansi_codepage
            fun(*args, **options)
        return job
    return run_fun


def bmp2svg(bmp: Path, output_file: Path = None, **options):
    src_path = str(bmp.resolve())
    output_file = output_file.resolve() if output_file else (bmp.parent / Path(bmp.stem + '.svg')).resolve()

    cmd_process = Popen([options.get('potrace_exe', 'potrace.exe'), "-b", "svg", "--group",
                         '--flat',  # whole image as a single path
                         '--alphamax', '0',  # corner threshold parameter (default 1), if set 0, then all the curve can see as the Line
                         src_path, '-o', str(output_file)], stdout=sys.stdout, stderr=sys.stderr, stdin=sys.stdout)
    print(' '.join([arg for arg in cmd_process.args]))
    out = cmd_process.communicate()[0]
    # print(f"result msg: {out.decode(options['ansi_codepage'])}")


def img2svg(img_path: Path):
    bmp_path = img_path
    if img_path.suffix != '.bmp' and 'Potrace does not support the PNG, so we need to create the BMP first.':
        np_img = cv2.imread(str(img_path), 0)
        np_img = morph_open_image(np_img)  # fill the hole.
        np_img = cv2.threshold(np_img, 200, 255, cv2.THRESH_BINARY)[1]
        # np_img = scale_image(np_img, 5)
        output_bmp_path = Path('.')/Path(img_path.stem + '.bmp')
        cv2.imwrite(str(output_bmp_path), np_img)  # create bmp
        bmp_path = output_bmp_path
    POTRACE_EXE(bmp2svg)(bmp_path)  # bmp to svg file  # Possible input file formats are: pnm (pbm, pgm, ppm), bmp


if __name__ == '__main__':
    POTRACE_EXE = init_potrace_exe(POTRACE_EXE_PATH)
    img2svg(Path('./zigzag.png'))

zigzag.png :(使用SVG,然后打开Microsoft Paint(mspaint.exe)(或您喜欢的某些编辑器),然后填充红色.)

zigzag.png: (Use your SVG, and open the Microsoft Paint(mspaint.exe) (or some editor you like), and then fill the red color.)

我之所以为您编写此脚本,是希望它可以用于更一般的情况. 在某些情况下,该图像可能很难显示,因此您需要修改(例如方法),然后再使用Potrace生成, 这比直接生成它更好.

The reason why I write this script for you is I hope it can use for more general cases. Some cases which image may ugly such that you need to modify (such as these methods) before using the Potrace to generate, and this is better than you generate it directly.

如果您不喜欢使用Python,则可以运行以下命令.

If you don't like to use the Python, it's ok for you to run the command of the following.

"X:\...\potrace.exe" -b svg --group --flat --alphamax 0 your.bmp -o output.svg

最后,将得到以下图片

<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
 width="692.000000pt" height="649.000000pt" viewBox="0 0 692.000000 649.000000"
 preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.16, written by Peter Selinger 2001-2019
</metadata>
<g transform="translate(0.000000,649.000000) scale(0.100000,-0.100000)"

fill="#ffaec9" stroke="red" stroke-width="20">
<path d="M3150 6259 l0 -12 -35 -586 -35 -586 -4 -11 -4 -10 -505 -333 -506
-333 -5 -61 -6 -62 -30 -510 -30 -511 0 -37 0 -38 -507 -336 -508 -335 -5 -5
-4 -4 -38 -611 -37 -612 -59 -60 -59 -61 -327 -338 -326 -339 6 -26 7 -27 1 0
1 0 549 -137 549 -136 529 264 528 264 30 0 30 0 533 -266 532 -266 533 266
532 266 30 0 30 0 533 -266 532 -266 553 276 552 276 0 28 0 28 -497 329 -498
328 -4 4 -4 3 -36 603 -36 602 -7 11 -8 12 -505 332 -505 333 0 35 0 35 -36
576 -35 576 -12 7 -12 7 -499 330 -499 329 -143 499 -143 498 -11 38 -11 37
-29 0 -30 0 0 -11z"/>
</g>
</svg>

这篇关于锯齿形边框和填充色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆