使用wkhtmltoimage实现生成长图分享

需求

用户可以选择以长图的形式分享本网页

方法

  • wkhtmltopdf
    • wkhtmltopdf url file
    • wkhtmltoimage url file
  • java
    • Runtime.getRuntime().exec()

下载

直接去官网下载对应的版本:官网

命令行使用WK

>  wkhtmltopdf https://www.nowcoder.com /opt/project/java/mycommunity-pdfs/1.pdf            
Loading pages (1/6)
Counting pages (2/6)
Resolving links (4/6)
Loading headers and footers (5/6)
Printing pages (6/6)
Done

>  wkhtmltoimage  https://www.nowcoder.com /opt/project/java/mycommunity-images/1.png     
Loading page (1/2)
Rendering (2/2)
Done

// 上面那条命令生成的长图太大了,可以使用下面这条:以75%的质量输出
>  wkhtmltoimage --quality 75  https://www.nowcoder.com /opt/project/java/mycommunity-images/1.png     
Loading page (1/2)
Rendering (2/2)
Done

在java中调用

application.properties:

mycommunity.path.domain=http://localhost:8080
server.servlet.context-path=/myCommunity
# WK
wk.image.command=/usr/local/bin/wkhtmltoimage
wk.image.storage=/opt/project/java/mycommunity-images/

WK配置类,在每次程序开始运行时自动生成存放图像的文件夹

@Configuration
public class WkConfig {

    private static final Logger logger = LoggerFactory.getLogger(WkConfig.class);

    @Value("${wk.image.storage}")
    private String wkImageStorage;

    @PostConstruct
    public void init(){
        // create the dic about WKimage
        File file = new File(wkImageStorage);
        if(!file.exists()){
            file.mkdir();
            logger.info("create the dictionary of WKimage: " + wkImageStorage);
        }
    }
}

调用WK的控制层,因为生成长图比较耗时,所以使用异步操作,在用户操作时调用Kafka的生产者生成事件,通知消费者:

@Controller
public class ShareController implements CommunityConstant {

    private static final Logger logger = LoggerFactory.getLogger(ShareController.class);

    @Autowired
    private EventProducer eventProducer;

    @Value("${mycommunity.path.domain}")
    private String domain;

    @Value("${server.servlet.context-path}")
    private String contextPath;

    @Value("${wk.image.storage}")
    private String wkImageStorage;

    @GetMapping(path = "/share")
    @ResponseBody
    public String share(String htmlUrl){
        // generate the file name
        String fileName = CommunityUtil.generateUUID();

        // Asynchronous generation long pic
        Event event = new Event()
                .setTopic(TOPIC_SHARE)
                .setData("htmlUrl", htmlUrl)
                .setData("fileName", fileName)
                .setData("suffix", ".png");
        eventProducer.fireEvent(event);

        Map<String, Object> map = new HashMap<>();
        map.put("shareUrl", domain + contextPath + "/share/image" + fileName);

        return CommunityUtil.getJSONString(0, null, map);
    }

    //
    @GetMapping(path = "/share/image/{fileName}")
    public void getShareImage(@PathVariable("fileName") String fileName, HttpServletResponse response){
        if(StringUtils.isBlank(fileName)){
            throw new IllegalStateException("the file name cannot be blank");
        }

        response.setContentType("image/png");
        File file = new File(wkImageStorage + "/" + fileName + ".png");
        try {
            OutputStream os = response.getOutputStream();
            FileInputStream fis = new FileInputStream(file);
            byte[] data = new byte[1024];
            int len = 0;
            while ((len = fis.read(data)) != -1) {
                os.write(data, 0, len);
            }
        } catch (IOException e) {
            logger.error("querty the long image failed: ", e.getMessage());
        }
    }
}

Kafka的消费者,定义如何消费生成长图的事件:

@Component
public class EventConsumer implements CommunityConstant {

    @Autowired
    private static final Logger logger = LoggerFactory.getLogger(EventConsumer.class);

    @Value("${wk.image.storage}")
    private String wkImageStorage;

    @Value("${wk.image.command}")
    private String wkImageCommand;

    @KafkaListener(topics = {TOPIC_SHARE})
    public void handleShareMessage(ConsumerRecord record) {
        if (record == null || record.value() == null) {
            logger.error("the content of the message is empty");
            return;
        }

        Event event = JSONObject.parseObject(record.value().toString(), Event.class);
        if (event == null) {
            logger.error("message format error");
            return;
        }

        String htmlUrl = (String) event.getData().get("htmlUrl");
        String fileName = (String) event.getData().get("fileName");
        String suffix = (String) event.getData().get("suffix");

        String cmd = wkImageCommand + " --quality 75 " + htmlUrl + " " + wkImageStorage + "/" + fileName + suffix;
        try {
            Runtime.getRuntime().exec(cmd);
            logger.info("generate long image successfully: " + cmd);
        } catch (IOException e) {
            logger.info("generate long image fail: " + e.getMessage());
        }
    }
}

测试

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值