PhantomJS实现网络截图和图片生成工具


上一篇做了一个PhantomJS简介,本文介绍如果通过PhantomJS生成图片,包括

  • 使用PhantomJS实现网络截图
  • 使用PhantomJS实现图片生成工具

本文默认你已经安装好了PhantomJS,不知道怎么安装的请看PhantomJS简介

使用PhantomJS实现网络截图

1、新建createImg.js

page = require('webpage').create();
//页面大写
page.viewportSize = { width: 1366, height: 768 };
//截取区域
page.clipRect = { top: 0, left: 0, width: 1366, height: 768 };
phantom.outputEncoding="utf8";
page.open("http://www.majunwei.com", function(status) {
   if ( status === "success" ) {
      page.render("majunwei.png"); 
   } else {
      console.log("Page failed to load."); 
   }
   phantom.exit(0);
});

2、执行./phantomjs createImg.js

./phantomjs createImg.js

查看当前目录就可以看到生成的majunwei.png图片了

localhost:bin majunwei$ ls

createImg.js hello.js majunwei.png phantomjs

可以看到,成功的截取了http://www.majunwei.com的上半部区域。是不是很帅。

当然你可以自己定义截取的参数(viewportSize和clipRect),来灵活截取网站的截图。

使用PhantomJS实现图片生成工具

上面介绍了生成图片等基本用法,这里发散一下,结合Java用这个功能做个图片生成工具,包含两种方式

  • 生成网络截图
  • 根据自定义的html生成截图

两种方法没太多差别,一种是在open的时候传入网址,一种是传入本地路径。open远程网址很简单,根上面一样,这里看自定义的html:

1、定义rasterize.js

var page = require('webpage').create(),
    system = require('system'),
    address, output, size;

if (system.args.length < 3 || system.args.length > 5) {
    console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat] [zoom]');
    console.log('  paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"');
    console.log('  image (png/jpg output) examples: "1920px" entire page, window width 1920px');
    console.log('                                   "800px*600px" window, clipped to 800x600');
    phantom.exit(1);
} else {
    address = system.args[1];
    output = system.args[2];
    page.viewportSize = { width: 600, height: 600 };
    if (system.args.length > 3 && system.args[2].substr(-4) === ".pdf") {
        size = system.args[3].split('*');
        page.paperSize = size.length === 2 ? { width: size[0], height: size[1], margin: '0px' }
                                           : { format: system.args[3], orientation: 'portrait', margin: '1cm' };
    } else if (system.args.length > 3 && system.args[3].substr(-2) === "px") {
        size = system.args[3].split('*');
        if (size.length === 2) {
            pageWidth = parseInt(size[0], 10);
            pageHeight = parseInt(size[1], 10);
            page.viewportSize = { width: pageWidth, height: pageHeight };
            page.clipRect = { top: 0, left: 0, width: pageWidth, height: pageHeight };
        } else {
            console.log("size:", system.args[3]);
            pageWidth = parseInt(system.args[3], 10);
            pageHeight = parseInt(pageWidth * 3/4, 10); // it's as good an assumption as any
            console.log ("pageHeight:",pageHeight);
            page.viewportSize = { width: pageWidth, height: pageHeight };
        }
    }
    if (system.args.length > 4) {
        page.zoomFactor = system.args[4];
    }
    page.open(address, function (status) {
        if (status !== 'success') {
            console.log('Unable to load the address!');
            phantom.exit(1);
        } else {
            window.setTimeout(function () {
                page.render(output);
                phantom.exit();
            }, 200);
        }
    });
}

2、编写Java代码

/**
 * Created by majunwei on 2017/8/30.
 */
@Controller("image")
public class ImageController {
    private Logger logger = LoggerFactory.getLogger(ImageController.class);

    @Autowired
    private SettingsProperties settingsProperties;



    /**
     * html生成图片
     * //第一步,生成html临时文件(需要获取图片生成配置参数)
     * //第二步,html装Image
     * //第三步,Image上传TFS
     * //最后一步,返回ImageURL和结果
     * @param htmlData  html源数据
     * @param userId    操作人
     * @param platform  平台
     * @param width     宽
     * @param height    高
     * @param size      大小
     * @param zoom      缩放比
     * @param outputQuality 图片质量,最大100
     * @param outputFormat  format  jpg png
     * @param uploadFlag    是否上传TFS
     * @return
     */
    @RequestMapping("html2image")
    @ResponseBody
    public Result html2Image(@RequestParam(value = "html", required = true, defaultValue = "") String htmlData,
                             @RequestParam(value = "userId", required = true, defaultValue = "") String userId,
                             @RequestParam(value = "platform", required = true, defaultValue = "") String platform,
                             @RequestParam(value = "width", required = false, defaultValue = "400") String width,
                             @RequestParam(value = "height", required = false, defaultValue = "300") String height,
                             @RequestParam(value = "size", required = false, defaultValue = "400*300px") String size,
                             @RequestParam(value = "zoom", required = false, defaultValue = "1") String zoom,
                             @RequestParam(value = "outputQuality", required = false, defaultValue = "100") String outputQuality,
                             @RequestParam(value = "outputFormat", required = false, defaultValue = "jpg") String outputFormat,
                             @RequestParam(value = "uploadFlag", required = false, defaultValue = "true") String uploadFlag
    ){
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        logger.info("htmlData {}",htmlData);
        logger.info("userId {}",userId);
        logger.info("platform {}",platform);
        logger.info("width {}",width);
        logger.info("height {}",height);
        logger.info("size {}",size);
        logger.info("outputQuality {}",outputQuality);
        logger.info("outputFormat {}",outputFormat);
        logger.info("uploadFlag {}",uploadFlag);


        //临时文件名
        String tempFileName = "" + System.currentTimeMillis() + RandomUtils.nextInt(0,1000);


        //默认值
        if(!StringUtils.isEmpty(width) && !StringUtils.isEmpty(height)){
            size = width + "*" + height + "px";
        }

        String extra = " " + size + " " + zoom + " " + outputFormat + " " + outputQuality;

        String htmlRoot = settingsProperties.getPhantomjsHtmlRoot();


        String phantomjsShell = settingsProperties.getPhantomjsShell();
        String htmlFilePath = htmlRoot + tempFileName + ".html";
        String imageFilePath = htmlRoot + tempFileName + "." + outputFormat;
        File htmlFile = new File(htmlFilePath);//静态文件存储路径

        String jspath = settingsProperties.getPhantomjsJsFile();
        String cmd = phantomjsShell + " --disk-cache=yes " + jspath + " " + htmlFilePath + " " + imageFilePath + extra;
        logger.info("will execCommand1--[" + cmd + "]  html_url [" + htmlFilePath + "]   img_url [" + imageFilePath + "]");

        File imageFile = new File(imageFilePath);


        InputStream is = null;
        ByteArrayOutputStream baos = null;
        try {

            long htmlStart = System.currentTimeMillis();
            FileUtils.writeStringToFile(htmlFile, htmlData, "utf-8");
            logger.info("create html used {} ms",System.currentTimeMillis() - htmlStart);

            long createImageStart = System.currentTimeMillis();
            execCommand(cmd);
            logger.info("生成图片用时 {} ms",System.currentTimeMillis() - createImageStart);
            if(!imageFile.exists()){
                return Result.illegalParameter("生成图片失败.");
            }

            String key = "resource_" + tempFileName + "." + outputFormat;
            if("true".equals(uploadFlag)){
                long tfsStart = System.currentTimeMillis();
                BufferedImage bimage = ImageIO.read(imageFile);
                baos = new ByteArrayOutputStream();
                ImageIO.write(bimage, outputFormat, baos);
                byte[] bImage = baos.toByteArray();
                int status = TFSPictureUtil.putImage(key, bImage);
                logger.info("上传TFS用时 {} ms",System.currentTimeMillis() - tfsStart);
                if (status != TFSPictureUtil.SUCCESS_CODE) {
                    return Result.illegalParameter("生成图片失败.");
                }
            }
            String imgUrl = settingsProperties.getImageDomain() + key + "?w=" + width + "&h=" + height;
            logger.info("imgUrl is {}",imgUrl);
            JSONObject result = new JSONObject();
            result.put("imageUrl",imgUrl);
            return new DataResult(result);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("html2Image error:", e);
            return Result.illegalParameter("生成图片失败.");
        } finally {

            if (imageFile.exists()) {
                imageFile.delete();
            }
            if (htmlFile.exists()) {
                htmlFile.delete();
            }
            if(baos != null) {
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            stopWatch.stop();
            logger.info("html2Image used {} ms." , stopWatch.getTotalTimeMillis());
        }

    }

    public List<String> execCommand(String cmd) {
        List<String> list = new ArrayList<String>();
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(cmd);
            InputStream error_is = process.getErrorStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(error_is));
            String line = null;
            while ((line = br.readLine()) != null) {
                logger.error(line);

            }


            InputStream res_in = process.getInputStream();
            BufferedReader res_br = new BufferedReader(new InputStreamReader(res_in));
            String line2 = null;
            Map<String, String> map = new HashMap<String, String>();
            while ((line2 = res_br.readLine()) != null) {
                logger.info("-----" + line2);
            }


        } catch (Exception e) {
            logger.error("execCommand 出错",e);
            e.printStackTrace();
        } finally {
            try {
                process.destroy();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return list;
    }
}

3、请求html2image服务

4、查看返回的imgUrl,就可以访问到图片了,是不是很帅。

想象一下,这里可以做在线编辑器,然后将编辑的内容保存为图片,这里有很大的用途。

备注:

1、例子里直接拷贝跑不起来的,我这里把图片上传到TFS了,还引用了其他的类。

2、如果你愿意,可以修改逻辑,比如把图片保存到其他地方,或者不删除图片,保存到磁盘上,等等

总结

本文介绍了通过phantomjs生成图片的两种方法;

其中第二种做通用的图片生成工具用处比较广泛,有兴趣可以参考一下。

 

 

 

原创文章,转载请注明出处:转载自小马过河 - PhantomJS实现网络截图和图片生成工具


Jbone

Spring Cloud实战项目jbone正在开发中, jbone功能包括服务管理、单点登录、系统管理平台、内容管理平台、电商平台、支付平台、工作流平台等子系统。欢迎关注!

GitHub 码云

相关文章

马军伟
关于作者 马军伟
写的不错,支持一下

先给自己定个小目标,日更一新。