activity5替换默认网关图片

1.SVG格式

SVG是一种图形文件格式,它的英文全称为Scalable Vector Graphics,意思为可缩放的矢量图形。它是基于XML(Extensible Markup Language),由World Wide Web Consortium(W3C)联盟进行开发的。严格来说应该是一种开放标准的矢量图形语言,可让你设计激动人心的、高分辨率的Web图形页面。用户可以直接用代码来描绘图像,可以用任何文字处理工具打开SVG图像,通过改变部分代码来使图像具有交互功能,并可以随时插入到HTML中通过浏览器来观看。
来源:百度百科-SVG格式

2.前端画流程图替换svg格式

2.1.替换接口/modeler/editor/stencilset中的view

为设计的新的svg图片即可,但是前端渲染的时候有一个问题,前端的框架默认svg左边开始点不是从0像素开始,顶部也不是从0像素开始,需要使用设计的原始svg进行一定的偏移和前端画流程图框架的偏移量对其,这样图片才正好在正中间

在这里插入图片描述

2.2.如下图,保存的svg需要有一定的偏移

在这里插入图片描述

2.3.替换后的接口/modeler/editor/stencilset获取的stencilsetjson数据

替换如下的view为井经过修改偏移后的svg即可,其中svg可以直接使用浏览器打开,在response中赋值复制出svg格式文件,可以使用xml格式压缩工具压缩后再替换view在这里插入图片描述

3.后端渲染实时流程图替换svg格式

通过流程instanceId获取实时流程图,后端是实时画的图,不是从stencilsetjson.json中获取view画出来的,所以需要自己定制画网关的逻辑,大概思路为:
从stencilsetjson.json获取orgView的原始svg图片>>转换为BufferedImage>>重写drawExclusiveGateway写网关逻辑>>>使用g.drawImage和orgView画替换的网关

3.1 其中需要说明,stencilsetjson.json的view和orgView的区别

看下图,orgView为左边从0像素开始,顶点从0像素开始
在这里插入图片描述

3.2 svg格式转换为BufferedImage

使用PNGTranscoder转换为BufferedImage
引入依赖

<!-- 解析SVG引入 -->
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-transcoder</artifactId>
    <version>1.7</version>
    <scope>compile</scope>
</dependency>
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;

import org.apache.batik.transcoder.image.ImageTranscoder;

import javax.imageio.ImageIO;

public class OffScreenSVGRenderer {

    /**
     * 将svgCode转换成png文件,直接输出到流中
     *
     * @param svgCode
     *            svg代码
     * @param outputStream
     *            输出流
     * @throws TranscoderException
     *             异常
     * @throws IOException
     *             io异常
     */
    public static void convertToPng(String svgCode, float width, float height, OutputStream outputStream) throws TranscoderException, IOException {
        try {
            byte[] bytes = svgCode.getBytes("utf-8");
            PNGTranscoder t = new PNGTranscoder();
            TranscoderInput input = new TranscoderInput(new ByteArrayInputStream(bytes));
            TranscoderOutput output = new TranscoderOutput(outputStream);
            // 增加图片的属性设置(单位是像素)
            t.addTranscodingHint(ImageTranscoder.KEY_WIDTH, new Float(width));
            t.addTranscodingHint(ImageTranscoder.KEY_HEIGHT, new Float(height));
            t.transcode(input, output);
            outputStream.flush();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 将svg格式图片输出为BufferedImage流
     * @param svgContent
     * @param width
     * @param height
     * @return
     */
    public static BufferedImage renderToImage(String svgContent, float width, float height) {
        try {
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            OffScreenSVGRenderer.convertToPng(svgContent, width, height, output);
            byte[] data = output.toByteArray();
            ByteArrayInputStream input = new ByteArrayInputStream(data);
            BufferedImage image = ImageIO.read(input);
            return image;
        } catch (TranscoderException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

参考:SVG2PNG(前台和后台将SVG转换为PNG)–amcharts导出png

3.3 之前使用ImageRenderer读取SVG转换为BufferedImage报错
java.io.IOException: SAX2 driver class org.apache.xerces.parsers.SAXParser not found

在pom.xml文件中加上xercesImpl的以下相关依赖并没有解决该报错,贴上方法renderToImage的代码,各位可以参考

<dependency>
    <groupId>xerces</groupId>
    <artifactId>xercesImpl</artifactId>
    <version>2.11.0</version>
</dependency>
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.UserAgentAdapter;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.gvt.renderer.ConcreteImageRendererFactory;
import org.apache.batik.gvt.renderer.ImageRenderer;
import org.apache.batik.gvt.renderer.ImageRendererFactory;
import org.w3c.dom.svg.SVGDocument;

public class OffScreenSVGRenderer {

    public static BufferedImage renderToImage(SVGDocument document, int width, int height, boolean stretch){

        ImageRendererFactory rendererFactory;
        rendererFactory = new ConcreteImageRendererFactory();
        ImageRenderer renderer = rendererFactory.createStaticImageRenderer();

        GVTBuilder builder = new GVTBuilder();
        BridgeContext ctx = new BridgeContext(new UserAgentAdapter());
        ctx.setDynamicState(BridgeContext.STATIC);
        GraphicsNode rootNode = builder.build(ctx, document);

        renderer.setTree(rootNode);

        float docWidth  = (float) ctx.getDocumentSize().getWidth();
        float docHeight = (float) ctx.getDocumentSize().getHeight();

        float xscale = width/docWidth;
        float yscale = height/docHeight;
        if(!stretch){
            float scale = Math.min(xscale, yscale);
            xscale = scale;
            yscale = scale;
        }

        AffineTransform px  = AffineTransform.getScaleInstance(xscale, yscale);

        double tx = -0 + (width/xscale - docWidth)/2;
        double ty = -0 + (height/yscale - docHeight)/2;
        px.translate(tx, ty);
        //cgn.setViewingTransform(px);

        renderer.updateOffScreen(width, height);
        renderer.setTree(rootNode);
        renderer.setTransform(px);
        //renderer.clearOffScreen();
        renderer.repaint(new Rectangle(0, 0, width, height));

        return renderer.getOffScreen();

    }
}

参考:由SVG直接绘制成BufferedImage

3.4 重写drawExclusiveGateway写网关逻辑

后端画流程图调用堆栈
其中CustomProcessDiagramGenerator和CustomProcessDiagramCanvas为自定义的重写类
其中public class CustomProcessDiagramGenerator extends DefaultProcessDiagramGenerator
其中public class CustomProcessDiagramCanvas extends DefaultProcessDiagramCanvas

java.lang.NumberFormatException: For input string: "5F"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.valueOf(Integer.java:766)
at com.demo.its.activiti.config.CustomProcessDiagramCanvas.drawExclusiveGateway(CustomProcessDiagramCanvas.java:212)
at org.activiti.image.impl.DefaultProcessDiagramGenerator$13.draw(DefaultProcessDiagramGenerator.java:255)
at com.demo.its.activiti.config.CustomProcessDiagramGenerator.drawActivity(CustomProcessDiagramGenerator.java:91)
at com.demo.its.activiti.config.CustomProcessDiagramGenerator.generateProcessDiagram(CustomProcessDiagramGenerator.java:62)
at com.demo.its.activiti.config.CustomProcessDiagramGenerator.generateDiagram(CustomProcessDiagramGenerator.java:340)
at com.demo.its.activiti.controller.ProcessController.getActivitiProccessImage(ProcessController.java:503)
at com.demo.its.activiti.controller.ProcessController.readResource(ProcessController.java:440)
at com.demo.its.activiti.controller.ProcessController$$FastClassBySpringCGLIB$$d3ae0527.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:687)
3.5 DefaultProcessDiagramGenerator为流程图生成器策略选择器

看源代码可以发现DefaultProcessDiagramGenerator为流程图生成器策略选择器,该方法定义了Activity根据何种具体实体类调用DefaultProcessDiagramCanvas的何种画的方法
在这里插入图片描述

3.5 DefaultProcessDiagramCanvas为具体的画流程图组件实现类

DefaultProcessDiagramCanvas的默认的drawExclusiveGateway方法虽然不是接口形式,但是不影响继承类CustomProcessDiagramCanvas重写该方法
在这里插入图片描述

3.6 在自定义的CustomProcessDiagramCanvas 方法中重写的drawExclusiveGateway方法
public class CustomProcessDiagramCanvas extends DefaultProcessDiagramCanvas {
    // 缓存自定义的svg图片
    private static Map<String, BufferedImage> bufferedImageMap = new HashMap<>();

    public void drawExclusiveGateway(GraphicInfo graphicInfo, double scaleFactor) {
        Polygon rhombus = new Polygon();
        int x = (int)graphicInfo.getX();
        int y = (int)graphicInfo.getY();
        int width = (int)graphicInfo.getWidth();
        int height = (int)graphicInfo.getHeight();
        rhombus.addPoint(x, y + height / 2);
        rhombus.addPoint(x + width / 2, y + height);
        rhombus.addPoint(x + width, y + height / 2);
        rhombus.addPoint(x + width / 2, y);
        String id = "ExclusiveGateway";
        BufferedImage image = null;
        if (bufferedImageMap.containsKey(id)) {
            image = bufferedImageMap.get(id);
            System.out.printf("命中网关缓存图片.");
        } else {
            JSONObject stencilsetJson = StencilsetRestResource.stencilsetJson;
            JSONArray stencils = stencilsetJson.getJSONArray("stencils");
             Map<String, JSONObject> groupStencils = stencils.stream().collect(
                    Collectors.toMap(item -> ((JSONObject) item).getString("id"), item -> ((JSONObject) item))
            );
            String xmlContent = groupStencils.get(id).getString("orgView");
            image = OffScreenSVGRenderer.renderToImage(xmlContent, width, height);
        }
        if (null == image) {
            return;
        }
        bufferedImageMap.put(id, image);
        int imageX = (int)(graphicInfo.getX() + graphicInfo.getWidth() / 2.0D - (double)(image.getWidth() / 2) * scaleFactor);
        int imageY = (int)(graphicInfo.getY() + graphicInfo.getHeight() / 2.0D - (double)(image.getHeight() / 2) * scaleFactor);
        this.g.drawImage(image, imageX, imageY, (int)((double)image.getWidth() / scaleFactor), (int)((double)image.getHeight() / scaleFactor), (ImageObserver)null);
    	}
    }
3.6 前端获取实时流程图如下在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值