5.图片转SVG使用示例
约 1149 字大约 4 分钟
本文为 image-plugin 中图转SVG的使用参考示例
1. 基本原理
我们知道图片是由一个一个的像素点组成的,将图片转换为svg的一个思路就是将图片中的每个像素点直接转换为svg中的矩形颜色块,这样就可以直接生成一个对应的svg文本了
一个基本的转换实现可以参见 SvgParseTest.java
public static String SVG_START = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
"<svg xmlns=\"http://www.w3.org/2000/svg\"\n" +
" viewBox=\"0 0 {width} {height}\"\n" +
" style=\"width: 100%; height: 100%; overflow: auto; fill: {BG_COLOR}\">\n";
public static String SVG_END = "\n</svg>";
public String toRect(String color, int w, int h, int x, int y) {
return "<rect" + " fill=\"" + color + "\" height=\"" + h + "\" width=\"" + w + "\" y=\"" + y + "\" x=\"" + x + "\"/>";
}
@Test
public void basicParse() throws Exception {
String img = "https://spring.hhui.top/spring-blog/css/images/avatar.jpg";
BufferedImage bufferedImage = ImageLoadUtil.getImageByPath(img);
int w = bufferedImage.getWidth(), h = bufferedImage.getHeight();
StringBuilder builder = new StringBuilder();
String s = StrUtil.replace(SVG_START, "{width}", String.valueOf(w), "{height}", String.valueOf(h), "{BG_COLOR}", "white", "{FONT_COLOR}", "black");
builder.append(s).append("\n");
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int color = bufferedImage.getRGB(x, y);
if (color == Color.WHITE.getRGB()) {
// 背景直接不要
continue;
}
String htmlColor = ColorUtil.int2htmlColor(color);
builder.append(toRect(htmlColor, 1, 1, x, y));
}
}
builder.append(SVG_END);
FileWriteUtil.saveContent(new File("/tmp/parseSvg-out1.svg"), builder.toString());
}
上面实现就是基本的像素块的替换了,可以看到输出的svg文本较大;接下来我们可以再优化一下,首先利用ImgPixelWrapper
将图片转换为像素块(降低精度),然后再将像素块的图片转换为svg
因此可以对上面的实现进行一个微调
@Test
public void test2svg() {
int size = 8;
BufferedImage pixelImg = ImgPixelWrapper.build()
.setSourceImg("https://spring.hhui.top/spring-blog/css/images/avatar.jpg")
.setBlockSize(size)
.setPixelType(PixelStyleEnum.PIXEL_COLOR_AVG)
.build().asBufferedImg();
int w = pixelImg.getWidth(), h = pixelImg.getHeight();
StringBuilder builder = new StringBuilder();
String s = StrUtil.replace(SVG_START, "{width}", String.valueOf(w), "{height}", String.valueOf(h), "{BG_COLOR}", "white", "{FONT_COLOR}", "black");
builder.append(s).append("\n");
for (int i = 0; i < w; i += size) {
for (int j = 0; j < h; j += size) {
int color = pixelImg.getRGB(i, j);
Color c = new Color(color, true);
if (c.getRed() >= 250 && c.getGreen() >= 250 && c.getBlue() >= 250) {
continue;
}
String htmlColor = ColorUtil.int2htmlColor(color);
builder.append(toRect(htmlColor, size, size, i, j)).append("\n");
}
}
builder.append(SVG_END);
System.out.println(builder);
System.out.println("over");
FileWriteUtil.saveContent(new File("/tmp/parseSvg-out2.svg"), builder.toString());
}
比如上面设置size = 8
,相当于将原图精度损失8倍,对应生成的svg如下
2. 使用示例
2.1 参数说明
核心参数四个,其中source传图为必填
参数名 | 类型 | 说明 | 是否必填 |
---|---|---|---|
source | BufferedImage | 原始图 | 是 |
blockSize | int | 对于转字符图时,它控制字符大小;对于灰度/像素处理时,这个表示像素化的处理操作 | 非必填,默认 4 |
scaleRate | Double | 缩放比例,1 表示输出的图不缩放; > 1,表示生成的图,按倍数扩大 | 非必填,默认 1 |
bgPredicate | Predicate<Color> | 背景色判断方式,传参为 intColor ,如果返回true ,表示认定为背景色;否则不是 | 非必填,默认纯白色为背景 |
2.2 使用示例
使用姿势形如
SvgParserWrapper
.of(png) // 制定图片
.setBgPredicate(c -> { // 设置背景判断方式
if (c.getRed() >= 50 && c.getRed() <= 60
&& c.getGreen() >= 55 && c.getGreen() <= 62
&& c.getBlue() >= 60 && c.getBlue() <= 65) {
return true;
}
if (c.getRed() >= 0xd7 && c.getGreen() >= 0x5f && c.getBlue() >= 0xf0) {
return true;
}
return false;
})
.build()
// 将svg输出到指定文件中,若目录不存在会自动创建缺省的目录
.asFile("...");
下面是一个简单的使用示例
@Test
public void png2svg() throws IOException {
// 图片转svg
String png = "https://ci.xiaohongshu.com/d5137769-1836-cc20-c1eb-20af1109dc7a?imageView2/2/w/1080/format/jpg";
SvgParserWrapper
.of(png)
.setScaleRate(0.3f)
.setBlockSize(1)
.setBgPredicate(c -> {
if (c.getRed() >= 50 && c.getRed() <= 60
&& c.getGreen() >= 55 && c.getGreen() <= 62
&& c.getBlue() >= 60 && c.getBlue() <= 65) {
return true;
}
if (c.getRed() >= 0xd7 && c.getGreen() >= 0x5f && c.getBlue() >= 0xf0) {
return true;
}
return false;
})
.build()
.asFile("/tmp/dlam.svg");
System.out.println("----over----");
}
原图 | svg图 |
---|---|
![]() |
接下来再看一个真实人像的转换过程,如下
@Test
public void parsePhoto() throws Exception {
String photo = "/tmp/quick-media/lyf.png";
SvgParserWrapper.of(photo)
.setScaleRate(0.4)
.setBlockSize(1)
.setBgPredicate(c -> {
return c.getAlpha() < 10;
})
.build().asFile("/tmp/quick-media/lyf.svg");
System.out.println("---over---");
}
// 用文字进行替换颜色单元格
public void parsePhoto() throws Exception {
String txt = "刘亦菲";
AtomicInteger ato = new AtomicInteger(1);
String photo = "d:/quick-media/lyf.png";
SvgParserWrapper.of(photo)
.setScaleRate(4)
.setBlockSize(12)
.setBgPredicate(c -> {
return c.getAlpha() < 10;
})
.setSvgCellParse((color, x, y, size) -> {
// 使用文字来填充像素单元格
return ImgPixelHelper.getSvgTxtCell(txt.charAt(ato.getAndAdd(1) % 3) + "", color, x, y, size);
})
.build().asFile("d:/quick-media/lyf2.svg");
System.out.println("---over---");
}
说明:原图来自网上 https://www.5youqu.com/bizhi/124906.html,做了背景剔除
对比结果如下
原图 | svg图 |
---|---|
![]() | |
![]() |
Loading...