Java html生成图片

/ 技术 / 无站内评论 / 458浏览

前言

抓取的时候有些场景,需要把整个页面截图下载下来。网上不少资源,不过文章水平参差不齐,实现出来的效果有人不尽人意。于是摸索了一番,总结了一个截图生成效果比较好的几个框架。

同时封装成更多方法使用工具类。


实例网站

https://sanii.cn/



Html2Image

这个框架放最前面的原因并不是它效果最好,反而效果是文章中最差的,放前面的原因是google百度一搜html生成图片,几乎都是这个框架的资料,但是截图效果很差劲,很多js css都无法正常渲染。

不过支持自定义html源码生成图片,html不复杂可以使用该方案。

maven

<dependency>
<groupId>com.github.xuwei-k</groupId>
<artifactId>html2image</artifactId>
<version>0.1.0</version>
</dependency>


效果


工具类

public class Html2ImageUtil {
/**
* @param filePath
* @param charset
* @return
* @Description 读取HTML文件,获取字符内容
*/
public static String getHtmlContent(String filePath, String charset) {

String line = null;
StringBuilder sb = new StringBuilder();
BufferedReader reader = null;

try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(new File(filePath)), charset));
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("读取HTML文件,获取字符内容异常");
} finally {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("关闭流异常");
}
}
return sb.toString();
}


/**
* @param htmText HTML文本字符串
* @return 希望生成的Image Location
* @Description HTMLImage
*/
public static String html2Img(String htmText, String saveImageLocation) {

HtmlImageGenerator imageGenerator = new HtmlImageGenerator();
try {
imageGenerator.loadHtml(htmText);
imageGenerator.getBufferedImage();
Thread.sleep(1000);
imageGenerator.saveAsImage(saveImageLocation);
imageGenerator.saveAsHtmlWithMap("hello-world.html", saveImageLocation);
//不需要转换位图的,下面三行可以不要
// BufferedImage sourceImg = ImageIO.read(new File(saveImageLocation));
// sourceImg = transform_Gray24BitMap(sourceImg);
// ImageIO.write(sourceImg, "BMP", new File(saveImageLocation));
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("HTML文件转换成图片异常");
}
return saveImageLocation;
}

/**
* @param image
* @return
* @Description 转换成24位图的BMP
*/
public static BufferedImage transform_Gray24BitMap(BufferedImage image) {

int h = image.getHeight();
int w = image.getWidth();
// 定义数组,用来存储图片的像素
int[] pixels = new int[w * h];
int gray;
PixelGrabber pg = new PixelGrabber(image, 0, 0, w, h, pixels, 0, w);
try {
pg.grabPixels(); // 读取像素值
} catch (InterruptedException e) {
throw new RuntimeException("转换成24位图的BMP时,处理像素值异常");
}
// 扫描列
for (int j = 0; j < h; j++) {
// 扫描行
for (int i = 0; i < w; i++) {
// 由红,绿,蓝值得到灰度值
gray = (int) (((pixels[w * j + i] >> 16) & 0xff) * 0.8);
gray += (int) (((pixels[w * j + i] >> 8) & 0xff) * 0.1);
gray += (int) (((pixels[w * j + i]) & 0xff) * 0.1);
pixels[w * j + i] = (255 << 24) | (gray << 16) | (gray << 8) | gray;
}
}

MemoryImageSource s = new MemoryImageSource(w, h, pixels, 0, w);
Image img = Toolkit.getDefaultToolkit().createImage(s);
//如果要转换成别的位图,改这个常量即可
BufferedImage buf = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
buf.createGraphics().drawImage(img, 0, 0, null);
return buf;
}
}


DJNativeSwing

该方案能完美截图,底层调用的是Java的实现的浏览器。不好的地方是资源消耗高,同时关闭浏览器的时候,会关闭整个应用,包括tomcat。


maven

<dependency>
<groupId>com.hynnet</groupId>
<artifactId>DJNativeSwing</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.hynnet</groupId>
<artifactId>DJNativeSwing-SWT</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.swt.org.eclipse.swt.win32.win32.x86_64.4.3.swt</groupId>
<artifactId>org.eclipse.swt.win32.win32.x86_64</artifactId>
<version>4.3</version>
</dependency>


效果



工具类

public class PrintScreen4DJNativeSwingUtils extends JPanel {
private static final long serialVersionUID = 1L;
// 行分隔符
final static public String LS = System.getProperty("line.separator", "/n");
// 文件分割符
final static public String FS = System.getProperty("file.separator", "//");
// 当网页超出目标大小时 截取
final static public int maxWidth = 2000;
final static public int maxHeight = 2000;

/**
* @param file
* 预生成的图片全路径
* @param url
* 网页地址
* @param width
* 打开网页宽度 ,0 = 全屏
* @param height
* 打开网页高度 ,0 = 全屏
* @return boolean
* @author xufei
* @version 4.0, 20181211
*/
public PrintScreen4DJNativeSwingUtils(final String file, final String url,
final String WithResult) {
super(new BorderLayout());
JPanel webBrowserPanel = new JPanel(new BorderLayout());
final JWebBrowser webBrowser = new JWebBrowser(null);
webBrowser.setBarsVisible(false);
webBrowser.navigate(url);
webBrowserPanel.add(webBrowser, BorderLayout.CENTER);
add(webBrowserPanel, BorderLayout.CENTER);
JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 4, 4));
webBrowser.addWebBrowserListener(new WebBrowserAdapter() {
// 监听加载进度
@Override
public void loadingProgressChanged(WebBrowserEvent e) {
// 当加载完毕时
if (e.getWebBrowser().getLoadingProgress() == 100) {
String result = (String) webBrowser
.executeJavascriptWithResult(WithResult);
int index = result == null ? -1 : result.indexOf(":");
NativeComponent nativeComponent = webBrowser
.getNativeComponent();
Dimension originalSize = nativeComponent.getSize();
Dimension imageSize = new Dimension(Integer.parseInt(result
.substring(0, index)), Integer.parseInt(result
.substring(index + 1)));
imageSize.width = Math.max(originalSize.width,
imageSize.width);
imageSize.height = Math.max(originalSize.height,
imageSize.height);
nativeComponent.setSize(imageSize);
BufferedImage image = new BufferedImage(imageSize.width,
imageSize.height, BufferedImage.TYPE_INT_RGB);
nativeComponent.paintComponent(image);
nativeComponent.setSize(originalSize);
// 当网页超出目标大小时
if (imageSize.width > maxWidth
|| imageSize.height > maxHeight) {
// 截图部分图形
image = image.getSubimage(0, 0, maxWidth, maxHeight);
// 此部分为使用缩略图
/*
* int width = image.getWidth(), height = image
* .getHeight(); AffineTransform tx = new
* AffineTransform(); tx.scale((double) maxWidth /
* width, (double) maxHeight / height);
* AffineTransformOp op = new AffineTransformOp(tx,
* AffineTransformOp.TYPE_NEAREST_NEIGHBOR); //缩小 image
* = op.filter(image, null);
*/
}
try {
// 输出图像
ImageIO.write(image, "jpg", new File(file));
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
});
add(panel, BorderLayout.SOUTH);

}

/**
* javascript脚本获得网页全屏后大小
* @return
*/
public static String getScreenWidthHeight() {

StringBuffer jsDimension = new StringBuffer();
jsDimension.append("var width = 0;").append(LS);
jsDimension.append("var height = 0;").append(LS);
jsDimension.append("if(document.documentElement) {").append(LS);
jsDimension
.append(" width = Math.max(width, document.documentElement.scrollWidth);")
.append(LS);
jsDimension
.append(" height = Math.max(height, document.documentElement.scrollHeight);")
.append(LS);
jsDimension.append("}").append(LS);
jsDimension.append("if(self.innerWidth) {").append(LS);
jsDimension.append(" width = Math.max(width, self.innerWidth);")
.append(LS);
jsDimension.append(" height = Math.max(height, self.innerHeight);")
.append(LS);
jsDimension.append("}").append(LS);
jsDimension.append("if(document.body.scrollWidth) {").append(LS);
jsDimension.append(
" width = Math.max(width, document.body.scrollWidth);")
.append(LS);
jsDimension.append(
" height = Math.max(height, document.body.scrollHeight);")
.append(LS);
jsDimension.append("}").append(LS);
jsDimension.append("return width + ':' + height;");

return jsDimension.toString();
}

/**
*
* @param file 图片保存路径
* @param url 要截图的URL地址
* @param width 裁剪图片的宽 0代表按照图片的原始大小保存
* @param height 裁剪图片的高 0代表按照图片的原始大小保存
* @return
*/
public static boolean printUrlScreen2jpg(final String file,
final String url, final int width, final int height) {

NativeInterface.open();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
String withResult = "var width = " + width + ";var height = "
+ height + ";return width +':' + height;";
if (width == 0 || height == 0)
withResult = getScreenWidthHeight();

// SWT组件转Swing组件,不初始化父窗体将无法启动webBrowser
JFrame frame = new JFrame("网页截图");
// 加载指定页面,最大保存为640x480的截图
frame.getContentPane().add(
new PrintScreen4DJNativeSwingUtils(file, url,
withResult), BorderLayout.CENTER);
frame.setSize(640, 480);
// 仅初始化,但不显示
frame.invalidate();

frame.pack();
frame.setVisible(false);
}
});
NativeInterface.runEventPump();

return true;
}

}


cssbox

最完美的一个,完美截图,效率比第二中快!依赖少,简直完美。


maven

<dependency>
<groupId>net.sf.cssbox</groupId>
<artifactId>cssbox</artifactId>
<version>4.12</version>
</dependency>


效果

工具类

public class CssboxUtil {

public static final int WIDTH = 1900;
public static final int HEIGHT = 1000;

/**
* 图片生成到指定路径
* 支持 file ftp http https
*
* @param url html地址
* @param path 生成文件地址
* @throws IOException
* @throws SAXException
*/
public static void toPath(String url, String path) throws IOException, SAXException {
toPath(url, path, WIDTH, HEIGHT);
}

/**
* 图片生成到指定路径
* 支持 file ftp http https
*
* @param url html地址
* @param path 生成文件地址
* @throws IOException
* @throws SAXException
*/
public static void toPath(String url, String path, int width, int height) throws IOException, SAXException {
ImageRenderer render = new ImageRenderer();
FileOutputStream out = new FileOutputStream(new File(path));
render.setWindowSize(new Dimension(width, height), false);
render.renderURL(url, out, ImageRenderer.Type.PNG);
out.close();
}

/**
* 图片生成到byte数组
* 支持 file ftp http https
*
* @param url html地址
* @throws IOException
* @throws SAXException
*/
public static byte[] toByte(String url) throws IOException, SAXException {
return toByte(url, WIDTH, HEIGHT);
}

/**
* 图片生成到byte数组
* 支持 file ftp http https
*
* @param url html地址
* @throws IOException
* @throws SAXException
*/
public static byte[] toByte(String url, int width, int height) throws IOException, SAXException {
ImageRenderer render = new ImageRenderer();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
render.setWindowSize(new Dimension(1900, 1000), false);
render.renderURL(url, stream, ImageRenderer.Type.PNG);
byte[] bytes = stream.toByteArray();
stream.close();
return bytes;
}
}



召唤蕾姆
琼ICP备18000156号

鄂公网安备 42011502000211号