1

我正在使用 PotraceJ(potrace库的 java 版本) - 请注意,potrace 用于图像的矢量化。

情况 - potrace 跟踪图像,并将结果存储在 BufferedImage 中,然后将其作为 ImageIcon 显示在 JPanel 中。

我的问题 - 我想将这个 BufferedImage 保存为一个文件,比如 vector.svg 使用 ImageIO.write() 我试过了,但是当我这样做时没有创建文件。可能的原因可能是 Java 的图像编写者可能不会写 svg

我必须将此矢量化图像存储为 svg 文件。我该怎么做?

这里嵌入了主要对光栅图像进行矢量化的代码。虽然您可以在github上找到整个库。

            package potracej.src;

            import potracej.src.compat.ConvertToJavaCurves;
            import potracej.src.compat.PathElement;
            import potracej.src.potracej.Bitmap;
            import potracej.src.potracej.PoTraceJ;
            import potracej.src.potracej.param_t;
            import potracej.src.potracej.path_t;

            import javax.imageio.ImageIO;
            import javax.swing.*;
            import javax.swing.event.ChangeEvent;
            import javax.swing.event.ChangeListener;
            import javax.swing.plaf.metal.MetalButtonUI;
            import java.awt.*;
            import java.awt.event.ActionEvent;
            import java.awt.event.ActionListener;
            import java.awt.geom.GeneralPath;
            import java.awt.image.BufferedImage;
            import java.awt.image.WritableRaster;
            import java.io.File;
            import java.io.IOException;
            import java.nio.file.Path;
            import java.nio.file.Paths;
            import java.util.ArrayList;
            import java.util.HashSet;

            /**
             * Created with IntelliJ IDEA.
             * User: san
             * Date: 6/10/12
             * Time: 12:55 PM
             * To change this template use File | Settings | File Templates.
             */
            public class Main {

                static BufferedImage result;
                static Bitmap bmp;
                static param_t param = new param_t();
                static double scale = 1;
                static ImageIcon resultIcon;
                static ImageIcon srcIcon;
                static BufferedImage sourceImage;
                static boolean renderSourceImage = false;

                public static void main(String[] args) throws IOException {
                    Path p = Paths.get(new File(".").getCanonicalPath()+"/potracej/girl.png");
                    sourceImage = ImageIO.read(p.toFile());

                    //Toolkit.getDefaultToolkit().
                    WritableRaster raster = sourceImage.getRaster();
                    int[] iarr = new int[4];
                    bmp = new Bitmap((int)(sourceImage.getWidth()), (int)(sourceImage.getHeight()));
                    for(int y=0; y<sourceImage.getHeight(); y++) {
                        for(int x=0; x<sourceImage.getWidth(); x++) {
                            int[] pixel = raster.getPixel(x, y, iarr);
                            if (pixel[0] + pixel[1] + pixel[2] + pixel[3] != 0) {
                                bmp.put(x, y, 1);
                            }
                        }
                    }

                    BufferedImage d2 = new BufferedImage((int) (scale * sourceImage.getWidth()), (int)(scale * sourceImage.getHeight()), BufferedImage.TYPE_INT_ARGB);
                    Graphics2D d2g = (Graphics2D) d2.getGraphics();
                    d2g.scale(scale, scale);
                    d2g.drawImage(sourceImage, 0, 0, null);
                    d2g.dispose();
                    sourceImage.flush();
                    srcIcon = new ImageIcon(d2);

                    doTrace(scale);

                    JFrame frame = new JFrame("Result") {
                        {
                            setLayout(new BorderLayout());
                            resultIcon = new ImageIcon(result, "Result");
                            JButton resultButton = new JButton(resultIcon);
                            resultButton.setUI(new MetalButtonUI() {
                                @Override
                                protected void paintButtonPressed(Graphics g, AbstractButton b) {
                                    //
                                }
                            });
                            add(resultButton, BorderLayout.CENTER);
                            resultButton.setPressedIcon(srcIcon);
                            JPanel stuff = new JPanel();
                            add(stuff, BorderLayout.NORTH);
                            stuff.setLayout(new GridLayout(4, 2));
                            stuff.add(new JLabel("Suppress speckles"));
                            final JSlider turdSlider = new JSlider(JSlider.HORIZONTAL, 0, 100, param.turdsize);
                            stuff.add(turdSlider);
                            turdSlider.addChangeListener(new ChangeListener() {
                                @Override
                                public void stateChanged(ChangeEvent e) {
                                    param.turdsize = turdSlider.getValue();
                                    doRetrace();
                                }
                            });
                            stuff.add(new JLabel("Smooth corners"));
                            final JSlider smoothSlider = new JSlider(JSlider.HORIZONTAL, 0, 300, (int) (param.opttolerance * 100));
                            stuff.add(smoothSlider);
                            smoothSlider.addChangeListener(new ChangeListener() {
                                @Override
                                public void stateChanged(ChangeEvent e) {
                                    param.opttolerance = smoothSlider.getValue() / 100.0;
                                    doRetrace();
                                }
                            });
                            stuff.add(new JLabel("Optimize paths"));
                            final JSlider optSlider = new JSlider(JSlider.HORIZONTAL, 0, 125, (int) (param.alphamax * 100));
                            stuff.add(optSlider);
                            optSlider.addChangeListener(new ChangeListener() {
                                @Override
                                public void stateChanged(ChangeEvent e) {
                                    param.alphamax = optSlider.getValue()/100.0;
                                    doRetrace();
                                }
                            });
                            final JCheckBox renderSource = new JCheckBox("Render source");
                            stuff.add(renderSource);
                            renderSource.addActionListener(new ActionListener() {
                                @Override
                                public void actionPerformed(ActionEvent e) {
                                    renderSourceImage = renderSource.getModel().isArmed();
                                    doRetrace();
                                }
                            });

                        }

                        private void doRetrace() {
                            doTrace(scale);

                            resultIcon.setImage(result);
                            repaint();
                        }
                    };
                    frame.pack();
                    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
                    frame.setVisible(true);

                }

                private static void doTrace(double scale) {
                    PoTraceJ poTraceJ = new PoTraceJ(param);
                    long l = System.currentTimeMillis();

                    path_t trace = null;
                    for(int i=0; i<10; i++) {
                        trace = poTraceJ.trace(bmp);
                        Thread.yield();
                    }
                    poTraceJ.resetTimers();
                    for(int i=0; i<100; i++) {
                        trace = poTraceJ.trace(bmp);
                    }
                    poTraceJ.printTimers();
                    l = System.currentTimeMillis() - l;
                    System.out.println("L="+l);
                    ArrayList<PathElement> al = new ArrayList<PathElement>();
                    ConvertToJavaCurves.convert(trace, new HashSet<ConvertToJavaCurves.Point>(), al);

                    if (result != null)
                        result.flush();
                    result = new BufferedImage((int)(scale * bmp.getWidth()), (int)(scale * bmp.getHeight()), BufferedImage.TYPE_INT_ARGB);


                    Graphics2D g2 = (Graphics2D)result.getGraphics();
                    g2.scale(scale, scale);
                    g2.setColor(Color.WHITE);
                    g2.fillRect(0, 0, bmp.getWidth(), bmp.getHeight());
                    g2.setColor(Color.BLACK);
                    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                    g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
                    g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                    GeneralPath path = new GeneralPath();
                    for (PathElement pathElement : al) {
                        switch (pathElement.getType()) {
                            case CLOSE_PATH:
                                path.closePath();
                                break;
                            case LINE_TO:
                                path.lineTo(pathElement.getP0x(), pathElement.getP0y());
                                break;
                            case MOVE_TO:
                                path.moveTo(pathElement.getP0x(), pathElement.getP0y());
                                break;
                            case CURVE_TO:
                                path.curveTo(pathElement.getP0x(), pathElement.getP0y(), pathElement.getP1x(), pathElement.getP1y(), pathElement.getP2x(), pathElement.getP2y());
                                break;
                        }
                    }
                    g2.setPaint(Color.black);
                    g2.fill(path);
                }

            }

提前致谢。

4

2 回答 2

1

我们可以转换这个对象:

GeneralPath path = new GeneralPath();

使用Apache BatikSVGPath

  1. 将依赖项添加到pom.xml
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-svggen</artifactId>
    <version>1.9</version>
</dependency>

<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-anim</artifactId>
    <version>1.9</version>
</dependency>
  1. 创建方法:
private static SVGOMDocument createSvgDocument(int width, int height) {
    DOMImplementation domImpl = SVGDOMImplementation.getDOMImplementation();
    SVGOMDocument document = (SVGOMDocument) domImpl.createDocument(SVGDOMImplementation.SVG_NAMESPACE_URI, "svg", null);
    Element svgTag = document.getRootElement();
    svgTag.setAttribute("width", String.valueOf(width));
    svgTag.setAttribute("height", String.valueOf(height));
    return document;
}

private static void putPathToSvgDocument(SVGOMDocument document, GeneralPath path) {
    SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(document);
    SVGPath svgPath = new SVGPath(ctx);
    Element svgElement = svgPath.toSVG(path);
    svgElement.setAttribute("fill", "#000");
    document.getRootElement().appendChild(svgElement);
}

private static void saveSvgDocumentToFile(SVGOMDocument document, File file) throws FileNotFoundException, IOException {
    SVGGraphics2D svgGenerator = new SVGGraphics2D(document);
    try (Writer out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) {
        svgGenerator.stream(document.getDocumentElement(), out);
    }
}
  1. 马上就好了。现在我们可以在里面创建带有 GeneralPath 的 SVG 文件
GeneralPath path = new GeneralPath();
...
// TODO: set your image width and height ;)
SVGOMDocument document = createSvgDocument(1000,1000);
putPathToSvgDocument(document, path);

// TODO: set your filename :)
saveSvgDocumentToFile(document, new File("c:\\temp\\result.svg"));

完毕!

于 2019-06-04T12:14:17.540 回答
0

任何期待这个问题的答案的人可能都是像我这样的人。新手进入图像处理并寻找可以解渴的图书馆。我还没有找到解决这个问题的方法,我不能错误地指导你还有什么可以做的。

我观察到大多数图像处理库都是用C++ 编写的。Java 中的库较少。为什么?性能。因此,对于任何想要生成高效代码并赞赏所有算法输入的人来说,也应该使用 C++。

我想为我的 Android 应用程序提供上述解决方案。我打算用 C++ 编写代码并通过 Android NDK 连接它。

对于所有其他迷失的灵魂,勇敢地做出这个决定。是我的证据来证明这一点。

于 2017-02-20T12:52:08.503 回答